Skip to content

Commit

Permalink
add new error DUPLICATE_DEPOSIT_DATA (#15)
Browse files Browse the repository at this point in the history
* add new error DUPLICATE_DEPOSIT_DATA

* add getVaultInfo, improve logic
  • Loading branch information
dfkadyr authored Sep 17, 2024
1 parent a6d3670 commit e22acc5
Show file tree
Hide file tree
Showing 9 changed files with 57 additions and 17 deletions.
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -80,6 +80,7 @@ self.addEventListener('message', async (event) => {
| `INVALID_JSON_FORMAT` | Deposit data file must be in JSON format
| `MERKLE_TREE_GENERATION_ERROR` | Failed to generate the Merkle tree
| `INVALID_PUBLIC_KEY_FORMAT` | Failed to parse deposit data public key
| `DUPLICATE_DEPOSIT_DATA` | The deposit data file has already been uploaded.
| `INVALID_WITHDRAW_ADDRESS` | The withdrawal addresses don’t match Eigen pods
| `MISSING_FIELDS` | Failed to verify the deposit data public keys. Missing fields: {fields}
| `DUPLICATE_PUBLIC_KEYS` | Failed to verify the deposit data public keys. All the entries must be unique.
Expand Down
21 changes: 20 additions & 1 deletion src/parser/depositDataParser.spec.ts
Original file line number Diff line number Diff line change
@@ -1,9 +1,13 @@
import type { FileItem, SupportedNetworks, ParserInput, ParserOutput } from './types'
import { ErrorTypes, mockData, ParserError } from './helpers'
import { ErrorTypes, mockData, ParserError, requests } from './helpers'
import { networkNames } from './verifySignature'
import { depositDataParser } from './index'


type MockVaultInfo = jest.MockedFunction<typeof requests.getVaultInfo>

jest.mock('./helpers/requests/getVaultInfo')

const testData = mockData[0]

const validInput: ParserInput = {
Expand All @@ -20,6 +24,9 @@ const validOutput: ParserOutput = {
}

describe('depositDataParser',() => {
afterEach(() => {
jest.clearAllMocks()
})

it('processes valid input without throwing errors ', async() => {
await expect(depositDataParser(validInput)).resolves.toEqual(validOutput)
Expand Down Expand Up @@ -95,5 +102,17 @@ describe('depositDataParser',() => {
await expect(depositDataParser({ ...validInput, data: [] })).rejects.toThrow(errorText)
})

it('throws ParserError if the deposit data file has already been uploaded', async () => {

(requests.getVaultInfo as MockVaultInfo).mockResolvedValue({
isRestake: false,
depositDataRoot: '0x406de60516154112c876f7250d8b289d4e3d840074e8cf755922dd5d3c75d1c0',
})

const errorText = new ParserError(ErrorTypes.DUPLICATE_DEPOSIT_DATA)

await expect(depositDataParser(validInput)).rejects.toThrow(errorText)
})

})

1 change: 1 addition & 0 deletions src/parser/getDepositData.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ const { pubkey } = mockData[0]

const mockInput = {
pubkey,
isRestake: false,
vaultAddress: '0x9b6a6867d222d62dc301528190e3984d60adb06b',
}

Expand Down
8 changes: 3 additions & 5 deletions src/parser/getDepositData.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,6 @@ import {
prefix0x,
ErrorTypes,
ParserError,
requests,
getBytes,
getAmount,
getEigenPodAddress,
Expand All @@ -13,17 +12,16 @@ import {

export type DepositDataInput = {
pubkey: string
isRestake: boolean
vaultAddress: string
withdrawalAddress?: string
network: SupportedNetworks
}

const getDepositData = async (values: DepositDataInput): Promise<DepositData> => {
const { pubkey, vaultAddress, withdrawalAddress, network } = values
const { pubkey, vaultAddress, isRestake, withdrawalAddress, network } = values

const isRestakeVault = await requests.checkIsRestakeVault(vaultAddress, network)

const withdrawalCredentialAddress = isRestakeVault
const withdrawalCredentialAddress = isRestake
? await getEigenPodAddress({ vaultAddress, withdrawalAddress, network })
: vaultAddress

Expand Down
8 changes: 7 additions & 1 deletion src/parser/getPostMessage.ts
Original file line number Diff line number Diff line change
@@ -1,22 +1,28 @@
import { StandardMerkleTree } from '@openzeppelin/merkle-tree'

import type { DepositDataFile, ParserOutput } from './types'
import { ParserError, ErrorTypes } from './helpers'


type Input = {
pubkeySet: Set<string>
depositDataRoot: string
treeLeaves: Uint8Array[]
parsedFile: DepositDataFile
}

const getPostMessage = (values: Input) => {
const { pubkeySet, treeLeaves, parsedFile } = values
const { depositDataRoot, pubkeySet, treeLeaves, parsedFile } = values

const merkleTree = StandardMerkleTree.of(
treeLeaves.map((value, index) => [ value, index ]),
[ 'bytes', 'uint256' ]
)

if (depositDataRoot === merkleTree.root) {
throw new ParserError(ErrorTypes.DUPLICATE_DEPOSIT_DATA)
}

const postMessage: ParserOutput = {
merkleRoot: merkleTree.root,
validators: parsedFile?.length || 0,
Expand Down
4 changes: 3 additions & 1 deletion src/parser/helpers/errors.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,12 @@ type DynamicValues = Record<string, any>

export enum ErrorTypes {
EMPTY_FILE = 'EMPTY_FILE',
EIGEN_PODS_EMPTY = 'EIGEN_PODS_EMPTY',
MISSING_FIELDS = 'MISSING_FIELDS',
EIGEN_PODS_EMPTY = 'EIGEN_PODS_EMPTY',
INVALID_SIGNATURE = 'INVALID_SIGNATURE',
INVALID_JSON_FORMAT = 'INVALID_JSON_FORMAT',
DUPLICATE_PUBLIC_KEYS = 'DUPLICATE_PUBLIC_KEYS',
DUPLICATE_DEPOSIT_DATA = 'DUPLICATE_DEPOSIT_DATA',
INVALID_WITHDRAW_ADDRESS = 'INVALID_WITHDRAW_ADDRESS',
INVALID_PUBLIC_KEY_FORMAT = 'INVALID_PUBLIC_KEY_FORMAT',
MERKLE_TREE_GENERATION_ERROR = 'MERKLE_TREE_GENERATION_ERROR',
Expand All @@ -18,6 +19,7 @@ export const ErrorMessages: Record<ErrorTypes, string> = {
[ErrorTypes.INVALID_JSON_FORMAT]: 'Deposit data file must be in JSON format.',
[ErrorTypes.MERKLE_TREE_GENERATION_ERROR]: 'Failed to generate the Merkle tree',
[ErrorTypes.INVALID_PUBLIC_KEY_FORMAT]: 'Failed to parse deposit data public key',
[ErrorTypes.DUPLICATE_DEPOSIT_DATA]: `The deposit data file has already been uploaded.`,
[ErrorTypes.INVALID_WITHDRAW_ADDRESS]: `The withdrawal addresses don’t match Eigen pods`,
[ErrorTypes.MISSING_FIELDS]: 'Failed to verify the deposit data public keys. Missing fields: {fields}',
[ErrorTypes.DUPLICATE_PUBLIC_KEYS]: 'Failed to verify the deposit data public keys. All the entries must be unique.',
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,19 +2,20 @@ import gqlRequest from './gqlRequest'
import { SupportedNetworks } from '../../types'


const checkIsRestakeVault = async (vaultId: string, network: SupportedNetworks) => {
const query = `query Vault($vaultId: ID!) { vault(id: $vaultId) { isRestake }}`
const getVaultInfo = async (vaultId: string, network: SupportedNetworks) => {
const query = `query Vault($vaultId: ID!) { vault(id: $vaultId) { isRestake depositDataRoot }}`

const variables = { vaultId: vaultId.toLowerCase() }

try {
const data = await gqlRequest({ query, variables }, network)

return data?.vault?.isRestake
return data?.vault
}
catch (error) {
console.error('Error fetching isRestake:', error)
console.error('Error fetching Vault info:', error)
}
}


export default checkIsRestakeVault
export default getVaultInfo
2 changes: 1 addition & 1 deletion src/parser/helpers/requests/index.ts
Original file line number Diff line number Diff line change
@@ -1,2 +1,2 @@
export { default as getEigenPods } from './getEigenPods'
export { default as checkIsRestakeVault } from './checkIsRestakeVault'
export { default as getVaultInfo } from './getVaultInfo'
18 changes: 15 additions & 3 deletions src/parser/index.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { ParserError, ErrorTypes } from './helpers'
import { ParserError, ErrorTypes, requests } from './helpers'

import initBls from './initBls'
import getTreeLeaf from './getTreeLeaf'
Expand All @@ -19,13 +19,20 @@ export const depositDataParser = async (input: ParserInput) => {
const pubkeySet = new Set<string>()
const treeLeaves: Uint8Array[] = []

const vaultInfo = await requests.getVaultInfo(vaultAddress, network)

for (let index = 0; index < parsedFile.length; index++) {
const item = parsedFile[index]
const { pubkey, signature, withdrawal_address } = item

validateFields({ item })

const depositData = await getDepositData({ pubkey, vaultAddress, withdrawalAddress: withdrawal_address, network })
const depositData = await getDepositData({
network,
pubkey, vaultAddress,
isRestake: vaultInfo?.isRestake,
withdrawalAddress: withdrawal_address,
})

verifySignature({ bls, pubkey, signature, depositData, network })

Expand All @@ -46,5 +53,10 @@ export const depositDataParser = async (input: ParserInput) => {
throw new ParserError(ErrorTypes.DUPLICATE_PUBLIC_KEYS)
}

return getPostMessage({ pubkeySet, parsedFile, treeLeaves })
return getPostMessage({
pubkeySet,
parsedFile,
treeLeaves,
depositDataRoot: vaultInfo?.depositDataRoot,
})
}

0 comments on commit e22acc5

Please sign in to comment.