diff --git a/deploy/2-sidechain/203_keep3r_helper_and_sidechain.ts b/deploy/2-sidechain/203_keep3r_helper_and_sidechain.ts index ce4686d..5c961c8 100644 --- a/deploy/2-sidechain/203_keep3r_helper_and_sidechain.ts +++ b/deploy/2-sidechain/203_keep3r_helper_and_sidechain.ts @@ -2,7 +2,7 @@ import { DeployFunction } from 'hardhat-deploy/types'; import { HardhatRuntimeEnvironment } from 'hardhat/types'; const deployFunction: DeployFunction = async function (hre: HardhatRuntimeEnvironment) { - const { deployer, governor, kp3rV1, weth, kp3rWethOracle, wethUsdOracle } = await hre.getNamedAccounts(); + const { deployer, governor, kp3rV1, weth, kp3rWethOracle, wethUsdOracle, usdDecimals } = await hre.getNamedAccounts(); const { kp3rV1: mainnetKp3rV1 } = await hre.companionNetworks['mainnet'].getNamedAccounts(); const keep3rEscrow = await hre.deployments.get('Keep3rEscrow'); @@ -11,7 +11,7 @@ const deployFunction: DeployFunction = async function (hre: HardhatRuntimeEnviro const currentNonce: number = await hre.ethers.provider.getTransactionCount(deployer); const keeperV2Address: string = hre.ethers.utils.getContractAddress({ from: deployer, nonce: currentNonce + 1 }); - const keep3rHelperArgs = [keeperV2Address, governor, mainnetKp3rV1, weth, kp3rWethOracle, wethUsdOracle]; + const keep3rHelperArgs = [keeperV2Address, governor, mainnetKp3rV1, weth, kp3rWethOracle, wethUsdOracle, usdDecimals]; const keep3rHelper = await hre.deployments.deploy('Keep3rHelperSidechain', { from: deployer, diff --git a/deploy/3-sidechain-test/301_keep3r_helper_and_sidechain.ts b/deploy/3-sidechain-test/301_keep3r_helper_and_sidechain.ts index ee1f0d9..c7288b0 100644 --- a/deploy/3-sidechain-test/301_keep3r_helper_and_sidechain.ts +++ b/deploy/3-sidechain-test/301_keep3r_helper_and_sidechain.ts @@ -2,7 +2,7 @@ import { DeployFunction } from 'hardhat-deploy/types'; import { HardhatRuntimeEnvironment } from 'hardhat/types'; const deployFunction: DeployFunction = async function (hre: HardhatRuntimeEnvironment) { - const { deployer, governor, kp3rV1, kp3rWethOracle, wethUsdOracle } = await hre.getNamedAccounts(); + const { deployer, governor, kp3rV1, kp3rWethOracle, wethUsdOracle, usdDecimals } = await hre.getNamedAccounts(); const { kp3rV1: mainnetKp3rV1, weth: mainnetWeth } = await hre.companionNetworks['mainnet'].getNamedAccounts(); const keep3rEscrow = await hre.deployments.get('Keep3rEscrow'); @@ -11,7 +11,7 @@ const deployFunction: DeployFunction = async function (hre: HardhatRuntimeEnviro const currentNonce: number = await hre.ethers.provider.getTransactionCount(deployer); const keeperV2Address: string = hre.ethers.utils.getContractAddress({ from: deployer, nonce: currentNonce + 1 }); - const keep3rHelperArgs = [keeperV2Address, governor, mainnetKp3rV1, mainnetWeth, kp3rWethOracle, wethUsdOracle]; + const keep3rHelperArgs = [keeperV2Address, governor, mainnetKp3rV1, mainnetWeth, kp3rWethOracle, wethUsdOracle, usdDecimals]; const keep3rHelper = await hre.deployments.deploy('Keep3rHelperSidechain', { from: deployer, diff --git a/solidity/contracts/Keep3rHelper.sol b/solidity/contracts/Keep3rHelper.sol index 5d6537e..0fb32e8 100644 --- a/solidity/contracts/Keep3rHelper.sol +++ b/solidity/contracts/Keep3rHelper.sol @@ -41,7 +41,7 @@ contract Keep3rHelper is IKeep3rHelper, Keep3rHelperParameters { (int56[] memory _tickCumulatives, ) = IUniswapV3Pool(kp3rWethPool.poolAddress).observe(_secondsAgos); int56 _difference = _tickCumulatives[0] - _tickCumulatives[1]; - _amountOut = getQuoteAtTick(uint128(_eth), kp3rWethPool.isTKNToken0 ? _difference : -_difference, quoteTwapTime); + _amountOut = getQuoteAtTick(uint128(_eth), kp3rWethPool.isKP3RToken0 ? _difference : -_difference, quoteTwapTime); } /// @inheritdoc IKeep3rHelper diff --git a/solidity/contracts/Keep3rHelperParameters.sol b/solidity/contracts/Keep3rHelperParameters.sol index 61c8c50..77d6531 100644 --- a/solidity/contracts/Keep3rHelperParameters.sol +++ b/solidity/contracts/Keep3rHelperParameters.sol @@ -45,7 +45,7 @@ contract Keep3rHelperParameters is IKeep3rHelperParameters, IBaseErrors, Governa address public override keep3rV2; /// @inheritdoc IKeep3rHelperParameters - IKeep3rHelperParameters.TokenOraclePool public override kp3rWethPool; + IKeep3rHelperParameters.Kp3rWethOraclePool public override kp3rWethPool; constructor( address _kp3r, @@ -57,8 +57,9 @@ contract Keep3rHelperParameters is IKeep3rHelperParameters, IBaseErrors, Governa keep3rV2 = _keep3rV2; // Immutable variables [KP3R] cannot be read during contract creation time [_setKp3rWethPool] - kp3rWethPool = _validateOraclePool(_kp3rWethPool, _kp3r); - emit Kp3rWethPoolChange(kp3rWethPool.poolAddress, kp3rWethPool.isTKNToken0); + bool _isKP3RToken0 = _validateOraclePool(_kp3rWethPool, KP3R); + kp3rWethPool = Kp3rWethOraclePool(_kp3rWethPool, _isKP3RToken0); + emit Kp3rWethPoolChange(_kp3rWethPool, _isKP3RToken0); } /// @inheritdoc IKeep3rHelperParameters @@ -123,15 +124,13 @@ contract Keep3rHelperParameters is IKeep3rHelperParameters, IBaseErrors, Governa /// @notice Sets KP3R-WETH pool /// @param _poolAddress The address of the KP3R-WETH pool function _setKp3rWethPool(address _poolAddress) internal { - kp3rWethPool = _validateOraclePool(_poolAddress, KP3R); - emit Kp3rWethPoolChange(kp3rWethPool.poolAddress, kp3rWethPool.isTKNToken0); + bool _isKP3RToken0 = _validateOraclePool(_poolAddress, KP3R); + kp3rWethPool = Kp3rWethOraclePool(_poolAddress, _isKP3RToken0); + emit Kp3rWethPoolChange(_poolAddress, _isKP3RToken0); } - function _validateOraclePool(address _poolAddress, address _token) internal view virtual returns (TokenOraclePool memory _oraclePool) { - bool _isTKNToken0 = IUniswapV3Pool(_poolAddress).token0() == _token; - + function _validateOraclePool(address _poolAddress, address _token) internal view virtual returns (bool _isTKNToken0) { + _isTKNToken0 = IUniswapV3Pool(_poolAddress).token0() == _token; if (!_isTKNToken0 && IUniswapV3Pool(_poolAddress).token1() != _token) revert InvalidOraclePool(); - - return TokenOraclePool(_poolAddress, _isTKNToken0); } } diff --git a/solidity/contracts/sidechain/Keep3rHelperSidechain.sol b/solidity/contracts/sidechain/Keep3rHelperSidechain.sol index d420313..c60bf03 100644 --- a/solidity/contracts/sidechain/Keep3rHelperSidechain.sol +++ b/solidity/contracts/sidechain/Keep3rHelperSidechain.sol @@ -26,11 +26,14 @@ contract Keep3rHelperSidechain is IKeep3rHelperSidechain, Keep3rHelper { /// @inheritdoc IKeep3rHelperSidechain mapping(address => address) public override oracle; /// @inheritdoc IKeep3rHelperSidechain - IKeep3rHelperParameters.TokenOraclePool public override wethUSDPool; + IKeep3rHelperSidechain.WethUsdOraclePool public override wethUSDPool; /// @notice Ethereum mainnet WETH address used for quoting references address public immutable override WETH; + /// @dev Amount of decimals in which USD is quoted within the contract + uint256 constant _USD_BASE_DECIMALS = 18; + /// @param _keep3rV2 Address of sidechain Keep3r implementation /// @param _governor Address of governor /// @param _kp3rWethOracle Address of oracle used for KP3R/WETH quote @@ -42,10 +45,16 @@ contract Keep3rHelperSidechain is IKeep3rHelperSidechain, Keep3rHelper { address _kp3r, address _weth, address _kp3rWethOracle, - address _wethUsdOracle + address _wethUsdOracle, + uint8 _usdDecimals ) Keep3rHelper(_kp3r, _keep3rV2, _governor, _kp3rWethOracle) { WETH = _weth; - wethUSDPool = _validateOraclePool(_wethUsdOracle, _weth); + + // Immutable variables [KP3R] cannot be read during contract creation time [_setKp3rWethPool] + bool _isWETHToken0 = _validateOraclePool(_wethUsdOracle, WETH); + wethUSDPool = WethUsdOraclePool(_wethUsdOracle, _isWETHToken0, _usdDecimals); + emit WethUSDPoolChange(wethUSDPool.poolAddress, wethUSDPool.isWETHToken0, _usdDecimals); + _setQuoteTwapTime(1 days); workExtraGas = 0; } @@ -68,17 +77,18 @@ contract Keep3rHelperSidechain is IKeep3rHelperSidechain, Keep3rHelper { function quoteUsdToEth(uint256 _usd) public view virtual override returns (uint256 _amountOut) { uint32[] memory _secondsAgos = new uint32[](2); _secondsAgos[1] = quoteTwapTime; + _usd = _usd / 10**(_USD_BASE_DECIMALS - wethUSDPool.usdDecimals); /// @dev Oracle is compatible with IUniswapV3Pool (int56[] memory _tickCumulatives, ) = IUniswapV3Pool(wethUSDPool.poolAddress).observe(_secondsAgos); int56 _difference = _tickCumulatives[0] - _tickCumulatives[1]; - _amountOut = getQuoteAtTick(uint128(_usd), wethUSDPool.isTKNToken0 ? _difference : -_difference, quoteTwapTime); + _amountOut = getQuoteAtTick(uint128(_usd), wethUSDPool.isWETHToken0 ? _difference : -_difference, quoteTwapTime); } /// @inheritdoc IKeep3rHelperSidechain - function setWethUsdPool(address _poolAddress) external override onlyGovernor { + function setWethUsdPool(address _poolAddress, uint8 _usdDecimals) external override onlyGovernor { if (_poolAddress == address(0)) revert ZeroAddress(); - _setWethUsdPool(_poolAddress); + _setWethUsdPool(_poolAddress, _usdDecimals); } /// @inheritdoc IKeep3rHelper @@ -98,9 +108,10 @@ contract Keep3rHelperSidechain is IKeep3rHelperSidechain, Keep3rHelper { _extraGas = workExtraGas; } - function _setWethUsdPool(address _poolAddress) internal { - wethUSDPool = _validateOraclePool(_poolAddress, WETH); - emit WethUSDPoolChange(wethUSDPool.poolAddress, wethUSDPool.isTKNToken0); + function _setWethUsdPool(address _poolAddress, uint8 _usdDecimals) internal { + bool _isWETHToken0 = _validateOraclePool(_poolAddress, WETH); + wethUSDPool = WethUsdOraclePool(_poolAddress, _isWETHToken0, _usdDecimals); + emit WethUSDPoolChange(wethUSDPool.poolAddress, wethUSDPool.isWETHToken0, _usdDecimals); } /// @dev Sidechain jobs are quoted by USD/gasUnit, baseFee is set to 1 diff --git a/solidity/interfaces/IKeep3rHelperParameters.sol b/solidity/interfaces/IKeep3rHelperParameters.sol index 12ce7bc..eb07478 100644 --- a/solidity/interfaces/IKeep3rHelperParameters.sol +++ b/solidity/interfaces/IKeep3rHelperParameters.sol @@ -8,9 +8,9 @@ interface IKeep3rHelperParameters { /// @dev KP3R-WETH Pool address and isKP3RToken0 /// @dev Created in order to save gas by avoiding calls to pool's token0 method - struct TokenOraclePool { + struct Kp3rWethOraclePool { address poolAddress; - bool isTKNToken0; + bool isKP3RToken0; } // Errors @@ -70,8 +70,8 @@ interface IKeep3rHelperParameters { /// @notice KP3R-WETH pool that is being used as oracle /// @return poolAddress Address of the pool - /// @return isTKNToken0 True if calling the token0 method of the pool returns the KP3R token address - function kp3rWethPool() external view returns (address poolAddress, bool isTKNToken0); + /// @return isKP3RToken0 True if calling the token0 method of the pool returns the KP3R token address + function kp3rWethPool() external view returns (address poolAddress, bool isKP3RToken0); /// @notice The minimum multiplier used to calculate the amount of gas paid to the Keeper for the gas used to perform a job /// For example: if the quoted gas used is 1000, then the minimum amount to be paid will be 1000 * minBoost / BOOST_BASE diff --git a/solidity/interfaces/sidechain/IKeep3rHelperSidechain.sol b/solidity/interfaces/sidechain/IKeep3rHelperSidechain.sol index 152ec64..2f77f04 100644 --- a/solidity/interfaces/sidechain/IKeep3rHelperSidechain.sol +++ b/solidity/interfaces/sidechain/IKeep3rHelperSidechain.sol @@ -6,6 +6,16 @@ import '../IKeep3rHelper.sol'; /// @title Keep3rHelperSidechain contract /// @notice Contains all the helper functions for sidechain keep3r implementations interface IKeep3rHelperSidechain is IKeep3rHelper { + // Structs + + /// @dev WETH-USD Pool address, isWETHToken0 and usdDecimals + /// @dev Created in order to quote any kind of USD tokens + struct WethUsdOraclePool { + address poolAddress; + bool isWETHToken0; + uint8 usdDecimals; + } + // Events /// @notice The oracle for a liquidity has been saved @@ -16,7 +26,8 @@ interface IKeep3rHelperSidechain is IKeep3rHelper { /// @notice Emitted when the WETH USD pool is changed /// @param _address Address of the new WETH USD pool /// @param _isWETHToken0 True if calling the token0 method of the pool returns the WETH token address - event WethUSDPoolChange(address _address, bool _isWETHToken0); + /// @param _usdDecimals The amount of decimals of the USD token paired with ETH + event WethUSDPoolChange(address _address, bool _isWETHToken0, uint8 _usdDecimals); /// Variables @@ -30,8 +41,16 @@ interface IKeep3rHelperSidechain is IKeep3rHelper { /// @notice WETH-USD pool that is being used as oracle /// @return poolAddress Address of the pool - /// @return isTKNToken0 True if calling the token0 method of the pool returns the WETH token address - function wethUSDPool() external view returns (address poolAddress, bool isTKNToken0); + /// @return isWETHToken0 True if calling the token0 method of the pool returns the WETH token address + /// @return usdDecimals The amount of decimals of the USD token paired with ETH + function wethUSDPool() + external + view + returns ( + address poolAddress, + bool isWETHToken0, + uint8 usdDecimals + ); /// @notice Quotes USD to ETH /// @dev Used to know how much ETH should be paid to keepers before converting it from ETH to KP3R @@ -49,6 +68,7 @@ interface IKeep3rHelperSidechain is IKeep3rHelper { /// @notice Sets an oracle for querying WETH/USD quote /// @param _poolAddress The address of the pool used as oracle + /// @param _usdDecimals The amount of decimals of the USD token paired with ETH /// @dev The oracle must contain WETH as either token0 or token1 - function setWethUsdPool(address _poolAddress) external; + function setWethUsdPool(address _poolAddress, uint8 _usdDecimals) external; } diff --git a/test/e2e/common.ts b/test/e2e/common.ts index a503603..7ec2b6e 100644 --- a/test/e2e/common.ts +++ b/test/e2e/common.ts @@ -33,6 +33,7 @@ export const RICH_KP3R_WETH_POOL_ADDRESS = '0x2269522ad48aeb971b25042471a44acc8c export const KP3R_WETH_POOL_ADDRESS = '0xaf988afF99d3d0cb870812C325C588D8D8CB7De8'; export const KP3R_WETH_V3_POOL_ADDRESS = '0x11B7a6bc0259ed6Cf9DB8F499988F9eCc7167bf5'; export const WETH_DAI_V3_POOL_ADDRESS = '0xc2e9f25be6257c210d7adf0d4cd6e3e881ba25f8'; +export const WETH_USDC_V3_POOL_ADDRESS = '0x88e6a0c2ddd26feeb64f039a2c41296fcb3f5640'; export const UNISWAP_V2_ROUTER_02_ADDRESS = '0x7a250d5630B4cF539739dF2C5dAcb4c659F2488D'; export const UNISWAP_V2_FACTORY_ADDRESS = '0x5C69bEe701ef814a2B6a3EDD4B1652CB9cc5aA6f'; export const KP3R_V1_ADDRESS = '0x1cEB5cB57C4D4E2b2433641b95Dd330A33185A44'; diff --git a/test/e2e/keep3r-multichain.spec.ts b/test/e2e/keep3r-multichain.spec.ts index f7ea8a6..3b5297c 100644 --- a/test/e2e/keep3r-multichain.spec.ts +++ b/test/e2e/keep3r-multichain.spec.ts @@ -21,7 +21,14 @@ import chai, { expect } from 'chai'; import { solidity } from 'ethereum-waffle'; import { BigNumber } from 'ethers'; import { ethers } from 'hardhat'; -import { KP3R_V1_ADDRESS, KP3R_WETH_V3_POOL_ADDRESS, PAIR_MANAGER_ADDRESS, WETH_ADDRESS, WETH_DAI_V3_POOL_ADDRESS } from './common'; +import { + KP3R_V1_ADDRESS, + KP3R_WETH_V3_POOL_ADDRESS, + PAIR_MANAGER_ADDRESS, + WETH_ADDRESS, + WETH_DAI_V3_POOL_ADDRESS, + WETH_USDC_V3_POOL_ADDRESS, +} from './common'; const kp3rWhaleAddress = '0xa0f75491720835b36edc92d06ddc468d201e9b73'; @@ -31,7 +38,7 @@ const DAY = 86400; const ONE = bn.toUnit(1); const BONDS = bn.toUnit(10); const ESCROW_AMOUNT = bn.toUnit(100); -const DELTA = bn.toUnit(0.001).toNumber(); +const DELTA = bn.toUnit(0.001).toNumber(); // in KP3Rs (18 decimals) describe('Keep3r Sidechain @skip-on-coverage', () => { let deployer: SignerWithAddress; @@ -94,7 +101,9 @@ describe('Keep3r Sidechain @skip-on-coverage', () => { KP3R_V1_ADDRESS, WETH_ADDRESS, KP3R_WETH_V3_POOL_ADDRESS, // uses KP3R-WETH pool as oracle - WETH_DAI_V3_POOL_ADDRESS // uses WETH-DAI pool as oracle + // helper uses WETH-USDC and test uses WETH-DAI to verify + WETH_USDC_V3_POOL_ADDRESS, // uses WETH-USDC pool as oracle + 6 // USDC has 6 decimals ); const kp3rSidechainFactory = (await ethers.getContractFactory('Keep3rSidechain')) as Keep3rSidechain__factory; diff --git a/test/unit/Keep3rHelperParameters.spec.ts b/test/unit/Keep3rHelperParameters.spec.ts index 375150a..e72517e 100644 --- a/test/unit/Keep3rHelperParameters.spec.ts +++ b/test/unit/Keep3rHelperParameters.spec.ts @@ -41,18 +41,18 @@ describe('Keep3rHelperParameters', () => { expect(assignedAddress).to.equal(pool.address); }); - it('should set kp3rWethPool isTKNToken0 to true if KP3R is token0', async () => { + it('should set kp3rWethPool isKP3RToken0 to true if KP3R is token0', async () => { parameters = await parametersFactory.deploy(KP3R_V1_ADDRESS, randomKeep3rV2Address, governor.address, pool.address); - const isTKNToken0 = (await parameters.callStatic.kp3rWethPool()).isTKNToken0; - expect(isTKNToken0).to.be.true; + const isKP3RToken0 = (await parameters.callStatic.kp3rWethPool()).isKP3RToken0; + expect(isKP3RToken0).to.be.true; }); - it('should set kp3rWethPool isTKNToken0 to false if KP3R is not token0', async () => { + it('should set kp3rWethPool isKP3RToken0 to false if KP3R is not token0', async () => { pool.token0.returns(generateRandomAddress()); pool.token1.returns(KP3R_V1_ADDRESS); parameters = await parametersFactory.deploy(KP3R_V1_ADDRESS, randomKeep3rV2Address, governor.address, pool.address); - const isTKNToken0 = (await parameters.callStatic.kp3rWethPool()).isTKNToken0; - expect(isTKNToken0).to.be.false; + const isKP3RToken0 = (await parameters.callStatic.kp3rWethPool()).isKP3RToken0; + expect(isKP3RToken0).to.be.false; }); }); @@ -79,19 +79,19 @@ describe('Keep3rHelperParameters', () => { await expect(parameters.connect(governor).setKp3rWethPool(ZERO_ADDRESS)).to.be.revertedWith('ZeroAddress()'); }); - it('should set kp3rWethPool isTKNToken0 to true if KP3R is token0', async () => { + it('should set kp3rWethPool isKP3RToken0 to true if KP3R is token0', async () => { await parameters.connect(governor).setKp3rWethPool(otherPool.address); - const isTKNToken0 = (await parameters.callStatic.kp3rWethPool()).isTKNToken0; - expect(isTKNToken0).to.be.true; + const isKP3RToken0 = (await parameters.callStatic.kp3rWethPool()).isKP3RToken0; + expect(isKP3RToken0).to.be.true; }); - it('should set kp3rWethPool isTKNToken0 to false if KP3R is not token0', async () => { + it('should set kp3rWethPool isKP3RToken0 to false if KP3R is not token0', async () => { otherPool.token0.returns(generateRandomAddress()); otherPool.token1.returns(KP3R_V1_ADDRESS); await parameters.connect(governor).setKp3rWethPool(otherPool.address); - const isTKNToken0 = (await parameters.callStatic.kp3rWethPool()).isTKNToken0; - expect(isTKNToken0).to.be.false; + const isKP3RToken0 = (await parameters.callStatic.kp3rWethPool()).isKP3RToken0; + expect(isKP3RToken0).to.be.false; }); it('should revert if pool does not contain KP3R as token0 nor token1', async () => { diff --git a/test/unit/sidechain/Keep3rHelperSidechain.spec.ts b/test/unit/sidechain/Keep3rHelperSidechain.spec.ts index 226e414..2288acd 100644 --- a/test/unit/sidechain/Keep3rHelperSidechain.spec.ts +++ b/test/unit/sidechain/Keep3rHelperSidechain.spec.ts @@ -22,6 +22,8 @@ describe('Keep3rHelperSidechain', () => { let otherPool: FakeContract; let snapshotId: string; + const USD_POOL_DECIMALS = 18; + before(async () => { [, governor] = await ethers.getSigners(); keep3r = await smock.fake('IKeep3r'); @@ -44,7 +46,8 @@ describe('Keep3rHelperSidechain', () => { KP3R_V1_ADDRESS, WETH_ADDRESS, kp3rWethOracle.address, - wethUsdOracle.address + wethUsdOracle.address, + USD_POOL_DECIMALS ); snapshotId = await evm.snapshot.take(); @@ -66,7 +69,7 @@ describe('Keep3rHelperSidechain', () => { it('should initialize kp3rWethOracle to the address passed to the constructor', async () => { const kp3rWethPool = await helper.kp3rWethPool(); expect(kp3rWethPool.poolAddress).to.eq(kp3rWethOracle.address); - expect(kp3rWethPool.isTKNToken0).to.eq(false); + expect(kp3rWethPool.isKP3RToken0).to.eq(false); }); it('should initialize kp3rWethOracle with the correct token0', async () => { @@ -78,17 +81,19 @@ describe('Keep3rHelperSidechain', () => { KP3R_V1_ADDRESS, WETH_ADDRESS, kp3rWethOracle.address, - wethUsdOracle.address + wethUsdOracle.address, + 18 ); const kp3rWethPool = await deployed.kp3rWethPool(); - expect(kp3rWethPool.isTKNToken0).to.eq(true); + expect(kp3rWethPool.isKP3RToken0).to.eq(true); }); it('should initialize wethUsdOracle to the address passed to the constructor', async () => { const wethUSDPool = await helper.wethUSDPool(); expect(wethUSDPool.poolAddress).to.eq(wethUsdOracle.address); - expect(wethUSDPool.isTKNToken0).to.eq(false); + expect(wethUSDPool.isWETHToken0).to.eq(false); + expect(wethUSDPool.usdDecimals).to.eq(USD_POOL_DECIMALS); }); it('should initialize wethUsdOracle with the correct token0', async () => { @@ -100,11 +105,12 @@ describe('Keep3rHelperSidechain', () => { KP3R_V1_ADDRESS, WETH_ADDRESS, kp3rWethOracle.address, - wethUsdOracle.address + wethUsdOracle.address, + USD_POOL_DECIMALS ); const wethUSDPool = await deployed.wethUSDPool(); - expect(wethUSDPool.isTKNToken0).to.eq(true); + expect(wethUSDPool.isWETHToken0).to.eq(true); }); it('should initialize quote twap time to 1 day', async () => { @@ -184,45 +190,56 @@ describe('Keep3rHelperSidechain', () => { }); context('setWethUsdPool', () => { + const USD_POOL_DECIMALS = 6; onlyGovernor( () => helper, 'setWethUsdPool', governor, - () => [otherPool.address] + () => [otherPool.address, USD_POOL_DECIMALS] ); it('should revert if pool address is 0', async () => { - await expect(helper.connect(governor).setWethUsdPool(ZERO_ADDRESS)).to.be.revertedWith('ZeroAddress()'); + await expect(helper.connect(governor).setWethUsdPool(ZERO_ADDRESS, USD_POOL_DECIMALS)).to.be.revertedWith('ZeroAddress()'); }); - it('should set wethUSDPool isTKNToken0 to true if WETH is token0', async () => { + it('should set wethUSDPool isWETHToken0 to true if WETH is token0', async () => { otherPool.token0.returns(WETH_ADDRESS); - await helper.connect(governor).setWethUsdPool(otherPool.address); - const isTKNToken0 = (await helper.callStatic.wethUSDPool()).isTKNToken0; - expect(isTKNToken0).to.be.true; + await helper.connect(governor).setWethUsdPool(otherPool.address, USD_POOL_DECIMALS); + const isWETHToken0 = (await helper.callStatic.wethUSDPool()).isWETHToken0; + expect(isWETHToken0).to.be.true; }); - it('should set wethUSDPool isTKNToken0 to false if WETH is not token0', async () => { + it('should set wethUSDPool isWETHToken0 to false if WETH is not token0', async () => { otherPool.token0.returns(wallet.generateRandomAddress()); otherPool.token1.returns(WETH_ADDRESS); - await helper.connect(governor).setWethUsdPool(otherPool.address); - const isTKNToken0 = (await helper.callStatic.wethUSDPool()).isTKNToken0; - expect(isTKNToken0).to.be.false; + await helper.connect(governor).setWethUsdPool(otherPool.address, USD_POOL_DECIMALS); + const isWETHToken0 = (await helper.callStatic.wethUSDPool()).isWETHToken0; + expect(isWETHToken0).to.be.false; + }); + + it('should set wethUSDPool parameters', async () => { + otherPool.token0.returns(WETH_ADDRESS); + + await helper.connect(governor).setWethUsdPool(otherPool.address, USD_POOL_DECIMALS); + const wethUSDPool = await helper.callStatic.wethUSDPool(); + expect(wethUSDPool.poolAddress).to.eq(otherPool.address); + expect(wethUSDPool.isWETHToken0).to.be.true; + expect(wethUSDPool.usdDecimals).to.eq(USD_POOL_DECIMALS); }); it('should revert if pool does not contain KP3R as token0 nor token1', async () => { otherPool.token0.returns(wallet.generateRandomAddress()); otherPool.token1.returns(wallet.generateRandomAddress()); - await expect(helper.connect(governor).setWethUsdPool(otherPool.address)).to.be.revertedWith('InvalidOraclePool()'); + await expect(helper.connect(governor).setWethUsdPool(otherPool.address, USD_POOL_DECIMALS)).to.be.revertedWith('InvalidOraclePool()'); }); it('should emit event', async () => { otherPool.token0.returns(WETH_ADDRESS); - await expect(helper.connect(governor).setWethUsdPool(otherPool.address)) + await expect(helper.connect(governor).setWethUsdPool(otherPool.address, USD_POOL_DECIMALS)) .to.emit(helper, 'WethUSDPoolChange') - .withArgs(otherPool.address, true); + .withArgs(otherPool.address, true, USD_POOL_DECIMALS); }); }); }); diff --git a/utils/constants.ts b/utils/constants.ts index c5a2874..4fc178c 100644 --- a/utils/constants.ts +++ b/utils/constants.ts @@ -45,4 +45,9 @@ export const addressRegistry = { 420: '0x4ECFF2c532d47D7be3D957E4a332AB134cad1fd9', // SidechainOracle 31337: '0x60594a405d53811d3bc4766596efd80fd545a270', // UniV3Pool }, + usdDecimals: { + 10: '0x0000000000000000000000000000000000000012', // 18 + 420: '0x0000000000000000000000000000000000000012', // 18 + 31337: '0x0000000000000000000000000000000000000012', // 18 + }, };