Blockchain / Global / Address

Contract

0xbd8e690465E84e97075a89Fb30c64D5C44e04ad5

Balance
0 SOMI
Transactions sent
1
Type
Contract · 8,916 bytes of code

CrossChainRouter Verified

Compiler
solc 0.8.33+commit.64118f21
Language
Solidity
Optimization
Yes, 777777 runs
EVM version
prague
License
—
Verified
2026-10-12

src/BrandedStablecoin/CrossChainRouter.sol

and 11 more files

Solidity
// SPDX-License-Identifier: AGPL-3.0-only
pragma solidity ^0.8.21;

// ====================================================================
// |     ______                   _______                             |
// |    / _____________ __  __   / ____(_____  ____ _____  ________   |
// |   / /_  / ___/ __ `| |/_/  / /_  / / __ \/ __ `/ __ \/ ___/ _ \  |
// |  / __/ / /  / /_/ _>  <   / __/ / / / / / /_/ / / / / /__/  __/  |
// | /_/   /_/   \__,_/_/|_|  /_/   /_/_/ /_/\__,_/_/ /_/\___/\___/   |
// |                                                                  |
// ====================================================================
// ========================= CrossChainRouter =========================
// ====================================================================
// Frax Finance: https://github.com/FraxFinance

import { AccessControl } from "@openzeppelin/contracts/access/AccessControl.sol";
import { IBrandedCustodian } from "src/BrandedStablecoin/interfaces/IBrandedCustodian.sol";
import { IGDollar } from "src/BrandedStablecoin/interfaces/IGDollar.sol";
import { IFrxUSD } from "src/interfaces/IFrxUSD.sol";
import { IRemoteHopV2 } from "src/BrandedStablecoin/interfaces/IRemoteHopV2.sol";
import { ILZSend } from "src/BrandedStablecoin/interfaces/ILzSend.sol";

/**
 * @title CrossChainRouter
 * @notice Implementation contract to be proxied. Intended to allow for branded stablecoins
 *         to be moved across supported EVM chains using the frax L0 mesh
 */
