Cryo Explorer Ethereum Mainnet

Address Contract Partially Verified

Address 0xC700000506423Bad12d5EB6D55b35EA9F5384Df6
Balance 0 ETH
Nonce 1
Code Size 5663 bytes
Indexed Transactions 0
External Etherscan · Sourcify

Contract Bytecode

5663 bytes
0x6080806040526004361015610012575f80fd5b5f3560e01c9081630d2aa245146105a75750806322d083211461058b578063249d39e91461056f57806357d775f814610535578063647846a5146104f157806365401e64146104a35780636cbdec7d14610456578063757991a8146103e8578063767bc1bf146102a757806378e979251461026d5780637b103999146102295780638da5cb5b14610114578063d42553c814610172578063e4fc6b6d14610158578063f2f4eb26146101145763fa443b53146100cc575f80fd5b34610110575f366003190112610110576040517f0000000000000000000000001099370bd8e48dd79a703f12ef59168c6ef8ad036001600160a01b03168152602090f35b5f80fd5b34610110575f366003190112610110576040517f000000000000000000000000c07e000044f95655c11fda4cd37f70a94d7e0a7d6001600160a01b03168152602090f35b34610110575f366003190112610110576101706107b0565b005b34610110576020366003190112610110576004356101ba337f000000000000000000000000c07e000044f95655c11fda4cd37f70a94d7e0a7d6001600160a01b031614610627565b620f424081116101f4576020817fc723f3965b561ddea13852839c5130d896a2e2d85699e6840b13dd87b03ee3aa925f55604051908152a1005b60405162461bcd60e51b815260206004820152600d60248201526c696e76616c696420726174696f60981b6044820152606490fd5b34610110575f366003190112610110576040517f00000000000000000000000010101010e0c3171d894b71b3400668af311e7d946001600160a01b03168152602090f35b34610110575f3660031901126101105760206040517f0000000000000000000000000000000000000000000000000000000067d220008152f35b34610110576080366003190112610110576044356024356064356004356102f8337f000000000000000000000000c07e000044f95655c11fda4cd37f70a94d7e0a7d6001600160a01b031614610627565b6127106103128361030d8761030d88876107a3565b6107a3565b036103b2576001805464ffffffffff60781b607885901b1664ffffffffff9384166001600160a01b0319909216821769ffffffffff0000000000602888901b161764ffffffffff60501b605089901b161717909155604080519182529382166020820152938116928401929092521660608201527f2980979c260d641cb2f63191367b76d0669367a564cf78fe1a08a12681e9f9be9080608081010390a1005b60405162461bcd60e51b815260206004820152600e60248201526d696e76616c69642073706c69747360901b6044820152606490fd5b34610110575f36600319011261011057602061044e6104277f0000000000000000000000000000000000000000000000000000000067d22000426105e8565b7f0000000000000000000000000000000000000000000000000000000000093a8090610609565b604051908152f35b34610110575f366003190112610110576001546040805164ffffffffff8084168252602884901c81166020830152605084901c81169282019290925260789290921c166060820152608090f35b34610110576020366003190112610110576004355f526002602052606060405f2054604051906001600160401b03811682526001600160401b038160401c16602083015260801c6040820152f35b34610110575f366003190112610110576040517f00000000000000000000000057ab1e0003f623289cd798b1824be09a793e4bec6001600160a01b03168152602090f35b34610110575f3660031901126101105760206040517f0000000000000000000000000000000000000000000000000000000000093a808152f35b34610110575f3660031901126101105760206040516127108152f35b34610110575f3660031901126101105760205f54604051908152f35b34610110575f366003190112610110577f000000000000000000000000aaaa0013e2ec451f76816d1e0a02aba596dd92516001600160a01b03168152602090f35b919082039182116105f557565b634e487b7160e01b5f52601160045260245ffd5b8115610613570490565b634e487b7160e01b5f52601260045260245ffd5b1561062e57565b60405162461bcd60e51b815260206004820152600560248201526421636f726560d81b6044820152606490fd5b606081019081106001600160401b0382111761067657604052565b634e487b7160e01b5f52604160045260245ffd5b90601f801991011681019081106001600160401b0382111761067657604052565b9081602091031261011057516001600160a01b03811681036101105790565b51906001600160401b038216820361011057565b908160609103126101105760408051916106f78361065b565b610700816106ca565b835261070e602082016106ca565b602084015201516001600160801b038116810361011057604082015290565b906001600160401b03809116911603906001600160401b0382116105f557565b906001600160401b03809116911602906001600160401b0382169182036105f557565b906001600160801b03809116911601906001600160801b0382116105f557565b818102929181159184041417156105f557565b919082018092116105f557565b604051630abca72960e41b81526020816004817f00000000000000000000000010101010e0c3171d894b71b3400668af311e7d946001600160a01b03165afa80156115e8575f915f916115f3575b506001600160a01b0316803b15610110575f80916004604051809481936305dabd6960e51b83525af180156115e8576115d5575b506108606104277f0000000000000000000000000000000000000000000000000000000067d22000426105e8565b600281106115d1576040516370a0823160e01b8152306004820152906020826024817f00000000000000000000000057ab1e0003f623289cd798b1824be09a793e4bec6001600160a01b03165afa9182156115c6578392611592575b508181600119810111611248577f0000000000000000000000001099370bd8e48dd79a703f12ef59168c6ef8ad036001600160a01b03163b1561156e5760405163073dd8e160e11b815260011983016004820152602481018290528481604481837f0000000000000000000000001099370bd8e48dd79a703f12ef59168c6ef8ad036001600160a01b03165af180156115725790859161157d575b50507f000000000000000000000000aaaa0013e2ec451f76816d1e0a02aba596dd92516001600160a01b03163b1561156e5760405163521ef18d60e11b81528481600481837f000000000000000000000000aaaa0013e2ec451f76816d1e0a02aba596dd92516001600160a01b03165af1801561157257908591611559575b5050839160011981018552600260205260408520604051906109f78261065b565b546001600160401b03811682526001600160401b038160401c16602083015260801c6040820152604051610a2a8161065b565b86815260208082018890526040808301899052516362982fb560e01b815290816004817f000000000000000000000000aaaa0013e2ec451f76816d1e0a02aba596dd92516001600160a01b03165afa90811561154e57889161151c575b50805f1981011161129d576001600160401b03835116806112b1575b506001600160401b0342811660208401525f19918201168252830183811161129d578752600260205260408720906001600160401b0381511690825491896fffffffffffffffff0000000000000000602084015160401b169260406001600160801b031991015160801b16931617171790556001600160801b0360408201511661116b575b505050604051608081018181106001600160401b038211176111575790610b9791604052610bb3612710610bab64ffffffffff82610ba18282600154998a99836060818d169283815282602082019e8f828260281c16905260501c166040820152019c60781c168c528d610790565b049751168a610790565b0495511687610790565b0480946107a3565b6040516361d027b360e01b815294906020866004817f00000000000000000000000010101010e0c3171d894b71b3400668af311e7d946001600160a01b03165afa958615610f7a578796611136575b5060405163a9059cbb60e01b88526001600160a01b039687166004526024859052956020908890604490829081907f00000000000000000000000057ab1e0003f623289cd798b1824be09a793e4bec165af160018851148116156110ee575b8660405215610f895763bf40fac160e01b8652602060048701819052600660248801526514d4915554d160d21b6044880152866064817f00000000000000000000000010101010e0c3171d894b71b3400668af311e7d946001600160a01b03165afa958615610f7a5787966110cd575b5060405163a9059cbb60e01b88526001600160a01b03968716600452602491909152946020908790604490829081907f00000000000000000000000057ab1e0003f623289cd798b1824be09a793e4bec165af16001875114811615611085575b85604052156110495763670fb82160e01b85526020856004817f00000000000000000000000010101010e0c3171d894b71b3400668af311e7d946001600160a01b03165afa94851561103e57869561100d575b5060405163a9059cbb60e01b87526001600160a01b0395861660048190526024849052956020908890604490829081907f00000000000000000000000057ab1e0003f623289cd798b1824be09a793e4bec165af16001885114811615610fc5575b8160405215610f8957853b15610f855763082662a360e21b81528681600481838a5af18015610f7a57908791610f61575b505091610e2a610e2a92610e2f95946105e8565b6105e8565b60405163a9059cbb60e01b8452600483905260249190915290602083604481807f00000000000000000000000057ab1e0003f623289cd798b1824be09a793e4bec6001600160a01b03165af16001845114811615610f19575b8260405215610edd57803b15610ed95781600481858094633890080960e11b83525af18015610ece57610eb9575050565b610ec482809261068a565b610ecb5750565b80fd5b6040513d84823e3d90fd5b8280fd5b635274afe760e01b83527f00000000000000000000000057ab1e0003f623289cd798b1824be09a793e4bec6001600160a01b0316600452602483fd5b6001811516610f58573d157f00000000000000000000000057ab1e0003f623289cd798b1824be09a793e4bec6001600160a01b03163b15151616610e88565b823d85823e3d90fd5b81610f6b9161068a565b610f7657855f610e16565b8580fd5b6040513d89823e3d90fd5b8680fd5b635274afe760e01b87527f00000000000000000000000057ab1e0003f623289cd798b1824be09a793e4bec6001600160a01b0316600452602487fd5b6001811516611004573d157f00000000000000000000000057ab1e0003f623289cd798b1824be09a793e4bec6001600160a01b03163b15151616610de5565b503d87823e3d90fd5b61103091955060203d602011611037575b611028818361068a565b8101906106ab565b935f610d84565b503d61101e565b6040513d88823e3d90fd5b635274afe760e01b86527f00000000000000000000000057ab1e0003f623289cd798b1824be09a793e4bec6001600160a01b0316600452602486fd5b60018115166110c4573d157f00000000000000000000000057ab1e0003f623289cd798b1824be09a793e4bec6001600160a01b03163b15151616610d31565b853d88823e3d90fd5b6110e791965060203d60201161103757611028818361068a565b945f610cd1565b600181151661112d573d157f00000000000000000000000057ab1e0003f623289cd798b1824be09a793e4bec6001600160a01b03163b15151616610c61565b863d89823e3d90fd5b61115091965060203d60201161103757611028818361068a565b945f610c02565b634e487b7160e01b85526041600452602485fd5b60405163bf8ab9a760e01b8152600119909201600483015291935091506020826024817f0000000000000000000000001099370bd8e48dd79a703f12ef59168c6ef8ad036001600160a01b03165afa91821561129257849261125c575b506111e7620f4240916001600160801b03604087549201511690610790565b04620f42400180620f42401161124857620f42408202828104620f42401483151715611234579161121e6112249261122b94610609565b906105e8565b80926105e8565b905f8080610b28565b634e487b7160e01b85526011600452602485fd5b634e487b7160e01b84526011600452602484fd5b9091506020813d60201161128a575b816112786020938361068a565b810103126101105751906111e76111c8565b3d915061126b565b6040513d86823e3d90fd5b634e487b7160e01b88526011600452602488fd5b604051635a3c097960e11b815260048101919091526060816024817f000000000000000000000000aaaa0013e2ec451f76816d1e0a02aba596dd92516001600160a01b03165afa9081156115115789916114f2575b506001600160801b0361135a6113346001600160401b036020880151166001600160401b038551169061072d565b6001600160401b0361135384604087015116928260208801511661074d565b1690610770565b1660408281019190915251635a3c097960e11b81525f1983016004820152906060826024817f000000000000000000000000aaaa0013e2ec451f76816d1e0a02aba596dd92516001600160a01b03165afa9182156114e7578a926114b6575b506113d76001600160401b038351166001600160401b03421661072d565b906001600160401b038351166001600160401b038316016001600160401b0381116114a2576001600160801b03916001600160401b0360409216855282611437838701956001600160401b0361135384895116928260208c01511661074d565b168094520151169003906001600160801b03821161148e576114826001600160401b0393926001600160801b038561147a81839651168260208c0151169061072d565b169116610609565b16604084015290610aa3565b634e487b7160e01b8a52601160045260248afd5b634e487b7160e01b8c52601160045260248cfd5b6114d991925060603d6060116114e0575b6114d1818361068a565b8101906106de565b905f6113b9565b503d6114c7565b6040513d8c823e3d90fd5b61150b915060603d6060116114e0576114d1818361068a565b5f611306565b6040513d8b823e3d90fd5b90506020813d602011611546575b816115376020938361068a565b8101031261011057515f610a87565b3d915061152a565b6040513d8a823e3d90fd5b816115639161068a565b61156e57835f6109d6565b8380fd5b6040513d87823e3d90fd5b816115879161068a565b61156e57835f610957565b9091506020813d6020116115be575b816115ae6020938361068a565b810103126101105751905f6108bc565b3d91506115a1565b6040513d85823e3d90fd5b5050565b6115e191505f9061068a565b5f5f610832565b6040513d5f823e3d90fd5b61160c915060203d60201161103757611028818361068a565b5f6107fe56fea164736f6c634300081c000a

