Skip to content

Commit

Permalink
feat: 🎸 return call with object
Browse files Browse the repository at this point in the history
BREAKING CHANGE: 🧨 return call with object instead of array
  • Loading branch information
waynewyang committed Dec 18, 2023
1 parent 426841f commit b2de8d0
Show file tree
Hide file tree
Showing 5 changed files with 147 additions and 36 deletions.
11 changes: 9 additions & 2 deletions src/evm/engine/ether/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@ import {
IEVMEngine,
defaultTransactionOptions,
} from "../../interface"
import { convertArrayToObjectByAbiAndName } from "../utils"

/**
* Define ethereum as an optional property.
Expand Down Expand Up @@ -193,7 +194,13 @@ export class EthersEvmEngine implements IEVMEngine {
return {
ok: true,
data:
result instanceof EthersResult ? result.toArray() : result,
result instanceof EthersResult
? convertArrayToObjectByAbiAndName(
this.getContractABI(),
input.method,
result.toArray()
)
: result,
}
} catch (error) {
return {
Expand Down Expand Up @@ -439,7 +446,7 @@ export class EthersEvmEngine implements IEVMEngine {

try {
const tr = await this.provider.broadcastTransaction(signed)
const result = await this.provider.waitForTransaction(tr.hash);
const result = await this.provider.waitForTransaction(tr.hash)
return {
ok: true,
data: result,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,8 @@
********************************************************************************/

import { Result } from "@unipackage/utils"
import { JsonFragment } from "ethers"
import { AbiFunctionFragment } from "web3"

/**
* Represents a parsed data object.
Expand All @@ -28,6 +30,84 @@ export type EvmReplyData = {
[key: string]: any
}

/**
* Converts the output array of a function call to an object using ABI and function name.
*
* @param abi An array containing function fragments (AbiFunctionFragment or JsonFragment).
* @param name The name of the function to search for.
* @param data The output array of a function call.
* @returns The converted object. Returns undefined if the output array is empty, or the single element if there's only one.
* @throws Throws an error if the ABI function fragment is undefined.
*/
export function convertArrayToObjectByAbiAndName(
abi: AbiFunctionFragment[] | JsonFragment[],
name: string,
data: any[]
): any {
const abiFragment = getAbiFunctionFragmentByMethodName(abi, name)
if (!abiFragment) {
throw new Error("Abi function fragment is undefined")
}
return convertArrayToObjectByAbiFunctionFragment(abiFragment, data)
}

/**
* Converts the output array of a function call to an object.
*
* @param abi The ABI information of the function, including the output parameters.
* @param data The output array of a function call.
* @returns The converted object. Returns undefined if the output array is empty, or the single element if there's only one.
*/
export function convertArrayToObjectByAbiFunctionFragment(
abi: AbiFunctionFragment | JsonFragment,
data: any[]
): any {
const outputs = abi.outputs
if (!outputs) {
throw new Error(`Outputs of abi function fragment undefined!`)
}
if (outputs.length !== data.length) {
throw new Error(
`The length of ${JSON.stringify(data)} and ${JSON.stringify(
outputs
)} is not matched`
)
}
const length = data.length

if (length === 0) {
return undefined
} else if (length === 1) {
return data[0]
} else {
const result: any = {}
data.forEach((value, index) => {
if (outputs[index].name) {
result[outputs[index].name!] = value
} else {
result[`unnameKey+${index}`] = value
}
})
return result
}
}

/**
* Retrieves a function fragment from the ABI based on the method name.
*
* @param abi An array containing function fragments (AbiFunctionFragment or JsonFragment).
* @param name The name of the function to search for.
* @returns The matching AbiFunctionFragment or JsonFragment object, or undefined if not found.
*/
export function getAbiFunctionFragmentByMethodName(
abi: AbiFunctionFragment[] | JsonFragment[],
name: string
): AbiFunctionFragment | JsonFragment | undefined {
return abi.find((method) => {
return method.type === "function" && method.name === name
})
}

