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

Commit

Permalink
Properly decode tuple from multicall (#84)
Browse files Browse the repository at this point in the history
  • Loading branch information
michalsidzej authored Oct 26, 2023
1 parent 8e8c35a commit 03a30b1
Show file tree
Hide file tree
Showing 5 changed files with 53 additions and 15 deletions.
6 changes: 6 additions & 0 deletions packages/discovery/CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,11 @@
# @l2beat/discovery

## 0.19.2

### Patch Changes

- Properly decode tuples from multicall

## 0.19.1

### Patch Changes
Expand Down
2 changes: 1 addition & 1 deletion 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.19.1",
"version": "0.19.2",
"main": "dist/index.js",
"types": "dist/index.d.ts",
"bin": {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -135,5 +135,33 @@ describe(SimpleMethodHandler.name, () => {
error: 'Multicall failed',
})
})

it('can correctly decode a tuple', async () => {
const response =
'0x0000000000000000000000000000000000000000000000000000000001312d00000000000000000000000000000000000000000000000000000000000000000a0000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000003b9aca0000000000000000000000000000000000000000000000000000000000000f424000000000000000000000000000000000ffffffffffffffffffffffffffffffff'
const abi =
'function resourceConfig() view returns (tuple(uint32 maxResourceLimit, uint8 elasticityMultiplier, uint8 baseFeeMaxChangeDenominator, uint32 minimumBaseFee, uint32 systemTxMaxGas, uint128 maximumBaseFee))'

const handler = new SimpleMethodHandler(abi, DiscoveryLogger.SILENT)

const decoded = handler.decode([
{
success: true,
data: Bytes.fromHex(response),
},
])

expect(decoded).toEqual({
field: 'resourceConfig',
value: [
20000000,
10,
8,
1000000000,
1000000,
'340282366920938463463374607431768211455',
],
})
})
})
})
Original file line number Diff line number Diff line change
Expand Up @@ -10,8 +10,7 @@ import {
MulticallResponse,
} from '../../provider/multicall/types'
import { HandlerResult, MulticallableHandler } from '../Handler'
import { callMethod } from '../utils/callMethod'
import { toContractValue } from '../utils/toContractValue'
import { callMethod, decodeMethodResult } from '../utils/callMethod'
import { toFunctionFragment } from '../utils/toFunctionFragment'

export class SimpleMethodHandler implements MulticallableHandler {
Expand Down Expand Up @@ -71,17 +70,11 @@ export class SimpleMethodHandler implements MulticallableHandler {
'Decoding from multicall ',
this.fragment.name + '()',
])
const output = this.fragment.outputs?.[0]
const resultType = output?.type
assert(resultType, 'Expected output type')
const decoded = utils.defaultAbiCoder.decode(
[resultType],
response.data.toString(),
)
const value = decoded[0] as string
const abi = new utils.Interface([this.fragment])

return {
field: this.field,
value: toContractValue(value),
value: decodeMethodResult(abi, this.fragment, response.data),
}
}
}
17 changes: 14 additions & 3 deletions packages/discovery/src/discovery/handlers/utils/callMethod.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,17 +18,28 @@ export async function callMethod(
blockNumber: number,
) {
const abi = new utils.Interface([fragment])

try {
const callData = Bytes.fromHex(abi.encodeFunctionData(fragment, parameters))
const result = await provider.call(address, callData, blockNumber)
const decoded = abi.decodeFunctionResult(fragment, result.toString())
const mapped = decoded.map(toContractValue)

return {
value: mapped.length === 1 ? mapped[0] : mapped,
value: decodeMethodResult(abi, fragment, result),
}
} catch (e) {
return {
error: isRevert(e) ? EXEC_REVERT_MSG : getErrorMessage(e),
}
}
}

// eslint-disable-next-line @typescript-eslint/explicit-function-return-type
export function decodeMethodResult(
abi: utils.Interface,
fragment: utils.FunctionFragment,
result: Bytes,
) {
const decoded = abi.decodeFunctionResult(fragment, result.toString())
const mapped = decoded.map(toContractValue)
return mapped.length === 1 ? mapped[0] : mapped
}

0 comments on commit 03a30b1

Please sign in to comment.