Source Code
Overview
ETH Balance
0 ETH
Eth Value
$0.00| Transaction Hash |
Method
|
Block
|
From
|
|
To
|
||||
|---|---|---|---|---|---|---|---|---|---|
Latest 1 internal transaction
Advanced mode:
| Parent Transaction Hash | Method | Block |
From
|
|
To
|
||
|---|---|---|---|---|---|---|---|
| 0x61014060 | 22337598 | 213 days ago | Contract Creation | 0 ETH |
Loading...
Loading
Cross-Chain Transactions
Loading...
Loading
Contract Name:
StableSwapNGOracle
Compiler Version
v0.8.21+commit.d9974bed
Optimization Enabled:
Yes with 200 runs
Other Settings:
shanghai EvmVersion
Contract Source Code (Solidity Standard Json-Input format)
// SPDX-License-Identifier: GPL-3.0-or-later
pragma solidity =0.8.21;
import {AggregatorV3Interface, IOracle, ICurveStableSwapNG, IERC20, IERC4626} from "./Interface.sol";
/**
* @title StableSwapNGOracle
* @notice Oracle providing the price of a Curve StableSwap NG LP token in USD,
* scaled by 1e36. It calculates the LP token value based on the underlying
* asset balances (fetched via POOL.balances) and their Chainlink prices.
*/
contract StableSwapNGOracle is IOracle {
// --- State Variables ---
/// @notice Address of the Curve StableSwap NG pool.
ICurveStableSwapNG public immutable POOL;
/// @notice ERC-4626 share token of first underlying asset (e.g., sUSDe)
IERC4626 public immutable SHARE_0;
/// @notice ERC-4626 share token of second underlying asset (e.g., sUSDS)
IERC4626 public immutable SHARE_1;
/// @notice Chainlink feed for the first underlying asset vs USD (e.g., USDe/USD).
AggregatorV3Interface public immutable FEED_ASSET_0;
/// @notice Chainlink feed for the second underlying asset vs USD (e.g., USDS/USD).
AggregatorV3Interface public immutable FEED_ASSET_1;
/// @notice Chainlink feed for USDC vs USD.
AggregatorV3Interface public immutable FEED_USDC;
// --- Constructor ---
constructor(address _pool, address _feedAsset0, address _feedAsset1, address _feedUsdc) {
POOL = ICurveStableSwapNG(_pool);
FEED_ASSET_0 = AggregatorV3Interface(_feedAsset0);
FEED_ASSET_1 = AggregatorV3Interface(_feedAsset1);
FEED_USDC = AggregatorV3Interface(_feedUsdc);
SHARE_0 = IERC4626(POOL.coins(0));
SHARE_1 = IERC4626(POOL.coins(1));
// Check for feed decimals
require(FEED_ASSET_0.decimals() == 8, "Feed 0 decimals != 8");
require(FEED_ASSET_1.decimals() == 8, "Feed 1 decimals != 8");
require(FEED_USDC.decimals() == 8, "Feed USDC decimals != 8");
}
/**
* @notice Returns the price of the LP token in USDC, scaled by 1e36
* @dev Fetches underlying balances, gets their USD prices from Chainlink,
* calculates total USD value, derives per-LP-token USD value,
* and converts it to USDC value using the USDC/USD feed.
* @return price The price of one LP token unit in USDC, scaled by 1e36.
*/
function price() external view returns (uint256) {
uint256 asset0Price = _getChainlinkPrice(FEED_ASSET_0, 86400); // Decimals: 8
uint256 asset1Price = _getChainlinkPrice(FEED_ASSET_1, 86400); // Decimals: 8
uint256 lpPrice = POOL.get_virtual_price() * (asset0Price < asset1Price ? asset0Price : asset1Price); // Decimals: 18+8=26
uint256 usdcPrice = _getChainlinkPrice(FEED_USDC, 86400); // Decimals: 8
// Calculate the price of the LP token in USDC (scaled by 1e36)
uint256 lpUsdcPrice = (lpPrice * 1e18) / usdcPrice; // Decimals: 26+18-8=36
return lpUsdcPrice;
}
/**
* @notice Fetches the latest price from a Chainlink feed with validation.
* @dev Reverts if the price is invalid (<= 0) or too old (older than heartbeat).
* @param feed The Chainlink AggregatorV3Interface address.
* @param heartbeat The maximum allowed age of the price feed update in seconds.
* @return price The latest price from the feed, assuming 8 decimals.
*/
function _getChainlinkPrice(AggregatorV3Interface feed, uint256 heartbeat) internal view returns (uint256) {
(, int256 answer,, uint256 updatedAt,) = feed.latestRoundData();
require(answer > 0, "Invalid price");
require(block.timestamp - updatedAt < heartbeat, "Price too old");
return uint256(answer); // Price has 8 decimals
}
}// SPDX-License-Identifier: GPL-3.0-or-later
pragma solidity =0.8.21;
interface IERC20 {
/**
* @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);
function decimals() external view returns (uint8);
}
/**
* @dev Curve StableSwap-NG interface
*/
interface ICurveStableSwapNG is IERC20 {
function coins(uint256 i) external view returns (address);
function get_virtual_price() external view returns (uint256);
}
/**
* @dev Chainlink's data feed interface
*/
interface AggregatorV3Interface {
function latestRoundData()
external
view
returns (uint80 roundId, int256 answer, uint256 startedAt, uint256 updatedAt, uint80 answeredInRound);
function decimals() external view returns (uint8);
}
interface IOracle {
/**
* Returns the price of 1 asset of collateral token quoted in 1 asset of loan token, scaled by 1e36.
*
* It corresponds to the price of 10**(collateral token decimals) assets of collateral token quoted in 10 **(loan token decimals) assets of loan token with 36 + loan token decimals - collateral token decimals decimals of precision.
*/
function price() external view returns (uint256);
}
interface IERC4626 is IERC20 {
/**
* @dev Returns the address of the underlying token used for the Vault for accounting, depositing, and withdrawing.
*
* - MUST be an ERC-20 token contract.
* - MUST NOT revert.
*/
function asset() external view returns (address assetTokenAddress);
/**
* @dev Returns the amount of shares that the Vault would exchange for the amount of assets provided, in an ideal
* scenario where all the conditions are met.
*
* - MUST NOT be inclusive of any fees that are charged against assets in the Vault.
* - MUST NOT show any variations depending on the caller.
* - MUST NOT reflect slippage or other on-chain conditions, when performing the actual exchange.
* - MUST NOT revert.
*
* NOTE: This calculation MAY NOT reflect the “per-user” price-per-share, and instead should reflect the
* “average-user’s” price-per-share, meaning what the average user should expect to see when exchanging to and
* from.
*/
function convertToShares(uint256 assets) external view returns (uint256 shares);
/**
* @dev Returns the amount of assets that the Vault would exchange for the amount of shares provided, in an ideal
* scenario where all the conditions are met.
*
* - MUST NOT be inclusive of any fees that are charged against assets in the Vault.
* - MUST NOT show any variations depending on the caller.
* - MUST NOT reflect slippage or other on-chain conditions, when performing the actual exchange.
* - MUST NOT revert.
*
* NOTE: This calculation MAY NOT reflect the “per-user” price-per-share, and instead should reflect the
* “average-user’s” price-per-share, meaning what the average user should expect to see when exchanging to and
* from.
*/
function convertToAssets(uint256 shares) external view returns (uint256 assets);
/**
* @dev Allows an on-chain or off-chain user to simulate the effects of their deposit at the current block, given
* current on-chain conditions.
*
* - MUST return as close to and no more than the exact amount of Vault shares that would be minted in a deposit
* call in the same transaction. I.e. deposit should return the same or more shares as previewDeposit if called
* in the same transaction.
* - MUST NOT account for deposit limits like those returned from maxDeposit and should always act as though the
* deposit would be accepted, regardless if the user has enough tokens approved, etc.
* - MUST be inclusive of deposit fees. Integrators should be aware of the existence of deposit fees.
* - MUST NOT revert.
*
* NOTE: any unfavorable discrepancy between convertToShares and previewDeposit SHOULD be considered slippage in
* share price or some other type of condition, meaning the depositor will lose assets by depositing.
*/
function previewDeposit(uint256 assets) external view returns (uint256 shares);
/**
* @dev Allows an on-chain or off-chain user to simulate the effects of their mint at the current block, given
* current on-chain conditions.
*
* - MUST return as close to and no fewer than the exact amount of assets that would be deposited in a mint call
* in the same transaction. I.e. mint should return the same or fewer assets as previewMint if called in the
* same transaction.
* - MUST NOT account for mint limits like those returned from maxMint and should always act as though the mint
* would be accepted, regardless if the user has enough tokens approved, etc.
* - MUST be inclusive of deposit fees. Integrators should be aware of the existence of deposit fees.
* - MUST NOT revert.
*
* NOTE: any unfavorable discrepancy between convertToAssets and previewMint SHOULD be considered slippage in
* share price or some other type of condition, meaning the depositor will lose assets by minting.
*/
function previewMint(uint256 shares) external view returns (uint256 assets);
/**
* @dev Allows an on-chain or off-chain user to simulate the effects of their withdrawal at the current block,
* given current on-chain conditions.
*
* - MUST return as close to and no fewer than the exact amount of Vault shares that would be burned in a withdraw
* call in the same transaction. I.e. withdraw should return the same or fewer shares as previewWithdraw if
* called
* in the same transaction.
* - MUST NOT account for withdrawal limits like those returned from maxWithdraw and should always act as though
* the withdrawal would be accepted, regardless if the user has enough shares, etc.
* - MUST be inclusive of withdrawal fees. Integrators should be aware of the existence of withdrawal fees.
* - MUST NOT revert.
*
* NOTE: any unfavorable discrepancy between convertToShares and previewWithdraw SHOULD be considered slippage in
* share price or some other type of condition, meaning the depositor will lose assets by depositing.
*/
function previewWithdraw(uint256 assets) external view returns (uint256 shares);
/**
* @dev Allows an on-chain or off-chain user to simulate the effects of their redeemption at the current block,
* given current on-chain conditions.
*
* - MUST return as close to and no more than the exact amount of assets that would be withdrawn in a redeem call
* in the same transaction. I.e. redeem should return the same or more assets as previewRedeem if called in the
* same transaction.
* - MUST NOT account for redemption limits like those returned from maxRedeem and should always act as though the
* redemption would be accepted, regardless if the user has enough shares, etc.
* - MUST be inclusive of withdrawal fees. Integrators should be aware of the existence of withdrawal fees.
* - MUST NOT revert.
*
* NOTE: any unfavorable discrepancy between convertToAssets and previewRedeem SHOULD be considered slippage in
* share price or some other type of condition, meaning the depositor will lose assets by redeeming.
*/
function previewRedeem(uint256 shares) external view returns (uint256 assets);
}{
"remappings": [
"@openzeppelin-contracts/=dependencies/@openzeppelin-contracts-5.2.0/",
"forge-std/=dependencies/forge-std-1.9.6/",
"morpho-blue/=dependencies/morpho-blue-1.0.0/"
],
"optimizer": {
"enabled": true,
"runs": 200
},
"metadata": {
"useLiteralContent": false,
"bytecodeHash": "ipfs",
"appendCBOR": true
},
"outputSelection": {
"*": {
"*": [
"evm.bytecode",
"evm.deployedBytecode",
"devdoc",
"userdoc",
"metadata",
"abi"
]
}
},
"evmVersion": "shanghai",
"viaIR": false,
"libraries": {}
}Contract Security Audit
- No Contract Security Audit Submitted- Submit Audit Here
Contract ABI
API[{"inputs":[{"internalType":"address","name":"_pool","type":"address"},{"internalType":"address","name":"_feedAsset0","type":"address"},{"internalType":"address","name":"_feedAsset1","type":"address"},{"internalType":"address","name":"_feedUsdc","type":"address"}],"stateMutability":"nonpayable","type":"constructor"},{"inputs":[],"name":"FEED_ASSET_0","outputs":[{"internalType":"contract AggregatorV3Interface","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"FEED_ASSET_1","outputs":[{"internalType":"contract AggregatorV3Interface","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"FEED_USDC","outputs":[{"internalType":"contract AggregatorV3Interface","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"POOL","outputs":[{"internalType":"contract ICurveStableSwapNG","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"SHARE_0","outputs":[{"internalType":"contract IERC4626","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"SHARE_1","outputs":[{"internalType":"contract IERC4626","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"price","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"}]Contract Creation Code
610140604052348015610010575f80fd5b5060405161097338038061097383398101604081905261002f9161037e565b6001600160a01b03848116608081905284821660e052838216610100529082166101205260405163c661065760e01b81525f600482015263c661065790602401602060405180830381865afa15801561008a573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906100ae91906103cf565b6001600160a01b0390811660a05260805160405163c661065760e01b81526001600482015291169063c661065790602401602060405180830381865afa1580156100fa573d5f803e3d5ffd5b505050506040513d601f19601f8201168201806040525081019061011e91906103cf565b6001600160a01b031660c0816001600160a01b03168152505060e0516001600160a01b031663313ce5676040518163ffffffff1660e01b8152600401602060405180830381865afa158015610175573d5f803e3d5ffd5b505050506040513d601f19601f8201168201806040525081019061019991906103ef565b60ff166008146101f05760405162461bcd60e51b815260206004820152601460248201527f46656564203020646563696d616c7320213d203800000000000000000000000060448201526064015b60405180910390fd5b610100516001600160a01b031663313ce5676040518163ffffffff1660e01b8152600401602060405180830381865afa15801561022f573d5f803e3d5ffd5b505050506040513d601f19601f8201168201806040525081019061025391906103ef565b60ff166008146102a55760405162461bcd60e51b815260206004820152601460248201527f46656564203120646563696d616c7320213d203800000000000000000000000060448201526064016101e7565b610120516001600160a01b031663313ce5676040518163ffffffff1660e01b8152600401602060405180830381865afa1580156102e4573d5f803e3d5ffd5b505050506040513d601f19601f8201168201806040525081019061030891906103ef565b60ff1660081461035a5760405162461bcd60e51b815260206004820152601760248201527f46656564205553444320646563696d616c7320213d203800000000000000000060448201526064016101e7565b5050505061040f565b80516001600160a01b0381168114610379575f80fd5b919050565b5f805f8060808587031215610391575f80fd5b61039a85610363565b93506103a860208601610363565b92506103b660408601610363565b91506103c460608601610363565b905092959194509250565b5f602082840312156103df575f80fd5b6103e882610363565b9392505050565b5f602082840312156103ff575f80fd5b815160ff811681146103e8575f80fd5b60805160a05160c05160e051610100516101205161050461046f5f395f81816083015261029e01525f818161016301526101d201525f818161013c01526101a201525f61011501525f60c701525f818160ee015261020e01526105045ff3fe608060405234801561000f575f80fd5b506004361061007a575f3560e01c8063785a58fc11610058578063785a58fc146101105780637f75cb01146101375780638f2e11311461015e578063a035b1fe14610185575f80fd5b80632a87f73a1461007e5780635a372a3c146100c25780637535d246146100e9575b5f80fd5b6100a57f000000000000000000000000000000000000000000000000000000000000000081565b6040516001600160a01b0390911681526020015b60405180910390f35b6100a57f000000000000000000000000000000000000000000000000000000000000000081565b6100a57f000000000000000000000000000000000000000000000000000000000000000081565b6100a57f000000000000000000000000000000000000000000000000000000000000000081565b6100a57f000000000000000000000000000000000000000000000000000000000000000081565b6100a57f000000000000000000000000000000000000000000000000000000000000000081565b61018d61019b565b6040519081526020016100b9565b5f806101ca7f0000000000000000000000000000000000000000000000000000000000000000620151806102f0565b90505f6101fa7f0000000000000000000000000000000000000000000000000000000000000000620151806102f0565b90505f81831061020a578161020c565b825b7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031663bb7b8b806040518163ffffffff1660e01b8152600401602060405180830381865afa158015610268573d5f803e3d5ffd5b505050506040513d601f19601f8201168201806040525081019061028c91906103f0565b610296919061041b565b90505f6102c67f0000000000000000000000000000000000000000000000000000000000000000620151806102f0565b90505f816102dc84670de0b6b3a764000061041b565b6102e69190610432565b9695505050505050565b5f805f846001600160a01b031663feaf968c6040518163ffffffff1660e01b815260040160a060405180830381865afa15801561032f573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190610353919061046f565b509350509250505f821361039e5760405162461bcd60e51b815260206004820152600d60248201526c496e76616c696420707269636560981b60448201526064015b60405180910390fd5b836103a982426104bb565b106103e65760405162461bcd60e51b815260206004820152600d60248201526c141c9a58d9481d1bdbc81bdb19609a1b6044820152606401610395565b5090505b92915050565b5f60208284031215610400575f80fd5b5051919050565b634e487b7160e01b5f52601160045260245ffd5b80820281158282048414176103ea576103ea610407565b5f8261044c57634e487b7160e01b5f52601260045260245ffd5b500490565b805169ffffffffffffffffffff8116811461046a575f80fd5b919050565b5f805f805f60a08688031215610483575f80fd5b61048c86610451565b94506020860151935060408601519250606086015191506104af60808701610451565b90509295509295909350565b818103818111156103ea576103ea61040756fea2646970667358221220de92c0e4618509d49222499724081f3ca89f9bd76c92828400acb000a10cc31164736f6c634300081500330000000000000000000000003cef1afc0e8324b57293a6e7ce663781bbefbb79000000000000000000000000a569d910839ae8865da8f8e70fffb0cba869f961000000000000000000000000ff30586cd0f29ed462364c7e81375fc0c71219b10000000000000000000000008fffffd4afb6115b954bd326cbe7b4ba576818f6
Deployed Bytecode
0x608060405234801561000f575f80fd5b506004361061007a575f3560e01c8063785a58fc11610058578063785a58fc146101105780637f75cb01146101375780638f2e11311461015e578063a035b1fe14610185575f80fd5b80632a87f73a1461007e5780635a372a3c146100c25780637535d246146100e9575b5f80fd5b6100a57f0000000000000000000000008fffffd4afb6115b954bd326cbe7b4ba576818f681565b6040516001600160a01b0390911681526020015b60405180910390f35b6100a57f0000000000000000000000009d39a5de30e57443bff2a8307a4256c8797a349781565b6100a57f0000000000000000000000003cef1afc0e8324b57293a6e7ce663781bbefbb7981565b6100a57f000000000000000000000000a3931d71877c0e7a3148cb7eb4463524fec27fbd81565b6100a57f000000000000000000000000a569d910839ae8865da8f8e70fffb0cba869f96181565b6100a57f000000000000000000000000ff30586cd0f29ed462364c7e81375fc0c71219b181565b61018d61019b565b6040519081526020016100b9565b5f806101ca7f000000000000000000000000a569d910839ae8865da8f8e70fffb0cba869f961620151806102f0565b90505f6101fa7f000000000000000000000000ff30586cd0f29ed462364c7e81375fc0c71219b1620151806102f0565b90505f81831061020a578161020c565b825b7f0000000000000000000000003cef1afc0e8324b57293a6e7ce663781bbefbb796001600160a01b031663bb7b8b806040518163ffffffff1660e01b8152600401602060405180830381865afa158015610268573d5f803e3d5ffd5b505050506040513d601f19601f8201168201806040525081019061028c91906103f0565b610296919061041b565b90505f6102c67f0000000000000000000000008fffffd4afb6115b954bd326cbe7b4ba576818f6620151806102f0565b90505f816102dc84670de0b6b3a764000061041b565b6102e69190610432565b9695505050505050565b5f805f846001600160a01b031663feaf968c6040518163ffffffff1660e01b815260040160a060405180830381865afa15801561032f573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190610353919061046f565b509350509250505f821361039e5760405162461bcd60e51b815260206004820152600d60248201526c496e76616c696420707269636560981b60448201526064015b60405180910390fd5b836103a982426104bb565b106103e65760405162461bcd60e51b815260206004820152600d60248201526c141c9a58d9481d1bdbc81bdb19609a1b6044820152606401610395565b5090505b92915050565b5f60208284031215610400575f80fd5b5051919050565b634e487b7160e01b5f52601160045260245ffd5b80820281158282048414176103ea576103ea610407565b5f8261044c57634e487b7160e01b5f52601260045260245ffd5b500490565b805169ffffffffffffffffffff8116811461046a575f80fd5b919050565b5f805f805f60a08688031215610483575f80fd5b61048c86610451565b94506020860151935060408601519250606086015191506104af60808701610451565b90509295509295909350565b818103818111156103ea576103ea61040756fea2646970667358221220de92c0e4618509d49222499724081f3ca89f9bd76c92828400acb000a10cc31164736f6c63430008150033
Constructor Arguments (ABI-Encoded and is the last bytes of the Contract Creation Code above)
0000000000000000000000003cef1afc0e8324b57293a6e7ce663781bbefbb79000000000000000000000000a569d910839ae8865da8f8e70fffb0cba869f961000000000000000000000000ff30586cd0f29ed462364c7e81375fc0c71219b10000000000000000000000008fffffd4afb6115b954bd326cbe7b4ba576818f6
-----Decoded View---------------
Arg [0] : _pool (address): 0x3CEf1AFC0E8324b57293a6E7cE663781bbEFBB79
Arg [1] : _feedAsset0 (address): 0xa569d910839Ae8865Da8F8e70FfFb0cBA869F961
Arg [2] : _feedAsset1 (address): 0xfF30586cD0F29eD462364C7e81375FC0C71219b1
Arg [3] : _feedUsdc (address): 0x8fFfFfd4AfB6115b954Bd326cbe7B4BA576818f6
-----Encoded View---------------
4 Constructor Arguments found :
Arg [0] : 0000000000000000000000003cef1afc0e8324b57293a6e7ce663781bbefbb79
Arg [1] : 000000000000000000000000a569d910839ae8865da8f8e70fffb0cba869f961
Arg [2] : 000000000000000000000000ff30586cd0f29ed462364c7e81375fc0c71219b1
Arg [3] : 0000000000000000000000008fffffd4afb6115b954bd326cbe7b4ba576818f6
Loading...
Loading
Loading...
Loading
Multichain Portfolio | 33 Chains
| Chain | Token | Portfolio % | Price | Amount | Value |
|---|
Loading...
Loading
Loading...
Loading
Loading...
Loading
[ Download: CSV Export ]
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.