Sonic Blaze Testnet

Contract

0x3BD6128Aa20E68933CDB2E8691BBeEc060166C06

Overview

S Balance

Sonic Blaze LogoSonic Blaze LogoSonic Blaze Logo0 S

Multichain Info

No addresses found
Transaction Hash
Method
Block
From
To

There are no matching entries

Please try again later

Parent Transaction Hash Block From To
View All Internal Transactions
Loading...
Loading

Similar Match Source Code
This contract matches the deployed Bytecode of the Source Code for Contract 0x3D13F94B...b7213Bc9A
The constructor portion of the code might be different and could alter the actual behaviour of the contract

Contract Name:
FeeRecipientFactory

Compiler Version
v0.8.28+commit.7893614a

Optimization Enabled:
Yes with 100 runs

Other Settings:
cancun EvmVersion

Contract Source Code (Solidity Standard Json-Input format)

File 1 of 7 : FeeRecipientFactory.sol
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.26;

import {IFeeRecipientFactory} from "../interfaces/IFeeRecipientFactory.sol";
import {FeeRecipient} from "./../FeeRecipient.sol";

contract FeeRecipientFactory is IFeeRecipientFactory {
    /// @inheritdoc IFeeRecipientFactory
    address public lastFeeRecipient;

    /// @inheritdoc IFeeRecipientFactory
    address public treasury;

    address public accessHub;

    address public immutable voter;

    /// @inheritdoc IFeeRecipientFactory
    uint256 public feeToTreasury;

    /// @inheritdoc IFeeRecipientFactory
    mapping(address pair => address feeRecipient) public feeRecipientForPair;

    event SetFeeToTreasury(uint256 indexed feeToTreasury);

    modifier onlyGovernance() {
        require(msg.sender == accessHub);
        _;
    }

    constructor(address _treasury, address _voter, address _accessHub) {
        treasury = _treasury;
        voter = _voter;
        accessHub = _accessHub;
        /// @dev start at 8%
        feeToTreasury = 800;
    }
    /// @inheritdoc IFeeRecipientFactory
    function createFeeRecipient(
        address pair
    ) external returns (address _feeRecipient) {
        /// @dev ensure caller is the voter
        require(msg.sender == voter, NOT_AUTHORIZED());
        /// @dev create a new feeRecipient
        _feeRecipient = address(
            new FeeRecipient(pair, msg.sender, address(this))
        );
        /// @dev dont need to ensure that a feeRecipient wasn't already made previously
        feeRecipientForPair[pair] = _feeRecipient;
        lastFeeRecipient = _feeRecipient;
    }
    /// @inheritdoc IFeeRecipientFactory
    function setFeeToTreasury(uint256 _feeToTreasury) external onlyGovernance {
        /// @dev ensure fee to treasury isn't too high
        require(_feeToTreasury <= 10_000, INVALID_TREASURY_FEE());
        feeToTreasury = _feeToTreasury;
        emit SetFeeToTreasury(_feeToTreasury);
    }

    /// @inheritdoc IFeeRecipientFactory
    function setTreasury(address _treasury) external onlyGovernance {
        treasury = _treasury;
    }
}

File 2 of 7 : IFeeRecipientFactory.sol
// SPDX-License-Identifier: GPL-2.0-or-later
pragma solidity ^0.8.26;

interface IFeeRecipientFactory {
    error INVALID_TREASURY_FEE();
    error NOT_AUTHORIZED();

    /// @notice the pair fees for a specific pair
    /// @param pair the pair to check
    /// @return feeRecipient the feeRecipient contract address for the pair
    function feeRecipientForPair(
        address pair
    ) external view returns (address feeRecipient);

    /// @notice the last feeRecipient address created
    /// @return _feeRecipient the address of the last pair fees contract
    function lastFeeRecipient() external view returns (address _feeRecipient);
    /// @notice create the pair fees for a pair
    /// @param pair the address of the pair
    /// @return _feeRecipient the address of the newly created feeRecipient
    function createFeeRecipient(
        address pair
    ) external returns (address _feeRecipient);

