Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: add decimals in nft oracle #129

Merged
merged 2 commits into from
Nov 12, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
57 changes: 57 additions & 0 deletions abis/NFTOracle.json
Original file line number Diff line number Diff line change
Expand Up @@ -183,6 +183,32 @@
"stateMutability": "view",
"type": "function"
},
{
"inputs": [],
"name": "decimalPrecision",
"outputs": [
{
"internalType": "uint256",
"name": "",
"type": "uint256"
}
],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [],
"name": "decimals",
"outputs": [
{
"internalType": "uint8",
"name": "",
"type": "uint8"
}
],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [
{
Expand Down Expand Up @@ -221,6 +247,19 @@
"stateMutability": "view",
"type": "function"
},
{
"inputs": [],
"name": "getDecimals",
"outputs": [
{
"internalType": "uint8",
"name": "",
"type": "uint8"
}
],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [
{
Expand Down Expand Up @@ -357,6 +396,11 @@
"internalType": "uint256",
"name": "_twapInterval",
"type": "uint256"
},
{
"internalType": "uint8",
"name": "_decimals",
"type": "uint8"
}
],
"name": "initialize",
Expand Down Expand Up @@ -731,5 +775,18 @@
],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [
{
"internalType": "uint8",
"name": "_decimals",
"type": "uint8"
}
],
"name": "updateDecimals",
"outputs": [],
"stateMutability": "nonpayable",
"type": "function"
}
]
21 changes: 18 additions & 3 deletions contracts/protocol/NFTOracle.sol
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,8 @@ contract NFTOracle is INFTOracle, Initializable, OwnableUpgradeable, BlockContex
mapping(address => EnumerableSetUpgradeable.AddressSet) private _originalAssetToMappedAsset;
// Mapping from mapped asset to original asset
mapping(address => address) private _mappedAssetToOriginalAsset;
uint8 public decimals;
uint256 public decimalPrecision;

// !!! For upgradable, MUST append one new variable above !!!
//////////////////////////////////////////////////////////////////////////////
Expand All @@ -82,7 +84,8 @@ contract NFTOracle is INFTOracle, Initializable, OwnableUpgradeable, BlockContex
uint256 _maxPriceDeviationWithTime,
uint256 _timeIntervalWithPrice,
uint256 _minUpdateTime,
uint256 _twapInterval
uint256 _twapInterval,
uint8 _decimals
) public initializer {
__Ownable_init();
priceFeedAdmin = _admin;
Expand All @@ -91,6 +94,17 @@ contract NFTOracle is INFTOracle, Initializable, OwnableUpgradeable, BlockContex
timeIntervalWithPrice = _timeIntervalWithPrice;
minUpdateTime = _minUpdateTime;
twapInterval = _twapInterval;
decimals = _decimals;
decimalPrecision = 10**decimals;
}

function updateDecimals(uint8 _decimals) external onlyOwner {
decimals = _decimals;
decimalPrecision = 10**decimals;
}

function getDecimals() external view returns (uint8) {
return decimals;
}

