Skip to content
This repository has been archived by the owner on Apr 26, 2024. It is now read-only.

Commit

Permalink
Merge branch 'main' into L2B-4618/Unify-config
Browse files Browse the repository at this point in the history
  • Loading branch information
maciekop-l2b committed Apr 8, 2024
2 parents a616bd8 + e713fa7 commit a71cfc4
Show file tree
Hide file tree
Showing 11 changed files with 309 additions and 22 deletions.
8 changes: 7 additions & 1 deletion packages/discovery/CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,11 +1,17 @@
# @l2beat/discovery

## 0.46.7
## 0.46.8

### Patch Changes

- Unify var names for discovery config

## 0.46.7

### Patch Changes

- Allow to pick fields from struct returns in CallHandler

## 0.46.6

### Patch Changes
Expand Down
4 changes: 2 additions & 2 deletions packages/discovery/package.json
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
{
"name": "@l2beat/discovery",
"description": "L2Beat discovery - engine & tooling utilized for keeping an eye on L2s",
"version": "0.46.7",
"version": "0.46.8",
"main": "dist/index.js",
"types": "dist/index.d.ts",
"bin": {
Expand Down Expand Up @@ -40,4 +40,4 @@
"@types/lodash": "^4.14.198",
"@types/node-fetch": "^2.6.4"
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ export const ArrayHandlerDefinition = z.strictObject({
length: z.optional(z.union([z.number().int().nonnegative(), Reference])),
maxLength: z.optional(z.number().int().nonnegative()),
startIndex: z.optional(z.number().int().nonnegative()),
filter: z.optional(z.array(z.union([z.string(), z.number()]))),
pickFields: z.optional(z.array(z.union([z.string(), z.number()]))),
ignoreRelative: z.optional(z.boolean()),
})

Expand Down Expand Up @@ -74,7 +74,7 @@ export class ArrayHandler implements ClassicHandler {
address,
this.fragment,
blockNumber,
this.definition.filter,
this.definition.pickFields,
)
if (resolved.indices) {
const results = await Promise.all(
Expand Down Expand Up @@ -136,7 +136,7 @@ function createCallIndex(
address: EthereumAddress,
fragment: utils.FunctionFragment,
blockNumber: number,
filter?: (string | number)[],
pickFields?: (string | number)[],
) {
return async (index: number) => {
return await callMethod(
Expand All @@ -145,7 +145,7 @@ function createCallIndex(
fragment,
[index],
blockNumber,
filter,
pickFields,
)
}
}
Expand Down
2 changes: 2 additions & 0 deletions packages/discovery/src/discovery/handlers/user/CallHandler.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ export const CallHandlerDefinition = z.strictObject({
method: z.optional(z.string()),
args: z.array(z.union([z.string(), z.number()])),
ignoreRelative: z.optional(z.boolean()),
pickFields: z.optional(z.array(z.union([z.string(), z.number()]))),
expectRevert: z.optional(z.boolean()),
})

Expand Down Expand Up @@ -67,6 +68,7 @@ export class CallHandler implements ClassicHandler {
this.fragment,
resolved.args,
blockNumber,
this.definition.pickFields,
)

if (this.definition.expectRevert && callResult.error === EXEC_REVERT_MSG) {
Expand Down
196 changes: 196 additions & 0 deletions packages/discovery/src/discovery/handlers/utils/callMethod.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,196 @@
import { expect, mockObject } from 'earl'
import { utils } from 'ethers'

import { Bytes } from '../../../utils/Bytes'
import { EthereumAddress } from '../../../utils/EthereumAddress'
import { DiscoveryProvider } from '../../provider/DiscoveryProvider'
import { callMethod } from './callMethod'

describe('callMethod', () => {
const ADDRESS = EthereumAddress.random()
const BLOCK_NUMBER = 1234
const encoder = utils.defaultAbiCoder

it('decodes struct returns', async () => {
const RESULT_VALUE = EthereumAddress.random().toString()

const abi = new utils.Interface([
'function testFunction() view returns (tuple(address r1, uint64 r2, address r3, uint64 r4))',
])

const provider = mockObject<DiscoveryProvider>({
call: async () =>
Bytes.fromHex(
encoder.encode(
['tuple(address r1, uint64 r2, address r3, uint64 r4)'],
[[RESULT_VALUE, 1234, RESULT_VALUE, 5678]],
),
),
})

const result = await callMethod(
provider,
ADDRESS,
abi.getFunction('testFunction'),
[],
BLOCK_NUMBER,
['r1', 'r4'],
)

expect(result.value).toEqual([RESULT_VALUE, 5678])
})

it('picks from multiple return values', async () => {
const RESULT_VALUE = EthereumAddress.random().toString()

const abi = new utils.Interface([
'function testFunction() view returns (address r1, uint64 r2, address r3, uint64 r4)',
])

const provider = mockObject<DiscoveryProvider>({
call: async () =>
Bytes.fromHex(
encoder.encode(
['address r1', 'uint64 r2', 'address r3', 'uint64 r4'],
[RESULT_VALUE, 1234, RESULT_VALUE, 5678],
),
),
})

const result = await callMethod(
provider,
ADDRESS,
abi.getFunction('testFunction'),
[],
BLOCK_NUMBER,
['r1', 'r4'],
)

expect(result.value).toEqual([RESULT_VALUE, 5678])
})

it('decodes multiple return values', async () => {
const RESULT_VALUE = EthereumAddress.random().toString()

const abi = new utils.Interface([
'function testFunction() view returns (address r1, uint64 r2, address r3, uint64 r4)',
])

const provider = mockObject<DiscoveryProvider>({
call: async () =>
Bytes.fromHex(
encoder.encode(
['address r1', 'uint64 r2', 'address r3', 'uint64 r4'],
[RESULT_VALUE, 1234, RESULT_VALUE, 5678],
),
),
})

const result = await callMethod(
provider,
ADDRESS,
abi.getFunction('testFunction'),
[],
BLOCK_NUMBER,
)

expect(result.value).toEqual([RESULT_VALUE, 1234, RESULT_VALUE, 5678])
})

it('picks from array return value', async () => {
const RESULT_VALUES = [
EthereumAddress.random().toString(),
EthereumAddress.random().toString(),
]

const abi = new utils.Interface([
'function testFunction() view returns (address[])',
])

const provider = mockObject<DiscoveryProvider>({
call: async () =>
Bytes.fromHex(encoder.encode(['address[]'], [RESULT_VALUES])),
})

const result = await callMethod(
provider,
ADDRESS,
abi.getFunction('testFunction'),
[],
BLOCK_NUMBER,
[1],
)

expect(result.value).toEqual(RESULT_VALUES[1])
})

it('decodes an array return value', async () => {
const RESULT_VALUES = [
EthereumAddress.random().toString(),
EthereumAddress.random().toString(),
]

const abi = new utils.Interface([
'function testFunction() view returns (address[])',
])

const provider = mockObject<DiscoveryProvider>({
call: async () =>
Bytes.fromHex(encoder.encode(['address[]'], [RESULT_VALUES])),
})

const result = await callMethod(
provider,
ADDRESS,
abi.getFunction('testFunction'),
[],
BLOCK_NUMBER,
)

expect(result.value).toEqual(RESULT_VALUES)
})

it('throws on trying to pick from scalar return value', async () => {
const abi = new utils.Interface([
'function testFunction() view returns (uint256)',
])

const provider = mockObject<DiscoveryProvider>({
call: async () => Bytes.randomOfLength(32),
})

const result = await callMethod(
provider,
ADDRESS,
abi.getFunction('testFunction'),
[],
BLOCK_NUMBER,
['field'],
)

expect(result.error).toEqual(
'Cannot pick fields from a non-struct-like return value',
)
})

it('decodes a scalar return value', async () => {
const RETURN_VALUE = EthereumAddress.random()
const abi = new utils.Interface([
'function testFunction() view returns (address)',
])

const provider = mockObject<DiscoveryProvider>({
call: async () => Bytes.fromHex(RETURN_VALUE.toString()).padStart(32),
})

const result = await callMethod(
provider,
ADDRESS,
abi.getFunction('testFunction'),
[],
BLOCK_NUMBER,
)

expect(result.value).toEqual(RETURN_VALUE.toString())
})
})
21 changes: 15 additions & 6 deletions packages/discovery/src/discovery/handlers/utils/callMethod.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ export async function callMethod(
fragment: utils.FunctionFragment,
parameters: unknown[],
blockNumber: number,
filter?: (string | number)[],
pickFields?: (string | number)[],
) {
const abi = new utils.Interface([fragment])

Expand All @@ -25,7 +25,7 @@ export async function callMethod(
const result = await provider.call(address, callData, blockNumber)

return {
value: decodeMethodResult(abi, fragment, result, filter),
value: decodeMethodResult(abi, fragment, result, pickFields),
}
} catch (e) {
return {
Expand All @@ -39,11 +39,20 @@ export function decodeMethodResult(
abi: utils.Interface,
fragment: utils.FunctionFragment,
result: Bytes,
filter?: (string | number)[],
pickFields?: (string | number)[],
) {
const decoded = abi.decodeFunctionResult(fragment, result.toString())
const filtered = filter
? filter.map((i) => decoded[i] as utils.Result)
let decoded = abi.decodeFunctionResult(fragment, result.toString())

if (decoded.length === 1 && Array.isArray(decoded[0])) {
decoded = decoded[0]
}

if (decoded.length === 1 && pickFields !== undefined) {
throw new Error('Cannot pick fields from a non-struct-like return value')
}

const filtered = pickFields
? pickFields.map((i) => decoded[i] as utils.Result)
: decoded
const mapped = filtered.map(toContractValue)
return mapped.length === 1 ? mapped[0] : mapped
Expand Down
10 changes: 10 additions & 0 deletions packages/uif-example/src/prices/PriceIndexer.ts
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,16 @@ export class PriceIndexer extends MultiIndexer<PriceConfig> {
return this.priceIndexerRepository.load(this.indexerId)
}

override async getSafeHeight(): Promise<number | undefined> {
// we don't have a safe height for prices as they don't depend on parent indexers
return Promise.resolve(undefined)
}

override setSafeHeight(_height: number): Promise<void> {
// we don't have a safe height for prices as they don't depend on parent indexers
return Promise.resolve()
}

override async multiUpdate(
from: number,
to: number,
Expand Down
6 changes: 6 additions & 0 deletions packages/uif/CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,11 @@
# @l2beat/uif

## 0.4.0

### Minor Changes

- Add getSafeHeight and setSafeHeight to MultiIndexer

## 0.3.1

### Patch Changes
Expand Down
2 changes: 1 addition & 1 deletion packages/uif/package.json
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
{
"name": "@l2beat/uif",
"description": "Universal Indexer Framework.",
"version": "0.3.1",
"version": "0.4.0",
"license": "MIT",
"repository": "https://github.com/l2beat/tools",
"bugs": {
Expand Down
Loading

0 comments on commit a71cfc4

Please sign in to comment.