Verified Source Code Partial Match

Compiler: v0.8.28+commit.7893614a EVM: cancun Optimization: Yes (200 runs)
FeeDepositController.sol 185 lines
// SPDX-License-Identifier: MIT
pragma solidity 0.8.28;

import { IERC20 } from "@openzeppelin/contracts/token/ERC20/IERC20.sol";
import { SafeERC20 } from "../libraries/SafeERC20.sol";
import { IResupplyRegistry } from "../interfaces/IResupplyRegistry.sol";
import { IRewardHandler } from "../interfaces/IRewardHandler.sol";
import { IPriceWatcher } from "../interfaces/IPriceWatcher.sol";
import { IFeeDeposit } from "../interfaces/IFeeDeposit.sol";
import { CoreOwnable } from "../dependencies/CoreOwnable.sol";
import { EpochTracker } from 'src/dependencies/EpochTracker.sol';
import { IFeeLogger } from "../interfaces/IFeeLogger.sol";

contract FeeDepositController is CoreOwnable, EpochTracker{
    using SafeERC20 for IERC20;

    address public immutable registry;
    address public immutable feeToken;
    address public immutable priceWatcher;
    uint256 public additionalFeeRatio;
    uint256 public constant BPS = 10_000;
    Splits public splits;
    IFeeLogger public immutable feeLogger;
    
    struct WeightData{
        uint64 index;
        uint64 timestamp;
        uint128 avgWeighting;
    }
    mapping(uint256 => WeightData) public epochWeighting;

    struct Splits {
        uint40 insurance;
        uint40 treasury;
        uint40 platform;
        uint40 stakedStable;
    }

    event SplitsSet(uint40 insurance, uint40 treasury, uint40 platform, uint40 stakedStable);
    event AdditionalFeeRatioSet(uint256 ratio);

    /**
     * @param _core Core contract address
     * @param _registry Registry contract address
     * @param _additionalFee Cap on the amount of additional fees to direct to staked stable (1e6 = 100%)
     * @param _insuranceSplit Insurance split percentage (in BPS)
     * @param _treasurySplit Treasury split percentage (in BPS)
     * @param _stakedStableSplit Staked stable split percentage (in BPS)
     */
    constructor(
        address _core,
        address _registry,
        uint256 _additionalFee,
        uint256 _insuranceSplit,
        uint256 _treasurySplit,
        uint256 _stakedStableSplit
    ) CoreOwnable(_core) EpochTracker(_core){
        require(_additionalFee <= 1e6, "invalid ratio");
        registry = _registry;
        additionalFeeRatio = _additionalFee;
        emit AdditionalFeeRatioSet(_additionalFee);
        feeToken = IResupplyRegistry(_registry).token();
        priceWatcher = IResupplyRegistry(_registry).getAddress("PRICE_WATCHER");
        feeLogger = IFeeLogger(IResupplyRegistry(_registry).getAddress("FEE_LOGGER"));
        uint40 _platformSplit = uint40(BPS - _insuranceSplit - _treasurySplit - _stakedStableSplit);
        _setSplits(_insuranceSplit, _treasurySplit, _platformSplit, _stakedStableSplit);
    }

    function distribute() external{
        // Pull fees. Reverts when called multiple times in single epoch.
        address feeDeposit = IResupplyRegistry(registry).feeDeposit();
        IFeeDeposit(feeDeposit).distributeFees();
        uint256 currentEpoch = getEpoch();
        if(currentEpoch < 2) return;

        uint256 balance = IERC20(feeToken).balanceOf(address(this));

        //log TOTAL fees for current epoch - 2 since the balance here is what was accrued two epochs ago
        feeLogger.logTotalFees(currentEpoch-2, balance);

        //max sure price watcher is up to date
        IPriceWatcher(priceWatcher).updatePriceData();

        uint256 stakedStableAmount;

        //process weighted fees for sreusd
        //first need to look at weighting differences for currentEpoch-2 (which was logged at the beginning of epoch-1)
        //and currentEpoch-1 (which is logged now but the data being logged is for the previous epoch)
        //ex. if getEpoch is 2, we need to find and record the avg weight during epoch 1.
        //we do that by looking at difference of (x-2) and (x-1), aka epoch 0 and 1
        WeightData memory prevWeight = epochWeighting[currentEpoch - 2];
        WeightData memory currentWeight;

        uint256 latestIndex =  IPriceWatcher(priceWatcher).priceDataLength() - 1;

        //only calc if there is enough data to do so, the first execution will result in 0 avgWeighting
        if(prevWeight.index > 0){
            //offset by the timestamp of the previous distribution
            IPriceWatcher.PriceData memory prevData = IPriceWatcher(priceWatcher).priceDataAtIndex(prevWeight.index);
            uint64 dt = prevWeight.timestamp - prevData.timestamp;
            prevData.totalWeight = prevData.totalWeight + (prevData.weight * dt);

            //get latest data and extrapolate a new data point that uses latest's weight and the time difference between
            //latest and block.timestamp 
            IPriceWatcher.PriceData memory latest = IPriceWatcher(priceWatcher).priceDataAtIndex(latestIndex);
            dt = uint64(block.timestamp) - latest.timestamp;
            latest.timestamp = latest.timestamp + dt;
            latest.totalWeight = latest.totalWeight + (latest.weight * dt);

            //get difference of total weight between these two points
            uint256 dw = latest.totalWeight - prevData.totalWeight;
            //dt will always be > 0
            dt = latest.timestamp - prevWeight.timestamp;
            currentWeight.avgWeighting = uint128(dw / dt);
        }

        //set the latest timestamp and index used
        currentWeight.timestamp = uint64(block.timestamp);
        currentWeight.index = uint64(latestIndex);

        //write to state to be used in the following epoch
        epochWeighting[currentEpoch - 1] = currentWeight;

        //next calculate how much of the current balance should be sent to sreusd
        //using currentEpoch - 2 as pair interest is trailing by two epochs
        if(prevWeight.avgWeighting > 0){
            //get total amount of fees collected in interest only
            uint256 feesInInterest = feeLogger.epochInterestFees(currentEpoch-2);
            //use weighting to determine how much of the max fee should be applied
            uint256 useAddFeeRatio = additionalFeeRatio * prevWeight.avgWeighting / 1e6;
            useAddFeeRatio = 1e6 + useAddFeeRatio; //turn something like 10% or 0.1 to 1.1
            stakedStableAmount = feesInInterest - (feesInInterest * 1e6 / useAddFeeRatio);
            balance -= stakedStableAmount;
        }

        Splits memory _splits = splits;
        uint256 ipAmount =  balance * _splits.insurance / BPS;
        uint256 treasuryAmount =  balance * _splits.treasury / BPS;
        uint256 stakedStableSplitAmount = balance * _splits.stakedStable / BPS;
        stakedStableAmount += stakedStableSplitAmount;
        
        //treasury
        address treasury = IResupplyRegistry(registry).treasury();
        IERC20(feeToken).safeTransfer(treasury, treasuryAmount);

        //staked stable
        address staked = IResupplyRegistry(registry).getAddress("SREUSD");
        IERC20(feeToken).safeTransfer(staked, stakedStableAmount);

        //insurance pool
        address rewardHandler = IResupplyRegistry(registry).rewardHandler();
        IERC20(feeToken).safeTransfer(rewardHandler, ipAmount);
        IRewardHandler(rewardHandler).queueInsuranceRewards();

        //rsup stakers
        IERC20(feeToken).safeTransfer(rewardHandler, balance - ipAmount - treasuryAmount - stakedStableSplitAmount);
        IRewardHandler(rewardHandler).queueStakingRewards();
    }

    /// @notice The ```setAdditionalFeeRatio``` function sets the max additional fee ratio attributed to staked stable
    /// @param _additionalFee max additional fee ratio (1e6 = 100%)
    function setAdditionalFeeRatio(uint256 _additionalFee) external onlyOwner {
        require(_additionalFee <= 1e6, "invalid ratio");
        additionalFeeRatio = _additionalFee;
        emit AdditionalFeeRatioSet(_additionalFee);
    }

    /// @notice The ```setSplits``` function sets the fee distribution splits between insurance, treasury, and platform
    /// @param _insuranceSplit The percentage (in BPS) to send to insurance pool
    /// @param _treasurySplit The percentage (in BPS) to send to treasury
    /// @param _platformSplit The percentage (in BPS) to send to platform stakers
    /// @param _stakedStableSplit The percentage (in BPS) to send to staked stable
    function setSplits(uint256 _insuranceSplit, uint256 _treasurySplit, uint256 _platformSplit, uint256 _stakedStableSplit) external onlyOwner {
        _setSplits(_insuranceSplit, _treasurySplit, _platformSplit, _stakedStableSplit);
    }

    function _setSplits(uint256 _insuranceSplit, uint256 _treasurySplit, uint256 _platformSplit, uint256 _stakedStableSplit) internal {
        require(_insuranceSplit + _treasurySplit + _platformSplit + _stakedStableSplit == BPS, "invalid splits");
        splits.insurance = uint40(_insuranceSplit);
        splits.treasury = uint40(_treasurySplit);
        splits.platform = uint40(_platformSplit);
        splits.stakedStable = uint40(_stakedStableSplit);
        emit SplitsSet(uint40(_insuranceSplit), uint40(_treasurySplit), uint40(_platformSplit), uint40(_stakedStableSplit));
    }
}
IERC20.sol 79 lines
// 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);
}
SafeERC20.sol 67 lines
// SPDX-License-Identifier: ISC
pragma solidity ^0.8.19;