    /// @notice the fee % going to the treasury
    /// @return _feeToTreasury the fee %
    function feeToTreasury() external view returns (uint256 _feeToTreasury);

    /// @notice get the treasury address
    /// @return _treasury address of the treasury
    function treasury() external view returns (address _treasury);

    /// @notice set the fee % to be sent to the treasury
    /// @param _feeToTreasury the fee % to be sent to the treasury
    function setFeeToTreasury(uint256 _feeToTreasury) external;

    /// @notice set a new treasury address
    /// @param _treasury the new address
    function setTreasury(address _treasury) external;
}

File 3 of 7 : FeeRecipient.sol
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.26;

import {IERC20} from "@openzeppelin/contracts/interfaces/IERC20.sol";
import {IFeeDistributor} from "./interfaces/IFeeDistributor.sol";
import {IFeeRecipient} from "./interfaces/IFeeRecipient.sol";
import {IFeeRecipientFactory} from "./interfaces/IFeeRecipientFactory.sol";

/// @notice Pair Fees contract is used as a 1:1 pair relationship to split out fees, this ensures that the curve does not need to be modified for LP shares
contract FeeRecipient is IFeeRecipient {
    /// @notice The pair it is bonded to
    address public immutable pair;
    /// @notice voter contract which fees are gated to be claimed by
    address public immutable voter;
    /// @notice feedist contract where fees will be sent to
    address public feeDistributor;
    /// @notice factory contract for feeRecipient (legacy fees)
    address public immutable feeRecipientFactory;

    constructor(address _pair, address _voter, address _feeRecipientFactory) {
        pair = _pair;
        voter = _voter;
        feeRecipientFactory = _feeRecipientFactory;
    }

    /// @notice initialize the FeeRecipient contract and approve the LP tokens to the feeDist, gated to voter
    function initialize(address _feeDistributor) external {
        require(msg.sender == voter, NOT_AUTHORIZED());
        feeDistributor = _feeDistributor;
        IERC20(pair).approve(_feeDistributor, type(uint256).max);
    }

    /// @notice notifies the fees
    function notifyFees() external {
        /// @dev limit calling notifyFees() to the voter contract
        require(msg.sender == voter, NOT_AUTHORIZED());

        /// @dev fetch balance of LP in the contract
        uint256 amount = IERC20(pair).balanceOf(address(this));
        /// @dev terminate early if there's no rewards
        if (amount == 0) return;
        /// @dev calculate treasury share
        uint256 feeToTreasury = IFeeRecipientFactory(feeRecipientFactory)
            .feeToTreasury();
        /// @dev if any to treasury
        if (feeToTreasury > 0) {
            /// @dev fetch treasury from factory
            address treasury = IFeeRecipientFactory(feeRecipientFactory)
                .treasury();
            /// @dev mulDiv
            uint256 amountToTreasury = (amount * feeToTreasury) / 10_000;
            /// @dev decrement amount
            amount -= amountToTreasury;
            /// @dev naked transfer to treasury, no staking
            IERC20(pair).transfer(treasury, amountToTreasury);
        }

        /// @dev if there's any fees
        if (amount > 0) {
            IFeeDistributor(feeDistributor).notifyRewardAmount(pair, amount);
        }
    }
}

File 4 of 7 : IERC20.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (interfaces/IERC20.sol)

pragma solidity ^0.8.20;

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

File 5 of 7 : IFeeDistributor.sol
// SPDX-License-Identifier: BUSL-1.1
pragma solidity ^0.8.26;

interface IFeeDistributor {
    error NOT_AUTHORIZED();
    error ZERO_AMOUNT();
    error NOT_FINALIZED();
    error TOKEN_ERROR(address);