/**
* Gets the encoded parameters from the transaction input.
*
Expand Down
30 changes: 21 additions & 9 deletions src/evm/engine/web3/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -37,12 +37,14 @@ import {
EvmType,
IEVMEngine,
} from "../../interface"
import { IEVM, defaultTransactionOptions } from "../../interface"
import { defaultTransactionOptions } from "../../interface"
import {
convertArrayToObjectByAbiAndName,
getAbiFunctionFragmentByMethodName,
getEncodedParamsFromTxinput,
getFunctionSignatureFromTxinput,
parseEvmReplyData,
} from "./tools"
} from "../utils"

/**
* Define ethereum as an optional property.
Expand Down Expand Up @@ -224,12 +226,25 @@ export class Web3EvmEngine implements IEVMEngine {

try {
const params: any[] = input.params || []
const result = await this.contractObject.methods[input.method](
const originResult = await this.contractObject.methods[
input.method
](
//@ts-ignore
...params
).call()
const result = parseEvmReplyData(originResult!)

return { ok: true, data: parseEvmReplyData(result!) }
return {
ok: true,
data:
result instanceof Array
? convertArrayToObjectByAbiAndName(
this.contractABI,
input.method,
result
)
: result,
}
} catch (error) {
return {
ok: false,
Expand Down Expand Up @@ -388,12 +403,9 @@ export class Web3EvmEngine implements IEVMEngine {
error: "Web3 is not initialized!",
}
}
const abi = this.contractABI.find((method, index) => {
return method.type === "function" && method.name === name
})

const abi = getAbiFunctionFragmentByMethodName(this.contractABI, name)
if (abi) {
return this.encodeFunctionSignatureByAbi(abi)
return this.encodeFunctionSignatureByAbi(abi as AbiFunctionFragment)
} else {
return {
ok: false,
Expand Down
5 changes: 4 additions & 1 deletion src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -51,9 +51,12 @@ export {
export { Web3EvmEngine } from "./evm/engine/web3"
export { EthersEvmEngine } from "./evm/engine/ether"
export {
convertArrayToObjectByAbiAndName,
convertArrayToObjectByAbiFunctionFragment,
getAbiFunctionFragmentByMethodName,
getEncodedParamsFromTxinput,
getFunctionSignatureFromTxinput,
} from "./evm/engine/web3/tools"
} from "./evm/engine/utils"
export { withCallMethod, withSendMethod } from "./evm/withMethod"
export { Evm } from "./evm/"
export { AbstractEvm } from "./evm/abstract"
57 changes: 33 additions & 24 deletions test/evm/call.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -24,19 +24,19 @@ import { web3Datasets, ethersDatasets } from "./env/datasets"

const expectedMeta = {
ok: true,
data: [
"test-sirius",
"my industry",
"hi siri",
"desc good data set",
"aws://sdfa.com",
"dataswap.com/test1",
"0x15B2896f76Cee4E2C567e7bC671bB701D7339B30",
BigInt(1084025),
BigInt(512000000),
true,
BigInt(1),
],
data: {
title: "test-sirius",
industry: "my industry",
name: "hi siri",
description: "desc good data set",
source: "aws://sdfa.com",
accessMethod: "dataswap.com/test1",
submitter: "0x15B2896f76Cee4E2C567e7bC671bB701D7339B30",
createdBlockNumber: BigInt(1084025),
sizeInBytes: BigInt(512000000),
isPublic: true,
version: BigInt(1),
},
}

const expectedSubmitter = {
Expand All @@ -46,20 +46,29 @@ const expectedSubmitter = {

//@ts-ignore
describe("Call test", () => {
it("web3 correct test", async () => {
const web3Meta = await web3Datasets.getDatasetMetadata(1)
const web3Submmiter = await web3Datasets.getDatasetMetadataSubmitter(1)
describe("web3 correct test", () => {
it("call object test", async () => {
const web3Meta = await web3Datasets.getDatasetMetadata(1)
assert.deepStrictEqual(web3Meta, expectedMeta)
})

assert.deepStrictEqual(web3Meta, expectedMeta)
assert.deepStrictEqual(web3Submmiter, expectedSubmitter)
it("call notObject test", async () => {
const web3Submmiter =
await web3Datasets.getDatasetMetadataSubmitter(1)
assert.deepStrictEqual(web3Submmiter, expectedSubmitter)
})
})

it("ethers correct test", async () => {
const ethersMeta = await ethersDatasets.getDatasetMetadata(1)
const ethersSubmmiter =
await ethersDatasets.getDatasetMetadataSubmitter(1)
describe("ehters correct test", () => {
it("call object test", async () => {
const ethersMeta = await ethersDatasets.getDatasetMetadata(1)
assert.deepStrictEqual(ethersMeta, expectedMeta)
})

assert.deepStrictEqual(ethersMeta, expectedMeta)
assert.deepStrictEqual(ethersSubmmiter, expectedSubmitter)
it("call notObject test", async () => {
const ethersSubmmiter =
await ethersDatasets.getDatasetMetadataSubmitter(1)
assert.deepStrictEqual(ethersSubmmiter, expectedSubmitter)
})
})
})

0 comments on commit b2de8d0

Please sign in to comment.