import { IERC20 } from "@openzeppelin/contracts/interfaces/IERC20.sol";
import { SafeERC20 as OZSafeERC20 } from "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol";

// solhint-disable avoid-low-level-calls
// solhint-disable max-line-length

/// @title SafeERC20 provides helper functions for safe transfers as well as safe metadata access
/// @author Library originally written by @Boring_Crypto github.com/boring_crypto, modified by Drake Evans (Frax Finance) github.com/drakeevans
/// @dev original: https://github.com/boringcrypto/BoringSolidity/blob/fed25c5d43cb7ce20764cd0b838e21a02ea162e9/contracts/libraries/BoringERC20.sol
library SafeERC20 {
    bytes4 private constant SIG_SYMBOL = 0x95d89b41; // symbol()
    bytes4 private constant SIG_NAME = 0x06fdde03; // name()
    bytes4 private constant SIG_DECIMALS = 0x313ce567; // decimals()

    function returnDataToString(bytes memory data) internal pure returns (string memory) {
        if (data.length >= 64) {
            return abi.decode(data, (string));
        } else if (data.length == 32) {
            uint8 i = 0;
            while (i < 32 && data[i] != 0) {
                i++;
            }
            bytes memory bytesArray = new bytes(i);
            for (i = 0; i < 32 && data[i] != 0; i++) {
                bytesArray[i] = data[i];
            }
            return string(bytesArray);
        } else {
            return "???";
        }
    }

    /// @notice Provides a safe ERC20.symbol version which returns '???' as fallback string.
    /// @param token The address of the ERC-20 token contract.
    /// @return (string) Token symbol.
    function safeSymbol(IERC20 token) internal view returns (string memory) {
        (bool success, bytes memory data) = address(token).staticcall(abi.encodeWithSelector(SIG_SYMBOL));
        return success ? returnDataToString(data) : "???";
    }

    /// @notice Provides a safe ERC20.name version which returns '???' as fallback string.
    /// @param token The address of the ERC-20 token contract.
    /// @return (string) Token name.
    function safeName(IERC20 token) internal view returns (string memory) {
        (bool success, bytes memory data) = address(token).staticcall(abi.encodeWithSelector(SIG_NAME));
        return success ? returnDataToString(data) : "???";
    }

    /// @notice Provides a safe ERC20.decimals version which returns '18' as fallback value.
    /// @param token The address of the ERC-20 token contract.
    /// @return (uint8) Token decimals.
    function safeDecimals(IERC20 token) internal view returns (uint8) {
        (bool success, bytes memory data) = address(token).staticcall(abi.encodeWithSelector(SIG_DECIMALS));
        return success && data.length == 32 ? abi.decode(data, (uint8)) : 18;
    }

    function safeTransfer(IERC20 token, address to, uint256 value) internal {
        OZSafeERC20.safeTransfer(token, to, value);
    }

    function safeTransferFrom(IERC20 token, address from, address to, uint256 value) internal {
        OZSafeERC20.safeTransferFrom(token, from, to, value);
    }
}
IResupplyRegistry.sol 74 lines
// SPDX-License-Identifier: MIT
pragma solidity 0.8.28;