contract CrossChainRouter is AccessControl, ILZSend {
  bytes32 public constant RELAYER_ROLE = keccak256("RELAYER_ROLE");
  uint128 public constant GLOBAL_COMPOSE_GAS = 500_000;
  uint128 public constant SOMNIA_COMPOSE_GAS = 3_500_000;
  bool public wasInitialized = true;
  IBrandedCustodian public custodian;
  IGDollar public coin;
  IFrxUSD public frxusd;
  address public oftLocal;
  IRemoteHopV2 public remoteHopV2;
  mapping(uint32 => bytes32) public eidToNonDeterministicAddress;
  bool public isolatedBackingEnabled;

  /**
   * @notice Initialization function called w/n `FraxBrandedStablecoinFactory._deployBrandedTokenChained`
   * @param _owner             The address given the default admin role
   * @param _custodianAddress  The address of the brandedStablecoin custodian contract
   * @param _coin              The address of the brandedStablecoin proxy
   * @param _localFrxUSD       The local frxUSD OFT contract | either the OFT token or the lockbox
   * @param _localRemoteHop    The address of the RemoteHopV2 contract
   */
  function initialize(
    address _owner,
    address _custodianAddress,
    address _coin,
    address _localFrxUSD,
    address _localRemoteHop,
    bool _isolatedBackingEnabled
  ) external {
    if (wasInitialized) revert AlreadyInitialized();
    _grantRole(DEFAULT_ADMIN_ROLE, _owner);
    _grantRole(RELAYER_ROLE, _owner);
    coin = IGDollar(_coin);
    custodian = IBrandedCustodian(_custodianAddress);
    if (block.chainid == 252) {
      frxusd = IFrxUSD(0xFc00000000000000000000000000000000000001);
      oftLocal = _localFrxUSD;
    } else if (block.chainid == 1) {
      frxusd = IFrxUSD(0xCAcd6fd266aF91b8AeD52aCCc382b4e165586E29);
      oftLocal = _localFrxUSD;
    } else {
      frxusd = IFrxUSD(_localFrxUSD);
      oftLocal = _localFrxUSD;
    }
    remoteHopV2 = IRemoteHopV2(payable(_localRemoteHop));
    isolatedBackingEnabled = _isolatedBackingEnabled;
    wasInitialized = true;
  }

  /**
   * @notice External function used to coordinate the cross chain transfer of branded Stablecoin
   * @param dstEid     The EID corresponding to the chain that we want to send the stablecoin to
   * @param recipient  The evm address of the recipient on the dst chain
   * @param amount     The amount of the stablecoin that we want to send cross chain
   */
  function send(uint32 dstEid, address recipient, uint256 amount) public payable {
    bytes32 router = bytes32(uint(uint160(address(this))));
    if (eidToNonDeterministicAddress[dstEid] != bytes32(0)) router = eidToNonDeterministicAddress[dstEid];
    amount = (amount / 1e12) * 1e12; // Remove lzDust
    coin.transferFrom(msg.sender, address(this), amount);
    coin.approve(address(custodian), amount);
    uint out = custodian.redeem(amount, address(this), address(this));
    frxusd.approve(address(remoteHopV2), amount);
    remoteHopV2.sendOFT{ value: msg.value }(
      oftLocal,
      dstEid,
      router,
      out,
      dstEid == 30380 ? SOMNIA_COMPOSE_GAS : GLOBAL_COMPOSE_GAS,
      abi.encode(recipient)
    );
    _refundExcess();
  }

  /**
   * @notice External function used to facilitate the minting and sending of a branded stablecoin
   *         via the receipt of frxUSD
   * @param dstEid    The EID of the destination chain
   * @param recipient The recipient on the destination chain
   * @param amount    The amount of frxUSD that we want to mint and send to the recipient
   */
  function mintAndSend(uint32 dstEid, address recipient, uint256 amount) external payable returns (uint256 out) {
    if (isolatedBackingEnabled) revert IsolatedBackingEnabled();
    bytes32 router = bytes32(uint(uint160(address(this))));
    if (eidToNonDeterministicAddress[dstEid] != bytes32(0)) router = eidToNonDeterministicAddress[dstEid];
    amount = (amount / 1e12) * 1e12; // Remove lzDust
    frxusd.transferFrom(msg.sender, address(this), amount);
    frxusd.approve(address(remoteHopV2), amount);
    out = amount;
    remoteHopV2.sendOFT{ value: msg.value }(
      oftLocal,
      dstEid,
      router,
      out,
      dstEid == 30380 ? SOMNIA_COMPOSE_GAS : GLOBAL_COMPOSE_GAS,
      abi.encode(recipient)
    );
    _refundExcess();
  }

  /**
   * @notice Internal helper function to refund any excess msg.value sent
   */
  function _refundExcess() internal {
    uint256 balance = address(this).balance;
    if (balance > 0) {
      (bool success, ) = msg.sender.call{ value: balance }("");
      if (!success) revert RefundFailed();
    }
  }

  /**
   * @notice Helper function to calculate the amount of gas to send along with calls
   *         to `address(this).send(...)`
   * @param dstEid     The EID corresponding to the chain we want to send the token to
   * @param recipient  The evm address to send the tokens on the dst chain to
   * @param amount     The amount of tokens we want to send cross chain
   */
  function quote(uint32 dstEid, address recipient, uint256 amount) public view returns (uint256) {
    bytes32 router = bytes32(uint(uint160(address(this))));
    if (eidToNonDeterministicAddress[dstEid] != bytes32(0)) router = eidToNonDeterministicAddress[dstEid];
    uint fee = remoteHopV2.quote({
      _oft: oftLocal,
      _dstEid: dstEid,
      _to: router,
      _amountLD: (1e12 * (amount / 1e12)),
      _composeGas: dstEid == 30380 ? SOMNIA_COMPOSE_GAS : GLOBAL_COMPOSE_GAS,
      _composeMsg: abi.encode(recipient)
    });
    return (fee);
  }

  /**
   * @notice Hook to be called by the remote hop on receiving a message passed
   * @param oft     The oft token corresponding to the msg being passed
   * @param _amount The amount of oft token we
   * @param data    The data being passed through
   * @dev Function call assumes frxUSD has been previously transfered to this contract
   */
  function hopCompose(uint32 srcEid, bytes32 sender, address oft, uint256 _amount, bytes memory data) external {
    if (msg.sender != address(remoteHopV2)) revert InvalidSender();
    if (oft != oftLocal) revert InvalidOFT();
    if (isolatedBackingEnabled) {
      bytes32 router = eidToNonDeterministicAddress[srcEid];
      if (router == bytes32(0)) router = bytes32(uint(uint160(address(this))));
      if (sender != router) revert NotFromRouter();
    }
    (address recipient) = abi.decode(data, (address));
    frxusd.approve(address(custodian), _amount);
    custodian.deposit(_amount, recipient);
  }

  /**
   * @notice Function to be implemented for non-determinist address deployment
   * @param eid   The eid for which we want to use a different router
   * @param value The value we want to have the `recipient` field be equal to on the sendParams
   */
  function setNonDeterministicRouterAddress(uint32 eid, bytes32 value) external onlyRole(RELAYER_ROLE) {
    eidToNonDeterministicAddress[eid] = value;
    emit NonDeterministicAddressSet(eid, value);
  }

  /**
   * @notice Function for setting the remoteHopV2 address post deployment
   * @param _updatedAddress The address of the updated hop contract
   */
  function setHopV2Address(address _updatedAddress) external onlyRole(DEFAULT_ADMIN_ROLE) {
    emit HopAddressUpdated(address(remoteHopV2), _updatedAddress);
    remoteHopV2 = IRemoteHopV2(payable(_updatedAddress));
  }

  /**
   * @notice Extension of LZ Send interface
   * @param _sendParam    Lz `_sendParam` tuple
   * @param _payInLzToken whether to pay in LZ tokens | cannot be true
   */
  function quoteSend(SendParam calldata _sendParam, bool _payInLzToken) external view returns (MessagingFee memory) {
    if (_payInLzToken) revert MustPayNative();
    if (bytes12(_sendParam.to) != bytes12(0)) revert MustBeEvmAddress();
    if (_sendParam.composeMsg.length != 0) revert NotSupported();
    if (_sendParam.oftCmd.length != 0) revert NotSupported();

    uint amount = (_sendParam.amountLD / 1e12) * 1e12;
    if (amount < _sendParam.minAmountLD) revert SlippageExceeded(amount, _sendParam.minAmountLD);
    return
      MessagingFee({
        nativeFee: quote({
          dstEid: _sendParam.dstEid,
          recipient: address(uint160(uint(_sendParam.to))),
          amount: amount
        }),
        lzTokenFee: 0
      });
  }

  /**
   * @notice Extension of LZ send interface
   * @param _sendParam        Lz `SendParam` tuple
   * @param _fee              Lz `MessagingFee` tuple
   * @param _refundAddress    Address for gas refund | must be caller
   * @return MessagingReceipt - Place Holder variable for ABI conformity
   * @return OFTReceipt - Place Holder variable for ABI conformity
   */
  function send(
    SendParam calldata _sendParam,
    MessagingFee calldata _fee,
    address _refundAddress
  ) external payable returns (MessagingReceipt memory, OFTReceipt memory) {
    if (_fee.lzTokenFee != 0) revert MustPayNative();
    if (_refundAddress != msg.sender) revert RefundMustBeSelf();
    if (bytes12(_sendParam.to) != bytes12(0)) revert MustBeEvmAddress();
    if (_sendParam.composeMsg.length != 0) revert NotSupported();
    if (_sendParam.oftCmd.length != 0) revert NotSupported();
    uint amount = (_sendParam.amountLD / 1e12) * 1e12;
    if (amount < _sendParam.minAmountLD) revert SlippageExceeded(amount, _sendParam.minAmountLD);
    send({ dstEid: _sendParam.dstEid, recipient: address(uint160(uint(_sendParam.to))), amount: _sendParam.amountLD });
    MessagingReceipt memory receipt = MessagingReceipt({ guid: bytes32(0), nonce: 0, fee: _fee });
    OFTReceipt memory oftReceipt = OFTReceipt({ amountSentLD: amount, amountReceivedLD: amount });
    return (receipt, oftReceipt);
  }

  receive() external payable {}

  /// Errors
  error NotFromRouter();
  error InvalidSender();
  error InvalidOFT();
  error AlreadyInitialized();
  error RefundFailed();
  error IsolatedBackingEnabled();
  error MustPayNative();
  error MustBeEvmAddress();
  error RefundMustBeSelf();
  error SlippageExceeded(uint256, uint256);
  error NotSupported();

  event HopAddressUpdated(address oldHopAddress, address newHopAddress);
  event NonDeterministicAddressSet(uint32 eid, bytes32 router);
}

