From 4d9ea1dca7637886daad1f8e1026da938fdc3b0b Mon Sep 17 00:00:00 2001 From: Shane Earley Date: Tue, 22 Aug 2023 14:12:50 -0400 Subject: [PATCH] Update state after loops when possible --- contracts/ethereum/hardhat.config.ts | 4 +- contracts/ethereum/scripts/deploy.ts | 2 +- contracts/ethereum/scripts/dev.ts | 8 +-- contracts/ethereum/src/v1/CasimirManager.sol | 53 +++++++++++---- contracts/ethereum/src/v1/CasimirPool.sol | 2 + contracts/ethereum/src/v1/CasimirRegistry.sol | 2 + contracts/ethereum/src/v1/CasimirUpkeep.sol | 40 +++++++---- contracts/ethereum/src/v1/CasimirViews.sol | 3 + .../src/v1/interfaces/ICasimirUpkeep.sol | 4 +- contracts/ethereum/test/fixtures/shared.ts | 68 +++++++++---------- contracts/ethereum/test/operators.ts | 12 ++-- contracts/ethereum/test/users.ts | 8 +-- scripts/ethereum/dev.ts | 2 +- scripts/ethereum/test.ts | 2 +- scripts/root/dev.ts | 2 +- services/oracle/README.md | 4 +- services/oracle/scripts/dev.ts | 2 +- services/oracle/scripts/generate.ts | 6 +- 18 files changed, 133 insertions(+), 91 deletions(-) diff --git a/contracts/ethereum/hardhat.config.ts b/contracts/ethereum/hardhat.config.ts index 8734829f4..4d6581240 100644 --- a/contracts/ethereum/hardhat.config.ts +++ b/contracts/ethereum/hardhat.config.ts @@ -27,7 +27,7 @@ const forkConfig = { url: forkUrl, blockNumber: parseInt(process.env.ETHEREUM_FO const externalEnv = { mainnet: { - ORACLE_ADDRESS: '0x0000000000000000000000000000000000000000', + DAO_ORACLE_ADDRESS: '0x0000000000000000000000000000000000000000', BEACON_DEPOSIT_ADDRESS: '0x00000000219ab540356cBB839Cbe05303d7705Fa', LINK_FUNCTIONS_ADDRESS: '0x0000000000000000000000000000000000000000', LINK_REGISTRAR_ADDRESS: ' 0xDb8e8e2ccb5C033938736aa89Fe4fa1eDfD15a1d', @@ -42,7 +42,7 @@ const externalEnv = { WETH_TOKEN_ADDRESS: '0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2' }, goerli: { - ORACLE_ADDRESS: '0x0000000000000000000000000000000000000000', + DAO_ORACLE_ADDRESS: '0x0000000000000000000000000000000000000000', BEACON_DEPOSIT_ADDRESS: '0x07b39F4fDE4A38bACe212b546dAc87C58DfE3fDC', LINK_FUNCTIONS_ADDRESS: '0x0000000000000000000000000000000000000000', LINK_REGISTRAR_ADDRESS: '0x57A4a13b35d25EE78e084168aBaC5ad360252467', diff --git a/contracts/ethereum/scripts/deploy.ts b/contracts/ethereum/scripts/deploy.ts index df0471303..92faa6af4 100644 --- a/contracts/ethereum/scripts/deploy.ts +++ b/contracts/ethereum/scripts/deploy.ts @@ -5,7 +5,7 @@ import { ethers } from 'hardhat' */ void async function () { const managerArgs = { - oracleAddress: process.env.ORACLE_ADDRESS, + daoOracleAddress: process.env.DAO_ORACLE_ADDRESS, beaconDepositAddress: process.env.BEACON_DEPOSIT_ADDRESS, linkFunctionsAddress: process.env.LINK_FUNCTIONS_ADDRESS, linkRegistrarAddress: process.env.LINK_REGISTRAR_ADDRESS, diff --git a/contracts/ethereum/scripts/dev.ts b/contracts/ethereum/scripts/dev.ts index 11366772d..e8c017f10 100644 --- a/contracts/ethereum/scripts/dev.ts +++ b/contracts/ethereum/scripts/dev.ts @@ -12,7 +12,7 @@ import { PoolStatus } from '@casimir/types' * Deploy contracts to local network and run local events and oracle handling */ void async function () { - const [, , , , fourthUser, keeper, oracle] = await ethers.getSigners() + const [, , , , fourthUser, keeper, daoOracle] = await ethers.getSigners() const preregisteredOperatorIds = process.env.PREREGISTERED_OPERATOR_IDS?.split(',').map(id => parseInt(id)) || [654, 655, 656, 657] if (preregisteredOperatorIds.length < 4) throw new Error('Not enough operator ids provided') @@ -24,7 +24,7 @@ void async function () { console.log(`MockFunctionsOracle contract deployed to ${mockFunctionsOracle.address}`) const managerArgs = { - oracleAddress: oracle.address, + daoOracleAddress: daoOracle.address, beaconDepositAddress: process.env.BEACON_DEPOSIT_ADDRESS, linkFunctionsAddress: mockFunctionsOracle.address, linkRegistrarAddress: process.env.LINK_REGISTRAR_ADDRESS, @@ -161,8 +161,8 @@ void async function () { const depositAmount = 32 * ((100 + await manager.feePercent()) / 100) const stake = await manager.connect(fourthUser).depositStake({ value: ethers.utils.parseEther(depositAmount.toString()) }) await stake?.wait() - // Todo handle in oracle - await depositUpkeepBalanceHandler({ manager, signer: oracle }) + // Todo handle in DAO oracle + await depositUpkeepBalanceHandler({ manager, signer: daoOracle }) }, 2500) run('npm run dev --workspace @casimir/oracle') diff --git a/contracts/ethereum/src/v1/CasimirManager.sol b/contracts/ethereum/src/v1/CasimirManager.sol index feb7b2128..4e00026c5 100644 --- a/contracts/ethereum/src/v1/CasimirManager.sol +++ b/contracts/ethereum/src/v1/CasimirManager.sol @@ -19,6 +19,8 @@ import "@uniswap/v3-core/contracts/interfaces/IUniswapV3Factory.sol"; import "@uniswap/v3-core/contracts/interfaces/pool/IUniswapV3PoolState.sol"; import "@uniswap/v3-periphery/contracts/interfaces/ISwapRouter.sol"; +import 'hardhat/console.sol'; + /** * @title Manager contract that accepts and distributes deposits */ @@ -49,7 +51,7 @@ contract CasimirManager is ICasimirManager, Ownable, ReentrancyGuard { /** Compound minimum (0.1 ETH) */ uint256 private constant COMPOUND_MINIMUM = 100000000 gwei; /** Minimum balance for upkeep registration (0.1 LINK) */ - uint256 private constant upkeepRegistrationMinimum = 100000000 gwei; + uint256 private constant UPKEEP_REGISTRATION_MINIMUM = 100000000 gwei; /** Scale factor for each rewards to stake ratio */ uint256 private constant SCALE_FACTOR = 1 ether; /** Uniswap 0.3% fee tier */ @@ -61,7 +63,7 @@ contract CasimirManager is ICasimirManager, Ownable, ReentrancyGuard { /* Immutable */ /*************/ - /** Manager oracle address */ + /** DAO oracle address */ address private immutable oracleAddress; /** Registry contract */ ICasimirRegistry private immutable registry; @@ -203,7 +205,7 @@ contract CasimirManager is ICasimirManager, Ownable, ReentrancyGuard { /** * @notice Constructor - * @param _oracleAddress The manager oracle address + * @param daoOracleAddress The DAO oracle address * @param beaconDepositAddress The Beacon deposit address * @param linkFunctionsAddress The Chainlink functions oracle address * @param linkRegistrarAddress The Chainlink keeper registrar address @@ -217,7 +219,7 @@ contract CasimirManager is ICasimirManager, Ownable, ReentrancyGuard { * @param wethTokenAddress The WETH contract address */ constructor( - address _oracleAddress, + address daoOracleAddress, address beaconDepositAddress, address linkFunctionsAddress, address linkRegistrarAddress, @@ -230,7 +232,18 @@ contract CasimirManager is ICasimirManager, Ownable, ReentrancyGuard { address swapRouterAddress, address wethTokenAddress ) { - oracleAddress = _oracleAddress; + require(daoOracleAddress != address(0), "Missing oracle address"); + require(beaconDepositAddress != address(0), "Missing beacon deposit address"); + require(linkRegistrarAddress != address(0), "Missing link registrar address"); + require(linkRegistryAddress != address(0), "Missing link registry address"); + require(linkTokenAddress != address(0), "Missing link token address"); + require(ssvNetworkAddress != address(0), "Missing SSV network address"); + require(ssvTokenAddress != address(0), "Missing SSV token address"); + require(swapFactoryAddress != address(0), "Missing Uniswap factory address"); + require(swapRouterAddress != address(0), "Missing Uniswap router address"); + require(wethTokenAddress != address(0), "Missing WETH token address"); + + oracleAddress = daoOracleAddress; beaconDeposit = IDepositContract(beaconDepositAddress); linkRegistrar = KeeperRegistrarInterface(linkRegistrarAddress); linkRegistry = AutomationRegistryInterface(linkRegistryAddress); @@ -369,7 +382,7 @@ contract CasimirManager is ICasimirManager, Ownable, ReentrancyGuard { ); linkToken.approve(address(linkRegistrar), linkAmount); if (upkeepId == 0) { - if (linkAmount < upkeepRegistrationMinimum) { + if (linkAmount < UPKEEP_REGISTRATION_MINIMUM) { revert("Upkeep registration minimum not met"); } upkeepId = linkRegistrar.registerUpkeep( @@ -565,6 +578,8 @@ contract CasimirManager is ICasimirManager, Ownable, ReentrancyGuard { * @param count The number of withdrawals to complete */ function fulfillWithdrawals(uint256 count) external onlyUpkeep { + uint256 withdrawalAmount; + uint256 withdrawalCount; while (count > 0) { count--; if (requestedWithdrawalQueue.length == 0) { @@ -575,11 +590,13 @@ contract CasimirManager is ICasimirManager, Ownable, ReentrancyGuard { break; } requestedWithdrawalQueue.remove(0); - requestedWithdrawalBalance -= withdrawal.amount; - requestedWithdrawals--; + withdrawalAmount += withdrawal.amount; + withdrawalCount++; fulfillWithdrawal(withdrawal.user, withdrawal.amount); } + requestedWithdrawalBalance -= withdrawalAmount; + requestedWithdrawals -= withdrawalCount; } /** @@ -588,6 +605,8 @@ contract CasimirManager is ICasimirManager, Ownable, ReentrancyGuard { * @param amount The withdrawal amount */ function fulfillWithdrawal(address sender, uint256 amount) private { + require(sender != address(0), "Missing sender"); + if (amount <= exitedBalance) { exitedBalance -= amount; } else { @@ -798,6 +817,8 @@ contract CasimirManager is ICasimirManager, Ownable, ReentrancyGuard { * @param poolIds The pool IDs */ function reportForcedExits(uint32[] memory poolIds) external onlyOracle { + uint256 newForcedExits; + uint256 newRequestedExits; for (uint256 i = 0; i < poolIds.length; i++) { uint32 poolId = poolIds[i]; ICasimirPool pool = ICasimirPool(poolAddresses[poolId]); @@ -807,12 +828,14 @@ contract CasimirManager is ICasimirManager, Ownable, ReentrancyGuard { "Forced exit already reported" ); - forcedExits++; + newForcedExits++; if (poolDetails.status == ICasimirPool.PoolStatus.EXITING_REQUESTED) { - requestedExits--; + newRequestedExits++; } pool.setStatus(ICasimirPool.PoolStatus.EXITING_FORCED); } + forcedExits += newForcedExits; + requestedExits -= newRequestedExits; emit ForcedExitsReported(poolIds); } @@ -1031,13 +1054,13 @@ contract CasimirManager is ICasimirManager, Ownable, ReentrancyGuard { } /** - * @notice Update the functions oracle address - * @param functionsAddress New functions oracle address + * @notice Set a new functions oracle address + * @param newFunctionsAddress New functions oracle address */ - function setFunctionsAddress(address functionsAddress) external onlyOwner { - upkeep.setOracleAddress(functionsAddress); + function setFunctionsAddress(address newFunctionsAddress) external onlyOwner { + upkeep.setFunctionsAddress(newFunctionsAddress); - emit FunctionsAddressSet(functionsAddress); + emit FunctionsAddressSet(newFunctionsAddress); } /** diff --git a/contracts/ethereum/src/v1/CasimirPool.sol b/contracts/ethereum/src/v1/CasimirPool.sol index b36ee003c..4b8f00ab8 100644 --- a/contracts/ethereum/src/v1/CasimirPool.sol +++ b/contracts/ethereum/src/v1/CasimirPool.sol @@ -56,6 +56,8 @@ contract CasimirPool is ICasimirPool, Ownable, ReentrancyGuard { bytes memory _publicKey, uint64[] memory _operatorIds ) { + require(registryAddress != address(0), "Missing registry address"); + manager = ICasimirManager(msg.sender); registry = ICasimirRegistry(registryAddress); id = _id; diff --git a/contracts/ethereum/src/v1/CasimirRegistry.sol b/contracts/ethereum/src/v1/CasimirRegistry.sol index fb69d3f15..2b0110185 100644 --- a/contracts/ethereum/src/v1/CasimirRegistry.sol +++ b/contracts/ethereum/src/v1/CasimirRegistry.sol @@ -66,6 +66,8 @@ contract CasimirRegistry is ICasimirRegistry, Ownable { * @param ssvNetworkViewsAddress The SSV network views address */ constructor(address ssvNetworkViewsAddress) { + require(ssvNetworkViewsAddress != address(0), "Missing SSV network views address"); + manager = ICasimirManager(msg.sender); ssvNetworkViews = ISSVNetworkViews(ssvNetworkViewsAddress); } diff --git a/contracts/ethereum/src/v1/CasimirUpkeep.sol b/contracts/ethereum/src/v1/CasimirUpkeep.sol index b09b70f99..b9b109e40 100644 --- a/contracts/ethereum/src/v1/CasimirUpkeep.sol +++ b/contracts/ethereum/src/v1/CasimirUpkeep.sol @@ -7,6 +7,8 @@ import {Functions, FunctionsClient} from "@chainlink/contracts/src/v0.8/dev/func import "@openzeppelin/contracts/token/ERC20/IERC20.sol"; import "@openzeppelin/contracts/access/Ownable.sol"; +import 'hardhat/console.sol'; + /** * @title Upkeep contract that automates and handles reports */ @@ -39,11 +41,11 @@ contract CasimirUpkeep is ICasimirUpkeep, FunctionsClient, Ownable { /** Current report status */ ReportStatus private reportStatus; /** Current report period */ - uint32 reportPeriod; + uint32 private reportPeriod; /** Current report remaining request count */ - uint256 reportRemainingRequests; + uint256 private reportRemainingRequests; /** Current report block */ - uint256 reportRequestBlock; + uint256 private reportRequestBlock; /** Current report request timestamp */ uint256 private reportTimestamp; /** Current report swept balance */ @@ -57,11 +59,11 @@ contract CasimirUpkeep is ICasimirUpkeep, FunctionsClient, Ownable { /** Current report completed exits */ uint256 private reportCompletedExits; /** Current report compoundable pools */ - uint32[5] reportCompoundablePoolIds; + uint32[5] private reportCompoundablePoolIds; /** Finalizable activated deposits */ uint256 private finalizableActivatedDeposits; /** Finalizable compoundable pools */ - uint32[5] finalizableCompoundablePoolIds; + uint32[5] private finalizableCompoundablePoolIds; /** Current report request */ mapping(bytes32 => RequestType) private reportRequests; /** Current report response error */ @@ -69,7 +71,7 @@ contract CasimirUpkeep is ICasimirUpkeep, FunctionsClient, Ownable { /** Binary request source code */ bytes public requestCBOR; /** Fulfillment gas limit */ - uint32 fulfillGasLimit; + uint32 private fulfillGasLimit; /** Functions subscription ID (Mocked until managed subscriptions are implemented) */ uint64 private linkSubscriptionId = 1; @@ -79,11 +81,16 @@ contract CasimirUpkeep is ICasimirUpkeep, FunctionsClient, Ownable { /** * Constructor - * @param linkFunctionsAddress The functions oracle contract address + * @param functionsAddress The functions oracle address */ constructor( - address linkFunctionsAddress - ) FunctionsClient(linkFunctionsAddress) { + address functionsAddress + ) FunctionsClient(functionsAddress) { + require( + functionsAddress != address(0), + "Missing functions address" + ); + manager = ICasimirManager(msg.sender); } @@ -259,13 +266,18 @@ contract CasimirUpkeep is ICasimirUpkeep, FunctionsClient, Ownable { } /** - * @notice Update the functions oracle address - * @param newOracleAddress New oracle address + * @notice Set a new functions oracle address + * @param newFunctionsAddress New functions oracle address */ - function setOracleAddress(address newOracleAddress) external onlyOwner { - setOracle(newOracleAddress); + function setFunctionsAddress(address newFunctionsAddress) external onlyOwner { + require ( + newFunctionsAddress != address(0), + "Missing functions address" + ); + + setOracle(newFunctionsAddress); - emit OracleAddressSet(newOracleAddress); + emit FunctionsAddressSet(newFunctionsAddress); } // Dev-only functions diff --git a/contracts/ethereum/src/v1/CasimirViews.sol b/contracts/ethereum/src/v1/CasimirViews.sol index 9edf8fa50..c02405189 100644 --- a/contracts/ethereum/src/v1/CasimirViews.sol +++ b/contracts/ethereum/src/v1/CasimirViews.sol @@ -34,6 +34,9 @@ contract CasimirViews is ICasimirViews { * @param registryAddress The registry address */ constructor(address managerAddress, address registryAddress) { + require(managerAddress != address(0), "Missing manager address"); + require(registryAddress != address(0), "Missing registry address"); + manager = ICasimirManager(managerAddress); registry = ICasimirRegistry(registryAddress); } diff --git a/contracts/ethereum/src/v1/interfaces/ICasimirUpkeep.sol b/contracts/ethereum/src/v1/interfaces/ICasimirUpkeep.sol index 05835cca1..7146dee1d 100644 --- a/contracts/ethereum/src/v1/interfaces/ICasimirUpkeep.sol +++ b/contracts/ethereum/src/v1/interfaces/ICasimirUpkeep.sol @@ -24,7 +24,7 @@ interface ICasimirUpkeep is AutomationCompatibleInterface { /**********/ event OCRResponse(bytes32 indexed requestId, bytes result, bytes err); - event OracleAddressSet(address oracleAddress); + event FunctionsAddressSet(address functionsAddress); event RequestSet(); event UpkeepPerformed(ReportStatus indexed status); @@ -33,7 +33,7 @@ interface ICasimirUpkeep is AutomationCompatibleInterface { /*************/ function performUpkeep(bytes calldata performData) external; - function setOracleAddress(address oracleAddress) external; + function setFunctionsAddress(address newFunctionsAddress) external; function mockFulfillRequest( bytes32 requestId, bytes memory result, diff --git a/contracts/ethereum/test/fixtures/shared.ts b/contracts/ethereum/test/fixtures/shared.ts index 161188963..50eadd76b 100644 --- a/contracts/ethereum/test/fixtures/shared.ts +++ b/contracts/ethereum/test/fixtures/shared.ts @@ -8,7 +8,7 @@ import ISSVNetworkViewsAbi from '../../build/abi/ISSVNetworkViews.json' /** Fixture to deploy SSV manager contract */ export async function deploymentFixture() { - const [owner, , , , , keeper, oracle] = await ethers.getSigners() + const [owner, , , , , keeper, daoOracle] = await ethers.getSigners() const preregisteredOperatorIds = process.env.PREREGISTERED_OPERATOR_IDS?.split(',').map(id => parseInt(id)) || [654, 655, 656, 657] if (preregisteredOperatorIds.length < 4) throw new Error('Not enough operator ids provided') @@ -18,7 +18,7 @@ export async function deploymentFixture() { await mockFunctionsOracle.deployed() const managerArgs = { - oracleAddress: oracle.address, + daoOracleAddress: daoOracle.address, beaconDepositAddress: process.env.BEACON_DEPOSIT_ADDRESS, linkFunctionsAddress: mockFunctionsOracle.address, linkRegistrarAddress: process.env.LINK_REGISTRAR_ADDRESS, @@ -66,34 +66,34 @@ export async function deploymentFixture() { await result.wait() } - return { manager, registry, upkeep, views, ssvNetwork, ssvNetworkViews, owner, keeper, oracle } + return { manager, registry, upkeep, views, ssvNetwork, ssvNetworkViews, owner, keeper, daoOracle } } /** Fixture to stake 16 for the first user */ export async function firstUserDepositFixture() { - const { manager, registry, upkeep, views, owner, keeper, oracle } = await loadFixture(deploymentFixture) + const { manager, registry, upkeep, views, owner, keeper, daoOracle } = await loadFixture(deploymentFixture) const [, firstUser] = await ethers.getSigners() const depositAmount = round(16 * ((100 + await manager.feePercent()) / 100), 10) const deposit = await manager.connect(firstUser).depositStake({ value: ethers.utils.parseEther(depositAmount.toString()) }) await deposit.wait() - return { manager, registry, upkeep, views, owner, firstUser, keeper, oracle } + return { manager, registry, upkeep, views, owner, firstUser, keeper, daoOracle } } /** Fixture to stake 24 for the second user */ export async function secondUserDepositFixture() { - const { manager, registry, upkeep, views, owner, firstUser, keeper, oracle } = await loadFixture(firstUserDepositFixture) + const { manager, registry, upkeep, views, owner, firstUser, keeper, daoOracle } = await loadFixture(firstUserDepositFixture) const [, , secondUser] = await ethers.getSigners() const depositAmount = round(24 * ((100 + await manager.feePercent()) / 100), 10) const deposit = await manager.connect(secondUser).depositStake({ value: ethers.utils.parseEther(depositAmount.toString()) }) await deposit.wait() if ((await manager.upkeepId()).toNumber() === 0) { - await depositUpkeepBalanceHandler({ manager, signer: oracle }) + await depositUpkeepBalanceHandler({ manager, signer: daoOracle }) } - await initiateDepositHandler({ manager, signer: oracle }) + await initiateDepositHandler({ manager, signer: daoOracle }) let requestId = 0 await time.increase(time.duration.days(1)) @@ -114,12 +114,12 @@ export async function secondUserDepositFixture() { }) await runUpkeep({ upkeep, keeper }) - return { manager, registry, upkeep, views, owner, firstUser, secondUser, keeper, oracle, requestId } + return { manager, registry, upkeep, views, owner, firstUser, secondUser, keeper, daoOracle, requestId } } /** Fixture to report increase of 0.105 in total rewards before fees */ export async function rewardsPostSecondUserDepositFixture() { - const { manager, registry, upkeep, views, owner, firstUser, secondUser, keeper, oracle, requestId: latestRequestId } = await loadFixture(secondUserDepositFixture) + const { manager, registry, upkeep, views, owner, firstUser, secondUser, keeper, daoOracle, requestId: latestRequestId } = await loadFixture(secondUserDepositFixture) let requestId = latestRequestId await time.increase(time.duration.days(1)) @@ -140,12 +140,12 @@ export async function rewardsPostSecondUserDepositFixture() { }) await runUpkeep({ upkeep, keeper }) - return { manager, registry, upkeep, views, owner, firstUser, secondUser, keeper, oracle, requestId } + return { manager, registry, upkeep, views, owner, firstUser, secondUser, keeper, daoOracle, requestId } } /** Fixture to sweep 0.105 to the manager */ export async function sweepPostSecondUserDepositFixture() { - const { manager, registry, upkeep, views, owner, firstUser, secondUser, keeper, oracle, requestId: latestRequestId } = await loadFixture(secondUserDepositFixture) + const { manager, registry, upkeep, views, owner, firstUser, secondUser, keeper, daoOracle, requestId: latestRequestId } = await loadFixture(secondUserDepositFixture) let requestId = latestRequestId await time.increase(time.duration.days(1)) @@ -176,19 +176,19 @@ export async function sweepPostSecondUserDepositFixture() { }) await runUpkeep({ upkeep, keeper }) - return { manager, registry, upkeep, views, owner, firstUser, secondUser, keeper, oracle, requestId } + return { manager, registry, upkeep, views, owner, firstUser, secondUser, keeper, daoOracle, requestId } } /** Fixture to stake 24 for the third user */ export async function thirdUserDepositFixture() { - const { manager, registry, upkeep, views, owner, firstUser, secondUser, keeper, oracle, requestId: latestRequestId } = await loadFixture(sweepPostSecondUserDepositFixture) + const { manager, registry, upkeep, views, owner, firstUser, secondUser, keeper, daoOracle, requestId: latestRequestId } = await loadFixture(sweepPostSecondUserDepositFixture) const [, , , thirdUser] = await ethers.getSigners() const depositAmount = round(24 * ((100 + await manager.feePercent()) / 100), 10) const deposit = await manager.connect(thirdUser).depositStake({ value: ethers.utils.parseEther(depositAmount.toString()) }) await deposit.wait() - await initiateDepositHandler({ manager, signer: oracle }) + await initiateDepositHandler({ manager, signer: daoOracle }) let requestId = latestRequestId await time.increase(time.duration.days(1)) @@ -209,12 +209,12 @@ export async function thirdUserDepositFixture() { }) await runUpkeep({ upkeep, keeper }) - return { manager, registry, upkeep, views, owner, firstUser, secondUser, thirdUser, keeper, oracle, requestId } + return { manager, registry, upkeep, views, owner, firstUser, secondUser, thirdUser, keeper, daoOracle, requestId } } /** Fixture to report increase of 0.21 in total rewards before fees */ export async function rewardsPostThirdUserDepositFixture() { - const { manager, registry, upkeep, views, owner, firstUser, secondUser, thirdUser, keeper, oracle, requestId: latestRequestId } = await loadFixture(thirdUserDepositFixture) + const { manager, registry, upkeep, views, owner, firstUser, secondUser, thirdUser, keeper, daoOracle, requestId: latestRequestId } = await loadFixture(thirdUserDepositFixture) let requestId = latestRequestId await time.increase(time.duration.days(1)) @@ -235,12 +235,12 @@ export async function rewardsPostThirdUserDepositFixture() { }) await runUpkeep({ upkeep, keeper }) - return { manager, registry, upkeep, views, owner, firstUser, secondUser, thirdUser, keeper, oracle, requestId } + return { manager, registry, upkeep, views, owner, firstUser, secondUser, thirdUser, keeper, daoOracle, requestId } } /** Fixture to sweep 0.21 to the manager */ export async function sweepPostThirdUserDepositFixture() { - const { manager, registry, upkeep, views, owner, firstUser, secondUser, thirdUser, keeper, oracle, requestId: latestRequestId } = await loadFixture(rewardsPostThirdUserDepositFixture) + const { manager, registry, upkeep, views, owner, firstUser, secondUser, thirdUser, keeper, daoOracle, requestId: latestRequestId } = await loadFixture(rewardsPostThirdUserDepositFixture) let requestId = latestRequestId await time.increase(time.duration.days(1)) @@ -271,12 +271,12 @@ export async function sweepPostThirdUserDepositFixture() { }) await runUpkeep({ upkeep, keeper }) - return { manager, registry, upkeep, views, owner, firstUser, secondUser, thirdUser, keeper, oracle, requestId } + return { manager, registry, upkeep, views, owner, firstUser, secondUser, thirdUser, keeper, daoOracle, requestId } } /** Fixture to partial withdraw 0.3 to the first user */ export async function firstUserPartialWithdrawalFixture() { - const { manager, registry, upkeep, views, firstUser, secondUser, thirdUser, keeper, oracle, requestId: latestRequestId } = await loadFixture(sweepPostThirdUserDepositFixture) + const { manager, registry, upkeep, views, firstUser, secondUser, thirdUser, keeper, daoOracle, requestId: latestRequestId } = await loadFixture(sweepPostThirdUserDepositFixture) const withdrawableBalance = await manager.getWithdrawableBalance() const withdraw = await manager.connect(firstUser).requestWithdrawal(withdrawableBalance) await withdraw.wait() @@ -300,12 +300,12 @@ export async function firstUserPartialWithdrawalFixture() { }) await runUpkeep({ upkeep, keeper }) - return { manager, registry, upkeep, views, firstUser, secondUser, thirdUser, keeper, oracle, requestId } + return { manager, registry, upkeep, views, firstUser, secondUser, thirdUser, keeper, daoOracle, requestId } } /** Fixture to stake 72 for the fourth user */ export async function fourthUserDepositFixture() { - const { manager, registry, upkeep, views, firstUser, secondUser, thirdUser, keeper, oracle, requestId: latestRequestId } = await loadFixture(firstUserPartialWithdrawalFixture) + const { manager, registry, upkeep, views, firstUser, secondUser, thirdUser, keeper, daoOracle, requestId: latestRequestId } = await loadFixture(firstUserPartialWithdrawalFixture) const [, , , , fourthUser] = await ethers.getSigners() const depositAmount = round(72 * ((100 + await manager.feePercent()) / 100), 10) @@ -313,7 +313,7 @@ export async function fourthUserDepositFixture() { await deposit.wait() for (let i = 0; i < 2; i++) { - await initiateDepositHandler({ manager, signer: oracle }) + await initiateDepositHandler({ manager, signer: daoOracle }) } let requestId = latestRequestId @@ -335,12 +335,12 @@ export async function fourthUserDepositFixture() { }) await runUpkeep({ upkeep, keeper }) - return { manager, registry, upkeep, views, firstUser, secondUser, thirdUser, fourthUser, keeper, oracle, requestId } + return { manager, registry, upkeep, views, firstUser, secondUser, thirdUser, fourthUser, keeper, daoOracle, requestId } } /** Fixture to simulate a validator stake penalty that decreases the active balance */ export async function activeBalanceLossFixture() { - const { manager, registry, upkeep, views, firstUser, secondUser, thirdUser, fourthUser, keeper, oracle, requestId: latestRequestId } = await loadFixture(fourthUserDepositFixture) + const { manager, registry, upkeep, views, firstUser, secondUser, thirdUser, fourthUser, keeper, daoOracle, requestId: latestRequestId } = await loadFixture(fourthUserDepositFixture) let requestId = latestRequestId await time.increase(time.duration.days(1)) @@ -361,12 +361,12 @@ export async function activeBalanceLossFixture() { }) await runUpkeep({ upkeep, keeper }) - return { manager, registry, upkeep, views, firstUser, secondUser, thirdUser, fourthUser, keeper, oracle, requestId } + return { manager, registry, upkeep, views, firstUser, secondUser, thirdUser, fourthUser, keeper, daoOracle, requestId } } /** Fixture to simulate a validator reward that brings the active balance back to expected */ export async function activeBalanceRecoveryFixture() { - const { manager, registry, upkeep, views, firstUser, secondUser, thirdUser, fourthUser, keeper, oracle, requestId: latestRequestId } = await loadFixture(activeBalanceLossFixture) + const { manager, registry, upkeep, views, firstUser, secondUser, thirdUser, fourthUser, keeper, daoOracle, requestId: latestRequestId } = await loadFixture(activeBalanceLossFixture) let nextActiveBalance = 127 let requestId = latestRequestId @@ -391,12 +391,12 @@ export async function activeBalanceRecoveryFixture() { nextActiveBalance += 1 } - return { manager, registry, upkeep, views, firstUser, secondUser, thirdUser, fourthUser, keeper, oracle, requestId } + return { manager, registry, upkeep, views, firstUser, secondUser, thirdUser, fourthUser, keeper, daoOracle, requestId } } /** Fixture to full withdraw ~24.07 */ export async function thirdUserFullWithdrawalFixture() { - const { manager, registry, upkeep, views, firstUser, secondUser, thirdUser, fourthUser, keeper, oracle, requestId: latestRequestId } = await loadFixture(activeBalanceRecoveryFixture) + const { manager, registry, upkeep, views, firstUser, secondUser, thirdUser, fourthUser, keeper, daoOracle, requestId: latestRequestId } = await loadFixture(activeBalanceRecoveryFixture) const thirdStake = await manager.getUserStake(thirdUser.address) const withdraw = await manager.connect(thirdUser).requestWithdrawal(thirdStake) @@ -426,16 +426,16 @@ export async function thirdUserFullWithdrawalFixture() { const nextBalance = currentBalance.add(ethers.utils.parseEther(sweptExitedBalance.toString())) await setBalance(exitedPoolAddress, nextBalance) - await reportCompletedExitsHandler({ manager, views, signer: oracle, args: { count: 1 } }) + await reportCompletedExitsHandler({ manager, views, signer: daoOracle, args: { count: 1 } }) await runUpkeep({ upkeep, keeper }) - return { manager, registry, upkeep, views, firstUser, secondUser, thirdUser, fourthUser, keeper, oracle, requestId } + return { manager, registry, upkeep, views, firstUser, secondUser, thirdUser, fourthUser, keeper, daoOracle, requestId } } /** Fixture to simulate rewards */ export async function simulationFixture() { - const { manager, registry, upkeep, views, firstUser, secondUser, thirdUser, fourthUser, keeper, oracle, requestId: latestRequestId } = await loadFixture(thirdUserFullWithdrawalFixture) + const { manager, registry, upkeep, views, firstUser, secondUser, thirdUser, fourthUser, keeper, daoOracle, requestId: latestRequestId } = await loadFixture(thirdUserFullWithdrawalFixture) const rewardsPerValidator = 0.105 let nextActiveBalance = 96 @@ -493,5 +493,5 @@ export async function simulationFixture() { }) await runUpkeep({ upkeep, keeper }) - return { manager, registry, upkeep, views, firstUser, secondUser, thirdUser, fourthUser, keeper, oracle, requestId } + return { manager, registry, upkeep, views, firstUser, secondUser, thirdUser, fourthUser, keeper, daoOracle, requestId } } \ No newline at end of file diff --git a/contracts/ethereum/test/operators.ts b/contracts/ethereum/test/operators.ts index 996198e24..f690aa0cd 100644 --- a/contracts/ethereum/test/operators.ts +++ b/contracts/ethereum/test/operators.ts @@ -25,14 +25,14 @@ describe('Operators', async function () { }) it('First initiated deposit uses 4 eligible operators', async function () { - const { manager, registry, views, oracle } = await loadFixture(deploymentFixture) + const { manager, registry, views, daoOracle } = await loadFixture(deploymentFixture) const [, user] = await ethers.getSigners() const depositAmount = round(32 * ((100 + await manager.feePercent()) / 100), 10) const deposit = await manager.connect(user).depositStake({ value: ethers.utils.parseEther(depositAmount.toString()) }) await deposit.wait() - await initiateDepositHandler({ manager, signer: oracle }) + await initiateDepositHandler({ manager, signer: daoOracle }) const operatorIds = await registry.getOperatorIds() const startIndex = 0 @@ -46,14 +46,14 @@ describe('Operators', async function () { }) it('Operator deregistration with 1 pool emits 1 reshare request', async function () { - const { manager, registry, ssvNetworkViews, oracle } = await loadFixture(deploymentFixture) + const { manager, registry, ssvNetworkViews, daoOracle } = await loadFixture(deploymentFixture) const [, user] = await ethers.getSigners() const depositAmount = round(32 * ((100 + await manager.feePercent()) / 100), 10) const deposit = await manager.connect(user).depositStake({ value: ethers.utils.parseEther(depositAmount.toString()) }) await deposit.wait() - await initiateDepositHandler({ manager, signer: oracle }) + await initiateDepositHandler({ manager, signer: daoOracle }) const operatorIds = await registry.getOperatorIds() const deregisteringOperatorId = operatorIds[0] @@ -105,7 +105,7 @@ describe('Operators', async function () { }) it('Pool exits with 31.0 and recovers from the blamed operator', async function () { - const { manager, registry, upkeep, views, secondUser, keeper, oracle, requestId } = await loadFixture(secondUserDepositFixture) + const { manager, registry, upkeep, views, secondUser, keeper, daoOracle, requestId } = await loadFixture(secondUserDepositFixture) const secondStake = await manager.getUserStake(secondUser.address) const withdraw = await manager.connect(secondUser).requestWithdrawal(secondStake) @@ -134,7 +134,7 @@ describe('Operators', async function () { values: reportValues, requestId }) - await reportCompletedExitsHandler({ manager, views, signer: oracle, args: { count: 1 } }) + await reportCompletedExitsHandler({ manager, views, signer: daoOracle, args: { count: 1 } }) await runUpkeep({ upkeep, keeper }) const stake = await manager.getTotalStake() diff --git a/contracts/ethereum/test/users.ts b/contracts/ethereum/test/users.ts index 9ff95459f..2b0217e26 100644 --- a/contracts/ethereum/test/users.ts +++ b/contracts/ethereum/test/users.ts @@ -35,15 +35,15 @@ describe('Users', async function () { }) it('User\'s 64.0 stake and half withdrawal updates total and user stake, and user balance', async function () { - const { manager, upkeep, views, keeper, oracle } = await loadFixture(deploymentFixture) + const { manager, upkeep, views, keeper, daoOracle } = await loadFixture(deploymentFixture) const [, user] = await ethers.getSigners() const depositAmount = round(64 * ((100 + await manager.feePercent()) / 100), 10) const deposit = await manager.connect(user).depositStake({ value: ethers.utils.parseEther(depositAmount.toString()) }) await deposit.wait() - await initiateDepositHandler({ manager, signer: oracle }) - await initiateDepositHandler({ manager, signer: oracle }) + await initiateDepositHandler({ manager, signer: daoOracle }) + await initiateDepositHandler({ manager, signer: daoOracle }) const pendingPoolIds = await manager.getPendingPoolIds() @@ -110,7 +110,7 @@ describe('Users', async function () { const currentBalance = await ethers.provider.getBalance(exitedPoolAddress) const nextBalance = currentBalance.add(ethers.utils.parseEther(sweptExitedBalance.toString())) await setBalance(exitedPoolAddress, nextBalance) - await reportCompletedExitsHandler({ manager, views, signer: oracle, args: { count: 1 } }) + await reportCompletedExitsHandler({ manager, views, signer: daoOracle, args: { count: 1 } }) const finalizableCompletedExits = await manager.finalizableCompletedExits() expect(finalizableCompletedExits.toNumber()).equal(1) await runUpkeep({ upkeep, keeper }) diff --git a/scripts/ethereum/dev.ts b/scripts/ethereum/dev.ts index f85faff0f..730d9491a 100644 --- a/scripts/ethereum/dev.ts +++ b/scripts/ethereum/dev.ts @@ -38,7 +38,7 @@ void async function () { const wallet = getWallet(process.env.BIP39_SEED) - // Account for the mock oracle contract deployment + // Account for the mock functions oracle contract deployment const deployerNonce = await provider.getTransactionCount(wallet.address) + 1 if (!process.env.MANAGER_ADDRESS) { diff --git a/scripts/ethereum/test.ts b/scripts/ethereum/test.ts index 2e9d80684..10d515de2 100755 --- a/scripts/ethereum/test.ts +++ b/scripts/ethereum/test.ts @@ -31,7 +31,7 @@ void async function () { const provider = new ethers.providers.JsonRpcProvider(process.env.ETHEREUM_FORK_RPC_URL) const wallet = getWallet(process.env.BIP39_SEED) - // Account for the mock oracle contract deployment + // Account for the mock functions oracle contract deployment const deployerNonce = await provider.getTransactionCount(wallet.address) + 1 if (!process.env.MANAGER_ADDRESS) { diff --git a/scripts/root/dev.ts b/scripts/root/dev.ts index 307e53c2d..21a362cb7 100644 --- a/scripts/root/dev.ts +++ b/scripts/root/dev.ts @@ -84,7 +84,7 @@ void async function () { const wallet = getWallet(process.env.BIP39_SEED) - // Account for the mock oracle contract deployment + // Account for the mock functions oracle contract deployment const deployerNonce = await provider.getTransactionCount(wallet.address) + 1 if (!process.env.MANAGER_ADDRESS) { diff --git a/services/oracle/README.md b/services/oracle/README.md index 836b05016..6153a3f22 100644 --- a/services/oracle/README.md +++ b/services/oracle/README.md @@ -1,10 +1,10 @@ # @casimir/oracle -Casimir validators oracle service +Casimir DAO oracle service ## About -The validator oracle service initiates and reports on validator operations: distributed key generation (DKG) ceremonies, DKG reshares, and DKG or presigned exit requests. It contains a [NodeJS](https://nodejs.org) application that listens for `DepositRequested`, `ReshareRequested`, and `ExitRequested` events, which then internally uses the [RockX DKG CLI and messenger server](https://github.com/rockx/rockx-dkg-cli) to initiate and retrieve operator group DKG results. The `DepositRequested` event starts a new DKG keygen and retrieves the results to submit a new validator via `depositPool`. The `ReshareRequested` event starts a new DKG reshare and retrieves the results to update an existing validator via `resharePool`. The `ExitRequested` event starts a new DKG exit and retrieves the results to submit a signed exit message directly to the Beacon chain. +The DAO oracle service initiates and reports on validator operations: distributed key generation (DKG) ceremonies, DKG reshares, and DKG or presigned exit requests. It contains a [NodeJS](https://nodejs.org) application that listens for `DepositRequested`, `ReshareRequested`, and `ExitRequested` events, which then internally uses the [RockX DKG CLI and messenger server](https://github.com/rockx/rockx-dkg-cli) to initiate and retrieve operator group DKG results. The `DepositRequested` event starts a new DKG keygen and retrieves the results to submit a new validator via `depositPool`. The `ReshareRequested` event starts a new DKG reshare and retrieves the results to update an existing validator via `resharePool`. The `ExitRequested` event starts a new DKG exit and retrieves the results to submit a signed exit message directly to the Beacon chain. DKG operations and reports will theoretically have [verifiable](https://docs.obol.tech/docs/next/charon/dkg#dkg-verification) aspects that prove fair DKG ceremonies. diff --git a/services/oracle/scripts/dev.ts b/services/oracle/scripts/dev.ts index bb312d9b5..7502eed3b 100644 --- a/services/oracle/scripts/dev.ts +++ b/services/oracle/scripts/dev.ts @@ -1,7 +1,7 @@ import { fetchRetry, run } from '@casimir/helpers' /** - * Start development oracle service + * Start development DAO oracle service */ void async function () { const resourceDir = 'scripts/resources' diff --git a/services/oracle/scripts/generate.ts b/services/oracle/scripts/generate.ts index a95294395..0e1566945 100644 --- a/services/oracle/scripts/generate.ts +++ b/services/oracle/scripts/generate.ts @@ -31,10 +31,10 @@ void async function () { if (preregisteredOperatorIds.length < 4) throw new Error('Not enough operator ids provided') const wallet = ethers.Wallet.fromMnemonic(process.env.BIP39_SEED, 'm/44\'/60\'/0\'/0/6') - const oracleAddress = wallet.address + const daoOracleAddress = wallet.address const validatorCount = 4 - if (!validatorStore[oracleAddress] || Object.keys(validatorStore[oracleAddress]).length < validatorCount) { + if (!validatorStore[daoOracleAddress] || Object.keys(validatorStore[daoOracleAddress]).length < validatorCount) { const dkg = await run(`which ${process.env.CLI_PATH}`) as string if (!dkg || dkg.includes('not found')) { await run(`GOWORK=off make -C ${resourceDir}/rockx-dkg-cli build`) @@ -76,7 +76,7 @@ void async function () { ownerNonce++ } - validatorStore[oracleAddress] = newValidators + validatorStore[daoOracleAddress] = newValidators fs.writeFileSync(`${outputPath}/validator.store.json`, JSON.stringify(validatorStore, null, 4)) }