function setPriceFeedAdmin(address _admin) external onlyOwner {
Expand Down Expand Up @@ -349,10 +363,11 @@ contract NFTOracle is INFTOracle, Initializable, OwnableUpgradeable, BlockContex
}
uint256 timestamp = nftPriceFeedMap[_nftContract].nftPriceData[len - 1].timestamp;
uint256 percentDeviation;
require(decimalPrecision > 0, "NFTOracle: invalid decimalPrecision");
if (_price > price) {
percentDeviation = ((_price - price) * DECIMAL_PRECISION) / price;
percentDeviation = ((_price - price) * decimalPrecision) / price;
} else {
percentDeviation = ((price - _price) * DECIMAL_PRECISION) / price;
percentDeviation = ((price - _price) * decimalPrecision) / price;
}
uint256 timeDeviation = _timestamp - timestamp;
if (percentDeviation > maxPriceDeviation) {
Expand Down
10 changes: 10 additions & 0 deletions deployments/deployed-contracts-main.json
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,9 @@
"address": "0x501c991E0D31D408c25bCf00da27BdF2759A394a",
"deployer": "0x868964fa49a6fd6e116FE82c8f4165904406f479"
},
"BendV2ProxyAdmin": {
"address": "0x3b241a4338f0C3f67aFE0e130ccB653D0Ef3767C"
},
"NFTOracleImpl": {
"address": "0x359424a81392588206cbb33159d6AebC292Cb404"
},
Expand Down Expand Up @@ -258,5 +261,12 @@
"rateStrategyWETH241012": {
"address": "0xe591B82ECf0f6D0D5a289c5E31fF4d3f5C9eB8B6",
"deployer": "0x868964fa49a6fd6e116FE82c8f4165904406f479"
},
"TokenOracleImpl": {
"address": "0xA1CFAdAD19e1261a65D04c4fB81Aa59Ae36326B4"
},
"TokenOracle": {
"address": "0x09AbE7f7297B27e4343E1f3906267b0BE6dBe4eb",
"deployer": "0x868964fa49a6fd6e116FE82c8f4165904406f479"
}
}
10 changes: 10 additions & 0 deletions deployments/deployed-contracts-sepolia.json
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,9 @@
"address": "0x15c2Ae6eE45b57f592e6DcDf7C06a2d956c98d03",
"deployer": "0xafF5C36642385b6c7Aaf7585eC785aB2316b5db6"
},
"BendV2ProxyAdmin": {
"address": "0xeF7D77D28694497130119F1Caf5c4fae229a9CCc"
},
"BendCollectorImpl": {
"address": "0x6cb417A3Cb4e2881814fa2945CCD49c3eAE435F1"
},
Expand Down Expand Up @@ -165,5 +168,12 @@
"rateStrategyWETH231117": {
"address": "0x2C86cdA99e2cea822a2915fFfeB75C9D3E2830F9",
"deployer": "0xafF5C36642385b6c7Aaf7585eC785aB2316b5db6"
},
"TokenOracleImpl": {
"address": "0xaBEdC0bD3bA48a78c8B9A6FA2ccB135af39d1Cf5"
},
"TokenOracle": {
"address": "0xA840dC2B97F565BF5179CccC8e4f6E72d5eD1eab",
"deployer": "0xafF5C36642385b6c7Aaf7585eC785aB2316b5db6"
}
}
4 changes: 2 additions & 2 deletions helper-hardhat-config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -44,10 +44,10 @@ export const NETWORKS_RPC_URL: iParamsPerNetwork<string> = {
};