    event Deposit(address owner, uint256 amount);

    event Withdraw(address owner, uint256 amount);

    event NotifyReward(
        address indexed from,
        address indexed reward,
        uint256 amount,
        uint256 period
    );

    event VotesIncentivized(
        address indexed from,
        address indexed reward,
        uint256 amount,
        uint256 period
    );

    event ClaimRewards(
        uint256 period,
        address owner,
        address receiver,
        address reward,
        uint256 amount
    );

    event RewardsRemoved(address _reward);
    /// @notice the address of the voter contract
    function voter() external view returns (address);
    /// @notice the address of the voting module
    function voteModule() external view returns (address);
    /// @notice the address of the feeRecipient contract
    function feeRecipient() external view returns (address);

    /// @notice the first period (epoch) that this contract was deployed
    function firstPeriod() external view returns (uint256);

    /// @notice balance of the voting power for a user
    /// @param owner the owner
    /// @return amount the amount of voting share
    function balanceOf(address owner) external view returns (uint256 amount);

    /// @notice total cumulative amount of voting power per epoch
    /// @param period the period to check
    /// @return weight the amount of total voting power
    function votes(uint256 period) external view returns (uint256 weight);

    /// @notice "internal" function gated to voter to add votes
    /// @dev internal notation inherited from original solidly, kept for continuity
    function _deposit(uint256 amount, address owner) external;
    /// @notice "internal" function gated to voter to remove votes
    /// @dev internal notation inherited from original solidly, kept for continuity
    function _withdraw(uint256 amount, address owner) external;

    /// @notice function to claim rewards on behalf of another
    /// @param owner owner's address
    /// @param tokens an array of the tokens
    function getRewardForOwner(address owner, address[] memory tokens) external;

    /// @notice function for sending fees directly to be claimable (in system where fees are distro'd through the week)
    /// @dev for lumpsum - this would operate similarly to incentivize
    /// @param token the address of the token to send for notifying
    /// @param amount the amount of token to send
    function notifyRewardAmount(address token, uint256 amount) external;

    /// @notice gives an array of reward tokens for the feedist
    /// @return _rewards array of rewards
    function getRewardTokens()
        external
        view
        returns (address[] memory _rewards);

    /// @notice shows the earned incentives in the feedist
    /// @param token the token address to check
    /// @param owner owner's address
    /// @return reward the amount earned/claimable
    function earned(
        address token,
        address owner
    ) external view returns (uint256 reward);

    /// @notice function to submit incentives to voters for the upcoming flip
    /// @param token the address of the token to send for incentivization
    /// @param amount the amount of token to send
    function incentivize(address token, uint256 amount) external;

    /// @notice get the rewards for a specific period
    /// @param owner owner's address
    function getPeriodReward(
        uint256 period,
        address owner,
        address token
    ) external;
    /// @notice get the fees and incentives
    function getReward(address owner, address[] memory tokens) external;

    /// @notice remove a reward from the set
    function removeReward(address _token) external;
}

File 6 of 7 : IFeeRecipient.sol
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.26;

interface IFeeRecipient {
    error STF();
    error NOT_AUTHORIZED();
    
    function initialize(address _feeDistributor) external;
    function notifyFees() external;
}

File 7 of 7 : 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);
}

