Skip to content

Commit

Permalink
feat: add decimals in nft oracle (#129)
Browse files Browse the repository at this point in the history
* add decimals in nft oracle

* deploy token oracle on mainnet
  • Loading branch information
thorseldon authored Nov 12, 2024
1 parent cff4d16 commit b7b36e1
Show file tree
Hide file tree
Showing 12 changed files with 208 additions and 8 deletions.
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

0 comments on commit b7b36e1

Please sign in to comment.