interface IResupplyRegistry {
    event AddPair(address pairAddress);
    event OwnershipTransferStarted(address indexed previousOwner, address indexed newOwner);
    event OwnershipTransferred(address indexed previousOwner, address indexed newOwner);
    event SetDeployer(address deployer, bool _bool);
    event DefaultSwappersSet(address[] addresses);
    event EntryUpdated(string indexed key, address indexed addr);
    event WithdrawTo(address indexed user, uint256 amount);

    // Protected keys
    function LIQUIDATION_HANDLER() external pure returns (string memory);
    function FEE_DEPOSIT() external pure returns (string memory);
    function REDEMPTION_HANDLER() external pure returns (string memory);
    function INSURANCE_POOL() external pure returns (string memory);
    function REWARD_HANDLER() external pure returns (string memory);
    function TREASURY() external pure returns (string memory);
    function STAKER() external pure returns (string memory);
    function L2_MANAGER() external pure returns (string memory);
    function VEST_MANAGER() external pure returns (string memory);

    // Other public functions
    function token() external view returns (address);
    function govToken() external view returns (address);
    function getAddress(string memory key) external view returns (address);
    function getAllKeys() external view returns (string[] memory);
    function getAllAddresses() external view returns (address[] memory);
    function getProtectedKeys() external pure returns (string[] memory);
    function keyExists(string memory) external view returns (bool);
    function hashToKey(bytes32) external view returns (string memory);
    function setAddress(string memory key, address addr) external;
    function acceptOwnership() external;
    function addPair(address _pairAddress) external;
    function registeredPairs(uint256) external view returns (address);
    function pairsByName(string memory) external view returns (address);
    function registeredPairsLength() external view returns (uint256);
    function getAllPairAddresses() external view returns (address[] memory _deployedPairsArray);
    function defaultSwappers(uint256 _index) external view returns (address);
    function owner() external view returns (address);
    function pendingOwner() external view returns (address);
    function renounceOwnership() external;
    function transferOwnership(address newOwner) external;
    function claimFees(address _pair) external;
    function claimRewards(address _pair) external;
    function claimInsuranceRewards() external;
    function withdrawTo(address _asset, uint256 _amount, address _to) external;
    function mint(address receiver, uint256 amount) external;
    function burn(address target, uint256 amount) external;
    function liquidationHandler() external view returns(address);
    function feeDeposit() external view returns(address);
    function redemptionHandler() external view returns(address);
    function rewardHandler() external view returns(address);
    function insurancePool() external view returns(address);
    function setRewardClaimer(address _newAddress) external;
    function setRedemptionHandler(address _newAddress) external;
    function setFeeDeposit(address _newAddress) external;
    function setLiquidationHandler(address _newAddress) external;
    function setInsurancePool(address _newAddress) external;
    function setStaker(address _newAddress) external;
    function setTreasury(address _newAddress) external;
    function staker() external view returns(address);
    function treasury() external view returns(address);
    function l2manager() external view returns(address);
    function setRewardHandler(address _newAddress) external;
    function setVestManager(address _newAddress) external;
    function setDefaultSwappers(address[] memory _swappers) external;
    function collateralId(address _collateral) external view returns(uint256);
    function core() external view returns(address);