Settings
{
  "remappings": [
    "@openzeppelin-contracts-upgradeable-5.1.0/=dependencies/@openzeppelin-contracts-upgradeable-5.1.0/",
    "@openzeppelin/contracts/=dependencies/@openzeppelin-contracts-5.1.0/",
    "forge-std/=dependencies/forge-std-1.9.4/src/",
    "permit2/=lib/permit2/",
    "@openzeppelin-3.4.2/=node_modules/@openzeppelin-3.4.2/",
    "@openzeppelin-contracts-5.1.0/=dependencies/@openzeppelin-contracts-5.1.0/",
    "@uniswap/=node_modules/@uniswap/",
    "base64-sol/=node_modules/base64-sol/",
    "eth-gas-reporter/=node_modules/eth-gas-reporter/",
    "forge-std-1.9.4/=dependencies/forge-std-1.9.4/src/",
    "hardhat/=node_modules/hardhat/",
    "solmate/=node_modules/solmate/"
  ],
  "optimizer": {
    "enabled": true,
    "runs": 100
  },
  "metadata": {
    "useLiteralContent": false,
    "bytecodeHash": "ipfs",
    "appendCBOR": true
  },
  "outputSelection": {
    "*": {
      "*": [
        "evm.bytecode",
        "evm.deployedBytecode",
        "devdoc",
        "userdoc",
        "metadata",
        "abi"
      ]
    }
  },
  "evmVersion": "cancun",
  "viaIR": true,
  "libraries": {}
}

Contract ABI

