Skip to content

Commit

Permalink
Merge pull request #135 from rainlanguage/131-flow-erc1155-signedcont…
Browse files Browse the repository at this point in the history
…ext-test-should-validate-multiple-signed-contexts

131 flow erc1155 signedcontext test should validate multiple signed contexts
  • Loading branch information
thedavidmeister authored Aug 12, 2024
2 parents dcbaadf + eb300a4 commit 5d46c1a
Show file tree
Hide file tree
Showing 3 changed files with 116 additions and 3 deletions.
44 changes: 44 additions & 0 deletions test/abstract/FlowERC1155Test.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
// SPDX-License-Identifier: CAL
pragma solidity ^0.8.18;

import {Vm} from "forge-std/Test.sol";
import {FlowUtilsAbstractTest} from "test/abstract/FlowUtilsAbstractTest.sol";
import {InterpreterMockTest} from "test/abstract/InterpreterMockTest.sol";
import {IFlowERC1155V5, FlowERC1155ConfigV3} from "src/interface/unstable/IFlowERC1155V5.sol";
import {EvaluableConfigV3} from "rain.interpreter.interface/interface/IInterpreterCallerV2.sol";
import {STUB_EXPRESSION_BYTECODE} from "./TestConstants.sol";
import {EvaluableV2} from "rain.interpreter.interface/lib/caller/LibEvaluable.sol";
import {CloneFactory} from "rain.factory/src/concrete/CloneFactory.sol";
import {FlowERC1155} from "../../src/concrete/erc1155/FlowERC1155.sol";

abstract contract FlowERC1155Test is FlowUtilsAbstractTest, InterpreterMockTest {
CloneFactory internal immutable iCloneFactory;
IFlowERC1155V5 internal immutable iFlowImplementation;

constructor() {
vm.pauseGasMetering();
iCloneFactory = new CloneFactory();
iFlowImplementation = new FlowERC1155();
vm.resumeGasMetering();
}

function deployIFlowERC1155V5(string memory uri)
internal
returns (IFlowERC1155V5 flowErc1155, EvaluableV2 memory evaluable)
{
expressionDeployerDeployExpression2MockCall(address(0), bytes(hex"0006"));
// Create the evaluableConfig
EvaluableConfigV3 memory evaluableConfig =
EvaluableConfigV3(iDeployer, STUB_EXPRESSION_BYTECODE, new uint256[](0));
// Create the flowConfig array with one entry
EvaluableConfigV3[] memory flowConfigArray = new EvaluableConfigV3[](1);
flowConfigArray[0] = evaluableConfig;
// Initialize the FlowERC1155ConfigV3 struct
FlowERC1155ConfigV3 memory flowErc1155Config = FlowERC1155ConfigV3(uri, evaluableConfig, flowConfigArray);
vm.recordLogs();
flowErc1155 = IFlowERC1155V5(iCloneFactory.clone(address(iFlowImplementation), abi.encode(flowErc1155Config)));
Vm.Log[] memory logs = vm.getRecordedLogs();
Vm.Log memory concreteEvent = findEvent(logs, keccak256("FlowInitialized(address,(address,address,address))"));
(, evaluable) = abi.decode(concreteEvent.data, (address, EvaluableV2));
}
}
69 changes: 69 additions & 0 deletions test/concrete/flowErc1155/FlowSignedContextTest.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
// SPDX-License-Identifier: CAL
pragma solidity ^0.8.19;

import {Test, Vm} from "forge-std/Test.sol";
import {FlowERC1155} from "../../../src/concrete/erc1155/FlowERC1155.sol";
import {
FlowUtilsAbstractTest,
ERC20Transfer,
ERC721Transfer,
ERC1155Transfer,
ERC1155SupplyChange
} from "test/abstract/FlowUtilsAbstractTest.sol";
import {IFlowERC1155V5} from "../../../src/interface/unstable/IFlowERC1155V5.sol";
import {EvaluableV2, SignedContextV1} from "rain.interpreter.interface/interface/IInterpreterCallerV2.sol";
import {InvalidSignature} from "rain.interpreter.interface/lib/caller/LibContext.sol";
import {FlowERC1155Test} from "../../abstract/FlowERC1155Test.sol";
import {SignContextLib} from "test/lib/SignContextLib.sol";