    error NameMustBeUnique();
    error ProtectedKey(string key);
}
IRewardHandler.sol 28 lines
// SPDX-License-Identifier: MIT
pragma solidity 0.8.28;

interface IRewardHandler{
    event BaseMinimumWeightSet(uint256 bweight);
    event MinimumWeightSet(address indexed user, uint256 mweight);
    function checkNewRewards(address _pair) external;
    function claimRewards(address _pair) external;
    function claimInsuranceRewards() external;
    function setPairWeight(address _pair, uint256 _amount) external;
    function queueInsuranceRewards() external;
    function queueStakingRewards() external;
    function pairEmissions() external view returns(address);
    function insuranceEmissions() external view returns(address);
    function insuranceRevenue() external view returns(address);
    function debtEmissionsReceiver() external view returns(address);
    function insuranceEmissionReceiver() external view returns(address);
    function priceWatcher() external view returns(address);
    function feeLogger() external view returns(address);
    function pairTimestamp(address _pair) external view returns(uint256);
    function minimumWeights(address _pair) external view returns(uint256);
    function migrateState(address _oldRewardHandler, bool _migrateTimestamp, bool _migrateMinWeights) external;
    function stateMigrated() external view returns(bool);
    function baseMinimumWeight() external view returns(uint256);
    function setBaseMinimumWeight(uint256 _bweight) external;
    function getPairRate(address _pair, uint256 _timespan, uint256 _amount) external view returns(uint256);
    function setPairMinimumWeight(address _account, uint256 _amount) external;
}
IPriceWatcher.sol 24 lines
// SPDX-License-Identifier: MIT
pragma solidity 0.8.28;