Other files

  • node_modules/@openzeppelin/contracts/access/AccessControl.sol
    // SPDX-License-Identifier: MIT
    // OpenZeppelin Contracts (last updated v5.0.0) (access/AccessControl.sol)
    
    pragma solidity ^0.8.20;
    
    import {IAccessControl} from "./IAccessControl.sol";
    import {Context} from "../utils/Context.sol";
    import {ERC165} from "../utils/introspection/ERC165.sol";
    
    /**
     * @dev Contract module that allows children to implement role-based access
     * control mechanisms. This is a lightweight version that doesn't allow enumerating role
     * members except through off-chain means by accessing the contract event logs. Some
     * applications may benefit from on-chain enumerability, for those cases see
     * {AccessControlEnumerable}.
     *
     * Roles are referred to by their `bytes32` identifier. These should be exposed
     * in the external API and be unique. The best way to achieve this is by
     * using `public constant` hash digests:
     *
     * ```solidity
     * bytes32 public constant MY_ROLE = keccak256("MY_ROLE");
     * ```
     *
     * Roles can be used to represent a set of permissions. To restrict access to a
     * function call, use {hasRole}:
     *
     * ```solidity
     * function foo() public {
     *     require(hasRole(MY_ROLE, msg.sender));
     *     ...
     * }
     * ```
     *
     * Roles can be granted and revoked dynamically via the {grantRole} and
     * {revokeRole} functions. Each role has an associated admin role, and only
     * accounts that have a role's admin role can call {grantRole} and {revokeRole}.
     *
     * By default, the admin role for all roles is `DEFAULT_ADMIN_ROLE`, which means
     * that only accounts with this role will be able to grant or revoke other
     * roles. More complex role relationships can be created by using
     * {_setRoleAdmin}.
     *
     * WARNING: The `DEFAULT_ADMIN_ROLE` is also its own admin: it has permission to
     * grant and revoke this role. Extra precautions should be taken to secure
     * accounts that have been granted it. We recommend using {AccessControlDefaultAdminRules}
     * to enforce additional security measures for this role.
     */
    abstract contract AccessControl is Context, IAccessControl, ERC165 {
        struct RoleData {
            mapping(address account => bool) hasRole;
            bytes32 adminRole;
        }
    
        mapping(bytes32 role => RoleData) private _roles;
    
        bytes32 public constant DEFAULT_ADMIN_ROLE = 0x00;
    
        /**
         * @dev Modifier that checks that an account has a specific role. Reverts
         * with an {AccessControlUnauthorizedAccount} error including the required role.
         */
        modifier onlyRole(bytes32 role) {
            _checkRole(role);
            _;
        }
    
        /**
         * @dev See {IERC165-supportsInterface}.
         */
        function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {
            return interfaceId == type(IAccessControl).interfaceId || super.supportsInterface(interfaceId);
        }
    
        /**
         * @dev Returns `true` if `account` has been granted `role`.
         */
        function hasRole(bytes32 role, address account) public view virtual returns (bool) {
            return _roles[role].hasRole[account];
        }
    
        /**
         * @dev Reverts with an {AccessControlUnauthorizedAccount} error if `_msgSender()`
         * is missing `role`. Overriding this function changes the behavior of the {onlyRole} modifier.
         */
        function _checkRole(bytes32 role) internal view virtual {
            _checkRole(role, _msgSender());
        }
    
        /**
         * @dev Reverts with an {AccessControlUnauthorizedAccount} error if `account`
         * is missing `role`.
         */
        function _checkRole(bytes32 role, address account) internal view virtual {
            if (!hasRole(role, account)) {
                revert AccessControlUnauthorizedAccount(account, role);
            }
        }
    
        /**
         * @dev Returns the admin role that controls `role`. See {grantRole} and
         * {revokeRole}.
         *
         * To change a role's admin, use {_setRoleAdmin}.
         */
        function getRoleAdmin(bytes32 role) public view virtual returns (bytes32) {
            return _roles[role].adminRole;
        }
    
        /**
         * @dev Grants `role` to `account`.
         *
         * If `account` had not been already granted `role`, emits a {RoleGranted}
         * event.
         *
         * Requirements:
         *
         * - the caller must have ``role``'s admin role.
         *
         * May emit a {RoleGranted} event.
         */
        function grantRole(bytes32 role, address account) public virtual onlyRole(getRoleAdmin(role)) {
            _grantRole(role, account);
        }
    
        /**
         * @dev Revokes `role` from `account`.
         *
         * If `account` had been granted `role`, emits a {RoleRevoked} event.
         *
         * Requirements:
         *
         * - the caller must have ``role``'s admin role.
         *
         * May emit a {RoleRevoked} event.
         */
        function revokeRole(bytes32 role, address account) public virtual onlyRole(getRoleAdmin(role)) {
            _revokeRole(role, account);
        }
    
        /**
         * @dev Revokes `role` from the calling account.
         *
         * Roles are often managed via {grantRole} and {revokeRole}: this function's
         * purpose is to provide a mechanism for accounts to lose their privileges
         * if they are compromised (such as when a trusted device is misplaced).
         *
         * If the calling account had been revoked `role`, emits a {RoleRevoked}
         * event.
         *
         * Requirements:
         *
         * - the caller must be `callerConfirmation`.
         *
         * May emit a {RoleRevoked} event.
         */
        function renounceRole(bytes32 role, address callerConfirmation) public virtual {
            if (callerConfirmation != _msgSender()) {
                revert AccessControlBadConfirmation();
            }
    
            _revokeRole(role, callerConfirmation);
        }
    
        /**
         * @dev Sets `adminRole` as ``role``'s admin role.
         *
         * Emits a {RoleAdminChanged} event.
         */
        function _setRoleAdmin(bytes32 role, bytes32 adminRole) internal virtual {
            bytes32 previousAdminRole = getRoleAdmin(role);
            _roles[role].adminRole = adminRole;
            emit RoleAdminChanged(role, previousAdminRole, adminRole);
        }
    
        /**
         * @dev Attempts to grant `role` to `account` and returns a boolean indicating if `role` was granted.
         *
         * Internal function without access restriction.
         *
         * May emit a {RoleGranted} event.
         */
        function _grantRole(bytes32 role, address account) internal virtual returns (bool) {
            if (!hasRole(role, account)) {
                _roles[role].hasRole[account] = true;
                emit RoleGranted(role, account, _msgSender());
                return true;
            } else {
                return false;
            }
        }
    
        /**
         * @dev Attempts to revoke `role` to `account` and returns a boolean indicating if `role` was revoked.
         *
         * Internal function without access restriction.
         *
         * May emit a {RoleRevoked} event.
         */
        function _revokeRole(bytes32 role, address account) internal virtual returns (bool) {
            if (hasRole(role, account)) {
                _roles[role].hasRole[account] = false;
                emit RoleRevoked(role, account, _msgSender());
                return true;
            } else {
                return false;
            }
        }
    }
    
  • node_modules/@openzeppelin/contracts/access/IAccessControl.sol
    // SPDX-License-Identifier: MIT
    // OpenZeppelin Contracts (last updated v5.1.0) (access/IAccessControl.sol)
    
    pragma solidity ^0.8.20;
    
    /**
     * @dev External interface of AccessControl declared to support ERC-165 detection.
     */
    interface IAccessControl {
        /**
         * @dev The `account` is missing a role.
         */
        error AccessControlUnauthorizedAccount(address account, bytes32 neededRole);
    
        /**
         * @dev The caller of a function is not the expected one.
         *
         * NOTE: Don't confuse with {AccessControlUnauthorizedAccount}.
         */
        error AccessControlBadConfirmation();
    
        /**
         * @dev Emitted when `newAdminRole` is set as ``role``'s admin role, replacing `previousAdminRole`
         *
         * `DEFAULT_ADMIN_ROLE` is the starting admin for all roles, despite
         * {RoleAdminChanged} not being emitted signaling this.
         */
        event RoleAdminChanged(bytes32 indexed role, bytes32 indexed previousAdminRole, bytes32 indexed newAdminRole);
    
        /**
         * @dev Emitted when `account` is granted `role`.
         *
         * `sender` is the account that originated the contract call. This account bears the admin role (for the granted role).
         * Expected in cases where the role was granted using the internal {AccessControl-_grantRole}.
         */
        event RoleGranted(bytes32 indexed role, address indexed account, address indexed sender);
    
        /**
         * @dev Emitted when `account` is revoked `role`.
         *
         * `sender` is the account that originated the contract call:
         *   - if using `revokeRole`, it is the admin role bearer
         *   - if using `renounceRole`, it is the role bearer (i.e. `account`)
         */
        event RoleRevoked(bytes32 indexed role, address indexed account, address indexed sender);
    
        /**
         * @dev Returns `true` if `account` has been granted `role`.
         */
        function hasRole(bytes32 role, address account) external view returns (bool);
    
        /**
         * @dev Returns the admin role that controls `role`. See {grantRole} and
         * {revokeRole}.
         *
         * To change a role's admin, use {AccessControl-_setRoleAdmin}.
         */
        function getRoleAdmin(bytes32 role) external view returns (bytes32);
    
        /**
         * @dev Grants `role` to `account`.
         *
         * If `account` had not been already granted `role`, emits a {RoleGranted}
         * event.
         *
         * Requirements:
         *
         * - the caller must have ``role``'s admin role.
         */
        function grantRole(bytes32 role, address account) external;
    
        /**
         * @dev Revokes `role` from `account`.
         *
         * If `account` had been granted `role`, emits a {RoleRevoked} event.
         *
         * Requirements:
         *
         * - the caller must have ``role``'s admin role.
         */
        function revokeRole(bytes32 role, address account) external;
    
        /**
         * @dev Revokes `role` from the calling account.
         *
         * Roles are often managed via {grantRole} and {revokeRole}: this function's
         * purpose is to provide a mechanism for accounts to lose their privileges
         * if they are compromised (such as when a trusted device is misplaced).
         *
         * If the calling account had been granted `role`, emits a {RoleRevoked}
         * event.
         *
         * Requirements:
         *
         * - the caller must be `callerConfirmation`.
         */
        function renounceRole(bytes32 role, address callerConfirmation) external;
    }
    
  • node_modules/@openzeppelin/contracts/token/ERC20/IERC20.sol
    // SPDX-License-Identifier: MIT
    // OpenZeppelin Contracts (last updated v5.1.0) (token/ERC20/IERC20.sol)
    
    pragma solidity ^0.8.20;
    
    /**
     * @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);
    }
    
  • node_modules/@openzeppelin/contracts/utils/Context.sol
    // 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;
        }
    }
    
  • node_modules/@openzeppelin/contracts/utils/introspection/ERC165.sol
    // SPDX-License-Identifier: MIT
    // OpenZeppelin Contracts (last updated v5.1.0) (utils/introspection/ERC165.sol)
    
    pragma solidity ^0.8.20;
    
    import {IERC165} from "./IERC165.sol";
    
    /**
     * @dev Implementation of the {IERC165} interface.
     *
     * Contracts that want to implement ERC-165 should inherit from this contract and override {supportsInterface} to check
     * for the additional interface id that will be supported. For example:
     *
     * ```solidity
     * function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {
     *     return interfaceId == type(MyInterface).interfaceId || super.supportsInterface(interfaceId);
     * }
     * ```
     */
    abstract contract ERC165 is IERC165 {
        /**
         * @dev See {IERC165-supportsInterface}.
         */
        function supportsInterface(bytes4 interfaceId) public view virtual returns (bool) {
            return interfaceId == type(IERC165).interfaceId;
        }
    }
    
  • node_modules/@openzeppelin/contracts/utils/introspection/IERC165.sol
    // SPDX-License-Identifier: MIT
    // OpenZeppelin Contracts (last updated v5.1.0) (utils/introspection/IERC165.sol)
    
    pragma solidity ^0.8.20;
    
    /**
     * @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);
    }
    
  • src/BrandedStablecoin/interfaces/IBrandedCustodian.sol
    // SPDX-License-Identifier: UNLICENSED
    pragma solidity ^0.8.4;
    
    interface IBrandedCustodian {
      error AmountTooHigh();
      error ERC4626ExceededMaxDeposit(address receiver, uint256 assets, uint256 max);
      error ERC4626ExceededMaxMint(address receiver, uint256 shares, uint256 max);
      error ERC4626ExceededMaxRedeem(address owner, uint256 shares, uint256 max);
      error ERC4626ExceededMaxWithdraw(address owner, uint256 assets, uint256 max);
      error InitializeFailed();
      error MintCapExceeded(address receiver, uint256 shares, uint256 mintCap);
      error NotOperator();
      error OwnableInvalidOwner(address owner);
      error OwnableUnauthorizedAccount(address account);
      error OwnerCannotInitToZeroAddress();
      error ReentrancyGuardReentrantCall();
      error SafeERC20FailedOperation(address token);
      error SlippageTooHigh();
      error TokenOwnerShouldBeSender();
    
      event Deposit(address indexed sender, address indexed owner, uint256 assets, uint256 shares);
      event MinAmountAfterShuffleSet(uint256 oldValue, uint256 newValue);
      event MintCapSet(uint256 mintCap);
      event OperatorStatusSet(address operator, bool status);
      event OwnershipTransferStarted(address indexed previousOwner, address indexed newOwner);
      event OwnershipTransferred(address indexed previousOwner, address indexed newOwner);
      event RecoveredERC20(address token, uint256 amount);
      event Withdraw(
        address indexed sender,
        address indexed receiver,
        address indexed owner,
        uint256 assets,
        uint256 shares
      );
      event custodianTknShuffledToRwa(uint256 custodianTknAmount, address targetRwa);
    
      function acceptOwnership() external;
      function asset() external view returns (address _custodianTkn);
      function balanceOf(address _addr) external view returns (uint256 _balance);
      function brandedCoinMinted() external view returns (uint256);
      function brandedStablecoin() external view returns (address);
      function brandedTknDecimals() external view returns (uint8);
      function convertToAssets(uint256 _shares) external view returns (uint256 _assets);
      function convertToShares(uint256 _assets) external view returns (uint256 _shares);
      function custodianTkn() external view returns (address);
      function custodianTknDecimals() external view returns (uint8);
      function deposit(uint256 _assetsIn, address _receiver) external returns (uint256 _sharesOut);
      function initialize(
        address _brandedCoin,
        address _owner,
        uint256 _mintCap,
        uint256 _mintFee,
        uint256 _redeemFee
      ) external;
      function isApprovedOperator(address) external view returns (bool);
      function maxDeposit(address _addr) external view returns (uint256 _maxAssetsIn);
      function maxMint(address _addr) external view returns (uint256 _maxSharesOut);
      function maxRedeem(address _owner) external view returns (uint256 _maxSharesIn);
      function maxWithdraw(address _owner) external view returns (uint256 _maxAssetsOut);
      function mdwrComboView()
        external
        view
        returns (
          uint256 _maxAssetsDepositable,
          uint256 _maxSharesMintable,
          uint256 _maxAssetsWithdrawable,
          uint256 _maxSharesRedeemable
        );
      function minAfterShuffle() external view returns (uint256);
      function mint(uint256 _sharesOut, address _receiver) external returns (uint256 _assetsIn);
      function mintCap() external view returns (uint256);
      function mintFee() external view returns (uint256);
      function owner() external view returns (address);
      function pendingOwner() external view returns (address);
      function previewDeposit(uint256 _assetsIn) external view returns (uint256 _sharesOut);
      function previewMint(uint256 _sharesOut) external view returns (uint256 _assetsIn);
      function previewRedeem(uint256 _sharesIn) external view returns (uint256 _assetsOut);
      function previewWithdraw(uint256 _assetsOut) external view returns (uint256 _sharesIn);
      function pricePerShare() external view returns (uint256 _pricePerShare);
      function recoverERC20(address _tokenAddress, uint256 _tokenAmount) external;
      function redeem(uint256 _sharesIn, address _receiver, address _owner) external returns (uint256 _assetsOut);
      function redeemFee() external view returns (uint256);
      function renounceOwnership() external;
      function setApprovedOperator(address _operator, bool _status) external;
      function setMinAfterShuffle(uint256 _minAfterShuffle) external;
      function setMintCap(uint256 _mintCap) external;
      function setMintRedeemFee(uint256 _mintFee, uint256 _redeemFee) external;
      function totalAssets() external view returns (uint256 _assets);
      function totalSupply() external view returns (uint256 _supply);
      function transferOwnership(address newOwner) external;
      function wasInitialized() external view returns (bool);
      function withdraw(uint256 _assetsOut, address _receiver, address _owner) external returns (uint256 _sharesIn);
    }
    
  • src/BrandedStablecoin/interfaces/IGDollar.sol
    // SPDX-License-Identifier: UNLICENSED
    pragma solidity ^0.8.4;
    
    interface IGDollar {
      error AccessControlBadConfirmation();
      error AccessControlUnauthorizedAccount(address account, bytes32 neededRole);
      error ERC20InsufficientAllowance(address spender, uint256 allowance, uint256 needed);
      error ERC20InsufficientBalance(address sender, uint256 balance, uint256 needed);
      error ERC20InvalidApprover(address approver);
      error ERC20InvalidReceiver(address receiver);
      error ERC20InvalidSender(address sender);
      error ERC20InvalidSpender(address spender);
      error ExpiredAuthorization();
      error InvalidAccountNonce(address account, uint256 currentNonce);
      error InvalidAuthorization();
      error InvalidInitialization();
      error InvalidPayee(address caller, address payee);
      error InvalidSignature();
      error NotInitializing();
      error UsedOrCanceledAuthorization();
    
      event Approval(address indexed owner, address indexed spender, uint256 value);
      event AuthorizationCanceled(address indexed authorizer, bytes32 indexed nonce);
      event AuthorizationUsed(address indexed authorizer, bytes32 indexed nonce);
      event EIP712DomainChanged();
      event Initialized(uint64 version);
      event RoleAdminChanged(bytes32 indexed role, bytes32 indexed previousAdminRole, bytes32 indexed newAdminRole);
      event RoleGranted(bytes32 indexed role, address indexed account, address indexed sender);
      event RoleRevoked(bytes32 indexed role, address indexed account, address indexed sender);
      event Transfer(address indexed from, address indexed to, uint256 value);
    
      function DOMAIN_SEPARATOR() external view returns (bytes32);
      function DEFAULT_ADMIN_ROLE() external view returns (bytes32);
      function FACTORY_ROLE() external view returns (bytes32);
      function MINTER_ROLE() external view returns (bytes32);
      function allowance(address owner, address spender) external view returns (uint256);
      function approve(address spender, uint256 value) external returns (bool);
      function authorizationState(address authorizer, bytes32 nonce) external view returns (bool);
      function balanceOf(address account) external view returns (uint256);
      function burn(uint256 value) external;
      function burnFrom(address account, uint256 value) external;
      function cancelAuthorization(address authorizer, bytes32 nonce, uint8 v, bytes32 r, bytes32 s) external;
      function cancelAuthorization(address authorizer, bytes32 nonce, bytes memory signature) external;
      function decimals() external view returns (uint8);
      function eip712Domain()
        external
        view
        returns (
          bytes1 fields,
          string memory name,
          string memory version,
          uint256 chainId,
          address verifyingContract,
          bytes32 salt,
          uint256[] memory extensions
        );
      function getRoleAdmin(bytes32 role) external view returns (bytes32);
      function grantRole(bytes32 role, address account) external;
      function hasRole(bytes32 role, address account) external view returns (bool);
      function initialize(string memory name, string memory symbol, address proxyAdminOwner) external;
      function mint(address account, uint256 value) external;
      function name() external view returns (string memory);
      function nonces(address owner) external view returns (uint256);
      function permit(address owner, address spender, uint256 value, uint256 deadline, bytes memory signature) external;
      function permit(
        address owner,
        address spender,
        uint256 value,
        uint256 deadline,
        uint8 v,
        bytes32 r,
        bytes32 s
      ) external;
      function receiveWithAuthorization(
        address from,
        address to,
        uint256 value,
        uint256 validAfter,
        uint256 validBefore,
        bytes32 nonce,
        bytes memory signature
      ) external;
      function receiveWithAuthorization(
        address from,
        address to,
        uint256 value,
        uint256 validAfter,
        uint256 validBefore,
        bytes32 nonce,
        uint8 v,
        bytes32 r,
        bytes32 s
      ) external;
      function renounceRole(bytes32 role, address callerConfirmation) external;
      function revokeRole(bytes32 role, address account) external;
      function supportsInterface(bytes4 interfaceId) external view returns (bool);
      function symbol() external view returns (string memory);
      function totalSupply() external view returns (uint256);
      function transfer(address to, uint256 value) external returns (bool);
      function transferFrom(address from, address to, uint256 value) external returns (bool);
      function transferWithAuthorization(
        address from,
        address to,
        uint256 value,
        uint256 validAfter,
        uint256 validBefore,
        bytes32 nonce,
        bytes memory signature
      ) external;
      function transferWithAuthorization(
        address from,
        address to,
        uint256 value,
        uint256 validAfter,
        uint256 validBefore,
        bytes32 nonce,
        uint8 v,
        bytes32 r,
        bytes32 s
      ) external;
    }
    
  • src/BrandedStablecoin/interfaces/ILzSend.sol
    // SPDX-License-Identifier: ISC
    pragma solidity ^0.8.19;
    
    interface ILZSend {
      struct SendParam {
        uint32 dstEid;
        bytes32 to;
        uint256 amountLD;
        uint256 minAmountLD;
        bytes extraOptions;
        bytes composeMsg;
        bytes oftCmd;
      }
    
      struct MessagingFee {
        uint256 nativeFee;
        uint256 lzTokenFee;
      }
    
      struct MessagingReceipt {
        bytes32 guid;
        uint64 nonce;
        MessagingFee fee;
      }
    
      struct OFTReceipt {
        uint256 amountSentLD;
        uint256 amountReceivedLD;
      }
    
      function quoteSend(SendParam calldata _sendParam, bool _payInLzToken) external view returns (MessagingFee memory);
    
      function send(
        SendParam calldata _sendParam,
        MessagingFee calldata _fee,
        address _refundAddress
      ) external payable returns (MessagingReceipt memory, OFTReceipt memory);
    }
    
  • src/BrandedStablecoin/interfaces/IRemoteHopV2.sol
    // SPDX-License-Identifier: UNLICENSED
    pragma solidity ^0.8.4;
    
    interface IRemoteHopV2 {
      struct MessagingFee {
        uint256 nativeFee;
        uint256 lzTokenFee;
      }
    
      error HopPaused();
      error InsufficientFee();
      error InvalidOFT();
      error InvalidOptionType(uint16 optionType);
      error InvalidSourceChain();
      error InvalidSourceHop();
      error NotEndpoint();
      error OwnableInvalidOwner(address owner);
      error OwnableUnauthorizedAccount(address account);
      error RefundFailed();
      error SafeCastOverflowedUintDowncast(uint8 bits, uint256 value);
      error SafeERC20FailedOperation(address token);
      error ZeroAmountSend();
    
      event Hop(address oft, address indexed recipient, uint256 amount);
      event MessageHash(address oft, uint64 indexed nonce, bytes32 indexed fraxtalHop);
      event OwnershipTransferStarted(address indexed previousOwner, address indexed newOwner);
      event OwnershipTransferred(address indexed previousOwner, address indexed newOwner);
      event SendOFT(address oft, address indexed sender, uint32 indexed dstEid, bytes32 indexed to, uint256 amountLD);
    
      receive() external payable;
    
      function DVN() external view returns (address);
      function EID() external view returns (uint32);
      function ENDPOINT() external view returns (address);
      function EXECUTOR() external view returns (address);
      function TREASURY() external view returns (address);
      function acceptOwnership() external;
      function approvedOft(address) external view returns (bool);
      function executorOptions(uint32) external view returns (bytes memory);
      function fraxtalHop() external view returns (bytes32);
      function hopFee() external view returns (uint256);
      function lzCompose(address _oft, bytes32, bytes memory _message, address, bytes memory) external payable;
      function messageProcessed(bytes32) external view returns (bool);
      function numDVNs() external view returns (uint256);
      function owner() external view returns (address);
      function pause(bool _paused) external;
      function paused() external view returns (bool);
      function pendingOwner() external view returns (address);
      function quote(
        address _oft,
        uint32 _dstEid,
        bytes32 _to,
        uint256 _amountLD,
        uint128 _composeGas,
        bytes memory _composeMsg
      ) external view returns (uint256 fee);
    
      function quoteHop(
        uint32 _dstEid,
        uint128 _composeGas,
        bytes memory _composeMsg
      ) external view returns (uint256 finalFee);
      function recoverERC20(address tokenAddress, address recipient, uint256 tokenAmount) external;
      function recoverETH(address recipient, uint256 tokenAmount) external;
      function renounceOwnership() external;
      function sendOFT(address _oft, uint32 _dstEid, bytes32 _to, uint256 _amountLD) external payable;
      function sendOFT(
        address _oft,
        uint32 _dstEid,
        bytes32 _to,
        uint256 _amountLD,
        uint128 _composeGas,
        bytes memory _composeMsg
      ) external payable;
      function setExecutorOptions(uint32 eid, bytes memory _options) external;
      function setFraxtalHop(address _fraxtalHop) external;
      function setFraxtalHop(bytes32 _fraxtalHop) external;
      function setHopFee(uint256 _hopFee) external;
      function setMessageProcessed(address oft, uint64 nonce, bytes32 fraxtalHop) external;
      function setNumDVNs(uint256 _numDVNs) external;
      function toggleOFTApproval(address _oft, bool _approved) external;
      function transferOwnership(address newOwner) external;
    }
    
  • src/interfaces/IFrxUSD.sol
    // SPDX-License-Identifier: UNLICENSED
    pragma solidity ^0.8.4;
    
    import { IERC20 } from "@openzeppelin/contracts/token/ERC20/IERC20.sol";
    
    interface IFrxUSD is IERC20 {
      error ArrayMisMatch();
      error ECDSAInvalidSignature();
      error ECDSAInvalidSignatureLength(uint256 length);
      error ECDSAInvalidSignatureS(bytes32 s);
      error ERC20InsufficientAllowance(address spender, uint256 allowance, uint256 needed);
      error ERC20InsufficientBalance(address sender, uint256 balance, uint256 needed);
      error ERC20InvalidApprover(address approver);
      error ERC20InvalidReceiver(address receiver);
      error ERC20InvalidSender(address sender);
      error ERC20InvalidSpender(address spender);
      error ERC2612ExpiredSignature(uint256 deadline);
      error ERC2612InvalidSigner(address signer, address owner);
      error InvalidAccountNonce(address account, uint256 currentNonce);
      error InvalidShortString();
      error IsFrozen();
      error IsPaused();
      error OwnableInvalidOwner(address owner);
      error OwnableUnauthorizedAccount(address account);
      error OwnerCannotInitToZeroAddress();
      error StringTooLong(string str);
    
      event AccountFrozen(address account);
      event AccountThawed(address account);
      event Burn(address indexed account, uint256 amount);
      event EIP712DomainChanged();
      event Mint(address indexed account, uint256 amount);
      event MinterAdded(address minter_address);
      event MinterRemoved(address minter_address);
      event OwnershipTransferStarted(address indexed previousOwner, address indexed newOwner);
      event OwnershipTransferred(address indexed previousOwner, address indexed newOwner);
      event Paused();
      event TokenMinterBurned(address indexed from, address indexed to, uint256 amount);
      event TokenMinterMinted(address indexed from, address indexed to, uint256 amount);
      event Unpaused();
    
      function DOMAIN_SEPARATOR() external view returns (bytes32);
      function acceptOwnership() external;
      function addMinter(address minter_address) external;
      function allowance(address owner, address spender) external view returns (uint256);
      function approve(address spender, uint256 value) external returns (bool);
      function balanceOf(address account) external view returns (uint256);
      function burn(uint256 value) external;
      function burn(address _owner, uint256 _amount) external;
      function burnFrom(address account, uint256 value) external;
      function burnMany(address[] memory _owners, uint256[] memory _amounts) external;
      function decimals() external view returns (uint8);
      function eip712Domain()
        external
        view
        returns (
          bytes1 fields,
          string memory name,
          string memory version,
          uint256 chainId,
          address verifyingContract,
          bytes32 salt,
          uint256[] memory extensions
        );
      function freeze(address _owner) external;
      function freezeMany(address[] memory _owners) external;
      function initialize(address _owner, string memory _name, string memory _symbol) external;
      function isFrozen(address) external view returns (bool);
      function isPaused() external view returns (bool);
      function minter_burn_from(address b_address, uint256 b_amount) external;
      function minter_mint(address m_address, uint256 m_amount) external;
      function minters(address) external view returns (bool);
      function minters_array(uint256) external view returns (address);
      function name() external view returns (string memory);
      function nonces(address owner) external view returns (uint256);
      function owner() external view returns (address);
      function pause() external;
      function pendingOwner() external view returns (address);
      function permit(
        address owner,
        address spender,
        uint256 value,
        uint256 deadline,
        uint8 v,
        bytes32 r,
        bytes32 s
      ) external;
      function removeMinter(address minter_address) external;
      function renounceOwnership() external;
      function symbol() external view returns (string memory);
      function thaw(address _owner) external;
      function thawMany(address[] memory _owners) external;
      function totalSupply() external view returns (uint256);
      function transfer(address to, uint256 value) external returns (bool);
      function transferFrom(address from, address to, uint256 value) external returns (bool);
      function transferOwnership(address newOwner) external;
      function unpause() external;
    }
    
ABI · 46 entries
json
[
  {
    "name": "AccessControlBadConfirmation",
    "type": "error",
    "inputs": []
  },
  {
    "name": "AccessControlUnauthorizedAccount",
    "type": "error",
    "inputs": [
      {
        "name": "account",
        "type": "address",
        "internalType": "address"
      },
      {
        "name": "neededRole",
        "type": "bytes32",
        "internalType": "bytes32"
      }
    ]
  },
  {
    "name": "AlreadyInitialized",
    "type": "error",
    "inputs": []
  },
  {
    "name": "InvalidOFT",
    "type": "error",
    "inputs": []
  },
  {
    "name": "InvalidSender",
    "type": "error",
    "inputs": []
  },
  {
    "name": "IsolatedBackingEnabled",
    "type": "error",
    "inputs": []
  },
  {
    "name": "MustBeEvmAddress",
    "type": "error",
    "inputs": []
  },
  {
    "name": "MustPayNative",
    "type": "error",
    "inputs": []
  },
  {
    "name": "NotFromRouter",
    "type": "error",
    "inputs": []
  },
  {
    "name": "NotSupported",
    "type": "error",
    "inputs": []
  },
  {
    "name": "RefundFailed",
    "type": "error",
    "inputs": []
  },
  {
    "name": "RefundMustBeSelf",
    "type": "error",
    "inputs": []
  },
  {
    "name": "SlippageExceeded",
    "type": "error",
    "inputs": [
      {
        "name": "",
        "type": "uint256",
        "internalType": "uint256"
      },
      {
        "name": "",
        "type": "uint256",
        "internalType": "uint256"
      }
    ]
  },
  {
    "name": "HopAddressUpdated",
    "type": "event",
    "inputs": [
      {
        "name": "oldHopAddress",
        "type": "address",
        "indexed": false,
        "internalType": "address"
      },
      {
        "name": "newHopAddress",
        "type": "address",
        "indexed": false,
        "internalType": "address"
      }
    ],
    "anonymous": false
  },
  {
    "name": "NonDeterministicAddressSet",
    "type": "event",
    "inputs": [
      {
        "name": "eid",
        "type": "uint32",
        "indexed": false,
        "internalType": "uint32"
      },
      {
        "name": "router",
        "type": "bytes32",
        "indexed": false,
        "internalType": "bytes32"
      }
    ],
    "anonymous": false
  },
  {
    "name": "RoleAdminChanged",
    "type": "event",
    "inputs": [
      {
        "name": "role",
        "type": "bytes32",
        "indexed": true,
        "internalType": "bytes32"
      },
      {
        "name": "previousAdminRole",
        "type": "bytes32",
        "indexed": true,
        "internalType": "bytes32"
      },
      {
        "name": "newAdminRole",
        "type": "bytes32",
        "indexed": true,
        "internalType": "bytes32"
      }
    ],
    "anonymous": false
  },
  {
    "name": "RoleGranted",
    "type": "event",
    "inputs": [
      {
        "name": "role",
        "type": "bytes32",
        "indexed": true,
        "internalType": "bytes32"
      },
      {
        "name": "account",
        "type": "address",
        "indexed": true,
        "internalType": "address"
      },
      {
        "name": "sender",
        "type": "address",
        "indexed": true,
        "internalType": "address"
      }
    ],
    "anonymous": false
  },
  {
    "name": "RoleRevoked",
    "type": "event",
    "inputs": [
      {
        "name": "role",
        "type": "bytes32",
        "indexed": true,
        "internalType": "bytes32"
      },
      {
        "name": "account",
        "type": "address",
        "indexed": true,
        "internalType": "address"
      },
      {
        "name": "sender",
        "type": "address",
        "indexed": true,
        "internalType": "address"
      }
    ],
    "anonymous": false
  },
  {
    "name": "DEFAULT_ADMIN_ROLE",
    "type": "function",
    "inputs": [],
    "outputs": [
      {
        "name": "",
        "type": "bytes32",
        "internalType": "bytes32"
      }
    ],
    "stateMutability": "view"
  },
  {
    "name": "GLOBAL_COMPOSE_GAS",
    "type": "function",
    "inputs": [],
    "outputs": [
      {
        "name": "",
        "type": "uint128",
        "internalType": "uint128"
      }
    ],
    "stateMutability": "view"
  },
  {
    "name": "RELAYER_ROLE",
    "type": "function",
    "inputs": [],
    "outputs": [
      {
        "name": "",
        "type": "bytes32",
        "internalType": "bytes32"
      }
    ],
    "stateMutability": "view"
  },
  {
    "name": "SOMNIA_COMPOSE_GAS",
    "type": "function",
    "inputs": [],
    "outputs": [
      {
        "name": "",
        "type": "uint128",
        "internalType": "uint128"
      }
    ],
    "stateMutability": "view"
  },
  {
    "name": "coin",
    "type": "function",
    "inputs": [],
    "outputs": [
      {
        "name": "",
        "type": "address",
        "internalType": "contract IGDollar"
      }
    ],
    "stateMutability": "view"
  },
  {
    "name": "custodian",
    "type": "function",
    "inputs": [],
    "outputs": [
      {
        "name": "",
        "type": "address",
        "internalType": "contract IBrandedCustodian"
      }
    ],
    "stateMutability": "view"
  },
  {
    "name": "eidToNonDeterministicAddress",
    "type": "function",
    "inputs": [
      {
        "name": "",
        "type": "uint32",
        "internalType": "uint32"
      }
    ],
    "outputs": [
      {
        "name": "",
        "type": "bytes32",
        "internalType": "bytes32"
      }
    ],
    "stateMutability": "view"
  },
  {
    "name": "frxusd",
    "type": "function",
    "inputs": [],
    "outputs": [
      {
        "name": "",
        "type": "address",
        "internalType": "contract IFrxUSD"
      }
    ],
    "stateMutability": "view"
  },
  {
    "name": "getRoleAdmin",
    "type": "function",
    "inputs": [
      {
        "name": "role",
        "type": "bytes32",
        "internalType": "bytes32"
      }
    ],
    "outputs": [
      {
        "name": "",
        "type": "bytes32",
        "internalType": "bytes32"
      }
    ],
    "stateMutability": "view"
  },
  {
    "name": "grantRole",
    "type": "function",
    "inputs": [
      {
        "name": "role",
        "type": "bytes32",
        "internalType": "bytes32"
      },
      {
        "name": "account",
        "type": "address",
        "internalType": "address"
      }
    ],
    "outputs": [],
    "stateMutability": "nonpayable"
  },
  {
    "name": "hasRole",
    "type": "function",
    "inputs": [
      {
        "name": "role",
        "type": "bytes32",
        "internalType": "bytes32"
      },
      {
        "name": "account",
        "type": "address",
        "internalType": "address"
      }
    ],
    "outputs": [
      {
        "name": "",
        "type": "bool",
        "internalType": "bool"
      }
    ],
    "stateMutability": "view"
  },
  {
    "name": "hopCompose",
    "type": "function",
    "inputs": [
      {
        "name": "srcEid",
        "type": "uint32",
        "internalType": "uint32"
      },
      {
        "name": "sender",
        "type": "bytes32",
        "internalType": "bytes32"
      },
      {
        "name": "oft",
        "type": "address",
        "internalType": "address"
      },
      {
        "name": "_amount",
        "type": "uint256",
        "internalType": "uint256"
      },
      {
        "name": "data",
        "type": "bytes",
        "internalType": "bytes"
      }
    ],
    "outputs": [],
    "stateMutability": "nonpayable"
  },
  {
    "name": "initialize",
    "type": "function",
    "inputs": [
      {
        "name": "_owner",
        "type": "address",
        "internalType": "address"
      },
      {
        "name": "_custodianAddress",
        "type": "address",
        "internalType": "address"
      },
      {
        "name": "_coin",
        "type": "address",
        "internalType": "address"
      },
      {
        "name": "_localFrxUSD",
        "type": "address",
        "internalType": "address"
      },
      {
        "name": "_localRemoteHop",
        "type": "address",
        "internalType": "address"
      },
      {
        "name": "_isolatedBackingEnabled",
        "type": "bool",
        "internalType": "bool"
      }
    ],
    "outputs": [],
    "stateMutability": "nonpayable"
  },
  {
    "name": "isolatedBackingEnabled",
    "type": "function",
    "inputs": [],
    "outputs": [
      {
        "name": "",
        "type": "bool",
        "internalType": "bool"
      }
    ],
    "stateMutability": "view"
  },
  {
    "name": "mintAndSend",
    "type": "function",
    "inputs": [
      {
        "name": "dstEid",
        "type": "uint32",
        "internalType": "uint32"
      },
      {
        "name": "recipient",
        "type": "address",
        "internalType": "address"
      },
      {
        "name": "amount",
        "type": "uint256",
        "internalType": "uint256"
      }
    ],
    "outputs": [
      {
        "name": "out",
        "type": "uint256",
        "internalType": "uint256"
      }
    ],
    "stateMutability": "payable"
  },
  {
    "name": "oftLocal",
    "type": "function",
    "inputs": [],
    "outputs": [
      {
        "name": "",
        "type": "address",
        "internalType": "address"
      }
    ],
    "stateMutability": "view"
  },
  {
    "name": "quote",
    "type": "function",
    "inputs": [
      {
        "name": "dstEid",
        "type": "uint32",
        "internalType": "uint32"
      },
      {
        "name": "recipient",
        "type": "address",
        "internalType": "address"
      },
      {
        "name": "amount",
        "type": "uint256",
        "internalType": "uint256"
      }
    ],
    "outputs": [
      {
        "name": "",
        "type": "uint256",
        "internalType": "uint256"
      }
    ],
    "stateMutability": "view"
  },
  {
    "name": "quoteSend",
    "type": "function",
    "inputs": [
      {
        "name": "_sendParam",
        "type": "tuple",
        "components": [
          {
            "name": "dstEid",
            "type": "uint32",
            "internalType": "uint32"
          },
          {
            "name": "to",
            "type": "bytes32",
            "internalType": "bytes32"
          },
          {
            "name": "amountLD",
            "type": "uint256",
            "internalType": "uint256"
          },
          {
            "name": "minAmountLD",
            "type": "uint256",
            "internalType": "uint256"
          },
          {
            "name": "extraOptions",
            "type": "bytes",
            "internalType": "bytes"
          },
          {
            "name": "composeMsg",
            "type": "bytes",
            "internalType": "bytes"
          },
          {
            "name": "oftCmd",
            "type": "bytes",
            "internalType": "bytes"
          }
        ],
        "internalType": "struct ILZSend.SendParam"
      },
      {
        "name": "_payInLzToken",
        "type": "bool",
        "internalType": "bool"
      }
    ],
    "outputs": [
      {
        "name": "",
        "type": "tuple",
        "components": [
          {
            "name": "nativeFee",
            "type": "uint256",
            "internalType": "uint256"
          },
          {
            "name": "lzTokenFee",
            "type": "uint256",
            "internalType": "uint256"
          }
        ],
        "internalType": "struct ILZSend.MessagingFee"
      }
    ],
    "stateMutability": "view"
  },
  {
    "name": "remoteHopV2",
    "type": "function",
    "inputs": [],
    "outputs": [
      {
        "name": "",
        "type": "address",
        "internalType": "contract IRemoteHopV2"
      }
    ],
    "stateMutability": "view"
  },
  {
    "name": "renounceRole",
    "type": "function",
    "inputs": [
      {
        "name": "role",
        "type": "bytes32",
        "internalType": "bytes32"
      },
      {
        "name": "callerConfirmation",
        "type": "address",
        "internalType": "address"
      }
    ],
    "outputs": [],
    "stateMutability": "nonpayable"
  },
  {
    "name": "revokeRole",
    "type": "function",
    "inputs": [
      {
        "name": "role",
        "type": "bytes32",
        "internalType": "bytes32"
      },
      {
        "name": "account",
        "type": "address",
        "internalType": "address"
      }
    ],
    "outputs": [],
    "stateMutability": "nonpayable"
  },
  {
    "name": "send",
    "type": "function",
    "inputs": [
      {
        "name": "_sendParam",
        "type": "tuple",
        "components": [
          {
            "name": "dstEid",
            "type": "uint32",
            "internalType": "uint32"
          },
          {
            "name": "to",
            "type": "bytes32",
            "internalType": "bytes32"
          },
          {
            "name": "amountLD",
            "type": "uint256",
            "internalType": "uint256"
          },
          {
            "name": "minAmountLD",
            "type": "uint256",
            "internalType": "uint256"
          },
          {
            "name": "extraOptions",
            "type": "bytes",
            "internalType": "bytes"
          },
          {
            "name": "composeMsg",
            "type": "bytes",
            "internalType": "bytes"
          },
          {
            "name": "oftCmd",
            "type": "bytes",
            "internalType": "bytes"
          }
        ],
        "internalType": "struct ILZSend.SendParam"
      },
      {
        "name": "_fee",
        "type": "tuple",
        "components": [
          {
            "name": "nativeFee",
            "type": "uint256",
            "internalType": "uint256"
          },
          {
            "name": "lzTokenFee",
            "type": "uint256",
            "internalType": "uint256"
          }
        ],
        "internalType": "struct ILZSend.MessagingFee"
      },
      {
        "name": "_refundAddress",
        "type": "address",
        "internalType": "address"
      }
    ],
    "outputs": [
      {
        "name": "",
        "type": "tuple",
        "components": [
          {
            "name": "guid",
            "type": "bytes32",
            "internalType": "bytes32"
          },
          {
            "name": "nonce",
            "type": "uint64",
            "internalType": "uint64"
          },
          {
            "name": "fee",
            "type": "tuple",
            "components": [
              {
                "name": "nativeFee",
                "type": "uint256",
                "internalType": "uint256"
              },
              {
                "name": "lzTokenFee",
                "type": "uint256",
                "internalType": "uint256"
              }
            ],
            "internalType": "struct ILZSend.MessagingFee"
          }
        ],
        "internalType": "struct ILZSend.MessagingReceipt"
      },
      {
        "name": "",
        "type": "tuple",
        "components": [
          {
            "name": "amountSentLD",
            "type": "uint256",
            "internalType": "uint256"
          },
          {
            "name": "amountReceivedLD",
            "type": "uint256",
            "internalType": "uint256"
          }
        ],
        "internalType": "struct ILZSend.OFTReceipt"
      }
    ],
    "stateMutability": "payable"
  },
  {
    "name": "send",
    "type": "function",
    "inputs": [
      {
        "name": "dstEid",
        "type": "uint32",
        "internalType": "uint32"
      },
      {
        "name": "recipient",
        "type": "address",
        "internalType": "address"
      },
      {
        "name": "amount",
        "type": "uint256",
        "internalType": "uint256"
      }
    ],
    "outputs": [],
    "stateMutability": "payable"
  },
  {
    "name": "setHopV2Address",
    "type": "function",
    "inputs": [
      {
        "name": "_updatedAddress",
        "type": "address",
        "internalType": "address"
      }
    ],
    "outputs": [],
    "stateMutability": "nonpayable"
  },
  {
    "name": "setNonDeterministicRouterAddress",
    "type": "function",
    "inputs": [
      {
        "name": "eid",
        "type": "uint32",
        "internalType": "uint32"
      },
      {
        "name": "value",
        "type": "bytes32",
        "internalType": "bytes32"
      }
    ],
    "outputs": [],
    "stateMutability": "nonpayable"
  },
  {
    "name": "supportsInterface",
    "type": "function",
    "inputs": [
      {
        "name": "interfaceId",
        "type": "bytes4",
        "internalType": "bytes4"
      }
    ],
    "outputs": [
      {
        "name": "",
        "type": "bool",
        "internalType": "bool"
      }
    ],
    "stateMutability": "view"
  },
  {
    "name": "wasInitialized",
    "type": "function",
    "inputs": [],
    "outputs": [
      {
        "name": "",
        "type": "bool",
        "internalType": "bool"
      }
    ],
    "stateMutability": "view"
  },
  {
    "type": "receive",
    "stateMutability": "payable"
  }
]