From cc42caaa0b4a5a2f8c9bb0bb776243c7489d6653 Mon Sep 17 00:00:00 2001 From: Abhishekkochar Date: Sat, 6 Jul 2024 00:49:07 +1000 Subject: [PATCH 1/3] Script to deploy on sepolia testnet Signed-off-by: Abhishekkochar --- hardhat.config.ts | 32 +++++++++++++-------------- ignition/deploy.ts | 51 +++++++++++++++++++++++++++++++++++++++++++ tsconfig.hardhat.json | 3 ++- tsconfig.json | 5 +++-- 4 files changed, 72 insertions(+), 19 deletions(-) create mode 100644 ignition/deploy.ts diff --git a/hardhat.config.ts b/hardhat.config.ts index 9a751e726..4daa1855d 100644 --- a/hardhat.config.ts +++ b/hardhat.config.ts @@ -51,27 +51,27 @@ const config: HardhatUserConfig = { blockGasLimit: 12000000 }, localhost: { - url: "http://127.0.0.1:8545", + url: "http://[::1]:8545", forking: (process.env.FORK) ? forkingConfig : undefined, timeout: 200000, gas: 12000000, blockGasLimit: 12000000 }, - kovan: { - url: "https://kovan.infura.io/v3/" + process.env.INFURA_TOKEN, - // @ts-ignore - accounts: [`0x${process.env.KOVAN_DEPLOY_PRIVATE_KEY}`], - }, - staging_mainnet: { - url: "https://mainnet.infura.io/v3/" + process.env.INFURA_TOKEN, - // @ts-ignore - accounts: [`0x${process.env.STAGING_MAINNET_DEPLOY_PRIVATE_KEY}`], - }, - production: { - url: "https://mainnet.infura.io/v3/" + process.env.INFURA_TOKEN, - // @ts-ignore - accounts: [`0x${process.env.PRODUCTION_MAINNET_DEPLOY_PRIVATE_KEY}`], - }, + // kovan: { + // url: "https://kovan.infura.io/v3/" + process.env.INFURA_TOKEN, + // // @ts-ignore + // accounts: [`0x${process.env.KOVAN_DEPLOY_PRIVATE_KEY}`], + // }, + // staging_mainnet: { + // url: "https://mainnet.infura.io/v3/" + process.env.INFURA_TOKEN, + // // @ts-ignore + // accounts: [`0x${process.env.STAGING_MAINNET_DEPLOY_PRIVATE_KEY}`], + // }, + // production: { + // url: "https://mainnet.infura.io/v3/" + process.env.INFURA_TOKEN, + // // @ts-ignore + // accounts: [`0x${process.env.PRODUCTION_MAINNET_DEPLOY_PRIVATE_KEY}`], + // }, // To update coverage network configuration got o .solcover.js and update param in providerOptions field coverage: { url: "http://127.0.0.1:8555", // Coverage launches its own ganache-cli client diff --git a/ignition/deploy.ts b/ignition/deploy.ts new file mode 100644 index 000000000..4165a03ce --- /dev/null +++ b/ignition/deploy.ts @@ -0,0 +1,51 @@ +import { getAccounts } from "../utils/test" +import DeployHelper from "../utils/deploys"; +import { ether } from "../utils/index"; + +async function deploy(){ + + const [owner, feeRecipient] = await getAccounts(); + + const deployer = new DeployHelper(owner.wallet) + // Deploying the controller + const controller = await deployer.core.deployController(feeRecipient.address) + const controllerAddress = controller.address + console.log("Controller contract address: ", controllerAddress) + // Deploying setTokenCreator + const setTokenCreator = await deployer.core.deploySetTokenCreator(controllerAddress) + const tokenCreatorAddress = setTokenCreator.address + console.log("Token creator address: ", tokenCreatorAddress) + // Deployiing integration registry + const integrationContract = await deployer.core.deployIntegrationRegistry(controllerAddress) + console.log("Inegration registry contract address: ", integrationContract.address) + // Deploying setValuer contract + const valuerContract = await deployer.core.deploySetValuer(controllerAddress) + console.log("Set vauler contract address: ", valuerContract.address) + // Deploying mock tokens + const metaData = [{name: "MUSDC Coin", symbol: "mUsdc", address: " "}, {name: "MDAI Coin", symbol: "mDai", address: " "},{name: "MBTC Coin", symbol: "mWbtc", address: " "}, /*{name: "MWETH coin", symbol: "mWeth", address: " "}*/] + for(let data of metaData){ + const mockTokenContract = await deployer.mocks.deployTokenMock(owner.address, ether(1000000000), data.symbol === "mWbtc" ? 18 : 6, data.name, data.symbol) + data.address = mockTokenContract.address + } + console.log("Updated metadata: ", metaData) + const WETH = await deployer.external.deployWETH() + const WETHAddress = WETH.address + console.log("WETH contract address: ", WETHAddress) + // Deploying Price Oracle + const priceOracleContract = await deployer.core.deployPriceOracle(controllerAddress, metaData[0].address, [],[/*USDC*/metaData[0].address, /*USDT*/metaData[1].address, /*WBTC*/metaData[2].address, /*WETH*/WETHAddress], /* All USDC */ [metaData[0].address, metaData[0].address, metaData[0].address, metaData[0].address], [/*USDC-USDC*/"0xA2F78ab2355fe2f984D808B5CeE7FD0A93D5270E", /*DAI-USDC*/ "0x14866185B1962B63C3Ea9E03Bc1da838bab34C19",/*WBTC-USDC*/"0x1b44F3514812d835EB1BDB0acB33d3fA3351Ee43",/*ETH-USDC*/ "0x694AA1769357215DE4FAC081bf1f309aDC325306" ]) + console.log("Price Oracle contract address: ", priceOracleContract.address) + // GeneralIndexModule: this will help with rebalance + const generalIndexModuleContract = await deployer.modules.deployGeneralIndexModule(controllerAddress, WETH.address) + const genearlIndexAddress = generalIndexModuleContract.address + console.log("General IndexModule Contract: ", genearlIndexAddress) + // BasicIssuanceModule: to mint and redeem set tokens + const basicIssuanceModuleContract = await deployer.modules.deployBasicIssuanceModule(controllerAddress) + const issuanceAddress = basicIssuanceModuleContract.address + console.log("Basic IssuanceModule Contract: ", issuanceAddress ) + // Deploying SetToken + const setToken = await deployer.core.deploySetToken([WETHAddress, metaData[2].address, metaData[1].address], [30,30,40], [genearlIndexAddress, issuanceAddress], controllerAddress, owner.address, "ETH-BTC_USDT Index", "EBU") + const setTokenAddress = setToken.address + console.log("ETH-BTC-USDt Token set address: ", setTokenAddress) +} + +deploy() \ No newline at end of file diff --git a/tsconfig.hardhat.json b/tsconfig.hardhat.json index f04ad5cfd..8cd906535 100644 --- a/tsconfig.hardhat.json +++ b/tsconfig.hardhat.json @@ -21,7 +21,8 @@ "./utils/**/*.ts", "./deploy/**/*.ts", "./typechain/**/*.ts", - "./tasks/**/*.ts" + "./tasks/**/*.ts", + "./ignition/**/*.ts" ], "files": [ "hardhat.config.ts", diff --git a/tsconfig.json b/tsconfig.json index 6f7aa744d..6baac49eb 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -15,7 +15,7 @@ "moduleResolution": "node", "paths": { "@utils/*": ["utils/*"], - "@typechain/*": ["typechain/*"] + "@typechain/*": ["typechain/*"], } }, "include": [ @@ -23,7 +23,8 @@ "./utils/**/*.ts", "./deploy/**/*.ts", "./typechain/**/*.ts", - "./tasks/**/*.ts" + "./tasks/**/*.ts", + "./ignition/**/*.ts" ], "files": [ "hardhat.config.ts", From a1ce741960a26dd0f0a0e3174ed89d2567c9c6c4 Mon Sep 17 00:00:00 2001 From: Abhishekkochar Date: Fri, 12 Jul 2024 22:03:25 +1000 Subject: [PATCH 2/3] Added chainlink oracle Signed-off-by: Abhishekkochar --- .../external/IAggregatorInterface.sol | 12 +++ contracts/protocol/PriceOracle.sol | 10 +- contracts/protocol/SetTokenCreator.sol | 3 +- contracts/protocol/SetValuer.sol | 9 +- .../oracles/ChainlinkOracleAdapter.sol | 49 ++++++++++ .../modules/v1/BasicIssuanceModule.sol | 3 - ignition/approve.ts | 22 +++++ ignition/deploy.ts | 98 ++++++++++++------- ignition/deployCoreContracts.ts | 25 +++++ ignition/deployMockTokens.ts | 22 +++++ ignition/deployModules.ts | 20 ++++ tsconfig.hardhat.json | 3 +- tsconfig.json | 3 +- 13 files changed, 227 insertions(+), 52 deletions(-) create mode 100644 contracts/interfaces/external/IAggregatorInterface.sol create mode 100644 contracts/protocol/integration/oracles/ChainlinkOracleAdapter.sol create mode 100644 ignition/approve.ts create mode 100644 ignition/deployCoreContracts.ts create mode 100644 ignition/deployMockTokens.ts create mode 100644 ignition/deployModules.ts diff --git a/contracts/interfaces/external/IAggregatorInterface.sol b/contracts/interfaces/external/IAggregatorInterface.sol new file mode 100644 index 000000000..f4c296fda --- /dev/null +++ b/contracts/interfaces/external/IAggregatorInterface.sol @@ -0,0 +1,12 @@ +pragma solidity 0.6.10; + +interface AggregatorInterface { + function latestAnswer() external view returns (int256); + function latestTimestamp() external view returns (uint256); + function latestRound() external view returns (uint256); + function getAnswer(uint256 roundId) external view returns (int256); + function getTimestamp(uint256 roundId) external view returns (uint256); + + event AnswerUpdated(int256 indexed current, uint256 indexed roundId, uint256 timestamp); + event NewRound(uint256 indexed roundId, address indexed startedBy); +} \ No newline at end of file diff --git a/contracts/protocol/PriceOracle.sol b/contracts/protocol/PriceOracle.sol index 8a89381e1..507a557a0 100644 --- a/contracts/protocol/PriceOracle.sol +++ b/contracts/protocol/PriceOracle.sol @@ -26,6 +26,7 @@ import { IController } from "../interfaces/IController.sol"; import { IOracle } from "../interfaces/IOracle.sol"; import { IOracleAdapter } from "../interfaces/IOracleAdapter.sol"; import { PreciseUnitMath } from "../lib/PreciseUnitMath.sol"; +import "hardhat/console.sol"; /** @@ -115,24 +116,25 @@ contract PriceOracle is Ownable { * @return Price of asset pair to 18 decimals of precision */ function getPrice(address _assetOne, address _assetTwo) external view returns (uint256) { + console.log("Price Oracle Test 1"); require( controller.isSystemContract(msg.sender), "PriceOracle.getPrice: Caller must be system contract." ); - + console.log("Price Oracle Test 2"); bool priceFound; uint256 price; (priceFound, price) = _getDirectOrInversePrice(_assetOne, _assetTwo); - + console.log("Price Oracle Test 3"); if (!priceFound) { (priceFound, price) = _getPriceFromMasterQuote(_assetOne, _assetTwo); } - + console.log("Price Oracle Test 4"); if (!priceFound) { (priceFound, price) = _getPriceFromAdapters(_assetOne, _assetTwo); } - + console.log("Price Oracle Test 5"); require(priceFound, "PriceOracle.getPrice: Price not found."); return price; diff --git a/contracts/protocol/SetTokenCreator.sol b/contracts/protocol/SetTokenCreator.sol index 230451fa3..07473ef06 100644 --- a/contracts/protocol/SetTokenCreator.sol +++ b/contracts/protocol/SetTokenCreator.sol @@ -19,6 +19,7 @@ pragma solidity 0.6.10; pragma experimental "ABIEncoderV2"; +import "hardhat/console.sol"; import { IController } from "../interfaces/IController.sol"; import { SetToken } from "./SetToken.sol"; import { AddressArrayUtils } from "../lib/AddressArrayUtils.sol"; @@ -99,7 +100,7 @@ contract SetTokenCreator { _name, _symbol ); - + console.log("Test: ", address(setToken)); // Registers Set with controller controller.addSet(address(setToken)); diff --git a/contracts/protocol/SetValuer.sol b/contracts/protocol/SetValuer.sol index 98dc29662..139ce1bd6 100644 --- a/contracts/protocol/SetValuer.sol +++ b/contracts/protocol/SetValuer.sol @@ -29,6 +29,7 @@ import { IPriceOracle } from "../interfaces/IPriceOracle.sol"; import { PreciseUnitMath } from "../lib/PreciseUnitMath.sol"; import { Position } from "./lib/Position.sol"; import { ResourceIdentifier } from "./lib/ResourceIdentifier.sol"; +import "hardhat/console.sol"; /** @@ -81,16 +82,18 @@ contract SetValuer { * @return SetToken valuation in terms of quote asset in precise units 1e18 */ function calculateSetTokenValuation(ISetToken _setToken, address _quoteAsset) external view returns (uint256) { + console.log("Test"); IPriceOracle priceOracle = controller.getPriceOracle(); address masterQuoteAsset = priceOracle.masterQuoteAsset(); address[] memory components = _setToken.getComponents(); + console.log("Test 1"); int256 valuation; for (uint256 i = 0; i < components.length; i++) { address component = components[i]; // Get component price from price oracle. If price does not exist, revert. uint256 componentPrice = priceOracle.getPrice(component, masterQuoteAsset); - + console.log(componentPrice); int256 aggregateUnits = _setToken.getTotalComponentRealUnits(component); // Normalize each position unit to preciseUnits 1e18 and cast to signed int @@ -101,12 +104,12 @@ contract SetValuer { // Calculate valuation of the component. Debt positions are effectively subtracted valuation = normalizedUnits.preciseMul(componentPrice.toInt256()).add(valuation); } - + console.log("Test 2"); if (masterQuoteAsset != _quoteAsset) { uint256 quoteToMaster = priceOracle.getPrice(_quoteAsset, masterQuoteAsset); valuation = valuation.preciseDiv(quoteToMaster.toInt256()); } - + console.log("Test 3"); return valuation.toUint256(); } } diff --git a/contracts/protocol/integration/oracles/ChainlinkOracleAdapter.sol b/contracts/protocol/integration/oracles/ChainlinkOracleAdapter.sol new file mode 100644 index 000000000..c77367803 --- /dev/null +++ b/contracts/protocol/integration/oracles/ChainlinkOracleAdapter.sol @@ -0,0 +1,49 @@ +pragma solidity 0.6.10; +/** + * @title ChainlinkOracleAdapter + * @author Set Protocol + * + * Coerces outputs from Chainlink oracles to uint256 and adapts value to 18 decimals. + */ +contract ChainlinkOracleAdapter { + using SafeMath for uint256; + + /* ============ Constants ============ */ + uint256 public constant PRICE_MULTIPLIER = 1e10; + + /* ============ State Variables ============ */ + AggregatorInterface public oracle; + + /* ============ Constructor ============ */ + /* + * Set address of aggregator being adapted for use + * + * @param _oracle The address of medianizer being adapted from bytes to uint256 + */ + constructor( + AggregatorInterface _oracle + ) + public + { + oracle = _oracle; + } + + /* ============ External ============ */ + + /* + * Reads value of oracle and coerces return to uint256 then applies price multiplier + * + * @returns Chainlink oracle price in uint256 + */ + function read() + external + view + returns (uint256) + { + // Read value of medianizer and coerce to uint256 + uint256 oracleOutput = uint256(oracle.latestAnswer()); + + // Apply multiplier to create 18 decimal price (since Chainlink returns 8 decimals) + return oracleOutput.mul(PRICE_MULTIPLIER); + } +} \ No newline at end of file diff --git a/contracts/protocol/modules/v1/BasicIssuanceModule.sol b/contracts/protocol/modules/v1/BasicIssuanceModule.sol index 2c5d9eb06..e4cc45303 100644 --- a/contracts/protocol/modules/v1/BasicIssuanceModule.sol +++ b/contracts/protocol/modules/v1/BasicIssuanceModule.sol @@ -95,12 +95,10 @@ contract BasicIssuanceModule is ModuleBase, ReentrancyGuard { require(_quantity > 0, "Issue quantity must be > 0"); address hookContract = _callPreIssueHooks(_setToken, _quantity, msg.sender, _to); - ( address[] memory components, uint256[] memory componentQuantities ) = getRequiredComponentUnitsForIssue(_setToken, _quantity); - // For each position, transfer the required underlying to the SetToken for (uint256 i = 0; i < components.length; i++) { // Transfer the component to the SetToken @@ -114,7 +112,6 @@ contract BasicIssuanceModule is ModuleBase, ReentrancyGuard { // Mint the SetToken _setToken.mint(_to, _quantity); - emit SetTokenIssued(address(_setToken), msg.sender, _to, hookContract, _quantity); } diff --git a/ignition/approve.ts b/ignition/approve.ts new file mode 100644 index 000000000..69fbe9ae3 --- /dev/null +++ b/ignition/approve.ts @@ -0,0 +1,22 @@ +import { ethers } from "ethers" +import { StandardTokenMock, WETH9 } from "../typechain" +import { Account } from "../utils/test/types" + +export async function approveModules({USDC, USDT, BTC, WETH, userOne, module}: IApproveModulesParams){ + console.log("Aprroving modules...") + const maxLimit = ethers.constants.MaxUint256 + await USDC.connect(userOne.wallet).approve(module, maxLimit) + await USDT.connect(userOne.wallet).approve(module, maxLimit) + await BTC.connect(userOne.wallet).approve(module, maxLimit) + await WETH.connect(userOne.wallet).approve(module, maxLimit) + console.log("Finished aprroving modules!\n") +} + +interface IApproveModulesParams{ + USDC: StandardTokenMock; + USDT: StandardTokenMock; + BTC: StandardTokenMock; + WETH: WETH9; + userOne: Account; + module: string +} \ No newline at end of file diff --git a/ignition/deploy.ts b/ignition/deploy.ts index 4165a03ce..774e9f02f 100644 --- a/ignition/deploy.ts +++ b/ignition/deploy.ts @@ -1,51 +1,75 @@ import { getAccounts } from "../utils/test" import DeployHelper from "../utils/deploys"; import { ether } from "../utils/index"; +import { ethers } from "ethers"; +import { SetToken__factory } from "../typechain"; +import { approveModules } from "./approve"; +import { deployMockTokens } from "./deployMockTokens"; +import { deployModules } from "./deployModules"; +import { deployCoreContracts } from "./deployCoreContracts"; -async function deploy(){ - - const [owner, feeRecipient] = await getAccounts(); +const usdcUSDC = "0xA2F78ab2355fe2f984D808B5CeE7FD0A93D5270E" +const daiUSDC = "0x14866185B1962B63C3Ea9E03Bc1da838bab34C19" +const wbtcUSDC = "0x1b44F3514812d835EB1BDB0acB33d3fA3351Ee43" +const ethUSDC = "0x694AA1769357215DE4FAC081bf1f309aDC325306" + +const provider = new ethers.providers.JsonRpcProvider("http://[::1]:8545") +async function deploy(){ + try{ + + const [owner, feeRecipient, userOne] = await getAccounts(); const deployer = new DeployHelper(owner.wallet) - // Deploying the controller - const controller = await deployer.core.deployController(feeRecipient.address) - const controllerAddress = controller.address - console.log("Controller contract address: ", controllerAddress) - // Deploying setTokenCreator - const setTokenCreator = await deployer.core.deploySetTokenCreator(controllerAddress) - const tokenCreatorAddress = setTokenCreator.address - console.log("Token creator address: ", tokenCreatorAddress) - // Deployiing integration registry - const integrationContract = await deployer.core.deployIntegrationRegistry(controllerAddress) - console.log("Inegration registry contract address: ", integrationContract.address) - // Deploying setValuer contract - const valuerContract = await deployer.core.deploySetValuer(controllerAddress) - console.log("Set vauler contract address: ", valuerContract.address) + + // Deploying the controllerContract + const {controllerContract, setTokenCreator, integrationContract, valuerContract, controllerAddress, tokenCreatorAddress, integrationAddress, valuerAddress} = await deployCoreContracts({deployer, feeAddress:feeRecipient.address}) + // Deploying mock tokens - const metaData = [{name: "MUSDC Coin", symbol: "mUsdc", address: " "}, {name: "MDAI Coin", symbol: "mDai", address: " "},{name: "MBTC Coin", symbol: "mWbtc", address: " "}, /*{name: "MWETH coin", symbol: "mWeth", address: " "}*/] - for(let data of metaData){ - const mockTokenContract = await deployer.mocks.deployTokenMock(owner.address, ether(1000000000), data.symbol === "mWbtc" ? 18 : 6, data.name, data.symbol) - data.address = mockTokenContract.address - } - console.log("Updated metadata: ", metaData) - const WETH = await deployer.external.deployWETH() - const WETHAddress = WETH.address - console.log("WETH contract address: ", WETHAddress) + const {USDC, USDT, BTC, WETH, USDCAddress, USDTAddress, BTCAddress, WETHAddress} = await deployMockTokens({deployer, owner: owner.address}) + // Deploying Price Oracle - const priceOracleContract = await deployer.core.deployPriceOracle(controllerAddress, metaData[0].address, [],[/*USDC*/metaData[0].address, /*USDT*/metaData[1].address, /*WBTC*/metaData[2].address, /*WETH*/WETHAddress], /* All USDC */ [metaData[0].address, metaData[0].address, metaData[0].address, metaData[0].address], [/*USDC-USDC*/"0xA2F78ab2355fe2f984D808B5CeE7FD0A93D5270E", /*DAI-USDC*/ "0x14866185B1962B63C3Ea9E03Bc1da838bab34C19",/*WBTC-USDC*/"0x1b44F3514812d835EB1BDB0acB33d3fA3351Ee43",/*ETH-USDC*/ "0x694AA1769357215DE4FAC081bf1f309aDC325306" ]) + const priceOracleContract = await deployer.core.deployPriceOracle(controllerAddress, USDCAddress, [],[USDCAddress, USDTAddress, BTCAddress, WETHAddress], [USDCAddress, USDCAddress, USDCAddress, USDCAddress], [usdcUSDC, daiUSDC, wbtcUSDC, ethUSDC ]) console.log("Price Oracle contract address: ", priceOracleContract.address) + // GeneralIndexModule: this will help with rebalance - const generalIndexModuleContract = await deployer.modules.deployGeneralIndexModule(controllerAddress, WETH.address) - const genearlIndexAddress = generalIndexModuleContract.address - console.log("General IndexModule Contract: ", genearlIndexAddress) - // BasicIssuanceModule: to mint and redeem set tokens - const basicIssuanceModuleContract = await deployer.modules.deployBasicIssuanceModule(controllerAddress) - const issuanceAddress = basicIssuanceModuleContract.address - console.log("Basic IssuanceModule Contract: ", issuanceAddress ) + const {generalIndexContract, issuanceContract, generalIndexAddress, issuanceAddress} = await deployModules({deployer, controllerAddress, WETHAddress}) + + // Initilaize the Controller contract + await controllerContract.connect(owner.wallet).initialize([tokenCreatorAddress], [generalIndexAddress, issuanceAddress],[integrationAddress, priceOracleContract.address, valuerAddress], [0,1,2]) + console.log("Controller has been initialized... \n") + // Deploying SetToken - const setToken = await deployer.core.deploySetToken([WETHAddress, metaData[2].address, metaData[1].address], [30,30,40], [genearlIndexAddress, issuanceAddress], controllerAddress, owner.address, "ETH-BTC_USDT Index", "EBU") - const setTokenAddress = setToken.address - console.log("ETH-BTC-USDt Token set address: ", setTokenAddress) + await setTokenCreator.create([USDTAddress, BTCAddress], [10000,1], [generalIndexAddress, issuanceAddress], owner.address, "BTC_USDT Index", "EBU") + const vaultAddress = await controllerContract.getSets() + console.log("Token Set - ETH-BTC_USDT Index address", vaultAddress[0], "\n") + + // Before issue token, modules must be basicIssuanceModule must be initialized with manager address. + // Initilzing the issuance Module. + await issuanceContract.connect(owner.wallet).initialize(vaultAddress[0], ethers.constants.AddressZero) + // Instance of tokenSet + const vaultContract = new ethers.Contract(vaultAddress[0], SetToken__factory.abi, provider) + + console.log(await vaultContract.getComponents()) + + // Approve module before trying to issuing the tokens. + // To mint 1 token of vault, we need to provide 1ETH, 1 USDT, 1 BTC. + await approveModules({USDC, USDT, BTC, WETH, userOne, module: issuanceAddress}) + await USDT.mint(userOne.address, ether(10)) + await BTC.mint(userOne.address, ether(10)) + + // Before balance of userOne + console.log((await vaultContract.balanceOf(userOne.address)).toString()) + // Issuing token. + await issuanceContract.connect(userOne.wallet).issue(vaultAddress[0], ether(2), userOne.address) + // After balance + console.log((await vaultContract.balanceOf(userOne.address)).toString()) + console.log(await valuerContract.calculateSetTokenValuation(vaultContract.address, USDCAddress)) + + } catch(e){ + console.error(e) + } + + } deploy() \ No newline at end of file diff --git a/ignition/deployCoreContracts.ts b/ignition/deployCoreContracts.ts new file mode 100644 index 000000000..53ade7cea --- /dev/null +++ b/ignition/deployCoreContracts.ts @@ -0,0 +1,25 @@ +import DeployHelper from "../utils/deploys" + +export async function deployCoreContracts({deployer, feeAddress}:ICoreContractsParams){ + console.log("Deploying core contracts...") + const controllerContract = await deployer.core.deployController(feeAddress) + const controllerAddress = controllerContract.address + console.log("Controller contract address: ", controllerAddress) + // Deploying setTokenCreator + const setTokenCreator = await deployer.core.deploySetTokenCreator(controllerAddress) + const tokenCreatorAddress = setTokenCreator.address + console.log("Token creator address: ", tokenCreatorAddress) + // Deployiing integration registry + const integrationContract = await deployer.core.deployIntegrationRegistry(controllerAddress) + console.log("Inegration registry contract address: ", integrationContract.address) + // Deploying setValuer contract + const valuerContract = await deployer.core.deploySetValuer(controllerAddress) + console.log("Set vauler contract address: ", valuerContract.address) + console.log("Finished deploying core contracts!\n") + + return {controllerContract, setTokenCreator, integrationContract, valuerContract, controllerAddress, tokenCreatorAddress, integrationAddress: integrationContract.address, valuerAddress: valuerContract.address} +} +interface ICoreContractsParams{ + deployer:DeployHelper; + feeAddress: string +} \ No newline at end of file diff --git a/ignition/deployMockTokens.ts b/ignition/deployMockTokens.ts new file mode 100644 index 000000000..c158df1f7 --- /dev/null +++ b/ignition/deployMockTokens.ts @@ -0,0 +1,22 @@ +import { ether } from "../utils" +import DeployHelper from "../utils/deploys" + +export async function deployMockTokens({deployer, owner}: IMockTokensParams){ + console.log("Deploying Mock tokens...") + const usdcContract = await deployer.mocks.deployTokenMock(owner, ether(1000000000), 6, "MUSDC Coin", "mUsdc") + const usdtContract = await deployer.mocks.deployTokenMock(owner, ether(1000000000), 6, "MUSDT Coin", "mUsdt") + const btcContract = await deployer.mocks.deployTokenMock(owner, ether(1000000000), 18, "MBTC Coin", "mBtc") + const WETH = await deployer.external.deployWETH() + console.log("USDC address: ", usdcContract.address) + console.log("USDT address: ", usdtContract.address) + console.log("BTC address: ", btcContract.address) + console.log("WETH address: ", WETH.address) + console.log("Finished deploying mock tokens!\n") + return {USDT:usdtContract, USDC:usdcContract, BTC:btcContract, WETH, USDCAddress:usdcContract.address, + USDTAddress:usdtContract.address,BTCAddress:btcContract.address, WETHAddress:WETH.address} +} + +interface IMockTokensParams{ + deployer: DeployHelper; + owner: string; +} \ No newline at end of file diff --git a/ignition/deployModules.ts b/ignition/deployModules.ts new file mode 100644 index 000000000..6ff2ae54e --- /dev/null +++ b/ignition/deployModules.ts @@ -0,0 +1,20 @@ +import DeployHelper from "../utils/deploys" + +export async function deployModules({deployer, controllerAddress, WETHAddress}: IDeployModuleParmas) { + console.log("Deploying modules...") + const generalIndexModuleContract = await deployer.modules.deployGeneralIndexModule(controllerAddress, WETHAddress) + const generalIndexAddress = generalIndexModuleContract.address + console.log("General IndexModule Contract: ", generalIndexAddress) + // BasicIssuanceModule: to mint and redeem set tokens + const basicIssuanceModuleContract = await deployer.modules.deployBasicIssuanceModule(controllerAddress) + const issuanceAddress = basicIssuanceModuleContract.address + console.log("Basic IssuanceModule Contract: ", issuanceAddress ) + console.log("Finished deploying modules!\n") + return {generalIndexContract: generalIndexModuleContract, issuanceContract: basicIssuanceModuleContract, generalIndexAddress: generalIndexModuleContract.address, issuanceAddress: basicIssuanceModuleContract.address} +} + +interface IDeployModuleParmas{ + deployer: DeployHelper; + controllerAddress: string; + WETHAddress: string +} diff --git a/tsconfig.hardhat.json b/tsconfig.hardhat.json index 8cd906535..f04ad5cfd 100644 --- a/tsconfig.hardhat.json +++ b/tsconfig.hardhat.json @@ -21,8 +21,7 @@ "./utils/**/*.ts", "./deploy/**/*.ts", "./typechain/**/*.ts", - "./tasks/**/*.ts", - "./ignition/**/*.ts" + "./tasks/**/*.ts" ], "files": [ "hardhat.config.ts", diff --git a/tsconfig.json b/tsconfig.json index 6baac49eb..7076de6fe 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -23,8 +23,7 @@ "./utils/**/*.ts", "./deploy/**/*.ts", "./typechain/**/*.ts", - "./tasks/**/*.ts", - "./ignition/**/*.ts" + "./tasks/**/*.ts" ], "files": [ "hardhat.config.ts", From 978037c776c4f034c532f5a0ac35e03ad4b6d0ce Mon Sep 17 00:00:00 2001 From: Abhishekkochar Date: Sat, 27 Jul 2024 01:14:21 +1000 Subject: [PATCH 3/3] Added support to deploy on seploia testnet Signed-off-by: Abhishekkochar --- contracts/protocol/PriceOracle.sol | 8 +++-- .../oracles/ChainlinkOracleAdapter.sol | 2 ++ {ignition => deployment}/approve.ts | 6 ++-- {ignition => deployment}/deploy.ts | 24 ++++++++----- .../deployCoreContracts.ts | 0 {ignition => deployment}/deployMockTokens.ts | 8 ++--- {ignition => deployment}/deployModules.ts | 0 deployment/deployOracleAdapter.ts | 32 +++++++++++++++++ hardhat.config.ts | 35 ++++--------------- utils/contracts/index.ts | 1 + utils/deploys/deployAdapters.ts | 8 +++++ 11 files changed, 76 insertions(+), 48 deletions(-) rename {ignition => deployment}/approve.ts (75%) rename {ignition => deployment}/deploy.ts (72%) rename {ignition => deployment}/deployCoreContracts.ts (100%) rename {ignition => deployment}/deployMockTokens.ts (67%) rename {ignition => deployment}/deployModules.ts (100%) create mode 100644 deployment/deployOracleAdapter.ts diff --git a/contracts/protocol/PriceOracle.sol b/contracts/protocol/PriceOracle.sol index 507a557a0..7d425d2c7 100644 --- a/contracts/protocol/PriceOracle.sol +++ b/contracts/protocol/PriceOracle.sol @@ -124,7 +124,7 @@ contract PriceOracle is Ownable { console.log("Price Oracle Test 2"); bool priceFound; uint256 price; - + console.log("Price Oracle Test 2.5"); (priceFound, price) = _getDirectOrInversePrice(_assetOne, _assetTwo); console.log("Price Oracle Test 3"); if (!priceFound) { @@ -261,13 +261,15 @@ contract PriceOracle is Ownable { returns (bool, uint256) { IOracle directOracle = oracles[_assetOne][_assetTwo]; + console.logAddress( address(directOracle)); bool hasDirectOracle = address(directOracle) != address(0); - + console.log("Direct price 1"); // Check asset1 -> asset 2. If exists, then return value if (hasDirectOracle) { + console.log("Direct price 2"); return (true, directOracle.read()); } - + console.log("Direct price 3"); IOracle inverseOracle = oracles[_assetTwo][_assetOne]; bool hasInverseOracle = address(inverseOracle) != address(0); diff --git a/contracts/protocol/integration/oracles/ChainlinkOracleAdapter.sol b/contracts/protocol/integration/oracles/ChainlinkOracleAdapter.sol index c77367803..6d2f41a01 100644 --- a/contracts/protocol/integration/oracles/ChainlinkOracleAdapter.sol +++ b/contracts/protocol/integration/oracles/ChainlinkOracleAdapter.sol @@ -1,4 +1,6 @@ pragma solidity 0.6.10; +import "../../../interfaces/external/IAggregatorInterface.sol"; +import { SafeMath } from "@openzeppelin/contracts/math/SafeMath.sol"; /** * @title ChainlinkOracleAdapter * @author Set Protocol diff --git a/ignition/approve.ts b/deployment/approve.ts similarity index 75% rename from ignition/approve.ts rename to deployment/approve.ts index 69fbe9ae3..e867f3a9d 100644 --- a/ignition/approve.ts +++ b/deployment/approve.ts @@ -2,11 +2,11 @@ import { ethers } from "ethers" import { StandardTokenMock, WETH9 } from "../typechain" import { Account } from "../utils/test/types" -export async function approveModules({USDC, USDT, BTC, WETH, userOne, module}: IApproveModulesParams){ +export async function approveModules({USDC, DAI, BTC, WETH, userOne, module}: IApproveModulesParams){ console.log("Aprroving modules...") const maxLimit = ethers.constants.MaxUint256 await USDC.connect(userOne.wallet).approve(module, maxLimit) - await USDT.connect(userOne.wallet).approve(module, maxLimit) + await DAI.connect(userOne.wallet).approve(module, maxLimit) await BTC.connect(userOne.wallet).approve(module, maxLimit) await WETH.connect(userOne.wallet).approve(module, maxLimit) console.log("Finished aprroving modules!\n") @@ -14,7 +14,7 @@ export async function approveModules({USDC, USDT, BTC, WETH, userOne, module}: I interface IApproveModulesParams{ USDC: StandardTokenMock; - USDT: StandardTokenMock; + DAI: StandardTokenMock; BTC: StandardTokenMock; WETH: WETH9; userOne: Account; diff --git a/ignition/deploy.ts b/deployment/deploy.ts similarity index 72% rename from ignition/deploy.ts rename to deployment/deploy.ts index 774e9f02f..8bcdec082 100644 --- a/ignition/deploy.ts +++ b/deployment/deploy.ts @@ -7,28 +7,34 @@ import { approveModules } from "./approve"; import { deployMockTokens } from "./deployMockTokens"; import { deployModules } from "./deployModules"; import { deployCoreContracts } from "./deployCoreContracts"; +import { deployOracleAdapter } from "./deployOracleAdapter" const usdcUSDC = "0xA2F78ab2355fe2f984D808B5CeE7FD0A93D5270E" const daiUSDC = "0x14866185B1962B63C3Ea9E03Bc1da838bab34C19" const wbtcUSDC = "0x1b44F3514812d835EB1BDB0acB33d3fA3351Ee43" const ethUSDC = "0x694AA1769357215DE4FAC081bf1f309aDC325306" -const provider = new ethers.providers.JsonRpcProvider("http://[::1]:8545") +const provider = new ethers.providers.JsonRpcProvider("http://127.0.0.1:8545/") async function deploy(){ try{ const [owner, feeRecipient, userOne] = await getAccounts(); const deployer = new DeployHelper(owner.wallet) + console.log(await provider.getNetwork()) // Deploying the controllerContract const {controllerContract, setTokenCreator, integrationContract, valuerContract, controllerAddress, tokenCreatorAddress, integrationAddress, valuerAddress} = await deployCoreContracts({deployer, feeAddress:feeRecipient.address}) // Deploying mock tokens - const {USDC, USDT, BTC, WETH, USDCAddress, USDTAddress, BTCAddress, WETHAddress} = await deployMockTokens({deployer, owner: owner.address}) + const {USDC, DAI, BTC, WETH, USDCAddress, DAIAddress, BTCAddress, WETHAddress} = await deployMockTokens({deployer, owner: owner.address}) + + // Deploy Chainlink Price Oracle adaptor + + const {USDC_USD, DAI_USDC, ETH_USD, BTC_USD, LINK_USD} = await deployOracleAdapter({deployer}) // Deploying Price Oracle - const priceOracleContract = await deployer.core.deployPriceOracle(controllerAddress, USDCAddress, [],[USDCAddress, USDTAddress, BTCAddress, WETHAddress], [USDCAddress, USDCAddress, USDCAddress, USDCAddress], [usdcUSDC, daiUSDC, wbtcUSDC, ethUSDC ]) + const priceOracleContract = await deployer.core.deployPriceOracle(controllerAddress, USDCAddress, [],[USDCAddress, DAIAddress, BTCAddress, WETHAddress], [USDCAddress, USDCAddress, USDCAddress, USDCAddress], [USDC_USD, DAI_USDC, BTC_USD, ETH_USD]) console.log("Price Oracle contract address: ", priceOracleContract.address) // GeneralIndexModule: this will help with rebalance @@ -39,22 +45,21 @@ async function deploy(){ console.log("Controller has been initialized... \n") // Deploying SetToken - await setTokenCreator.create([USDTAddress, BTCAddress], [10000,1], [generalIndexAddress, issuanceAddress], owner.address, "BTC_USDT Index", "EBU") + await setTokenCreator.create([DAIAddress, BTCAddress], [10000,1], [generalIndexAddress, issuanceAddress], owner.address, "ETH-BTC_DAI Index", "EBD") const vaultAddress = await controllerContract.getSets() - console.log("Token Set - ETH-BTC_USDT Index address", vaultAddress[0], "\n") + console.log("Token Set - ETH-BTC_DAI Index address", vaultAddress[0], "\n") // Before issue token, modules must be basicIssuanceModule must be initialized with manager address. // Initilzing the issuance Module. await issuanceContract.connect(owner.wallet).initialize(vaultAddress[0], ethers.constants.AddressZero) // Instance of tokenSet const vaultContract = new ethers.Contract(vaultAddress[0], SetToken__factory.abi, provider) - console.log(await vaultContract.getComponents()) // Approve module before trying to issuing the tokens. - // To mint 1 token of vault, we need to provide 1ETH, 1 USDT, 1 BTC. - await approveModules({USDC, USDT, BTC, WETH, userOne, module: issuanceAddress}) - await USDT.mint(userOne.address, ether(10)) + // To mint 1 token of vault, we need to provide 1ETH, 1 DAI, 1 BTC. + await approveModules({USDC, DAI, BTC, WETH, userOne, module: issuanceAddress}) + await DAI.mint(userOne.address, ether(10)) await BTC.mint(userOne.address, ether(10)) // Before balance of userOne @@ -63,6 +68,7 @@ async function deploy(){ await issuanceContract.connect(userOne.wallet).issue(vaultAddress[0], ether(2), userOne.address) // After balance console.log((await vaultContract.balanceOf(userOne.address)).toString()) + console.log(await valuerContract.calculateSetTokenValuation(vaultContract.address, USDCAddress)) } catch(e){ diff --git a/ignition/deployCoreContracts.ts b/deployment/deployCoreContracts.ts similarity index 100% rename from ignition/deployCoreContracts.ts rename to deployment/deployCoreContracts.ts diff --git a/ignition/deployMockTokens.ts b/deployment/deployMockTokens.ts similarity index 67% rename from ignition/deployMockTokens.ts rename to deployment/deployMockTokens.ts index c158df1f7..b6b98b067 100644 --- a/ignition/deployMockTokens.ts +++ b/deployment/deployMockTokens.ts @@ -4,16 +4,16 @@ import DeployHelper from "../utils/deploys" export async function deployMockTokens({deployer, owner}: IMockTokensParams){ console.log("Deploying Mock tokens...") const usdcContract = await deployer.mocks.deployTokenMock(owner, ether(1000000000), 6, "MUSDC Coin", "mUsdc") - const usdtContract = await deployer.mocks.deployTokenMock(owner, ether(1000000000), 6, "MUSDT Coin", "mUsdt") + const daiContract = await deployer.mocks.deployTokenMock(owner, ether(1000000000), 6, "Mdai Coin", "mdai") const btcContract = await deployer.mocks.deployTokenMock(owner, ether(1000000000), 18, "MBTC Coin", "mBtc") const WETH = await deployer.external.deployWETH() console.log("USDC address: ", usdcContract.address) - console.log("USDT address: ", usdtContract.address) + console.log("DAI address: ", daiContract.address) console.log("BTC address: ", btcContract.address) console.log("WETH address: ", WETH.address) console.log("Finished deploying mock tokens!\n") - return {USDT:usdtContract, USDC:usdcContract, BTC:btcContract, WETH, USDCAddress:usdcContract.address, - USDTAddress:usdtContract.address,BTCAddress:btcContract.address, WETHAddress:WETH.address} + return {DAI:daiContract, USDC:usdcContract, BTC:btcContract, WETH, USDCAddress:usdcContract.address, + DAIAddress:daiContract.address,BTCAddress:btcContract.address, WETHAddress:WETH.address} } interface IMockTokensParams{ diff --git a/ignition/deployModules.ts b/deployment/deployModules.ts similarity index 100% rename from ignition/deployModules.ts rename to deployment/deployModules.ts diff --git a/deployment/deployOracleAdapter.ts b/deployment/deployOracleAdapter.ts new file mode 100644 index 000000000..557233243 --- /dev/null +++ b/deployment/deployOracleAdapter.ts @@ -0,0 +1,32 @@ +import { ether } from "../utils" +import DeployHelper from "../utils/deploys" + +const oracles = { + "USDC_USD": "0xA2F78ab2355fe2f984D808B5CeE7FD0A93D5270E", + "DAI_USDC": "0x14866185B1962B63C3Ea9E03Bc1da838bab34C19", + "ETH_USD": "0x694AA1769357215DE4FAC081bf1f309aDC325306", + "BTC_USD": "0x1b44F3514812d835EB1BDB0acB33d3fA3351Ee43", + "LINK_USD": "0xc59E3633BAAC79493d908e63626716e204A45EdF", +}; + + +export async function deployOracleAdapter({deployer}: IOracleParams){ + console.log("Deploying Chainlink adpators ...") + const oracleAddresses:Record = {} + + try{ + for (const [key, address] of Object.entries(oracles)){ + const oracle = await deployer.adapters.deployChainlinkOrcaleAdapter(address) + oracleAddresses[`${key}`] = oracle.address + console.log(`${key} adapter oracle address: ${oracle.address}`); + } + console.log("Finished deploying oracle adaptors!\n") + } catch(e){ + console.error("Error deploying one or more adapters: ", e) + } + return oracleAddresses +} + +interface IOracleParams{ + deployer: DeployHelper; +} \ No newline at end of file diff --git a/hardhat.config.ts b/hardhat.config.ts index 4daa1855d..67f57c4a9 100644 --- a/hardhat.config.ts +++ b/hardhat.config.ts @@ -12,16 +12,10 @@ import "solidity-coverage"; import "./tasks"; const forkingConfig = { - url: `https://eth-mainnet.alchemyapi.io/v2/${process.env.ALCHEMY_TOKEN}`, - blockNumber: 14792479, + url: `https://eth-sepolia.g.alchemy.com/v2/${process.env.ALCHEMY_TOKEN}`, + blockNumber: 6378120, }; -const mochaConfig = { - grep: "@forked-mainnet", - invert: (process.env.FORK) ? false : true, - timeout: (process.env.FORK) ? 100000 : 40000, -} as Mocha.MochaOptions; - checkForkedProviderEnvironment(); const config: HardhatUserConfig = { @@ -51,32 +45,17 @@ const config: HardhatUserConfig = { blockGasLimit: 12000000 }, localhost: { - url: "http://[::1]:8545", + url: "http://127.0.0.1:8545/", forking: (process.env.FORK) ? forkingConfig : undefined, timeout: 200000, gas: 12000000, blockGasLimit: 12000000 }, - // kovan: { - // url: "https://kovan.infura.io/v3/" + process.env.INFURA_TOKEN, - // // @ts-ignore - // accounts: [`0x${process.env.KOVAN_DEPLOY_PRIVATE_KEY}`], - // }, - // staging_mainnet: { - // url: "https://mainnet.infura.io/v3/" + process.env.INFURA_TOKEN, - // // @ts-ignore - // accounts: [`0x${process.env.STAGING_MAINNET_DEPLOY_PRIVATE_KEY}`], - // }, - // production: { - // url: "https://mainnet.infura.io/v3/" + process.env.INFURA_TOKEN, + // sepolia: { + // url: `https://eth-sepolia.g.alchemy.com/v2/${process.env.ALCHEMY_TOKEN}`, // // @ts-ignore - // accounts: [`0x${process.env.PRODUCTION_MAINNET_DEPLOY_PRIVATE_KEY}`], + // accounts: [`0x${process.env.DEPLOY_PRIVATE_KEY}`], // }, - // To update coverage network configuration got o .solcover.js and update param in providerOptions field - coverage: { - url: "http://127.0.0.1:8555", // Coverage launches its own ganache-cli client - timeout: 200000, - }, }, // @ts-ignore typechain: { @@ -89,8 +68,6 @@ const config: HardhatUserConfig = { runOnCompile: false, }, - mocha: mochaConfig, - // These are external artifacts we don't compile but would like to improve // test performance for by hardcoding the gas into the abi at runtime // @ts-ignore diff --git a/utils/contracts/index.ts b/utils/contracts/index.ts index a5635d0fe..85d08e5cf 100644 --- a/utils/contracts/index.ts +++ b/utils/contracts/index.ts @@ -136,3 +136,4 @@ export { YearnWrapV2Adapter } from "../../typechain/YearnWrapV2Adapter"; export { YearnStrategyMock } from "../../typechain/YearnStrategyMock"; export { ZeroExApiAdapter } from "../../typechain/ZeroExApiAdapter"; export { ZeroExMock } from "../../typechain/ZeroExMock"; +export {ChainlinkOracleAdapter} from "../../typechain/ChainlinkOracleAdapter"; diff --git a/utils/deploys/deployAdapters.ts b/utils/deploys/deployAdapters.ts index 72af8e9d1..828c00ae8 100644 --- a/utils/deploys/deployAdapters.ts +++ b/utils/deploys/deployAdapters.ts @@ -28,6 +28,7 @@ import { CompoundBravoGovernanceAdapter, CompClaimAdapter, RgtMigrationWrapAdapter, + ChainlinkOracleAdapter, } from "../contracts"; import { Address, Bytes } from "./../types"; @@ -58,6 +59,7 @@ import { SynthetixExchangeAdapter__factory } from "../../typechain/factories/Syn import { CompoundBravoGovernanceAdapter__factory } from "../../typechain/factories/CompoundBravoGovernanceAdapter__factory"; import { CompClaimAdapter__factory } from "../../typechain"; import { RgtMigrationWrapAdapter__factory } from "../../typechain/factories/RgtMigrationWrapAdapter__factory"; +import { ChainlinkOracleAdapter__factory } from "../../typechain/factories/ChainlinkOracleAdapter__factory"; export default class DeployAdapters { private _deployerSigner: Signer; @@ -66,6 +68,12 @@ export default class DeployAdapters { this._deployerSigner = deployerSigner; } + public async deployChainlinkOrcaleAdapter( + ChainlinkOracle: Address, + ): Promise { + return await new ChainlinkOracleAdapter__factory(this._deployerSigner).deploy(ChainlinkOracle); + } + public async deployKyberExchangeAdapter( kyberNetworkProxy: Address, ): Promise {