interface IPriceWatcher {
    struct PriceData{
        uint64 timestamp;
        uint64 weight;
        uint128 totalWeight;
    }
    event NewPriceData(uint256 indexed index, uint64 timestamp, uint64 weight, uint128 weightedValue);
    event OracleSet(address indexed oracle);

    function UPDATE_INTERVAL() external view returns(uint256);
    function registry() external view returns(address);
    function oracle() external view returns(address);
    function updatePriceData() external;
    function priceDataLength() external view returns(uint256);
    function priceDataAtIndex(uint256 i) external view returns(PriceData memory _pd);
    function latestPriceData() external view returns(PriceData memory _pd);
    function findPairPriceWeight(address _pair) external view returns(uint256);
    function getCurrentWeight() external view returns(uint64);
    function canUpdatePriceData() external view returns(bool);
    function setOracle() external;
}
IFeeDeposit.sol 11 lines
// SPDX-License-Identifier: MIT
pragma solidity 0.8.28;

interface IFeeDeposit {
    function operator() external view returns(address);
    function lastDistributedEpoch() external view returns(uint256);
    function setOperator(address _newAddress) external;
    function distributeFees() external;
    function incrementPairRevenue(uint256 _fees, uint256 _otherFees) external;
    function getEpoch() external view returns(uint256);
}
CoreOwnable.sol 27 lines
// SPDX-License-Identifier: MIT
pragma solidity 0.8.28;

