diff --git a/.env.example b/.env.example index 2286b26..556fbe6 100644 --- a/.env.example +++ b/.env.example @@ -14,3 +14,6 @@ MELLOW_VAULTS=["0x5fD13359Ba15A84B76f7F87568309040176167cd"] MELLOW_QUOTE_ASSETS=["0x7f39C581F595B53c5cb19bD0b3f8dA6c935E2Ca0"] YN_PRICE_FEEDS=["YNETH/ETH"] YN_VIEWERS=["0x0365a6eF790e05EEe386B57326e5Ceaf5B10899e"] +INCEPTION_PRICE_FEEDS=["inwstETHs/wstETH"] +INCEPTION_VAULTS=["0xf9D9F828989A624423C48b95BC04E9Ae0ef5Ec97"] +INCEPTION_LRT_ADDRESS=["0x8E0789d39db454DBE9f4a77aCEF6dc7c69f6D552"] diff --git a/contracts/inception/interfaces/IVault.sol b/contracts/inception/interfaces/IVault.sol new file mode 100644 index 0000000..7e97fbf --- /dev/null +++ b/contracts/inception/interfaces/IVault.sol @@ -0,0 +1,7 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.20; + +interface IVault { + /// @dev returns the total deposited into asset strategy + function getTotalDeposited() external view returns (uint256); +} diff --git a/contracts/inceptionpricefeed/CloneFactory.sol b/contracts/inceptionpricefeed/CloneFactory.sol new file mode 100644 index 0000000..ced2e08 --- /dev/null +++ b/contracts/inceptionpricefeed/CloneFactory.sol @@ -0,0 +1,48 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.20; + +import "./InceptionPriceFeed.sol"; +import "@openzeppelin/contracts/proxy/Clones.sol"; + +/// @title Factory for creating InceptionPriceFeed contract clones. +/// @notice This contract will create a InceptionPriceFeed clone and map its address to the clone creator. +/// @dev Cloning is done with OpenZeppelin's Clones contract. +contract CloneFactory { + event InceptionPriceFeedCloneCreated( + address _inceptionPriceFeedCloneAddress + ); + + mapping (address => address) public InceptionPriceFeedCloneAddresses; + address public implementationAddress; + + /// @param _implementationAddress Address of implementation contract to be cloned. + constructor(address _implementationAddress) { + implementationAddress = _implementationAddress; + } + + /// @notice Create clone of InceptionPriceFeed contract and initialize it. + /// @dev Clone method returns address of created clone. + /// @param _vault Address of Inception vault contract. + /// @param _inceptionLRT Address of Inception LRT token. + /// @param _priceFeedDecimals Amount of decimals a PriceFeed is denominiated in. + /// @param _priceFeedBase Base asset of PriceFeed, should be set to asset symbol ticker. + /// @param _priceFeedQuote Quote asset of PriceFeed, should be set to asset symbol ticker. + function createInceptionPriceFeed( + address _vault, + address _inceptionLRT, + uint8 _priceFeedDecimals, + string calldata _priceFeedBase, + string calldata _priceFeedQuote + ) external { + address inceptionPriceFeedCloneAddress = Clones.clone(implementationAddress); + InceptionPriceFeed(inceptionPriceFeedCloneAddress).initialize( + _vault, + _inceptionLRT, + _priceFeedDecimals, + _priceFeedBase, + _priceFeedQuote + ); + InceptionPriceFeedCloneAddresses[msg.sender] = inceptionPriceFeedCloneAddress; + emit InceptionPriceFeedCloneCreated(inceptionPriceFeedCloneAddress); + } +} diff --git a/contracts/inceptionpricefeed/InceptionPriceFeed.sol b/contracts/inceptionpricefeed/InceptionPriceFeed.sol new file mode 100644 index 0000000..6ebaa4c --- /dev/null +++ b/contracts/inceptionpricefeed/InceptionPriceFeed.sol @@ -0,0 +1,138 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.20; + +import "@openzeppelin/contracts/proxy/utils/Initializable.sol"; +import "@openzeppelin/contracts/token/ERC20/ERC20.sol"; +import "@chainlink/contracts/src/v0.8/interfaces/AggregatorV3Interface.sol"; +import "../inception/interfaces/IVault.sol"; + +/// @title Contract for retreiving a Inception LRT's exchange rate value with chainlink's AggregatorV3Interface +/// implemented. +/// @author Ojo Network (https://docs.ojo.network/) +contract InceptionPriceFeed is Initializable, AggregatorV3Interface { + uint8 private priceFeedDecimals; + + string private priceFeedBase; + + string private priceFeedQuote; + + address public vault; + + address public inceptionLRT; + + uint80 constant DEFAULT_ROUND = 1; + + uint256 constant DEFAULT_VERSION = 1; + + uint256 internal constant INT256_MAX = uint256(type(int256).max); + + error GetRoundDataCanBeOnlyCalledWithLatestRound(uint80 requestedRoundId); + + /// @notice Initialize clone of this contract. + /// @dev This function is used in place of a constructor in proxy contracts. + /// @param _vault Address of Inception vault contract. + /// @param _inceptionLRT Address of Inception LRT token. + /// @param _priceFeedDecimals Amount of decimals a PriceFeed is denominiated in. + /// @param _priceFeedBase Base asset of PriceFeed. + /// @param _priceFeedQuote Quote asset of PriceFeed. + function initialize( + address _vault, + address _inceptionLRT, + uint8 _priceFeedDecimals, + string calldata _priceFeedBase, + string calldata _priceFeedQuote + ) external initializer { + vault = _vault; + inceptionLRT = _inceptionLRT; + priceFeedDecimals = _priceFeedDecimals; + priceFeedBase = _priceFeedBase; + priceFeedQuote = _priceFeedQuote; + } + + /// @notice Amount of decimals price is denominated in. + function decimals() external view returns (uint8) { + return priceFeedDecimals; + } + + /// @notice Asset pair that this proxy is tracking. + function description() external view returns (string memory) { + return string(abi.encodePacked(priceFeedBase, "/", priceFeedQuote)); + } + + /// @notice Version always returns 1. + function version() external view returns (uint256) { + return DEFAULT_VERSION; + } + + /// @dev Latest round always returns 1 since this contract does not support rounds. + function latestRound() public pure returns (uint80) { + return DEFAULT_ROUND; + } + + /// @notice Calculates exchange rate from the Inception LRT Vault from a specified round. + /// @dev Even though rounds are not utilized in this contract getRoundData is implemented for contracts + /// that still rely on it. Function will revert if specified round is not the latest round. + /// @return roundId Round ID of price data, this is always set to 1. + /// @return answer Price in USD of asset this contract is tracking. + /// @return startedAt Timestamp relating to price update. + /// @return updatedAt Timestamp relating to price update. + /// @return answeredInRound Equal to round ID. + function getRoundData(uint80 _roundId) + external + view + returns ( + uint80 roundId, + int256 answer, + uint256 startedAt, + uint256 updatedAt, + uint80 answeredInRound + ) { + if (_roundId != latestRound()) { + revert GetRoundDataCanBeOnlyCalledWithLatestRound(_roundId); + } + return latestRoundData(); + } + + /// @notice Calculates exchange rate from the Inception LRT Vault. + /// @return roundId Round ID of price data, this is always set to 1. + /// @return answer Price of priceFeedBase quoted by priceFeedQuote. + /// @return startedAt Timestamp relating to price update. + /// @return updatedAt Timestamp relating to price update. + /// @return answeredInRound Equal to round ID. + function latestRoundData() + public + view + returns ( + uint80 roundId, + int256 answer, + uint256 startedAt, + uint256 updatedAt, + uint80 answeredInRound + ) { + roundId = latestRound(); + + IVault vault_ = IVault(vault); + ERC20 inceptionLRT_ = ERC20(inceptionLRT); + + answer = 0; + + if (inceptionLRT_.totalSupply() != 0) { + answer = int256(vault_.getTotalDeposited()) * 1e18 / int256(inceptionLRT_.totalSupply()); + } + + // These values are equal after chainlink’s OCR update + startedAt = block.timestamp; + updatedAt = startedAt; + + // roundId is always equal to answeredInRound + answeredInRound = roundId; + + return ( + roundId, + answer, + startedAt, + updatedAt, + answeredInRound + ); + } +} diff --git a/mainnet_chains.json b/mainnet_chains.json index 039755c..fa91637 100644 --- a/mainnet_chains.json +++ b/mainnet_chains.json @@ -11,10 +11,12 @@ "priceFeedImplementation": "0xa1aB70C0F3725AcA1D1e85Bd4402Dd2d5F6AFf19", "priceFeedQuotedImplementation": "", "mellowPriceFeedImplementation": "", + "inceptionPriceFeedImplementation": "", "ynPriceFeedImplementation": "", "cloneFactory": "0xd285A4F0Ad1BB6b1Db8cD3dD839E9f423938ef9E", "cloneFactoryQuoted": "", "cloneFactoryMellow": "", + "cloneFactoryInception": "", "cloneFactoryYn": "" }, { @@ -29,10 +31,12 @@ "priceFeedImplementation": "0xfaC9d315b9b558e10eBdb0462aA42577aADe6601", "priceFeedQuotedImplementation": "", "mellowPriceFeedImplementation": "", + "inceptionPriceFeedImplementation": "", "ynPriceFeedImplementation": "", "cloneFactory": "0x02Ed15B70D4dE1209c3Dd5a75195CB3f3dDB8B07", "cloneFactoryQuoted": "", "cloneFactoryMellow": "", + "cloneFactoryInception": "", "cloneFactoryYn": "" }, { @@ -47,10 +51,12 @@ "priceFeedImplementation": "0x09d43904C8ABd470df1B793df68904A9714558CF", "priceFeedQuotedImplementation": "", "mellowPriceFeedImplementation": "", + "inceptionPriceFeedImplementation": "", "ynPriceFeedImplementation": "", "cloneFactory": "0xfaC9d315b9b558e10eBdb0462aA42577aADe6601", "cloneFactoryQuoted": "", "cloneFactoryMellow": "", + "cloneFactoryInception": "", "cloneFactoryYn": "" }, { @@ -65,10 +71,12 @@ "priceFeedImplementation": "0xde471274F1B684476d341eB131224F389AD4A270", "priceFeedQuotedImplementation": "", "mellowPriceFeedImplementation": "0xc2E105535132E588b5D1764A0b9472e5537FA9cD", + "inceptionPriceFeedImplementation": "0x418630F34A6E82c93a97a1b6E79B6a20C76EaD05", "ynPriceFeedImplementation": "", "cloneFactory": "0x710C8a3c8CB393cA24748849de3585b5C48D4D0c", "cloneFactoryQuoted": "", "cloneFactoryMellow": "0x721c05f08308Bcce5C62e342070564Fd4441ec32", + "cloneFactoryInception": "0x2Babd8D4BCE072e78aA288c639Ef4516fCe26d89", "cloneFactoryYn": "" } ] diff --git a/scripts/createInceptionPriceFeed.ts b/scripts/createInceptionPriceFeed.ts new file mode 100644 index 0000000..380d531 --- /dev/null +++ b/scripts/createInceptionPriceFeed.ts @@ -0,0 +1,62 @@ +import { Wallet, ethers } from "ethers"; +import CloneFactory from '../artifacts/contracts/inceptionpricefeed/CloneFactory.sol/CloneFactory.json'; +import testnet_chains from '../testnet_chains.json'; +import mainnet_chains from '../mainnet_chains.json'; + +async function main() { + const evmChains = JSON.parse(process.env.EVM_CHAINS!); + const inceptionPriceFeedDecimals = process.env.PRICE_FEED_DECIMALS as any; + const inceptionPriceFeeds = JSON.parse(process.env.INCEPTION_PRICE_FEEDS!); + const inceptionVaults = JSON.parse(process.env.INCEPTION_VAULTS!); + const inceptionLRTAddresses = JSON.parse(process.env.INCEPTION_LRT_ADDRESS!); + + if (inceptionPriceFeeds.length !== inceptionVaults.length || inceptionPriceFeeds.length !== inceptionLRTAddresses.length) { + throw new Error('unequal amount of inceptionVaults associated with inceptionPriceFeeds'); + } + + const privateKey = process.env.PRIVATE_KEY; + + if (!privateKey) { + throw new Error('Invalid private key. Make sure the PRIVATE_KEY environment variable is set.'); + } + + const mainnet = process.env.MAINNET as string + let chains = testnet_chains.map((chain) => ({ ...chain })); + if (mainnet === "TRUE") { + chains = mainnet_chains.map((chain) => ({ ...chain })); + } + + for (const chain of chains) { + if (evmChains.includes(chain.name)) { + const provider = new ethers.JsonRpcProvider(chain.rpc) + const wallet = new Wallet(privateKey, provider); + const balance = await provider.getBalance(wallet.address) + console.log(`${chain.name} wallet balance: ${ethers.formatEther(balance.toString())} ${chain.tokenSymbol}`); + + const cloneFactoryInceptionContract = new ethers.Contract(chain.cloneFactoryInception, CloneFactory.abi, wallet) + let i = 0 + for (const inceptionPriceFeed of inceptionPriceFeeds) { + console.log(`Deploying ${inceptionPriceFeed} price feed on ${chain.name}`); + try { + const [baseAsset, quoteAsset] = inceptionPriceFeed.split('/'); + + console.log("baseAsset", baseAsset) + console.log("quoteAsset", quoteAsset) + const tx = await cloneFactoryInceptionContract.createInceptionPriceFeed(inceptionVaults[i], inceptionLRTAddresses[i], inceptionPriceFeedDecimals, baseAsset, quoteAsset); + console.log(`Transaction sent: ${tx.hash}`); + + const receipt = await tx.wait(); + console.log(`Transaction mined: ${receipt.transactionHash}`); + } catch (error) { + console.error(`Failed to deploy ${inceptionPriceFeed} on ${chain.name}:`, error); + } + i += 1 + } + } + } +} + +main().catch((error) => { + console.error(error); + process.exitCode = 1; +}); diff --git a/scripts/deployInceptionCloneFactory.ts b/scripts/deployInceptionCloneFactory.ts new file mode 100644 index 0000000..08c0366 --- /dev/null +++ b/scripts/deployInceptionCloneFactory.ts @@ -0,0 +1,38 @@ +import { Wallet, ethers } from "ethers"; +import InceptionCloneFactory from '../artifacts/contracts/inceptionpricefeed/CloneFactory.sol/CloneFactory.json'; +import testnet_chains from '../testnet_chains.json'; +import mainnet_chains from '../mainnet_chains.json'; + +async function main () { + const evmChains = JSON.parse(process.env.EVM_CHAINS!); + + const privateKey = process.env.PRIVATE_KEY; + + if (!privateKey) { + throw new Error('Invalid private key. Make sure the PRIVATE_KEY environment variable is set.'); + } + + const mainnet = process.env.MAINNET as string + let chains = testnet_chains.map((chain) => ({ ...chain })); + if (mainnet === "TRUE") { + chains = mainnet_chains.map((chain) => ({ ...chain })); + } + + for (const chain of chains) { + if (evmChains.includes(chain.name)) { + const provider = new ethers.JsonRpcProvider(chain.rpc) + const wallet = new Wallet(privateKey, provider); + const balance = await provider.getBalance(wallet.address) + console.log(`${chain.name} wallet balance: ${ethers.formatEther(balance.toString())} ${chain.tokenSymbol}`); + + const inceptionCloneFactoryFactory = new ethers.ContractFactory(InceptionCloneFactory.abi, InceptionCloneFactory.bytecode, wallet) + const inceptionCloneFactory = await inceptionCloneFactoryFactory.deploy(chain.inceptionPriceFeedImplementation) + console.log(`${chain.name}, address: ${await inceptionCloneFactory.getAddress()}`); + } + } +} + +main().catch((error) => { + console.error(error); + process.exitCode = 1; +}); diff --git a/scripts/deployInceptionPriceFeedImplementation.ts b/scripts/deployInceptionPriceFeedImplementation.ts new file mode 100644 index 0000000..279cf55 --- /dev/null +++ b/scripts/deployInceptionPriceFeedImplementation.ts @@ -0,0 +1,38 @@ +import { Wallet, ethers } from "ethers"; +import InceptionPriceFeed from '../artifacts/contracts/inceptionpricefeed/InceptionPriceFeed.sol/InceptionPriceFeed.json'; +import testnet_chains from '../testnet_chains.json'; +import mainnet_chains from '../mainnet_chains.json'; + +async function main() { + const evmChains = JSON.parse(process.env.EVM_CHAINS!); + + const privateKey = process.env.PRIVATE_KEY; + + if (!privateKey) { + throw new Error('Invalid private key. Make sure the PRIVATE_KEY environment variable is set.'); + } + + const mainnet = process.env.MAINNET as string + let chains = testnet_chains.map((chain) => ({ ...chain })); + if (mainnet === "TRUE") { + chains = mainnet_chains.map((chain) => ({ ...chain })); + } + + for (const chain of chains) { + if (evmChains.includes(chain.name)) { + const provider = new ethers.JsonRpcProvider(chain.rpc) + const wallet = new Wallet(privateKey, provider); + const balance = await provider.getBalance(wallet.address) + console.log(`${chain.name} wallet balance: ${ethers.formatEther(balance.toString())} ${chain.tokenSymbol}`); + + const inceptionPriceFeedFactory = new ethers.ContractFactory(InceptionPriceFeed.abi, InceptionPriceFeed.bytecode, wallet) + const inceptionPriceFeed = await inceptionPriceFeedFactory.deploy() + console.log(`${chain.name}, address: ${await inceptionPriceFeed.getAddress()}`); + } + } +} + +main().catch((error) => { + console.error(error); + process.exitCode = 1; +}); diff --git a/testnet_chains.json b/testnet_chains.json index 1546d25..593ede9 100644 --- a/testnet_chains.json +++ b/testnet_chains.json @@ -11,10 +11,12 @@ "priceFeedImplementation": "", "priceFeedQuotedImplementation": "", "mellowPriceFeedImplementation": "", + "inceptionPriceFeedImplementation": "", "ynPriceFeedImplementation": "", "cloneFactory": "", "cloneFactoryQuoted": "", "cloneFactoryMellow": "", + "cloneFactoryInception": "", "cloneFactoryYn": "" }, { @@ -29,10 +31,12 @@ "priceFeedImplementation": "", "priceFeedQuotedImplementation": "0x1A069010D7F572c97925E83a1298Df8f96893c60", "mellowPriceFeedImplementation": "", + "inceptionPriceFeedImplementation": "", "ynPriceFeedImplementation": "", "cloneFactory": "", "cloneFactoryQuoted": "0x694723e8Fe9945CffDB671b02175DC55DeDf7F29", "cloneFactoryMellow": "", + "cloneFactoryInception": "", "cloneFactoryYn": "" }, { @@ -47,10 +51,12 @@ "priceFeedImplementation": "", "priceFeedQuotedImplementation": "", "mellowPriceFeedImplementation": "", + "inceptionPriceFeedImplementation": "", "ynPriceFeedImplementation": "0x710C8a3c8CB393cA24748849de3585b5C48D4D0c", "cloneFactory": "", "cloneFactoryQuoted": "", "cloneFactoryMellow": "", + "cloneFactoryInception": "", "cloneFactoryYn": "0x1bc0555c2137447160a2581837372f63835a8002" }, { @@ -65,10 +71,12 @@ "priceFeedImplementation": "", "priceFeedQuotedImplementation": "", "mellowPriceFeedImplementation": "", + "inceptionPriceFeedImplementation": "", "ynPriceFeedImplementation": "", "cloneFactory": "", "cloneFactoryQuoted": "", "cloneFactoryMellow": "", + "cloneFactoryInception": "", "cloneFactoryYn": "" }, { @@ -83,9 +91,11 @@ "priceFeedImplementation": "", "priceFeedQuotedImplementation": "", "mellowPriceFeedImplementation": "", + "inceptionPriceFeedImplementation": "", "cloneFactory": "", "cloneFactoryQuoted": "", "cloneFactoryMellow": "", + "cloneFactoryInception": "", "cloneFactoryYn": "" }, { @@ -100,9 +110,11 @@ "priceFeedImplementation": "", "priceFeedQuotedImplementation": "", "mellowPriceFeedImplementation": "", + "inceptionPriceFeedImplementation": "", "cloneFactory": "", "cloneFactoryQuoted": "", - "cloneFactoryMellow": "" + "cloneFactoryMellow": "", + "cloneFactoryInception": "" }, { "name": "Avalanche Fuji C-Chain", @@ -116,10 +128,12 @@ "priceFeedImplementation": "", "priceFeedQuotedImplementation": "", "mellowPriceFeedImplementation": "", + "inceptionPriceFeedImplementation": "", "ynPriceFeedImplementation": "", "cloneFactory": "", "cloneFactoryQuoted": "", "cloneFactoryMellow": "", + "cloneFactoryInception": "", "cloneFactoryYn": "" }, { @@ -134,10 +148,12 @@ "priceFeedImplementation": "", "priceFeedQuotedImplementation": "", "mellowPriceFeedImplementation": "", + "inceptionPriceFeedImplementation": "", "ynPriceFeedImplementation": "", "cloneFactory": "", "cloneFactoryQuoted": "", "cloneFactoryMellow": "", + "cloneFactoryInception": "", "cloneFactoryYn": "" }, { @@ -152,10 +168,12 @@ "priceFeedImplementation": "", "priceFeedQuotedImplementation": "", "mellowPriceFeedImplementation": "", + "inceptionPriceFeedImplementation": "", "ynPriceFeedImplementation": "", "cloneFactory": "", "cloneFactoryQuoted": "", "cloneFactoryMellow": "", + "cloneFactoryInception": "", "cloneFactoryYn": "" }, { @@ -170,8 +188,10 @@ "priceFeedImplementation": "", "priceFeedQuotedImplementation": "", "mellowPriceFeedImplementation": "", + "inceptionPriceFeedImplementation": "", "cloneFactory": "", "cloneFactoryQuoted": "", + "cloneFactoryInception": "", "cloneFactoryYn": "" }, { @@ -186,10 +206,12 @@ "priceFeedImplementation": "0x3DB6DF9EDfDcfE97D574Aa6f106C767051561Be2", "priceFeedQuotedImplementation": "0x2Babd8D4BCE072e78aA288c639Ef4516fCe26d89", "mellowPriceFeedImplementation": "", + "inceptionPriceFeedImplementation": "", "ynPriceFeedImplementation": "", "cloneFactory": "0xab2c7cc090A45836fae04501e0454413ECA96611", "cloneFactoryQuoted": "0x4f5E3B2d64670cd8EA2329c4B028a4c07832F846", "cloneFactoryMellow": "", + "cloneFactoryInception": "", "cloneFactoryYn": "" }, { @@ -204,10 +226,12 @@ "priceFeedImplementation": "", "priceFeedQuotedImplementation": "", "mellowPriceFeedImplementation": "", + "inceptionPriceFeedImplementation": "", "ynPriceFeedImplementation": "", "cloneFactory": "", "cloneFactoryQuoted": "", "cloneFactoryMellow": "", + "cloneFactoryInception": "", "cloneFactoryYn": "" }, { @@ -222,10 +246,12 @@ "priceFeedImplementation": "0x48B10B538B7E5af4CbFd93B1C4d36668e8F6F644", "priceFeedQuotedImplementation": "", "mellowPriceFeedImplementation": "", + "inceptionPriceFeedImplementation": "", "ynPriceFeedImplementation": "", "cloneFactory": "0xe9c4145FCeDdc19bc9B788C5d16cF08AD70d3850", "cloneFactoryQuoted": "", "cloneFactoryMellow": "", + "cloneFactoryInception": "", "cloneFactoryYn": "" }, { @@ -240,10 +266,12 @@ "priceFeedImplementation": "", "priceFeedQuotedImplementation": "", "mellowPriceFeedImplementation": "", + "inceptionPriceFeedImplementation": "", "ynPriceFeedImplementation": "", "cloneFactory": "", "cloneFactoryQuoted": "", "cloneFactoryMellow": "", + "cloneFactoryInception": "", "cloneFactoryYn": "" }, { @@ -258,10 +286,12 @@ "priceFeedImplementation": "0x09d43904C8ABd470df1B793df68904A9714558CF", "priceFeedQuotedImplementation": "", "mellowPriceFeedImplementation": "", + "inceptionPriceFeedImplementation": "", "ynPriceFeedImplementation": "", "cloneFactory": "0x02Ed15B70D4dE1209c3Dd5a75195CB3f3dDB8B07", "cloneFactoryQuoted": "", "cloneFactoryMellow": "", + "cloneFactoryInception": "", "cloneFactoryYn": "" }, { @@ -276,10 +306,12 @@ "priceFeedImplementation": "", "priceFeedQuotedImplementation": "", "mellowPriceFeedImplementation": "", + "inceptionPriceFeedImplementation": "", "ynPriceFeedImplementation": "", "cloneFactory": "", "cloneFactoryQuoted": "", "cloneFactoryMellow": "", + "cloneFactoryInception": "", "cloneFactoryYn": "" }, { @@ -294,10 +326,12 @@ "priceFeedImplementation": "", "priceFeedQuotedImplementation": "", "mellowPriceFeedImplementation": "", + "inceptionPriceFeedImplementation": "", "ynPriceFeedImplementation": "", "cloneFactory": "", "cloneFactoryQuoted": "", "cloneFactoryMellow": "", + "cloneFactoryInception": "", "cloneFactoryYn": "" }, { @@ -311,10 +345,12 @@ "create2Deployer": "0x98b2920d53612483f91f12ed7754e51b4a77919e", "priceFeedImplementation": "", "priceFeedQuotedImplementation": "", + "inceptionPriceFeedImplementation": "", "mellowPriceFeedImplementation": "", "cloneFactory": "", "cloneFactoryQuoted": "", "cloneFactoryMellow": "", + "cloneFactoryInception": "", "cloneFactoryYn": "" }, { @@ -329,10 +365,12 @@ "priceFeedImplementation": "", "priceFeedQuotedImplementation": "", "mellowPriceFeedImplementation": "", + "inceptionPriceFeedImplementation": "", "ynPriceFeedImplementation": "", "cloneFactory": "", "cloneFactoryQuoted": "", "cloneFactoryMellow": "", + "cloneFactoryInception": "", "cloneFactoryYn": "" }, { @@ -347,10 +385,12 @@ "priceFeedImplementation": "", "priceFeedQuotedImplementation": "", "mellowPriceFeedImplementation": "", + "inceptionPriceFeedImplementation": "", "ynPriceFeedImplementation": "", "cloneFactory": "", "cloneFactoryQuoted": "", "cloneFactoryMellow": "", + "cloneFactoryInception": "", "cloneFactoryYn": "" } ]