Skip to content

Commit

Permalink
Add multicall encoding tests
Browse files Browse the repository at this point in the history
  • Loading branch information
prevostc committed Jul 5, 2024
1 parent a4799e8 commit a63a041
Show file tree
Hide file tree
Showing 4 changed files with 74 additions and 22 deletions.
2 changes: 1 addition & 1 deletion src/classic/utils/classic-data.ts
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@ export function fetchClassicData(classic: Classic): ClassicData {
} else if (PRICE_ORACLE_TYPE === "pyth") {
calls.push(
new Multicall3Params(PYTH_PRICE_FEED_ADDRESS, "getPriceUnsafe(bytes32)", "(int64,uint64,int32,uint256)", [
ethereum.Value.fromBytes(PYTH_NATIVE_PRICE_ID),
ethereum.Value.fromFixedBytes(PYTH_NATIVE_PRICE_ID),
]),
)
} else {
Expand Down
2 changes: 1 addition & 1 deletion src/clm/utils/clm-data.ts
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,7 @@ export function fetchCLMData(clm: CLM): CLMData {
} else if (PRICE_ORACLE_TYPE === "pyth") {
calls.push(
new Multicall3Params(PYTH_PRICE_FEED_ADDRESS, "getPriceUnsafe(bytes32)", "(int64,uint64,int32,uint256)", [
ethereum.Value.fromBytes(PYTH_NATIVE_PRICE_ID),
ethereum.Value.fromFixedBytes(PYTH_NATIVE_PRICE_ID),
]),
)
} else {
Expand Down
44 changes: 24 additions & 20 deletions src/common/utils/multicall.ts
Original file line number Diff line number Diff line change
Expand Up @@ -24,26 +24,7 @@ export function multicall(callParams: Array<Multicall3Params>): Array<MulticallR
let params: Array<ethereum.Tuple> = []
for (let i = 0; i < callParams.length; i++) {
const callParam = callParams[i]
const signature = Bytes.fromUint8Array(
crypto.keccak256(ByteArray.fromUTF8(callParam.functionSignature)).slice(0, 4),
)

let functionCall = signature
if (callParam.args.length > 0) {
const calldata = ethereum.encode(
ethereum.Value.fromTuple(
// @ts-expect-error assemblyscript native function
changetype<ethereum.Tuple>(callParam.args),
),
)

if (calldata) {
functionCall = functionCall.concat(calldata)
} else {
log.error("Failed to encode calldata for function {}", [callParam.functionSignature])
}
}

const functionCall = _multicall3ParamsToCallData(callParam)
params.push(
// @ts-expect-error assemblyscript native function
changetype<ethereum.Tuple>([
Expand Down Expand Up @@ -73,6 +54,7 @@ export function multicall(callParams: Array<Multicall3Params>): Array<MulticallR
}

const multiResults: Array<ethereum.Tuple> = callResult.value[0].toTupleArray<ethereum.Tuple>()

for (let i = 0; i < callParams.length; i++) {
const callParam = callParams[i]
const res = multiResults[i]
Expand Down Expand Up @@ -101,3 +83,25 @@ export function multicall(callParams: Array<Multicall3Params>): Array<MulticallR

return results
}

export function _multicall3ParamsToCallData(callParam: Multicall3Params): Bytes {
const signature = Bytes.fromUint8Array(crypto.keccak256(ByteArray.fromUTF8(callParam.functionSignature)).slice(0, 4))

let functionCall = signature
if (callParam.args.length > 0) {
const calldata = ethereum.encode(
ethereum.Value.fromTuple(
// @ts-expect-error assemblyscript native function
changetype<ethereum.Tuple>(callParam.args),
),
)

if (calldata) {
functionCall = functionCall.concat(calldata)
} else {
log.error("Failed to encode calldata for function {}", [callParam.functionSignature])
}
}

return functionCall
}
48 changes: 48 additions & 0 deletions tests/utils/multicall.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
import { assert, test, describe } from "matchstick-as/assembly/index"
import { Address, BigInt, Bytes, ethereum, log } from "@graphprotocol/graph-ts"
import { BEEFY_ORACLE_ADDRESS, PYTH_NATIVE_PRICE_ID, PYTH_PRICE_FEED_ADDRESS } from "../../src/config"
import { Multicall3Params, _multicall3ParamsToCallData } from "../../src/common/utils/multicall"

describe("multicall", () => {
test("Encodes solo signature properly", () => {
const someAddress = Address.fromBytes(Bytes.fromHexString("0x0dc808adce2099a9f62aa87d9670745aba741746"))

const params = new Multicall3Params(someAddress, "totalSupply()", "uint256")

const functionCall = _multicall3ParamsToCallData(params)

assert.assertTrue(functionCall.equals(Bytes.fromHexString("0x18160ddd")))
})

test("Must encode one address parameter properly", () => {
const someAddress = Address.fromBytes(Bytes.fromHexString("0x0dc808adce2099a9f62aa87d9670745aba741746"))

const params = new Multicall3Params(BEEFY_ORACLE_ADDRESS, "getFreshPrice(address)", "(uint256,bool)", [
ethereum.Value.fromAddress(someAddress),
])

const functionCall = _multicall3ParamsToCallData(params)

assert.assertTrue(
functionCall.equals(
Bytes.fromHexString("0xbaeb325b0000000000000000000000000dc808adce2099a9f62aa87d9670745aba741746"),
),
)
})

test("Must encode pyth bytes32 parameter properly", () => {
const params = new Multicall3Params(
PYTH_PRICE_FEED_ADDRESS,
"getPriceUnsafe(bytes32)",
"(int64,uint64,int32,uint256)",
[ethereum.Value.fromFixedBytes(PYTH_NATIVE_PRICE_ID)],
)
const functionCall = _multicall3ParamsToCallData(params)

assert.assertTrue(
functionCall.equals(
Bytes.fromHexString("0x96834ad3ff61491a931112ddf1bd8147cd1b641375f79f5825126d665480874634fd0ace"),
),
)
})
})

0 comments on commit a63a041

Please sign in to comment.