diff --git a/apps/web/src/composables/ssv.ts b/apps/web/src/composables/ssv.ts index 5f67a3258..358c20ae9 100644 --- a/apps/web/src/composables/ssv.ts +++ b/apps/web/src/composables/ssv.ts @@ -11,7 +11,7 @@ import { Account, Pool, ProviderString } from '@casimir/types' import { ReadyOrStakeString } from '../interfaces' /** Manager contract */ -let casimirManager: CasimirManager +let manager: CasimirManager export default function useSSV() { const { ethereumURL } = useEnvironment() @@ -20,12 +20,12 @@ export default function useSSV() { const { getEthersTrezorSigner } = useTrezor() const { isWalletConnectSigner, getEthersWalletConnectSigner } = useWalletConnect() - if (!casimirManager) { - casimirManager = (() => { - const address = import.meta.env.PUBLIC_CASIMIR_MANAGER + if (!manager) { + manager = (() => { + const address = import.meta.env.PUBLIC_MANAGER_ADDRESS if (!address) console.log( ` - The PUBLIC_CASIMIR_MANAGER environment variable is empty.\n + The PUBLIC_MANAGER_ADDRESS environment variable is empty.\n If you are on mainnet or testnet, the contract does not exist yet.\n If you are on the local network, check your terminal logs for a contract address or errors. ` @@ -45,20 +45,19 @@ export default function useSSV() { const signerCreator = signerCreators[signerType as keyof typeof signerCreators] let signer = signerCreator(walletProvider) if (isWalletConnectSigner(signer)) signer = await signer - const casimirManagerSigner = casimirManager.connect(signer as ethers.Signer) - const fees = await casimirManagerSigner.getFees() + const managerSigner = manager.connect(signer as ethers.Signer) + const fees = await managerSigner.getFees() const { LINK, SSV } = fees const feesTotalPercent = LINK + SSV const depositAmount = parseFloat(amount) * ((100 + feesTotalPercent) / 100) const value = ethers.utils.parseEther(depositAmount.toString()) - const result = await casimirManagerSigner.deposit({ value, type: 0 }) + const result = await managerSigner.depositStake({ value, type: 0 }) return await result.wait() } async function getDepositFees() { const provider = new ethers.providers.JsonRpcProvider(ethereumURL) - const casimirManagerProvider = casimirManager.connect(provider) - const fees = await casimirManagerProvider.getFees() + const fees = await manager.connect(provider).getFees() const { LINK, SSV } = fees const feesTotalPercent = LINK + SSV const feesRounded = Math.round(feesTotalPercent * 100) / 100 @@ -67,19 +66,17 @@ export default function useSSV() { async function getPools(address: string, readyOrStake: ReadyOrStakeString): Promise { const { user } = useUsers() - const provider = new ethers.providers.JsonRpcProvider(ethereumURL) - const casimirManagerProvider = casimirManager.connect(provider) - - const userStake = await casimirManagerProvider.getUserStake(address) // to get user's stake balance - const poolStake = await casimirManagerProvider.getStake() // to get total stake balance - const poolIds = readyOrStake === 'ready' ? await casimirManagerProvider.getReadyPoolIds() : await casimirManagerProvider.getStakedPoolIds() // to get ready (open) pool IDs OR to get staked (active) pool IDs + const provider = new ethers.providers.JsonRpcProvider(ethereumURL) + const userStake = await manager.connect(provider).getUserStake(address) // to get user's stake balance + const poolStake = await manager.connect(provider).getStake() // to get total stake balance + const poolIds = readyOrStake === 'ready' ? await manager.connect(provider).getReadyPoolIds() : await manager.connect(provider).getStakedPoolIds() // to get ready (open) pool IDs OR to get staked (active) pool IDs console.log('userStake :>> ', ethers.utils.formatEther(userStake)) console.log('poolStake :>> ', ethers.utils.formatEther(poolStake)) console.log('poolIds :>> ', poolIds) return await Promise.all(poolIds.map(async (poolId: number) => { - const { deposits, operatorIds, validatorPublicKey } = await casimirManagerProvider.getPool(poolId) + const { deposits, operatorIds, validatorPublicKey } = await manager.connect(provider).getPoolDetails(poolId) // TODO: Decide when/how to get rewards/userRewards let pool: Pool = { @@ -147,11 +144,11 @@ export default function useSSV() { const signerCreator = signerCreators[signerType as keyof typeof signerCreators] let signer = signerCreator(walletProvider) if (isWalletConnectSigner(signer)) signer = await signer - const casimirManagerSigner = casimirManager.connect(signer as ethers.Signer) + const managerSigner = manager.connect(signer as ethers.Signer) const value = ethers.utils.parseEther(amount) - const result = await casimirManagerSigner.withdraw(value) + const result = await managerSigner.requestWithdrawal(value) return await result.wait() } - return { casimirManager, deposit, getDepositFees, getPools, withdraw } + return { manager, deposit, getDepositFees, getPools, withdraw } } \ No newline at end of file diff --git a/apps/web/src/composables/users.ts b/apps/web/src/composables/users.ts index c2bef36fc..3e8e17c28 100644 --- a/apps/web/src/composables/users.ts +++ b/apps/web/src/composables/users.ts @@ -76,7 +76,7 @@ const user = ref() // pools: [] // } // ) -const { casimirManager, getPools } = useSSV() +const { manager, getPools } = useSSV() export default function useUsers () { @@ -176,13 +176,13 @@ export default function useUsers () { const provider = new ethers.providers.JsonRpcProvider(ethereumURL) const validatorInitFilter = { - address: casimirManager.address, + address: manager.address, topics: [ // ethers.utils.id('ManagerDistribution(address,uint256,uint256,uint256)'), // TODO: Make sure to query for past events on page load (Fetch and then subscribe), - ethers.utils.id('PoolStaked(uint32)'), + ethers.utils.id('PoolInitiated(uint32)'), ] } - casimirManager.connect(provider).on(validatorInitFilter, async () => { + manager.connect(provider).on(validatorInitFilter, async () => { console.log('ValidatorInit event... updating pools') user.value.balance = await getUserBalance() user.value.pools = await getPools(user.value.id) diff --git a/common/hardhat/.gitignore b/common/hardhat/.gitignore deleted file mode 100644 index 04c01ba7b..000000000 --- a/common/hardhat/.gitignore +++ /dev/null @@ -1,2 +0,0 @@ -node_modules/ -dist/ \ No newline at end of file diff --git a/common/hardhat/hardhat.config.ts b/common/hardhat/hardhat.config.ts deleted file mode 100644 index ede214d53..000000000 --- a/common/hardhat/hardhat.config.ts +++ /dev/null @@ -1,8 +0,0 @@ -import defaultConfig from '@casimir/ethereum/hardhat.config' -import { HardhatUserConfig } from 'hardhat/config' - -const config: HardhatUserConfig = { - ...defaultConfig -} - -export default config \ No newline at end of file diff --git a/common/hardhat/package.json b/common/hardhat/package.json deleted file mode 100644 index db70c4f89..000000000 --- a/common/hardhat/package.json +++ /dev/null @@ -1,18 +0,0 @@ -{ - "name": "@casimir/hardhat", - "private": true, - "main": "src/index.ts", - "scripts": { - "build": "echo '@casimir/hardhat build not specified. Disregard this warning and any listed errors above if @casimir/hardhat is not needed for the current project build.' && exit 0", - "test": "echo \"Error: no test specified\" && exit 1" - }, - "devDependencies": { - "@nomiclabs/hardhat-ethers": "^2.0.6", - "@typechain/ethers-v5": "^10.1.0", - "@typechain/hardhat": "^6.1.2", - "@types/node": "^17.0.38", - "esbuild": "^0.15.9", - "hardhat": "^2.12.2", - "typechain": "^8.1.0" - } -} diff --git a/common/hardhat/tsconfig.json b/common/hardhat/tsconfig.json deleted file mode 100644 index 70bc036f0..000000000 --- a/common/hardhat/tsconfig.json +++ /dev/null @@ -1,27 +0,0 @@ -{ - "compilerOptions": { - "target": "ESNext", - "strict": true, - "preserveConstEnums": true, - "noEmit": true, - "sourceMap": false, - "module": "CommonJS", - "moduleResolution": "Node", - "esModuleInterop": true, - "skipLibCheck": true, - "forceConsistentCasingInFileNames": true, - "isolatedModules": true - }, - "exclude": [ - "node_modules" - ], - "include": [ - "./src/*" - ], - "typeRoots": [ - "node_modules/@types" - ], - "files": [ - "hardhat.config.ts" - ] -} \ No newline at end of file diff --git a/contracts/ethereum/README.md b/contracts/ethereum/README.md index ee07fdbb6..0e9ae78c8 100644 --- a/contracts/ethereum/README.md +++ b/contracts/ethereum/README.md @@ -92,7 +92,7 @@ Core internal contracts and interfaces are located in the [src](./src) directory | Contract | Description | Docs | | --- | --- | --- | | [CasimirManager](./src/CasimirManager.sol) | Manages stake distribution | [docs/index.md#casimirmanager](./docs/index.md#casimirmanager) | -| [CasimirAutomation](./src/CasimirAutomation.sol) | Automates event handling | [docs/index.md#casimirautomation](./docs/index.md#casimirautomation) | +| [CasimirUpkeep](./src/CasimirUpkeep.sol) | Automates event handling | [docs/index.md#CasimirUpkeep](./docs/index.md#CasimirUpkeep) | **Vendor Contracts:** @@ -116,11 +116,11 @@ Mock (development-only) contracts and interfaces are located in the [src/mock](. ### Distributed Key Generation -Casimir trustlessly distributes validator key shares to operators using the [rockx-dkg-cli](https://github.com/RockX-SG/rockx-dkg-cli). The DKG server is called via [Automated Chainlink Functions](https://docs.chain.link/chainlink-functions/tutorials/automate-functions/) to generate, reshare, and exit validators. +Casimir trustlessly distributes validator key shares to operators using the [rockx-dkg-cli](https://github.com/RockX-SG/rockx-dkg-cli). ### Oracles -The contract loosely depends on two decentralized oracles. The first oracle provides a PoR feed aggregating the total of all Casimir validator balances on the Beacon chain. The second oracle automates checking balance changes, responds with relevant validator actions, and updates the contract only when necessary conditions are met (see [Chainlink PoR](https://docs.chain.link/data-feeds/proof-of-reserve) and [Chainlink Automation](https://docs.chain.link/chainlink-automation/introduction)). External requests are made using trust-minimized compute infrastructure (see [Chainlink Functions](https://docs.chain.link/chainlink-functions)). +The contract loosely depends on two decentralized oracles. The first oracle automatically syncs validator configuration, statuses, and balances when necessary conditions are met (see [Chainlink Automation](https://docs.chain.link/chainlink-automation/introduction)) by performing external requests with trust-minimized compute infrastructure (see [Chainlink Functions](https://docs.chain.link/chainlink-functions)). The second oracle watches the manager contract events, automatically executes zero-coordination distributed key generation (DKG) operations: validator key creating, resharing, and exiting (see [Chainlink Keepers](https://docs.chain.link/chainlink-keepers/introduction)) off-chain, and submits ceremony verification proofs. ## 👥 Users diff --git a/contracts/ethereum/docs/index.md b/contracts/ethereum/docs/index.md index db549d156..17de85412 100644 --- a/contracts/ethereum/docs/index.md +++ b/contracts/ethereum/docs/index.md @@ -1,6 +1,6 @@ # Solidity API -## CasimirAutomation +## CasimirUpkeep ### oracleHeartbeat @@ -755,7 +755,7 @@ receive() external payable _Will be removed in production Used for mocking sweeps from Beacon to the manager_ -## ICasimirAutomation +## ICasimirUpkeep ### OracleReport diff --git a/common/hardhat/src/index.ts b/contracts/ethereum/helpers/deploy.ts similarity index 96% rename from common/hardhat/src/index.ts rename to contracts/ethereum/helpers/deploy.ts index ad06f6020..c612c2475 100644 --- a/common/hardhat/src/index.ts +++ b/contracts/ethereum/helpers/deploy.ts @@ -18,4 +18,4 @@ async function deployContract(name: string, proxy?: boolean, args?: Record validatorStore[key]) as Validator[] + const validators = Object.keys(validatorStore).map((key) => validatorStore[key as keyof typeof validatorStore]) as Validator[] for (const validator of validators) { const { depositDataRoot, @@ -106,48 +98,70 @@ void async function () { const stakedValidatorPublicKeys = await manager?.getStakedValidatorPublicKeys() if (stakedValidatorPublicKeys?.length) { - const rewardAmount = (rewardPerValidator * stakedValidatorPublicKeys.length).toString() - - // const nextActiveStakeAmount = ethers.utils.formatEther(await manager?.getActiveStake() as ) + parseFloat(rewardAmount) - // const nextSweptRewardsAmount = 0.2 - // const nextSweptExitsAmount = 0 + const rewardAmount = rewardPerValidator * stakedValidatorPublicKeys.length /** Perform upkeep */ - const ranUpkeepBefore = await runUpkeep(automation, chainlink) + const ranUpkeepBefore = await runUpkeep({ upkeep, chainlink }) /** Fulfill oracle answer */ if (ranUpkeepBefore) { - // await fulfillOracleAnswer(automation, chainlink, nextActiveStakeAmount, nextSweptRewardsAmount, nextSweptExitsAmount) + const nextActiveStakeAmount = Math.round((parseFloat(ethers.utils.formatEther(await manager.getActiveStake())) + rewardAmount) * 10) / 10 + const nextSweptRewardsAmount = 0 + const nextSweptExitsAmount = 0 + const nextDepositedCount = 0 + const nextExitedCount = 0 + await fulfillOracleAnswer({ upkeep, chainlink, nextActiveStakeAmount, nextSweptRewardsAmount, nextSweptExitsAmount, nextDepositedCount, nextExitedCount }) } /** Sweep rewards before next upkeep (balance will increment silently) */ - // const sweep = await chainlink.sendTransaction({ to: manager?.address, value: ethers.utils.parseEther(nextSweptRewardsAmount.toString()) }) - // await sweep.wait() + const sweep = await chainlink.sendTransaction({ to: manager?.address, value: ethers.utils.parseEther(rewardAmount.toString()) }) + await sweep.wait() /** Perform upkeep */ - const ranUpkeepAfter = await runUpkeep(automation, chainlink) + const ranUpkeepAfter = await runUpkeep({ upkeep, chainlink }) /** Fulfill oracle answer */ if (ranUpkeepAfter) { - // await fulfillOracleAnswer(automation, chainlink, nextActiveStakeAmount, nextSweptRewardsAmount, nextSweptExitsAmount) + const nextActiveStakeAmount = Math.round((parseFloat(ethers.utils.formatEther(await manager.getActiveStake())) - rewardAmount) * 10) / 10 + const nextSweptRewardsAmount = rewardAmount + const nextSweptExitsAmount = 0 + const nextDepositedCount = 0 + const nextExitedCount = 0 + await fulfillOracleAnswer({ upkeep, chainlink, nextActiveStakeAmount, nextSweptRewardsAmount, nextSweptExitsAmount, nextDepositedCount, nextExitedCount }) } } } }) - /** Perform upkeep and fulfill oracle answer after each pool is staked */ - manager?.on('PoolStaked(uint32)', async () => { + /** Perform upkeep and fulfill oracle answer after each pool is filled */ + const poolFilledFilter = { + address: manager.address, + topics: [ + ethers.utils.id('PoolFilled(address,uint32)'), + ] + } + manager.on(poolFilledFilter, async () => { /** Perform upkeep */ - const ranUpkeep = await runUpkeep(automation, chainlink) + const ranUpkeep = await runUpkeep({ upkeep, chainlink }) /** Fulfill oracle answer */ if (ranUpkeep) { - // const nextActiveStakeAmount = - // const nextSweptRewardsAmount = - // const nextSweptExitsAmount = - // await fulfillOracleAnswer(automation, chainlink, nextActiveStakeAmount, nextSweptRewardsAmount, nextSweptExitsAmount) + const nextActiveStakeAmount = parseFloat(ethers.utils.formatEther(await manager.getActiveStake())) + 32 + const nextSweptRewardsAmount = 0 + const nextSweptExitsAmount = 0 + const nextDepositedCount = 1 + const nextExitedCount = 0 + await fulfillOracleAnswer({ upkeep, chainlink, nextActiveStakeAmount, nextSweptRewardsAmount, nextSweptExitsAmount, nextDepositedCount, nextExitedCount }) } }) + + /** Stake 32 from the fourth user */ + const fourthUserStakeAmount = 32 + const fourthUserFees = { ...await (manager as CasimirManager).getFees() } + const fourthUserFeePercent = fourthUserFees.LINK + fourthUserFees.SSV + const fourthUserDepositAmount = fourthUserStakeAmount * ((100 + fourthUserFeePercent) / 100) + const fourthUserStake = await manager?.connect(fourthUser).depositStake({ value: ethers.utils.parseEther(fourthUserDepositAmount.toString()) }) + await fourthUserStake?.wait() }() \ No newline at end of file diff --git a/contracts/ethereum/src/CasimirManager.sol b/contracts/ethereum/src/CasimirManager.sol index 0ab486438..8f8ceff09 100644 --- a/contracts/ethereum/src/CasimirManager.sol +++ b/contracts/ethereum/src/CasimirManager.sol @@ -1,7 +1,7 @@ // SPDX-License-Identifier: MIT pragma solidity 0.8.16; -import "./CasimirAutomation.sol"; +import "./CasimirUpkeep.sol"; import "./interfaces/ICasimirManager.sol"; import "./libraries/Types.sol"; import "./vendor/interfaces/IDepositContract.sol"; @@ -55,8 +55,8 @@ contract CasimirManager is ICasimirManager, Ownable, ReentrancyGuard { /* Contracts */ /*************/ - /** Automation contract */ - ICasimirAutomation private immutable automation; + /** Upkeep contract */ + ICasimirUpkeep private immutable upkeep; /** Beacon deposit contract */ IDepositContract private immutable beaconDeposit; /** LINK ERC-20 token contract */ @@ -85,7 +85,7 @@ contract CasimirManager is ICasimirManager, Ownable, ReentrancyGuard { /* Dynamic State */ /********************/ - /** Latest active (consensus) balance reported from automation */ + /** Latest active (consensus) balance reported from upkeep */ uint256 latestActiveStake; /** Last pool ID created */ uint256 lastPoolId; @@ -163,8 +163,8 @@ contract CasimirManager is ICasimirManager, Ownable, ReentrancyGuard { swapRouter = ISwapRouter(swapRouterAddress); tokenAddresses[Token.WETH] = wethTokenAddress; - /** Deploy automation contract */ - automation = new CasimirAutomation( + /** Deploy upkeep contract */ + upkeep = new CasimirUpkeep( address(this), oracleAddress, oracleSubId @@ -202,8 +202,8 @@ contract CasimirManager is ICasimirManager, Ownable, ReentrancyGuard { */ function rebalanceStake(uint256 activeStake, uint256 sweptRewards) external { require( - msg.sender == address(automation), - "Only automation can distribute rewards" + msg.sender == address(upkeep), + "Only upkeep can distribute rewards" ); int256 change = int256(activeStake + sweptRewards) - @@ -292,8 +292,8 @@ contract CasimirManager is ICasimirManager, Ownable, ReentrancyGuard { */ function initiateRequestedWithdrawals(uint256 count) external { require( - msg.sender == address(automation), - "Only automation can initiate withdrawals" + msg.sender == address(upkeep), + "Only upkeep can initiate withdrawals" ); while (count > 0) { @@ -339,8 +339,8 @@ contract CasimirManager is ICasimirManager, Ownable, ReentrancyGuard { */ function completePendingWithdrawals(uint256 count) external { require( - msg.sender == address(automation), - "Only automation can complete withdrawals" + msg.sender == address(upkeep), + "Only upkeep can complete withdrawals" ); while (count > 0) { @@ -365,11 +365,11 @@ contract CasimirManager is ICasimirManager, Ownable, ReentrancyGuard { */ function initiateReadyPools(uint256 count) external { require( - msg.sender == address(automation), - "Only automation can stake pools" + msg.sender == address(upkeep), + "Only upkeep can stake pools" ); - // Todo move these checks to automation + // Todo move these checks to upkeep require(readyValidatorPublicKeys.length >= count, "Not enough ready validators"); require(readyPoolIds.length >= count, "Not enough ready pools"); @@ -425,8 +425,8 @@ contract CasimirManager is ICasimirManager, Ownable, ReentrancyGuard { */ function completePendingPools(uint256 count) external { require( - msg.sender == address(automation), - "Only automation can complete pending pools" + msg.sender == address(upkeep), + "Only upkeep can complete pending pools" ); require(pendingPoolIds.length >= count, "Not enough pending pools"); @@ -455,8 +455,8 @@ contract CasimirManager is ICasimirManager, Ownable, ReentrancyGuard { */ function requestPoolExits(uint256 count) external { require( - msg.sender == address(automation), - "Only automation can request pool exits" + msg.sender == address(upkeep), + "Only upkeep can request pool exits" ); uint256 index = 0; // Keeping the same staked pool array @@ -488,8 +488,8 @@ contract CasimirManager is ICasimirManager, Ownable, ReentrancyGuard { uint256 validatorIndex ) external { require( - msg.sender == address(automation), - "Only automation can complete pool exits" + msg.sender == address(upkeep), + "Only upkeep can complete pool exits" ); require(exitingValidatorCount > 0, "No exiting validators"); @@ -631,7 +631,7 @@ contract CasimirManager is ICasimirManager, Ownable, ReentrancyGuard { ); // Todo use linkToken.increaseAllowance(swappedLINK) if available linkToken.approve( - address(automation), + address(upkeep), linkToken.balanceOf(address(this)) ); unswappedTokens[tokenAddresses[Token.LINK]] += unswappedLINK; @@ -643,7 +643,7 @@ contract CasimirManager is ICasimirManager, Ownable, ReentrancyGuard { ); // Todo use ssvToken.increaseAllowance(swappedSSV) if available ssvToken.approve( - address(automation), + address(upkeep), ssvToken.balanceOf(address(this)) ); unswappedTokens[tokenAddresses[Token.SSV]] += unswappedSSV; @@ -723,7 +723,7 @@ contract CasimirManager is ICasimirManager, Ownable, ReentrancyGuard { * @param oracle New oracle address */ function setOracleAddress(address oracle) external onlyOwner { - automation.setOracleAddress(oracle); + upkeep.setOracleAddress(oracle); } /** @@ -934,15 +934,15 @@ contract CasimirManager is ICasimirManager, Ownable, ReentrancyGuard { } /** - * @notice Get the automation address - * @return automationAddress The automation address + * @notice Get the upkeep address + * @return upkeepAddress The upkeep address */ - function getAutomationAddress() + function getUpkeepAddress() external view - returns (address automationAddress) + returns (address upkeepAddress) { - automationAddress = address(automation); + upkeepAddress = address(upkeep); } // Dev-only functions diff --git a/contracts/ethereum/src/CasimirAutomation.sol b/contracts/ethereum/src/CasimirUpkeep.sol similarity index 89% rename from contracts/ethereum/src/CasimirAutomation.sol rename to contracts/ethereum/src/CasimirUpkeep.sol index f70cbcc60..55e033c74 100644 --- a/contracts/ethereum/src/CasimirAutomation.sol +++ b/contracts/ethereum/src/CasimirUpkeep.sol @@ -1,10 +1,9 @@ // SPDX-License-Identifier: MIT pragma solidity ^0.8.7; -import "./interfaces/ICasimirAutomation.sol"; +import "./interfaces/ICasimirUpkeep.sol"; import "./interfaces/ICasimirManager.sol"; -import {Functions, FunctionsClient} from "./vendor/FunctionsClient.sol"; -// import "@chainlink/contracts/src/v0.8/dev/functions/FunctionsClient.sol"; // Once published +import {Functions, FunctionsClient} from "@chainlink/contracts/src/v0.8/dev/functions/FunctionsClient.sol"; import "@openzeppelin/contracts/access/Ownable.sol"; // Dev-only imports @@ -30,7 +29,7 @@ import "hardhat/console.sol"; /** * @title Oracle contract that triggers and handles actions */ -contract CasimirAutomation is ICasimirAutomation, FunctionsClient, Ownable { +contract CasimirUpkeep is ICasimirUpkeep, FunctionsClient, Ownable { /*************/ /* Libraries */ /*************/ @@ -194,12 +193,14 @@ contract CasimirAutomation is ICasimirAutomation, FunctionsClient, Ownable { manager.initiateReadyPools(readyPoolIds.length); // Todo find good bounds for batching } + /** Placeholder request */ + Functions.Request memory req; + /** Request a report */ - bytes32 requestId = s_oracle.sendRequest(oracleSubId, requestCBOR, fulfillGasLimit); - s_pendingRequests[requestId] = s_oracle.getRegistry(); + bytes32 requestId = sendRequest(req, oracleSubId, fulfillGasLimit); latestRequestId = requestId; - emit RequestSent(requestId); + emit UpkeepPerformed(performData); } /** @@ -222,16 +223,17 @@ contract CasimirAutomation is ICasimirAutomation, FunctionsClient, Ownable { if (err.length == 0) { /** Decode report */ - ( - uint256 activeStake, - uint256 sweptStake, - uint256 sweptExits - ) = abi.decode(response, (uint256, uint256, uint256)); + uint256 report = abi.decode(response, (uint256)); + console.log('Report: %s', report); - // Todo apply sensible heuristics to bound changes in stake + /** Unpack values */ + uint256 activeStake = uint256(uint64(report)) * 1 gwei; + uint256 sweptRewards = uint256(uint64(report >> 64)) * 1 gwei; + // uint256 sweptExits = uint256(uint64(report >> 128)) * 1 gwei; + // uint32 depositCount = uint32(report >> 192); + // uint32 withdrawalCount = uint32(report >> 224); - // Todo check simulation test for mistyped input - manager.rebalanceStake(activeStake, sweptStake); + manager.rebalanceStake(activeStake, sweptRewards); /** Complete the bounded count of pending pools */ uint32[] memory pendingPoolIds = manager.getPendingPoolIds(); diff --git a/contracts/ethereum/src/interfaces/ICasimirManager.sol b/contracts/ethereum/src/interfaces/ICasimirManager.sol index 95b949dc6..575059748 100644 --- a/contracts/ethereum/src/interfaces/ICasimirManager.sol +++ b/contracts/ethereum/src/interfaces/ICasimirManager.sol @@ -55,18 +55,18 @@ interface ICasimirManager { /* Events */ /**********/ - event PoolFilled(address indexed sender, uint32 poolId); - event PoolInitiated(uint32 indexed poolId); - event PoolCompleted(uint32 indexed poolId); - event PoolExitRequested(uint32 indexed poolId); - event PoolExited(uint32 indexed poolId); - event StakeDistributed(address indexed sender, uint256 amount); - event StakeRebalanced(address indexed sender, uint256 amount); - event WithdrawalRequested(address indexed sender, uint256 amount); - event WithdrawalInitiated(address indexed sender, uint256 amount); - event WithdrawalCompleted(address indexed sender, uint256 amount); - event ValidatorRegistered(bytes indexed publicKey); - event ValidatorReshared(bytes indexed publicKey); + event PoolFilled(address sender, uint32 poolId); + event PoolInitiated(uint32 poolId); + event PoolCompleted(uint32 poolId); + event PoolExitRequested(uint32 poolId); + event PoolExited(uint32 poolId); + event StakeDistributed(address sender, uint256 amount); + event StakeRebalanced(address sender, uint256 amount); + event WithdrawalRequested(address sender, uint256 amount); + event WithdrawalInitiated(address sender, uint256 amount); + event WithdrawalCompleted(address sender, uint256 amount); + event ValidatorRegistered(bytes publicKey); + event ValidatorReshared(bytes publicKey); /*************/ /* Functions */ diff --git a/contracts/ethereum/src/interfaces/ICasimirAutomation.sol b/contracts/ethereum/src/interfaces/ICasimirUpkeep.sol similarity index 90% rename from contracts/ethereum/src/interfaces/ICasimirAutomation.sol rename to contracts/ethereum/src/interfaces/ICasimirUpkeep.sol index 2c89e24fd..d6db3f958 100644 --- a/contracts/ethereum/src/interfaces/ICasimirAutomation.sol +++ b/contracts/ethereum/src/interfaces/ICasimirUpkeep.sol @@ -3,7 +3,7 @@ pragma solidity ^0.8.7; import "@chainlink/contracts/src/v0.8/interfaces/AutomationCompatibleInterface.sol"; -interface ICasimirAutomation is AutomationCompatibleInterface { +interface ICasimirUpkeep is AutomationCompatibleInterface { /***********/ /* Structs */ /***********/ @@ -21,6 +21,7 @@ interface ICasimirAutomation is AutomationCompatibleInterface { /**********/ event OCRResponse(bytes32 indexed requestId, bytes result, bytes err); + event UpkeepPerformed(bytes performData); /*************/ /* Functions */ diff --git a/contracts/ethereum/src/mock/MockFunctionsOracle.sol b/contracts/ethereum/src/mock/MockFunctionsOracle.sol index 690e80a72..77f272f73 100644 --- a/contracts/ethereum/src/mock/MockFunctionsOracle.sol +++ b/contracts/ethereum/src/mock/MockFunctionsOracle.sol @@ -1,7 +1,8 @@ // SPDX-License-Identifier: MIT pragma solidity ^0.8.0; -import "../vendor/interfaces/FunctionsOracleInterface.sol"; // Todo implement this interface +import "@chainlink/contracts/src/v0.8/dev/interfaces/FunctionsOracleInterface.sol"; + import "hardhat/console.sol"; /** diff --git a/contracts/ethereum/src/mock/MockKeeperRegistry.sol b/contracts/ethereum/src/mock/MockKeeperRegistry.sol deleted file mode 100644 index 34e2179e9..000000000 --- a/contracts/ethereum/src/mock/MockKeeperRegistry.sol +++ /dev/null @@ -1,33 +0,0 @@ -// SPDX-License-Identifier: MIT -pragma solidity ^0.8.0; - -import "../vendor/interfaces/IKeeperRegistry.sol"; // Todo implement this interface -import "hardhat/console.sol"; - -contract MockKeeperRegistry { - - function registerUpkeep( - address target, - uint32 gasLimit, - address admin, - bytes calldata checkData, - bytes calldata offchainConfig - ) external view returns (uint256 id) { - console.log(target, gasLimit, admin); - console.log(abi.decode(checkData, (string))); - console.log(offchainConfig.length); - return 0; - } - - function getState() - external - pure - returns ( - State memory state, - OnchainConfig memory config, - address[] memory signers, - address[] memory transmitters, - uint8 f - ) - {} -} diff --git a/contracts/ethereum/src/vendor/Functions.sol b/contracts/ethereum/src/vendor/Functions.sol deleted file mode 100644 index 1e258bd55..000000000 --- a/contracts/ethereum/src/vendor/Functions.sol +++ /dev/null @@ -1,145 +0,0 @@ -// SPDX-License-Identifier: MIT -pragma solidity ^0.8.6; - -import {CBOR, Buffer} from "./libraries/CBOR.sol"; - -/** - * @title Library for Chainlink Functions - */ -library Functions { - uint256 internal constant DEFAULT_BUFFER_SIZE = 256; - - using CBOR for Buffer.buffer; - - enum Location { - Inline, - Remote - } - - enum CodeLanguage { - JavaScript - // In future version we may add other languages - } - - struct Request { - Location codeLocation; - Location secretsLocation; - CodeLanguage language; - string source; // Source code for Location.Inline or url for Location.Remote - bytes secrets; // Encrypted secrets blob for Location.Inline or url for Location.Remote - string[] args; - } - - error EmptySource(); - error EmptyUrl(); - error EmptySecrets(); - error EmptyArgs(); - error NoInlineSecrets(); - - /** - * @notice Encodes a Request to CBOR encoded bytes - * @param self The request to encode - * @return CBOR encoded bytes - */ - function encodeCBOR( - Request memory self - ) internal pure returns (bytes memory) { - CBOR.CBORBuffer memory buffer; - Buffer.init(buffer.buf, DEFAULT_BUFFER_SIZE); - - CBOR.writeString(buffer, "codeLocation"); - CBOR.writeUInt256(buffer, uint256(self.codeLocation)); - - CBOR.writeString(buffer, "language"); - CBOR.writeUInt256(buffer, uint256(self.language)); - - CBOR.writeString(buffer, "source"); - CBOR.writeString(buffer, self.source); - - if (self.args.length > 0) { - CBOR.writeString(buffer, "args"); - CBOR.startArray(buffer); - for (uint256 i = 0; i < self.args.length; i++) { - CBOR.writeString(buffer, self.args[i]); - } - CBOR.endSequence(buffer); - } - - if (self.secrets.length > 0) { - if (self.secretsLocation == Location.Inline) { - revert NoInlineSecrets(); - } - CBOR.writeString(buffer, "secretsLocation"); - CBOR.writeUInt256(buffer, uint256(self.secretsLocation)); - CBOR.writeString(buffer, "secrets"); - CBOR.writeBytes(buffer, self.secrets); - } - - return buffer.buf.buf; - } - - /** - * @notice Initializes a Chainlink Functions Request - * @dev Sets the codeLocation and code on the request - * @param self The uninitialized request - * @param location The user provided source code location - * @param language The programming language of the user code - * @param source The user provided source code or a url - */ - function initializeRequest( - Request memory self, - Location location, - CodeLanguage language, - string memory source - ) internal pure { - if (bytes(source).length == 0) revert EmptySource(); - - self.codeLocation = location; - self.language = language; - self.source = source; - } - - /** - * @notice Initializes a Chainlink Functions Request - * @dev Simplified version of initializeRequest for PoC - * @param self The uninitialized request - * @param javaScriptSource The user provided JS code (must not be empty) - */ - function initializeRequestForInlineJavaScript( - Request memory self, - string memory javaScriptSource - ) internal pure { - initializeRequest( - self, - Location.Inline, - CodeLanguage.JavaScript, - javaScriptSource - ); - } - - /** - * @notice Adds Remote user encrypted secrets to a Request - * @param self The initialized request - * @param encryptedSecretsURLs Encrypted comma-separated string of URLs pointing to off-chain secrets - */ - function addRemoteSecrets( - Request memory self, - bytes memory encryptedSecretsURLs - ) internal pure { - if (encryptedSecretsURLs.length == 0) revert EmptySecrets(); - - self.secretsLocation = Location.Remote; - self.secrets = encryptedSecretsURLs; - } - - /** - * @notice Adds args for the user run function - * @param self The initialized request - * @param args The array of args (must not be empty) - */ - function addArgs(Request memory self, string[] memory args) internal pure { - if (args.length == 0) revert EmptyArgs(); - - self.args = args; - } -} diff --git a/contracts/ethereum/src/vendor/FunctionsClient.sol b/contracts/ethereum/src/vendor/FunctionsClient.sol deleted file mode 100644 index fd8b4a279..000000000 --- a/contracts/ethereum/src/vendor/FunctionsClient.sol +++ /dev/null @@ -1,155 +0,0 @@ -// SPDX-License-Identifier: MIT -pragma solidity ^0.8.6; - -import {Functions} from "./Functions.sol"; -import {FunctionsClientInterface} from "./interfaces/FunctionsClientInterface.sol"; -import {FunctionsOracleInterface} from "./interfaces/FunctionsOracleInterface.sol"; - -/** - * @title The Chainlink Functions client contract - * @notice Contract writers can inherit this contract in order to create Chainlink Functions requests - */ -abstract contract FunctionsClient is FunctionsClientInterface { - FunctionsOracleInterface internal s_oracle; - mapping(bytes32 => address) internal s_pendingRequests; - - event RequestSent(bytes32 indexed id); - event RequestFulfilled(bytes32 indexed id); - - error SenderIsNotRegistry(); - error RequestIsAlreadyPending(); - error RequestIsNotPending(); - - constructor(address oracle) { - setOracle(oracle); - } - - /** - * @inheritdoc FunctionsClientInterface - */ - function getDONPublicKey() external view override returns (bytes memory) { - return s_oracle.getDONPublicKey(); - } - - /** - * @notice Estimate the total cost that will be charged to a subscription to make a request: gas re-imbursement, plus DON fee, plus Registry fee - * @param req The initialized Functions.Request - * @param subscriptionId The subscription ID - * @param gasLimit gas limit for the fulfillment callback - * @return billedCost Cost in Juels (1e18) of LINK - */ - function estimateCost( - Functions.Request memory req, - uint64 subscriptionId, - uint32 gasLimit, - uint256 gasPrice - ) public view returns (uint96) { - return - s_oracle.estimateCost( - subscriptionId, - Functions.encodeCBOR(req), - gasLimit, - gasPrice - ); - } - - /** - * @notice Sends a Chainlink Functions request to the stored oracle address - * @param req The initialized Functions.Request - * @param subscriptionId The subscription ID - * @param gasLimit gas limit for the fulfillment callback - * @return requestId The generated request ID - */ - function sendRequest( - Functions.Request memory req, - uint64 subscriptionId, - uint32 gasLimit - ) internal returns (bytes32) { - bytes32 requestId = s_oracle.sendRequest( - subscriptionId, - Functions.encodeCBOR(req), - gasLimit - ); - s_pendingRequests[requestId] = s_oracle.getRegistry(); - emit RequestSent(requestId); - return requestId; - } - - /** - * @notice User defined function to handle a response - * @param requestId The request ID, returned by sendRequest() - * @param response Aggregated response from the user code - * @param err Aggregated error from the user code or from the execution pipeline - * Either response or error parameter will be set, but never both - */ - function fulfillRequest( - bytes32 requestId, - bytes memory response, - bytes memory err - ) internal virtual; - - /** - * @inheritdoc FunctionsClientInterface - */ - function handleOracleFulfillment( - bytes32 requestId, - bytes memory response, - bytes memory err - ) external override recordChainlinkFulfillment(requestId) { - fulfillRequest(requestId, response, err); - } - - /** - * @notice Sets the stored Oracle address - * @param oracle The address of Functions Oracle contract - */ - function setOracle(address oracle) internal { - s_oracle = FunctionsOracleInterface(oracle); - } - - /** - * @notice Gets the stored address of the oracle contract - * @return The address of the oracle contract - */ - function getChainlinkOracleAddress() internal view returns (address) { - return address(s_oracle); - } - - /** - * @notice Allows for a request which was created on another contract to be fulfilled - * on this contract - * @param oracleAddress The address of the oracle contract that will fulfill the request - * @param requestId The request ID used for the response - */ - function addExternalRequest( - address oracleAddress, - bytes32 requestId - ) internal notPendingRequest(requestId) { - s_pendingRequests[requestId] = oracleAddress; - } - - /** - * @dev Reverts if the sender is not the oracle that serviced the request. - * Emits RequestFulfilled event. - * @param requestId The request ID for fulfillment - */ - modifier recordChainlinkFulfillment(bytes32 requestId) { - if (msg.sender != s_pendingRequests[requestId]) { - revert SenderIsNotRegistry(); - } - delete s_pendingRequests[requestId]; - emit RequestFulfilled(requestId); - _; - } - - /** - * @dev Reverts if the request is already pending - * @param requestId The request ID for fulfillment - */ - modifier notPendingRequest(bytes32 requestId) { - if (s_pendingRequests[requestId] != address(0)) { - revert RequestIsAlreadyPending(); - } - _; - } -} diff --git a/contracts/ethereum/functions/FunctionsSandboxLibrary/Functions.js b/contracts/ethereum/src/vendor/FunctionsSandboxLibrary/Functions.js similarity index 100% rename from contracts/ethereum/functions/FunctionsSandboxLibrary/Functions.js rename to contracts/ethereum/src/vendor/FunctionsSandboxLibrary/Functions.js diff --git a/contracts/ethereum/functions/FunctionsSandboxLibrary/Log.js b/contracts/ethereum/src/vendor/FunctionsSandboxLibrary/Log.js similarity index 100% rename from contracts/ethereum/functions/FunctionsSandboxLibrary/Log.js rename to contracts/ethereum/src/vendor/FunctionsSandboxLibrary/Log.js diff --git a/contracts/ethereum/functions/FunctionsSandboxLibrary/Sandbox.js b/contracts/ethereum/src/vendor/FunctionsSandboxLibrary/Sandbox.js similarity index 100% rename from contracts/ethereum/functions/FunctionsSandboxLibrary/Sandbox.js rename to contracts/ethereum/src/vendor/FunctionsSandboxLibrary/Sandbox.js diff --git a/contracts/ethereum/functions/FunctionsSandboxLibrary/Validator.js b/contracts/ethereum/src/vendor/FunctionsSandboxLibrary/Validator.js similarity index 100% rename from contracts/ethereum/functions/FunctionsSandboxLibrary/Validator.js rename to contracts/ethereum/src/vendor/FunctionsSandboxLibrary/Validator.js diff --git a/contracts/ethereum/functions/FunctionsSandboxLibrary/buildRequest.js b/contracts/ethereum/src/vendor/FunctionsSandboxLibrary/buildRequest.js similarity index 100% rename from contracts/ethereum/functions/FunctionsSandboxLibrary/buildRequest.js rename to contracts/ethereum/src/vendor/FunctionsSandboxLibrary/buildRequest.js diff --git a/contracts/ethereum/functions/FunctionsSandboxLibrary/encryptSecrets.js b/contracts/ethereum/src/vendor/FunctionsSandboxLibrary/encryptSecrets.js similarity index 100% rename from contracts/ethereum/functions/FunctionsSandboxLibrary/encryptSecrets.js rename to contracts/ethereum/src/vendor/FunctionsSandboxLibrary/encryptSecrets.js diff --git a/contracts/ethereum/functions/FunctionsSandboxLibrary/getRequestConfig.js b/contracts/ethereum/src/vendor/FunctionsSandboxLibrary/getRequestConfig.js similarity index 100% rename from contracts/ethereum/functions/FunctionsSandboxLibrary/getRequestConfig.js rename to contracts/ethereum/src/vendor/FunctionsSandboxLibrary/getRequestConfig.js diff --git a/contracts/ethereum/functions/FunctionsSandboxLibrary/handler.js b/contracts/ethereum/src/vendor/FunctionsSandboxLibrary/handler.js similarity index 100% rename from contracts/ethereum/functions/FunctionsSandboxLibrary/handler.js rename to contracts/ethereum/src/vendor/FunctionsSandboxLibrary/handler.js diff --git a/contracts/ethereum/functions/FunctionsSandboxLibrary/index.js b/contracts/ethereum/src/vendor/FunctionsSandboxLibrary/index.js similarity index 100% rename from contracts/ethereum/functions/FunctionsSandboxLibrary/index.js rename to contracts/ethereum/src/vendor/FunctionsSandboxLibrary/index.js diff --git a/contracts/ethereum/functions/FunctionsSandboxLibrary/simulateRequest.js b/contracts/ethereum/src/vendor/FunctionsSandboxLibrary/simulateRequest.js similarity index 100% rename from contracts/ethereum/functions/FunctionsSandboxLibrary/simulateRequest.js rename to contracts/ethereum/src/vendor/FunctionsSandboxLibrary/simulateRequest.js diff --git a/contracts/ethereum/src/vendor/interfaces/FunctionsBillingRegistryInterface.sol b/contracts/ethereum/src/vendor/interfaces/FunctionsBillingRegistryInterface.sol deleted file mode 100644 index a09226f99..000000000 --- a/contracts/ethereum/src/vendor/interfaces/FunctionsBillingRegistryInterface.sol +++ /dev/null @@ -1,107 +0,0 @@ -// SPDX-License-Identifier: MIT -pragma solidity ^0.8.6; - -/** - * @title Chainlink Functions billing subscription registry interface. - */ -interface FunctionsBillingRegistryInterface { - struct RequestBilling { - // a unique subscription ID allocated by billing system, - uint64 subscriptionId; - // the client contract that initiated the request to the DON - // to use the subscription it must be added as a consumer on the subscription - address client; - // customer specified gas limit for the fulfillment callback - uint32 gasLimit; - // the expected gas price used to execute the transaction - uint256 gasPrice; - } - - enum FulfillResult { - USER_SUCCESS, - USER_ERROR, - INVALID_REQUEST_ID - } - - /** - * @notice Get configuration relevant for making requests - * @return uint32 global max for request gas limit - * @return address[] list of registered DONs - */ - function getRequestConfig() - external - view - returns (uint32, address[] memory); - - /** - * @notice Determine the charged fee that will be paid to the Registry owner - * @param data Encoded Chainlink Functions request data, use FunctionsClient API to encode a request - * @param billing The request's billing configuration - * @return fee Cost in Juels (1e18) of LINK - */ - function getRequiredFee( - bytes calldata data, - FunctionsBillingRegistryInterface.RequestBilling memory billing - ) external view returns (uint96); - - /** - * @notice Estimate the total cost to make a request: gas re-imbursement, plus DON fee, plus Registry fee - * @param gasLimit Encoded Chainlink Functions request data, use FunctionsClient API to encode a request - * @param gasPrice The request's billing configuration - * @param donFee Fee charged by the DON that is paid to Oracle Node - * @param registryFee Fee charged by the DON that is paid to Oracle Node - * @return costEstimate Cost in Juels (1e18) of LINK - */ - function estimateCost( - uint32 gasLimit, - uint256 gasPrice, - uint96 donFee, - uint96 registryFee - ) external view returns (uint96); - - /** - * @notice Initiate the billing process for an Functions request - * @param data Encoded Chainlink Functions request data, use FunctionsClient API to encode a request - * @param billing Billing configuration for the request - * @return requestId - A unique identifier of the request. Can be used to match a request to a response in fulfillRequest. - * @dev Only callable by a node that has been approved on the Registry - */ - function startBilling( - bytes calldata data, - RequestBilling calldata billing - ) external returns (bytes32); - - /** - * @notice Finalize billing process for an Functions request by sending a callback to the Client contract and then charging the subscription - * @param requestId identifier for the request that was generated by the Registry in the beginBilling commitment - * @param response response data from DON consensus - * @param err error from DON consensus - * @param transmitter the Oracle who sent the report - * @param signers the Oracles who had a part in generating the report - * @param signerCount the number of signers on the report - * @param reportValidationGas the amount of gas used for the report validation. Cost is split by all fulfillments on the report. - * @param initialGas the initial amount of gas that should be used as a baseline to charge the single fulfillment for execution cost - * @return result fulfillment result - * @dev Only callable by a node that has been approved on the Registry - * @dev simulated offchain to determine if sufficient balance is present to fulfill the request - */ - function fulfillAndBill( - bytes32 requestId, - bytes calldata response, - bytes calldata err, - address transmitter, - address[31] memory signers, // 31 comes from OCR2Abstract.sol's maxNumOracles constant - uint8 signerCount, - uint256 reportValidationGas, - uint256 initialGas - ) external returns (FulfillResult); - - /** - * @notice Gets subscription owner. - * @param subscriptionId - ID of the subscription - * @return owner - owner of the subscription. - */ - function getSubscriptionOwner( - uint64 subscriptionId - ) external view returns (address owner); -} diff --git a/contracts/ethereum/src/vendor/interfaces/FunctionsClientInterface.sol b/contracts/ethereum/src/vendor/interfaces/FunctionsClientInterface.sol deleted file mode 100644 index f70325d97..000000000 --- a/contracts/ethereum/src/vendor/interfaces/FunctionsClientInterface.sol +++ /dev/null @@ -1,28 +0,0 @@ -// SPDX-License-Identifier: MIT -pragma solidity ^0.8.6; - -/** - * @title Chainlink Functions client interface. - */ -interface FunctionsClientInterface { - /** - * @notice Returns the DON's secp256k1 public key used to encrypt secrets - * @dev All Oracles nodes have the corresponding private key - * needed to decrypt the secrets encrypted with the public key - * @return publicKey DON's public key - */ - function getDONPublicKey() external view returns (bytes memory); - - /** - * @notice Chainlink Functions response handler called by the designated transmitter node in an OCR round. - * @param requestId The requestId returned by FunctionsClient.sendRequest(). - * @param response Aggregated response from the user code. - * @param err Aggregated error either from the user code or from the execution pipeline. - * Either response or error parameter will be set, but never both. - */ - function handleOracleFulfillment( - bytes32 requestId, - bytes memory response, - bytes memory err - ) external; -} diff --git a/contracts/ethereum/src/vendor/interfaces/FunctionsOracleInterface.sol b/contracts/ethereum/src/vendor/interfaces/FunctionsOracleInterface.sol deleted file mode 100644 index d590a7c20..000000000 --- a/contracts/ethereum/src/vendor/interfaces/FunctionsOracleInterface.sol +++ /dev/null @@ -1,100 +0,0 @@ -// SPDX-License-Identifier: MIT -pragma solidity ^0.8.6; - -import "./FunctionsBillingRegistryInterface.sol"; - -/** - * @title Chainlink Functions oracle interface. - */ -interface FunctionsOracleInterface { - /** - * @notice Gets the stored billing registry address - * @return registryAddress The address of Chainlink Functions billing registry contract - */ - function getRegistry() external view returns (address); - - /** - * @notice Sets the stored billing registry address - * @param registryAddress The new address of Chainlink Functions billing registry contract - */ - function setRegistry(address registryAddress) external; - - /** - * @notice Returns the DON's secp256k1 public key that is used to encrypt secrets - * @dev All nodes on the DON have the corresponding private key - * needed to decrypt the secrets encrypted with the public key - * @return publicKey the DON's public key - */ - function getDONPublicKey() external view returns (bytes memory); - - /** - * @notice Sets DON's secp256k1 public key used to encrypt secrets - * @dev Used to rotate the key - * @param donPublicKey The new public key - */ - function setDONPublicKey(bytes calldata donPublicKey) external; - - /** - * @notice Sets a per-node secp256k1 public key used to encrypt secrets for that node - * @dev Callable only by contract owner and DON members - * @param node node's address - * @param publicKey node's public key - */ - function setNodePublicKey(address node, bytes calldata publicKey) external; - - /** - * @notice Deletes node's public key - * @dev Callable only by contract owner or the node itself - * @param node node's address - */ - function deleteNodePublicKey(address node) external; - - /** - * @notice Return two arrays of equal size containing DON members' addresses and their corresponding - * public keys (or empty byte arrays if per-node key is not defined) - */ - function getAllNodePublicKeys() - external - view - returns (address[] memory, bytes[] memory); - - /** - * @notice Determine the fee charged by the DON that will be split between signing Node Operators for servicing the request - * @param data Encoded Chainlink Functions request data, use FunctionsClient API to encode a request - * @param billing The request's billing configuration - * @return fee Cost in Juels (1e18) of LINK - */ - function getRequiredFee( - bytes calldata data, - FunctionsBillingRegistryInterface.RequestBilling calldata billing - ) external view returns (uint96); - - /** - * @notice Estimate the total cost that will be charged to a subscription to make a request: gas re-imbursement, plus DON fee, plus Registry fee - * @param subscriptionId A unique subscription ID allocated by billing system, - * a client can make requests from different contracts referencing the same subscription - * @param data Encoded Chainlink Functions request data, use FunctionsClient API to encode a request - * @param gasLimit Gas limit for the fulfillment callback - * @return billedCost Cost in Juels (1e18) of LINK - */ - function estimateCost( - uint64 subscriptionId, - bytes calldata data, - uint32 gasLimit, - uint256 gasPrice - ) external view returns (uint96); - - /** - * @notice Sends a request (encoded as data) using the provided subscriptionId - * @param subscriptionId A unique subscription ID allocated by billing system, - * a client can make requests from different contracts referencing the same subscription - * @param data Encoded Chainlink Functions request data, use FunctionsClient API to encode a request - * @param gasLimit Gas limit for the fulfillment callback - * @return requestId A unique request identifier (unique per DON) - */ - function sendRequest( - uint64 subscriptionId, - bytes calldata data, - uint32 gasLimit - ) external returns (bytes32); -} diff --git a/contracts/ethereum/src/vendor/interfaces/IKeeperRegistry.sol b/contracts/ethereum/src/vendor/interfaces/IKeeperRegistry.sol deleted file mode 100644 index ff62ebdfb..000000000 --- a/contracts/ethereum/src/vendor/interfaces/IKeeperRegistry.sol +++ /dev/null @@ -1,202 +0,0 @@ -// SPDX-License-Identifier: MIT -pragma solidity ^0.8.0; - -/** - * @notice OnchainConfig of the registry - * @dev only used in params and return values - * @member paymentPremiumPPB payment premium rate oracles receive on top of - * being reimbursed for gas, measured in parts per billion - * @member flatFeeMicroLink flat fee paid to oracles for performing upkeeps, - * priced in MicroLink; can be used in conjunction with or independently of - * paymentPremiumPPB - * @member checkGasLimit gas limit when checking for upkeep - * @member stalenessSeconds number of seconds that is allowed for feed data to - * be stale before switching to the fallback pricing - * @member gasCeilingMultiplier multiplier to apply to the fast gas feed price - * when calculating the payment ceiling for keepers - * @member minUpkeepSpend minimum LINK that an upkeep must spend before cancelling - * @member maxPerformGas max executeGas allowed for an upkeep on this registry - * @member fallbackGasPrice gas price used if the gas price feed is stale - * @member fallbackLinkPrice LINK price used if the LINK price feed is stale - * @member transcoder address of the transcoder contract - * @member registrar address of the registrar contract - */ -struct OnchainConfig { - uint32 paymentPremiumPPB; - uint32 flatFeeMicroLink; // min 0.000001 LINK, max 4294 LINK - uint32 checkGasLimit; - uint24 stalenessSeconds; - uint16 gasCeilingMultiplier; - uint96 minUpkeepSpend; - uint32 maxPerformGas; - uint32 maxCheckDataSize; - uint32 maxPerformDataSize; - uint256 fallbackGasPrice; - uint256 fallbackLinkPrice; - address transcoder; - address registrar; -} - -/** - * @notice state of the registry - * @dev only used in params and return values - * @member nonce used for ID generation - * @member ownerLinkBalance withdrawable balance of LINK by contract owner - * @member expectedLinkBalance the expected balance of LINK of the registry - * @member totalPremium the total premium collected on registry so far - * @member numUpkeeps total number of upkeeps on the registry - * @member configCount ordinal number of current config, out of all configs applied to this contract so far - * @member latestConfigBlockNumber last block at which this config was set - * @member latestConfigDigest domain-separation tag for current config - * @member latestEpoch for which a report was transmitted - * @member paused freeze on execution scoped to the entire registry - */ -struct State { - uint32 nonce; - uint96 ownerLinkBalance; - uint256 expectedLinkBalance; - uint96 totalPremium; - uint256 numUpkeeps; - uint32 configCount; - uint32 latestConfigBlockNumber; - bytes32 latestConfigDigest; - uint32 latestEpoch; - bool paused; -} - -/** - * @notice all information about an upkeep - * @dev only used in return values - * @member target the contract which needs to be serviced - * @member executeGas the gas limit of upkeep execution - * @member checkData the checkData bytes for this upkeep - * @member balance the balance of this upkeep - * @member admin for this upkeep - * @member maxValidBlocknumber until which block this upkeep is valid - * @member lastPerformBlockNumber the last block number when this upkeep was performed - * @member amountSpent the amount this upkeep has spent - * @member paused if this upkeep has been paused - * @member skipSigVerification skip signature verification in transmit for a low security low cost model - */ -struct UpkeepInfo { - address target; - uint32 executeGas; - bytes checkData; - uint96 balance; - address admin; - uint64 maxValidBlocknumber; - uint32 lastPerformBlockNumber; - uint96 amountSpent; - bool paused; - bytes offchainConfig; -} - -enum UpkeepFailureReason { - NONE, - UPKEEP_CANCELLED, - UPKEEP_PAUSED, - TARGET_CHECK_REVERTED, - UPKEEP_NOT_NEEDED, - PERFORM_DATA_EXCEEDS_LIMIT, - INSUFFICIENT_BALANCE -} - -interface KeeperRegistryBaseInterface { - function registerUpkeep( - address target, - uint32 gasLimit, - address admin, - bytes calldata checkData, - bytes calldata offchainConfig - ) external returns (uint256 id); - - function cancelUpkeep(uint256 id) external; - - function pauseUpkeep(uint256 id) external; - - function unpauseUpkeep(uint256 id) external; - - function transferUpkeepAdmin(uint256 id, address proposed) external; - - function acceptUpkeepAdmin(uint256 id) external; - - function updateCheckData(uint256 id, bytes calldata newCheckData) external; - - function addFunds(uint256 id, uint96 amount) external; - - function setUpkeepGasLimit(uint256 id, uint32 gasLimit) external; - - function setUpkeepOffchainConfig( - uint256 id, - bytes calldata config - ) external; - - function getUpkeep( - uint256 id - ) external view returns (UpkeepInfo memory upkeepInfo); - - function getActiveUpkeepIDs( - uint256 startIndex, - uint256 maxCount - ) external view returns (uint256[] memory); - - function getTransmitterInfo( - address query - ) - external - view - returns ( - bool active, - uint8 index, - uint96 balance, - uint96 lastCollected, - address payee - ); - - function getState() - external - view - returns ( - State memory state, - OnchainConfig memory config, - address[] memory signers, - address[] memory transmitters, - uint8 f - ); -} - -/** - * @dev The view methods are not actually marked as view in the implementation - * but we want them to be easily queried off-chain. Solidity will not compile - * if we actually inherit from this interface, so we document it here. - */ -interface IKeeperRegistry is KeeperRegistryBaseInterface { - function checkUpkeep( - uint256 upkeepId - ) - external - view - returns ( - bool upkeepNeeded, - bytes memory performData, - UpkeepFailureReason upkeepFailureReason, - uint256 gasUsed, - uint256 fastGasWei, - uint256 linkNative - ); -} - -interface KeeperRegistryExecutableInterface is KeeperRegistryBaseInterface { - function checkUpkeep( - uint256 upkeepId - ) - external - returns ( - bool upkeepNeeded, - bytes memory performData, - UpkeepFailureReason upkeepFailureReason, - uint256 gasUsed, - uint256 fastGasWei, - uint256 linkNative - ); -} diff --git a/contracts/ethereum/src/vendor/libraries/Buffer.sol b/contracts/ethereum/src/vendor/libraries/Buffer.sol deleted file mode 100644 index 34a72d629..000000000 --- a/contracts/ethereum/src/vendor/libraries/Buffer.sol +++ /dev/null @@ -1,287 +0,0 @@ -// SPDX-License-Identifier: BSD-2-Clause -pragma solidity ^0.8.4; - -/** - * @dev A library for working with mutable byte buffers in Solidity. - * - * Byte buffers are mutable and expandable, and provide a variety of primitives - * for appending to them. At any time you can fetch a bytes object containing the - * current contents of the buffer. The bytes object should not be stored between - * operations, as it may change due to resizing of the buffer. - */ -library Buffer { - /** - * @dev Represents a mutable buffer. Buffers have a current value (buf) and - * a capacity. The capacity may be longer than the current value, in - * which case it can be extended without the need to allocate more memory. - */ - struct buffer { - bytes buf; - uint capacity; - } - - /** - * @dev Initializes a buffer with an initial capacity. - * @param buf The buffer to initialize. - * @param capacity The number of bytes of space to allocate the buffer. - * @return The buffer, for chaining. - */ - function init( - buffer memory buf, - uint capacity - ) internal pure returns (buffer memory) { - if (capacity % 32 != 0) { - capacity += 32 - (capacity % 32); - } - // Allocate space for the buffer data - buf.capacity = capacity; - assembly { - let ptr := mload(0x40) - mstore(buf, ptr) - mstore(ptr, 0) - let fpm := add(32, add(ptr, capacity)) - if lt(fpm, ptr) { - revert(0, 0) - } - mstore(0x40, fpm) - } - return buf; - } - - /** - * @dev Initializes a new buffer from an existing bytes object. - * Changes to the buffer may mutate the original value. - * @param b The bytes object to initialize the buffer with. - * @return A new buffer. - */ - function fromBytes(bytes memory b) internal pure returns (buffer memory) { - buffer memory buf; - buf.buf = b; - buf.capacity = b.length; - return buf; - } - - function resize(buffer memory buf, uint capacity) private pure { - bytes memory oldbuf = buf.buf; - init(buf, capacity); - append(buf, oldbuf); - } - - /** - * @dev Sets buffer length to 0. - * @param buf The buffer to truncate. - * @return The original buffer, for chaining.. - */ - function truncate(buffer memory buf) internal pure returns (buffer memory) { - assembly { - let bufptr := mload(buf) - mstore(bufptr, 0) - } - return buf; - } - - /** - * @dev Appends len bytes of a byte string to a buffer. Resizes if doing so would exceed - * the capacity of the buffer. - * @param buf The buffer to append to. - * @param data The data to append. - * @param len The number of bytes to copy. - * @return The original buffer, for chaining. - */ - function append( - buffer memory buf, - bytes memory data, - uint len - ) internal pure returns (buffer memory) { - require(len <= data.length); - - uint off = buf.buf.length; - uint newCapacity = off + len; - if (newCapacity > buf.capacity) { - resize(buf, newCapacity * 2); - } - - uint dest; - uint src; - assembly { - // Memory address of the buffer data - let bufptr := mload(buf) - // Length of existing buffer data - let buflen := mload(bufptr) - // Start address = buffer address + offset + sizeof(buffer length) - dest := add(add(bufptr, 32), off) - // Update buffer length if we're extending it - if gt(newCapacity, buflen) { - mstore(bufptr, newCapacity) - } - src := add(data, 32) - } - - // Copy word-length chunks while possible - for (; len >= 32; len -= 32) { - assembly { - mstore(dest, mload(src)) - } - dest += 32; - src += 32; - } - - // Copy remaining bytes - unchecked { - uint mask = (256 ** (32 - len)) - 1; - assembly { - let srcpart := and(mload(src), not(mask)) - let destpart := and(mload(dest), mask) - mstore(dest, or(destpart, srcpart)) - } - } - - return buf; - } - - /** - * @dev Appends a byte string to a buffer. Resizes if doing so would exceed - * the capacity of the buffer. - * @param buf The buffer to append to. - * @param data The data to append. - * @return The original buffer, for chaining. - */ - function append( - buffer memory buf, - bytes memory data - ) internal pure returns (buffer memory) { - return append(buf, data, data.length); - } - - /** - * @dev Appends a byte to the buffer. Resizes if doing so would exceed the - * capacity of the buffer. - * @param buf The buffer to append to. - * @param data The data to append. - * @return The original buffer, for chaining. - */ - function appendUint8( - buffer memory buf, - uint8 data - ) internal pure returns (buffer memory) { - uint off = buf.buf.length; - uint offPlusOne = off + 1; - if (off >= buf.capacity) { - resize(buf, offPlusOne * 2); - } - - assembly { - // Memory address of the buffer data - let bufptr := mload(buf) - // Address = buffer address + sizeof(buffer length) + off - let dest := add(add(bufptr, off), 32) - mstore8(dest, data) - // Update buffer length if we extended it - if gt(offPlusOne, mload(bufptr)) { - mstore(bufptr, offPlusOne) - } - } - - return buf; - } - - /** - * @dev Appends len bytes of bytes32 to a buffer. Resizes if doing so would - * exceed the capacity of the buffer. - * @param buf The buffer to append to. - * @param data The data to append. - * @param len The number of bytes to write (left-aligned). - * @return The original buffer, for chaining. - */ - function append( - buffer memory buf, - bytes32 data, - uint len - ) private pure returns (buffer memory) { - uint off = buf.buf.length; - uint newCapacity = len + off; - if (newCapacity > buf.capacity) { - resize(buf, newCapacity * 2); - } - - unchecked { - uint mask = (256 ** len) - 1; - // Right-align data - data = data >> (8 * (32 - len)); - assembly { - // Memory address of the buffer data - let bufptr := mload(buf) - // Address = buffer address + sizeof(buffer length) + newCapacity - let dest := add(bufptr, newCapacity) - mstore(dest, or(and(mload(dest), not(mask)), data)) - // Update buffer length if we extended it - if gt(newCapacity, mload(bufptr)) { - mstore(bufptr, newCapacity) - } - } - } - return buf; - } - - /** - * @dev Appends a bytes20 to the buffer. Resizes if doing so would exceed - * the capacity of the buffer. - * @param buf The buffer to append to. - * @param data The data to append. - * @return The original buffer, for chhaining. - */ - function appendBytes20( - buffer memory buf, - bytes20 data - ) internal pure returns (buffer memory) { - return append(buf, bytes32(data), 20); - } - - /** - * @dev Appends a bytes32 to the buffer. Resizes if doing so would exceed - * the capacity of the buffer. - * @param buf The buffer to append to. - * @param data The data to append. - * @return The original buffer, for chaining. - */ - function appendBytes32( - buffer memory buf, - bytes32 data - ) internal pure returns (buffer memory) { - return append(buf, data, 32); - } - - /** - * @dev Appends a byte to the end of the buffer. Resizes if doing so would - * exceed the capacity of the buffer. - * @param buf The buffer to append to. - * @param data The data to append. - * @param len The number of bytes to write (right-aligned). - * @return The original buffer. - */ - function appendInt( - buffer memory buf, - uint data, - uint len - ) internal pure returns (buffer memory) { - uint off = buf.buf.length; - uint newCapacity = len + off; - if (newCapacity > buf.capacity) { - resize(buf, newCapacity * 2); - } - - uint mask = (256 ** len) - 1; - assembly { - // Memory address of the buffer data - let bufptr := mload(buf) - // Address = buffer address + sizeof(buffer length) + newCapacity - let dest := add(bufptr, newCapacity) - mstore(dest, or(and(mload(dest), not(mask)), data)) - // Update buffer length if we extended it - if gt(newCapacity, mload(bufptr)) { - mstore(bufptr, newCapacity) - } - } - return buf; - } -} diff --git a/contracts/ethereum/src/vendor/libraries/CBOR.sol b/contracts/ethereum/src/vendor/libraries/CBOR.sol deleted file mode 100644 index 559264282..000000000 --- a/contracts/ethereum/src/vendor/libraries/CBOR.sol +++ /dev/null @@ -1,274 +0,0 @@ -// SPDX-License-Identifier: MIT -pragma solidity ^0.8.4; - -import "./Buffer.sol"; - -/** - * @dev A library for populating CBOR encoded payload in Solidity. - * - * https://datatracker.ietf.org/doc/html/rfc7049 - * - * The library offers various write* and start* methods to encode values of different types. - * The resulted buffer can be obtained with data() method. - * Encoding of primitive types is staightforward, whereas encoding of sequences can result - * in an invalid CBOR if start/write/end flow is violated. - * For the purpose of gas saving, the library does not verify start/write/end flow internally, - * except for nested start/end pairs. - */ - -library CBOR { - using Buffer for Buffer.buffer; - - struct CBORBuffer { - Buffer.buffer buf; - uint256 depth; - } - - uint8 private constant MAJOR_TYPE_INT = 0; - uint8 private constant MAJOR_TYPE_NEGATIVE_INT = 1; - uint8 private constant MAJOR_TYPE_BYTES = 2; - uint8 private constant MAJOR_TYPE_STRING = 3; - uint8 private constant MAJOR_TYPE_ARRAY = 4; - uint8 private constant MAJOR_TYPE_MAP = 5; - uint8 private constant MAJOR_TYPE_TAG = 6; - uint8 private constant MAJOR_TYPE_CONTENT_FREE = 7; - - uint8 private constant TAG_TYPE_BIGNUM = 2; - uint8 private constant TAG_TYPE_NEGATIVE_BIGNUM = 3; - - uint8 private constant CBOR_FALSE = 20; - uint8 private constant CBOR_TRUE = 21; - uint8 private constant CBOR_NULL = 22; - uint8 private constant CBOR_UNDEFINED = 23; - - function create( - uint256 capacity - ) internal pure returns (CBORBuffer memory cbor) { - Buffer.init(cbor.buf, capacity); - cbor.depth = 0; - return cbor; - } - - function data(CBORBuffer memory buf) internal pure returns (bytes memory) { - require(buf.depth == 0, "Invalid CBOR"); - return buf.buf.buf; - } - - function writeUInt256(CBORBuffer memory buf, uint256 value) internal pure { - buf.buf.appendUint8(uint8((MAJOR_TYPE_TAG << 5) | TAG_TYPE_BIGNUM)); - writeBytes(buf, abi.encode(value)); - } - - function writeInt256(CBORBuffer memory buf, int256 value) internal pure { - if (value < 0) { - buf.buf.appendUint8( - uint8((MAJOR_TYPE_TAG << 5) | TAG_TYPE_NEGATIVE_BIGNUM) - ); - writeBytes(buf, abi.encode(uint256(-1 - value))); - } else { - writeUInt256(buf, uint256(value)); - } - } - - function writeUInt64(CBORBuffer memory buf, uint64 value) internal pure { - writeFixedNumeric(buf, MAJOR_TYPE_INT, value); - } - - function writeInt64(CBORBuffer memory buf, int64 value) internal pure { - if (value >= 0) { - writeFixedNumeric(buf, MAJOR_TYPE_INT, uint64(value)); - } else { - writeFixedNumeric(buf, MAJOR_TYPE_NEGATIVE_INT, uint64(-1 - value)); - } - } - - function writeBytes( - CBORBuffer memory buf, - bytes memory value - ) internal pure { - writeFixedNumeric(buf, MAJOR_TYPE_BYTES, uint64(value.length)); - buf.buf.append(value); - } - - function writeString( - CBORBuffer memory buf, - string memory value - ) internal pure { - writeFixedNumeric(buf, MAJOR_TYPE_STRING, uint64(bytes(value).length)); - buf.buf.append(bytes(value)); - } - - function writeBool(CBORBuffer memory buf, bool value) internal pure { - writeContentFree(buf, value ? CBOR_TRUE : CBOR_FALSE); - } - - function writeNull(CBORBuffer memory buf) internal pure { - writeContentFree(buf, CBOR_NULL); - } - - function writeUndefined(CBORBuffer memory buf) internal pure { - writeContentFree(buf, CBOR_UNDEFINED); - } - - function startArray(CBORBuffer memory buf) internal pure { - writeIndefiniteLengthType(buf, MAJOR_TYPE_ARRAY); - buf.depth += 1; - } - - function startFixedArray( - CBORBuffer memory buf, - uint64 length - ) internal pure { - writeDefiniteLengthType(buf, MAJOR_TYPE_ARRAY, length); - } - - function startMap(CBORBuffer memory buf) internal pure { - writeIndefiniteLengthType(buf, MAJOR_TYPE_MAP); - buf.depth += 1; - } - - function startFixedMap(CBORBuffer memory buf, uint64 length) internal pure { - writeDefiniteLengthType(buf, MAJOR_TYPE_MAP, length); - } - - function endSequence(CBORBuffer memory buf) internal pure { - writeIndefiniteLengthType(buf, MAJOR_TYPE_CONTENT_FREE); - buf.depth -= 1; - } - - function writeKVString( - CBORBuffer memory buf, - string memory key, - string memory value - ) internal pure { - writeString(buf, key); - writeString(buf, value); - } - - function writeKVBytes( - CBORBuffer memory buf, - string memory key, - bytes memory value - ) internal pure { - writeString(buf, key); - writeBytes(buf, value); - } - - function writeKVUInt256( - CBORBuffer memory buf, - string memory key, - uint256 value - ) internal pure { - writeString(buf, key); - writeUInt256(buf, value); - } - - function writeKVInt256( - CBORBuffer memory buf, - string memory key, - int256 value - ) internal pure { - writeString(buf, key); - writeInt256(buf, value); - } - - function writeKVUInt64( - CBORBuffer memory buf, - string memory key, - uint64 value - ) internal pure { - writeString(buf, key); - writeUInt64(buf, value); - } - - function writeKVInt64( - CBORBuffer memory buf, - string memory key, - int64 value - ) internal pure { - writeString(buf, key); - writeInt64(buf, value); - } - - function writeKVBool( - CBORBuffer memory buf, - string memory key, - bool value - ) internal pure { - writeString(buf, key); - writeBool(buf, value); - } - - function writeKVNull( - CBORBuffer memory buf, - string memory key - ) internal pure { - writeString(buf, key); - writeNull(buf); - } - - function writeKVUndefined( - CBORBuffer memory buf, - string memory key - ) internal pure { - writeString(buf, key); - writeUndefined(buf); - } - - function writeKVMap( - CBORBuffer memory buf, - string memory key - ) internal pure { - writeString(buf, key); - startMap(buf); - } - - function writeKVArray( - CBORBuffer memory buf, - string memory key - ) internal pure { - writeString(buf, key); - startArray(buf); - } - - function writeFixedNumeric( - CBORBuffer memory buf, - uint8 major, - uint64 value - ) private pure { - if (value <= 23) { - buf.buf.appendUint8(uint8((major << 5) | value)); - } else if (value <= 0xFF) { - buf.buf.appendUint8(uint8((major << 5) | 24)); - buf.buf.appendInt(value, 1); - } else if (value <= 0xFFFF) { - buf.buf.appendUint8(uint8((major << 5) | 25)); - buf.buf.appendInt(value, 2); - } else if (value <= 0xFFFFFFFF) { - buf.buf.appendUint8(uint8((major << 5) | 26)); - buf.buf.appendInt(value, 4); - } else { - buf.buf.appendUint8(uint8((major << 5) | 27)); - buf.buf.appendInt(value, 8); - } - } - - function writeIndefiniteLengthType( - CBORBuffer memory buf, - uint8 major - ) private pure { - buf.buf.appendUint8(uint8((major << 5) | 31)); - } - - function writeDefiniteLengthType( - CBORBuffer memory buf, - uint8 major, - uint64 length - ) private pure { - writeFixedNumeric(buf, major, length); - } - - function writeContentFree(CBORBuffer memory buf, uint8 value) private pure { - buf.buf.appendUint8(uint8((MAJOR_TYPE_CONTENT_FREE << 5) | value)); - } -} diff --git a/contracts/ethereum/test/fixtures/shared.ts b/contracts/ethereum/test/fixtures/shared.ts index 928381d10..9a9d76258 100644 --- a/contracts/ethereum/test/fixtures/shared.ts +++ b/contracts/ethereum/test/fixtures/shared.ts @@ -1,8 +1,8 @@ import { ethers } from 'hardhat' import { loadFixture } from '@nomicfoundation/hardhat-network-helpers' -import { deployContract } from '@casimir/hardhat' -import { CasimirManager, CasimirAutomation, MockFunctionsOracle } from '../../build/artifacts/types' -import { fulfillOracleAnswer, runUpkeep } from '../helpers/automation' +import { deployContract } from '@casimir/ethereum/helpers/deploy' +import { CasimirManager, CasimirUpkeep, MockFunctionsOracle } from '@casimir/ethereum/build/artifacts/types' +import { fulfillOracleAnswer, runUpkeep } from '@casimir/ethereum/helpers/upkeep' import { ContractConfig, DeploymentConfig, Validator } from '@casimir/types' import { validatorStore } from '@casimir/data' @@ -72,17 +72,17 @@ export async function deploymentFixture() { if (name === 'MockFunctionsOracle') mockFunctionsOracle = contract as MockFunctionsOracle } - const automationAddress = await manager?.getAutomationAddress() as string - const automation = await ethers.getContractAt('CasimirAutomation', automationAddress) as CasimirAutomation + const upkeepAddress = await manager?.getUpkeepAddress() as string + const upkeep = await ethers.getContractAt('CasimirUpkeep', upkeepAddress) as CasimirUpkeep - return { manager: manager as CasimirManager, automation: automation as CasimirAutomation, mockFunctionsOracle, owner, chainlink } + return { manager: manager as CasimirManager, upkeep: upkeep as CasimirUpkeep, mockFunctionsOracle, owner, chainlink } } /** Fixture to add validators */ export async function registerValidatorsFixture() { - const { manager, automation, mockFunctionsOracle, owner, chainlink } = await loadFixture(deploymentFixture) + const { manager, upkeep, mockFunctionsOracle, owner, chainlink } = await loadFixture(deploymentFixture) - const validators = Object.keys(validatorStore).map((key) => validatorStore[key]) as Validator[] + const validators = Object.keys(validatorStore).map((key) => validatorStore[key as keyof typeof validatorStore]) as Validator[] for (const validator of validators) { const { depositDataRoot, @@ -104,12 +104,12 @@ export async function registerValidatorsFixture() { ) await registerValidator.wait() } - return { manager, automation, mockFunctionsOracle, owner, chainlink, validators } + return { manager, upkeep, mockFunctionsOracle, owner, chainlink, validators } } /** Fixture to stake 16 ETH for the first user */ export async function firstUserDepositFixture() { - const { manager, automation, mockFunctionsOracle, owner, chainlink } = await loadFixture(registerValidatorsFixture) + const { manager, upkeep, mockFunctionsOracle, owner, chainlink } = await loadFixture(registerValidatorsFixture) const [, firstUser] = await ethers.getSigners() const stakeAmount = 16 @@ -122,20 +122,22 @@ export async function firstUserDepositFixture() { await deposit.wait() /** Run upkeep */ - await runUpkeep(automation, chainlink) + await runUpkeep({ upkeep, chainlink }) - return { manager, automation, mockFunctionsOracle, owner, chainlink, firstUser } + return { manager, upkeep, mockFunctionsOracle, owner, chainlink, firstUser } } /** Fixture to stake 24 ETH for the second user */ export async function secondUserDepositFixture() { - const { manager, automation, mockFunctionsOracle, owner, chainlink, firstUser } = await loadFixture(firstUserDepositFixture) + const { manager, upkeep, mockFunctionsOracle, owner, chainlink, firstUser } = await loadFixture(firstUserDepositFixture) const [, , secondUser] = await ethers.getSigners() const stakeAmount = 24 const nextActiveStakeAmount = 32 const nextSweptRewardsAmount = 0 const nextSweptExitsAmount = 0 + const nextDepositedCount = 1 + const nextExitedCount = 0 const fees = { ...await manager.getFees() } const feePercent = fees.LINK + fees.SSV @@ -145,67 +147,74 @@ export async function secondUserDepositFixture() { await deposit.wait() /** Run upkeep */ - const ranUpkeep = await runUpkeep(automation, chainlink) + const ranUpkeep = await runUpkeep({ upkeep, chainlink }) /** Fulfill oracle answer */ if (ranUpkeep) { - await fulfillOracleAnswer(automation, chainlink, nextActiveStakeAmount, nextSweptRewardsAmount, nextSweptExitsAmount) + await fulfillOracleAnswer({ upkeep, chainlink, nextActiveStakeAmount, nextSweptRewardsAmount, nextSweptExitsAmount, nextDepositedCount, nextExitedCount }) } - return { manager, automation, mockFunctionsOracle, owner, chainlink, firstUser, secondUser } + return { manager, upkeep, mockFunctionsOracle, owner, chainlink, firstUser, secondUser } } /** Fixture to reward 0.1 ETH in total to the first and second user */ export async function rewardPostSecondUserDepositFixture() { - const { manager, automation, mockFunctionsOracle, owner, chainlink, firstUser, secondUser } = await loadFixture(secondUserDepositFixture) + const { manager, upkeep, mockFunctionsOracle, owner, chainlink, firstUser, secondUser } = await loadFixture(secondUserDepositFixture) const rewardAmount = 0.1 const nextActiveStakeAmount = 32 + rewardAmount const nextSweptRewardsAmount = 0 const nextSweptExitsAmount = 0 + const nextDepositedCount = 0 + const nextExitedCount = 0 /** Run upkeep */ - const ranUpkeep = await runUpkeep(automation, chainlink) + const ranUpkeep = await runUpkeep({ upkeep, chainlink }) /** Fulfill oracle answer */ if (ranUpkeep) { - await fulfillOracleAnswer(automation, chainlink, nextActiveStakeAmount, nextSweptRewardsAmount, nextSweptExitsAmount) + await fulfillOracleAnswer({ upkeep, chainlink, nextActiveStakeAmount, nextSweptRewardsAmount, nextSweptExitsAmount, nextDepositedCount, nextExitedCount }) } - return { manager, automation, mockFunctionsOracle, owner, chainlink, firstUser, secondUser } + return { manager, upkeep, mockFunctionsOracle, owner, chainlink, firstUser, secondUser } } /** Fixture to sweep 0.1 ETH to the manager */ export async function sweepPostSecondUserDepositFixture() { - const { manager, automation, mockFunctionsOracle, owner, chainlink, firstUser, secondUser } = await loadFixture(secondUserDepositFixture) + const { manager, upkeep, mockFunctionsOracle, owner, chainlink, firstUser, secondUser } = await loadFixture(secondUserDepositFixture) + + const sweptRewards = 0.1 + const sweep = await chainlink.sendTransaction({ to: manager?.address, value: ethers.utils.parseEther(sweptRewards.toString()) }) + await sweep.wait() const nextActiveStakeAmount = 32 - const nextSweptRewardsAmount = 0.1 + const nextSweptRewardsAmount = sweptRewards const nextSweptExitsAmount = 0 - - const sweep = await chainlink.sendTransaction({ to: manager?.address, value: ethers.utils.parseEther('0.1') }) - await sweep.wait() + const nextDepositedCount = 0 + const nextExitedCount = 0 /** Run upkeep */ - const ranUpkeep = await runUpkeep(automation, chainlink) + const ranUpkeep = await runUpkeep({ upkeep, chainlink }) /** Fulfill oracle answer */ if (ranUpkeep) { - await fulfillOracleAnswer(automation, chainlink, nextActiveStakeAmount, nextSweptRewardsAmount, nextSweptExitsAmount) + await fulfillOracleAnswer({ upkeep, chainlink, nextActiveStakeAmount, nextSweptRewardsAmount, nextSweptExitsAmount, nextDepositedCount, nextExitedCount }) } - return { manager, automation, mockFunctionsOracle, owner, chainlink, firstUser, secondUser } + return { manager, upkeep, mockFunctionsOracle, owner, chainlink, firstUser, secondUser } } /** Fixture to stake 24 ETH for the third user */ export async function thirdUserDepositFixture() { - const { manager, automation, mockFunctionsOracle, owner, chainlink, firstUser, secondUser } = await loadFixture(sweepPostSecondUserDepositFixture) + const { manager, upkeep, mockFunctionsOracle, owner, chainlink, firstUser, secondUser } = await loadFixture(sweepPostSecondUserDepositFixture) const [, , , thirdUser] = await ethers.getSigners() const stakeAmount = 24 const nextActiveStakeAmount = 64 const nextSweptRewardsAmount = 0 const nextSweptExitsAmount = 0 + const nextDepositedCount = 1 + const nextExitedCount = 0 const fees = { ...await manager.getFees() } const feePercent = fees.LINK + fees.SSV @@ -215,81 +224,87 @@ export async function thirdUserDepositFixture() { await deposit.wait() /** Run upkeep */ - const ranUpkeep = await runUpkeep(automation, chainlink) + const ranUpkeep = await runUpkeep({ upkeep, chainlink }) /** Fulfill oracle answer */ if (ranUpkeep) { - await fulfillOracleAnswer(automation, chainlink, nextActiveStakeAmount, nextSweptRewardsAmount, nextSweptExitsAmount) + await fulfillOracleAnswer({ upkeep, chainlink, nextActiveStakeAmount, nextSweptRewardsAmount, nextSweptExitsAmount, nextDepositedCount, nextExitedCount }) } - return { manager, automation, mockFunctionsOracle, owner, chainlink, firstUser, secondUser, thirdUser } + return { manager, upkeep, mockFunctionsOracle, owner, chainlink, firstUser, secondUser, thirdUser } } /** Fixture to reward 0.2 ETH in total to the first, second, and third user */ export async function rewardPostThirdUserDepositFixture() { - const { manager, automation, mockFunctionsOracle, owner, chainlink, firstUser, secondUser, thirdUser } = await loadFixture(thirdUserDepositFixture) + const { manager, upkeep, mockFunctionsOracle, owner, chainlink, firstUser, secondUser, thirdUser } = await loadFixture(thirdUserDepositFixture) const rewardAmount = 0.2 const nextActiveStakeAmount = 64 + rewardAmount const nextSweptRewardsAmount = 0 const nextSweptExitsAmount = 0 + const nextDepositedCount = 0 + const nextExitedCount = 0 /** Run upkeep */ - const ranUpkeep = await runUpkeep(automation, chainlink) + const ranUpkeep = await runUpkeep({ upkeep, chainlink }) /** Fulfill oracle answer */ if (ranUpkeep) { - await fulfillOracleAnswer(automation, chainlink, nextActiveStakeAmount, nextSweptRewardsAmount, nextSweptExitsAmount) + await fulfillOracleAnswer({ upkeep, chainlink, nextActiveStakeAmount, nextSweptRewardsAmount, nextSweptExitsAmount, nextDepositedCount, nextExitedCount }) } - return { manager, automation, mockFunctionsOracle, owner, chainlink, firstUser, secondUser, thirdUser } + return { manager, upkeep, mockFunctionsOracle, owner, chainlink, firstUser, secondUser, thirdUser } } /** Fixture to sweep 0.2 ETH to the manager */ export async function sweepPostThirdUserDepositFixture() { - const { manager, automation, mockFunctionsOracle, owner, chainlink, firstUser, secondUser, thirdUser } = await loadFixture(rewardPostThirdUserDepositFixture) + const { manager, upkeep, mockFunctionsOracle, owner, chainlink, firstUser, secondUser, thirdUser } = await loadFixture(rewardPostThirdUserDepositFixture) + + const sweptRewards = 0.2 + const sweep = await chainlink.sendTransaction({ to: manager?.address, value: ethers.utils.parseEther(sweptRewards.toString()) }) + await sweep.wait() const nextActiveStakeAmount = 64 - const nextSweptRewardsAmount = 0.2 + const nextSweptRewardsAmount = sweptRewards const nextSweptExitsAmount = 0 - - /** Sweep rewards before upkeep (balance will increment silently) */ - const sweep = await chainlink.sendTransaction({ to: manager?.address, value: ethers.utils.parseEther(nextSweptRewardsAmount.toString()) }) - await sweep.wait() + const nextDepositedCount = 0 + const nextExitedCount = 0 /** Run upkeep */ - const ranUpkeep = await runUpkeep(automation, chainlink) + const ranUpkeep = await runUpkeep({ upkeep, chainlink }) /** Fulfill oracle answer */ if (ranUpkeep) { - await fulfillOracleAnswer(automation, chainlink, nextActiveStakeAmount, nextSweptRewardsAmount, nextSweptExitsAmount) + await fulfillOracleAnswer({ upkeep, chainlink, nextActiveStakeAmount, nextSweptRewardsAmount, nextSweptExitsAmount, nextDepositedCount, nextExitedCount }) } - return { manager, automation, mockFunctionsOracle, owner, chainlink, firstUser, secondUser, thirdUser } + return { manager, upkeep, mockFunctionsOracle, owner, chainlink, firstUser, secondUser, thirdUser } } /** Fixture to withdraw 0.3 to the first user */ export async function firstUserPartialWithdrawalFixture() { - const { manager, automation, mockFunctionsOracle, chainlink, firstUser, secondUser, thirdUser } = await loadFixture(sweepPostThirdUserDepositFixture) + const { manager, upkeep, mockFunctionsOracle, chainlink, firstUser, secondUser, thirdUser } = await loadFixture(sweepPostThirdUserDepositFixture) const openDeposits = await manager?.getOpenDeposits() const withdraw = await manager.connect(firstUser).requestWithdrawal(openDeposits) await withdraw.wait() /** Run upkeep */ - await runUpkeep(automation, chainlink) + await runUpkeep({ upkeep, chainlink }) - return { manager, automation, mockFunctionsOracle, chainlink, firstUser, secondUser, thirdUser } + return { manager, upkeep, mockFunctionsOracle, chainlink, firstUser, secondUser, thirdUser } } /** Fixture to stake 72 for the fourth user */ export async function fourthUserDepositFixture() { - const { manager, automation, mockFunctionsOracle, chainlink, firstUser, secondUser, thirdUser } = await loadFixture(firstUserPartialWithdrawalFixture) + const { manager, upkeep, mockFunctionsOracle, chainlink, firstUser, secondUser, thirdUser } = await loadFixture(firstUserPartialWithdrawalFixture) const [, , , , fourthUser] = await ethers.getSigners() const stakeAmount = 72 const nextActiveStakeAmount = 128 const nextSweptRewardsAmount = 0 const nextSweptExitsAmount = 0 + const nextDepositedCount = 2 + const nextExitedCount = 0 const fees = { ...await manager.getFees() } const feePercent = fees.LINK + fees.SSV @@ -299,19 +314,19 @@ export async function fourthUserDepositFixture() { await deposit.wait() /** Run upkeep */ - const ranUpkeep = await runUpkeep(automation, chainlink) + const ranUpkeep = await runUpkeep({ upkeep, chainlink }) /** Fulfill oracle answer */ if (ranUpkeep) { - await fulfillOracleAnswer(automation, chainlink, nextActiveStakeAmount, nextSweptRewardsAmount, nextSweptExitsAmount) + await fulfillOracleAnswer({ upkeep, chainlink, nextActiveStakeAmount, nextSweptRewardsAmount, nextSweptExitsAmount, nextDepositedCount, nextExitedCount }) } - return { manager, automation, mockFunctionsOracle, chainlink, firstUser, secondUser, thirdUser, fourthUser } + return { manager, upkeep, mockFunctionsOracle, chainlink, firstUser, secondUser, thirdUser, fourthUser } } /** Fixture to simulate stakes and rewards */ export async function simulationFixture() { - const { manager, automation, mockFunctionsOracle, chainlink, firstUser, secondUser, thirdUser, fourthUser } = await loadFixture(fourthUserDepositFixture) + const { manager, upkeep, mockFunctionsOracle, chainlink, firstUser, secondUser, thirdUser, fourthUser } = await loadFixture(fourthUserDepositFixture) let nextActiveStakeAmount = 128 @@ -322,15 +337,17 @@ export async function simulationFixture() { nextActiveStakeAmount = Math.round((nextActiveStakeAmount + rewardAmount) * 10) / 10 // Fixes weird rounding error const nextSweptRewardsAmount = 0 const nextSweptExitsAmount = 0 + const nextDepositedCount = 0 + const nextExitedCount = 0 /** Run upkeep */ - const ranUpkeep = await runUpkeep(automation, chainlink) + const ranUpkeep = await runUpkeep({ upkeep, chainlink }) /** Fulfill oracle answer */ if (ranUpkeep) { - await fulfillOracleAnswer(automation, chainlink, nextActiveStakeAmount, nextSweptRewardsAmount, nextSweptExitsAmount) + await fulfillOracleAnswer({ upkeep, chainlink, nextActiveStakeAmount, nextSweptRewardsAmount, nextSweptExitsAmount, nextDepositedCount, nextExitedCount }) } } } - return { manager, automation, mockFunctionsOracle, chainlink, firstUser, secondUser, thirdUser, fourthUser } + return { manager, upkeep, mockFunctionsOracle, chainlink, firstUser, secondUser, thirdUser, fourthUser } } \ No newline at end of file diff --git a/contracts/ethereum/test/helpers/automation.ts b/contracts/ethereum/test/helpers/automation.ts deleted file mode 100644 index d04f80b46..000000000 --- a/contracts/ethereum/test/helpers/automation.ts +++ /dev/null @@ -1,31 +0,0 @@ -import { ethers } from 'hardhat' -import { SignerWithAddress } from '@nomiclabs/hardhat-ethers/signers' -import { CasimirManager, CasimirAutomation, MockFunctionsOracle } from '../../build/artifacts/types' - -export async function runUpkeep(automation: CasimirAutomation, chainlink: SignerWithAddress) { - let ranUpkeep = false - const checkData = ethers.utils.toUtf8Bytes('') - const { ...check } = await automation.connect(chainlink).checkUpkeep(checkData) - const { upkeepNeeded, performData } = check - if (upkeepNeeded) { - const performUpkeep = await automation.connect(chainlink).performUpkeep(performData) - await performUpkeep.wait() - ranUpkeep = true - } - return ranUpkeep -} - -export async function fulfillOracleAnswer(automation: CasimirAutomation, chainlink: SignerWithAddress, nextActiveStakeAmount: number, nextSweptRewardsAmount: number, nextSweptExitsAmount: number) { - const requestId = ethers.utils.keccak256(ethers.utils.defaultAbiCoder.encode(['uint256'], [1])) - const responseBytes = ethers.utils.defaultAbiCoder.encode( - ['uint256', 'uint256', 'uint256'], - [ - ethers.utils.parseEther(nextActiveStakeAmount.toString()), - ethers.utils.parseEther(nextSweptRewardsAmount.toString()), - ethers.utils.parseEther(nextSweptExitsAmount.toString()) - ] - ) - const errorBytes = ethers.utils.toUtf8Bytes('') - const mockFulfillRequest = await automation.connect(chainlink).mockFulfillRequest(requestId, responseBytes, errorBytes) - await mockFulfillRequest.wait() -} \ No newline at end of file diff --git a/contracts/ethereum/tsconfig.json b/contracts/ethereum/tsconfig.json index 8c0758972..7756b12a0 100644 --- a/contracts/ethereum/tsconfig.json +++ b/contracts/ethereum/tsconfig.json @@ -10,13 +10,14 @@ "esModuleInterop": true, "skipLibCheck": true, "forceConsistentCasingInFileNames": true, - "isolatedModules": true + "isolatedModules": true, + "resolveJsonModule": true }, "include": [ "scripts/*.ts", "./test/*.ts", "src/index.ts" -, "test/e2e/simulation.ts" ], +, "test/e2e/simulation.ts", "helpers/deploy.ts" ], "typeRoots": [ "node_modules/@types" ], diff --git a/package-lock.json b/package-lock.json index e57683f73..130feb1ca 100644 --- a/package-lock.json +++ b/package-lock.json @@ -90,6 +90,13 @@ "vue-tsc": "^0.34.7" } }, + "common/core": { + "name": "@casimir/core", + "extraneous": true, + "dependencies": { + "ethers": "^5.7.2" + } + }, "common/data": { "name": "@casimir/data", "dependencies": { @@ -123,6 +130,7 @@ }, "common/hardhat": { "name": "@casimir/hardhat", + "extraneous": true, "devDependencies": { "@nomiclabs/hardhat-ethers": "^2.0.6", "@typechain/ethers-v5": "^10.1.0", @@ -133,43 +141,6 @@ "typechain": "^8.1.0" } }, - "common/hardhat/node_modules/esbuild": { - "version": "0.15.18", - "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.15.18.tgz", - "integrity": "sha512-x/R72SmW3sSFRm5zrrIjAhCeQSAWoni3CmHEqfQrZIQTM3lVCdehdwuIqaOtfC2slvpdlLa62GYoN8SxT23m6Q==", - "dev": true, - "hasInstallScript": true, - "bin": { - "esbuild": "bin/esbuild" - }, - "engines": { - "node": ">=12" - }, - "optionalDependencies": { - "@esbuild/android-arm": "0.15.18", - "@esbuild/linux-loong64": "0.15.18", - "esbuild-android-64": "0.15.18", - "esbuild-android-arm64": "0.15.18", - "esbuild-darwin-64": "0.15.18", - "esbuild-darwin-arm64": "0.15.18", - "esbuild-freebsd-64": "0.15.18", - "esbuild-freebsd-arm64": "0.15.18", - "esbuild-linux-32": "0.15.18", - "esbuild-linux-64": "0.15.18", - "esbuild-linux-arm": "0.15.18", - "esbuild-linux-arm64": "0.15.18", - "esbuild-linux-mips64le": "0.15.18", - "esbuild-linux-ppc64le": "0.15.18", - "esbuild-linux-riscv64": "0.15.18", - "esbuild-linux-s390x": "0.15.18", - "esbuild-netbsd-64": "0.15.18", - "esbuild-openbsd-64": "0.15.18", - "esbuild-sunos-64": "0.15.18", - "esbuild-windows-32": "0.15.18", - "esbuild-windows-64": "0.15.18", - "esbuild-windows-arm64": "0.15.18" - } - }, "common/helpers": { "name": "@casimir/helpers", "dependencies": { @@ -242,7 +213,7 @@ "contracts/ethereum": { "name": "@casimir/ethereum", "dependencies": { - "@chainlink/contracts": "^0.5.1", + "@chainlink/contracts": "^0.6.1", "@openzeppelin/contracts": "^4.8.0", "@openzeppelin/contracts-upgradeable": "^4.8.0", "@uniswap/v3-core": "1.0.1", @@ -2022,10 +1993,6 @@ "resolved": "contracts/ethereum", "link": true }, - "node_modules/@casimir/hardhat": { - "resolved": "common/hardhat", - "link": true - }, "node_modules/@casimir/helpers": { "resolved": "common/helpers", "link": true @@ -2059,15 +2026,21 @@ "link": true }, "node_modules/@chainlink/contracts": { - "version": "0.5.1", - "resolved": "https://registry.npmjs.org/@chainlink/contracts/-/contracts-0.5.1.tgz", - "integrity": "sha512-3PDBJ38Sd6Ml9h7FNK/tZQti+kTCdXUq1qzE6E59CnlzycsV9ElPvf2hTvs9Mi9C6pEx2Mmw9yhZMfBktYUInQ==", + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/@chainlink/contracts/-/contracts-0.6.1.tgz", + "integrity": "sha512-EuwijGexttw0UjfrW+HygwhQIrGAbqpf1ue28R55HhWMHBzphEH0PhWm8DQmFfj5OZNy8Io66N4L0nStkZ3QKQ==", "dependencies": { "@eth-optimism/contracts": "^0.5.21", - "@openzeppelin/contracts": "^4.3.3", + "@openzeppelin/contracts": "~4.3.3", + "@openzeppelin/contracts-upgradeable": "^4.7.3", "@openzeppelin/contracts-v0.7": "npm:@openzeppelin/contracts@v3.4.2" } }, + "node_modules/@chainlink/contracts/node_modules/@openzeppelin/contracts": { + "version": "4.3.3", + "resolved": "https://registry.npmjs.org/@openzeppelin/contracts/-/contracts-4.3.3.tgz", + "integrity": "sha512-tDBopO1c98Yk7Cv/PZlHqrvtVjlgK5R4J6jxLwoO7qxK4xqOiZG+zSkIvGFpPZ0ikc3QOED3plgdqjgNTnBc7g==" + }, "node_modules/@cspotcode/source-map-support": { "version": "0.8.1", "resolved": "https://registry.npmjs.org/@cspotcode/source-map-support/-/source-map-support-0.8.1.tgz", @@ -27399,8 +27372,7 @@ "services/keys": { "name": "@casimir/keys", "dependencies": { - "ethers": "^5.7.2", - "minimist": "^1.2.7" + "ethers": "^5.7.2" }, "devDependencies": { "@types/cors": "^2.8.12", diff --git a/scripts/ethereum/dev.ts b/scripts/ethereum/dev.ts index c8b50a896..ccfe8c001 100644 --- a/scripts/ethereum/dev.ts +++ b/scripts/ethereum/dev.ts @@ -15,6 +15,21 @@ import minimist from 'minimist' * - https://hardhat.org/hardhat-network/docs/overview */ void async function () { + /** Chain forks */ + const forks = { + ethereum: { + mainnet: 'mainnet', + testnet: 'goerli' + } + } + + /** Casimir addresses */ + const addresses = { + mainnet: '', + testnet: '0xaaf5751d370d2fD5F1D5642C2f88bbFa67a29301', + local: '0x07E05700CB4E946BA50244e27f01805354cD8eF0' + } + /** Load AWS credentials for configuration */ await loadCredentials() @@ -46,6 +61,14 @@ void async function () { echo(chalk.bgBlackBright('Using ') + chalk.bgBlue(fork) + chalk.bgBlackBright(' ethereum fork at ') + chalk.bgBlue(url)) } + if (mock) { + /** Use local manager address */ + process.env.PUBLIC_MANAGER_ADDRESS = addresses['local'] + } else { + /** Use ${fork} manager address */ + process.env.PUBLIC_MANAGER_ADDRESS = addresses[fork] + } + if (clean) { await $`npm run clean --workspace @casimir/ethereum` } diff --git a/scripts/local/dev.ts b/scripts/local/dev.ts index 40c09cea4..d861323bb 100644 --- a/scripts/local/dev.ts +++ b/scripts/local/dev.ts @@ -100,7 +100,7 @@ void async function () { if (network) { /** Use ${network} manager address */ - process.env.CASIMIR_MANAGER_ADDRESS = addresses[network] + process.env.PUBLIC_MANAGER_ADDRESS = addresses[network] const key = await getSecret(`consensus-networks-${chain}-${network}`) const currency = chain.slice(0, 3) @@ -111,10 +111,10 @@ void async function () { if (mock) { /** Use local manager address */ - process.env.CASIMIR_MANAGER_ADDRESS = addresses['local'] + process.env.PUBLIC_MANAGER_ADDRESS = addresses['local'] } else { /** Use ${fork} manager address */ - process.env.CASIMIR_MANAGER_ADDRESS = addresses[fork] + process.env.PUBLIC_MANAGER_ADDRESS = addresses[fork] } const chainFork = forks[chain][fork] diff --git a/services/keys/package.json b/services/keys/package.json index 4d25367ba..a39a6224f 100644 --- a/services/keys/package.json +++ b/services/keys/package.json @@ -4,12 +4,11 @@ "main": "src/index.ts", "scripts": { "build": "node build.js", - "dev": "npx esno -r dotenv/config scripts/dev.ts", + "dev": "npx esno -r dotenv/config src/index.ts", "test": "jest --config jest.config.js" }, "dependencies": { - "ethers": "^5.7.2", - "minimist": "^1.2.7" + "ethers": "^5.7.2" }, "devDependencies": { "@types/cors": "^2.8.12", diff --git a/services/keys/scripts/dev.ts b/services/keys/scripts/dev.ts index 69a9ebb87..33079fe30 100644 --- a/services/keys/scripts/dev.ts +++ b/services/keys/scripts/dev.ts @@ -1,6 +1,10 @@ import { retryFetch } from '@casimir/helpers' import { $ } from 'zx' +// Todo just start services and import/run the desired command (dev CLI, no prod CLI) + +process.env.PUBLIC_MANAGER_ADDRESS = '0xaaf5751d370d2fD5F1D5642C2f88bbFa67a29301' + void async function () { await $`npx esno -r dotenv/config src/index.ts help`