export const NETWORKS_DEFAULT_GAS: iParamsPerNetwork<number> = {
[eEthereumNetwork.sepolia]: 35 * GWEI,
[eEthereumNetwork.sepolia]: 15 * GWEI,
[eEthereumNetwork.goerli]: 65 * GWEI,
[eEthereumNetwork.rinkeby]: 65 * GWEI,
[eEthereumNetwork.main]: 10 * GWEI,
[eEthereumNetwork.main]: 15 * GWEI,
[eEthereumNetwork.coverage]: 65 * GWEI,
[eEthereumNetwork.hardhat]: 65 * GWEI,
[eEthereumNetwork.localhost]: 65 * GWEI,
Expand Down
6 changes: 6 additions & 0 deletions helpers/contracts-deployments.ts
Original file line number Diff line number Diff line change
Expand Up @@ -323,6 +323,12 @@ export const deployNFTOracle = async (verify?: boolean) => {
return withSaveAndVerify(oracleImpl, eContractid.NFTOracle, [], verify);
};

export const deployTokenOracle = async (verify?: boolean) => {
const oracleImpl = await new NFTOracleFactory(await getDeploySigner()).deploy();
await insertContractAddressInDb(eContractid.TokenOracleImpl, oracleImpl.address);
return withSaveAndVerify(oracleImpl, eContractid.TokenOracle, [], verify);
};

export const deployMockNFTOracle = async (verify?: boolean) =>
withSaveAndVerify(
await new MockNFTOracleFactory(await getDeploySigner()).deploy(),
Expand Down
12 changes: 12 additions & 0 deletions helpers/contracts-getters.ts
Original file line number Diff line number Diff line change
Expand Up @@ -152,6 +152,18 @@ export const getNFTOracleImpl = async (address?: tEthereumAddress) =>
await getDeploySigner()
);

export const getTokenOracle = async (address?: tEthereumAddress) =>
await NFTOracleFactory.connect(
address || (await getDb(DRE.network.name).get(`${eContractid.TokenOracle}`).value()).address,
await getDeploySigner()
);

export const getTokenOracleImpl = async (address?: tEthereumAddress) =>
await NFTOracleFactory.connect(
address || (await getDb(DRE.network.name).get(`${eContractid.TokenOracleImpl}`).value()).address,
await getDeploySigner()
);

export const getMockReserveOracle = async (address?: tEthereumAddress) =>
await MockReserveOracleFactory.connect(
address || (await getDb(DRE.network.name).get(`${eContractid.MockReserveOracle}`).value()).address,
Expand Down
3 changes: 3 additions & 0 deletions helpers/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,8 @@ export enum eContractid {
ReserveOracleImpl = "ReserveOracleImpl",
NFTOracle = "NFTOracle",
NFTOracleImpl = "NFTOracleImpl",
TokenOracle = "TokenOracle",
TokenOracleImpl = "TokenOracleImpl",
Proxy = "Proxy",
MockChainlinkOracle = "MockChainlinkOracle",
MockNFTOracle = "MockNFTOracle",
Expand All @@ -53,6 +55,7 @@ export enum eContractid {
BendProxyAdminPool = "BendProxyAdminPool", //LendPool Contracts, etc Oracle(Reserve, NFT)
BendProxyAdminFund = "BendProxyAdminFund", //Treasury Fundings, etc Collector
BendProxyAdminWTL = "BendProxyAdminWTL", //Common Proxy Admin Without Timelock
BendV2ProxyAdmin = "BendV2ProxyAdmin", //Common Proxy Admin in V2
WalletBalanceProvider = "WalletBalanceProvider",
BToken = "BToken",
DebtToken = "DebtToken",
Expand Down
2 changes: 1 addition & 1 deletion tasks/dev/oracle_nft.ts
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ task("dev:deploy-oracle-nft", "Deploy nft oracle for dev environment")

const nftOracleImpl = await deployNFTOracle(verify);
await waitForTx(
await nftOracleImpl.initialize(await addressesProvider.getPoolAdmin(), 2e17, 1e17, 1800, 600, 1800)
await nftOracleImpl.initialize(await addressesProvider.getPoolAdmin(), 2e17, 1e17, 1800, 600, 1800, 18)
);
await waitForTx(await addressesProvider.setNFTOracle(nftOracleImpl.address));
await addAssetsInNFTOracle(allNftAddresses, nftOracleImpl);
Expand Down
1 change: 1 addition & 0 deletions tasks/full/oracle-nft.ts
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,7 @@ task("full:deploy-oracle-nft", "Deploy nft oracle for full enviroment")
1800,
600,
21600,
18,
]);

let nftOracle: NFTOracle;
Expand Down
84 changes: 84 additions & 0 deletions tasks/full/oracle-token.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,84 @@
import { task } from "hardhat/config";
import {
getParamPerNetwork,
insertContractAddressInDb,
tryGetContractAddressInDb,
} from "../../helpers/contracts-helpers";
import { deployBendUpgradeableProxy, deployTokenOracle } from "../../helpers/contracts-deployments";
import { ICommonConfiguration, eNetwork, eContractid } from "../../helpers/types";
import { waitForTx, notFalsyOrZeroAddress } from "../../helpers/misc-utils";
import { ConfigNames, loadPoolConfig, getGenesisPoolAdmin } from "../../helpers/configuration";
import { getTokenOracle, getBendUpgradeableProxy, getBendProxyAdminById } from "../../helpers/contracts-getters";
import { NFTOracle, BendUpgradeableProxy } from "../../types";
import { BigNumber as BN } from "ethers";

task("full:deploy-oracle-token", "Deploy erc20 token oracle for full enviroment")
.addParam("pool", `Pool name to retrieve configuration, supported: ${Object.values(ConfigNames)}`)
.addOptionalParam("feedAdmin", "Address of price feed")
.setAction(async ({ pool, feedAdmin }, DRE) => {
try {
await DRE.run("set-DRE");
await DRE.run("compile");

const network = <eNetwork>DRE.network.name;
const poolConfig = loadPoolConfig(pool);

const proxyAdmin = await getBendProxyAdminById(eContractid.BendV2ProxyAdmin);
if (proxyAdmin == undefined || !notFalsyOrZeroAddress(proxyAdmin.address)) {
throw Error("Invalid pool proxy admin in config");
}
const proxyAdminOwnerAddress = await proxyAdmin.owner();
const proxyAdminOwnerSigner = DRE.ethers.provider.getSigner(proxyAdminOwnerAddress);

if (feedAdmin == undefined || !notFalsyOrZeroAddress(feedAdmin)) {
feedAdmin = await getGenesisPoolAdmin(poolConfig);
}

const tokenOracleAddress = await tryGetContractAddressInDb(eContractid.TokenOracle);

const tokenOracleImpl = await deployTokenOracle(true);
const initEncodedData = tokenOracleImpl.interface.encodeFunctionData("initialize", [
feedAdmin,
BN.from(2).mul(BN.from(10).pow(7)), //2e7
BN.from(1).mul(BN.from(10).pow(7)), //1e7
1800,
600,
21600,
8,
]);

let tokenOracle: NFTOracle;
let tokenOracleProxy: BendUpgradeableProxy;

if (tokenOracleAddress != undefined && notFalsyOrZeroAddress(tokenOracleAddress)) {
console.log("Upgrading exist token oracle proxy to new implementation...");

await insertContractAddressInDb(eContractid.TokenOracle, tokenOracleAddress);

tokenOracleProxy = await getBendUpgradeableProxy(tokenOracleAddress);

// only proxy admin can do upgrading
await waitForTx(
await proxyAdmin.connect(proxyAdminOwnerSigner).upgrade(tokenOracleProxy.address, tokenOracleImpl.address)
);

tokenOracle = await getTokenOracle(tokenOracleProxy.address);
} else {
console.log("Deploying new token oracle proxy & implementation...");

tokenOracleProxy = await deployBendUpgradeableProxy(
eContractid.TokenOracle,
proxyAdmin.address,
tokenOracleImpl.address,
initEncodedData,
true
);

tokenOracle = await getTokenOracle(tokenOracleProxy.address);
}

console.log("Token Oracle: proxy %s, implementation %s", tokenOracle.address, tokenOracleImpl.address);
} catch (error) {
throw error;
}
});
6 changes: 4 additions & 2 deletions test/__setup.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -275,7 +275,8 @@ const buildTestEnv = async (deployer: Signer, secondaryWallet: Signer) => {
"10000000000000000000",
1,
1,
100
100,
18
)
);
await waitForTx(await addressesProvider.setNFTOracle(nftOracleImpl.address));
Expand All @@ -291,7 +292,8 @@ const buildTestEnv = async (deployer: Signer, secondaryWallet: Signer) => {
"10000000000000000000",
1,
1,
100
100,
18
)
);

Expand Down
Loading