Forkchoice Ethereum Mainnet

Address Contract Partially Verified

Address 0x8300976D173B6874F2F95B2Dd6CD893FCa0466D9
Balance 0 ETH
Nonce 1
Code Size 3182 bytes
Indexed Transactions 0 (1 on-chain, 1.5% indexed)
External Etherscan · Sourcify

Contract Bytecode

3182 bytes
Copy Bytecode
0x608060405234801561000f575f80fd5b506004361061013d575f3560e01c80638da5cb5b116100b4578063c7b3662b11610079578063c7b3662b146102ae578063d69efdc5146102c1578063dd07d288146102d4578063f2fde38b146102dd578063fe2c9fbe146102f0578063feaf968c146102f9575f80fd5b80638da5cb5b146102465780639c52a7f114610256578063a08edce814610269578063afe041661461027c578063bf353dbb1461028f575f80fd5b80635c60da1b116101055780635c60da1b146101cf57806365fae35e146101fa5780636e57b4c71461020d578063715018a6146102165780637284e4161461021e5780638cb2378d14610233575f80fd5b80632c9f6792146101415780632da42d4f1461015d578063313ce5671461018057806350d25bcd146101b15780635132eefd146101ba575b5f80fd5b61014a60075481565b6040519081526020015b60405180910390f35b61017061016b3660046107ec565b61032d565b6040519015158152602001610154565b60405160ff7f0000000000000000000000000000000000000000000000000000000000000012168152602001610154565b61014a60035481565b6101cd6101c836600461080c565b61038b565b005b6001546101e2906001600160a01b031681565b6040516001600160a01b039091168152602001610154565b6101cd610208366004610823565b6103e2565b61014a61271081565b6101cd610406565b610226610419565b604051610154919061088c565b6101cd6102413660046108b2565b6104a5565b5f546001600160a01b03166101e2565b6101cd610264366004610823565b610504565b6101cd61027736600461080c565b610525565b6101cd61028a36600461080c565b6105d8565b61014a61029d366004610823565b60026020525f908152604090205481565b6101cd6102bc36600461080c565b610607565b6101cd6102cf366004610823565b610614565b61014a60045481565b6101cd6102eb366004610823565b61063e565b61014a60085481565b600354600454604080515f80825260208201949094529081018390526060810191909152608081019190915260a001610154565b5f80612710600854846103409190610983565b61034a91906109b2565b905061035681846109ea565b84138061036b57506103688184610a11565b84125b1561037a576001915050610385565b5f915050610385565b505b92915050565b610393610680565b6003805490829055426004556040517fe00eeacf23bab8ef18abec306590e1ac8e5f55bf242e6e018aee132ba9985e8e906103d690600990849086908190610a68565b60405180910390a15050565b6103ea610680565b6001600160a01b03165f90815260026020526040902060019055565b61040e610680565b6104175f6106ac565b565b6009805461042690610a30565b80601f016020809104026020016040519081016040528092919081815260200182805461045290610a30565b801561049d5780601f106104745761010080835404028352916020019161049d565b820191905f5260205f20905b81548152906001019060200180831161048057829003601f168201915b505050505081565b6104ad610680565b600382905560096104be8282610b4f565b50426004556109c460085560036007556040517fe00eeacf23bab8ef18abec306590e1ac8e5f55bf242e6e018aee132ba9985e8e906103d69083905f9086908190610c0a565b61050c610680565b6001600160a01b03165f90815260026020526040812055565b335f908152600260205260408120549003610552576040516282b42960e81b815260040160405180910390fd5b60035461055f828261032d565b1561057d5760405163614f544560e01b815260040160405180910390fd5b5f61058882846106fb565b6003819055426004556040519091507fe00eeacf23bab8ef18abec306590e1ac8e5f55bf242e6e018aee132ba9985e8e906105cb90600990859085908890610a68565b60405180910390a1505050565b6105e0610680565b6002811215610602576040516366c931e760e01b815260040160405180910390fd5b600755565b61060f610680565b600855565b61061c610680565b600180546001600160a01b0319166001600160a01b0392909216919091179055565b610646610680565b6001600160a01b03811661067457604051631e4fbdf760e01b81525f60048201526024015b60405180910390fd5b61067d816106ac565b50565b5f546001600160a01b031633146104175760405163118cdaa760e01b815233600482015260240161066b565b5f80546001600160a01b038381166001600160a01b0319831681178455604051919092169283917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e09190a35050565b6007545f908161075261072d6107128460016109ea565b61071d876002610983565b61072791906109b2565b8761075b565b6107388460016109ea565b610743886002610983565b61074d91906109b2565b6107a7565b95945050505050565b5f82820181831280159061076f5750838112155b8061078357505f8312801561078357508381125b6107a05760405163a421190b60e01b815260040160405180910390fd5b9392505050565b5f8183038183128015906107bb5750838113155b806107cf57505f831280156107cf57508381135b6107a057604051630c4050cb60e11b815260040160405180910390fd5b5f80604083850312156107fd575f80fd5b50508035926020909101359150565b5f6020828403121561081c575f80fd5b5035919050565b5f60208284031215610833575f80fd5b81356001600160a01b03811681146107a0575f80fd5b5f81518084525f5b8181101561086d57602081850181015186830182015201610851565b505f602082860101526020601f19601f83011685010191505092915050565b602081525f6107a06020830184610849565b634e487b7160e01b5f52604160045260245ffd5b5f80604083850312156108c3575f80fd5b82359150602083013567ffffffffffffffff8111156108e0575f80fd5b8301601f810185136108f0575f80fd5b803567ffffffffffffffff81111561090a5761090a61089e565b604051601f8201601f19908116603f0116810167ffffffffffffffff811182821017156109395761093961089e565b604052818152828201602001871015610950575f80fd5b816020840160208301375f602083830101528093505050509250929050565b634e487b7160e01b5f52601160045260245ffd5b8082025f8212600160ff1b8414161561099e5761099e61096f565b81810583148215176103855761038561096f565b5f826109cc57634e487b7160e01b5f52601260045260245ffd5b600160ff1b82145f19841416156109e5576109e561096f565b500590565b8082018281125f831280158216821582161715610a0957610a0961096f565b505092915050565b8181035f8312801583831316838312821617156103835761038361096f565b600181811c90821680610a4457607f821691505b602082108103610a6257634e487b7160e01b5f52602260045260245ffd5b50919050565b608081525f808654610a7981610a30565b806080860152600182165f8114610a975760018114610ab357610ae4565b60ff19831660a087015260a082151560051b8701019350610ae4565b895f5260205f205f5b83811015610adb57815488820160a00152600190910190602001610abc565b870160a0019450505b5050506020830195909552506040810192909252606090910152919050565b601f821115610b4a57805f5260205f20601f840160051c81016020851015610b285750805b601f840160051c820191505b81811015610b47575f8155600101610b34565b50505b505050565b815167ffffffffffffffff811115610b6957610b6961089e565b610b7d81610b778454610a30565b84610b03565b6020601f821160018114610baf575f8315610b985750848201515b5f19600385901b1c1916600184901b178455610b47565b5f84815260208120601f198516915b82811015610bde5787850151825560209485019460019092019101610bbe565b5084821015610bfb57868401515f19600387901b60f8161c191681555b50505050600190811b01905550565b608081525f610c1c6080830187610849565b602083019590955250604081019290925260609091015291905056fea26469706673582212206e8b6595b2e29b0818d8ebfe75d38d37132133828db2ed500618d84e7f15c15064736f6c634300081a0033

