From 470fe7bd240abbab3ee1bbf8981e75b3a4925f5e Mon Sep 17 00:00:00 2001 From: thedavidmeister Date: Thu, 7 May 2026 14:16:40 +0400 Subject: [PATCH 1/3] test reentrancy guard on store + ERC721/ERC1155 recipient paths The `Flow.flow` `nonReentrant` guard has four documented entry points (LibFlow.sol:142). PR #446 covers ERC20/ERC777-style reentrancy via a malicious token. This adds tests for the remaining three: 1. Malicious interpreter store: `MaliciousReenteringStore.set` re-enters `flow.flow`. Etched at the framework's STORE address. 2. Malicious ERC721 recipient: `MaliciousReenteringRecipient .onERC721Received` re-enters. The framework's TOKEN_B is etched with `StubERC721WithReceiverHook` so the underlying `safeTransferFrom` call propagates into the recipient hook. 3. Malicious ERC1155 recipient: same shape via `StubERC1155WithReceiverHook` at TOKEN_C and `onERC1155Received`. Mutation verified: dropping `nonReentrant` from `Flow.flow` makes all three new tests fail; reverting passes. Closes #309. Co-Authored-By: Claude Opus 4.7 (1M context) --- .../concrete/MaliciousReenteringRecipient.sol | 49 +++++++ test/concrete/MaliciousReenteringStore.sol | 35 +++++ test/concrete/StubERC1155WithReceiverHook.sol | 18 +++ test/concrete/StubERC721WithReceiverHook.sol | 18 +++ test/src/concrete/Flow.transfer.t.sol | 121 ++++++++++++++++++ 5 files changed, 241 insertions(+) create mode 100644 test/concrete/MaliciousReenteringRecipient.sol create mode 100644 test/concrete/MaliciousReenteringStore.sol create mode 100644 test/concrete/StubERC1155WithReceiverHook.sol create mode 100644 test/concrete/StubERC721WithReceiverHook.sol diff --git a/test/concrete/MaliciousReenteringRecipient.sol b/test/concrete/MaliciousReenteringRecipient.sol new file mode 100644 index 00000000..8b43aabf --- /dev/null +++ b/test/concrete/MaliciousReenteringRecipient.sol @@ -0,0 +1,49 @@ +// SPDX-License-Identifier: LicenseRef-DCL-1.0 +// SPDX-FileCopyrightText: Copyright (c) 2020 Rain Open Source Software Ltd +pragma solidity =0.8.25; + +import {IFlowV5} from "../../src/interface/IFlowV5.sol"; +import {EvaluableV2} from "rain.interpreter.interface/lib/caller/LibEvaluable.sol"; +import {SignedContextV1} from "rain.interpreter.interface/interface/IInterpreterCallerV2.sol"; +import {IERC721Receiver} from "openzeppelin-contracts/contracts/token/ERC721/IERC721Receiver.sol"; +import {IERC1155Receiver} from "openzeppelin-contracts/contracts/token/ERC1155/IERC1155Receiver.sol"; + +/// A recipient whose ERC721 / ERC1155 receiver hooks re-enter +/// `flow.flow(...)` on the same flow contract. Used to exercise +/// `Flow.flow`'s `nonReentrant` guard against reentry through the +/// EIP-721 / EIP-1155 receiver-side hooks. +contract MaliciousReenteringRecipient is IERC721Receiver, IERC1155Receiver { + IFlowV5 internal immutable I_FLOW; + EvaluableV2 internal evaluable; + + constructor(IFlowV5 flow_) { + I_FLOW = flow_; + } + + function setEvaluable(EvaluableV2 memory ev) external { + evaluable = ev; + } + + function onERC721Received(address, address, uint256, bytes calldata) external returns (bytes4) { + I_FLOW.flow(evaluable, new uint256[](0), new SignedContextV1[](0)); + return IERC721Receiver.onERC721Received.selector; + } + + function onERC1155Received(address, address, uint256, uint256, bytes calldata) external returns (bytes4) { + I_FLOW.flow(evaluable, new uint256[](0), new SignedContextV1[](0)); + return IERC1155Receiver.onERC1155Received.selector; + } + + function onERC1155BatchReceived(address, address, uint256[] calldata, uint256[] calldata, bytes calldata) + external + returns (bytes4) + { + I_FLOW.flow(evaluable, new uint256[](0), new SignedContextV1[](0)); + return IERC1155Receiver.onERC1155BatchReceived.selector; + } + + function supportsInterface(bytes4 interfaceId) external pure returns (bool) { + return interfaceId == type(IERC721Receiver).interfaceId || interfaceId == type(IERC1155Receiver).interfaceId + || interfaceId == 0x01ffc9a7; + } +} diff --git a/test/concrete/MaliciousReenteringStore.sol b/test/concrete/MaliciousReenteringStore.sol new file mode 100644 index 00000000..6afbb77a --- /dev/null +++ b/test/concrete/MaliciousReenteringStore.sol @@ -0,0 +1,35 @@ +// SPDX-License-Identifier: LicenseRef-DCL-1.0 +// SPDX-FileCopyrightText: Copyright (c) 2020 Rain Open Source Software Ltd +pragma solidity =0.8.25; + +import {IFlowV5} from "../../src/interface/IFlowV5.sol"; +import {EvaluableV2} from "rain.interpreter.interface/lib/caller/LibEvaluable.sol"; +import {SignedContextV1} from "rain.interpreter.interface/interface/IInterpreterCallerV2.sol"; + +/// An interpreter store whose `set` callback re-enters `flow.flow(...)` +/// on the same flow contract. Used to exercise `Flow.flow`'s +/// `nonReentrant` guard against reentry through the store's `set` path. +/// Its `get` returns zero so reads from this store do not crash other +/// callers. +contract MaliciousReenteringStore { + IFlowV5 internal immutable I_FLOW; + EvaluableV2 internal evaluable; + + constructor(IFlowV5 flow_) { + I_FLOW = flow_; + } + + function setEvaluable(EvaluableV2 memory ev) external { + evaluable = ev; + } + + /// Matches `IInterpreterStoreV2.set(StateNamespace, uint256[])`. Re-enters + /// the flow. + function set(uint256, uint256[] calldata) external { + I_FLOW.flow(evaluable, new uint256[](0), new SignedContextV1[](0)); + } + + function get(uint256, uint256) external pure returns (uint256) { + return 0; + } +} diff --git a/test/concrete/StubERC1155WithReceiverHook.sol b/test/concrete/StubERC1155WithReceiverHook.sol new file mode 100644 index 00000000..913f8a96 --- /dev/null +++ b/test/concrete/StubERC1155WithReceiverHook.sol @@ -0,0 +1,18 @@ +// SPDX-License-Identifier: LicenseRef-DCL-1.0 +// SPDX-FileCopyrightText: Copyright (c) 2020 Rain Open Source Software Ltd +pragma solidity =0.8.25; + +import {IERC1155Receiver} from "openzeppelin-contracts/contracts/token/ERC1155/IERC1155Receiver.sol"; + +/// Minimal ERC1155-shaped stub that, on `safeTransferFrom`, calls the +/// recipient's `onERC1155Received` hook if the recipient has code. Used +/// in tests to exercise recipient-side reentrancy through the ERC1155 +/// path without deploying a full ERC1155 token implementation. +contract StubERC1155WithReceiverHook { + //forge-lint: disable-next-line(mixed-case-function) + function safeTransferFrom(address from, address to, uint256 id, uint256 amount, bytes calldata data) external { + if (to.code.length > 0) { + IERC1155Receiver(to).onERC1155Received(msg.sender, from, id, amount, data); + } + } +} diff --git a/test/concrete/StubERC721WithReceiverHook.sol b/test/concrete/StubERC721WithReceiverHook.sol new file mode 100644 index 00000000..b3315a52 --- /dev/null +++ b/test/concrete/StubERC721WithReceiverHook.sol @@ -0,0 +1,18 @@ +// SPDX-License-Identifier: LicenseRef-DCL-1.0 +// SPDX-FileCopyrightText: Copyright (c) 2020 Rain Open Source Software Ltd +pragma solidity =0.8.25; + +import {IERC721Receiver} from "openzeppelin-contracts/contracts/token/ERC721/IERC721Receiver.sol"; + +/// Minimal ERC721-shaped stub that, on `safeTransferFrom`, calls the +/// recipient's `onERC721Received` hook if the recipient has code. Used in +/// tests to exercise recipient-side reentrancy through the ERC721 path +/// without deploying a full ERC721 token implementation. +contract StubERC721WithReceiverHook { + //forge-lint: disable-next-line(mixed-case-function) + function safeTransferFrom(address from, address to, uint256 tokenId) external { + if (to.code.length > 0) { + IERC721Receiver(to).onERC721Received(msg.sender, from, tokenId, ""); + } + } +} diff --git a/test/src/concrete/Flow.transfer.t.sol b/test/src/concrete/Flow.transfer.t.sol index 50c6e581..5e58881e 100644 --- a/test/src/concrete/Flow.transfer.t.sol +++ b/test/src/concrete/Flow.transfer.t.sol @@ -29,6 +29,10 @@ import {LibContextWrapper} from "test/lib/LibContextWrapper.sol"; import {IERC721} from "openzeppelin-contracts/contracts/token/ERC721/IERC721.sol"; import {IERC1155} from "openzeppelin-contracts/contracts/token/ERC1155/IERC1155.sol"; import {LibStackGeneration} from "test/lib/LibStackGeneration.sol"; +import {MaliciousReenteringStore} from "test/concrete/MaliciousReenteringStore.sol"; +import {MaliciousReenteringRecipient} from "test/concrete/MaliciousReenteringRecipient.sol"; +import {StubERC721WithReceiverHook} from "test/concrete/StubERC721WithReceiverHook.sol"; +import {StubERC1155WithReceiverHook} from "test/concrete/StubERC1155WithReceiverHook.sol"; /// `IERC721.safeTransferFrom` is overloaded (3-arg + 4-arg). Pin the 3-arg /// selector via a single-overload wrapper interface so the disambiguation @@ -428,4 +432,121 @@ contract FlowTransferTest is FlowTest { flow.flow(evaluable, new uint256[](0), new SignedContextV1[](0)); vm.stopPrank(); } + + /// `Flow.flow` carries `nonReentrant`. A malicious interpreter store + /// whose `set` re-enters `flow.flow(...)` MUST cause the inner call + /// to revert. + function testFlowReentrancyGuardFiresOnStoreCallback(uint256 writeKey, uint256 writeValue) external { + address alice = address(uint160(uint256(keccak256("alice.reentrancy.store")))); + vm.label(alice, "Alice"); + + (IFlowV5 flow, EvaluableV2 memory evaluable) = deployFlow(); + assumeEtchable(alice, address(flow)); + + // Replace the framework's mock STORE with the malicious bytecode so + // LibFlow.flow's `set(...)` lands in the re-entering implementation. + MaliciousReenteringStore malStore = new MaliciousReenteringStore(flow); + malStore.setEvaluable(evaluable); + vm.etch(address(STORE), address(malStore).code); + // The runtime still needs to know which evaluable to flow into; the + // MaliciousReenteringStore reads its `evaluable` storage slot, so + // copy it over after the etch. + bytes32 evalSlot0 = vm.load(address(malStore), bytes32(uint256(0))); + bytes32 evalSlot1 = vm.load(address(malStore), bytes32(uint256(1))); + bytes32 evalSlot2 = vm.load(address(malStore), bytes32(uint256(2))); + vm.store(address(STORE), bytes32(uint256(0)), evalSlot0); + vm.store(address(STORE), bytes32(uint256(1)), evalSlot1); + vm.store(address(STORE), bytes32(uint256(2)), evalSlot2); + + // Eval2 returns non-empty kvs so LibFlow.flow takes the `set` branch. + uint256[] memory stack = LibStackGeneration.generateFlowStack(Sentinel.unwrap(RAIN_FLOW_SENTINEL), transferEmpty()); + uint256[] memory writes = new uint256[](2); + writes[0] = writeKey; + writes[1] = writeValue; + interpreterEval2MockCall(stack, writes); + + vm.startPrank(alice); + vm.expectRevert(bytes("ReentrancyGuard: reentrant call")); + flow.flow(evaluable, new uint256[](0), new SignedContextV1[](0)); + vm.stopPrank(); + } + + /// A malicious ERC721 recipient whose `onERC721Received` re-enters + /// `flow.flow(...)` MUST cause the inner call to revert. Exercises the + /// EIP-721 receiver-hook reentrancy path (the underlying token's + /// `safeTransferFrom` invokes the recipient hook on a contract `to`). + /// forge-config: default.fuzz.runs = 100 + function testFlowReentrancyGuardFiresOnERC721Recipient(uint256 tokenId) external { + vm.assume(Sentinel.unwrap(RAIN_FLOW_SENTINEL) != tokenId); + address alice = address(uint160(uint256(keccak256("alice.reentrancy.erc721")))); + vm.label(alice, "Alice"); + + (IFlowV5 flow, EvaluableV2 memory evaluable) = deployFlow(); + assumeEtchable(alice, address(flow)); + + // Etch a stub ERC721 implementation at TOKEN_B that forwards + // safeTransferFrom into the recipient hook. + StubERC721WithReceiverHook stub = new StubERC721WithReceiverHook(); + vm.etch(TOKEN_B, address(stub).code); + + // Deploy the malicious recipient and arm it with the flow's + // evaluable. + MaliciousReenteringRecipient recipient = new MaliciousReenteringRecipient(flow); + recipient.setEvaluable(evaluable); + + ERC721Transfer[] memory erc721Transfers = new ERC721Transfer[](1); + erc721Transfers[0] = + ERC721Transfer({token: TOKEN_B, from: address(flow), to: address(recipient), id: tokenId}); + + uint256[] memory stack = LibStackGeneration.generateFlowStack( + Sentinel.unwrap(RAIN_FLOW_SENTINEL), + FlowTransferV1(new ERC20Transfer[](0), erc721Transfers, new ERC1155Transfer[](0)) + ); + interpreterEval2MockCall(stack, new uint256[](0)); + + vm.startPrank(alice); + vm.expectRevert(bytes("ReentrancyGuard: reentrant call")); + flow.flow(evaluable, new uint256[](0), new SignedContextV1[](0)); + vm.stopPrank(); + } + + /// A malicious ERC1155 recipient whose `onERC1155Received` re-enters + /// `flow.flow(...)` MUST cause the inner call to revert. Exercises the + /// EIP-1155 receiver-hook reentrancy path. + /// forge-config: default.fuzz.runs = 100 + function testFlowReentrancyGuardFiresOnERC1155Recipient(uint256 tokenId, uint256 amount) external { + vm.assume(Sentinel.unwrap(RAIN_FLOW_SENTINEL) != tokenId); + vm.assume(Sentinel.unwrap(RAIN_FLOW_SENTINEL) != amount); + address alice = address(uint160(uint256(keccak256("alice.reentrancy.erc1155")))); + vm.label(alice, "Alice"); + + (IFlowV5 flow, EvaluableV2 memory evaluable) = deployFlow(); + assumeEtchable(alice, address(flow)); + + StubERC1155WithReceiverHook stub = new StubERC1155WithReceiverHook(); + vm.etch(TOKEN_C, address(stub).code); + + MaliciousReenteringRecipient recipient = new MaliciousReenteringRecipient(flow); + recipient.setEvaluable(evaluable); + + ERC1155Transfer[] memory erc1155Transfers = new ERC1155Transfer[](1); + erc1155Transfers[0] = ERC1155Transfer({ + token: TOKEN_C, + from: address(flow), + to: address(recipient), + id: tokenId, + amount: amount + }); + + uint256[] memory stack = LibStackGeneration.generateFlowStack( + Sentinel.unwrap(RAIN_FLOW_SENTINEL), + FlowTransferV1(new ERC20Transfer[](0), new ERC721Transfer[](0), erc1155Transfers) + ); + interpreterEval2MockCall(stack, new uint256[](0)); + + vm.startPrank(alice); + vm.expectRevert(bytes("ReentrancyGuard: reentrant call")); + flow.flow(evaluable, new uint256[](0), new SignedContextV1[](0)); + vm.stopPrank(); + } } From 0754b8045ae2514ab77770de803403ce48855541 Mon Sep 17 00:00:00 2001 From: thedavidmeister Date: Sat, 9 May 2026 18:53:37 +0400 Subject: [PATCH 2/3] delete FlowUtilsAbstractTest, inline pass-through wrappers at callsites `generateFlowStack` / `findEvent` / `findEvents` were thin wrappers in `FlowUtilsAbstractTest`. The wrappers exist only because Solidity's `using X for T` clauses don't inherit, so child contracts of `FlowTest` couldn't otherwise call the library forms directly. Replace each callsite with the explicit static form: - `generateFlowStack(t)` -> `LibStackGeneration.generateFlowStack(Sentinel.unwrap(RAIN_FLOW_SENTINEL), t)` - `findEvent(logs, sig)` -> `LibLogHelper.findEvent(logs, sig)` `FlowTest` now inherits `FlowTransferOperation` directly. `FlowUtilsAbstractTest.sol` is removed. Co-Authored-By: Claude Opus 4.7 (1M context) --- test/abstract/FlowTest.sol | 4 +-- test/abstract/FlowUtilsAbstractTest.sol | 35 ------------------- test/src/concrete/Flow.construction.t.sol | 3 +- test/src/concrete/Flow.context.t.sol | 7 ++-- test/src/concrete/Flow.expression.t.sol | 3 +- test/src/concrete/Flow.preview.t.sol | 3 +- test/src/concrete/Flow.signedContext.t.sol | 10 ++++-- test/src/concrete/Flow.time.t.sol | 7 ++-- test/src/concrete/Flow.transfer.t.sol | 39 ++++++++++++---------- 9 files changed, 46 insertions(+), 65 deletions(-) delete mode 100644 test/abstract/FlowUtilsAbstractTest.sol diff --git a/test/abstract/FlowTest.sol b/test/abstract/FlowTest.sol index 1c1d0186..1c31c52d 100644 --- a/test/abstract/FlowTest.sol +++ b/test/abstract/FlowTest.sol @@ -3,7 +3,7 @@ pragma solidity ^0.8.25; import {Vm} from "forge-std/Test.sol"; -import {FlowUtilsAbstractTest} from "test/abstract/FlowUtilsAbstractTest.sol"; +import {FlowTransferOperation} from "test/abstract/FlowTransferOperation.sol"; import {InterpreterMockTest} from "test/abstract/InterpreterMockTest.sol"; import {EvaluableConfigV3} from "rain.interpreter.interface/interface/IInterpreterCallerV2.sol"; import {EvaluableV2} from "rain.interpreter.interface/lib/caller/LibEvaluable.sol"; @@ -16,7 +16,7 @@ import {Flow} from "src/concrete/Flow.sol"; import {LibUint256Matrix} from "rain.solmem/lib/LibUint256Matrix.sol"; import {LibUint256Array} from "rain.solmem/lib/LibUint256Array.sol"; -abstract contract FlowTest is FlowUtilsAbstractTest, InterpreterMockTest { +abstract contract FlowTest is FlowTransferOperation, InterpreterMockTest { using LibLogHelper for Vm.Log[]; using LibStackGeneration for uint256; using Address for address; diff --git a/test/abstract/FlowUtilsAbstractTest.sol b/test/abstract/FlowUtilsAbstractTest.sol deleted file mode 100644 index ec5a5467..00000000 --- a/test/abstract/FlowUtilsAbstractTest.sol +++ /dev/null @@ -1,35 +0,0 @@ -// SPDX-License-Identifier: LicenseRef-DCL-1.0 -// SPDX-FileCopyrightText: Copyright (c) 2020 Rain Open Source Software Ltd -pragma solidity ^0.8.25; - -import {Vm} from "forge-std/Test.sol"; - -import {FlowTransferV1, RAIN_FLOW_SENTINEL} from "src/interface/IFlowV5.sol"; -import {Sentinel} from "rain.solmem/lib/LibStackSentinel.sol"; -import {LibStackGeneration} from "test/lib/LibStackGeneration.sol"; -import {LibLogHelper} from "test/lib/LibLogHelper.sol"; -import {FlowTransferOperation} from "test/abstract/FlowTransferOperation.sol"; - -abstract contract FlowUtilsAbstractTest is FlowTransferOperation { - using LibStackGeneration for uint256; - using LibLogHelper for Vm.Log[]; - - // A temporary solution for a smooth transition to using libraries. - function generateFlowStack(FlowTransferV1 memory flowTransfer) internal pure returns (uint256[] memory stack) { - stack = Sentinel.unwrap(RAIN_FLOW_SENTINEL).generateFlowStack(flowTransfer); - } - - // A temporary solution for a smooth transition to using libraries. - function findEvent(Vm.Log[] memory logs, bytes32 eventSignature) internal pure returns (Vm.Log memory) { - return logs.findEvent(eventSignature); - } - - // A temporary solution for a smooth transition to using libraries. - function findEvents(Vm.Log[] memory logs, bytes32 eventSignature) - internal - pure - returns (Vm.Log[] memory foundLogs) - { - foundLogs = logs.findEvents(eventSignature); - } -} diff --git a/test/src/concrete/Flow.construction.t.sol b/test/src/concrete/Flow.construction.t.sol index 03206941..78d22019 100644 --- a/test/src/concrete/Flow.construction.t.sol +++ b/test/src/concrete/Flow.construction.t.sol @@ -7,6 +7,7 @@ import {Vm} from "forge-std/Test.sol"; import {EvaluableConfigV3} from "rain.interpreter.interface/interface/IInterpreterCallerV2.sol"; import {FlowTest} from "test/abstract/FlowTest.sol"; import {EmptyFlowConfig} from "src/error/ErrFlow.sol"; +import {LibLogHelper} from "test/lib/LibLogHelper.sol"; contract FlowConstructionTest is FlowTest { function testFlowConstructionEmptyConfigReverts() external { @@ -30,7 +31,7 @@ contract FlowConstructionTest is FlowTest { Vm.Log[] memory logs = vm.getRecordedLogs(); bytes32 eventSignature = keccak256("Initialize(address,(address,bytes,uint256[])[])"); - Vm.Log memory concreteEvent = findEvent(logs, eventSignature); + Vm.Log memory concreteEvent = LibLogHelper.findEvent(logs, eventSignature); (address sender, EvaluableConfigV3[] memory config) = abi.decode(concreteEvent.data, (address, EvaluableConfigV3[])); diff --git a/test/src/concrete/Flow.context.t.sol b/test/src/concrete/Flow.context.t.sol index 6d30d27b..90615af4 100644 --- a/test/src/concrete/Flow.context.t.sol +++ b/test/src/concrete/Flow.context.t.sol @@ -3,12 +3,14 @@ pragma solidity =0.8.25; import {FlowTest} from "test/abstract/FlowTest.sol"; -import {IFlowV5} from "src/interface/IFlowV5.sol"; +import {IFlowV5, RAIN_FLOW_SENTINEL} from "src/interface/IFlowV5.sol"; +import {Sentinel} from "rain.solmem/lib/LibStackSentinel.sol"; import {EvaluableV2} from "rain.interpreter.interface/lib/caller/LibEvaluable.sol"; import {FLOW_MAX_OUTPUTS, FLOW_ENTRYPOINT} from "src/concrete/Flow.sol"; import {LibEncodedDispatch} from "rain.interpreter.interface/lib/caller/LibEncodedDispatch.sol"; import {SignedContextV1} from "rain.interpreter.interface/interface/IInterpreterCallerV2.sol"; import {LibContextWrapper} from "test/lib/LibContextWrapper.sol"; +import {LibStackGeneration} from "test/lib/LibStackGeneration.sol"; contract FlowContextTest is FlowTest { /** @@ -26,7 +28,8 @@ contract FlowContextTest is FlowTest { LibContextWrapper.buildAndSetContext(callerContext, signedContext, address(alice), address(flow)); { - uint256[] memory stack = generateFlowStack(transferEmpty()); + uint256[] memory stack = + LibStackGeneration.generateFlowStack(Sentinel.unwrap(RAIN_FLOW_SENTINEL), transferEmpty()); interpreterEval2MockCall(stack, new uint256[](0)); diff --git a/test/src/concrete/Flow.expression.t.sol b/test/src/concrete/Flow.expression.t.sol index 4ee547d0..b7970c79 100644 --- a/test/src/concrete/Flow.expression.t.sol +++ b/test/src/concrete/Flow.expression.t.sol @@ -12,6 +12,7 @@ import {LibUint256Matrix} from "rain.solmem/lib/LibUint256Matrix.sol"; import {LibContextWrapper} from "test/lib/LibContextWrapper.sol"; import {IInterpreterCallerV2} from "rain.interpreter.interface/interface/IInterpreterCallerV2.sol"; import {SignContextLib} from "test/lib/SignContextLib.sol"; +import {LibLogHelper} from "test/lib/LibLogHelper.sol"; contract FlowExpressionTest is FlowTest, IInterpreterCallerV2 { using SignContextLib for Vm; @@ -74,7 +75,7 @@ contract FlowExpressionTest is FlowTest, IInterpreterCallerV2 { ); Vm.Log[] memory logs = vm.getRecordedLogs(); - Vm.Log memory log = findEvent(logs, keccak256("Context(address,uint256[][])")); + Vm.Log memory log = LibLogHelper.findEvent(logs, keccak256("Context(address,uint256[][])")); (address sender, uint256[][] memory buildContextOutput) = abi.decode(log.data, (address, uint256[][])); assertEq(sender, address(this), "wrong sender"); diff --git a/test/src/concrete/Flow.preview.t.sol b/test/src/concrete/Flow.preview.t.sol index fd4d127d..bb086c86 100644 --- a/test/src/concrete/Flow.preview.t.sol +++ b/test/src/concrete/Flow.preview.t.sol @@ -14,6 +14,7 @@ import { } from "src/interface/IFlowV5.sol"; import {EvaluableV2} from "rain.interpreter.interface/lib/caller/LibEvaluable.sol"; import {LibEvaluable} from "rain.interpreter.interface/lib/caller/LibEvaluable.sol"; +import {LibStackGeneration} from "test/lib/LibStackGeneration.sol"; contract FlowPreviewTest is FlowTest { using LibEvaluable for EvaluableV2; @@ -178,7 +179,7 @@ contract FlowPreviewTest is FlowTest { FlowTransferV1 memory flowTransfer = FlowTransferV1(new ERC20Transfer[](0), new ERC721Transfer[](0), new ERC1155Transfer[](0)); - uint256[] memory stack = generateFlowStack(flowTransfer); + uint256[] memory stack = LibStackGeneration.generateFlowStack(Sentinel.unwrap(RAIN_FLOW_SENTINEL), flowTransfer); assertEq( keccak256(abi.encode(flowTransfer)), keccak256(abi.encode(flow.stackToFlow(stack))), "wrong compare Structs" ); diff --git a/test/src/concrete/Flow.signedContext.t.sol b/test/src/concrete/Flow.signedContext.t.sol index beabbeae..2516aaf0 100644 --- a/test/src/concrete/Flow.signedContext.t.sol +++ b/test/src/concrete/Flow.signedContext.t.sol @@ -5,9 +5,11 @@ pragma solidity =0.8.25; import {Vm} from "forge-std/Test.sol"; import {FlowTest} from "test/abstract/FlowTest.sol"; import {SignContextLib} from "test/lib/SignContextLib.sol"; -import {IFlowV5} from "src/interface/IFlowV5.sol"; +import {IFlowV5, RAIN_FLOW_SENTINEL} from "src/interface/IFlowV5.sol"; +import {Sentinel} from "rain.solmem/lib/LibStackSentinel.sol"; import {EvaluableV2, SignedContextV1} from "rain.interpreter.interface/interface/IInterpreterCallerV2.sol"; import {InvalidSignature} from "rain.interpreter.interface/lib/caller/LibContext.sol"; +import {LibStackGeneration} from "test/lib/LibStackGeneration.sol"; contract FlowSignedContextTest is FlowTest { using SignContextLib for Vm; @@ -32,7 +34,8 @@ contract FlowSignedContextTest is FlowTest { signedContexts[0] = vm.signContext(aliceKey, aliceKey, context0); signedContexts[1] = vm.signContext(aliceKey, aliceKey, context1); - uint256[] memory stack = generateFlowStack(transferEmpty()); + uint256[] memory stack = + LibStackGeneration.generateFlowStack(Sentinel.unwrap(RAIN_FLOW_SENTINEL), transferEmpty()); interpreterEval2MockCall(stack, new uint256[](0)); flow.flow(evaluable, new uint256[](0), signedContexts); @@ -63,7 +66,8 @@ contract FlowSignedContextTest is FlowTest { SignedContextV1[] memory signedContext = new SignedContextV1[](1); signedContext[0] = vm.signContext(aliceKey, aliceKey, context0); - uint256[] memory stack = generateFlowStack(transferEmpty()); + uint256[] memory stack = + LibStackGeneration.generateFlowStack(Sentinel.unwrap(RAIN_FLOW_SENTINEL), transferEmpty()); interpreterEval2MockCall(stack, new uint256[](0)); flow.flow(evaluable, new uint256[](0), signedContext); diff --git a/test/src/concrete/Flow.time.t.sol b/test/src/concrete/Flow.time.t.sol index 055cfa33..a3ac6519 100644 --- a/test/src/concrete/Flow.time.t.sol +++ b/test/src/concrete/Flow.time.t.sol @@ -3,10 +3,12 @@ pragma solidity =0.8.25; import {FlowTest} from "test/abstract/FlowTest.sol"; -import {IFlowV5} from "src/interface/IFlowV5.sol"; +import {IFlowV5, RAIN_FLOW_SENTINEL} from "src/interface/IFlowV5.sol"; +import {Sentinel} from "rain.solmem/lib/LibStackSentinel.sol"; import {EvaluableV2, SignedContextV1} from "rain.interpreter.interface/interface/IInterpreterCallerV2.sol"; import {DEFAULT_STATE_NAMESPACE} from "rain.interpreter.interface/interface/IInterpreterV2.sol"; import {IInterpreterStoreV2} from "rain.interpreter.interface/interface/IInterpreterStoreV2.sol"; +import {LibStackGeneration} from "test/lib/LibStackGeneration.sol"; contract FlowTimeTest is FlowTest { function testFlowBasicFlowTime(uint256[] memory writeToStore) public { @@ -14,7 +16,8 @@ contract FlowTimeTest is FlowTest { (IFlowV5 flow, EvaluableV2 memory evaluable) = deployFlow(); - uint256[] memory stack = generateFlowStack(transferEmpty()); + uint256[] memory stack = + LibStackGeneration.generateFlowStack(Sentinel.unwrap(RAIN_FLOW_SENTINEL), transferEmpty()); interpreterEval2MockCall(stack, writeToStore); diff --git a/test/src/concrete/Flow.transfer.t.sol b/test/src/concrete/Flow.transfer.t.sol index 5e58881e..8d8621c1 100644 --- a/test/src/concrete/Flow.transfer.t.sol +++ b/test/src/concrete/Flow.transfer.t.sol @@ -190,8 +190,10 @@ contract FlowTransferTest is FlowTest { erc20Transfers[0] = ERC20Transfer({token: TOKEN_A, from: bob, to: address(flow), amount: erc20Amount}); erc20Transfers[1] = ERC20Transfer({token: TOKEN_B, from: address(flow), to: alice, amount: erc20Amount}); - uint256[] memory stack = - generateFlowStack(FlowTransferV1(erc20Transfers, new ERC721Transfer[](0), new ERC1155Transfer[](0))); + uint256[] memory stack = LibStackGeneration.generateFlowStack( + Sentinel.unwrap(RAIN_FLOW_SENTINEL), + FlowTransferV1(erc20Transfers, new ERC721Transfer[](0), new ERC1155Transfer[](0)) + ); interpreterEval2MockCall(stack, new uint256[](0)); } @@ -207,8 +209,10 @@ contract FlowTransferTest is FlowTest { erc20Transfers[1] = ERC20Transfer({token: TOKEN_B, from: bob, to: alice, amount: erc20Amount}); vm.mockCall(TOKEN_A, abi.encodeWithSelector(IERC20.transferFrom.selector), abi.encode(true)); - uint256[] memory stack = - generateFlowStack(FlowTransferV1(erc20Transfers, new ERC721Transfer[](0), new ERC1155Transfer[](0))); + uint256[] memory stack = LibStackGeneration.generateFlowStack( + Sentinel.unwrap(RAIN_FLOW_SENTINEL), + FlowTransferV1(erc20Transfers, new ERC721Transfer[](0), new ERC1155Transfer[](0)) + ); interpreterEval2MockCall(stack, new uint256[](0)); } @@ -240,8 +244,10 @@ contract FlowTransferTest is FlowTest { erc721Transfers[0] = ERC721Transfer({token: TOKEN_A, from: bob, to: address(flow), id: erc721TokenId}); erc721Transfers[1] = ERC721Transfer({token: TOKEN_B, from: address(flow), to: alice, id: erc721TokenId}); - uint256[] memory stack = - generateFlowStack(FlowTransferV1(new ERC20Transfer[](0), erc721Transfers, new ERC1155Transfer[](0))); + uint256[] memory stack = LibStackGeneration.generateFlowStack( + Sentinel.unwrap(RAIN_FLOW_SENTINEL), + FlowTransferV1(new ERC20Transfer[](0), erc721Transfers, new ERC1155Transfer[](0)) + ); interpreterEval2MockCall(stack, new uint256[](0)); } @@ -284,8 +290,10 @@ contract FlowTransferTest is FlowTest { token: TOKEN_B, from: address(flow), to: alice, id: erc1155InTokenId, amount: erc1155InAmount }); - uint256[] memory stack = - generateFlowStack(FlowTransferV1(new ERC20Transfer[](0), new ERC721Transfer[](0), erc1155Transfers)); + uint256[] memory stack = LibStackGeneration.generateFlowStack( + Sentinel.unwrap(RAIN_FLOW_SENTINEL), + FlowTransferV1(new ERC20Transfer[](0), new ERC721Transfer[](0), erc1155Transfers) + ); interpreterEval2MockCall(stack, new uint256[](0)); } @@ -459,7 +467,8 @@ contract FlowTransferTest is FlowTest { vm.store(address(STORE), bytes32(uint256(2)), evalSlot2); // Eval2 returns non-empty kvs so LibFlow.flow takes the `set` branch. - uint256[] memory stack = LibStackGeneration.generateFlowStack(Sentinel.unwrap(RAIN_FLOW_SENTINEL), transferEmpty()); + uint256[] memory stack = + LibStackGeneration.generateFlowStack(Sentinel.unwrap(RAIN_FLOW_SENTINEL), transferEmpty()); uint256[] memory writes = new uint256[](2); writes[0] = writeKey; writes[1] = writeValue; @@ -495,8 +504,7 @@ contract FlowTransferTest is FlowTest { recipient.setEvaluable(evaluable); ERC721Transfer[] memory erc721Transfers = new ERC721Transfer[](1); - erc721Transfers[0] = - ERC721Transfer({token: TOKEN_B, from: address(flow), to: address(recipient), id: tokenId}); + erc721Transfers[0] = ERC721Transfer({token: TOKEN_B, from: address(flow), to: address(recipient), id: tokenId}); uint256[] memory stack = LibStackGeneration.generateFlowStack( Sentinel.unwrap(RAIN_FLOW_SENTINEL), @@ -530,13 +538,8 @@ contract FlowTransferTest is FlowTest { recipient.setEvaluable(evaluable); ERC1155Transfer[] memory erc1155Transfers = new ERC1155Transfer[](1); - erc1155Transfers[0] = ERC1155Transfer({ - token: TOKEN_C, - from: address(flow), - to: address(recipient), - id: tokenId, - amount: amount - }); + erc1155Transfers[0] = + ERC1155Transfer({token: TOKEN_C, from: address(flow), to: address(recipient), id: tokenId, amount: amount}); uint256[] memory stack = LibStackGeneration.generateFlowStack( Sentinel.unwrap(RAIN_FLOW_SENTINEL), From b5df7c4cb3b61ab9d835c0606077a84bfa33e329 Mon Sep 17 00:00:00 2001 From: thedavidmeister Date: Sat, 9 May 2026 19:22:22 +0400 Subject: [PATCH 3/3] Revert "delete FlowUtilsAbstractTest, inline pass-through wrappers at callsites" This reverts commit 0754b8045ae2514ab77770de803403ce48855541. --- test/abstract/FlowTest.sol | 4 +-- test/abstract/FlowUtilsAbstractTest.sol | 35 +++++++++++++++++++ test/src/concrete/Flow.construction.t.sol | 3 +- test/src/concrete/Flow.context.t.sol | 7 ++-- test/src/concrete/Flow.expression.t.sol | 3 +- test/src/concrete/Flow.preview.t.sol | 3 +- test/src/concrete/Flow.signedContext.t.sol | 10 ++---- test/src/concrete/Flow.time.t.sol | 7 ++-- test/src/concrete/Flow.transfer.t.sol | 39 ++++++++++------------ 9 files changed, 65 insertions(+), 46 deletions(-) create mode 100644 test/abstract/FlowUtilsAbstractTest.sol diff --git a/test/abstract/FlowTest.sol b/test/abstract/FlowTest.sol index 1c31c52d..1c1d0186 100644 --- a/test/abstract/FlowTest.sol +++ b/test/abstract/FlowTest.sol @@ -3,7 +3,7 @@ pragma solidity ^0.8.25; import {Vm} from "forge-std/Test.sol"; -import {FlowTransferOperation} from "test/abstract/FlowTransferOperation.sol"; +import {FlowUtilsAbstractTest} from "test/abstract/FlowUtilsAbstractTest.sol"; import {InterpreterMockTest} from "test/abstract/InterpreterMockTest.sol"; import {EvaluableConfigV3} from "rain.interpreter.interface/interface/IInterpreterCallerV2.sol"; import {EvaluableV2} from "rain.interpreter.interface/lib/caller/LibEvaluable.sol"; @@ -16,7 +16,7 @@ import {Flow} from "src/concrete/Flow.sol"; import {LibUint256Matrix} from "rain.solmem/lib/LibUint256Matrix.sol"; import {LibUint256Array} from "rain.solmem/lib/LibUint256Array.sol"; -abstract contract FlowTest is FlowTransferOperation, InterpreterMockTest { +abstract contract FlowTest is FlowUtilsAbstractTest, InterpreterMockTest { using LibLogHelper for Vm.Log[]; using LibStackGeneration for uint256; using Address for address; diff --git a/test/abstract/FlowUtilsAbstractTest.sol b/test/abstract/FlowUtilsAbstractTest.sol new file mode 100644 index 00000000..ec5a5467 --- /dev/null +++ b/test/abstract/FlowUtilsAbstractTest.sol @@ -0,0 +1,35 @@ +// SPDX-License-Identifier: LicenseRef-DCL-1.0 +// SPDX-FileCopyrightText: Copyright (c) 2020 Rain Open Source Software Ltd +pragma solidity ^0.8.25; + +import {Vm} from "forge-std/Test.sol"; + +import {FlowTransferV1, RAIN_FLOW_SENTINEL} from "src/interface/IFlowV5.sol"; +import {Sentinel} from "rain.solmem/lib/LibStackSentinel.sol"; +import {LibStackGeneration} from "test/lib/LibStackGeneration.sol"; +import {LibLogHelper} from "test/lib/LibLogHelper.sol"; +import {FlowTransferOperation} from "test/abstract/FlowTransferOperation.sol"; + +abstract contract FlowUtilsAbstractTest is FlowTransferOperation { + using LibStackGeneration for uint256; + using LibLogHelper for Vm.Log[]; + + // A temporary solution for a smooth transition to using libraries. + function generateFlowStack(FlowTransferV1 memory flowTransfer) internal pure returns (uint256[] memory stack) { + stack = Sentinel.unwrap(RAIN_FLOW_SENTINEL).generateFlowStack(flowTransfer); + } + + // A temporary solution for a smooth transition to using libraries. + function findEvent(Vm.Log[] memory logs, bytes32 eventSignature) internal pure returns (Vm.Log memory) { + return logs.findEvent(eventSignature); + } + + // A temporary solution for a smooth transition to using libraries. + function findEvents(Vm.Log[] memory logs, bytes32 eventSignature) + internal + pure + returns (Vm.Log[] memory foundLogs) + { + foundLogs = logs.findEvents(eventSignature); + } +} diff --git a/test/src/concrete/Flow.construction.t.sol b/test/src/concrete/Flow.construction.t.sol index 78d22019..03206941 100644 --- a/test/src/concrete/Flow.construction.t.sol +++ b/test/src/concrete/Flow.construction.t.sol @@ -7,7 +7,6 @@ import {Vm} from "forge-std/Test.sol"; import {EvaluableConfigV3} from "rain.interpreter.interface/interface/IInterpreterCallerV2.sol"; import {FlowTest} from "test/abstract/FlowTest.sol"; import {EmptyFlowConfig} from "src/error/ErrFlow.sol"; -import {LibLogHelper} from "test/lib/LibLogHelper.sol"; contract FlowConstructionTest is FlowTest { function testFlowConstructionEmptyConfigReverts() external { @@ -31,7 +30,7 @@ contract FlowConstructionTest is FlowTest { Vm.Log[] memory logs = vm.getRecordedLogs(); bytes32 eventSignature = keccak256("Initialize(address,(address,bytes,uint256[])[])"); - Vm.Log memory concreteEvent = LibLogHelper.findEvent(logs, eventSignature); + Vm.Log memory concreteEvent = findEvent(logs, eventSignature); (address sender, EvaluableConfigV3[] memory config) = abi.decode(concreteEvent.data, (address, EvaluableConfigV3[])); diff --git a/test/src/concrete/Flow.context.t.sol b/test/src/concrete/Flow.context.t.sol index 90615af4..6d30d27b 100644 --- a/test/src/concrete/Flow.context.t.sol +++ b/test/src/concrete/Flow.context.t.sol @@ -3,14 +3,12 @@ pragma solidity =0.8.25; import {FlowTest} from "test/abstract/FlowTest.sol"; -import {IFlowV5, RAIN_FLOW_SENTINEL} from "src/interface/IFlowV5.sol"; -import {Sentinel} from "rain.solmem/lib/LibStackSentinel.sol"; +import {IFlowV5} from "src/interface/IFlowV5.sol"; import {EvaluableV2} from "rain.interpreter.interface/lib/caller/LibEvaluable.sol"; import {FLOW_MAX_OUTPUTS, FLOW_ENTRYPOINT} from "src/concrete/Flow.sol"; import {LibEncodedDispatch} from "rain.interpreter.interface/lib/caller/LibEncodedDispatch.sol"; import {SignedContextV1} from "rain.interpreter.interface/interface/IInterpreterCallerV2.sol"; import {LibContextWrapper} from "test/lib/LibContextWrapper.sol"; -import {LibStackGeneration} from "test/lib/LibStackGeneration.sol"; contract FlowContextTest is FlowTest { /** @@ -28,8 +26,7 @@ contract FlowContextTest is FlowTest { LibContextWrapper.buildAndSetContext(callerContext, signedContext, address(alice), address(flow)); { - uint256[] memory stack = - LibStackGeneration.generateFlowStack(Sentinel.unwrap(RAIN_FLOW_SENTINEL), transferEmpty()); + uint256[] memory stack = generateFlowStack(transferEmpty()); interpreterEval2MockCall(stack, new uint256[](0)); diff --git a/test/src/concrete/Flow.expression.t.sol b/test/src/concrete/Flow.expression.t.sol index b7970c79..4ee547d0 100644 --- a/test/src/concrete/Flow.expression.t.sol +++ b/test/src/concrete/Flow.expression.t.sol @@ -12,7 +12,6 @@ import {LibUint256Matrix} from "rain.solmem/lib/LibUint256Matrix.sol"; import {LibContextWrapper} from "test/lib/LibContextWrapper.sol"; import {IInterpreterCallerV2} from "rain.interpreter.interface/interface/IInterpreterCallerV2.sol"; import {SignContextLib} from "test/lib/SignContextLib.sol"; -import {LibLogHelper} from "test/lib/LibLogHelper.sol"; contract FlowExpressionTest is FlowTest, IInterpreterCallerV2 { using SignContextLib for Vm; @@ -75,7 +74,7 @@ contract FlowExpressionTest is FlowTest, IInterpreterCallerV2 { ); Vm.Log[] memory logs = vm.getRecordedLogs(); - Vm.Log memory log = LibLogHelper.findEvent(logs, keccak256("Context(address,uint256[][])")); + Vm.Log memory log = findEvent(logs, keccak256("Context(address,uint256[][])")); (address sender, uint256[][] memory buildContextOutput) = abi.decode(log.data, (address, uint256[][])); assertEq(sender, address(this), "wrong sender"); diff --git a/test/src/concrete/Flow.preview.t.sol b/test/src/concrete/Flow.preview.t.sol index bb086c86..fd4d127d 100644 --- a/test/src/concrete/Flow.preview.t.sol +++ b/test/src/concrete/Flow.preview.t.sol @@ -14,7 +14,6 @@ import { } from "src/interface/IFlowV5.sol"; import {EvaluableV2} from "rain.interpreter.interface/lib/caller/LibEvaluable.sol"; import {LibEvaluable} from "rain.interpreter.interface/lib/caller/LibEvaluable.sol"; -import {LibStackGeneration} from "test/lib/LibStackGeneration.sol"; contract FlowPreviewTest is FlowTest { using LibEvaluable for EvaluableV2; @@ -179,7 +178,7 @@ contract FlowPreviewTest is FlowTest { FlowTransferV1 memory flowTransfer = FlowTransferV1(new ERC20Transfer[](0), new ERC721Transfer[](0), new ERC1155Transfer[](0)); - uint256[] memory stack = LibStackGeneration.generateFlowStack(Sentinel.unwrap(RAIN_FLOW_SENTINEL), flowTransfer); + uint256[] memory stack = generateFlowStack(flowTransfer); assertEq( keccak256(abi.encode(flowTransfer)), keccak256(abi.encode(flow.stackToFlow(stack))), "wrong compare Structs" ); diff --git a/test/src/concrete/Flow.signedContext.t.sol b/test/src/concrete/Flow.signedContext.t.sol index 2516aaf0..beabbeae 100644 --- a/test/src/concrete/Flow.signedContext.t.sol +++ b/test/src/concrete/Flow.signedContext.t.sol @@ -5,11 +5,9 @@ pragma solidity =0.8.25; import {Vm} from "forge-std/Test.sol"; import {FlowTest} from "test/abstract/FlowTest.sol"; import {SignContextLib} from "test/lib/SignContextLib.sol"; -import {IFlowV5, RAIN_FLOW_SENTINEL} from "src/interface/IFlowV5.sol"; -import {Sentinel} from "rain.solmem/lib/LibStackSentinel.sol"; +import {IFlowV5} from "src/interface/IFlowV5.sol"; import {EvaluableV2, SignedContextV1} from "rain.interpreter.interface/interface/IInterpreterCallerV2.sol"; import {InvalidSignature} from "rain.interpreter.interface/lib/caller/LibContext.sol"; -import {LibStackGeneration} from "test/lib/LibStackGeneration.sol"; contract FlowSignedContextTest is FlowTest { using SignContextLib for Vm; @@ -34,8 +32,7 @@ contract FlowSignedContextTest is FlowTest { signedContexts[0] = vm.signContext(aliceKey, aliceKey, context0); signedContexts[1] = vm.signContext(aliceKey, aliceKey, context1); - uint256[] memory stack = - LibStackGeneration.generateFlowStack(Sentinel.unwrap(RAIN_FLOW_SENTINEL), transferEmpty()); + uint256[] memory stack = generateFlowStack(transferEmpty()); interpreterEval2MockCall(stack, new uint256[](0)); flow.flow(evaluable, new uint256[](0), signedContexts); @@ -66,8 +63,7 @@ contract FlowSignedContextTest is FlowTest { SignedContextV1[] memory signedContext = new SignedContextV1[](1); signedContext[0] = vm.signContext(aliceKey, aliceKey, context0); - uint256[] memory stack = - LibStackGeneration.generateFlowStack(Sentinel.unwrap(RAIN_FLOW_SENTINEL), transferEmpty()); + uint256[] memory stack = generateFlowStack(transferEmpty()); interpreterEval2MockCall(stack, new uint256[](0)); flow.flow(evaluable, new uint256[](0), signedContext); diff --git a/test/src/concrete/Flow.time.t.sol b/test/src/concrete/Flow.time.t.sol index a3ac6519..055cfa33 100644 --- a/test/src/concrete/Flow.time.t.sol +++ b/test/src/concrete/Flow.time.t.sol @@ -3,12 +3,10 @@ pragma solidity =0.8.25; import {FlowTest} from "test/abstract/FlowTest.sol"; -import {IFlowV5, RAIN_FLOW_SENTINEL} from "src/interface/IFlowV5.sol"; -import {Sentinel} from "rain.solmem/lib/LibStackSentinel.sol"; +import {IFlowV5} from "src/interface/IFlowV5.sol"; import {EvaluableV2, SignedContextV1} from "rain.interpreter.interface/interface/IInterpreterCallerV2.sol"; import {DEFAULT_STATE_NAMESPACE} from "rain.interpreter.interface/interface/IInterpreterV2.sol"; import {IInterpreterStoreV2} from "rain.interpreter.interface/interface/IInterpreterStoreV2.sol"; -import {LibStackGeneration} from "test/lib/LibStackGeneration.sol"; contract FlowTimeTest is FlowTest { function testFlowBasicFlowTime(uint256[] memory writeToStore) public { @@ -16,8 +14,7 @@ contract FlowTimeTest is FlowTest { (IFlowV5 flow, EvaluableV2 memory evaluable) = deployFlow(); - uint256[] memory stack = - LibStackGeneration.generateFlowStack(Sentinel.unwrap(RAIN_FLOW_SENTINEL), transferEmpty()); + uint256[] memory stack = generateFlowStack(transferEmpty()); interpreterEval2MockCall(stack, writeToStore); diff --git a/test/src/concrete/Flow.transfer.t.sol b/test/src/concrete/Flow.transfer.t.sol index 8d8621c1..5e58881e 100644 --- a/test/src/concrete/Flow.transfer.t.sol +++ b/test/src/concrete/Flow.transfer.t.sol @@ -190,10 +190,8 @@ contract FlowTransferTest is FlowTest { erc20Transfers[0] = ERC20Transfer({token: TOKEN_A, from: bob, to: address(flow), amount: erc20Amount}); erc20Transfers[1] = ERC20Transfer({token: TOKEN_B, from: address(flow), to: alice, amount: erc20Amount}); - uint256[] memory stack = LibStackGeneration.generateFlowStack( - Sentinel.unwrap(RAIN_FLOW_SENTINEL), - FlowTransferV1(erc20Transfers, new ERC721Transfer[](0), new ERC1155Transfer[](0)) - ); + uint256[] memory stack = + generateFlowStack(FlowTransferV1(erc20Transfers, new ERC721Transfer[](0), new ERC1155Transfer[](0))); interpreterEval2MockCall(stack, new uint256[](0)); } @@ -209,10 +207,8 @@ contract FlowTransferTest is FlowTest { erc20Transfers[1] = ERC20Transfer({token: TOKEN_B, from: bob, to: alice, amount: erc20Amount}); vm.mockCall(TOKEN_A, abi.encodeWithSelector(IERC20.transferFrom.selector), abi.encode(true)); - uint256[] memory stack = LibStackGeneration.generateFlowStack( - Sentinel.unwrap(RAIN_FLOW_SENTINEL), - FlowTransferV1(erc20Transfers, new ERC721Transfer[](0), new ERC1155Transfer[](0)) - ); + uint256[] memory stack = + generateFlowStack(FlowTransferV1(erc20Transfers, new ERC721Transfer[](0), new ERC1155Transfer[](0))); interpreterEval2MockCall(stack, new uint256[](0)); } @@ -244,10 +240,8 @@ contract FlowTransferTest is FlowTest { erc721Transfers[0] = ERC721Transfer({token: TOKEN_A, from: bob, to: address(flow), id: erc721TokenId}); erc721Transfers[1] = ERC721Transfer({token: TOKEN_B, from: address(flow), to: alice, id: erc721TokenId}); - uint256[] memory stack = LibStackGeneration.generateFlowStack( - Sentinel.unwrap(RAIN_FLOW_SENTINEL), - FlowTransferV1(new ERC20Transfer[](0), erc721Transfers, new ERC1155Transfer[](0)) - ); + uint256[] memory stack = + generateFlowStack(FlowTransferV1(new ERC20Transfer[](0), erc721Transfers, new ERC1155Transfer[](0))); interpreterEval2MockCall(stack, new uint256[](0)); } @@ -290,10 +284,8 @@ contract FlowTransferTest is FlowTest { token: TOKEN_B, from: address(flow), to: alice, id: erc1155InTokenId, amount: erc1155InAmount }); - uint256[] memory stack = LibStackGeneration.generateFlowStack( - Sentinel.unwrap(RAIN_FLOW_SENTINEL), - FlowTransferV1(new ERC20Transfer[](0), new ERC721Transfer[](0), erc1155Transfers) - ); + uint256[] memory stack = + generateFlowStack(FlowTransferV1(new ERC20Transfer[](0), new ERC721Transfer[](0), erc1155Transfers)); interpreterEval2MockCall(stack, new uint256[](0)); } @@ -467,8 +459,7 @@ contract FlowTransferTest is FlowTest { vm.store(address(STORE), bytes32(uint256(2)), evalSlot2); // Eval2 returns non-empty kvs so LibFlow.flow takes the `set` branch. - uint256[] memory stack = - LibStackGeneration.generateFlowStack(Sentinel.unwrap(RAIN_FLOW_SENTINEL), transferEmpty()); + uint256[] memory stack = LibStackGeneration.generateFlowStack(Sentinel.unwrap(RAIN_FLOW_SENTINEL), transferEmpty()); uint256[] memory writes = new uint256[](2); writes[0] = writeKey; writes[1] = writeValue; @@ -504,7 +495,8 @@ contract FlowTransferTest is FlowTest { recipient.setEvaluable(evaluable); ERC721Transfer[] memory erc721Transfers = new ERC721Transfer[](1); - erc721Transfers[0] = ERC721Transfer({token: TOKEN_B, from: address(flow), to: address(recipient), id: tokenId}); + erc721Transfers[0] = + ERC721Transfer({token: TOKEN_B, from: address(flow), to: address(recipient), id: tokenId}); uint256[] memory stack = LibStackGeneration.generateFlowStack( Sentinel.unwrap(RAIN_FLOW_SENTINEL), @@ -538,8 +530,13 @@ contract FlowTransferTest is FlowTest { recipient.setEvaluable(evaluable); ERC1155Transfer[] memory erc1155Transfers = new ERC1155Transfer[](1); - erc1155Transfers[0] = - ERC1155Transfer({token: TOKEN_C, from: address(flow), to: address(recipient), id: tokenId, amount: amount}); + erc1155Transfers[0] = ERC1155Transfer({ + token: TOKEN_C, + from: address(flow), + to: address(recipient), + id: tokenId, + amount: amount + }); uint256[] memory stack = LibStackGeneration.generateFlowStack( Sentinel.unwrap(RAIN_FLOW_SENTINEL),