import {ICore} from "../interfaces/ICore.sol";

/**
    @title Core Ownable
    @author Prisma Finance (with edits by Resupply Finance)
    @notice Contracts inheriting `CoreOwnable` have the same owner as `Core`.
            The ownership cannot be independently modified or renounced.
 */
contract CoreOwnable {
    ICore public immutable core;

    constructor(address _core) {
        core = ICore(_core);
    }

    modifier onlyOwner() {
        require(msg.sender == address(core), "!core");
        _;
    }

    function owner() public view returns (address) {
        return address(core);
    }
}
EpochTracker.sol 24 lines
// SPDX-License-Identifier: MIT
pragma solidity 0.8.28;

import "../interfaces/ICore.sol";

/**
    @title EpochTracker
    @dev Provides a unified `startTime` and `getEpoch`, used for tracking epochs.
 */
contract EpochTracker {
    uint256 public immutable startTime;
    
    /// @notice Length of an epoch, in seconds
    uint256 public immutable epochLength;

    constructor(address _core) {
        startTime = ICore(_core).startTime();
        epochLength = ICore(_core).epochLength();
    }

    function getEpoch() public view returns (uint256 epoch) {
        return (block.timestamp - startTime) / epochLength;
    }
}
IFeeLogger.sol 15 lines
// SPDX-License-Identifier: MIT
pragma solidity 0.8.28;