Verified Source Code Partial Match

Compiler: v0.8.26+commit.8a97fa7a EVM: shanghai Optimization: Yes (200 runs)
FungifyPriceFeed.sol 298 lines
// SPDX-License-Identifier: UNLICENSED
pragma solidity 0.8.26;

/**
 * @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;
    }
}

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

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

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

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

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

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

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

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

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

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

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

contract Upgradeable is Ownable {
    address public implementation;

    constructor() Ownable(msg.sender) {}

    function replaceImplementation(address impl_) public onlyOwner {
        implementation = impl_;
    }
}

contract Proxy is Upgradeable {

    constructor(address impl_) {
        replaceImplementation(impl_);
    }

    fallback() external payable {
        assembly {
            calldatacopy(0, 0, calldatasize())
            let result := delegatecall(gas(), sload(implementation.slot), 0, calldatasize(), 0, 0)
            returndatacopy(0, 0, returndatasize())
            switch result
            case 0 { revert(0, returndatasize()) }
            default { return(0, returndatasize()) }
        }
    }
}

contract FungifyPriceFeed is Upgradeable {
    event RateUpdated(string description, int256 oldRate, int256 newRate, int256 inputRate);
    error OverPriceDeviationMaximum();
    error Unauthorized();
    error AdditionOverflow();
    error SubtractionOverflow();
    error LessThanTwoPeriods();

    // --- Auth ---
    mapping (address => uint256) public wards;
    function rely(address guy) external onlyOwner { wards[guy] = 1; }
    function deny(address guy) external onlyOwner { wards[guy] = 0; }
    modifier auth {
        if (wards[msg.sender] == 0) {
            revert Unauthorized();
        }
        _;
    }

    int256 public constant ONE_IN_BIP = 10000;
    uint8 internal immutable _decimals;

    int256 public latestAnswer;
    uint256 public latestUpdateTime;

    // Variables for price updating assertions
    int256 internal minPriceDeviationBip_unused; // Defined in basis points: 1 Bip = .01%
    uint256 internal stalePriceTime_unused;

    int256 public emaPeriods; // averaging periods for EMA calculation
    int public maxPriceDeviationBip; // Defined in basis points: 1 Bip = .01%

    string public description;

    constructor(uint8 decimals_) {
        _decimals = decimals_;
    }

    function initialize(int256 startingRate_, string memory description_) external onlyOwner {
        latestAnswer = startingRate_;
        description = description_;
        latestUpdateTime = block.timestamp;
        maxPriceDeviationBip = 2500;
        emaPeriods = 3;
        emit RateUpdated(description_, 0, startingRate_, startingRate_);
    }

    function decimals() public view returns (uint8) {
        return _decimals;
    }

    function latestRoundData()
        public
        view
        returns (
            uint80 roundId,
            int256 answer,
            uint256 startedAt,
            uint256 updatedAt,
            uint80 answeredInRound
        ) {
        return (0, latestAnswer, 0, latestUpdateTime, 0);
    }

    // Verifies that a newRate is within the maxPriceDeviationBip of oldRate
    function overMaxPriceDeviation(int256 newRate, int256 oldRate) public view returns(bool) {

        int allowedDeviation = oldRate * maxPriceDeviationBip / ONE_IN_BIP;

        if (newRate > oldRate + allowedDeviation || newRate < oldRate - allowedDeviation) {
            return true;
        } else {
            return false;
        }
    }

    function updateRate(int256 newRate_) public auth {

        int256 oldEMA = latestAnswer;

        if (overMaxPriceDeviation(newRate_, oldEMA)) {
            revert OverPriceDeviationMaximum();
        }

        int256 newEMA = updateEMA(oldEMA, newRate_);

        latestAnswer = newEMA;
        latestUpdateTime = block.timestamp;
        emit RateUpdated(description, oldEMA, newEMA, newRate_);
    }

    function updateEMA(int256 currentEMA, int256 newValue) internal view returns (int256) {
        /*
            Multiplier: 2 / (emaPeriods + 1)
            EMA: (LastestValue - PreviousEMA) * Multiplier + PreviousEMA
        */

        int256 emaPeriods_ = emaPeriods;

        int256 newEMA =
            sub(
                add(
                    newValue * 2 / (emaPeriods_ + 1),
                    currentEMA
                ),
                currentEMA * 2 / (emaPeriods_ + 1)
            );

        return newEMA;
    }

    // Defined in basis points: 1 Bip = .01%
    function setMaxPriceDeviationBip(int _maxPriceDeviationBip) external onlyOwner {
        maxPriceDeviationBip = _maxPriceDeviationBip;
    }

    function setEMAPeriods(int _emaPeriods) external onlyOwner {
        if (_emaPeriods < 2) {
            revert LessThanTwoPeriods();
        }
        emaPeriods = _emaPeriods;
    }

    function adminUpdateRate(int256 newRate_) external onlyOwner {
        int256 oldRate = latestAnswer;
        latestAnswer = newRate_;
        latestUpdateTime = block.timestamp;
        emit RateUpdated(description, oldRate, newRate_, newRate_);
    }

    function add(int256 a, int256 b) internal pure returns (int256) {
        int256 c;
        unchecked { c = a + b; }
        if (!((b >= 0 && c >= a) || (b < 0 && c < a))) {
            revert AdditionOverflow();
        }

        return c;
    }
    function sub(int256 a, int256 b) internal pure returns (int256) {
        int256 c;
        unchecked { c = a - b; }
        if (!((b >= 0 && c <= a) || (b < 0 && c > a))) {
            revert SubtractionOverflow();
        }

        return c;
    }
}

