Skip to content

Commit

Permalink
Build SSV network views contract ABI
Browse files Browse the repository at this point in the history
  • Loading branch information
shanejearley committed Jun 1, 2023
1 parent 8fe953d commit b509ff0
Show file tree
Hide file tree
Showing 14 changed files with 128 additions and 62 deletions.
7 changes: 5 additions & 2 deletions common/ssv/src/interfaces/ClusterDetailsInput.ts
Original file line number Diff line number Diff line change
@@ -1,12 +1,15 @@
import { CasimirManager } from '@casimir/ethereum/build/artifacts/types'
import { ethers } from 'ethers'

export interface ClusterDetailsInput {
/** JSON RPC node provider */
provider: ethers.providers.JsonRpcProvider
/** SSV network address */
networkAddress: string
/** SSV network views address */
networkViewsAddress: string
/** Operator IDs */
operatorIds: number[]
/** JSON RPC node provider */
provider: ethers.providers.JsonRpcProvider
/** Withdrawal address */
withdrawalAddress: string
}
23 changes: 17 additions & 6 deletions common/ssv/src/providers/clusters.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
import { ethers } from 'ethers'
import { SSVNetwork, SSVNetworkViews } from '@casimir/ethereum/build/artifacts/types'
import SSVNetworkJson from '@casimir/ethereum/build/artifacts/scripts/resources/ssv-network/contracts/SSVNetwork.sol/SSVNetwork.json'
import SSVNetworkJsonViews from '@casimir/ethereum/build/artifacts/scripts/resources/ssv-network/contracts/SSVNetworkViews.sol/SSVNetworkViews.json'
import { ClusterDetailsInput } from '../interfaces/ClusterDetailsInput'
import { ClusterDetails } from '../interfaces/ClusterDetails'
import { Cluster } from '@casimir/types'
Expand All @@ -22,10 +24,12 @@ const eventList = [
* @returns {Promise<Cluster>} Cluster snapshot
*/
export async function getClusterDetails(input: ClusterDetailsInput): Promise<ClusterDetails> {
const { provider, networkAddress, operatorIds, withdrawalAddress } = input
const { provider, networkAddress, networkViewsAddress, operatorIds, withdrawalAddress } = input

const ssv = new ethers.Contract(networkAddress, SSVNetworkJson.abi, provider)
const eventFilters = eventList.map(event => ssv.filters[event](withdrawalAddress))
const ssvNetwork = new ethers.Contract(networkAddress, SSVNetworkJson.abi, provider) as SSVNetwork & ethers.Contract
const ssvNetworkViews = new ethers.Contract(networkViewsAddress, SSVNetworkJsonViews.abi, provider) as SSVNetworkViews & ethers.Contract

const eventFilters = eventList.map(event => ssvNetwork.filters[event](withdrawalAddress))

let step = MONTH
const latestBlockNumber = await provider.getBlockNumber()
Expand All @@ -38,7 +42,7 @@ export async function getClusterDetails(input: ClusterDetailsInput): Promise<Clu
try {
const items = (await Promise.all(
eventFilters.map(async eventFilter => {
return await ssv.queryFilter(eventFilter, fromBlock, toBlock)
return await ssvNetwork.queryFilter(eventFilter, fromBlock, toBlock)
})
)).flat()

Expand Down Expand Up @@ -68,8 +72,8 @@ export async function getClusterDetails(input: ClusterDetailsInput): Promise<Clu
}
}
toBlock = fromBlock
} catch (e) {
console.error(e)
} catch (error) {
console.error(error)
if (step === MONTH) {
step = WEEK
} else if (step === WEEK) {
Expand All @@ -86,6 +90,13 @@ export async function getClusterDetails(input: ClusterDetailsInput): Promise<Clu
balance: 0,
active: true
}

// let requiredFees
// if (cluster.validatorCount) {
// // Can also top off cluster here
// }
// // Get a minimum runway for the next validator

const requiredFees = ethers.utils.parseEther('0.1')

return { cluster, requiredFees }
Expand Down
2 changes: 2 additions & 0 deletions contracts/ethereum/hardhat.config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@ const externalEnv = {
FUNCTIONS_SUBSCRIPTION_ID: '1',
LINK_TOKEN_ADDRESS: '0x514910771AF9Ca656af840dff83E8264EcF986CA',
SSV_NETWORK_ADDRESS: '0x0000000000000000000000000000000000000000',
SSV_NETWORK_VIEWS_ADDRESS: '0x8dB45282d7C4559fd093C26f677B3837a5598914',
SSV_TOKEN_ADDRESS: '0x9D65fF81a3c488d585bBfb0Bfe3c7707c7917f54',
SWAP_FACTORY_ADDRESS: '0x1F98431c8aD98523631AE4a59f267346ea31F984',
SWAP_ROUTER_ADDRESS: '0xE592427A0AEce92De3Edee1F18E0157C05861564',
Expand All @@ -43,6 +44,7 @@ const externalEnv = {
FUNCTIONS_SUBSCRIPTION_ID: '1',
LINK_TOKEN_ADDRESS: '0x326C977E6efc84E512bB9C30f76E30c160eD06FB',
SSV_NETWORK_ADDRESS: '0xAfdb141Dd99b5a101065f40e3D7636262dce65b3',
SSV_NETWORK_VIEWS_ADDRESS: '0x8dB45282d7C4559fd093C26f677B3837a5598914',
SSV_TOKEN_ADDRESS: '0x3a9f01091C446bdE031E39ea8354647AFef091E7',
SWAP_FACTORY_ADDRESS: '0x1F98431c8aD98523631AE4a59f267346ea31F984',
SWAP_ROUTER_ADDRESS: '0xE592427A0AEce92De3Edee1F18E0157C05861564',
Expand Down
40 changes: 19 additions & 21 deletions contracts/ethereum/helpers/oracle.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,11 +4,12 @@ import { CasimirManager } from '../build/artifacts/types'
import { validatorStore } from '@casimir/data'
import { Validator } from '@casimir/types'
import { getClusterDetails } from '@casimir/ssv'
import { ClusterDetails } from '@casimir/ssv/src/interfaces/ClusterDetails'

const mockValidators: Validator[] = Object.values(validatorStore)

const mockFee = 0.1
const networkAddress = process.env.SSV_NETWORK_ADDRESS as string
if (!networkAddress) throw new Error('No network address provided')
const networkViewsAddress = process.env.SSV_NETWORK_VIEWS_ADDRESS as string
if (!networkViewsAddress) throw new Error('No network views address provided')

export async function initiatePoolDepositHandler({ manager, signer, args }: { manager: CasimirManager, signer: SignerWithAddress, args: Record<string, any> }) {
const { poolId } = args
Expand All @@ -22,22 +23,14 @@ export async function initiatePoolDepositHandler({ manager, signer, args }: { ma
shares,
} = mockValidators[poolId - 1]

let clusterDetails: ClusterDetails = {
cluster: {
validatorCount: 0,
networkFeeIndex: 0,
index: 0,
balance: 0,
active: true
},
requiredFees: ethers.utils.parseEther(mockFee.toString())
}

if (poolId !== 1) {
const networkAddress = await manager.getSSVNetworkAddress()
const withdrawalAddress = manager.address
clusterDetails = await getClusterDetails({ provider: ethers.provider, networkAddress, operatorIds, withdrawalAddress })
}
const withdrawalAddress = manager.address
const clusterDetails = await getClusterDetails({
provider: ethers.provider,
networkAddress,
networkViewsAddress,
operatorIds,
withdrawalAddress
})

const { cluster, requiredFees } = clusterDetails

Expand All @@ -63,9 +56,14 @@ export async function completePoolExitHandler({ manager, signer }: { manager: Ca
const finalEffectiveBalance = ethers.utils.parseEther('32')
const blamePercents = [0, 0, 0, 0]

const networkAddress = await manager.getSSVNetworkAddress()
const withdrawalAddress = manager.address
const clusterDetails = await getClusterDetails({ provider: ethers.provider, networkAddress, operatorIds, withdrawalAddress })
const clusterDetails = await getClusterDetails({
provider: ethers.provider,
networkAddress,
networkViewsAddress,
operatorIds,
withdrawalAddress
})
const { cluster } = clusterDetails

const completePoolExit = await manager.connect(signer).completePoolExit(
Expand Down
5 changes: 3 additions & 2 deletions contracts/ethereum/scripts/dev.ts
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,7 @@ void async function () {

/** Link mock external contracts to Casimir */
if (name === 'CasimirManager') {
(config[name as keyof typeof config] as ContractConfig).args.functionsOracleAddress = config.MockFunctionsOracle?.address
(config[name as keyof typeof config] as ContractConfig).args.functionsAddress = config.MockFunctionsOracle?.address
}

const { args, options, proxy } = config[name as keyof typeof config] as ContractConfig
Expand Down Expand Up @@ -79,7 +79,8 @@ void async function () {
const rewardPerValidator = 0.105
let lastRewardBlock = await ethers.provider.getBlockNumber()
for await (const block of on(ethers.provider as unknown as EventEmitter, 'block')) {
if (block - blocksPerReward === lastRewardBlock) {
if (block - blocksPerReward >= lastRewardBlock) {
console.log('New reward block')
lastRewardBlock = block
const depositedPoolCount = await manager.getDepositedPoolCount()
if (depositedPoolCount) {
Expand Down
12 changes: 0 additions & 12 deletions contracts/ethereum/src/CasimirManager.sol
Original file line number Diff line number Diff line change
Expand Up @@ -1069,18 +1069,6 @@ contract CasimirManager is ICasimirManager, Ownable, ReentrancyGuard {
return ssvFeePercent;
}

/**
* @notice Get the SSV network address
* @return ssvNetworkAddress The SSV network address
*/
function getSSVNetworkAddress()
external
view
returns (address ssvNetworkAddress)
{
ssvNetworkAddress = address(ssvNetwork);
}

/**
* @notice Get the upkeep address
* @return upkeepAddress The upkeep address
Expand Down
4 changes: 4 additions & 0 deletions contracts/ethereum/src/vendor/SSVNetwork.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
// SPDX-License-Identifier: GPL-3.0-or-later
pragma solidity 0.8.18;

import "../../scripts/resources/ssv-network/contracts/SSVNetwork.sol";
4 changes: 4 additions & 0 deletions contracts/ethereum/src/vendor/SSVNetworkViews.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
// SPDX-License-Identifier: GPL-3.0-or-later
pragma solidity 0.8.18;

import "../../scripts/resources/ssv-network/contracts/SSVNetworkViews.sol";
2 changes: 2 additions & 0 deletions services/oracle/scripts/dev.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,8 @@ const resourcePath = 'scripts/resources/rockx-dkg-cli'
void async function () {
process.env.BIP39_PATH_INDEX = '6'
process.env.MANAGER_ADDRESS = process.env.PUBLIC_MANAGER_ADDRESS
process.env.NETWORK_ADDRESS = '0xAfdb141Dd99b5a101065f40e3D7636262dce65b3'
process.env.NETWORK_VIEWS_ADDRESS = '0x8dB45282d7C4559fd093C26f677B3837a5598914'
process.env.CLI_PATH = `./${resourcePath}/build/bin/rockx-dkg-cli`
process.env.MESSENGER_SRV_ADDR = 'http://0.0.0.0:3000'
process.env.USE_HARDCODED_OPERATORS = 'true'
Expand Down
23 changes: 16 additions & 7 deletions services/oracle/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,21 +5,30 @@ import { initiatePoolDepositHandler, initiatePoolExitHandler, initiatePoolReshar
const handlers = {
PoolDepositRequested: initiatePoolDepositHandler,
PoolReshareRequested: initiatePoolReshareHandler,
PoolExitRequested: initiatePoolExitHandler
PoolExitRequested: initiatePoolExitHandler,
// PoolUnexpectedExitReportsRequested: reportUnexpectedExitsHandler,
// PoolSlashedExitReportsRequested: reportSlashedExitsHandler,
// PoolWithdrawnExitReportsRequested: reportWithdrawnExitsHandler
}

const { provider, signer, manager, cliPath, messengerUrl } = config()
const { provider, signer, manager, networkAddress, networkViewsAddress, cliPath, messengerUrl } = config()

;(async function () {
const eventEmitter = getEventEmitter({ manager, events: Object.keys(handlers) })
for await (const event of eventEmitter) {
const [ id, details ] = event

console.log(`Event ${details.event} received for pool ${id}`)

const [ value, details ] = event
const handler = handlers[details.event as keyof typeof handlers]
if (!handler) throw new Error(`No handler found for event ${details.event}`)
await handler({ provider, signer, manager, cliPath, messengerUrl, args: { poolId: id } })
await handler({
provider,
signer,
manager,
networkAddress,
networkViewsAddress,
cliPath,
messengerUrl,
value
})
}
})()

8 changes: 6 additions & 2 deletions services/oracle/src/interfaces/HandlerInput.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,10 +8,14 @@ export interface HandlerInput {
signer: ethers.Signer
/** Manager contract */
manager: CasimirManager & ethers.Contract
/** Network address */
networkAddress: string
/** Network views address */
networkViewsAddress: string
/** DKG cli path */
cliPath: string
/** DKG messenger service URL */
messengerUrl: string
/** Handler args */
args: Record<string, any>
/** Event value */
value: number
}
8 changes: 7 additions & 1 deletion services/oracle/src/providers/config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,12 @@ export function config() {
const managerAddress = process.env.MANAGER_ADDRESS
if (!managerAddress) throw new Error('No manager address provided')
const manager = new ethers.Contract(managerAddress, CasimirManagerJson.abi, provider) as CasimirManager & ethers.Contract

/** Get network contract addresses */
const networkAddress = process.env.NETWORK_ADDRESS
if (!networkAddress) throw new Error('No network address provided')
const networkViewsAddress = process.env.NETWORK_VIEWS_ADDRESS
if (!networkViewsAddress) throw new Error('No network views address provided')

/** Get DKG CLI path */
const cliPath = process.env.CLI_PATH
Expand All @@ -28,5 +34,5 @@ export function config() {
const messengerUrl = process.env.MESSENGER_SRV_ADDR
if (!messengerUrl) throw new Error('No messenger url provided')

return { provider, signer, manager, cliPath, messengerUrl }
return { provider, signer, manager, networkAddress, networkViewsAddress, cliPath, messengerUrl }
}
7 changes: 4 additions & 3 deletions services/oracle/src/providers/dkg.ts
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@ export class DKG {
console.log(`Started ceremony with ID ${ceremonyId}`)

/** Wait for ceremony to complete */
await new Promise(resolve => setTimeout(resolve, 2000))
await new Promise(resolve => setTimeout(resolve, 3000))

/** Get operator key shares */
const shares = await this.getShares(ceremonyId)
Expand Down Expand Up @@ -71,6 +71,9 @@ export class DKG {
const ceremonyId = await this.startReshare({ operators, publicKey, oldOperators })
console.log(`Started ceremony with ID ${ceremonyId}`)

/** Wait for ceremony to complete */
await new Promise(resolve => setTimeout(resolve, 3000))

/** Get operator key shares */
const shares = await this.getShares(ceremonyId)

Expand Down Expand Up @@ -102,8 +105,6 @@ export class DKG {
const withdrawalCredentialsFlag = `--withdrawal-credentials ${getWithdrawalCredentials(withdrawalAddress)}`
const forkVersionFlag = '--fork-version prater'
const command = `${this.cliPath} keygen ${operatorFlags} ${thresholdFlag} ${withdrawalCredentialsFlag} ${forkVersionFlag}`

console.log('Running command', command)
const ceremony = await runRetry(`${command}`) as string
return ceremony.trim().split(' ').pop() as string
}
Expand Down
45 changes: 39 additions & 6 deletions services/oracle/src/providers/handlers.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,18 @@ import { CasimirManager } from '@casimir/ethereum/build/artifacts/types'
import { getClusterDetails } from '@casimir/ssv'

export async function initiatePoolDepositHandler(input: HandlerInput) {
const { provider, signer, manager, cliPath, messengerUrl } = input
const {
provider,
signer,
manager,
networkAddress,
networkViewsAddress,
cliPath,
messengerUrl,
value
} = input

const poolId = value
const newOperatorIds = [1, 2, 3, 4] // Todo get new group here
const dkg = new DKG({ cliPath, messengerUrl })

Expand All @@ -27,7 +38,8 @@ export async function initiatePoolDepositHandler(input: HandlerInput) {

const clusterDetails = await getClusterDetails({
provider,
networkAddress: await manager.getSSVNetworkAddress(),
networkAddress,
networkViewsAddress,
operatorIds,
withdrawalAddress: manager.address
})
Expand All @@ -48,8 +60,19 @@ export async function initiatePoolDepositHandler(input: HandlerInput) {
}

export async function initiatePoolReshareHandler(input: HandlerInput) {
const { manager, signer, cliPath, messengerUrl, args } = input
const { poolId } = args
const {
provider,
signer,
manager,
networkAddress,
networkViewsAddress,
cliPath,
messengerUrl,
value
} = input

const poolId = value

// Todo reshare event will include the operator to boot

// Get pool to reshare
Expand All @@ -76,8 +99,18 @@ export async function initiatePoolReshareHandler(input: HandlerInput) {
}

export async function initiatePoolExitHandler(input: HandlerInput) {
const { manager, signer, cliPath, messengerUrl, args } = input
const { poolId } = args
const {
provider,
signer,
manager,
networkAddress,
networkViewsAddress,
cliPath,
messengerUrl,
value
} = input

const poolId = value

// Get pool to exit
const pool = await manager.getPool(poolId)
Expand Down

0 comments on commit b509ff0

Please sign in to comment.