[{"inputs":[{"internalType":"address","name":"_treasury","type":"address"},{"internalType":"address","name":"_voter","type":"address"},{"internalType":"address","name":"_accessHub","type":"address"}],"stateMutability":"nonpayable","type":"constructor"},{"inputs":[],"name":"INVALID_TREASURY_FEE","type":"error"},{"inputs":[],"name":"NOT_AUTHORIZED","type":"error"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"feeToTreasury","type":"uint256"}],"name":"SetFeeToTreasury","type":"event"},{"inputs":[],"name":"accessHub","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"pair","type":"address"}],"name":"createFeeRecipient","outputs":[{"internalType":"address","name":"_feeRecipient","type":"address"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"pair","type":"address"}],"name":"feeRecipientForPair","outputs":[{"internalType":"address","name":"feeRecipient","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"feeToTreasury","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"lastFeeRecipient","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_feeToTreasury","type":"uint256"}],"name":"setFeeToTreasury","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_treasury","type":"address"}],"name":"setTreasury","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"treasury","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"voter","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"}]

Deployed Bytecode

0x60806040526004361015610011575f80fd5b5f3560e01c8063019494b3146102ef57806311474d5a146102ab5780631fb45e31146101a6578063361ad73f1461017f57806346c96aac1461013b57806361d027b314610113578063c2ab8766146100f6578063e7589b39146100ce5763f0f442601461007c575f80fd5b346100ca5760203660031901126100ca576004356001600160a01b038116908190036100ca576002546001600160a01b031633036100ca57600180546001600160a01b031916919091179055005b5f80fd5b346100ca575f3660031901126100ca576002546040516001600160a01b039091168152602090f35b346100ca575f3660031901126100ca576020600354604051908152f35b346100ca575f3660031901126100ca576001546040516001600160a01b039091168152602090f35b346100ca575f3660031901126100ca576040517f000000000000000000000000457214de3f942c0e3dd83ea5708f729c7fae44bd6001600160a01b03168152602090f35b346100ca575f3660031901126100ca575f546040516001600160a01b039091168152602090f35b346100ca5760203660031901126100ca576004356001600160a01b038116908190036100ca577f000000000000000000000000457214de3f942c0e3dd83ea5708f729c7fae44bd6001600160a01b0316330361029c576040516106938082019082821067ffffffffffffffff83111761028857606091839161035983398481523360208201523060408201520301905ff090811561027d575f90815260046020908152604080832080546001600160a01b03199081166001600160a01b039096169586179091558354168417909255905191825290f35b6040513d5f823e3d90fd5b634e487b7160e01b5f52604160045260245ffd5b633d83866f60e01b5f5260045ffd5b346100ca5760203660031901126100ca576004356001600160a01b038116908190036100ca575f526004602052602060018060a01b0360405f205416604051908152f35b346100ca5760203660031901126100ca57600254600435906001600160a01b031633036100ca57612710811161034957806003557ff8ddd90671ef7e65d8f84857bb0e433895a9e3095157d82099594f779060c69a5f80a2005b6324242f7360e21b5f5260045ffdfe60e0346100b557601f61069338819003918201601f19168301916001600160401b038311848410176100b9578084926060946040528339810103126100b557610047816100cd565b906100606040610059602084016100cd565b92016100cd565b9160805260a05260c0526040516105b190816100e28239608051818181610135015281816101c40152610304015260a05181818160ce0152818161022001526102c1015260c0518181816073015261035b0152f35b5f80fd5b634e487b7160e01b5f52604160045260245ffd5b51906001600160a01b03821682036100b55756fe6080806040526004361015610012575f80fd5b5f3560e01c9081630d43e8ad1461024f5750806346c96aac1461020b5780634c4f2a95146101f3578063a8aa1b31146101af578063c4d66de8146100a65763d32af6c11461005e575f80fd5b346100a2575f3660031901126100a2576040517f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03168152602090f35b5f80fd5b346100a25760203660031901126100a2576004356001600160a01b038116908190036100a2577f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031633036101a0575f80546001600160a01b0319168217815560405163095ea7b360e01b815260048101929092525f196024830152602090829060449082907f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03165af180156101955761016b57005b61018c9060203d60201161018e575b6101848183610271565b8101906102a7565b005b503d61017a565b6040513d5f823e3d90fd5b633d83866f60e01b5f5260045ffd5b346100a2575f3660031901126100a2576040517f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03168152602090f35b346100a2575f3660031901126100a25761018c6102bf565b346100a2575f3660031901126100a2576040517f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03168152602090f35b346100a2575f3660031901126100a2575f546001600160a01b03168152602090f35b90601f8019910116810190811067ffffffffffffffff82111761029357604052565b634e487b7160e01b5f52604160045260245ffd5b908160209103126100a2575180151581036100a25790565b7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031633036101a0576040516370a0823160e01b81523060048201527f00000000000000000000000000000000000000000000000000000000000000006001600160a01b038116602083602481845afa928315610195575f93610547575b5082801561054157604051636155c3b360e11b81527f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316602082600481845afa918215610195575f9261050d575b508161040b575b50505050816103ae575050565b5f546001600160a01b031691823b156100a25760405163b66503cf60e01b81526001600160a01b039290921660048301526024820152905f908290604490829084905af18015610195576103ff5750565b5f61040991610271565b565b6040516361d027b360e01b81529550602090869060049082905afa948515610195575f956104c9575b5080820290828204036104b55761271090048082039182116104b55760405163a9059cbb60e01b81526001600160a01b0395909516600486015260248501529290602090829060449082905f905af1801561019557610496575b8080806103a1565b6104ae9060203d60201161018e576101848183610271565b505f61048e565b634e487b7160e01b5f52601160045260245ffd5b9094506020813d602011610505575b816104e560209383610271565b810103126100a257516001600160a01b03811681036100a257935f610434565b3d91506104d8565b9091506020813d602011610539575b8161052960209383610271565b810103126100a25751905f61039a565b3d915061051c565b50505050565b9092506020813d602011610573575b8161056360209383610271565b810103126100a25751915f610344565b3d915061055656fea2646970667358221220329fcbce2231c1ba895b5bb52380441ef426840fa31b47b26465aedd8dbfae3164736f6c634300081c0033a2646970667358221220a497ecdcbe7148c1edc5afe41717661509ebdac0fd0eb24d40a052615c98b7b464736f6c634300081c0033

Block Transaction Gas Used Reward
view all blocks produced

Block Uncle Number Difficulty Gas Used Reward
View All Uncles
Loading...
Loading
Loading...
Loading

Validator Index Block Amount
View All Withdrawals

Transaction Hash Block Value Eth2 PubKey Valid
View All Deposits

A contract address hosts a smart contract, which is a set of code stored on the blockchain that runs when predetermined conditions are met. Learn more about addresses in our Knowledge Base.