Read Contract

ONE_IN_BIP 0x6e57b4c7 → int256
decimals 0x313ce567 → uint8
description 0x7284e416 → string
emaPeriods 0x2c9f6792 → int256
implementation 0x5c60da1b → address
latestAnswer 0x50d25bcd → int256
latestRoundData 0xfeaf968c → uint80, int256, uint256, uint256, uint80
latestUpdateTime 0xdd07d288 → uint256
maxPriceDeviationBip 0xfe2c9fbe → int256
overMaxPriceDeviation 0x2da42d4f → bool
owner 0x8da5cb5b → address
wards 0xbf353dbb → uint256

Write Contract 10 functions

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

adminUpdateRate 0x5132eefd
int256 newRate_
deny 0x9c52a7f1
address guy
initialize 0x8cb2378d
int256 startingRate_
string description_
rely 0x65fae35e
address guy
renounceOwnership 0x715018a6
No parameters
replaceImplementation 0xd69efdc5
address impl_
setEMAPeriods 0xafe04166
int256 _emaPeriods
setMaxPriceDeviationBip 0xc7b3662b
int256 _maxPriceDeviationBip
transferOwnership 0xf2fde38b
address newOwner
updateRate 0xa08edce8
int256 newRate_

Recent Transactions

This address has 1 on-chain transactions, but only 1.5% of the chain is indexed. Transactions will appear as indexing progresses. View on Etherscan →