contract FlowSignedContextTest is FlowUtilsAbstractTest, FlowERC1155Test {
using SignContextLib for Vm;

/// Should validate multiple signed contexts
function testValidateMultipleSignedContexts(
string memory uri,
uint256[] memory context0,
uint256[] memory context1,
uint256 fuzzedKeyAlice,
uint256 fuzzedKeyBob
) public {
vm.assume(fuzzedKeyBob != fuzzedKeyAlice);
(IFlowERC1155V5 erc1155Flow, EvaluableV2 memory evaluable) = deployIFlowERC1155V5(uri);

// Ensure the fuzzed key is within the valid range for secp256k1
uint256 aliceKey = (fuzzedKeyAlice % (SECP256K1_ORDER - 1)) + 1;
uint256 bobKey = (fuzzedKeyBob % (SECP256K1_ORDER - 1)) + 1;

SignedContextV1[] memory signedContexts = new SignedContextV1[](2);

signedContexts[0] = vm.signContext(aliceKey, aliceKey, context0);
signedContexts[1] = vm.signContext(aliceKey, aliceKey, context1);

uint256[] memory stack = generateFlowERC1155Stack(
new ERC1155Transfer[](0),
new ERC721Transfer[](0),
new ERC20Transfer[](0),
new ERC1155SupplyChange[](0),
new ERC1155SupplyChange[](0)
);
interpreterEval2MockCall(stack, new uint256[](0));
erc1155Flow.flow(evaluable, new uint256[](0), signedContexts);

// With bad signature in second signed context
SignedContextV1[] memory signedContexts1 = new SignedContextV1[](2);
signedContexts1[0] = vm.signContext(aliceKey, aliceKey, context0);
signedContexts1[1] = vm.signContext(aliceKey, bobKey, context1);

uint256[] memory stack1 = generateFlowERC1155Stack(
new ERC1155Transfer[](0),
new ERC721Transfer[](0),
new ERC20Transfer[](0),
new ERC1155SupplyChange[](0),
new ERC1155SupplyChange[](0)
);
interpreterEval2MockCall(stack1, new uint256[](0));

vm.expectRevert(abi.encodeWithSelector(InvalidSignature.selector, 1));
erc1155Flow.flow(evaluable, new uint256[](0), signedContexts1);
}
}
6 changes: 3 additions & 3 deletions test/lib/SignContextLib.sol
Original file line number Diff line number Diff line change
Expand Up @@ -7,23 +7,23 @@ import {ECDSAUpgradeable as ECDSA} from "openzeppelin/utils/cryptography/ECDSAUp
import {SignedContextV1} from "rain.interpreter.interface/interface/IInterpreterCallerV2.sol";

library SignContextLib {
function signContext(Vm vm, uint256 privateKey, uint256[] memory context)
function signContext(Vm vm, uint256 signerPrivateKey, uint256 signaturePrivateKey, uint256[] memory context)
internal
pure
returns (SignedContextV1 memory)
{
SignedContextV1 memory signedContext;

// Store the signer's address in the struct
signedContext.signer = vm.addr(privateKey);
signedContext.signer = vm.addr(signerPrivateKey);
signedContext.context = context; // copy the context data into the struct

// Create a digest of the context data
bytes32 contextHash = keccak256(abi.encodePacked(context));
bytes32 digest = ECDSA.toEthSignedMessageHash(contextHash);

// Create the signature using the cheatCode 'sign'
(uint8 v, bytes32 r, bytes32 s) = vm.sign(privateKey, digest);
(uint8 v, bytes32 r, bytes32 s) = vm.sign(signaturePrivateKey, digest);
signedContext.signature = abi.encodePacked(r, s, v);

return signedContext;
Expand Down

0 comments on commit 5d46c1a

Please sign in to comment.