Skip to content

Commit

Permalink
fix static call results and add tests
Browse files Browse the repository at this point in the history
  • Loading branch information
zoeyTM committed Sep 12, 2023
1 parent 7599732 commit 34fee02
Show file tree
Hide file tree
Showing 8 changed files with 286 additions and 133 deletions.
8 changes: 4 additions & 4 deletions packages/core/src/internal/execution/abi.ts
Original file line number Diff line number Diff line change
Expand Up @@ -278,7 +278,7 @@ export function getEventArgumentFromReceipt(
emitterAddress: string,
eventName: string,
eventIndex: number,
argument: string | number
nameOrIndex: string | number
): EvmValue {
const emitterLogs = receipt.logs.filter((l) => l.address === emitterAddress);

Expand All @@ -300,11 +300,11 @@ export function getEventArgumentFromReceipt(

const evmTuple = ethersResultIntoEvmTuple(ethersResult, eventFragment.inputs);

if (typeof argument === "string") {
return evmTuple.named[argument];
if (typeof nameOrIndex === "string") {
return evmTuple.named[nameOrIndex];
}

return evmTuple.positional[argument];
return evmTuple.positional[nameOrIndex];
}

/**
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,6 @@ import {
StaticCallResponse,
SuccessfulTransaction,
} from "./types/execution-strategy";
import { convertEvmTupleToSolidityParam } from "./utils/convert-evm-tuple-to-solidity-param";

/**
* Returns true if the given response is an onchain interaction response.
Expand Down Expand Up @@ -205,12 +204,16 @@ export async function* executeStaticCallRequest(
* @returns The value that should be used as the result of the static call execution state.
*/
export function getStaticCallExecutionStateResultValue(
_exState: StaticCallExecutionState,
exState: StaticCallExecutionState,
lastStaticCallResult: SuccessfulEvmExecutionResult
): SolidityParameterType {
const values = convertEvmTupleToSolidityParam(lastStaticCallResult.values);
// TODO: We should have a way to handle other results.
return values[0];
return typeof exState.nameOrIndex === "string"
? (lastStaticCallResult.values.named[
exState.nameOrIndex
] as SolidityParameterType)
: (lastStaticCallResult.values.positional[
exState.nameOrIndex
] as SolidityParameterType);
}

export * from "./abi";
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,6 @@ import {
CallExecutionResult,
SendDataExecutionResult,
StaticCallExecutionResult,
ExecutionResultType,
} from "../../types/execution-result";
import {
DeploymentExecutionState,
Expand Down Expand Up @@ -47,19 +46,10 @@ export function createExecutionStateCompleteMessage(
| SendDataExecutionStateCompleteMessage
| StaticCallExecutionStateCompleteMessage {
if (exState.type === ExecutionSateType.STATIC_CALL_EXECUTION_STATE) {
const newResult = result as StaticCallExecutionResult;
if (newResult.type === ExecutionResultType.SUCCESS) {
newResult.value = Array.isArray(newResult.value)
? newResult.value[exState.nameOrIndex as number]
: typeof newResult.value === "object"
? newResult.value[exState.nameOrIndex]
: newResult.value;
}

return {
type: JournalMessageType.STATIC_CALL_EXECUTION_STATE_COMPLETE,
futureId: exState.id,
result: newResult,
result: result as StaticCallExecutionResult,
};
}

Expand Down
19 changes: 17 additions & 2 deletions packages/core/test/readEventArgument.ts
Original file line number Diff line number Diff line change
Expand Up @@ -90,7 +90,7 @@ describe("Read event argument", () => {
const call = m.call(contract, "fuc");

m.readEventArgument(contract, "EventName1", "arg1");
m.readEventArgument(call, "EventName2", "arg2");
m.readEventArgument(call, "EventName2", 2);

return { contract };
});
Expand All @@ -103,7 +103,7 @@ describe("Read event argument", () => {
assert.equal(read1.nameOrIndex, "arg1");

assert.equal(read2.eventName, "EventName2");
assert.equal(read2.nameOrIndex, "arg2");
assert.equal(read2.nameOrIndex, 2);
});

it("should default the eventIndex to 0", () => {
Expand Down Expand Up @@ -191,6 +191,21 @@ describe("Read event argument", () => {
});

describe("validation", () => {
describe("module stage", () => {
it("should not validate a nameOrIndex that is not a number or string", () => {
assert.throws(
() =>
buildModule("Module1", (m) => {
const another = m.contract("Another", []);
m.readEventArgument(another, "test", {} as any);

return { another };
}),
/Invalid nameOrIndex given/
);
});
});

describe("stage one", () => {
let vm: typeof import("../src/internal/validation/stageOne/validateReadEventArgument");
let validateReadEventArgument: typeof vm.validateReadEventArgument;
Expand Down
45 changes: 45 additions & 0 deletions packages/core/test/staticCall.ts
Original file line number Diff line number Diff line change
Expand Up @@ -143,6 +143,38 @@ describe("static call", () => {
assert(callFuture.dependencies.has(staticCallFuture!));
});

it("should be able to use a string or number to index its result", () => {
const moduleWithASingleContract = buildModule("Module1", (m) => {
const contract1 = m.contract("Contract1");

m.staticCall(contract1, "test", [], "testName");
m.staticCall(contract1, "test2", [], 2);

return { contract1 };
});

assert.isDefined(moduleWithASingleContract);

const staticCallFuture = [...moduleWithASingleContract.futures].find(
({ id }) => id === "Module1:Contract1#test"
);

const staticCallFuture2 = [...moduleWithASingleContract.futures].find(
({ id }) => id === "Module1:Contract1#test2"
);

if (!(staticCallFuture instanceof NamedStaticCallFutureImplementation)) {
assert.fail("Not a named static contract deployment");
}

if (!(staticCallFuture2 instanceof NamedStaticCallFutureImplementation)) {
assert.fail("Not a named static contract deployment");
}

assert.equal(staticCallFuture.nameOrIndex, "testName");
assert.equal(staticCallFuture2.nameOrIndex, 2);
});

it("should be able to pass a string as from option", () => {
const moduleWithDependentContracts = buildModule("Module1", (m) => {
const example = m.contract("Example");
Expand Down Expand Up @@ -420,6 +452,19 @@ describe("static call", () => {
);
});

it("should not validate a nameOrIndex that is not a number or string", () => {
assert.throws(
() =>
buildModule("Module1", (m) => {
const another = m.contract("Another", []);
m.staticCall(another, "test", [], {} as any);

return { another };
}),
/Invalid nameOrIndex given/
);
});

it("should not validate a non-contract", () => {
assert.throws(
() =>
Expand Down
25 changes: 25 additions & 0 deletions packages/hardhat-plugin/test/events.ts
Original file line number Diff line number Diff line change
Expand Up @@ -58,4 +58,29 @@ describe("events", () => {
assert.equal(await result.fooFactory.isDeployed(), true);
assert.equal(await result.foo.x(), Number(1));
});

it("should be able to use the output of a readEvent with an indexed tuple result", async function () {
const moduleDefinition = buildModule("FooModule", (m) => {
const tupleContract = m.contract("TupleEmitter");

const tupleCall = m.call(tupleContract, "emitTuple");

const arg1 = m.readEventArgument(tupleCall, "TupleEvent", "arg1", {
id: "arg1",
});
const arg2 = m.readEventArgument(tupleCall, "TupleEvent", 1, {
id: "arg2",
});

m.call(tupleContract, "verifyArg1", [arg1], { id: "call1" });
m.call(tupleContract, "verifyArg2", [arg2], { id: "call2" });

return { tupleContract };
});

const result = await this.deploy(moduleDefinition);

assert.equal(await result.tupleContract.arg1Captured(), true);
assert.equal(await result.tupleContract.arg2Captured(), true);
});
});
Loading

0 comments on commit 34fee02

Please sign in to comment.