/// @title IFeeLogger
/// @notice Interface for FeeLogger
interface IFeeLogger {
    event LogTotalFees(uint256 _epoch, uint256 _amount);
    event LogInterestFees(address _pair, uint256 _epoch, uint256 _amount);
    function logTotalFees(uint256 _epoch, uint256 _amount) external;
    function logInterestFees(address _pair, uint256 _epoch, uint256 _amount) external;
    function pairEpochWeightings(address _pair, uint256 _epoch) external view returns(uint256 _interestFees);
    function epochInterestFees(uint256 _epoch) external view returns(uint256 _fees);
    function epochTotalFees(uint256 _epoch) external view returns(uint256 _fees);
    function registry() external view returns(address _registry);
}
IERC20.sol 6 lines
// 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";
SafeERC20.sol 280 lines
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.3.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 rely 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 rely 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}.
     * Opposedly, 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, 0, 0x44, 0, 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, 0, 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, 0, 0x64, 0, 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, 0, 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, 0, 0x44, 0, 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, 0, 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)
        }
    }
}
ICore.sol 31 lines
// SPDX-License-Identifier: MIT
pragma solidity 0.8.28;

import { IAuthHook } from './IAuthHook.sol';

interface ICore {
    struct OperatorAuth {
        bool authorized;
        IAuthHook hook;
    }

    event VoterSet(address indexed newVoter);
    event OperatorExecuted(address indexed caller, address indexed target, bytes data);
    event OperatorSet(address indexed caller, address indexed target, bool authorized, bytes4 selector, IAuthHook authHook);

    function execute(address target, bytes calldata data) external returns (bytes memory);
    function epochLength() external view returns (uint256);
    function startTime() external view returns (uint256);
    function voter() external view returns (address);
    function ownershipTransferDeadline() external view returns (uint256);
    function pendingOwner() external view returns (address);
    function setOperatorPermissions(
        address caller,
        address target,
        bytes4 selector,
        bool authorized,
        IAuthHook authHook
    ) external;
    function setVoter(address newVoter) external;
    function operatorPermissions(address caller, address target, bytes4 selector) external view returns (bool authorized, IAuthHook hook);
}
IERC1363.sol 86 lines
// 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);
}
IAuthHook.sol 7 lines
// SPDX-License-Identifier: MIT
pragma solidity 0.8.28;

interface IAuthHook {
    function preHook(address operator, address target, bytes calldata data) external returns (bool);
    function postHook(bytes memory result, address operator, address target, bytes calldata data) external returns (bool);
}
IERC165.sol 6 lines
// 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";
IERC165.sol 25 lines
// 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);
}

Read Contract

BPS 0x249d39e9 → uint256
additionalFeeRatio 0x22d08321 → uint256
core 0xf2f4eb26 → address
epochLength 0x57d775f8 → uint256
epochWeighting 0x65401e64 → uint64, uint64, uint128
feeLogger 0xfa443b53 → address
feeToken 0x647846a5 → address
getEpoch 0x757991a8 → uint256
owner 0x8da5cb5b → address
priceWatcher 0x0d2aa245 → address
registry 0x7b103999 → address
splits 0x6cbdec7d → uint40, uint40, uint40, uint40
startTime 0x78e97925 → uint256

Write Contract 3 functions

These functions modify contract state and require a wallet transaction to execute.

distribute 0xe4fc6b6d
No parameters
setAdditionalFeeRatio 0xd42553c8
uint256 _additionalFee
setSplits 0x767bc1bf
uint256 _insuranceSplit
uint256 _treasurySplit
uint256 _platformSplit
uint256 _stakedStableSplit

Recent Transactions

No transactions found for this address