From 6ef88c4311aec4297e4e393848972450e8e134b0 Mon Sep 17 00:00:00 2001 From: thedavidmeister Date: Wed, 28 Feb 2024 07:22:12 +0400 Subject: [PATCH 01/13] wip on i9r int --- lib/rain.factory | 2 +- src/abstract/FlowCommon.sol | 17 ++++++++--------- 2 files changed, 9 insertions(+), 10 deletions(-) diff --git a/lib/rain.factory b/lib/rain.factory index e6babfcc..c6d66594 160000 --- a/lib/rain.factory +++ b/lib/rain.factory @@ -1 +1 @@ -Subproject commit e6babfcc5788bb387878d6915955228b2a4cfc70 +Subproject commit c6d66594f23e920d7a2605d22138be70af001739 diff --git a/src/abstract/FlowCommon.sol b/src/abstract/FlowCommon.sol index 41758ff8..2086a16a 100644 --- a/src/abstract/FlowCommon.sol +++ b/src/abstract/FlowCommon.sol @@ -3,8 +3,8 @@ pragma solidity =0.8.19; import {LibUint256Array} from "rain.solmem/lib/LibUint256Array.sol"; import {Pointer} from "rain.solmem/lib/LibPointer.sol"; -import {IInterpreterCallerV2, SignedContextV1} from "rain.interpreter/src/interface/IInterpreterCallerV2.sol"; -import {LibEncodedDispatch} from "rain.interpreter/src/lib/caller/LibEncodedDispatch.sol"; +import {IInterpreterCallerV2, SignedContextV1} from "rain.interpreter.interface/interface/IInterpreterCallerV2.sol"; +import {LibEncodedDispatch} from "rain.interpreter.interface/lib/caller/LibEncodedDispatch.sol"; import {LibContext} from "rain.interpreter/src/lib/caller/LibContext.sol"; import {UnregisteredFlow, MIN_FLOW_SENTINELS} from "../interface/unstable/IFlowV4.sol"; import { @@ -14,11 +14,10 @@ import { import { LibEvaluable, Evaluable, - EvaluableConfigV2, + EvaluableConfigV3, DEFAULT_STATE_NAMESPACE } from "rain.interpreter/src/lib/caller/LibEvaluable.sol"; -import {SourceIndex, IInterpreterV1} from "rain.interpreter/src/interface/IInterpreterV1.sol"; -import {IInterpreterStoreV1} from "rain.interpreter/src/interface/IInterpreterStoreV1.sol"; +import {SourceIndexV2, IInterpreterV2, IInterpreterStoreV2} from "rain.interpreter.interface/interface/unstable/IInterpreterV2.sol"; import {MulticallUpgradeable as Multicall} from "openzeppelin-contracts-upgradeable/contracts/utils/MulticallUpgradeable.sol"; @@ -41,7 +40,7 @@ error BadMinStackLength(uint256 flowMinOutputs); /// @dev The entrypoint for a flow is always `0` because each flow has its own /// evaluable with its own entrypoint. Running multiple flows involves evaluating /// several expressions in sequence. -SourceIndex constant FLOW_ENTRYPOINT = SourceIndex.wrap(0); +SourceIndexV2 constant FLOW_ENTRYPOINT = SourceIndexV2.wrap(0); /// @dev There is no maximum number of outputs for a flow. Pragmatically gas will /// limit the number of outputs well before this limit is reached. uint16 constant FLOW_MAX_OUTPUTS = type(uint16).max; @@ -149,7 +148,7 @@ abstract contract FlowCommon is revert BadMinStackLength(flowMinOutputs); } - EvaluableConfigV2 memory config; + EvaluableConfigV3 memory config; Evaluable memory evaluable; // Every evaluable MUST deploy cleanly (e.g. pass integrity checks) // otherwise the entire initialization will fail. @@ -161,9 +160,9 @@ abstract contract FlowCommon is // Reentrancy is just one of many ways that a malicious deployer // can cause problems, and it's probably the least of your // worries if you're using a malicious deployer. - (IInterpreterV1 interpreter, IInterpreterStoreV1 store, address expression) = config + (IInterpreterV2 interpreter, IInterpreterStoreV2 store, address expression) = config .deployer - .deployExpression(config.bytecode, config.constants, LibUint256Array.arrayFrom(flowMinOutputs)); + .deployExpression2(config.bytecode, config.constants, LibUint256Array.arrayFrom(flowMinOutputs)); evaluable = Evaluable(interpreter, store, expression); // There's no way to set this mapping before the external // contract call because the output of the external contract From 29f72fe635732d80178f2d2d5a1c10ba4b93aa25 Mon Sep 17 00:00:00 2001 From: thedavidmeister Date: Wed, 28 Feb 2024 08:06:01 +0400 Subject: [PATCH 02/13] wip on i9r bump --- src/abstract/FlowCommon.sol | 50 +++++++------------ src/concrete/basic/Flow.sol | 19 +++---- src/concrete/erc1155/FlowERC1155.sol | 18 +++---- src/concrete/erc20/FlowERC20.sol | 18 +++---- src/concrete/erc721/FlowERC721.sol | 17 +++---- src/interface/IFlowERC1155V3.sol | 3 +- src/interface/IFlowERC20V3.sol | 4 +- src/interface/IFlowERC721V3.sol | 4 +- src/interface/IFlowV3.sol | 5 +- .../deprecated/v1/IFlowERC1155V1.sol | 4 +- src/interface/deprecated/v1/IFlowERC20V1.sol | 4 +- src/interface/deprecated/v1/IFlowERC721V1.sol | 4 +- src/interface/deprecated/v1/IFlowV1.sol | 4 +- .../deprecated/v2/IFlowERC1155V2.sol | 4 +- src/interface/deprecated/v2/IFlowERC20V2.sol | 4 +- src/interface/deprecated/v2/IFlowERC721V2.sol | 4 +- src/interface/deprecated/v2/IFlowV2.sol | 4 +- src/interface/unstable/IFlowERC1155V4.sol | 4 +- src/interface/unstable/IFlowERC20V4.sol | 4 +- src/interface/unstable/IFlowERC721V4.sol | 4 +- src/interface/unstable/IFlowV4.sol | 8 +-- src/lib/LibFlow.sol | 5 +- 22 files changed, 87 insertions(+), 108 deletions(-) diff --git a/src/abstract/FlowCommon.sol b/src/abstract/FlowCommon.sol index 2086a16a..fea5f9c1 100644 --- a/src/abstract/FlowCommon.sol +++ b/src/abstract/FlowCommon.sol @@ -3,22 +3,21 @@ pragma solidity =0.8.19; import {LibUint256Array} from "rain.solmem/lib/LibUint256Array.sol"; import {Pointer} from "rain.solmem/lib/LibPointer.sol"; -import {IInterpreterCallerV2, SignedContextV1} from "rain.interpreter.interface/interface/IInterpreterCallerV2.sol"; +import { + IInterpreterCallerV2, + SignedContextV1, + EvaluableConfigV3 +} from "rain.interpreter.interface/interface/IInterpreterCallerV2.sol"; import {LibEncodedDispatch} from "rain.interpreter.interface/lib/caller/LibEncodedDispatch.sol"; -import {LibContext} from "rain.interpreter/src/lib/caller/LibContext.sol"; +import {LibContext} from "rain.interpreter.interface/lib/caller/LibContext.sol"; import {UnregisteredFlow, MIN_FLOW_SENTINELS} from "../interface/unstable/IFlowV4.sol"; +import {LibEvaluable, EvaluableV2} from "rain.interpreter.interface/lib/caller/LibEvaluable.sol"; import { - DeployerDiscoverableMetaV2, - DeployerDiscoverableMetaV2ConstructionConfig -} from "rain.interpreter/src/abstract/DeployerDiscoverableMetaV2.sol"; -import { - LibEvaluable, - Evaluable, - EvaluableConfigV3, + SourceIndexV2, + IInterpreterV2, + IInterpreterStoreV2, DEFAULT_STATE_NAMESPACE -} from "rain.interpreter/src/lib/caller/LibEvaluable.sol"; -import {SourceIndexV2, IInterpreterV2, IInterpreterStoreV2} from "rain.interpreter.interface/interface/unstable/IInterpreterV2.sol"; - +} from "rain.interpreter.interface/interface/unstable/IInterpreterV2.sol"; import {MulticallUpgradeable as Multicall} from "openzeppelin-contracts-upgradeable/contracts/utils/MulticallUpgradeable.sol"; import {ERC721HolderUpgradeable as ERC721Holder} from @@ -81,17 +80,10 @@ uint256 constant FLOW_IS_NOT_REGISTERED = 0; /// This is a known issue with `Multicall` so in the future, we may refactor /// `FlowCommon` to not use `Multicall` and instead implement flow batching /// directly in the flow contracts. -abstract contract FlowCommon is - ERC721Holder, - ERC1155Holder, - Multicall, - ReentrancyGuard, - IInterpreterCallerV2, - DeployerDiscoverableMetaV2 -{ +abstract contract FlowCommon is ERC721Holder, ERC1155Holder, Multicall, ReentrancyGuard, IInterpreterCallerV2 { using LibUint256Array for uint256[]; using LibUint256Matrix for uint256[]; - using LibEvaluable for Evaluable; + using LibEvaluable for EvaluableV2; /// @dev This mapping tracks all flows that are registered at initialization. /// This is used to ensure that only registered flows are evaluated. @@ -106,7 +98,7 @@ abstract contract FlowCommon is /// @param evaluable The evaluable of the flow that was registered. The hash /// of this evaluable is used as the key in `registeredFlows` so users MUST /// provide the same evaluable when they evaluate the flow. - event FlowInitialized(address sender, Evaluable evaluable); + event FlowInitialized(address sender, EvaluableV2 evaluable); /// Forwards config to `DeployerDiscoverableMetaV2` and disables /// initializers. The initializers are disabled because inheriting contracts @@ -115,11 +107,7 @@ abstract contract FlowCommon is /// in the implementation contract forces that the only way to initialize /// the contract is via. a proxy, which should also strongly encourage /// patterns that _atomically_ clone and initialize via. some factory. - /// @param metaHash As per `DeployerDiscoverableMetaV2`. - /// @param config As per `DeployerDiscoverableMetaV2`. - constructor(bytes32 metaHash, DeployerDiscoverableMetaV2ConstructionConfig memory config) - DeployerDiscoverableMetaV2(metaHash, config) - { + constructor() { _disableInitializers(); } @@ -130,7 +118,7 @@ abstract contract FlowCommon is /// movements at runtime for the inheriting contract. /// @param flowMinOutputs The minimum number of outputs for each flow. All /// flows share the same minimum number of outputs for simplicity. - function flowCommonInit(EvaluableConfigV2[] memory evaluableConfigs, uint256 flowMinOutputs) + function flowCommonInit(EvaluableConfigV3[] memory evaluableConfigs, uint256 flowMinOutputs) internal onlyInitializing { @@ -149,7 +137,7 @@ abstract contract FlowCommon is } EvaluableConfigV3 memory config; - Evaluable memory evaluable; + EvaluableV2 memory evaluable; // Every evaluable MUST deploy cleanly (e.g. pass integrity checks) // otherwise the entire initialization will fail. for (uint256 i = 0; i < evaluableConfigs.length; ++i) { @@ -163,7 +151,7 @@ abstract contract FlowCommon is (IInterpreterV2 interpreter, IInterpreterStoreV2 store, address expression) = config .deployer .deployExpression2(config.bytecode, config.constants, LibUint256Array.arrayFrom(flowMinOutputs)); - evaluable = Evaluable(interpreter, store, expression); + evaluable = EvaluableV2(interpreter, store, expression); // There's no way to set this mapping before the external // contract call because the output of the external contract // call is used to build the evaluable that we're registering. @@ -195,7 +183,7 @@ abstract contract FlowCommon is /// @return The top of the stack after evaluation. /// @return The key-value pairs that were emitted during evaluation. function _flowStack( - Evaluable memory evaluable, + EvaluableV2 memory evaluable, uint256[] memory callerContext, SignedContextV1[] memory signedContexts ) internal returns (Pointer, Pointer, uint256[] memory) { diff --git a/src/concrete/basic/Flow.sol b/src/concrete/basic/Flow.sol index c9931735..aa8503cf 100644 --- a/src/concrete/basic/Flow.sol +++ b/src/concrete/basic/Flow.sol @@ -2,19 +2,15 @@ pragma solidity =0.8.19; import {ICloneableV2, ICLONEABLE_V2_SUCCESS} from "rain.factory/src/interface/ICloneableV2.sol"; -import {FlowCommon, DeployerDiscoverableMetaV2ConstructionConfig, LibContext} from "../../abstract/FlowCommon.sol"; +import {FlowCommon, LibContext} from "../../abstract/FlowCommon.sol"; import {IFlowV4, MIN_FLOW_SENTINELS} from "../../interface/unstable/IFlowV4.sol"; import {LibFlow} from "../../lib/LibFlow.sol"; import {LibUint256Matrix} from "rain.solmem/lib/LibUint256Matrix.sol"; import {Pointer} from "rain.solmem/lib/LibPointer.sol"; import {LibUint256Array} from "rain.solmem/lib/LibUint256Array.sol"; -import {Evaluable, EvaluableConfigV2} from "rain.interpreter/src/lib/caller/LibEvaluable.sol"; +import {EvaluableV2} from "rain.interpreter.interface/lib/caller/LibEvaluable.sol"; import {FlowTransferV1} from "../../interface/unstable/IFlowV4.sol"; -import {SignedContextV1} from "rain.interpreter/src/interface/IInterpreterCallerV2.sol"; - -/// @dev The hash of the meta data expected to be passed to `FlowCommon`'s -/// constructor. -bytes32 constant CALLER_META_HASH = bytes32(0x95de68a447a477b8fab10701f1265b3e85a98b24710b3e40e6a96aa6d76263bc); +import {SignedContextV1, EvaluableConfigV3} from "rain.interpreter.interface/interface/IInterpreterCallerV2.sol"; /// @title Flow /// See `IFlowV4` docs. @@ -22,18 +18,15 @@ contract Flow is ICloneableV2, IFlowV4, FlowCommon { using LibUint256Matrix for uint256[]; using LibUint256Array for uint256[]; - /// Forwards to `FlowCommon` constructor. - constructor(DeployerDiscoverableMetaV2ConstructionConfig memory config) FlowCommon(CALLER_META_HASH, config) {} - /// Overloaded typed initialize function MUST revert with this error. /// As per `ICloneableV2` interface. - function initialize(EvaluableConfigV2[] memory) external pure { + function initialize(EvaluableConfigV3[] memory) external pure { revert InitializeSignatureFn(); } /// @inheritdoc ICloneableV2 function initialize(bytes calldata data) external initializer returns (bytes32) { - EvaluableConfigV2[] memory flowConfig = abi.decode(data, (EvaluableConfigV2[])); + EvaluableConfigV3[] memory flowConfig = abi.decode(data, (EvaluableConfigV3[])); emit Initialize(msg.sender, flowConfig); flowCommonInit(flowConfig, MIN_FLOW_SENTINELS); @@ -46,7 +39,7 @@ contract Flow is ICloneableV2, IFlowV4, FlowCommon { } /// @inheritdoc IFlowV4 - function flow(Evaluable memory evaluable, uint256[] memory callerContext, SignedContextV1[] memory signedContexts) + function flow(EvaluableV2 memory evaluable, uint256[] memory callerContext, SignedContextV1[] memory signedContexts) external virtual nonReentrant diff --git a/src/concrete/erc1155/FlowERC1155.sol b/src/concrete/erc1155/FlowERC1155.sol index f86aa2ce..53df6544 100644 --- a/src/concrete/erc1155/FlowERC1155.sol +++ b/src/concrete/erc1155/FlowERC1155.sol @@ -4,7 +4,7 @@ pragma solidity =0.8.19; import {ERC1155Upgradeable as ERC1155} from "openzeppelin-contracts-upgradeable/contracts/token/ERC1155/ERC1155Upgradeable.sol"; -import {LibEncodedDispatch, EncodedDispatch} from "rain.interpreter/src/lib/caller/LibEncodedDispatch.sol"; +import {LibEncodedDispatch, EncodedDispatch} from "rain.interpreter.interface/lib/caller/LibEncodedDispatch.sol"; import {Sentinel, LibStackSentinel} from "rain.solmem/lib/LibStackSentinel.sol"; import {ICloneableV2, ICLONEABLE_V2_SUCCESS} from "rain.factory/src/interface/ICloneableV2.sol"; import {LibUint256Array} from "rain.solmem/lib/LibUint256Array.sol"; @@ -22,16 +22,16 @@ import { FLOW_ERC1155_MIN_FLOW_SENTINELS } from "../../interface/unstable/IFlowERC1155V4.sol"; import {LibBytecode} from "rain.interpreter.interface/lib/bytecode/LibBytecode.sol"; -import {IInterpreterV1} from "rain.interpreter/src/interface/IInterpreterV1.sol"; -import {IInterpreterStoreV1} from "rain.interpreter/src/interface/IInterpreterStoreV1.sol"; -import {Evaluable, DEFAULT_STATE_NAMESPACE} from "rain.interpreter/src/lib/caller/LibEvaluable.sol"; +import { + IInterpreterV2, DEFAULT_STATE_NAMESPACE +} from "rain.interpreter.interface/interface/unstable/IInterpreterV2.sol"; +import {IInterpreterStoreV2} from "rain.interpreter.interface/interface/unstable/IInterpreterStoreV2.sol"; +import {EvaluableV2} from "rain.interpreter.interface/lib/caller/LibEvaluable.sol"; import {Pointer} from "rain.solmem/lib/LibPointer.sol"; import {LibFlow} from "../../lib/LibFlow.sol"; -import {SourceIndex} from "rain.interpreter/src/interface/IInterpreterV1.sol"; -import { - FlowCommon, DeployerDiscoverableMetaV2ConstructionConfig, ERC1155Receiver -} from "../../abstract/FlowCommon.sol"; -import {LibContext} from "rain.interpreter/src/lib/caller/LibContext.sol"; +import {SourceIndexV2} from "rain.interpreter.interface/interface/unstable/IInterpreterV2.sol"; +import {FlowCommon, ERC1155Receiver} from "../../abstract/FlowCommon.sol"; +import {LibContext} from "rain.interpreter.interface/lib/caller/LibContext.sol"; /// @dev The hash of the meta data expected by the `FlowCommon` constructor. bytes32 constant CALLER_META_HASH = bytes32(0x7ea70f837234357ec1bb5b777e04453ebaf3ca778a98805c4bb20a738d559a21); diff --git a/src/concrete/erc20/FlowERC20.sol b/src/concrete/erc20/FlowERC20.sol index eb8faf6e..85012f7b 100644 --- a/src/concrete/erc20/FlowERC20.sol +++ b/src/concrete/erc20/FlowERC20.sol @@ -19,19 +19,19 @@ import { FLOW_ERC20_MIN_FLOW_SENTINELS } from "../../interface/unstable/IFlowERC20V4.sol"; import {LibBytecode} from "rain.interpreter.interface/lib/bytecode/LibBytecode.sol"; -import {EncodedDispatch, LibEncodedDispatch} from "rain.interpreter/src/lib/caller/LibEncodedDispatch.sol"; +import {EncodedDispatch, LibEncodedDispatch} from "rain.interpreter.interface/lib/caller/LibEncodedDispatch.sol"; import {Sentinel, LibStackSentinel} from "rain.solmem/lib/LibStackSentinel.sol"; import {LibFlow} from "../../lib/LibFlow.sol"; +import {FlowCommon} from "../../abstract/FlowCommon.sol"; import { - FlowCommon, - DeployerDiscoverableMetaV2, - DeployerDiscoverableMetaV2ConstructionConfig -} from "../../abstract/FlowCommon.sol"; -import {SourceIndex, IInterpreterV1} from "rain.interpreter/src/interface/IInterpreterV1.sol"; -import {IInterpreterStoreV1} from "rain.interpreter/src/interface/IInterpreterStoreV1.sol"; + SourceIndexV2, + IInterpreterV2, + DEFAULT_STATE_NAMESPACE +} from "rain.interpreter.interface/interface/unstable/IInterpreterV2.sol"; +import {IInterpreterStoreV1} from "rain.interpreter.interface/interface/IInterpreterStoreV1.sol"; import {Pointer} from "rain.solmem/lib/LibPointer.sol"; -import {Evaluable, DEFAULT_STATE_NAMESPACE} from "rain.interpreter/src/lib/caller/LibEvaluable.sol"; -import {LibContext} from "rain.interpreter/src/lib/caller/LibContext.sol"; +import {EvaluableV2} from "rain.interpreter.interface/lib/caller/LibEvaluable.sol"; +import {LibContext} from "rain.interpreter.interface/lib/caller/LibContext.sol"; /// @dev The hash of the meta data expected to be passed to `FlowCommon`'s /// constructor. diff --git a/src/concrete/erc721/FlowERC721.sol b/src/concrete/erc721/FlowERC721.sol index 6b1fddda..de3b1896 100644 --- a/src/concrete/erc721/FlowERC721.sol +++ b/src/concrete/erc721/FlowERC721.sol @@ -7,7 +7,7 @@ import {ERC721Upgradeable as ERC721} from import {LibUint256Array} from "rain.solmem/lib/LibUint256Array.sol"; import {LibUint256Matrix} from "rain.solmem/lib/LibUint256Matrix.sol"; import {Sentinel, LibStackSentinel} from "rain.solmem/lib/LibStackSentinel.sol"; -import {EncodedDispatch, LibEncodedDispatch} from "rain.interpreter/src/lib/caller/LibEncodedDispatch.sol"; +import {EncodedDispatch, LibEncodedDispatch} from "rain.interpreter.interface/lib/caller/LibEncodedDispatch.sol"; import {ICloneableV2, ICLONEABLE_V2_SUCCESS} from "rain.factory/src/interface/ICloneableV2.sol"; import { IFlowERC721V4, @@ -24,17 +24,14 @@ import { FLOW_ERC721_MIN_FLOW_SENTINELS } from "../../interface/unstable/IFlowERC721V4.sol"; import {LibBytecode} from "rain.interpreter.interface/lib/bytecode/LibBytecode.sol"; -import {SourceIndex} from "rain.interpreter/src/interface/IInterpreterV1.sol"; +import {SourceIndexV2} from "rain.interpreter.interface/interface/unstable/IInterpreterV2.sol"; import {LibFlow} from "../../lib/LibFlow.sol"; +import {FlowCommon, LibContext, ERC1155Receiver} from "../../abstract/FlowCommon.sol"; +import {EvaluableV2} from "rain.interpreter.interface/lib/caller/LibEvaluable.sol"; import { - FlowCommon, - DeployerDiscoverableMetaV2ConstructionConfig, - LibContext, - ERC1155Receiver -} from "../../abstract/FlowCommon.sol"; -import {Evaluable, DEFAULT_STATE_NAMESPACE} from "rain.interpreter/src/lib/caller/LibEvaluable.sol"; -import {IInterpreterV1} from "rain.interpreter/src/interface/IInterpreterV1.sol"; -import {IInterpreterStoreV1} from "rain.interpreter/src/interface/IInterpreterStoreV1.sol"; + IInterpreterV2, DEFAULT_STATE_NAMESPACE +} from "rain.interpreter.interface/interface/unstable/IInterpreterV2.sol"; +import {IInterpreterStoreV2} from "rain.interpreter.interface/interface/unstable/IInterpreterStoreV2.sol"; import {Pointer} from "rain.solmem/lib/LibPointer.sol"; import {RAIN_FLOW_SENTINEL, BurnerNotOwner} from "../../interface/unstable/IFlowERC721V4.sol"; diff --git a/src/interface/IFlowERC1155V3.sol b/src/interface/IFlowERC1155V3.sol index 7176c231..1ec09470 100644 --- a/src/interface/IFlowERC1155V3.sol +++ b/src/interface/IFlowERC1155V3.sol @@ -1,8 +1,7 @@ // SPDX-License-Identifier: CAL pragma solidity ^0.8.18; -import {SignedContextV1} from "rain.interpreter/src/interface/IInterpreterCallerV2.sol"; -import {EvaluableConfigV2} from "rain.interpreter/src/lib/caller/LibEvaluable.sol"; +import {SignedContextV1} from "rain.interpreter.interface/interface/IInterpreterCallerV2.sol"; import "./IFlowV3.sol"; diff --git a/src/interface/IFlowERC20V3.sol b/src/interface/IFlowERC20V3.sol index 5c19abb2..bb4d93ef 100644 --- a/src/interface/IFlowERC20V3.sol +++ b/src/interface/IFlowERC20V3.sol @@ -1,8 +1,8 @@ // SPDX-License-Identifier: CAL pragma solidity ^0.8.18; -import "rain.interpreter/src/interface/IInterpreterCallerV2.sol"; -import "rain.interpreter/src/lib/caller/LibEvaluable.sol"; +import "rain.interpreter.interface/interface/IInterpreterCallerV2.sol"; +import "rain.interpreter.interface/lib/caller/LibEvaluable.sol"; import {Sentinel} from "rain.solmem/lib/LibStackSentinel.sol"; import {MIN_FLOW_SENTINELS, SENTINEL_HIGH_BITS, FlowTransferV1} from "./IFlowV3.sol"; diff --git a/src/interface/IFlowERC721V3.sol b/src/interface/IFlowERC721V3.sol index a8223a30..0af859da 100644 --- a/src/interface/IFlowERC721V3.sol +++ b/src/interface/IFlowERC721V3.sol @@ -1,8 +1,8 @@ // SPDX-License-Identifier: CAL pragma solidity ^0.8.18; -import "rain.interpreter/src/interface/IInterpreterCallerV2.sol"; -import "rain.interpreter/src/lib/caller/LibEvaluable.sol"; +import "rain.interpreter.interface/interface/IInterpreterCallerV2.sol"; +import "rain.interpreter.interface/lib/caller/LibEvaluable.sol"; import "./IFlowV3.sol"; diff --git a/src/interface/IFlowV3.sol b/src/interface/IFlowV3.sol index 1f262621..c6a24565 100644 --- a/src/interface/IFlowV3.sol +++ b/src/interface/IFlowV3.sol @@ -1,8 +1,9 @@ // SPDX-License-Identifier: CAL pragma solidity ^0.8.18; -import "rain.interpreter/src/interface/IInterpreterCallerV2.sol"; -import "rain.interpreter/src/lib/caller/LibEvaluable.sol"; +import {Evaluable, EvaluableConfig} from "rain.interpreter.interface/interface/deprecated/IInterpreterCallerV1.sol"; +import {SignedContextV1} from "rain.interpreter.interface/interface/IInterpreterCallerV2.sol"; +import "rain.interpreter.interface/lib/caller/LibEvaluable.sol"; import {Sentinel} from "rain.solmem/lib/LibStackSentinel.sol"; /// Thrown when the flow being evaluated is unregistered. diff --git a/src/interface/deprecated/v1/IFlowERC1155V1.sol b/src/interface/deprecated/v1/IFlowERC1155V1.sol index ec3be66a..f161dfd9 100644 --- a/src/interface/deprecated/v1/IFlowERC1155V1.sol +++ b/src/interface/deprecated/v1/IFlowERC1155V1.sol @@ -1,8 +1,8 @@ // SPDX-License-Identifier: CAL pragma solidity ^0.8.18; -import "rain.interpreter/src/interface/deprecated/IInterpreterCallerV1.sol"; -import "rain.interpreter/src/lib/caller/LibEvaluable.sol"; +import "rain.interpreter.interface/interface/deprecated/IInterpreterCallerV1.sol"; +import "rain.interpreter.interface/lib/caller/LibEvaluable.sol"; import "./IFlowV1.sol"; diff --git a/src/interface/deprecated/v1/IFlowERC20V1.sol b/src/interface/deprecated/v1/IFlowERC20V1.sol index 6fa7f8e1..542f0950 100644 --- a/src/interface/deprecated/v1/IFlowERC20V1.sol +++ b/src/interface/deprecated/v1/IFlowERC20V1.sol @@ -1,8 +1,8 @@ // SPDX-License-Identifier: CAL pragma solidity ^0.8.18; -import "rain.interpreter/src/interface/deprecated/IInterpreterCallerV1.sol"; -import "rain.interpreter/src/lib/caller/LibEvaluable.sol"; +import "rain.interpreter.interface/interface/deprecated/IInterpreterCallerV1.sol"; +import "rain.interpreter.interface/lib/caller/LibEvaluable.sol"; import "./IFlowV1.sol"; diff --git a/src/interface/deprecated/v1/IFlowERC721V1.sol b/src/interface/deprecated/v1/IFlowERC721V1.sol index 0087e8a8..f58fd292 100644 --- a/src/interface/deprecated/v1/IFlowERC721V1.sol +++ b/src/interface/deprecated/v1/IFlowERC721V1.sol @@ -1,8 +1,8 @@ // SPDX-License-Identifier: CAL pragma solidity ^0.8.18; -import "rain.interpreter/src/interface/deprecated/IInterpreterCallerV1.sol"; -import "rain.interpreter/src/lib/caller/LibEvaluable.sol"; +import "rain.interpreter.interface/interface/deprecated/IInterpreterCallerV1.sol"; +import "rain.interpreter.interface/lib/caller/LibEvaluable.sol"; import "./IFlowV1.sol"; diff --git a/src/interface/deprecated/v1/IFlowV1.sol b/src/interface/deprecated/v1/IFlowV1.sol index 83c2042b..65ae0eb0 100644 --- a/src/interface/deprecated/v1/IFlowV1.sol +++ b/src/interface/deprecated/v1/IFlowV1.sol @@ -1,8 +1,8 @@ // SPDX-License-Identifier: CAL pragma solidity ^0.8.18; -import "rain.interpreter/src/interface/deprecated/IInterpreterCallerV1.sol"; -import "rain.interpreter/src/lib/caller/LibEvaluable.sol"; +import "rain.interpreter.interface/interface/deprecated/IInterpreterCallerV1.sol"; +import "rain.interpreter.interface/lib/caller/LibEvaluable.sol"; struct FlowConfig { // https://github.com/ethereum/solidity/issues/13597 diff --git a/src/interface/deprecated/v2/IFlowERC1155V2.sol b/src/interface/deprecated/v2/IFlowERC1155V2.sol index f3febff2..a30dc1b9 100644 --- a/src/interface/deprecated/v2/IFlowERC1155V2.sol +++ b/src/interface/deprecated/v2/IFlowERC1155V2.sol @@ -1,8 +1,8 @@ // SPDX-License-Identifier: CAL pragma solidity ^0.8.18; -import "rain.interpreter/src/interface/IInterpreterCallerV2.sol"; -import "rain.interpreter/src/lib/caller/LibEvaluable.sol"; +import "rain.interpreter.interface/interface/IInterpreterCallerV2.sol"; +import "rain.interpreter.interface/lib/caller/LibEvaluable.sol"; import "./IFlowV2.sol"; diff --git a/src/interface/deprecated/v2/IFlowERC20V2.sol b/src/interface/deprecated/v2/IFlowERC20V2.sol index 83e68027..4b5a7533 100644 --- a/src/interface/deprecated/v2/IFlowERC20V2.sol +++ b/src/interface/deprecated/v2/IFlowERC20V2.sol @@ -1,8 +1,8 @@ // SPDX-License-Identifier: CAL pragma solidity ^0.8.18; -import "rain.interpreter/src/interface/IInterpreterCallerV2.sol"; -import "rain.interpreter/src/lib/caller/LibEvaluable.sol"; +import "rain.interpreter.interface/interface/IInterpreterCallerV2.sol"; +import "rain.interpreter.interface/lib/caller/LibEvaluable.sol"; import "./IFlowV2.sol"; diff --git a/src/interface/deprecated/v2/IFlowERC721V2.sol b/src/interface/deprecated/v2/IFlowERC721V2.sol index 0d150ec7..4f2b7e8a 100644 --- a/src/interface/deprecated/v2/IFlowERC721V2.sol +++ b/src/interface/deprecated/v2/IFlowERC721V2.sol @@ -1,8 +1,8 @@ // SPDX-License-Identifier: CAL pragma solidity ^0.8.18; -import "rain.interpreter/src/interface/IInterpreterCallerV2.sol"; -import "rain.interpreter/src/lib/caller/LibEvaluable.sol"; +import "rain.interpreter.interface/interface/IInterpreterCallerV2.sol"; +import "rain.interpreter.interface/lib/caller/LibEvaluable.sol"; import "./IFlowV2.sol"; diff --git a/src/interface/deprecated/v2/IFlowV2.sol b/src/interface/deprecated/v2/IFlowV2.sol index a0558eb5..aaa62197 100644 --- a/src/interface/deprecated/v2/IFlowV2.sol +++ b/src/interface/deprecated/v2/IFlowV2.sol @@ -1,8 +1,8 @@ // SPDX-License-Identifier: CAL pragma solidity ^0.8.18; -import "rain.interpreter/src/interface/IInterpreterCallerV2.sol"; -import "rain.interpreter/src/lib/caller/LibEvaluable.sol"; +import "rain.interpreter.interface/interface/IInterpreterCallerV2.sol"; +import "rain.interpreter.interface/lib/caller/LibEvaluable.sol"; struct FlowConfig { // https://github.com/ethereum/solidity/issues/13597 diff --git a/src/interface/unstable/IFlowERC1155V4.sol b/src/interface/unstable/IFlowERC1155V4.sol index db58b3df..96f45f78 100644 --- a/src/interface/unstable/IFlowERC1155V4.sol +++ b/src/interface/unstable/IFlowERC1155V4.sol @@ -1,8 +1,8 @@ // SPDX-License-Identifier: CAL pragma solidity ^0.8.18; -import {SignedContextV1} from "rain.interpreter/src/interface/IInterpreterCallerV2.sol"; -import {Evaluable, EvaluableConfigV2} from "rain.interpreter/src/lib/caller/LibEvaluable.sol"; +import {SignedContextV1} from "rain.interpreter.interface/interface/IInterpreterCallerV2.sol"; +import {EvaluableV2} from "rain.interpreter.interface/lib/caller/LibEvaluable.sol"; import {Sentinel} from "rain.solmem/lib/LibStackSentinel.sol"; import {RAIN_FLOW_SENTINEL} from "./IFlowV4.sol"; diff --git a/src/interface/unstable/IFlowERC20V4.sol b/src/interface/unstable/IFlowERC20V4.sol index 5aa349f3..728e093a 100644 --- a/src/interface/unstable/IFlowERC20V4.sol +++ b/src/interface/unstable/IFlowERC20V4.sol @@ -1,8 +1,8 @@ // SPDX-License-Identifier: CAL pragma solidity ^0.8.18; -import {SignedContextV1} from "rain.interpreter/src/interface/IInterpreterCallerV2.sol"; -import {Evaluable, EvaluableConfigV2} from "rain.interpreter/src/lib/caller/LibEvaluable.sol"; +import {SignedContextV1} from "rain.interpreter.interface/interface/IInterpreterCallerV2.sol"; +import {EvaluableV2} from "rain.interpreter.interface/lib/caller/LibEvaluable.sol"; import {Sentinel} from "rain.solmem/lib/LibStackSentinel.sol"; import { FlowERC20IOV1, diff --git a/src/interface/unstable/IFlowERC721V4.sol b/src/interface/unstable/IFlowERC721V4.sol index 2190a26d..d76a94a2 100644 --- a/src/interface/unstable/IFlowERC721V4.sol +++ b/src/interface/unstable/IFlowERC721V4.sol @@ -1,8 +1,8 @@ // SPDX-License-Identifier: CAL pragma solidity ^0.8.18; -import "rain.interpreter/src/interface/IInterpreterCallerV2.sol"; -import "rain.interpreter/src/lib/caller/LibEvaluable.sol"; +import "rain.interpreter.interface/interface/IInterpreterCallerV2.sol"; +import "rain.interpreter.interface/lib/caller/LibEvaluable.sol"; import { FlowERC721IOV1, diff --git a/src/interface/unstable/IFlowV4.sol b/src/interface/unstable/IFlowV4.sol index 7a4fd40a..27998b5e 100644 --- a/src/interface/unstable/IFlowV4.sol +++ b/src/interface/unstable/IFlowV4.sol @@ -1,8 +1,8 @@ // SPDX-License-Identifier: CAL pragma solidity ^0.8.18; -import {SignedContextV1} from "rain.interpreter/src/interface/IInterpreterCallerV2.sol"; -import {EvaluableConfigV2, Evaluable} from "rain.interpreter/src/lib/caller/LibEvaluable.sol"; +import {SignedContextV1, EvaluableConfigV3} from "rain.interpreter.interface/interface/IInterpreterCallerV2.sol"; +import {EvaluableV2} from "rain.interpreter.interface/lib/caller/LibEvaluable.sol"; import {Sentinel} from "rain.solmem/lib/LibStackSentinel.sol"; import {Pointer} from "rain.solmem/lib/LibPointer.sol"; @@ -126,7 +126,7 @@ interface IFlowV4 { /// MUST be emitted when the flow contract is initialized. /// @param sender The EOA that deployed the flow contract. /// @param config The list of evaluable configs that define the flows. - event Initialize(address sender, EvaluableConfigV2[] config); + event Initialize(address sender, EvaluableConfigV3[] config); /// Given a stack of values, convert it to a flow transfer. MUST NOT modify /// state but MAY revert if the stack is malformed. The intended workflow is @@ -155,7 +155,7 @@ interface IFlowV4 { /// @param signedContexts The signed contexts to pass to the evaluable. /// @return flowTransfer The resulting flow transfer. function flow( - Evaluable calldata evaluable, + EvaluableV2 calldata evaluable, uint256[] calldata callerContext, SignedContextV1[] calldata signedContexts ) external returns (FlowTransferV1 calldata flowTransfer); diff --git a/src/lib/LibFlow.sol b/src/lib/LibFlow.sol index 40d1199e..0d170f81 100644 --- a/src/lib/LibFlow.sol +++ b/src/lib/LibFlow.sol @@ -12,8 +12,9 @@ import { UnsupportedERC721Flow, UnsupportedERC1155Flow } from "../interface/unstable/IFlowV4.sol"; -import {IInterpreterStoreV1, DEFAULT_STATE_NAMESPACE} from "rain.interpreter/src/interface/IInterpreterStoreV1.sol"; +import {IInterpreterStoreV2} from "rain.interpreter.interface/interface/unstable/IInterpreterStoreV2.sol"; import {LibStackSentinel} from "rain.solmem/lib/LibStackSentinel.sol"; +import {DEFAULT_STATE_NAMESPACE} from "rain.interpreter.interface/interface/unstable/IInterpreterV2.sol"; import {IERC20} from "openzeppelin-contracts/contracts/token/ERC20/IERC20.sol"; import {SafeERC20} from "openzeppelin-contracts/contracts/token/ERC20/utils/SafeERC20.sol"; @@ -135,7 +136,7 @@ library LibFlow { /// @param flowTransfer The `FlowTransferV1` to process. /// @param interpreterStore The `IInterpreterStoreV1` to set state on. /// @param kvs The key value pairs to set on the interpreter store. - function flow(FlowTransferV1 memory flowTransfer, IInterpreterStoreV1 interpreterStore, uint256[] memory kvs) + function flow(FlowTransferV1 memory flowTransfer, IInterpreterStoreV2 interpreterStore, uint256[] memory kvs) internal { if (kvs.length > 0) { From cf1f7f89d31e232d65fb7829ce2baa573366d6da Mon Sep 17 00:00:00 2001 From: thedavidmeister Date: Wed, 28 Feb 2024 08:17:03 +0400 Subject: [PATCH 03/13] wip on i9r bump --- src/concrete/erc1155/FlowERC1155.sol | 14 +- src/interface/IFlowERC1155V3.sol | 103 -------------- src/interface/IFlowERC20V3.sol | 105 -------------- src/interface/IFlowERC721V3.sol | 126 ----------------- src/interface/IFlowV3.sol | 145 ------------------- src/interface/unstable/IFlowERC1155V4.sol | 68 --------- src/interface/unstable/IFlowERC20V4.sol | 69 --------- src/interface/unstable/IFlowERC721V4.sol | 83 ----------- src/interface/unstable/IFlowV4.sol | 162 ---------------------- 9 files changed, 4 insertions(+), 871 deletions(-) delete mode 100644 src/interface/IFlowERC1155V3.sol delete mode 100644 src/interface/IFlowERC20V3.sol delete mode 100644 src/interface/IFlowERC721V3.sol delete mode 100644 src/interface/IFlowV3.sol delete mode 100644 src/interface/unstable/IFlowERC1155V4.sol delete mode 100644 src/interface/unstable/IFlowERC20V4.sol delete mode 100644 src/interface/unstable/IFlowERC721V4.sol delete mode 100644 src/interface/unstable/IFlowV4.sol diff --git a/src/concrete/erc1155/FlowERC1155.sol b/src/concrete/erc1155/FlowERC1155.sol index 53df6544..4c7e89f1 100644 --- a/src/concrete/erc1155/FlowERC1155.sol +++ b/src/concrete/erc1155/FlowERC1155.sol @@ -33,9 +33,6 @@ import {SourceIndexV2} from "rain.interpreter.interface/interface/unstable/IInte import {FlowCommon, ERC1155Receiver} from "../../abstract/FlowCommon.sol"; import {LibContext} from "rain.interpreter.interface/lib/caller/LibContext.sol"; -/// @dev The hash of the meta data expected by the `FlowCommon` constructor. -bytes32 constant CALLER_META_HASH = bytes32(0x7ea70f837234357ec1bb5b777e04453ebaf3ca778a98805c4bb20a738d559a21); - /// @title FlowERC1155 /// See `IFlowERC1155V4` for documentation. contract FlowERC1155 is ICloneableV2, IFlowERC1155V4, FlowCommon, ERC1155 { @@ -47,10 +44,7 @@ contract FlowERC1155 is ICloneableV2, IFlowERC1155V4, FlowCommon, ERC1155 { bool private sEvalHandleTransfer; /// The `Evaluable` that handles transfers. - Evaluable internal sEvaluable; - - /// Forwards the `FlowCommon` constructor. - constructor(DeployerDiscoverableMetaV2ConstructionConfig memory config) FlowCommon(CALLER_META_HASH, config) {} + EvaluableV2 internal sEvaluable; /// Overloaded typed initialize function MUST revert with this error. /// As per `ICloneableV2` interface. @@ -67,7 +61,7 @@ contract FlowERC1155 is ICloneableV2, IFlowERC1155V4, FlowCommon, ERC1155 { // Set state before external calls here. bool evalHandleTransfer = LibBytecode.sourceCount(flowERC1155Config.evaluableConfig.bytecode) > 0 && LibBytecode.sourceOpsCount( - flowERC1155Config.evaluableConfig.bytecode, SourceIndex.unwrap(FLOW_ERC1155_HANDLE_TRANSFER_ENTRYPOINT) + flowERC1155Config.evaluableConfig.bytecode, SourceIndexV2.unwrap(FLOW_ERC1155_HANDLE_TRANSFER_ENTRYPOINT) ) > 0; sEvalHandleTransfer = evalHandleTransfer; @@ -167,7 +161,7 @@ contract FlowERC1155 is ICloneableV2, IFlowERC1155V4, FlowCommon, ERC1155 { } /// @inheritdoc IFlowERC1155V4 - function flow(Evaluable memory evaluable, uint256[] memory callerContext, SignedContextV1[] memory signedContexts) + function flow(EvaluableV2 memory evaluable, uint256[] memory callerContext, SignedContextV1[] memory signedContexts) external virtual returns (FlowERC1155IOV1 memory) @@ -207,7 +201,7 @@ contract FlowERC1155 is ICloneableV2, IFlowERC1155V4, FlowCommon, ERC1155 { /// of the flow contract itself. This involves consuming the mint/burn /// sentinels from the stack and minting/burning the tokens accordingly, then /// calling `LibFlow.flow` to handle the rest of the flow. - function _flow(Evaluable memory evaluable, uint256[] memory callerContext, SignedContextV1[] memory signedContexts) + function _flow(EvaluableV2 memory evaluable, uint256[] memory callerContext, SignedContextV1[] memory signedContexts) internal virtual nonReentrant diff --git a/src/interface/IFlowERC1155V3.sol b/src/interface/IFlowERC1155V3.sol deleted file mode 100644 index 1ec09470..00000000 --- a/src/interface/IFlowERC1155V3.sol +++ /dev/null @@ -1,103 +0,0 @@ -// SPDX-License-Identifier: CAL -pragma solidity ^0.8.18; - -import {SignedContextV1} from "rain.interpreter.interface/interface/IInterpreterCallerV2.sol"; - -import "./IFlowV3.sol"; - -/// @dev Entrypont of the `handleTransfer` evaluation. -SourceIndex constant FLOW_ERC1155_HANDLE_TRANSFER_ENTRYPOINT = SourceIndex.wrap(0); - -/// @dev Minimum number of outputs of the `handleTransfer` evaluation. -/// This is 0 because the return stack is ignored. -uint256 constant FLOW_ERC1155_HANDLE_TRANSFER_MIN_OUTPUTS = 0; - -/// @dev Maximum number of outputs of the `handleTransfer` evaluation. -/// This is 0 because the return stack is ignored. -uint16 constant FLOW_ERC1155_HANDLE_TRANSFER_MAX_OUTPUTS = 0; - -/// @dev Minimum number of sentinels required by `FlowERC1155`. -/// This is 2 more than the minimum required by `FlowCommon` because the -/// mints and burns are included in the stack. -uint256 constant FLOW_ERC1155_MIN_FLOW_SENTINELS = MIN_FLOW_SENTINELS + 2; - -/// @dev v3 of `FlowERC1155` expected a sentinel different to -/// `RAIN_FLOW_SENTINEL`, but this was generally more confusing than helpful. -Sentinel constant RAIN_FLOW_ERC1155_SENTINEL = - Sentinel.wrap(uint256(keccak256(bytes("RAIN_FLOW_ERC1155_SENTINEL")) | SENTINEL_HIGH_BITS)); - -/// Initializer config. -/// @param uri As per Open Zeppelin `ERC1155Upgradeable`. -/// @param evaluableConfig The `EvaluableConfigV2` to use to build the -/// `evaluable` that can be used to handle transfers. -/// @param flowConfig Constructor config for the `Evaluable`s that define the -/// flow behaviours including self mints/burns. -struct FlowERC1155Config { - string uri; - EvaluableConfig evaluableConfig; - EvaluableConfig[] flowConfig; -} - -/// Represents a single mint or burn of a single ERC1155 token. Whether this is -/// a mint or burn must be implied by the context. -/// @param account The address the token is being minted/burned to/from. -/// @param id The id of the token being minted/burned. -/// @param amount The amount of the token being minted/burned. -struct ERC1155SupplyChange { - address account; - uint256 id; - uint256 amount; -} - -/// Represents a set of ERC1155 transfers, including self mints/burns. -/// @param mints The mints that occurred. -/// @param burns The burns that occurred. -/// @param flow The transfers that occured. -struct FlowERC1155IOV1 { - ERC1155SupplyChange[] mints; - ERC1155SupplyChange[] burns; - FlowTransferV1 flow; -} - -/// @title IFlowERC1155V3 -/// Conceptually identical to `IFlowV3`, but the flow contract itself is an -/// ERC1155 token. This means that ERC1155 self mints and burns are included in -/// the stack that the flows must evaluate to. As stacks are processed by flow -/// from bottom to top, this means that the self mint/burn will be the last thing -/// evaluated, with mints at the bottom and burns next, followed by the flows. -/// -/// As the flow is an ERC1155 token it also includes an evaluation to be run on -/// every token transfer. This is the `handleTransfer` entrypoint. The return -/// stack of this evaluation is ignored, but reverts MUST be respected. This -/// allows expression authors to prevent transfers from occurring if they don't -/// want them to, by reverting within the expression. -/// -/// Otherwise the flow contract is identical to `IFlowV3`. -interface IFlowERC1155V3 { - /// Contract has initialized. - event Initialize(address sender, FlowERC1155Config config); - - /// As per `IFlowV3` but returns a `FlowERC1155IOV1` instead of a - /// `FlowTransferV1`. - /// @param evaluable The `Evaluable` that is flowing. - /// @param callerContext The context of the caller. - /// @param signedContexts The signed contexts of the caller. - /// @return flowERC1155IO The `FlowERC1155IOV1` that occurred. - function previewFlow( - Evaluable calldata evaluable, - uint256[] calldata callerContext, - SignedContextV1[] calldata signedContexts - ) external view returns (FlowERC1155IOV1 calldata flowERC1155IO); - - /// As per `IFlowV3` but returns a `FlowERC1155IOV1` instead of a - /// `FlowTransferV1` and mints/burns itself as an ERC1155 accordingly. - /// @param evaluable The `Evaluable` that is flowing. - /// @param callerContext The context of the caller. - /// @param signedContexts The signed contexts of the caller. - /// @return flowERC1155IO The `FlowERC1155IOV1` that occurred. - function flow( - Evaluable calldata evaluable, - uint256[] calldata callerContext, - SignedContextV1[] calldata signedContexts - ) external returns (FlowERC1155IOV1 calldata flowERC1155IO); -} diff --git a/src/interface/IFlowERC20V3.sol b/src/interface/IFlowERC20V3.sol deleted file mode 100644 index bb4d93ef..00000000 --- a/src/interface/IFlowERC20V3.sol +++ /dev/null @@ -1,105 +0,0 @@ -// SPDX-License-Identifier: CAL -pragma solidity ^0.8.18; - -import "rain.interpreter.interface/interface/IInterpreterCallerV2.sol"; -import "rain.interpreter.interface/lib/caller/LibEvaluable.sol"; -import {Sentinel} from "rain.solmem/lib/LibStackSentinel.sol"; -import {MIN_FLOW_SENTINELS, SENTINEL_HIGH_BITS, FlowTransferV1} from "./IFlowV3.sol"; - -/// @dev v3 of `FlowERC20` expected a sentinel different to -/// `RAIN_FLOW_SENTINEL`, but this was generally more confusing than helpful. -Sentinel constant RAIN_FLOW_ERC20_SENTINEL = - Sentinel.wrap(uint256(keccak256(bytes("RAIN_FLOW_ERC20_SENTINEL")) | SENTINEL_HIGH_BITS)); - -/// @dev Entrypont of the `handleTransfer` evaluation. -SourceIndex constant FLOW_ERC20_HANDLE_TRANSFER_ENTRYPOINT = SourceIndex.wrap(0); - -/// @dev Minimum number of outputs of the `handleTransfer` evaluation. -/// This is 0 because the return stack is ignored. -uint256 constant FLOW_ERC20_HANDLE_TRANSFER_MIN_OUTPUTS = 0; - -/// @dev Maximum number of outputs of the `handleTransfer` evaluation. -/// This is 0 because the return stack is ignored. -uint16 constant FLOW_ERC20_HANDLE_TRANSFER_MAX_OUTPUTS = 0; - -/// @dev Minimum number of sentinels required by `FlowERC20`. -/// This is 2 more than the minimum required by `FlowCommon` because the -/// mints and burns are included in the stack. -uint256 constant FLOW_ERC20_MIN_FLOW_SENTINELS = MIN_FLOW_SENTINELS + 2; - -/// Represents a single mint or burn of a single ERC20 token. Whether this is -/// a mint or burn must be implied by the context. -/// @param account The address the token is being minted/burned to/from. -/// @param amount The amount of the token being minted/burned. -struct ERC20SupplyChange { - address account; - uint256 amount; -} - -/// Represents a set of ERC20 transfers, including self mints/burns. -/// @param mints The mints that occurred. -/// @param burns The burns that occurred. -/// @param flow The transfers that occured. -struct FlowERC20IOV1 { - ERC20SupplyChange[] mints; - ERC20SupplyChange[] burns; - FlowTransferV1 flow; -} - -/// Initializer config. -/// @param name As per Open Zeppelin `ERC20Upgradeable`. -/// @param symbol As per Open Zeppelin `ERC20Upgradeable`. -/// @param evaluableConfig The `EvaluableConfigV2` to use to build the -/// `evaluable` that can be used to handle transfers. -/// @param flowConfig Initializer config for the `Evaluable`s that define the -/// flow behaviours including self mints/burns. -struct FlowERC20Config { - string name; - string symbol; - EvaluableConfig evaluableConfig; - EvaluableConfig[] flowConfig; -} - -/// @title IFlowERC20V3 -/// @notice Mints itself according to some predefined schedule. The schedule is -/// expressed as an expression and the `claim` function is world-callable. -/// Intended behaviour is to avoid sybils infinitely minting by putting the -/// claim functionality behind a `TierV2` contract. The flow contract -/// itself implements `ReadOnlyTier` and every time a claim is processed it -/// logs the block number of the claim against every tier claimed. So the block -/// numbers in the tier report for `FlowERC20` are the last time that tier -/// was claimed against this contract. The simplest way to make use of this -/// information is to take the max block for the underlying tier and the last -/// claim and then diff it against the current block number. -/// See `test/Claim/FlowERC20.sol.ts` for examples, including providing -/// staggered rewards where more tokens are minted for higher tier accounts. -interface IFlowERC20V3 { - /// Contract has initialized. - /// @param sender `msg.sender` initializing the contract (factory). - /// @param config All initialized config. - event Initialize(address sender, FlowERC20Config config); - - /// As per `IFlowV3` but returns a `FlowERC20IOV1` instead of a - /// `FlowTransferV1`. - /// @param evaluable The `Evaluable` to use to evaluate the flow. - /// @param callerContext The caller context to use to evaluate the flow. - /// @param signedContexts The signed contexts to use to evaluate the flow. - /// @return flowERC20IO The `FlowERC20IOV1` that occurred. - function previewFlow( - Evaluable calldata evaluable, - uint256[] calldata callerContext, - SignedContextV1[] calldata signedContexts - ) external view returns (FlowERC20IOV1 calldata flowERC20IO); - - /// As per `IFlowV3` but returns a `FlowERC20IOV1` instead of a - /// `FlowTransferV1` and mints/burns itself as an ERC20 accordingly. - /// @param evaluable The `Evaluable` to use to evaluate the flow. - /// @param callerContext The caller context to use to evaluate the flow. - /// @param signedContexts The signed contexts to use to evaluate the flow. - /// @return flowERC20IO The `FlowERC20IOV1` that occurred. - function flow( - Evaluable calldata evaluable, - uint256[] calldata callerContext, - SignedContextV1[] calldata signedContexts - ) external returns (FlowERC20IOV1 calldata flowERC20IO); -} diff --git a/src/interface/IFlowERC721V3.sol b/src/interface/IFlowERC721V3.sol deleted file mode 100644 index 0af859da..00000000 --- a/src/interface/IFlowERC721V3.sol +++ /dev/null @@ -1,126 +0,0 @@ -// SPDX-License-Identifier: CAL -pragma solidity ^0.8.18; - -import "rain.interpreter.interface/interface/IInterpreterCallerV2.sol"; -import "rain.interpreter.interface/lib/caller/LibEvaluable.sol"; - -import "./IFlowV3.sol"; - -/// @dev Entrypont of the `handleTransfer` evaluation. -SourceIndex constant FLOW_ERC721_HANDLE_TRANSFER_ENTRYPOINT = SourceIndex.wrap(0); -/// @dev Entrypont of the `tokenURI` evaluation. -SourceIndex constant FLOW_ERC721_TOKEN_URI_ENTRYPOINT = SourceIndex.wrap(1); - -/// @dev Minimum number of outputs of the `handleTransfer` evaluation. -/// This is 0 because the return stack is ignored. -uint256 constant FLOW_ERC721_HANDLE_TRANSFER_MIN_OUTPUTS = 0; -/// @dev Minimum number of outputs of the `tokenURI` evaluation. -/// This is 1 because we can only handle a single token ID value. -uint256 constant FLOW_ERC721_TOKEN_URI_MIN_OUTPUTS = 1; - -/// @dev Maximum number of outputs of the `handleTransfer` evaluation. -/// This is 0 because the return stack is ignored. -uint16 constant FLOW_ERC721_HANDLE_TRANSFER_MAX_OUTPUTS = 0; -/// @dev Maximum number of outputs of the `tokenURI` evaluation. -/// This is 1 because we can only handle a single token ID value. -uint16 constant FLOW_ERC721_TOKEN_URI_MAX_OUTPUTS = 1; - -/// @dev v3 of `FlowERC721` expected a sentinel different to -/// `RAIN_FLOW_SENTINEL`, but this was generally more confusing than helpful. -Sentinel constant RAIN_FLOW_ERC721_SENTINEL = - Sentinel.wrap(uint256(keccak256(bytes("RAIN_FLOW_ERC721_SENTINEL")) | SENTINEL_HIGH_BITS)); - -/// @dev Minimum number of sentinels required by `FlowERC721`. -/// This is 2 more than the minimum required by `FlowCommon` because the -/// mints and burns are included in the stack. -uint256 constant FLOW_ERC721_MIN_FLOW_SENTINELS = MIN_FLOW_SENTINELS + 2; - -/// Initializer config. -/// @param name As per Open Zeppelin `ERC721Upgradeable`. -/// @param symbol As per Open Zeppelin `ERC721Upgradeable`. -/// @param baseURI As per Open Zeppelin `ERC721Upgradeable`. -/// @param evaluableConfig The `EvaluableConfigV2` to use to build the -/// `evaluable` that can be used to handle transfers and token URIs. The token -/// URI entrypoint is optional. -/// @param flowConfig Constructor config for the `Evaluable`s that define the -/// flow behaviours including self mints/burns. -struct FlowERC721Config { - string name; - string symbol; - string baseURI; - EvaluableConfig evaluableConfig; - EvaluableConfig[] flowConfig; -} - -/// Represents a single mint or burn of a single ERC721 token. Whether this is -/// a mint or burn must be implied by the context. -/// @param account The address the token is being minted/burned to/from. -/// @param id The id of the token being minted/burned. -struct ERC721SupplyChange { - address account; - uint256 id; -} - -/// Represents a set of ERC721 transfers, including self mints/burns. -/// @param mints The mints that occurred. -/// @param burns The burns that occurred. -/// @param flow The transfers that occured. -struct FlowERC721IOV1 { - ERC721SupplyChange[] mints; - ERC721SupplyChange[] burns; - FlowTransferV1 flow; -} - -/// @title IFlowERC721V3 -/// Conceptually identical to `IFlowV3`, but the flow contract itself is an -/// ERC721 token. This means that ERC721 self mints and burns are included in -/// the stack. -/// -/// As the flow is an ERC721 token, there are two entrypoints in addition to -/// the flows: -/// - `handleTransfer` is called when the flow is transferred. -/// - `tokenURI` is called when the token URI is requested. -/// -/// The `handleTransfer` entrypoint is mandatory, but the `tokenURI` entrypoint -/// is optional. If the `tokenURI` entrypoint is not provided, the default -/// Open Zeppelin implementation will be used. -/// -/// The `handleTransfer` entrypoint may be used to restrict transfers of the -/// flow token. For example, it may be used to restrict transfers to only -/// occur when the flow is in a certain state. -/// -/// The `tokenURI` entrypoint may be used to provide a custom token ID to build -/// a token URI for the flow token. -/// -/// Otherwise the flow contract behaves identically to `IFlowV3`. -interface IFlowERC721V3 { - /// Contract has initialized. - /// @param sender `msg.sender` initializing the contract (factory). - /// @param config All initialized config. - event Initialize(address sender, FlowERC721Config config); - - /// As per `IFlowV3` but returns a `FlowERC721IOV1` instead of a - /// `FlowTransferV1`. - /// @param evaluable The `Evaluable` that is flowing. - /// @param callerContext The context of the caller. - /// @param signedContexts The signed contexts of the caller. - /// @return flowERC721IO The `FlowERC721IOV1` that would occur if the flow - /// was executed. - function previewFlow( - Evaluable calldata evaluable, - uint256[] calldata callerContext, - SignedContextV1[] calldata signedContexts - ) external view returns (FlowERC721IOV1 calldata flowERC721IO); - - /// As per `IFlowV3` but returns a `FlowERC721IOV1` instead of a - /// `FlowTransferV1` and mints/burns itself as an ERC721 accordingly. - /// @param evaluable The `Evaluable` that is flowing. - /// @param callerContext The context of the caller. - /// @param signedContexts The signed contexts of the caller. - /// @return flowERC721IO The `FlowERC721IOV1` that occurred. - function flow( - Evaluable calldata evaluable, - uint256[] calldata callerContext, - SignedContextV1[] calldata signedContexts - ) external returns (FlowERC721IOV1 calldata flowERC721IO); -} diff --git a/src/interface/IFlowV3.sol b/src/interface/IFlowV3.sol deleted file mode 100644 index c6a24565..00000000 --- a/src/interface/IFlowV3.sol +++ /dev/null @@ -1,145 +0,0 @@ -// SPDX-License-Identifier: CAL -pragma solidity ^0.8.18; - -import {Evaluable, EvaluableConfig} from "rain.interpreter.interface/interface/deprecated/IInterpreterCallerV1.sol"; -import {SignedContextV1} from "rain.interpreter.interface/interface/IInterpreterCallerV2.sol"; -import "rain.interpreter.interface/lib/caller/LibEvaluable.sol"; -import {Sentinel} from "rain.solmem/lib/LibStackSentinel.sol"; - -/// Thrown when the flow being evaluated is unregistered. -/// @param unregisteredHash Hash of the unregistered flow. -error UnregisteredFlow(bytes32 unregisteredHash); - -/// Thrown for unsupported native transfers. -error UnsupportedNativeFlow(); - -/// Thrown for unsupported erc20 transfers. -error UnsupportedERC20Flow(); - -/// Thrown for unsupported erc721 transfers. -error UnsupportedERC721Flow(); - -/// Thrown for unsupported erc1155 transfers. -error UnsupportedERC1155Flow(); - -/// @dev The number of sentinels required by `FlowCommon`. An evaluable can never -/// have fewer minimum outputs than required sentinels. -uint256 constant MIN_FLOW_SENTINELS = 3; - -/// @dev Sets the high bits of all flow sentinels to guarantee that the numeric -/// value of the sentinel will never collide with a token amount or address. This -/// guarantee holds as long as the token supply is less than 2^252, and the -/// that token IDs have no specific reason to collide with the sentinel. -/// i.e. There won't be random collisions because the space of token IDs is -/// too large. -bytes32 constant SENTINEL_HIGH_BITS = bytes32(0xF000000000000000000000000000000000000000000000000000000000000000); - -/// @dev We want a sentinel with the following properties: -/// - Won't collide with token amounts (| with very large number) -/// - Won't collide with token addresses -/// - Won't collide with common values like `type(uint256).max` and -/// `type(uint256).min` -/// - Won't collide with other sentinels from unrelated contexts -Sentinel constant RAIN_FLOW_SENTINEL = - Sentinel.wrap(uint256(keccak256(bytes("RAIN_FLOW_SENTINEL")) | SENTINEL_HIGH_BITS)); - -/// Wraps `EvaluableConfig[]` to workaround a Solidity bug. -/// https://github.com/ethereum/solidity/issues/13597 -/// @param dummyConfig A dummy config to workaround a Solidity bug. -/// @param config The list of evaluable configs that define the flows. -struct FlowConfig { - EvaluableConfig dummyConfig; - EvaluableConfig[] config; -} - -/// Represents a single transfer of a single ERC20 token. -/// @param token The address of the ERC20 token being transferred. -/// @param from The address the token is being transferred from. -/// @param to The address the token is being transferred to. -/// @param amount The amount of the token being transferred. -struct ERC20Transfer { - address token; - address from; - address to; - uint256 amount; -} - -/// Represents a single transfer of a single ERC721 token. -/// @param token The address of the ERC721 token being transferred. -/// @param from The address the token is being transferred from. -/// @param to The address the token is being transferred to. -/// @param id The id of the token being transferred. -struct ERC721Transfer { - address token; - address from; - address to; - uint256 id; -} - -/// Represents a single transfer of a single ERC1155 token. -/// @param token The address of the ERC1155 token being transferred. -/// @param from The address the token is being transferred from. -/// @param to The address the token is being transferred to. -/// @param id The id of the token being transferred. -/// @param amount The amount of the token being transferred. -struct ERC1155Transfer { - address token; - address from; - address to; - uint256 id; - uint256 amount; -} - -/// Represents an ordered set of transfers that will be or have been executed. -/// Supports ERC20, ERC721, and ERC1155 transfers. -/// @param erc20 An array of ERC20 transfers. -/// @param erc721 An array of ERC721 transfers. -/// @param erc1155 An array of ERC1155 transfers. -struct FlowTransferV1 { - ERC20Transfer[] erc20; - ERC721Transfer[] erc721; - ERC1155Transfer[] erc1155; -} - -/// @title IFlowV3 -/// At a high level, identical to `IFlowV4` but with an older, less flexible -/// previewing system, and the older `FlowConfig` struct that was used with -/// older versions of the interpreter. -interface IFlowV3 { - /// MUST be emitted when the flow contract is initialized. - /// @param sender The EOA that deployed the flow contract. - /// @param config The list of evaluable configs that define the flows. - event Initialize(address sender, FlowConfig config); - - /// "Dry run" of a flow, returning the resulting token transfers without - /// actually executing them. - /// @param evaluable The evaluable to evaluate. - /// @param callerContext The caller context to use when evaluating the - /// flow. - /// @param signedContexts The signed contexts to use when evaluating the - /// flow. - function previewFlow( - Evaluable calldata evaluable, - uint256[] calldata callerContext, - SignedContextV1[] calldata signedContexts - ) external view returns (FlowTransferV1 calldata flowTransfer); - - /// Given an evaluable, caller context, and signed contexts, evaluate the - /// evaluable and return the resulting flow transfer. MUST process the - /// flow transfer atomically, either all of it succeeds or none of it - /// succeeds. MUST revert if the evaluable is not registered with the flow - /// contract. MUST revert if the evaluable reverts. MUST revert if the - /// evaluable returns a stack that is malformed. MUST revert if the evaluable - /// returns a stack that contains a token transfer that is not allowed by - /// the flow contract (e.g. if a token is being moved from an address that - /// is not the caller or the flow contract). - /// @param evaluable The evaluable to evaluate. - /// @param callerContext The caller context to pass to the evaluable. - /// @param signedContexts The signed contexts to pass to the evaluable. - /// @return flowTransfer The resulting flow transfer. - function flow( - Evaluable calldata evaluable, - uint256[] calldata callerContext, - SignedContextV1[] calldata signedContexts - ) external returns (FlowTransferV1 calldata flowTransfer); -} diff --git a/src/interface/unstable/IFlowERC1155V4.sol b/src/interface/unstable/IFlowERC1155V4.sol deleted file mode 100644 index 96f45f78..00000000 --- a/src/interface/unstable/IFlowERC1155V4.sol +++ /dev/null @@ -1,68 +0,0 @@ -// SPDX-License-Identifier: CAL -pragma solidity ^0.8.18; - -import {SignedContextV1} from "rain.interpreter.interface/interface/IInterpreterCallerV2.sol"; -import {EvaluableV2} from "rain.interpreter.interface/lib/caller/LibEvaluable.sol"; -import {Sentinel} from "rain.solmem/lib/LibStackSentinel.sol"; -import {RAIN_FLOW_SENTINEL} from "./IFlowV4.sol"; - -import { - FlowERC1155IOV1, - ERC1155SupplyChange, - FLOW_ERC1155_HANDLE_TRANSFER_MAX_OUTPUTS, - FLOW_ERC1155_HANDLE_TRANSFER_ENTRYPOINT, - FLOW_ERC1155_HANDLE_TRANSFER_MIN_OUTPUTS, - FLOW_ERC1155_MIN_FLOW_SENTINELS -} from "../IFlowERC1155V3.sol"; - -/// Initialization config. -/// @param uri As per Open Zeppelin `ERC1155Upgradeable`. -/// @param evaluableConfig The `EvaluableConfigV2` to use to build the -/// `evaluable` that can be used to handle transfers. -/// @param flowConfig Initialization config for the `Evaluable`s that define the -/// flow behaviours outside self mints/burns. -struct FlowERC1155ConfigV2 { - string uri; - EvaluableConfigV2 evaluableConfig; - EvaluableConfigV2[] flowConfig; -} - -/// @title IFlowERC1155V4 -/// Conceptually identical to `IFlowV4`, but the flow contract itself is an -/// ERC1155 token. This means that ERC1155 self mints and burns are included in -/// the stack that the flows must evaluate to. As stacks are processed by flow -/// from bottom to top, this means that the self mint/burn will be the last thing -/// evaluated, with mints at the bottom and burns next, followed by the flows. -/// -/// As the flow is an ERC1155 token it also includes an evaluation to be run on -/// every token transfer. This is the `handleTransfer` entrypoint. The return -/// stack of this evaluation is ignored, but reverts MUST be respected. This -/// allows expression authors to prevent transfers from occurring if they don't -/// want them to, by reverting within the expression. -/// -/// Otherwise the flow contract is identical to `IFlowV4`. -interface IFlowERC1155V4 { - /// Contract has initialized. - /// @param sender `msg.sender` initializing the contract (factory). - /// @param config All initialized config. - event Initialize(address sender, FlowERC1155ConfigV2 config); - - /// As per `IFlowV4` but returns a `FlowERC1155IOV1` instead of a - /// `FlowTransferV1`. - /// @param stack The stack to convert to a `FlowERC1155IOV1`. - /// @return flowERC1155IO The `FlowERC1155IOV1` representation of the stack. - function stackToFlow(uint256[] memory stack) external pure returns (FlowERC1155IOV1 memory flowERC1155IO); - - /// As per `IFlowV4` but returns a `FlowERC1155IOV1` instead of a - /// `FlowTransferV1` and mints/burns itself as an ERC1155 accordingly. - /// @param evaluable The `Evaluable` to use to evaluate the flow. - /// @param callerContext The caller context to use to evaluate the flow. - /// @param signedContexts The signed contexts to use to evaluate the flow. - /// @return flowERC1155IO The `FlowERC1155IOV1` representing all token - /// mint/burns and transfers that occurred during the flow. - function flow( - Evaluable calldata evaluable, - uint256[] calldata callerContext, - SignedContextV1[] calldata signedContexts - ) external returns (FlowERC1155IOV1 calldata); -} diff --git a/src/interface/unstable/IFlowERC20V4.sol b/src/interface/unstable/IFlowERC20V4.sol deleted file mode 100644 index 728e093a..00000000 --- a/src/interface/unstable/IFlowERC20V4.sol +++ /dev/null @@ -1,69 +0,0 @@ -// SPDX-License-Identifier: CAL -pragma solidity ^0.8.18; - -import {SignedContextV1} from "rain.interpreter.interface/interface/IInterpreterCallerV2.sol"; -import {EvaluableV2} from "rain.interpreter.interface/lib/caller/LibEvaluable.sol"; -import {Sentinel} from "rain.solmem/lib/LibStackSentinel.sol"; -import { - FlowERC20IOV1, - ERC20SupplyChange, - FLOW_ERC20_HANDLE_TRANSFER_ENTRYPOINT, - FLOW_ERC20_HANDLE_TRANSFER_MIN_OUTPUTS, - FLOW_ERC20_HANDLE_TRANSFER_MAX_OUTPUTS, - FLOW_ERC20_MIN_FLOW_SENTINELS -} from "../IFlowERC20V3.sol"; -import {RAIN_FLOW_SENTINEL} from "./IFlowV4.sol"; - -/// Initialization config. -/// @param name As per Open Zeppelin `ERC20Upgradeable`. -/// @param symbol As per Open Zeppelin `ERC20Upgradeable`. -/// @param evaluableConfig The `EvaluableConfigV2` to use to build the -/// `evaluable` that can be used to evaluate `handleTransfer`. -/// @param flowConfig The `EvaluableConfigV2[]` to use to build the -/// `evaluable`s for all the flows, including self minting and burning. -struct FlowERC20ConfigV2 { - string name; - string symbol; - EvaluableConfigV2 evaluableConfig; - EvaluableConfigV2[] flowConfig; -} - -/// @title IFlowERC20V4 -/// Conceptually identical to `IFlowV4`, but the flow contract itself is an -/// ERC20 token. This means that ERC20 self mints and burns are included in the -/// stack that the flows must evaluate to. As stacks are processed by flow from -/// bottom to top, this means that the self mint/burn will be the last thing -/// evaluated, with mints at the bottom and burns next, followed by the flows. -/// -/// As the flow is an ERC20 token it also includes an evaluation to be run on -/// every token transfer. This is the `handleTransfer` entrypoint. The return -/// stack of this evaluation is ignored, but reverts MUST be respected. This -/// allows expression authors to prevent transfers from occurring if they don't -/// want them to, by reverting within the expression. -/// -/// Otherwise the flow contract is identical to `IFlowV4`. -interface IFlowERC20V4 { - /// Contract has initialized. - /// @param sender `msg.sender` initializing the contract (factory). - /// @param config All initialized config. - event Initialize(address sender, FlowERC20ConfigV2 config); - - /// As per `IFlowV4` but returns a `FlowERC20IOV1` instead of a - /// `FlowTransferV1`. - /// @param stack The stack to convert to a `FlowERC20IOV1`. - /// @return flowERC20IO The `FlowERC20IOV1` representation of the stack. - function stackToFlow(uint256[] memory stack) external pure returns (FlowERC20IOV1 memory flowERC20IO); - - /// As per `IFlowV4` but returns a `FlowERC20IOV1` instead of a - /// `FlowTransferV1` and mints/burns itself as an ERC20 accordingly. - /// @param evaluable The `Evaluable` to use to evaluate the flow. - /// @param callerContext The caller context to use to evaluate the flow. - /// @param signedContexts The signed contexts to use to evaluate the flow. - /// @return flowERC20IO The `FlowERC20IOV1` representing all token mint/burns - /// and transfers that occurred during the flow. - function flow( - Evaluable calldata evaluable, - uint256[] calldata callerContext, - SignedContextV1[] calldata signedContexts - ) external returns (FlowERC20IOV1 calldata flowERC20IO); -} diff --git a/src/interface/unstable/IFlowERC721V4.sol b/src/interface/unstable/IFlowERC721V4.sol deleted file mode 100644 index d76a94a2..00000000 --- a/src/interface/unstable/IFlowERC721V4.sol +++ /dev/null @@ -1,83 +0,0 @@ -// SPDX-License-Identifier: CAL -pragma solidity ^0.8.18; - -import "rain.interpreter.interface/interface/IInterpreterCallerV2.sol"; -import "rain.interpreter.interface/lib/caller/LibEvaluable.sol"; - -import { - FlowERC721IOV1, - ERC721SupplyChange, - FLOW_ERC721_TOKEN_URI_MIN_OUTPUTS, - FLOW_ERC721_TOKEN_URI_MAX_OUTPUTS, - FLOW_ERC721_HANDLE_TRANSFER_MIN_OUTPUTS, - FLOW_ERC721_HANDLE_TRANSFER_MAX_OUTPUTS, - FLOW_ERC721_TOKEN_URI_ENTRYPOINT, - FLOW_ERC721_HANDLE_TRANSFER_ENTRYPOINT, - FLOW_ERC721_MIN_FLOW_SENTINELS -} from "../IFlowERC721V3.sol"; - -import {RAIN_FLOW_SENTINEL} from "./IFlowV4.sol"; - -/// Thrown when burner of tokens is not the owner of tokens. -error BurnerNotOwner(); - -/// Initialization config. -/// @param name As per Open Zeppelin `ERC721Upgradeable`. -/// @param symbol As per Open Zeppelin `ERC721Upgradeable`. -/// @param baseURI As per Open Zeppelin `ERC721Upgradeable`. -/// @param evaluableConfig The `EvaluableConfigV2` to use to build the -/// `evaluable` that can be used to handle transfers and build token IDs for the -/// token URI. -/// @param flowConfig Initialization config for the `Evaluable`s that define the -/// flow behaviours outside self mints/burns. -struct FlowERC721ConfigV2 { - string name; - string symbol; - string baseURI; - EvaluableConfigV2 evaluableConfig; - EvaluableConfigV2[] flowConfig; -} - -/// @title IFlowERC721V4 -/// Conceptually identical to `IFlowV4`, but the flow contract itself is an -/// ERC721 token. This means that ERC721 self mints and burns are included in the -/// stack that the flows must evaluate to. As stacks are processed by flow from -/// bottom to top, this means that the self mint/burn will be the last thing -/// evaluated, with mints at the bottom and burns next, followed by the flows. -/// -/// As the flow is an ERC721 token it also includes an evaluation to be run on -/// every token transfer. This is the `handleTransfer` entrypoint. The return -/// stack of this evaluation is ignored, but reverts MUST be respected. This -/// allows expression authors to prevent transfers from occurring if they don't -/// want them to, by reverting within the expression. -/// -/// The flow contract also includes an evaluation to be run on every token URI -/// request. This is the `tokenURI` entrypoint. The return value of this -/// evaluation is the token ID to use for the token URI. This entryoint is -/// optional, and if not provided the token URI will be the default Open Zeppelin -/// token URI logic. -/// -/// Otherwise the flow contract is identical to `IFlowV4`. -interface IFlowERC721V4 { - /// Contract has initialized. - /// @param sender `msg.sender` initializing the contract (factory). - /// @param config All initialized config. - event Initialize(address sender, FlowERC721ConfigV2 config); - - /// As per `IFlowV4` but returns a `FlowERC721IOV1` instead of a - /// `FlowTransferV1`. - function stackToFlow(uint256[] memory stack) external pure returns (FlowERC721IOV1 memory flowERC721IO); - - /// As per `IFlowV4` but returns a `FlowERC721IOV1` instead of a - /// `FlowTransferV1` and mints/burns itself as an ERC721 accordingly. - /// @param evaluable The `Evaluable` to use to evaluate the flow. - /// @param callerContext The caller context to use to evaluate the flow. - /// @param signedContexts The signed contexts to use to evaluate the flow. - /// @return flowERC721IO The `FlowERC721IOV1` representing all token - /// mint/burns and transfers that occurred during the flow. - function flow( - Evaluable calldata evaluable, - uint256[] calldata callerContext, - SignedContextV1[] calldata signedContexts - ) external returns (FlowERC721IOV1 calldata flowERC721IO); -} diff --git a/src/interface/unstable/IFlowV4.sol b/src/interface/unstable/IFlowV4.sol deleted file mode 100644 index 27998b5e..00000000 --- a/src/interface/unstable/IFlowV4.sol +++ /dev/null @@ -1,162 +0,0 @@ -// SPDX-License-Identifier: CAL -pragma solidity ^0.8.18; - -import {SignedContextV1, EvaluableConfigV3} from "rain.interpreter.interface/interface/IInterpreterCallerV2.sol"; -import {EvaluableV2} from "rain.interpreter.interface/lib/caller/LibEvaluable.sol"; -import {Sentinel} from "rain.solmem/lib/LibStackSentinel.sol"; -import {Pointer} from "rain.solmem/lib/LibPointer.sol"; - -import { - FlowTransferV1, - ERC20Transfer, - ERC721Transfer, - ERC1155Transfer, - RAIN_FLOW_SENTINEL, - UnregisteredFlow, - UnsupportedERC20Flow, - UnsupportedERC721Flow, - UnsupportedERC1155Flow, - MIN_FLOW_SENTINELS -} from "../IFlowV3.sol"; - -/// @title IFlowV4 -/// @notice Interface for a flow contract that does NOT require native minting -/// or burning of itself as a token. This is the base case that all other flow -/// interfaces model themselves after, with the addition of token minting and -/// burning. -/// -/// Current functionality only allows for moving third party tokens between -/// accounts. Token standards ERC20, ERC721, and ERC1155 are supported. -/// -/// The basic lifecycle of a flow is: -/// - `Flow` is deployed as a reference implementation to be cloned, with its -/// initializers disabled on construction. -/// - `Flow` is cloned and initialized with an abi encoded list of evaluable -/// configs that define every possible movement of tokens that can occur due -/// to the clone. The EOA that deployed the clone DOES NOT have any special -/// privileges over the clone, although they could grant themselves privileges -/// by flowing tokens to themselves or similar within the evaluables. Ideally -/// the EOA doesn't introduce "admin" features as it would be a security risk -/// to themselves and others. In the case that they do, all priviledges will -/// be visible in the rainlang code of the evaluable, there's no hidden -/// functionality that can be introduced to the clone bytecode. -/// - Anyone can call `flow` on the clone, passing in one of the evaluables set -/// during initialization. If the evaluable passed by the caller does not -/// match an initialized evaluable, the flow MUST revert with -/// `UnregisteredFlow`. The entirety of the resulting stack from the evaluation -/// defines all the token movements that MUST occur as a result of the flow. -/// ANY failures during the flow MUST revert the entire flow, leaving the -/// state of the tokens unchanged. -/// -/// The structure of the stack can be thought of as a simple list of transfers. -/// All the erc20 tokens are moved first, then the erc721 tokens, then the -/// erc1155 tokens. Each token type is separated in the stack by a sentinel -/// value. The sentinel is a constant, `RAIN_FLOW_SENTINEL`, that is guaranteed -/// to not collide with any token amounts or addresses. The sentinel is also -/// guaranteed to not collide with any other sentinels from other contexts, to -/// the extent that we can guarantee that with raw cryptographic collision -/// resistance. This sentinel can be thought of as similar to the null terminator -/// in a c string, it's a value that is guaranteed to not be a valid value for -/// the type of data it's separating. The main benefit in this context, for -/// rainlang authors, is that they can always use the same constant value in -/// all their rainlang code to separate the different token types, rather than -/// needing to manually calculate the length of the tuples they're wanting to -/// flow over in each token type (which would be very error prone). -/// -/// Currently every token transfer type MUST be present in every flow stack, -/// which is awkward as it means that if you want to flow erc20 tokens, you -/// MUST also flow erc721 and erc1155 tokens, even if you don't want to. This -/// is a limitation of the current implementation, and will be fixed in a future -/// version. -/// -/// Each individual token transfer is simply a list of values, where the values -/// are specific to the token type. -/// - erc20 transfers are a list of 4 values: -/// - address of the token contract -/// - address of the token sender -/// - address of the token recipient -/// - amount of tokens to transfer -/// - erc721 transfers are a list of 4 values: -/// - address of the token contract -/// - address of the token sender -/// - address of the token recipient -/// - token id to transfer -/// - erc1155 transfers are a list of 5 values: -/// - address of the token contract -/// - address of the token sender -/// - address of the token recipient -/// - token id to transfer -/// - amount of tokens to transfer -/// -/// The final stack is processed from the bottom up, so the first token transfer -/// in the stack is the last one to be processed. -/// -/// For example, a rainlang expression that transfers 1e18 erc20 token 0xf00baa -/// from the flow contract to the address 0xdeadbeef, and 1 erc721 token address -/// 0x1234 and id 5678 from the address 0xdeadbeef to the flow contract, would -/// result in the following rainlang/stack: -/// -/// ``` -/// /* sentinel is always the same. */ -/// sentinel: 0xfea74d0c9bf4a3c28f0dd0674db22a3d7f8bf259c56af19f4ac1e735b156974f, -/// /* erc1155 transfers are first, just a sentinel as there's nothing to do */ -/// _: sentinel, -/// /* erc721 transfers are next, with the token id as the last value */ -/// _: 0x1234 0xdeadbeef context<0 1>() 5678, -/// /* erc20 transfers are last, with the amount as the last value */ -/// _: 0xf00baa context<0 1>() 0xdeadbeef 1e18; -/// ``` -/// -/// Note that for all token transfers the sender of the tokens MUST be either -/// the flow contract itself, or the caller of the flow contract. This is to -/// prevent the flow contract from being able to transfer tokens from arbitrary -/// addresses without their consent. Even if some address has approved the flow -/// contract to transfer tokens on their behalf, the flow contract MUST NOT -/// transfer tokens from that address unless the caller of the flow contract -/// is that address. -/// -/// Note that native gas movements are not supported in this version of the -/// flow contract. This is because the current reference implementation uses -/// `Multicall` to batch together multiple calls to the flow contract, and -/// this involves a loop over a delegate call, which is not safe to do with -/// native gas movements. This will be fixed in a future version of the interface -/// where batching is handled by the flow contract itself, rather than relying -/// on `Multicall`. -interface IFlowV4 { - /// MUST be emitted when the flow contract is initialized. - /// @param sender The EOA that deployed the flow contract. - /// @param config The list of evaluable configs that define the flows. - event Initialize(address sender, EvaluableConfigV3[] config); - - /// Given a stack of values, convert it to a flow transfer. MUST NOT modify - /// state but MAY revert if the stack is malformed. The intended workflow is - /// that the interpreter contract is called to produce a stack then the stack - /// is converted to a flow transfer struct, to allow the caller to preview - /// a flow before actually executing it. By accepting a stack as input, the - /// caller can preview any possible flow, not just ones that have been - /// registered with the flow contract, and can preview flows that may not - /// even be possible to execute due to the state of the tokens, or access - /// gating that would exclude the caller, etc. - /// @param stack The stack of values to convert to a flow transfer. - /// @return flowTransfer The resulting flow transfer. - function stackToFlow(uint256[] memory stack) external pure returns (FlowTransferV1 calldata flowTransfer); - - /// Given an evaluable, caller context, and signed contexts, evaluate the - /// evaluable and return the resulting flow transfer. MUST process the - /// flow transfer atomically, either all of it succeeds or none of it - /// succeeds. MUST revert if the evaluable is not registered with the flow - /// contract. MUST revert if the evaluable reverts. MUST revert if the - /// evaluable returns a stack that is malformed. MUST revert if the evaluable - /// returns a stack that contains a token transfer that is not allowed by - /// the flow contract (e.g. if a token is being moved from an address that - /// is not the caller or the flow contract). - /// @param evaluable The evaluable to evaluate. - /// @param callerContext The caller context to pass to the evaluable. - /// @param signedContexts The signed contexts to pass to the evaluable. - /// @return flowTransfer The resulting flow transfer. - function flow( - EvaluableV2 calldata evaluable, - uint256[] calldata callerContext, - SignedContextV1[] calldata signedContexts - ) external returns (FlowTransferV1 calldata flowTransfer); -} From 0a36669e0ad25acd4f8a5c5f561ad7bed80972a5 Mon Sep 17 00:00:00 2001 From: thedavidmeister Date: Wed, 28 Feb 2024 08:17:40 +0400 Subject: [PATCH 04/13] wip on i9r bump --- .../deprecated/v3/IFlowERC1155V3.sol | 103 +++++++++++ src/interface/deprecated/v3/IFlowERC20V3.sol | 105 ++++++++++++ src/interface/deprecated/v3/IFlowERC721V3.sol | 126 ++++++++++++++ src/interface/deprecated/v3/IFlowV3.sol | 146 ++++++++++++++++ .../deprecated/v4/IFlowERC1155V4.sol | 68 ++++++++ src/interface/deprecated/v4/IFlowERC20V4.sol | 69 ++++++++ src/interface/deprecated/v4/IFlowERC721V4.sol | 83 +++++++++ src/interface/deprecated/v4/IFlowV4.sol | 162 ++++++++++++++++++ src/interface/unstable/IFlowERC1155V5.sol | 68 ++++++++ src/interface/unstable/IFlowERC20V5.sol | 69 ++++++++ src/interface/unstable/IFlowERC721V5.sol | 83 +++++++++ src/interface/unstable/IFlowV5.sol | 162 ++++++++++++++++++ 12 files changed, 1244 insertions(+) create mode 100644 src/interface/deprecated/v3/IFlowERC1155V3.sol create mode 100644 src/interface/deprecated/v3/IFlowERC20V3.sol create mode 100644 src/interface/deprecated/v3/IFlowERC721V3.sol create mode 100644 src/interface/deprecated/v3/IFlowV3.sol create mode 100644 src/interface/deprecated/v4/IFlowERC1155V4.sol create mode 100644 src/interface/deprecated/v4/IFlowERC20V4.sol create mode 100644 src/interface/deprecated/v4/IFlowERC721V4.sol create mode 100644 src/interface/deprecated/v4/IFlowV4.sol create mode 100644 src/interface/unstable/IFlowERC1155V5.sol create mode 100644 src/interface/unstable/IFlowERC20V5.sol create mode 100644 src/interface/unstable/IFlowERC721V5.sol create mode 100644 src/interface/unstable/IFlowV5.sol diff --git a/src/interface/deprecated/v3/IFlowERC1155V3.sol b/src/interface/deprecated/v3/IFlowERC1155V3.sol new file mode 100644 index 00000000..1ec09470 --- /dev/null +++ b/src/interface/deprecated/v3/IFlowERC1155V3.sol @@ -0,0 +1,103 @@ +// SPDX-License-Identifier: CAL +pragma solidity ^0.8.18; + +import {SignedContextV1} from "rain.interpreter.interface/interface/IInterpreterCallerV2.sol"; + +import "./IFlowV3.sol"; + +/// @dev Entrypont of the `handleTransfer` evaluation. +SourceIndex constant FLOW_ERC1155_HANDLE_TRANSFER_ENTRYPOINT = SourceIndex.wrap(0); + +/// @dev Minimum number of outputs of the `handleTransfer` evaluation. +/// This is 0 because the return stack is ignored. +uint256 constant FLOW_ERC1155_HANDLE_TRANSFER_MIN_OUTPUTS = 0; + +/// @dev Maximum number of outputs of the `handleTransfer` evaluation. +/// This is 0 because the return stack is ignored. +uint16 constant FLOW_ERC1155_HANDLE_TRANSFER_MAX_OUTPUTS = 0; + +/// @dev Minimum number of sentinels required by `FlowERC1155`. +/// This is 2 more than the minimum required by `FlowCommon` because the +/// mints and burns are included in the stack. +uint256 constant FLOW_ERC1155_MIN_FLOW_SENTINELS = MIN_FLOW_SENTINELS + 2; + +/// @dev v3 of `FlowERC1155` expected a sentinel different to +/// `RAIN_FLOW_SENTINEL`, but this was generally more confusing than helpful. +Sentinel constant RAIN_FLOW_ERC1155_SENTINEL = + Sentinel.wrap(uint256(keccak256(bytes("RAIN_FLOW_ERC1155_SENTINEL")) | SENTINEL_HIGH_BITS)); + +/// Initializer config. +/// @param uri As per Open Zeppelin `ERC1155Upgradeable`. +/// @param evaluableConfig The `EvaluableConfigV2` to use to build the +/// `evaluable` that can be used to handle transfers. +/// @param flowConfig Constructor config for the `Evaluable`s that define the +/// flow behaviours including self mints/burns. +struct FlowERC1155Config { + string uri; + EvaluableConfig evaluableConfig; + EvaluableConfig[] flowConfig; +} + +/// Represents a single mint or burn of a single ERC1155 token. Whether this is +/// a mint or burn must be implied by the context. +/// @param account The address the token is being minted/burned to/from. +/// @param id The id of the token being minted/burned. +/// @param amount The amount of the token being minted/burned. +struct ERC1155SupplyChange { + address account; + uint256 id; + uint256 amount; +} + +/// Represents a set of ERC1155 transfers, including self mints/burns. +/// @param mints The mints that occurred. +/// @param burns The burns that occurred. +/// @param flow The transfers that occured. +struct FlowERC1155IOV1 { + ERC1155SupplyChange[] mints; + ERC1155SupplyChange[] burns; + FlowTransferV1 flow; +} + +/// @title IFlowERC1155V3 +/// Conceptually identical to `IFlowV3`, but the flow contract itself is an +/// ERC1155 token. This means that ERC1155 self mints and burns are included in +/// the stack that the flows must evaluate to. As stacks are processed by flow +/// from bottom to top, this means that the self mint/burn will be the last thing +/// evaluated, with mints at the bottom and burns next, followed by the flows. +/// +/// As the flow is an ERC1155 token it also includes an evaluation to be run on +/// every token transfer. This is the `handleTransfer` entrypoint. The return +/// stack of this evaluation is ignored, but reverts MUST be respected. This +/// allows expression authors to prevent transfers from occurring if they don't +/// want them to, by reverting within the expression. +/// +/// Otherwise the flow contract is identical to `IFlowV3`. +interface IFlowERC1155V3 { + /// Contract has initialized. + event Initialize(address sender, FlowERC1155Config config); + + /// As per `IFlowV3` but returns a `FlowERC1155IOV1` instead of a + /// `FlowTransferV1`. + /// @param evaluable The `Evaluable` that is flowing. + /// @param callerContext The context of the caller. + /// @param signedContexts The signed contexts of the caller. + /// @return flowERC1155IO The `FlowERC1155IOV1` that occurred. + function previewFlow( + Evaluable calldata evaluable, + uint256[] calldata callerContext, + SignedContextV1[] calldata signedContexts + ) external view returns (FlowERC1155IOV1 calldata flowERC1155IO); + + /// As per `IFlowV3` but returns a `FlowERC1155IOV1` instead of a + /// `FlowTransferV1` and mints/burns itself as an ERC1155 accordingly. + /// @param evaluable The `Evaluable` that is flowing. + /// @param callerContext The context of the caller. + /// @param signedContexts The signed contexts of the caller. + /// @return flowERC1155IO The `FlowERC1155IOV1` that occurred. + function flow( + Evaluable calldata evaluable, + uint256[] calldata callerContext, + SignedContextV1[] calldata signedContexts + ) external returns (FlowERC1155IOV1 calldata flowERC1155IO); +} diff --git a/src/interface/deprecated/v3/IFlowERC20V3.sol b/src/interface/deprecated/v3/IFlowERC20V3.sol new file mode 100644 index 00000000..bb4d93ef --- /dev/null +++ b/src/interface/deprecated/v3/IFlowERC20V3.sol @@ -0,0 +1,105 @@ +// SPDX-License-Identifier: CAL +pragma solidity ^0.8.18; + +import "rain.interpreter.interface/interface/IInterpreterCallerV2.sol"; +import "rain.interpreter.interface/lib/caller/LibEvaluable.sol"; +import {Sentinel} from "rain.solmem/lib/LibStackSentinel.sol"; +import {MIN_FLOW_SENTINELS, SENTINEL_HIGH_BITS, FlowTransferV1} from "./IFlowV3.sol"; + +/// @dev v3 of `FlowERC20` expected a sentinel different to +/// `RAIN_FLOW_SENTINEL`, but this was generally more confusing than helpful. +Sentinel constant RAIN_FLOW_ERC20_SENTINEL = + Sentinel.wrap(uint256(keccak256(bytes("RAIN_FLOW_ERC20_SENTINEL")) | SENTINEL_HIGH_BITS)); + +/// @dev Entrypont of the `handleTransfer` evaluation. +SourceIndex constant FLOW_ERC20_HANDLE_TRANSFER_ENTRYPOINT = SourceIndex.wrap(0); + +/// @dev Minimum number of outputs of the `handleTransfer` evaluation. +/// This is 0 because the return stack is ignored. +uint256 constant FLOW_ERC20_HANDLE_TRANSFER_MIN_OUTPUTS = 0; + +/// @dev Maximum number of outputs of the `handleTransfer` evaluation. +/// This is 0 because the return stack is ignored. +uint16 constant FLOW_ERC20_HANDLE_TRANSFER_MAX_OUTPUTS = 0; + +/// @dev Minimum number of sentinels required by `FlowERC20`. +/// This is 2 more than the minimum required by `FlowCommon` because the +/// mints and burns are included in the stack. +uint256 constant FLOW_ERC20_MIN_FLOW_SENTINELS = MIN_FLOW_SENTINELS + 2; + +/// Represents a single mint or burn of a single ERC20 token. Whether this is +/// a mint or burn must be implied by the context. +/// @param account The address the token is being minted/burned to/from. +/// @param amount The amount of the token being minted/burned. +struct ERC20SupplyChange { + address account; + uint256 amount; +} + +/// Represents a set of ERC20 transfers, including self mints/burns. +/// @param mints The mints that occurred. +/// @param burns The burns that occurred. +/// @param flow The transfers that occured. +struct FlowERC20IOV1 { + ERC20SupplyChange[] mints; + ERC20SupplyChange[] burns; + FlowTransferV1 flow; +} + +/// Initializer config. +/// @param name As per Open Zeppelin `ERC20Upgradeable`. +/// @param symbol As per Open Zeppelin `ERC20Upgradeable`. +/// @param evaluableConfig The `EvaluableConfigV2` to use to build the +/// `evaluable` that can be used to handle transfers. +/// @param flowConfig Initializer config for the `Evaluable`s that define the +/// flow behaviours including self mints/burns. +struct FlowERC20Config { + string name; + string symbol; + EvaluableConfig evaluableConfig; + EvaluableConfig[] flowConfig; +} + +/// @title IFlowERC20V3 +/// @notice Mints itself according to some predefined schedule. The schedule is +/// expressed as an expression and the `claim` function is world-callable. +/// Intended behaviour is to avoid sybils infinitely minting by putting the +/// claim functionality behind a `TierV2` contract. The flow contract +/// itself implements `ReadOnlyTier` and every time a claim is processed it +/// logs the block number of the claim against every tier claimed. So the block +/// numbers in the tier report for `FlowERC20` are the last time that tier +/// was claimed against this contract. The simplest way to make use of this +/// information is to take the max block for the underlying tier and the last +/// claim and then diff it against the current block number. +/// See `test/Claim/FlowERC20.sol.ts` for examples, including providing +/// staggered rewards where more tokens are minted for higher tier accounts. +interface IFlowERC20V3 { + /// Contract has initialized. + /// @param sender `msg.sender` initializing the contract (factory). + /// @param config All initialized config. + event Initialize(address sender, FlowERC20Config config); + + /// As per `IFlowV3` but returns a `FlowERC20IOV1` instead of a + /// `FlowTransferV1`. + /// @param evaluable The `Evaluable` to use to evaluate the flow. + /// @param callerContext The caller context to use to evaluate the flow. + /// @param signedContexts The signed contexts to use to evaluate the flow. + /// @return flowERC20IO The `FlowERC20IOV1` that occurred. + function previewFlow( + Evaluable calldata evaluable, + uint256[] calldata callerContext, + SignedContextV1[] calldata signedContexts + ) external view returns (FlowERC20IOV1 calldata flowERC20IO); + + /// As per `IFlowV3` but returns a `FlowERC20IOV1` instead of a + /// `FlowTransferV1` and mints/burns itself as an ERC20 accordingly. + /// @param evaluable The `Evaluable` to use to evaluate the flow. + /// @param callerContext The caller context to use to evaluate the flow. + /// @param signedContexts The signed contexts to use to evaluate the flow. + /// @return flowERC20IO The `FlowERC20IOV1` that occurred. + function flow( + Evaluable calldata evaluable, + uint256[] calldata callerContext, + SignedContextV1[] calldata signedContexts + ) external returns (FlowERC20IOV1 calldata flowERC20IO); +} diff --git a/src/interface/deprecated/v3/IFlowERC721V3.sol b/src/interface/deprecated/v3/IFlowERC721V3.sol new file mode 100644 index 00000000..0af859da --- /dev/null +++ b/src/interface/deprecated/v3/IFlowERC721V3.sol @@ -0,0 +1,126 @@ +// SPDX-License-Identifier: CAL +pragma solidity ^0.8.18; + +import "rain.interpreter.interface/interface/IInterpreterCallerV2.sol"; +import "rain.interpreter.interface/lib/caller/LibEvaluable.sol"; + +import "./IFlowV3.sol"; + +/// @dev Entrypont of the `handleTransfer` evaluation. +SourceIndex constant FLOW_ERC721_HANDLE_TRANSFER_ENTRYPOINT = SourceIndex.wrap(0); +/// @dev Entrypont of the `tokenURI` evaluation. +SourceIndex constant FLOW_ERC721_TOKEN_URI_ENTRYPOINT = SourceIndex.wrap(1); + +/// @dev Minimum number of outputs of the `handleTransfer` evaluation. +/// This is 0 because the return stack is ignored. +uint256 constant FLOW_ERC721_HANDLE_TRANSFER_MIN_OUTPUTS = 0; +/// @dev Minimum number of outputs of the `tokenURI` evaluation. +/// This is 1 because we can only handle a single token ID value. +uint256 constant FLOW_ERC721_TOKEN_URI_MIN_OUTPUTS = 1; + +/// @dev Maximum number of outputs of the `handleTransfer` evaluation. +/// This is 0 because the return stack is ignored. +uint16 constant FLOW_ERC721_HANDLE_TRANSFER_MAX_OUTPUTS = 0; +/// @dev Maximum number of outputs of the `tokenURI` evaluation. +/// This is 1 because we can only handle a single token ID value. +uint16 constant FLOW_ERC721_TOKEN_URI_MAX_OUTPUTS = 1; + +/// @dev v3 of `FlowERC721` expected a sentinel different to +/// `RAIN_FLOW_SENTINEL`, but this was generally more confusing than helpful. +Sentinel constant RAIN_FLOW_ERC721_SENTINEL = + Sentinel.wrap(uint256(keccak256(bytes("RAIN_FLOW_ERC721_SENTINEL")) | SENTINEL_HIGH_BITS)); + +/// @dev Minimum number of sentinels required by `FlowERC721`. +/// This is 2 more than the minimum required by `FlowCommon` because the +/// mints and burns are included in the stack. +uint256 constant FLOW_ERC721_MIN_FLOW_SENTINELS = MIN_FLOW_SENTINELS + 2; + +/// Initializer config. +/// @param name As per Open Zeppelin `ERC721Upgradeable`. +/// @param symbol As per Open Zeppelin `ERC721Upgradeable`. +/// @param baseURI As per Open Zeppelin `ERC721Upgradeable`. +/// @param evaluableConfig The `EvaluableConfigV2` to use to build the +/// `evaluable` that can be used to handle transfers and token URIs. The token +/// URI entrypoint is optional. +/// @param flowConfig Constructor config for the `Evaluable`s that define the +/// flow behaviours including self mints/burns. +struct FlowERC721Config { + string name; + string symbol; + string baseURI; + EvaluableConfig evaluableConfig; + EvaluableConfig[] flowConfig; +} + +/// Represents a single mint or burn of a single ERC721 token. Whether this is +/// a mint or burn must be implied by the context. +/// @param account The address the token is being minted/burned to/from. +/// @param id The id of the token being minted/burned. +struct ERC721SupplyChange { + address account; + uint256 id; +} + +/// Represents a set of ERC721 transfers, including self mints/burns. +/// @param mints The mints that occurred. +/// @param burns The burns that occurred. +/// @param flow The transfers that occured. +struct FlowERC721IOV1 { + ERC721SupplyChange[] mints; + ERC721SupplyChange[] burns; + FlowTransferV1 flow; +} + +/// @title IFlowERC721V3 +/// Conceptually identical to `IFlowV3`, but the flow contract itself is an +/// ERC721 token. This means that ERC721 self mints and burns are included in +/// the stack. +/// +/// As the flow is an ERC721 token, there are two entrypoints in addition to +/// the flows: +/// - `handleTransfer` is called when the flow is transferred. +/// - `tokenURI` is called when the token URI is requested. +/// +/// The `handleTransfer` entrypoint is mandatory, but the `tokenURI` entrypoint +/// is optional. If the `tokenURI` entrypoint is not provided, the default +/// Open Zeppelin implementation will be used. +/// +/// The `handleTransfer` entrypoint may be used to restrict transfers of the +/// flow token. For example, it may be used to restrict transfers to only +/// occur when the flow is in a certain state. +/// +/// The `tokenURI` entrypoint may be used to provide a custom token ID to build +/// a token URI for the flow token. +/// +/// Otherwise the flow contract behaves identically to `IFlowV3`. +interface IFlowERC721V3 { + /// Contract has initialized. + /// @param sender `msg.sender` initializing the contract (factory). + /// @param config All initialized config. + event Initialize(address sender, FlowERC721Config config); + + /// As per `IFlowV3` but returns a `FlowERC721IOV1` instead of a + /// `FlowTransferV1`. + /// @param evaluable The `Evaluable` that is flowing. + /// @param callerContext The context of the caller. + /// @param signedContexts The signed contexts of the caller. + /// @return flowERC721IO The `FlowERC721IOV1` that would occur if the flow + /// was executed. + function previewFlow( + Evaluable calldata evaluable, + uint256[] calldata callerContext, + SignedContextV1[] calldata signedContexts + ) external view returns (FlowERC721IOV1 calldata flowERC721IO); + + /// As per `IFlowV3` but returns a `FlowERC721IOV1` instead of a + /// `FlowTransferV1` and mints/burns itself as an ERC721 accordingly. + /// @param evaluable The `Evaluable` that is flowing. + /// @param callerContext The context of the caller. + /// @param signedContexts The signed contexts of the caller. + /// @return flowERC721IO The `FlowERC721IOV1` that occurred. + function flow( + Evaluable calldata evaluable, + uint256[] calldata callerContext, + SignedContextV1[] calldata signedContexts + ) external returns (FlowERC721IOV1 calldata flowERC721IO); +} diff --git a/src/interface/deprecated/v3/IFlowV3.sol b/src/interface/deprecated/v3/IFlowV3.sol new file mode 100644 index 00000000..6fef197d --- /dev/null +++ b/src/interface/deprecated/v3/IFlowV3.sol @@ -0,0 +1,146 @@ +// SPDX-License-Identifier: CAL +pragma solidity ^0.8.18; + +import {SourceIndex} from "rain.interpreter.interface/interface/deprecated/IInterpreterV1.sol"; +import {Evaluable, EvaluableConfig} from "rain.interpreter.interface/interface/deprecated/IInterpreterCallerV1.sol"; +import {SignedContextV1} from "rain.interpreter.interface/interface/IInterpreterCallerV2.sol"; +import "rain.interpreter.interface/lib/caller/LibEvaluable.sol"; +import {Sentinel} from "rain.solmem/lib/LibStackSentinel.sol"; + +/// Thrown when the flow being evaluated is unregistered. +/// @param unregisteredHash Hash of the unregistered flow. +error UnregisteredFlow(bytes32 unregisteredHash); + +/// Thrown for unsupported native transfers. +error UnsupportedNativeFlow(); + +/// Thrown for unsupported erc20 transfers. +error UnsupportedERC20Flow(); + +/// Thrown for unsupported erc721 transfers. +error UnsupportedERC721Flow(); + +/// Thrown for unsupported erc1155 transfers. +error UnsupportedERC1155Flow(); + +/// @dev The number of sentinels required by `FlowCommon`. An evaluable can never +/// have fewer minimum outputs than required sentinels. +uint256 constant MIN_FLOW_SENTINELS = 3; + +/// @dev Sets the high bits of all flow sentinels to guarantee that the numeric +/// value of the sentinel will never collide with a token amount or address. This +/// guarantee holds as long as the token supply is less than 2^252, and the +/// that token IDs have no specific reason to collide with the sentinel. +/// i.e. There won't be random collisions because the space of token IDs is +/// too large. +bytes32 constant SENTINEL_HIGH_BITS = bytes32(0xF000000000000000000000000000000000000000000000000000000000000000); + +/// @dev We want a sentinel with the following properties: +/// - Won't collide with token amounts (| with very large number) +/// - Won't collide with token addresses +/// - Won't collide with common values like `type(uint256).max` and +/// `type(uint256).min` +/// - Won't collide with other sentinels from unrelated contexts +Sentinel constant RAIN_FLOW_SENTINEL = + Sentinel.wrap(uint256(keccak256(bytes("RAIN_FLOW_SENTINEL")) | SENTINEL_HIGH_BITS)); + +/// Wraps `EvaluableConfig[]` to workaround a Solidity bug. +/// https://github.com/ethereum/solidity/issues/13597 +/// @param dummyConfig A dummy config to workaround a Solidity bug. +/// @param config The list of evaluable configs that define the flows. +struct FlowConfig { + EvaluableConfig dummyConfig; + EvaluableConfig[] config; +} + +/// Represents a single transfer of a single ERC20 token. +/// @param token The address of the ERC20 token being transferred. +/// @param from The address the token is being transferred from. +/// @param to The address the token is being transferred to. +/// @param amount The amount of the token being transferred. +struct ERC20Transfer { + address token; + address from; + address to; + uint256 amount; +} + +/// Represents a single transfer of a single ERC721 token. +/// @param token The address of the ERC721 token being transferred. +/// @param from The address the token is being transferred from. +/// @param to The address the token is being transferred to. +/// @param id The id of the token being transferred. +struct ERC721Transfer { + address token; + address from; + address to; + uint256 id; +} + +/// Represents a single transfer of a single ERC1155 token. +/// @param token The address of the ERC1155 token being transferred. +/// @param from The address the token is being transferred from. +/// @param to The address the token is being transferred to. +/// @param id The id of the token being transferred. +/// @param amount The amount of the token being transferred. +struct ERC1155Transfer { + address token; + address from; + address to; + uint256 id; + uint256 amount; +} + +/// Represents an ordered set of transfers that will be or have been executed. +/// Supports ERC20, ERC721, and ERC1155 transfers. +/// @param erc20 An array of ERC20 transfers. +/// @param erc721 An array of ERC721 transfers. +/// @param erc1155 An array of ERC1155 transfers. +struct FlowTransferV1 { + ERC20Transfer[] erc20; + ERC721Transfer[] erc721; + ERC1155Transfer[] erc1155; +} + +/// @title IFlowV3 +/// At a high level, identical to `IFlowV4` but with an older, less flexible +/// previewing system, and the older `FlowConfig` struct that was used with +/// older versions of the interpreter. +interface IFlowV3 { + /// MUST be emitted when the flow contract is initialized. + /// @param sender The EOA that deployed the flow contract. + /// @param config The list of evaluable configs that define the flows. + event Initialize(address sender, FlowConfig config); + + /// "Dry run" of a flow, returning the resulting token transfers without + /// actually executing them. + /// @param evaluable The evaluable to evaluate. + /// @param callerContext The caller context to use when evaluating the + /// flow. + /// @param signedContexts The signed contexts to use when evaluating the + /// flow. + function previewFlow( + Evaluable calldata evaluable, + uint256[] calldata callerContext, + SignedContextV1[] calldata signedContexts + ) external view returns (FlowTransferV1 calldata flowTransfer); + + /// Given an evaluable, caller context, and signed contexts, evaluate the + /// evaluable and return the resulting flow transfer. MUST process the + /// flow transfer atomically, either all of it succeeds or none of it + /// succeeds. MUST revert if the evaluable is not registered with the flow + /// contract. MUST revert if the evaluable reverts. MUST revert if the + /// evaluable returns a stack that is malformed. MUST revert if the evaluable + /// returns a stack that contains a token transfer that is not allowed by + /// the flow contract (e.g. if a token is being moved from an address that + /// is not the caller or the flow contract). + /// @param evaluable The evaluable to evaluate. + /// @param callerContext The caller context to pass to the evaluable. + /// @param signedContexts The signed contexts to pass to the evaluable. + /// @return flowTransfer The resulting flow transfer. + function flow( + Evaluable calldata evaluable, + uint256[] calldata callerContext, + SignedContextV1[] calldata signedContexts + ) external returns (FlowTransferV1 calldata flowTransfer); +} diff --git a/src/interface/deprecated/v4/IFlowERC1155V4.sol b/src/interface/deprecated/v4/IFlowERC1155V4.sol new file mode 100644 index 00000000..4c2cdcb1 --- /dev/null +++ b/src/interface/deprecated/v4/IFlowERC1155V4.sol @@ -0,0 +1,68 @@ +// SPDX-License-Identifier: CAL +pragma solidity ^0.8.18; + +import {SignedContextV1, EvaluableConfigV3} from "rain.interpreter.interface/interface/IInterpreterCallerV2.sol"; +import {EvaluableV2} from "rain.interpreter.interface/lib/caller/LibEvaluable.sol"; +import {Sentinel} from "rain.solmem/lib/LibStackSentinel.sol"; +import {RAIN_FLOW_SENTINEL} from "./IFlowV4.sol"; + +import { + FlowERC1155IOV1, + ERC1155SupplyChange, + FLOW_ERC1155_HANDLE_TRANSFER_MAX_OUTPUTS, + FLOW_ERC1155_HANDLE_TRANSFER_ENTRYPOINT, + FLOW_ERC1155_HANDLE_TRANSFER_MIN_OUTPUTS, + FLOW_ERC1155_MIN_FLOW_SENTINELS +} from "../IFlowERC1155V3.sol"; + +/// Initialization config. +/// @param uri As per Open Zeppelin `ERC1155Upgradeable`. +/// @param evaluableConfig The `EvaluableConfigV2` to use to build the +/// `evaluable` that can be used to handle transfers. +/// @param flowConfig Initialization config for the `Evaluable`s that define the +/// flow behaviours outside self mints/burns. +struct FlowERC1155ConfigV2 { + string uri; + EvaluableConfigV3 evaluableConfig; + EvaluableConfigV3[] flowConfig; +} + +/// @title IFlowERC1155V4 +/// Conceptually identical to `IFlowV4`, but the flow contract itself is an +/// ERC1155 token. This means that ERC1155 self mints and burns are included in +/// the stack that the flows must evaluate to. As stacks are processed by flow +/// from bottom to top, this means that the self mint/burn will be the last thing +/// evaluated, with mints at the bottom and burns next, followed by the flows. +/// +/// As the flow is an ERC1155 token it also includes an evaluation to be run on +/// every token transfer. This is the `handleTransfer` entrypoint. The return +/// stack of this evaluation is ignored, but reverts MUST be respected. This +/// allows expression authors to prevent transfers from occurring if they don't +/// want them to, by reverting within the expression. +/// +/// Otherwise the flow contract is identical to `IFlowV4`. +interface IFlowERC1155V4 { + /// Contract has initialized. + /// @param sender `msg.sender` initializing the contract (factory). + /// @param config All initialized config. + event Initialize(address sender, FlowERC1155ConfigV2 config); + + /// As per `IFlowV4` but returns a `FlowERC1155IOV1` instead of a + /// `FlowTransferV1`. + /// @param stack The stack to convert to a `FlowERC1155IOV1`. + /// @return flowERC1155IO The `FlowERC1155IOV1` representation of the stack. + function stackToFlow(uint256[] memory stack) external pure returns (FlowERC1155IOV1 memory flowERC1155IO); + + /// As per `IFlowV4` but returns a `FlowERC1155IOV1` instead of a + /// `FlowTransferV1` and mints/burns itself as an ERC1155 accordingly. + /// @param evaluable The `Evaluable` to use to evaluate the flow. + /// @param callerContext The caller context to use to evaluate the flow. + /// @param signedContexts The signed contexts to use to evaluate the flow. + /// @return flowERC1155IO The `FlowERC1155IOV1` representing all token + /// mint/burns and transfers that occurred during the flow. + function flow( + EvaluableV2 calldata evaluable, + uint256[] calldata callerContext, + SignedContextV1[] calldata signedContexts + ) external returns (FlowERC1155IOV1 calldata); +} diff --git a/src/interface/deprecated/v4/IFlowERC20V4.sol b/src/interface/deprecated/v4/IFlowERC20V4.sol new file mode 100644 index 00000000..728e093a --- /dev/null +++ b/src/interface/deprecated/v4/IFlowERC20V4.sol @@ -0,0 +1,69 @@ +// SPDX-License-Identifier: CAL +pragma solidity ^0.8.18; + +import {SignedContextV1} from "rain.interpreter.interface/interface/IInterpreterCallerV2.sol"; +import {EvaluableV2} from "rain.interpreter.interface/lib/caller/LibEvaluable.sol"; +import {Sentinel} from "rain.solmem/lib/LibStackSentinel.sol"; +import { + FlowERC20IOV1, + ERC20SupplyChange, + FLOW_ERC20_HANDLE_TRANSFER_ENTRYPOINT, + FLOW_ERC20_HANDLE_TRANSFER_MIN_OUTPUTS, + FLOW_ERC20_HANDLE_TRANSFER_MAX_OUTPUTS, + FLOW_ERC20_MIN_FLOW_SENTINELS +} from "../IFlowERC20V3.sol"; +import {RAIN_FLOW_SENTINEL} from "./IFlowV4.sol"; + +/// Initialization config. +/// @param name As per Open Zeppelin `ERC20Upgradeable`. +/// @param symbol As per Open Zeppelin `ERC20Upgradeable`. +/// @param evaluableConfig The `EvaluableConfigV2` to use to build the +/// `evaluable` that can be used to evaluate `handleTransfer`. +/// @param flowConfig The `EvaluableConfigV2[]` to use to build the +/// `evaluable`s for all the flows, including self minting and burning. +struct FlowERC20ConfigV2 { + string name; + string symbol; + EvaluableConfigV2 evaluableConfig; + EvaluableConfigV2[] flowConfig; +} + +/// @title IFlowERC20V4 +/// Conceptually identical to `IFlowV4`, but the flow contract itself is an +/// ERC20 token. This means that ERC20 self mints and burns are included in the +/// stack that the flows must evaluate to. As stacks are processed by flow from +/// bottom to top, this means that the self mint/burn will be the last thing +/// evaluated, with mints at the bottom and burns next, followed by the flows. +/// +/// As the flow is an ERC20 token it also includes an evaluation to be run on +/// every token transfer. This is the `handleTransfer` entrypoint. The return +/// stack of this evaluation is ignored, but reverts MUST be respected. This +/// allows expression authors to prevent transfers from occurring if they don't +/// want them to, by reverting within the expression. +/// +/// Otherwise the flow contract is identical to `IFlowV4`. +interface IFlowERC20V4 { + /// Contract has initialized. + /// @param sender `msg.sender` initializing the contract (factory). + /// @param config All initialized config. + event Initialize(address sender, FlowERC20ConfigV2 config); + + /// As per `IFlowV4` but returns a `FlowERC20IOV1` instead of a + /// `FlowTransferV1`. + /// @param stack The stack to convert to a `FlowERC20IOV1`. + /// @return flowERC20IO The `FlowERC20IOV1` representation of the stack. + function stackToFlow(uint256[] memory stack) external pure returns (FlowERC20IOV1 memory flowERC20IO); + + /// As per `IFlowV4` but returns a `FlowERC20IOV1` instead of a + /// `FlowTransferV1` and mints/burns itself as an ERC20 accordingly. + /// @param evaluable The `Evaluable` to use to evaluate the flow. + /// @param callerContext The caller context to use to evaluate the flow. + /// @param signedContexts The signed contexts to use to evaluate the flow. + /// @return flowERC20IO The `FlowERC20IOV1` representing all token mint/burns + /// and transfers that occurred during the flow. + function flow( + Evaluable calldata evaluable, + uint256[] calldata callerContext, + SignedContextV1[] calldata signedContexts + ) external returns (FlowERC20IOV1 calldata flowERC20IO); +} diff --git a/src/interface/deprecated/v4/IFlowERC721V4.sol b/src/interface/deprecated/v4/IFlowERC721V4.sol new file mode 100644 index 00000000..d76a94a2 --- /dev/null +++ b/src/interface/deprecated/v4/IFlowERC721V4.sol @@ -0,0 +1,83 @@ +// SPDX-License-Identifier: CAL +pragma solidity ^0.8.18; + +import "rain.interpreter.interface/interface/IInterpreterCallerV2.sol"; +import "rain.interpreter.interface/lib/caller/LibEvaluable.sol"; + +import { + FlowERC721IOV1, + ERC721SupplyChange, + FLOW_ERC721_TOKEN_URI_MIN_OUTPUTS, + FLOW_ERC721_TOKEN_URI_MAX_OUTPUTS, + FLOW_ERC721_HANDLE_TRANSFER_MIN_OUTPUTS, + FLOW_ERC721_HANDLE_TRANSFER_MAX_OUTPUTS, + FLOW_ERC721_TOKEN_URI_ENTRYPOINT, + FLOW_ERC721_HANDLE_TRANSFER_ENTRYPOINT, + FLOW_ERC721_MIN_FLOW_SENTINELS +} from "../IFlowERC721V3.sol"; + +import {RAIN_FLOW_SENTINEL} from "./IFlowV4.sol"; + +/// Thrown when burner of tokens is not the owner of tokens. +error BurnerNotOwner(); + +/// Initialization config. +/// @param name As per Open Zeppelin `ERC721Upgradeable`. +/// @param symbol As per Open Zeppelin `ERC721Upgradeable`. +/// @param baseURI As per Open Zeppelin `ERC721Upgradeable`. +/// @param evaluableConfig The `EvaluableConfigV2` to use to build the +/// `evaluable` that can be used to handle transfers and build token IDs for the +/// token URI. +/// @param flowConfig Initialization config for the `Evaluable`s that define the +/// flow behaviours outside self mints/burns. +struct FlowERC721ConfigV2 { + string name; + string symbol; + string baseURI; + EvaluableConfigV2 evaluableConfig; + EvaluableConfigV2[] flowConfig; +} + +/// @title IFlowERC721V4 +/// Conceptually identical to `IFlowV4`, but the flow contract itself is an +/// ERC721 token. This means that ERC721 self mints and burns are included in the +/// stack that the flows must evaluate to. As stacks are processed by flow from +/// bottom to top, this means that the self mint/burn will be the last thing +/// evaluated, with mints at the bottom and burns next, followed by the flows. +/// +/// As the flow is an ERC721 token it also includes an evaluation to be run on +/// every token transfer. This is the `handleTransfer` entrypoint. The return +/// stack of this evaluation is ignored, but reverts MUST be respected. This +/// allows expression authors to prevent transfers from occurring if they don't +/// want them to, by reverting within the expression. +/// +/// The flow contract also includes an evaluation to be run on every token URI +/// request. This is the `tokenURI` entrypoint. The return value of this +/// evaluation is the token ID to use for the token URI. This entryoint is +/// optional, and if not provided the token URI will be the default Open Zeppelin +/// token URI logic. +/// +/// Otherwise the flow contract is identical to `IFlowV4`. +interface IFlowERC721V4 { + /// Contract has initialized. + /// @param sender `msg.sender` initializing the contract (factory). + /// @param config All initialized config. + event Initialize(address sender, FlowERC721ConfigV2 config); + + /// As per `IFlowV4` but returns a `FlowERC721IOV1` instead of a + /// `FlowTransferV1`. + function stackToFlow(uint256[] memory stack) external pure returns (FlowERC721IOV1 memory flowERC721IO); + + /// As per `IFlowV4` but returns a `FlowERC721IOV1` instead of a + /// `FlowTransferV1` and mints/burns itself as an ERC721 accordingly. + /// @param evaluable The `Evaluable` to use to evaluate the flow. + /// @param callerContext The caller context to use to evaluate the flow. + /// @param signedContexts The signed contexts to use to evaluate the flow. + /// @return flowERC721IO The `FlowERC721IOV1` representing all token + /// mint/burns and transfers that occurred during the flow. + function flow( + Evaluable calldata evaluable, + uint256[] calldata callerContext, + SignedContextV1[] calldata signedContexts + ) external returns (FlowERC721IOV1 calldata flowERC721IO); +} diff --git a/src/interface/deprecated/v4/IFlowV4.sol b/src/interface/deprecated/v4/IFlowV4.sol new file mode 100644 index 00000000..27998b5e --- /dev/null +++ b/src/interface/deprecated/v4/IFlowV4.sol @@ -0,0 +1,162 @@ +// SPDX-License-Identifier: CAL +pragma solidity ^0.8.18; + +import {SignedContextV1, EvaluableConfigV3} from "rain.interpreter.interface/interface/IInterpreterCallerV2.sol"; +import {EvaluableV2} from "rain.interpreter.interface/lib/caller/LibEvaluable.sol"; +import {Sentinel} from "rain.solmem/lib/LibStackSentinel.sol"; +import {Pointer} from "rain.solmem/lib/LibPointer.sol"; + +import { + FlowTransferV1, + ERC20Transfer, + ERC721Transfer, + ERC1155Transfer, + RAIN_FLOW_SENTINEL, + UnregisteredFlow, + UnsupportedERC20Flow, + UnsupportedERC721Flow, + UnsupportedERC1155Flow, + MIN_FLOW_SENTINELS +} from "../IFlowV3.sol"; + +/// @title IFlowV4 +/// @notice Interface for a flow contract that does NOT require native minting +/// or burning of itself as a token. This is the base case that all other flow +/// interfaces model themselves after, with the addition of token minting and +/// burning. +/// +/// Current functionality only allows for moving third party tokens between +/// accounts. Token standards ERC20, ERC721, and ERC1155 are supported. +/// +/// The basic lifecycle of a flow is: +/// - `Flow` is deployed as a reference implementation to be cloned, with its +/// initializers disabled on construction. +/// - `Flow` is cloned and initialized with an abi encoded list of evaluable +/// configs that define every possible movement of tokens that can occur due +/// to the clone. The EOA that deployed the clone DOES NOT have any special +/// privileges over the clone, although they could grant themselves privileges +/// by flowing tokens to themselves or similar within the evaluables. Ideally +/// the EOA doesn't introduce "admin" features as it would be a security risk +/// to themselves and others. In the case that they do, all priviledges will +/// be visible in the rainlang code of the evaluable, there's no hidden +/// functionality that can be introduced to the clone bytecode. +/// - Anyone can call `flow` on the clone, passing in one of the evaluables set +/// during initialization. If the evaluable passed by the caller does not +/// match an initialized evaluable, the flow MUST revert with +/// `UnregisteredFlow`. The entirety of the resulting stack from the evaluation +/// defines all the token movements that MUST occur as a result of the flow. +/// ANY failures during the flow MUST revert the entire flow, leaving the +/// state of the tokens unchanged. +/// +/// The structure of the stack can be thought of as a simple list of transfers. +/// All the erc20 tokens are moved first, then the erc721 tokens, then the +/// erc1155 tokens. Each token type is separated in the stack by a sentinel +/// value. The sentinel is a constant, `RAIN_FLOW_SENTINEL`, that is guaranteed +/// to not collide with any token amounts or addresses. The sentinel is also +/// guaranteed to not collide with any other sentinels from other contexts, to +/// the extent that we can guarantee that with raw cryptographic collision +/// resistance. This sentinel can be thought of as similar to the null terminator +/// in a c string, it's a value that is guaranteed to not be a valid value for +/// the type of data it's separating. The main benefit in this context, for +/// rainlang authors, is that they can always use the same constant value in +/// all their rainlang code to separate the different token types, rather than +/// needing to manually calculate the length of the tuples they're wanting to +/// flow over in each token type (which would be very error prone). +/// +/// Currently every token transfer type MUST be present in every flow stack, +/// which is awkward as it means that if you want to flow erc20 tokens, you +/// MUST also flow erc721 and erc1155 tokens, even if you don't want to. This +/// is a limitation of the current implementation, and will be fixed in a future +/// version. +/// +/// Each individual token transfer is simply a list of values, where the values +/// are specific to the token type. +/// - erc20 transfers are a list of 4 values: +/// - address of the token contract +/// - address of the token sender +/// - address of the token recipient +/// - amount of tokens to transfer +/// - erc721 transfers are a list of 4 values: +/// - address of the token contract +/// - address of the token sender +/// - address of the token recipient +/// - token id to transfer +/// - erc1155 transfers are a list of 5 values: +/// - address of the token contract +/// - address of the token sender +/// - address of the token recipient +/// - token id to transfer +/// - amount of tokens to transfer +/// +/// The final stack is processed from the bottom up, so the first token transfer +/// in the stack is the last one to be processed. +/// +/// For example, a rainlang expression that transfers 1e18 erc20 token 0xf00baa +/// from the flow contract to the address 0xdeadbeef, and 1 erc721 token address +/// 0x1234 and id 5678 from the address 0xdeadbeef to the flow contract, would +/// result in the following rainlang/stack: +/// +/// ``` +/// /* sentinel is always the same. */ +/// sentinel: 0xfea74d0c9bf4a3c28f0dd0674db22a3d7f8bf259c56af19f4ac1e735b156974f, +/// /* erc1155 transfers are first, just a sentinel as there's nothing to do */ +/// _: sentinel, +/// /* erc721 transfers are next, with the token id as the last value */ +/// _: 0x1234 0xdeadbeef context<0 1>() 5678, +/// /* erc20 transfers are last, with the amount as the last value */ +/// _: 0xf00baa context<0 1>() 0xdeadbeef 1e18; +/// ``` +/// +/// Note that for all token transfers the sender of the tokens MUST be either +/// the flow contract itself, or the caller of the flow contract. This is to +/// prevent the flow contract from being able to transfer tokens from arbitrary +/// addresses without their consent. Even if some address has approved the flow +/// contract to transfer tokens on their behalf, the flow contract MUST NOT +/// transfer tokens from that address unless the caller of the flow contract +/// is that address. +/// +/// Note that native gas movements are not supported in this version of the +/// flow contract. This is because the current reference implementation uses +/// `Multicall` to batch together multiple calls to the flow contract, and +/// this involves a loop over a delegate call, which is not safe to do with +/// native gas movements. This will be fixed in a future version of the interface +/// where batching is handled by the flow contract itself, rather than relying +/// on `Multicall`. +interface IFlowV4 { + /// MUST be emitted when the flow contract is initialized. + /// @param sender The EOA that deployed the flow contract. + /// @param config The list of evaluable configs that define the flows. + event Initialize(address sender, EvaluableConfigV3[] config); + + /// Given a stack of values, convert it to a flow transfer. MUST NOT modify + /// state but MAY revert if the stack is malformed. The intended workflow is + /// that the interpreter contract is called to produce a stack then the stack + /// is converted to a flow transfer struct, to allow the caller to preview + /// a flow before actually executing it. By accepting a stack as input, the + /// caller can preview any possible flow, not just ones that have been + /// registered with the flow contract, and can preview flows that may not + /// even be possible to execute due to the state of the tokens, or access + /// gating that would exclude the caller, etc. + /// @param stack The stack of values to convert to a flow transfer. + /// @return flowTransfer The resulting flow transfer. + function stackToFlow(uint256[] memory stack) external pure returns (FlowTransferV1 calldata flowTransfer); + + /// Given an evaluable, caller context, and signed contexts, evaluate the + /// evaluable and return the resulting flow transfer. MUST process the + /// flow transfer atomically, either all of it succeeds or none of it + /// succeeds. MUST revert if the evaluable is not registered with the flow + /// contract. MUST revert if the evaluable reverts. MUST revert if the + /// evaluable returns a stack that is malformed. MUST revert if the evaluable + /// returns a stack that contains a token transfer that is not allowed by + /// the flow contract (e.g. if a token is being moved from an address that + /// is not the caller or the flow contract). + /// @param evaluable The evaluable to evaluate. + /// @param callerContext The caller context to pass to the evaluable. + /// @param signedContexts The signed contexts to pass to the evaluable. + /// @return flowTransfer The resulting flow transfer. + function flow( + EvaluableV2 calldata evaluable, + uint256[] calldata callerContext, + SignedContextV1[] calldata signedContexts + ) external returns (FlowTransferV1 calldata flowTransfer); +} diff --git a/src/interface/unstable/IFlowERC1155V5.sol b/src/interface/unstable/IFlowERC1155V5.sol new file mode 100644 index 00000000..4c2cdcb1 --- /dev/null +++ b/src/interface/unstable/IFlowERC1155V5.sol @@ -0,0 +1,68 @@ +// SPDX-License-Identifier: CAL +pragma solidity ^0.8.18; + +import {SignedContextV1, EvaluableConfigV3} from "rain.interpreter.interface/interface/IInterpreterCallerV2.sol"; +import {EvaluableV2} from "rain.interpreter.interface/lib/caller/LibEvaluable.sol"; +import {Sentinel} from "rain.solmem/lib/LibStackSentinel.sol"; +import {RAIN_FLOW_SENTINEL} from "./IFlowV4.sol"; + +import { + FlowERC1155IOV1, + ERC1155SupplyChange, + FLOW_ERC1155_HANDLE_TRANSFER_MAX_OUTPUTS, + FLOW_ERC1155_HANDLE_TRANSFER_ENTRYPOINT, + FLOW_ERC1155_HANDLE_TRANSFER_MIN_OUTPUTS, + FLOW_ERC1155_MIN_FLOW_SENTINELS +} from "../IFlowERC1155V3.sol"; + +/// Initialization config. +/// @param uri As per Open Zeppelin `ERC1155Upgradeable`. +/// @param evaluableConfig The `EvaluableConfigV2` to use to build the +/// `evaluable` that can be used to handle transfers. +/// @param flowConfig Initialization config for the `Evaluable`s that define the +/// flow behaviours outside self mints/burns. +struct FlowERC1155ConfigV2 { + string uri; + EvaluableConfigV3 evaluableConfig; + EvaluableConfigV3[] flowConfig; +} + +/// @title IFlowERC1155V4 +/// Conceptually identical to `IFlowV4`, but the flow contract itself is an +/// ERC1155 token. This means that ERC1155 self mints and burns are included in +/// the stack that the flows must evaluate to. As stacks are processed by flow +/// from bottom to top, this means that the self mint/burn will be the last thing +/// evaluated, with mints at the bottom and burns next, followed by the flows. +/// +/// As the flow is an ERC1155 token it also includes an evaluation to be run on +/// every token transfer. This is the `handleTransfer` entrypoint. The return +/// stack of this evaluation is ignored, but reverts MUST be respected. This +/// allows expression authors to prevent transfers from occurring if they don't +/// want them to, by reverting within the expression. +/// +/// Otherwise the flow contract is identical to `IFlowV4`. +interface IFlowERC1155V4 { + /// Contract has initialized. + /// @param sender `msg.sender` initializing the contract (factory). + /// @param config All initialized config. + event Initialize(address sender, FlowERC1155ConfigV2 config); + + /// As per `IFlowV4` but returns a `FlowERC1155IOV1` instead of a + /// `FlowTransferV1`. + /// @param stack The stack to convert to a `FlowERC1155IOV1`. + /// @return flowERC1155IO The `FlowERC1155IOV1` representation of the stack. + function stackToFlow(uint256[] memory stack) external pure returns (FlowERC1155IOV1 memory flowERC1155IO); + + /// As per `IFlowV4` but returns a `FlowERC1155IOV1` instead of a + /// `FlowTransferV1` and mints/burns itself as an ERC1155 accordingly. + /// @param evaluable The `Evaluable` to use to evaluate the flow. + /// @param callerContext The caller context to use to evaluate the flow. + /// @param signedContexts The signed contexts to use to evaluate the flow. + /// @return flowERC1155IO The `FlowERC1155IOV1` representing all token + /// mint/burns and transfers that occurred during the flow. + function flow( + EvaluableV2 calldata evaluable, + uint256[] calldata callerContext, + SignedContextV1[] calldata signedContexts + ) external returns (FlowERC1155IOV1 calldata); +} diff --git a/src/interface/unstable/IFlowERC20V5.sol b/src/interface/unstable/IFlowERC20V5.sol new file mode 100644 index 00000000..190c1cd4 --- /dev/null +++ b/src/interface/unstable/IFlowERC20V5.sol @@ -0,0 +1,69 @@ +// SPDX-License-Identifier: CAL +pragma solidity ^0.8.18; + +import {SignedContextV1} from "rain.interpreter.interface/interface/IInterpreterCallerV2.sol"; +import {EvaluableV2} from "rain.interpreter.interface/lib/caller/LibEvaluable.sol"; +import {Sentinel} from "rain.solmem/lib/LibStackSentinel.sol"; +import { + FlowERC20IOV1, + ERC20SupplyChange, + FLOW_ERC20_HANDLE_TRANSFER_ENTRYPOINT, + FLOW_ERC20_HANDLE_TRANSFER_MIN_OUTPUTS, + FLOW_ERC20_HANDLE_TRANSFER_MAX_OUTPUTS, + FLOW_ERC20_MIN_FLOW_SENTINELS +} from "../IFlowERC20V3.sol"; +import {RAIN_FLOW_SENTINEL} from "./IFlowV4.sol"; + +/// Initialization config. +/// @param name As per Open Zeppelin `ERC20Upgradeable`. +/// @param symbol As per Open Zeppelin `ERC20Upgradeable`. +/// @param evaluableConfig The `EvaluableConfigV2` to use to build the +/// `evaluable` that can be used to evaluate `handleTransfer`. +/// @param flowConfig The `EvaluableConfigV2[]` to use to build the +/// `evaluable`s for all the flows, including self minting and burning. +struct FlowERC20ConfigV2 { + string name; + string symbol; + EvaluableConfigV2 evaluableConfig; + EvaluableConfigV2[] flowConfig; +} + +/// @title IFlowERC20V5 +/// Conceptually identical to `IFlowV5`, but the flow contract itself is an +/// ERC20 token. This means that ERC20 self mints and burns are included in the +/// stack that the flows must evaluate to. As stacks are processed by flow from +/// bottom to top, this means that the self mint/burn will be the last thing +/// evaluated, with mints at the bottom and burns next, followed by the flows. +/// +/// As the flow is an ERC20 token it also includes an evaluation to be run on +/// every token transfer. This is the `handleTransfer` entrypoint. The return +/// stack of this evaluation is ignored, but reverts MUST be respected. This +/// allows expression authors to prevent transfers from occurring if they don't +/// want them to, by reverting within the expression. +/// +/// Otherwise the flow contract is identical to `IFlowV5`. +interface IFlowERC20V5 { + /// Contract has initialized. + /// @param sender `msg.sender` initializing the contract (factory). + /// @param config All initialized config. + event Initialize(address sender, FlowERC20ConfigV2 config); + + /// As per `IFlowV4` but returns a `FlowERC20IOV1` instead of a + /// `FlowTransferV1`. + /// @param stack The stack to convert to a `FlowERC20IOV1`. + /// @return flowERC20IO The `FlowERC20IOV1` representation of the stack. + function stackToFlow(uint256[] memory stack) external pure returns (FlowERC20IOV1 memory flowERC20IO); + + /// As per `IFlowV4` but returns a `FlowERC20IOV1` instead of a + /// `FlowTransferV1` and mints/burns itself as an ERC20 accordingly. + /// @param evaluable The `Evaluable` to use to evaluate the flow. + /// @param callerContext The caller context to use to evaluate the flow. + /// @param signedContexts The signed contexts to use to evaluate the flow. + /// @return flowERC20IO The `FlowERC20IOV1` representing all token mint/burns + /// and transfers that occurred during the flow. + function flow( + Evaluable calldata evaluable, + uint256[] calldata callerContext, + SignedContextV1[] calldata signedContexts + ) external returns (FlowERC20IOV1 calldata flowERC20IO); +} diff --git a/src/interface/unstable/IFlowERC721V5.sol b/src/interface/unstable/IFlowERC721V5.sol new file mode 100644 index 00000000..d76a94a2 --- /dev/null +++ b/src/interface/unstable/IFlowERC721V5.sol @@ -0,0 +1,83 @@ +// SPDX-License-Identifier: CAL +pragma solidity ^0.8.18; + +import "rain.interpreter.interface/interface/IInterpreterCallerV2.sol"; +import "rain.interpreter.interface/lib/caller/LibEvaluable.sol"; + +import { + FlowERC721IOV1, + ERC721SupplyChange, + FLOW_ERC721_TOKEN_URI_MIN_OUTPUTS, + FLOW_ERC721_TOKEN_URI_MAX_OUTPUTS, + FLOW_ERC721_HANDLE_TRANSFER_MIN_OUTPUTS, + FLOW_ERC721_HANDLE_TRANSFER_MAX_OUTPUTS, + FLOW_ERC721_TOKEN_URI_ENTRYPOINT, + FLOW_ERC721_HANDLE_TRANSFER_ENTRYPOINT, + FLOW_ERC721_MIN_FLOW_SENTINELS +} from "../IFlowERC721V3.sol"; + +import {RAIN_FLOW_SENTINEL} from "./IFlowV4.sol"; + +/// Thrown when burner of tokens is not the owner of tokens. +error BurnerNotOwner(); + +/// Initialization config. +/// @param name As per Open Zeppelin `ERC721Upgradeable`. +/// @param symbol As per Open Zeppelin `ERC721Upgradeable`. +/// @param baseURI As per Open Zeppelin `ERC721Upgradeable`. +/// @param evaluableConfig The `EvaluableConfigV2` to use to build the +/// `evaluable` that can be used to handle transfers and build token IDs for the +/// token URI. +/// @param flowConfig Initialization config for the `Evaluable`s that define the +/// flow behaviours outside self mints/burns. +struct FlowERC721ConfigV2 { + string name; + string symbol; + string baseURI; + EvaluableConfigV2 evaluableConfig; + EvaluableConfigV2[] flowConfig; +} + +/// @title IFlowERC721V4 +/// Conceptually identical to `IFlowV4`, but the flow contract itself is an +/// ERC721 token. This means that ERC721 self mints and burns are included in the +/// stack that the flows must evaluate to. As stacks are processed by flow from +/// bottom to top, this means that the self mint/burn will be the last thing +/// evaluated, with mints at the bottom and burns next, followed by the flows. +/// +/// As the flow is an ERC721 token it also includes an evaluation to be run on +/// every token transfer. This is the `handleTransfer` entrypoint. The return +/// stack of this evaluation is ignored, but reverts MUST be respected. This +/// allows expression authors to prevent transfers from occurring if they don't +/// want them to, by reverting within the expression. +/// +/// The flow contract also includes an evaluation to be run on every token URI +/// request. This is the `tokenURI` entrypoint. The return value of this +/// evaluation is the token ID to use for the token URI. This entryoint is +/// optional, and if not provided the token URI will be the default Open Zeppelin +/// token URI logic. +/// +/// Otherwise the flow contract is identical to `IFlowV4`. +interface IFlowERC721V4 { + /// Contract has initialized. + /// @param sender `msg.sender` initializing the contract (factory). + /// @param config All initialized config. + event Initialize(address sender, FlowERC721ConfigV2 config); + + /// As per `IFlowV4` but returns a `FlowERC721IOV1` instead of a + /// `FlowTransferV1`. + function stackToFlow(uint256[] memory stack) external pure returns (FlowERC721IOV1 memory flowERC721IO); + + /// As per `IFlowV4` but returns a `FlowERC721IOV1` instead of a + /// `FlowTransferV1` and mints/burns itself as an ERC721 accordingly. + /// @param evaluable The `Evaluable` to use to evaluate the flow. + /// @param callerContext The caller context to use to evaluate the flow. + /// @param signedContexts The signed contexts to use to evaluate the flow. + /// @return flowERC721IO The `FlowERC721IOV1` representing all token + /// mint/burns and transfers that occurred during the flow. + function flow( + Evaluable calldata evaluable, + uint256[] calldata callerContext, + SignedContextV1[] calldata signedContexts + ) external returns (FlowERC721IOV1 calldata flowERC721IO); +} diff --git a/src/interface/unstable/IFlowV5.sol b/src/interface/unstable/IFlowV5.sol new file mode 100644 index 00000000..27998b5e --- /dev/null +++ b/src/interface/unstable/IFlowV5.sol @@ -0,0 +1,162 @@ +// SPDX-License-Identifier: CAL +pragma solidity ^0.8.18; + +import {SignedContextV1, EvaluableConfigV3} from "rain.interpreter.interface/interface/IInterpreterCallerV2.sol"; +import {EvaluableV2} from "rain.interpreter.interface/lib/caller/LibEvaluable.sol"; +import {Sentinel} from "rain.solmem/lib/LibStackSentinel.sol"; +import {Pointer} from "rain.solmem/lib/LibPointer.sol"; + +import { + FlowTransferV1, + ERC20Transfer, + ERC721Transfer, + ERC1155Transfer, + RAIN_FLOW_SENTINEL, + UnregisteredFlow, + UnsupportedERC20Flow, + UnsupportedERC721Flow, + UnsupportedERC1155Flow, + MIN_FLOW_SENTINELS +} from "../IFlowV3.sol"; + +/// @title IFlowV4 +/// @notice Interface for a flow contract that does NOT require native minting +/// or burning of itself as a token. This is the base case that all other flow +/// interfaces model themselves after, with the addition of token minting and +/// burning. +/// +/// Current functionality only allows for moving third party tokens between +/// accounts. Token standards ERC20, ERC721, and ERC1155 are supported. +/// +/// The basic lifecycle of a flow is: +/// - `Flow` is deployed as a reference implementation to be cloned, with its +/// initializers disabled on construction. +/// - `Flow` is cloned and initialized with an abi encoded list of evaluable +/// configs that define every possible movement of tokens that can occur due +/// to the clone. The EOA that deployed the clone DOES NOT have any special +/// privileges over the clone, although they could grant themselves privileges +/// by flowing tokens to themselves or similar within the evaluables. Ideally +/// the EOA doesn't introduce "admin" features as it would be a security risk +/// to themselves and others. In the case that they do, all priviledges will +/// be visible in the rainlang code of the evaluable, there's no hidden +/// functionality that can be introduced to the clone bytecode. +/// - Anyone can call `flow` on the clone, passing in one of the evaluables set +/// during initialization. If the evaluable passed by the caller does not +/// match an initialized evaluable, the flow MUST revert with +/// `UnregisteredFlow`. The entirety of the resulting stack from the evaluation +/// defines all the token movements that MUST occur as a result of the flow. +/// ANY failures during the flow MUST revert the entire flow, leaving the +/// state of the tokens unchanged. +/// +/// The structure of the stack can be thought of as a simple list of transfers. +/// All the erc20 tokens are moved first, then the erc721 tokens, then the +/// erc1155 tokens. Each token type is separated in the stack by a sentinel +/// value. The sentinel is a constant, `RAIN_FLOW_SENTINEL`, that is guaranteed +/// to not collide with any token amounts or addresses. The sentinel is also +/// guaranteed to not collide with any other sentinels from other contexts, to +/// the extent that we can guarantee that with raw cryptographic collision +/// resistance. This sentinel can be thought of as similar to the null terminator +/// in a c string, it's a value that is guaranteed to not be a valid value for +/// the type of data it's separating. The main benefit in this context, for +/// rainlang authors, is that they can always use the same constant value in +/// all their rainlang code to separate the different token types, rather than +/// needing to manually calculate the length of the tuples they're wanting to +/// flow over in each token type (which would be very error prone). +/// +/// Currently every token transfer type MUST be present in every flow stack, +/// which is awkward as it means that if you want to flow erc20 tokens, you +/// MUST also flow erc721 and erc1155 tokens, even if you don't want to. This +/// is a limitation of the current implementation, and will be fixed in a future +/// version. +/// +/// Each individual token transfer is simply a list of values, where the values +/// are specific to the token type. +/// - erc20 transfers are a list of 4 values: +/// - address of the token contract +/// - address of the token sender +/// - address of the token recipient +/// - amount of tokens to transfer +/// - erc721 transfers are a list of 4 values: +/// - address of the token contract +/// - address of the token sender +/// - address of the token recipient +/// - token id to transfer +/// - erc1155 transfers are a list of 5 values: +/// - address of the token contract +/// - address of the token sender +/// - address of the token recipient +/// - token id to transfer +/// - amount of tokens to transfer +/// +/// The final stack is processed from the bottom up, so the first token transfer +/// in the stack is the last one to be processed. +/// +/// For example, a rainlang expression that transfers 1e18 erc20 token 0xf00baa +/// from the flow contract to the address 0xdeadbeef, and 1 erc721 token address +/// 0x1234 and id 5678 from the address 0xdeadbeef to the flow contract, would +/// result in the following rainlang/stack: +/// +/// ``` +/// /* sentinel is always the same. */ +/// sentinel: 0xfea74d0c9bf4a3c28f0dd0674db22a3d7f8bf259c56af19f4ac1e735b156974f, +/// /* erc1155 transfers are first, just a sentinel as there's nothing to do */ +/// _: sentinel, +/// /* erc721 transfers are next, with the token id as the last value */ +/// _: 0x1234 0xdeadbeef context<0 1>() 5678, +/// /* erc20 transfers are last, with the amount as the last value */ +/// _: 0xf00baa context<0 1>() 0xdeadbeef 1e18; +/// ``` +/// +/// Note that for all token transfers the sender of the tokens MUST be either +/// the flow contract itself, or the caller of the flow contract. This is to +/// prevent the flow contract from being able to transfer tokens from arbitrary +/// addresses without their consent. Even if some address has approved the flow +/// contract to transfer tokens on their behalf, the flow contract MUST NOT +/// transfer tokens from that address unless the caller of the flow contract +/// is that address. +/// +/// Note that native gas movements are not supported in this version of the +/// flow contract. This is because the current reference implementation uses +/// `Multicall` to batch together multiple calls to the flow contract, and +/// this involves a loop over a delegate call, which is not safe to do with +/// native gas movements. This will be fixed in a future version of the interface +/// where batching is handled by the flow contract itself, rather than relying +/// on `Multicall`. +interface IFlowV4 { + /// MUST be emitted when the flow contract is initialized. + /// @param sender The EOA that deployed the flow contract. + /// @param config The list of evaluable configs that define the flows. + event Initialize(address sender, EvaluableConfigV3[] config); + + /// Given a stack of values, convert it to a flow transfer. MUST NOT modify + /// state but MAY revert if the stack is malformed. The intended workflow is + /// that the interpreter contract is called to produce a stack then the stack + /// is converted to a flow transfer struct, to allow the caller to preview + /// a flow before actually executing it. By accepting a stack as input, the + /// caller can preview any possible flow, not just ones that have been + /// registered with the flow contract, and can preview flows that may not + /// even be possible to execute due to the state of the tokens, or access + /// gating that would exclude the caller, etc. + /// @param stack The stack of values to convert to a flow transfer. + /// @return flowTransfer The resulting flow transfer. + function stackToFlow(uint256[] memory stack) external pure returns (FlowTransferV1 calldata flowTransfer); + + /// Given an evaluable, caller context, and signed contexts, evaluate the + /// evaluable and return the resulting flow transfer. MUST process the + /// flow transfer atomically, either all of it succeeds or none of it + /// succeeds. MUST revert if the evaluable is not registered with the flow + /// contract. MUST revert if the evaluable reverts. MUST revert if the + /// evaluable returns a stack that is malformed. MUST revert if the evaluable + /// returns a stack that contains a token transfer that is not allowed by + /// the flow contract (e.g. if a token is being moved from an address that + /// is not the caller or the flow contract). + /// @param evaluable The evaluable to evaluate. + /// @param callerContext The caller context to pass to the evaluable. + /// @param signedContexts The signed contexts to pass to the evaluable. + /// @return flowTransfer The resulting flow transfer. + function flow( + EvaluableV2 calldata evaluable, + uint256[] calldata callerContext, + SignedContextV1[] calldata signedContexts + ) external returns (FlowTransferV1 calldata flowTransfer); +} From 272ff50b8d2f9440460fdc2eeeaa1b8b2257cc5d Mon Sep 17 00:00:00 2001 From: thedavidmeister Date: Wed, 28 Feb 2024 09:02:31 +0400 Subject: [PATCH 05/13] wip on i9r bump --- src/abstract/FlowCommon.sol | 6 +- src/concrete/basic/Flow.meta.json | 52 -------- src/concrete/basic/Flow.sol | 3 +- src/concrete/erc1155/FlowERC1155.meta.json | 121 ------------------ src/concrete/erc1155/FlowERC1155.sol | 14 +- src/concrete/erc20/FlowERC20.meta.json | 115 ----------------- src/concrete/erc20/FlowERC20.sol | 37 +++--- src/concrete/erc721/FlowERC721.meta.json | 121 ------------------ src/concrete/erc721/FlowERC721.sol | 46 ++++--- src/interface/deprecated/v2/IFlowV2.sol | 1 + src/interface/deprecated/v3/IFlowERC20V3.sol | 5 +- src/interface/deprecated/v3/IFlowV3.sol | 16 --- .../deprecated/v4/IFlowERC1155V4.sol | 2 +- src/interface/deprecated/v4/IFlowERC20V4.sol | 4 +- src/interface/deprecated/v4/IFlowERC721V4.sol | 5 +- src/interface/deprecated/v4/IFlowV4.sol | 6 +- src/interface/unstable/IFlowERC1155V5.sol | 4 +- src/interface/unstable/IFlowERC20V5.sol | 12 +- src/interface/unstable/IFlowERC721V5.sol | 30 ++--- src/interface/unstable/IFlowV5.sol | 9 +- src/lib/LibFlow.sol | 14 +- test/interface/unstable/IFlowV4.t.sol | 2 +- 22 files changed, 95 insertions(+), 530 deletions(-) delete mode 100644 src/concrete/basic/Flow.meta.json delete mode 100644 src/concrete/erc1155/FlowERC1155.meta.json delete mode 100644 src/concrete/erc20/FlowERC20.meta.json delete mode 100644 src/concrete/erc721/FlowERC721.meta.json diff --git a/src/abstract/FlowCommon.sol b/src/abstract/FlowCommon.sol index fea5f9c1..faa9ef8d 100644 --- a/src/abstract/FlowCommon.sol +++ b/src/abstract/FlowCommon.sol @@ -10,7 +10,7 @@ import { } from "rain.interpreter.interface/interface/IInterpreterCallerV2.sol"; import {LibEncodedDispatch} from "rain.interpreter.interface/lib/caller/LibEncodedDispatch.sol"; import {LibContext} from "rain.interpreter.interface/lib/caller/LibContext.sol"; -import {UnregisteredFlow, MIN_FLOW_SENTINELS} from "../interface/unstable/IFlowV4.sol"; +import {UnregisteredFlow, MIN_FLOW_SENTINELS} from "../interface/unstable/IFlowV5.sol"; import {LibEvaluable, EvaluableV2} from "rain.interpreter.interface/lib/caller/LibEvaluable.sol"; import { SourceIndexV2, @@ -198,10 +198,10 @@ abstract contract FlowCommon is ERC721Holder, ERC1155Holder, Multicall, Reentran } } - (uint256[] memory stack, uint256[] memory kvs) = evaluable.interpreter.eval( + (uint256[] memory stack, uint256[] memory kvs) = evaluable.interpreter.eval2( evaluable.store, DEFAULT_STATE_NAMESPACE, - LibEncodedDispatch.encode(evaluable.expression, FLOW_ENTRYPOINT, FLOW_MAX_OUTPUTS), + LibEncodedDispatch.encode2(evaluable.expression, FLOW_ENTRYPOINT, FLOW_MAX_OUTPUTS), context ); return (stack.dataPointer(), stack.endPointer(), kvs); diff --git a/src/concrete/basic/Flow.meta.json b/src/concrete/basic/Flow.meta.json deleted file mode 100644 index 03fb64f6..00000000 --- a/src/concrete/basic/Flow.meta.json +++ /dev/null @@ -1,52 +0,0 @@ -{ - "name": "Flow", - "abiName": "Flow", - "desc": "Flow contracts transfer tokens based on deployed expressions.", - "alias": "flow", - "source": "https://github.com/rainprotocol/rain-protocol", - "methods": [ - { - "name": "initialize", - "abiName": "initialize", - "desc": "Initialize a new Flow ERC20 contract.", - "expressions": [ - { - "name": "Dummy Expression", - "abiName": "dummyConfig", - "desc": "A dummy expression. This is here to workaround a bug in Solidity.", - "path": "[13].inputs[1].components[0]" - }, - { - "name": "Flows", - "abiName": "config", - "desc": "The available flows.", - "path": "[13].inputs[1].components[1]", - "signedContext": true, - "callerContext": true, - "contextColumns": [ - { - "name": "Base", - "desc": "Base context column.", - "alias": "base", - "columnIndex": 0, - "cells": [ - { - "name": "Flow caller", - "desc": "The contract or wallet that called flow.", - "alias": "flow-caller", - "cellIndex": 0 - }, - { - "name": "Flow contract", - "desc": "The address of the flow contract.", - "alias": "flow-contract", - "cellIndex": 1 - } - ] - } - ] - } - ] - } - ] -} diff --git a/src/concrete/basic/Flow.sol b/src/concrete/basic/Flow.sol index aa8503cf..e7a07b7c 100644 --- a/src/concrete/basic/Flow.sol +++ b/src/concrete/basic/Flow.sol @@ -3,13 +3,12 @@ pragma solidity =0.8.19; import {ICloneableV2, ICLONEABLE_V2_SUCCESS} from "rain.factory/src/interface/ICloneableV2.sol"; import {FlowCommon, LibContext} from "../../abstract/FlowCommon.sol"; -import {IFlowV4, MIN_FLOW_SENTINELS} from "../../interface/unstable/IFlowV4.sol"; +import {IFlowV4, MIN_FLOW_SENTINELS, FlowTransferV1} from "../../interface/unstable/IFlowV5.sol"; import {LibFlow} from "../../lib/LibFlow.sol"; import {LibUint256Matrix} from "rain.solmem/lib/LibUint256Matrix.sol"; import {Pointer} from "rain.solmem/lib/LibPointer.sol"; import {LibUint256Array} from "rain.solmem/lib/LibUint256Array.sol"; import {EvaluableV2} from "rain.interpreter.interface/lib/caller/LibEvaluable.sol"; -import {FlowTransferV1} from "../../interface/unstable/IFlowV4.sol"; import {SignedContextV1, EvaluableConfigV3} from "rain.interpreter.interface/interface/IInterpreterCallerV2.sol"; /// @title Flow diff --git a/src/concrete/erc1155/FlowERC1155.meta.json b/src/concrete/erc1155/FlowERC1155.meta.json deleted file mode 100644 index c004228c..00000000 --- a/src/concrete/erc1155/FlowERC1155.meta.json +++ /dev/null @@ -1,121 +0,0 @@ -{ - "name": "Flow ERC1155", - "abiName": "FlowERC1155", - "desc": "A flow contract that is also an ERC1155 token that can be minted by expressions. Transfers can be restricted by an expression.", - "alias": "flow-erc1155", - "source": "https://github.com/rainprotocol/rain-protocol", - "methods": [ - { - "name": "initialize", - "abiName": "initialize", - "desc": "Initialize a FlowERC1155 contract.", - "inputs": [ - { - "name": "URI", - "abiName": "uri", - "desc": "The URI for the ERC1155 token that is minted.", - "path": "[14].inputs[1].components[0]" - } - ], - "expressions": [ - { - "name": "Handle transfer", - "abiName": "evaluableConfig", - "desc": "Review and restrict transfers of the flow contract's own ERC1155 token. Mint and burns must be controlled by the flow expressions instead.", - "path": "[14].inputs[1].components[1]", - "signedContext": false, - "contextColumns": [ - { - "name": "Base", - "desc": "Base context column", - "alias": "base", - "columnIndex": 0, - "cells": [ - { - "name": "Transfer caller", - "desc": "The contract or wallet that called transfer.", - "alias": "transfer-caller", - "cellIndex": 0 - }, - { - "name": "Flow contract", - "desc": "The address of the FlowERC1155 contract.", - "alias": "flow-contract", - "cellIndex": 1 - } - ] - }, - { - "name": "Transfer information", - "desc": "Information about the current transfer.", - "alias": "transfer-information", - "columnIndex": 1, - "cells": [ - { - "name": "Transfer operator", - "desc": "The address of the transfer operator.", - "alias": "transfer-operator-address", - "cellIndex": 0 - }, - { - "name": "Transfer from address", - "desc": "The address the token is being transferred from.", - "alias": "transfer-from-address", - "cellIndex": 1 - }, - { - "name": "Transfer to address", - "desc": "The address the token is being transferred to.", - "alias": "transfer-to-address", - "cellIndex": 2 - } - ] - }, - { - "name": "Token IDs", - "desc": "All the ERC1155 ids being transferred.", - "alias": "transfer-ids", - "columnIndex": 2 - }, - { - "name": "Token amounts", - "desc": "All the ERC1155 amounts being transferred, pairwise with the IDs.", - "alias": "transfer-amounts", - "columnIndex": 3 - } - ] - }, - { - "name": "Flows", - "abiName": "flowConfig", - "desc": "The available flows for this token.", - "path": "[14].inputs[1].components[2]", - "signedContext": true, - "callerContext": true, - "contextColumns": [ - { - "name": "Base", - "desc": "Base context column.", - "alias": "base", - "columnIndex": 0, - "cells": [ - { - "name": "Flow caller", - "desc": "The contract or wallet that called flow.", - "alias": "flow-caller", - "cellIndex": 0 - }, - { - "name": "Flow contract", - "desc": "The address of the FlowERC1155 contract.", - "alias": "flow-contract", - "cellIndex": 1 - } - ] - } - ] - } - ] - } - ] -} diff --git a/src/concrete/erc1155/FlowERC1155.sol b/src/concrete/erc1155/FlowERC1155.sol index 4c7e89f1..4a086719 100644 --- a/src/concrete/erc1155/FlowERC1155.sol +++ b/src/concrete/erc1155/FlowERC1155.sol @@ -20,7 +20,7 @@ import { FLOW_ERC1155_HANDLE_TRANSFER_MAX_OUTPUTS, FLOW_ERC1155_HANDLE_TRANSFER_MIN_OUTPUTS, FLOW_ERC1155_MIN_FLOW_SENTINELS -} from "../../interface/unstable/IFlowERC1155V4.sol"; +} from "../../interface/unstable/IFlowERC1155V5.sol"; import {LibBytecode} from "rain.interpreter.interface/lib/bytecode/LibBytecode.sol"; import { IInterpreterV2, DEFAULT_STATE_NAMESPACE @@ -68,10 +68,10 @@ contract FlowERC1155 is ICloneableV2, IFlowERC1155V4, FlowCommon, ERC1155 { flowCommonInit(flowERC1155Config.flowConfig, FLOW_ERC1155_MIN_FLOW_SENTINELS); if (evalHandleTransfer) { - (IInterpreterV1 interpreter, IInterpreterStoreV1 store, address expression) = flowERC1155Config + (IInterpreterV2 interpreter, IInterpreterStoreV2 store, address expression) = flowERC1155Config .evaluableConfig .deployer - .deployExpression( + .deployExpression2( flowERC1155Config.evaluableConfig.bytecode, flowERC1155Config.evaluableConfig.constants, LibUint256Array.arrayFrom(FLOW_ERC1155_HANDLE_TRANSFER_MIN_OUTPUTS) @@ -83,7 +83,7 @@ contract FlowERC1155 is ICloneableV2, IFlowERC1155V4, FlowCommon, ERC1155 { // integrity checks are complete. // The deployer MUST be a trusted contract anyway. // slither-disable-next-line reentrancy-benign - sEvaluable = Evaluable(interpreter, store, expression); + sEvaluable = EvaluableV2(interpreter, store, expression); } return ICLONEABLE_V2_SUCCESS; @@ -115,7 +115,7 @@ contract FlowERC1155 is ICloneableV2, IFlowERC1155V4, FlowCommon, ERC1155 { // Mint and burn access MUST be handled by flow. // HANDLE_TRANSFER will only restrict subsequent transfers. if (sEvalHandleTransfer && !(from == address(0) || to == address(0))) { - Evaluable memory evaluable = sEvaluable; + EvaluableV2 memory evaluable = sEvaluable; uint256[][] memory context; { context = LibContext.build( @@ -132,10 +132,10 @@ contract FlowERC1155 is ICloneableV2, IFlowERC1155V4, FlowCommon, ERC1155 { ); } - (uint256[] memory stack, uint256[] memory kvs) = evaluable.interpreter.eval( + (uint256[] memory stack, uint256[] memory kvs) = evaluable.interpreter.eval2( evaluable.store, DEFAULT_STATE_NAMESPACE, - LibEncodedDispatch.encode( + LibEncodedDispatch.encode2( evaluable.expression, FLOW_ERC1155_HANDLE_TRANSFER_ENTRYPOINT, FLOW_ERC1155_HANDLE_TRANSFER_MAX_OUTPUTS diff --git a/src/concrete/erc20/FlowERC20.meta.json b/src/concrete/erc20/FlowERC20.meta.json deleted file mode 100644 index 4b624ed2..00000000 --- a/src/concrete/erc20/FlowERC20.meta.json +++ /dev/null @@ -1,115 +0,0 @@ -{ - "name": "Flow ERC20", - "abiName": "FlowERC20", - "desc": "A flow contract that is also an ERC20 token that can be minted by expressions. Transfers can be restricted by an expression.", - "alias": "flow-erc20", - "source": "https://github.com/rainprotocol/rain-protocol", - "methods": [ - { - "name": "initialize", - "abiName": "initialize", - "desc": "Initialize a FlowERC20 contract.", - "inputs": [ - { - "name": "Name", - "abiName": "name", - "desc": "Name of the ERC20 token that is minted.", - "path": "[14].inputs[1].components[0]" - }, - { - "name": "Symbol", - "abiName": "symbol", - "desc": "Symbol of the ERC20 token that is minted.", - "path": "[14].inputs[1].components[1]" - } - ], - "expressions": [ - { - "name": "Handle Transfer", - "abiName": "evaluableConfig", - "desc": "Review and restrict transfers of the flow contract's own ERC20 token. Mint and burns must be controlled by the flow expressions instead.", - "path": "[14].inputs[1].components[2]", - "signedContext": false, - "contextColumns": [ - { - "name": "Base", - "desc": "Base context column.", - "alias": "base", - "columnIndex": 0, - "cells": [ - { - "name": "Transfer caller", - "desc": "The contract or wallet that called transfer.", - "alias": "transfer-caller", - "cellIndex": 0 - }, - { - "name": "Flow contract", - "desc": "The address of the FlowERC20 contract.", - "alias": "flow-contract", - "cellIndex": 1 - } - ] - }, - { - "name": "Transfer information", - "desc": "Information about the current transfer.", - "alias": "transfer-information", - "columnIndex": 1, - "cells": [ - { - "name": "Transfer from address", - "desc": "The address the token is being transferred from.", - "alias": "transfer-from-address", - "cellIndex": 0 - }, - { - "name": "Transfer to address", - "desc": "The address the token is being transferred to.", - "alias": "transfer-to-address", - "cellIndex": 1 - }, - { - "name": "Transfer amount", - "desc": "The amount of token being transferred.", - "alias": "transfer-amount", - "cellIndex": 2 - } - ] - } - ] - }, - { - "name": "Flows", - "abiName": "flowConfig", - "desc": "The available flows.", - "path": "[14].inputs[1].components[3]", - "signedContext": true, - "callerContext": true, - "contextColumns": [ - { - "name": "Base", - "desc": "Base context column.", - "alias": "base", - "columnIndex": 0, - "cells": [ - { - "name": "Flow caller", - "desc": "The contract or wallet that called flow.", - "alias": "flow-caller", - "cellIndex": 0 - }, - { - "name": "Flow contract", - "desc": "The address of the FlowERC20 contract.", - "alias": "flow-contract", - "cellIndex": 1 - } - ] - } - ] - } - ] - } - ] -} diff --git a/src/concrete/erc20/FlowERC20.sol b/src/concrete/erc20/FlowERC20.sol index 85012f7b..20bb18be 100644 --- a/src/concrete/erc20/FlowERC20.sol +++ b/src/concrete/erc20/FlowERC20.sol @@ -7,7 +7,7 @@ import {LibUint256Array} from "rain.solmem/lib/LibUint256Array.sol"; import {LibUint256Matrix} from "rain.solmem/lib/LibUint256Matrix.sol"; import {ICloneableV2, ICLONEABLE_V2_SUCCESS} from "rain.factory/src/interface/ICloneableV2.sol"; import { - IFlowERC20V4, + IFlowERC20V5, FlowERC20IOV1, FlowERC20ConfigV2, ERC20SupplyChange, @@ -17,7 +17,7 @@ import { FLOW_ERC20_HANDLE_TRANSFER_MAX_OUTPUTS, RAIN_FLOW_SENTINEL, FLOW_ERC20_MIN_FLOW_SENTINELS -} from "../../interface/unstable/IFlowERC20V4.sol"; +} from "../../interface/unstable/IFlowERC20V5.sol"; import {LibBytecode} from "rain.interpreter.interface/lib/bytecode/LibBytecode.sol"; import {EncodedDispatch, LibEncodedDispatch} from "rain.interpreter.interface/lib/caller/LibEncodedDispatch.sol"; import {Sentinel, LibStackSentinel} from "rain.solmem/lib/LibStackSentinel.sol"; @@ -28,7 +28,7 @@ import { IInterpreterV2, DEFAULT_STATE_NAMESPACE } from "rain.interpreter.interface/interface/unstable/IInterpreterV2.sol"; -import {IInterpreterStoreV1} from "rain.interpreter.interface/interface/IInterpreterStoreV1.sol"; +import {IInterpreterStoreV2} from "rain.interpreter.interface/interface/unstable/IInterpreterStoreV2.sol"; import {Pointer} from "rain.solmem/lib/LibPointer.sol"; import {EvaluableV2} from "rain.interpreter.interface/lib/caller/LibEvaluable.sol"; import {LibContext} from "rain.interpreter.interface/lib/caller/LibContext.sol"; @@ -38,8 +38,8 @@ import {LibContext} from "rain.interpreter.interface/lib/caller/LibContext.sol"; bytes32 constant CALLER_META_HASH = bytes32(0xff0499e4ee7171a54d176cfe13165a7ea512d146dbd99d42b3d3ec9963025acf); /// @title FlowERC20 -/// See `IFlowERC20V4` for documentation. -contract FlowERC20 is ICloneableV2, IFlowERC20V4, FlowCommon, ERC20 { +/// See `IFlowERC20V5` for documentation. +contract FlowERC20 is ICloneableV2, IFlowERC20V5, FlowCommon, ERC20 { using LibStackSentinel for Pointer; using LibUint256Matrix for uint256[]; using LibUint256Array for uint256[]; @@ -51,10 +51,7 @@ contract FlowERC20 is ICloneableV2, IFlowERC20V4, FlowCommon, ERC20 { /// @dev The evaluable that will be used to evaluate `handleTransfer` on /// every transfer. This is only set if `sEvalHandleTransfer` is true. - Evaluable internal sEvaluable; - - /// Forwards the `FlowCommon` constructor arguments to the `FlowCommon`. - constructor(DeployerDiscoverableMetaV2ConstructionConfig memory config) FlowCommon(CALLER_META_HASH, config) {} + EvaluableV2 internal sEvaluable; /// Overloaded typed initialize function MUST revert with this error. /// As per `ICloneableV2` interface. @@ -71,17 +68,17 @@ contract FlowERC20 is ICloneableV2, IFlowERC20V4, FlowCommon, ERC20 { // Set state before external calls here. bool evalHandleTransfer = LibBytecode.sourceCount(flowERC20Config.evaluableConfig.bytecode) > 0 && LibBytecode.sourceOpsCount( - flowERC20Config.evaluableConfig.bytecode, SourceIndex.unwrap(FLOW_ERC20_HANDLE_TRANSFER_ENTRYPOINT) + flowERC20Config.evaluableConfig.bytecode, SourceIndexV2.unwrap(FLOW_ERC20_HANDLE_TRANSFER_ENTRYPOINT) ) > 0; sEvalHandleTransfer = evalHandleTransfer; flowCommonInit(flowERC20Config.flowConfig, FLOW_ERC20_MIN_FLOW_SENTINELS); if (evalHandleTransfer) { - (IInterpreterV1 interpreter, IInterpreterStoreV1 store, address expression) = flowERC20Config + (IInterpreterV2 interpreter, IInterpreterStoreV2 store, address expression) = flowERC20Config .evaluableConfig .deployer - .deployExpression( + .deployExpression2( flowERC20Config.evaluableConfig.bytecode, flowERC20Config.evaluableConfig.constants, LibUint256Array.arrayFrom(FLOW_ERC20_HANDLE_TRANSFER_MIN_OUTPUTS) @@ -93,19 +90,19 @@ contract FlowERC20 is ICloneableV2, IFlowERC20V4, FlowCommon, ERC20 { // integrity checks are complete. // The deployer MUST be a trusted contract anyway. // slither-disable-next-line reentrancy-benign - sEvaluable = Evaluable(interpreter, store, expression); + sEvaluable = EvaluableV2(interpreter, store, expression); } return ICLONEABLE_V2_SUCCESS; } - /// @inheritdoc IFlowERC20V4 + /// @inheritdoc IFlowERC20V5 function stackToFlow(uint256[] memory stack) external pure virtual override returns (FlowERC20IOV1 memory) { return _stackToFlow(stack.dataPointer(), stack.endPointer()); } - /// @inheritdoc IFlowERC20V4 - function flow(Evaluable memory evaluable, uint256[] memory callerContext, SignedContextV1[] memory signedContexts) + /// @inheritdoc IFlowERC20V5 + function flow(EvaluableV2 memory evaluable, uint256[] memory callerContext, SignedContextV1[] memory signedContexts) external virtual returns (FlowERC20IOV1 memory) @@ -126,11 +123,11 @@ contract FlowERC20 is ICloneableV2, IFlowERC20V4, FlowCommon, ERC20 { // Mint and burn access MUST be handled by flow. // HANDLE_TRANSFER will only restrict subsequent transfers. if (sEvalHandleTransfer && !(from == address(0) || to == address(0))) { - Evaluable memory evaluable = sEvaluable; - (uint256[] memory stack, uint256[] memory kvs) = evaluable.interpreter.eval( + EvaluableV2 memory evaluable = sEvaluable; + (uint256[] memory stack, uint256[] memory kvs) = evaluable.interpreter.eval2( evaluable.store, DEFAULT_STATE_NAMESPACE, - LibEncodedDispatch.encode( + LibEncodedDispatch.encode2( evaluable.expression, FLOW_ERC20_HANDLE_TRANSFER_ENTRYPOINT, FLOW_ERC20_HANDLE_TRANSFER_MAX_OUTPUTS @@ -185,7 +182,7 @@ contract FlowERC20 is ICloneableV2, IFlowERC20V4, FlowCommon, ERC20 { /// the mints and burns from the `FlowERC20IOV1` struct. The mints are /// processed first, then the burns, then the remaining flow is processed /// as normal. - function _flow(Evaluable memory evaluable, uint256[] memory callerContext, SignedContextV1[] memory signedContexts) + function _flow(EvaluableV2 memory evaluable, uint256[] memory callerContext, SignedContextV1[] memory signedContexts) internal virtual nonReentrant diff --git a/src/concrete/erc721/FlowERC721.meta.json b/src/concrete/erc721/FlowERC721.meta.json deleted file mode 100644 index be45f4de..00000000 --- a/src/concrete/erc721/FlowERC721.meta.json +++ /dev/null @@ -1,121 +0,0 @@ -{ - "name": "Flow ERC721", - "abiName": "FlowERC721", - "desc": "A flow contract that is also an ERC721 token that can be minted by expressions. Transfers can be restricted by an expression.", - "alias": "flow-erc721", - "source": "https://github.com/rainprotocol/rain-protocol", - "methods": [ - { - "name": "initialize", - "abiName": "initialize", - "desc": "Initialize a FlowERC721 contract.", - "inputs": [ - { - "name": "Name", - "abiName": "name", - "desc": "Name of the ERC721 token that is minted.", - "path": "[16].inputs[1].components[0]" - }, - { - "name": "Symbol", - "abiName": "symbol", - "desc": "Symbol for the ERC721 token that is minted.", - "path": "[16].inputs[1].components[1]" - }, - { - "name": "Base URI", - "abiName": "baseURI", - "desc": "Base URI for the ERC721 token that is minted.", - "path": "[16].inputs[1].components[2]" - } - ], - "expressions": [ - { - "name": "Handle transfer", - "abiName": "evaluableConfig", - "desc": "Review and restrict transfers of the flow contract's own ERC721 token. Mint and burns must be controlled by the flow expressions instead.", - "path": "[16].inputs[1].components[3]", - "signedContext": false, - "contextColumns": [ - { - "name": "Base", - "desc": "Base context column", - "alias": "base", - "columnIndex": 0, - "cells": [ - { - "name": "Transfer caller", - "desc": "The contract or wallet that called transfer.", - "alias": "transfer-caller", - "cellIndex": 0 - }, - { - "name": "Flow contract", - "desc": "The address of the FlowERC721 contract.", - "alias": "flow-contract", - "cellIndex": 1 - } - ] - }, - { - "name": "Transfer information", - "desc": "Information about the current transfer.", - "alias": "transfer-information", - "columnIndex": 1, - "cells": [ - { - "name": "Transfer from address", - "desc": "The address the token is being transferred from.", - "alias": "transfer-from-address", - "cellIndex": 0 - }, - { - "name": "Transfer to address", - "desc": "The address the token is being transferred to.", - "alias": "transfer-to-address", - "cellIndex": 1 - }, - { - "name": "Token ID", - "desc": "The ID of the token being transferred.", - "alias": "transfer-token-id", - "cellIndex": 2 - } - ] - } - ] - }, - { - "name": "Flows", - "abiName": "flowConfig", - "desc": "The available flows.", - "path": "[16].inputs[1].components[4]", - "signedContext": true, - "callerContext": true, - "contextColumns": [ - { - "name": "Base", - "desc": "Base context column.", - "alias": "base", - "columnIndex": 0, - "cells": [ - { - "name": "Flow caller", - "desc": "The contract or wallet that called flow.", - "alias": "flow-caller", - "cellIndex": 0 - }, - { - "name": "Flow contract", - "desc": "The address of the FlowERC721 contract.", - "alias": "flow-contract", - "cellIndex": 1 - } - ] - } - ] - } - ] - } - ] -} diff --git a/src/concrete/erc721/FlowERC721.sol b/src/concrete/erc721/FlowERC721.sol index de3b1896..9840f984 100644 --- a/src/concrete/erc721/FlowERC721.sol +++ b/src/concrete/erc721/FlowERC721.sol @@ -10,7 +10,7 @@ import {Sentinel, LibStackSentinel} from "rain.solmem/lib/LibStackSentinel.sol"; import {EncodedDispatch, LibEncodedDispatch} from "rain.interpreter.interface/lib/caller/LibEncodedDispatch.sol"; import {ICloneableV2, ICLONEABLE_V2_SUCCESS} from "rain.factory/src/interface/ICloneableV2.sol"; import { - IFlowERC721V4, + IFlowERC721V5, FlowERC721IOV1, SignedContextV1, FlowERC721ConfigV2, @@ -21,8 +21,9 @@ import { FLOW_ERC721_HANDLE_TRANSFER_MAX_OUTPUTS, FLOW_ERC721_TOKEN_URI_ENTRYPOINT, FLOW_ERC721_HANDLE_TRANSFER_ENTRYPOINT, - FLOW_ERC721_MIN_FLOW_SENTINELS -} from "../../interface/unstable/IFlowERC721V4.sol"; + FLOW_ERC721_MIN_FLOW_SENTINELS, + RAIN_FLOW_SENTINEL +} from "../../interface/unstable/IFlowERC721V5.sol"; import {LibBytecode} from "rain.interpreter.interface/lib/bytecode/LibBytecode.sol"; import {SourceIndexV2} from "rain.interpreter.interface/interface/unstable/IInterpreterV2.sol"; import {LibFlow} from "../../lib/LibFlow.sol"; @@ -33,7 +34,7 @@ import { } from "rain.interpreter.interface/interface/unstable/IInterpreterV2.sol"; import {IInterpreterStoreV2} from "rain.interpreter.interface/interface/unstable/IInterpreterStoreV2.sol"; import {Pointer} from "rain.solmem/lib/LibPointer.sol"; -import {RAIN_FLOW_SENTINEL, BurnerNotOwner} from "../../interface/unstable/IFlowERC721V4.sol"; +import {BurnerNotOwner} from "../../error/ErrFlow.sol"; /// @dev The hash of the meta data expected to be passed to `FlowCommon`'s /// constructor. @@ -41,7 +42,7 @@ bytes32 constant CALLER_META_HASH = bytes32(0xf0003e81ff90467c9933f3ac68db3ca49d /// @title FlowERC721 /// See `IFlowERC721V4` for documentation. -contract FlowERC721 is ICloneableV2, IFlowERC721V4, FlowCommon, ERC721 { +contract FlowERC721 is ICloneableV2, IFlowERC721V5, FlowCommon, ERC721 { using LibUint256Matrix for uint256[]; using LibUint256Array for uint256[]; using LibStackSentinel for Pointer; @@ -59,16 +60,13 @@ contract FlowERC721 is ICloneableV2, IFlowERC721V4, FlowCommon, ERC721 { /// @dev The evaluable that contains the entrypoints for `handleTransfer` and /// `tokenURI`. This is only set if `sEvalHandleTransfer` or `sEvalTokenURI` /// is true. - Evaluable internal sEvaluable; + EvaluableV2 internal sEvaluable; /// @dev The base URI for all token URIs. This is set during initialization /// and cannot be changed. The token URI evaluable can be used for dynamic /// token URIs from the base URI. string private sBaseURI; - /// Forwards the `FlowCommon` constructor arguments to the `FlowCommon`. - constructor(DeployerDiscoverableMetaV2ConstructionConfig memory config) FlowCommon(CALLER_META_HASH, config) {} - /// Needed here to fix Open Zeppelin implementing `supportsInterface` on /// multiple base contracts. function supportsInterface(bytes4 interfaceId) @@ -98,11 +96,11 @@ contract FlowERC721 is ICloneableV2, IFlowERC721V4, FlowCommon, ERC721 { uint256 sourceCount = LibBytecode.sourceCount(flowERC721Config.evaluableConfig.bytecode); bool evalHandleTransfer = sourceCount > 0 && LibBytecode.sourceOpsCount( - flowERC721Config.evaluableConfig.bytecode, SourceIndex.unwrap(FLOW_ERC721_HANDLE_TRANSFER_ENTRYPOINT) + flowERC721Config.evaluableConfig.bytecode, SourceIndexV2.unwrap(FLOW_ERC721_HANDLE_TRANSFER_ENTRYPOINT) ) > 0; bool evalTokenURI = sourceCount > 1 && LibBytecode.sourceOpsCount( - flowERC721Config.evaluableConfig.bytecode, SourceIndex.unwrap(FLOW_ERC721_TOKEN_URI_ENTRYPOINT) + flowERC721Config.evaluableConfig.bytecode, SourceIndexV2.unwrap(FLOW_ERC721_TOKEN_URI_ENTRYPOINT) ) > 0; sEvalHandleTransfer = evalHandleTransfer; sEvalTokenURI = evalTokenURI; @@ -116,10 +114,10 @@ contract FlowERC721 is ICloneableV2, IFlowERC721V4, FlowCommon, ERC721 { ? LibUint256Array.arrayFrom(FLOW_ERC721_HANDLE_TRANSFER_MIN_OUTPUTS, FLOW_ERC721_TOKEN_URI_MIN_OUTPUTS) : LibUint256Array.arrayFrom(FLOW_ERC721_HANDLE_TRANSFER_MIN_OUTPUTS); - (IInterpreterV1 interpreter, IInterpreterStoreV1 store, address expression) = flowERC721Config + (IInterpreterV2 interpreter, IInterpreterStoreV2 store, address expression) = flowERC721Config .evaluableConfig .deployer - .deployExpression( + .deployExpression2( flowERC721Config.evaluableConfig.bytecode, flowERC721Config.evaluableConfig.constants, minOutputs ); // There's no way to set this before the external call because the @@ -129,7 +127,7 @@ contract FlowERC721 is ICloneableV2, IFlowERC721V4, FlowCommon, ERC721 { // integrity checks are complete. // The deployer MUST be a trusted contract anyway. // slither-disable-next-line reentrancy-benign - sEvaluable = Evaluable(interpreter, store, expression); + sEvaluable = EvaluableV2(interpreter, store, expression); } return ICLONEABLE_V2_SUCCESS; @@ -151,11 +149,11 @@ contract FlowERC721 is ICloneableV2, IFlowERC721V4, FlowCommon, ERC721 { /// @inheritdoc ERC721 function tokenURI(uint256 tokenId) public view virtual override returns (string memory) { if (sEvalTokenURI) { - Evaluable memory evaluable = sEvaluable; - (uint256[] memory stack, uint256[] memory kvs) = evaluable.interpreter.eval( + EvaluableV2 memory evaluable = sEvaluable; + (uint256[] memory stack, uint256[] memory kvs) = evaluable.interpreter.eval2( evaluable.store, DEFAULT_STATE_NAMESPACE, - LibEncodedDispatch.encode( + LibEncodedDispatch.encode2( evaluable.expression, FLOW_ERC721_TOKEN_URI_ENTRYPOINT, FLOW_ERC721_TOKEN_URI_MAX_OUTPUTS ), LibContext.build(LibUint256Array.arrayFrom(tokenId).matrixFrom(), new SignedContextV1[](0)) @@ -169,13 +167,13 @@ contract FlowERC721 is ICloneableV2, IFlowERC721V4, FlowCommon, ERC721 { return super.tokenURI(tokenId); } - /// @inheritdoc IFlowERC721V4 + /// @inheritdoc IFlowERC721V5 function stackToFlow(uint256[] memory stack) external pure virtual override returns (FlowERC721IOV1 memory) { return _stackToFlow(stack.dataPointer(), stack.endPointer()); } - /// @inheritdoc IFlowERC721V4 - function flow(Evaluable memory evaluable, uint256[] memory callerContext, SignedContextV1[] memory signedContexts) + /// @inheritdoc IFlowERC721V5 + function flow(EvaluableV2 memory evaluable, uint256[] memory callerContext, SignedContextV1[] memory signedContexts) external virtual returns (FlowERC721IOV1 memory) @@ -200,11 +198,11 @@ contract FlowERC721 is ICloneableV2, IFlowERC721V4, FlowCommon, ERC721 { // Mint and burn access MUST be handled by flow. // HANDLE_TRANSFER will only restrict subsequent transfers. if (sEvalHandleTransfer && !(from == address(0) || to == address(0))) { - Evaluable memory evaluable = sEvaluable; - (uint256[] memory stack, uint256[] memory kvs) = evaluable.interpreter.eval( + EvaluableV2 memory evaluable = sEvaluable; + (uint256[] memory stack, uint256[] memory kvs) = evaluable.interpreter.eval2( evaluable.store, DEFAULT_STATE_NAMESPACE, - LibEncodedDispatch.encode( + LibEncodedDispatch.encode2( evaluable.expression, FLOW_ERC721_HANDLE_TRANSFER_ENTRYPOINT, FLOW_ERC721_HANDLE_TRANSFER_MAX_OUTPUTS @@ -261,7 +259,7 @@ contract FlowERC721 is ICloneableV2, IFlowERC721V4, FlowCommon, ERC721 { /// from the stack as additional sentinel separated tuples. The mints are /// consumed first, then the burns, then the remaining stack is converted to /// a flow as normal. - function _flow(Evaluable memory evaluable, uint256[] memory callerContext, SignedContextV1[] memory signedContexts) + function _flow(EvaluableV2 memory evaluable, uint256[] memory callerContext, SignedContextV1[] memory signedContexts) internal virtual nonReentrant diff --git a/src/interface/deprecated/v2/IFlowV2.sol b/src/interface/deprecated/v2/IFlowV2.sol index aaa62197..cb1e9d53 100644 --- a/src/interface/deprecated/v2/IFlowV2.sol +++ b/src/interface/deprecated/v2/IFlowV2.sol @@ -1,6 +1,7 @@ // SPDX-License-Identifier: CAL pragma solidity ^0.8.18; +import {Evaluable, EvaluableConfig} from "rain.interpreter.interface/interface/deprecated/IInterpreterCallerV1.sol"; import "rain.interpreter.interface/interface/IInterpreterCallerV2.sol"; import "rain.interpreter.interface/lib/caller/LibEvaluable.sol"; diff --git a/src/interface/deprecated/v3/IFlowERC20V3.sol b/src/interface/deprecated/v3/IFlowERC20V3.sol index bb4d93ef..0c191742 100644 --- a/src/interface/deprecated/v3/IFlowERC20V3.sol +++ b/src/interface/deprecated/v3/IFlowERC20V3.sol @@ -1,8 +1,9 @@ // SPDX-License-Identifier: CAL pragma solidity ^0.8.18; -import "rain.interpreter.interface/interface/IInterpreterCallerV2.sol"; -import "rain.interpreter.interface/lib/caller/LibEvaluable.sol"; +import {SourceIndex} from "rain.interpreter.interface/interface/deprecated/IInterpreterV1.sol"; +import {EvaluableConfig, Evaluable} from "rain.interpreter.interface/interface/deprecated/IInterpreterCallerV1.sol"; +import {SignedContextV1} from "rain.interpreter.interface/interface/IInterpreterCallerV2.sol"; import {Sentinel} from "rain.solmem/lib/LibStackSentinel.sol"; import {MIN_FLOW_SENTINELS, SENTINEL_HIGH_BITS, FlowTransferV1} from "./IFlowV3.sol"; diff --git a/src/interface/deprecated/v3/IFlowV3.sol b/src/interface/deprecated/v3/IFlowV3.sol index 6fef197d..f305d4f9 100644 --- a/src/interface/deprecated/v3/IFlowV3.sol +++ b/src/interface/deprecated/v3/IFlowV3.sol @@ -7,22 +7,6 @@ import {SignedContextV1} from "rain.interpreter.interface/interface/IInterpreter import "rain.interpreter.interface/lib/caller/LibEvaluable.sol"; import {Sentinel} from "rain.solmem/lib/LibStackSentinel.sol"; -/// Thrown when the flow being evaluated is unregistered. -/// @param unregisteredHash Hash of the unregistered flow. -error UnregisteredFlow(bytes32 unregisteredHash); - -/// Thrown for unsupported native transfers. -error UnsupportedNativeFlow(); - -/// Thrown for unsupported erc20 transfers. -error UnsupportedERC20Flow(); - -/// Thrown for unsupported erc721 transfers. -error UnsupportedERC721Flow(); - -/// Thrown for unsupported erc1155 transfers. -error UnsupportedERC1155Flow(); - /// @dev The number of sentinels required by `FlowCommon`. An evaluable can never /// have fewer minimum outputs than required sentinels. uint256 constant MIN_FLOW_SENTINELS = 3; diff --git a/src/interface/deprecated/v4/IFlowERC1155V4.sol b/src/interface/deprecated/v4/IFlowERC1155V4.sol index 4c2cdcb1..37100940 100644 --- a/src/interface/deprecated/v4/IFlowERC1155V4.sol +++ b/src/interface/deprecated/v4/IFlowERC1155V4.sol @@ -13,7 +13,7 @@ import { FLOW_ERC1155_HANDLE_TRANSFER_ENTRYPOINT, FLOW_ERC1155_HANDLE_TRANSFER_MIN_OUTPUTS, FLOW_ERC1155_MIN_FLOW_SENTINELS -} from "../IFlowERC1155V3.sol"; +} from "../v3/IFlowERC1155V3.sol"; /// Initialization config. /// @param uri As per Open Zeppelin `ERC1155Upgradeable`. diff --git a/src/interface/deprecated/v4/IFlowERC20V4.sol b/src/interface/deprecated/v4/IFlowERC20V4.sol index 728e093a..873424b1 100644 --- a/src/interface/deprecated/v4/IFlowERC20V4.sol +++ b/src/interface/deprecated/v4/IFlowERC20V4.sol @@ -1,8 +1,8 @@ // SPDX-License-Identifier: CAL pragma solidity ^0.8.18; +import {Evaluable, EvaluableConfigV2} from "rain.interpreter.interface/interface/deprecated/IInterpreterCallerV1.sol"; import {SignedContextV1} from "rain.interpreter.interface/interface/IInterpreterCallerV2.sol"; -import {EvaluableV2} from "rain.interpreter.interface/lib/caller/LibEvaluable.sol"; import {Sentinel} from "rain.solmem/lib/LibStackSentinel.sol"; import { FlowERC20IOV1, @@ -11,7 +11,7 @@ import { FLOW_ERC20_HANDLE_TRANSFER_MIN_OUTPUTS, FLOW_ERC20_HANDLE_TRANSFER_MAX_OUTPUTS, FLOW_ERC20_MIN_FLOW_SENTINELS -} from "../IFlowERC20V3.sol"; +} from "../v3/IFlowERC20V3.sol"; import {RAIN_FLOW_SENTINEL} from "./IFlowV4.sol"; /// Initialization config. diff --git a/src/interface/deprecated/v4/IFlowERC721V4.sol b/src/interface/deprecated/v4/IFlowERC721V4.sol index d76a94a2..789d7e25 100644 --- a/src/interface/deprecated/v4/IFlowERC721V4.sol +++ b/src/interface/deprecated/v4/IFlowERC721V4.sol @@ -1,7 +1,8 @@ // SPDX-License-Identifier: CAL pragma solidity ^0.8.18; -import "rain.interpreter.interface/interface/IInterpreterCallerV2.sol"; +import {Evaluable, EvaluableConfigV2} from "rain.interpreter.interface/interface/deprecated/IInterpreterCallerV1.sol"; +import {SignedContextV1} from "rain.interpreter.interface/interface/IInterpreterCallerV2.sol"; import "rain.interpreter.interface/lib/caller/LibEvaluable.sol"; import { @@ -14,7 +15,7 @@ import { FLOW_ERC721_TOKEN_URI_ENTRYPOINT, FLOW_ERC721_HANDLE_TRANSFER_ENTRYPOINT, FLOW_ERC721_MIN_FLOW_SENTINELS -} from "../IFlowERC721V3.sol"; +} from "../v3/IFlowERC721V3.sol"; import {RAIN_FLOW_SENTINEL} from "./IFlowV4.sol"; diff --git a/src/interface/deprecated/v4/IFlowV4.sol b/src/interface/deprecated/v4/IFlowV4.sol index 27998b5e..d0e66fc5 100644 --- a/src/interface/deprecated/v4/IFlowV4.sol +++ b/src/interface/deprecated/v4/IFlowV4.sol @@ -12,12 +12,8 @@ import { ERC721Transfer, ERC1155Transfer, RAIN_FLOW_SENTINEL, - UnregisteredFlow, - UnsupportedERC20Flow, - UnsupportedERC721Flow, - UnsupportedERC1155Flow, MIN_FLOW_SENTINELS -} from "../IFlowV3.sol"; +} from "../v3/IFlowV3.sol"; /// @title IFlowV4 /// @notice Interface for a flow contract that does NOT require native minting diff --git a/src/interface/unstable/IFlowERC1155V5.sol b/src/interface/unstable/IFlowERC1155V5.sol index 4c2cdcb1..aa1c8e51 100644 --- a/src/interface/unstable/IFlowERC1155V5.sol +++ b/src/interface/unstable/IFlowERC1155V5.sol @@ -4,7 +4,7 @@ pragma solidity ^0.8.18; import {SignedContextV1, EvaluableConfigV3} from "rain.interpreter.interface/interface/IInterpreterCallerV2.sol"; import {EvaluableV2} from "rain.interpreter.interface/lib/caller/LibEvaluable.sol"; import {Sentinel} from "rain.solmem/lib/LibStackSentinel.sol"; -import {RAIN_FLOW_SENTINEL} from "./IFlowV4.sol"; +import {RAIN_FLOW_SENTINEL} from "./IFlowV5.sol"; import { FlowERC1155IOV1, @@ -13,7 +13,7 @@ import { FLOW_ERC1155_HANDLE_TRANSFER_ENTRYPOINT, FLOW_ERC1155_HANDLE_TRANSFER_MIN_OUTPUTS, FLOW_ERC1155_MIN_FLOW_SENTINELS -} from "../IFlowERC1155V3.sol"; +} from "../deprecated/v4/IFlowERC1155V4.sol"; /// Initialization config. /// @param uri As per Open Zeppelin `ERC1155Upgradeable`. diff --git a/src/interface/unstable/IFlowERC20V5.sol b/src/interface/unstable/IFlowERC20V5.sol index 190c1cd4..feca5cf7 100644 --- a/src/interface/unstable/IFlowERC20V5.sol +++ b/src/interface/unstable/IFlowERC20V5.sol @@ -1,7 +1,7 @@ // SPDX-License-Identifier: CAL pragma solidity ^0.8.18; -import {SignedContextV1} from "rain.interpreter.interface/interface/IInterpreterCallerV2.sol"; +import {SignedContextV1, EvaluableConfigV3} from "rain.interpreter.interface/interface/IInterpreterCallerV2.sol"; import {EvaluableV2} from "rain.interpreter.interface/lib/caller/LibEvaluable.sol"; import {Sentinel} from "rain.solmem/lib/LibStackSentinel.sol"; import { @@ -11,8 +11,8 @@ import { FLOW_ERC20_HANDLE_TRANSFER_MIN_OUTPUTS, FLOW_ERC20_HANDLE_TRANSFER_MAX_OUTPUTS, FLOW_ERC20_MIN_FLOW_SENTINELS -} from "../IFlowERC20V3.sol"; -import {RAIN_FLOW_SENTINEL} from "./IFlowV4.sol"; +} from "../deprecated/v4/IFlowERC20V4.sol"; +import {RAIN_FLOW_SENTINEL} from "./IFlowV5.sol"; /// Initialization config. /// @param name As per Open Zeppelin `ERC20Upgradeable`. @@ -24,8 +24,8 @@ import {RAIN_FLOW_SENTINEL} from "./IFlowV4.sol"; struct FlowERC20ConfigV2 { string name; string symbol; - EvaluableConfigV2 evaluableConfig; - EvaluableConfigV2[] flowConfig; + EvaluableConfigV3 evaluableConfig; + EvaluableConfigV3[] flowConfig; } /// @title IFlowERC20V5 @@ -62,7 +62,7 @@ interface IFlowERC20V5 { /// @return flowERC20IO The `FlowERC20IOV1` representing all token mint/burns /// and transfers that occurred during the flow. function flow( - Evaluable calldata evaluable, + EvaluableV2 calldata evaluable, uint256[] calldata callerContext, SignedContextV1[] calldata signedContexts ) external returns (FlowERC20IOV1 calldata flowERC20IO); diff --git a/src/interface/unstable/IFlowERC721V5.sol b/src/interface/unstable/IFlowERC721V5.sol index d76a94a2..2032c143 100644 --- a/src/interface/unstable/IFlowERC721V5.sol +++ b/src/interface/unstable/IFlowERC721V5.sol @@ -1,8 +1,8 @@ // SPDX-License-Identifier: CAL pragma solidity ^0.8.18; -import "rain.interpreter.interface/interface/IInterpreterCallerV2.sol"; -import "rain.interpreter.interface/lib/caller/LibEvaluable.sol"; +import {SignedContextV1, EvaluableConfigV3} from "rain.interpreter.interface/interface/IInterpreterCallerV2.sol"; +import {EvaluableV2} from "rain.interpreter.interface/lib/caller/LibEvaluable.sol"; import { FlowERC721IOV1, @@ -14,32 +14,28 @@ import { FLOW_ERC721_TOKEN_URI_ENTRYPOINT, FLOW_ERC721_HANDLE_TRANSFER_ENTRYPOINT, FLOW_ERC721_MIN_FLOW_SENTINELS -} from "../IFlowERC721V3.sol"; +} from "../deprecated/v4/IFlowERC721V4.sol"; -import {RAIN_FLOW_SENTINEL} from "./IFlowV4.sol"; - -/// Thrown when burner of tokens is not the owner of tokens. -error BurnerNotOwner(); +import {RAIN_FLOW_SENTINEL} from "../deprecated/v4/IFlowV4.sol"; /// Initialization config. /// @param name As per Open Zeppelin `ERC721Upgradeable`. /// @param symbol As per Open Zeppelin `ERC721Upgradeable`. /// @param baseURI As per Open Zeppelin `ERC721Upgradeable`. -/// @param evaluableConfig The `EvaluableConfigV2` to use to build the -/// `evaluable` that can be used to handle transfers and build token IDs for the -/// token URI. +/// @param evaluableConfig Config to use to build the `evaluable` that can be +/// used to handle transfers and build token IDs for the token URI. /// @param flowConfig Initialization config for the `Evaluable`s that define the /// flow behaviours outside self mints/burns. struct FlowERC721ConfigV2 { string name; string symbol; string baseURI; - EvaluableConfigV2 evaluableConfig; - EvaluableConfigV2[] flowConfig; + EvaluableConfigV3 evaluableConfig; + EvaluableConfigV3[] flowConfig; } -/// @title IFlowERC721V4 -/// Conceptually identical to `IFlowV4`, but the flow contract itself is an +/// @title IFlowERC721V5 +/// Conceptually identical to `IFlowV5`, but the flow contract itself is an /// ERC721 token. This means that ERC721 self mints and burns are included in the /// stack that the flows must evaluate to. As stacks are processed by flow from /// bottom to top, this means that the self mint/burn will be the last thing @@ -57,8 +53,8 @@ struct FlowERC721ConfigV2 { /// optional, and if not provided the token URI will be the default Open Zeppelin /// token URI logic. /// -/// Otherwise the flow contract is identical to `IFlowV4`. -interface IFlowERC721V4 { +/// Otherwise the flow contract is identical to `IFlowV5`. +interface IFlowERC721V5 { /// Contract has initialized. /// @param sender `msg.sender` initializing the contract (factory). /// @param config All initialized config. @@ -76,7 +72,7 @@ interface IFlowERC721V4 { /// @return flowERC721IO The `FlowERC721IOV1` representing all token /// mint/burns and transfers that occurred during the flow. function flow( - Evaluable calldata evaluable, + EvaluableV2 calldata evaluable, uint256[] calldata callerContext, SignedContextV1[] calldata signedContexts ) external returns (FlowERC721IOV1 calldata flowERC721IO); diff --git a/src/interface/unstable/IFlowV5.sol b/src/interface/unstable/IFlowV5.sol index 27998b5e..97e6cd97 100644 --- a/src/interface/unstable/IFlowV5.sol +++ b/src/interface/unstable/IFlowV5.sol @@ -12,12 +12,11 @@ import { ERC721Transfer, ERC1155Transfer, RAIN_FLOW_SENTINEL, - UnregisteredFlow, - UnsupportedERC20Flow, - UnsupportedERC721Flow, - UnsupportedERC1155Flow, MIN_FLOW_SENTINELS -} from "../IFlowV3.sol"; +} from "../deprecated/v4/IFlowV4.sol"; +import { + UnregisteredFlow +} from "../../error/ErrFlow.sol"; /// @title IFlowV4 /// @notice Interface for a flow contract that does NOT require native minting diff --git a/src/lib/LibFlow.sol b/src/lib/LibFlow.sol index 0d170f81..5be3e153 100644 --- a/src/lib/LibFlow.sol +++ b/src/lib/LibFlow.sol @@ -1,17 +1,14 @@ // SPDX-License-Identifier: CAL pragma solidity ^0.8.18; -import {IFlowV4, RAIN_FLOW_SENTINEL} from "../interface/unstable/IFlowV4.sol"; +import {IFlowV4, RAIN_FLOW_SENTINEL} from "../interface/unstable/IFlowV5.sol"; import {Pointer} from "rain.solmem/lib/LibPointer.sol"; import { FlowTransferV1, ERC20Transfer, ERC721Transfer, - ERC1155Transfer, - UnsupportedERC20Flow, - UnsupportedERC721Flow, - UnsupportedERC1155Flow -} from "../interface/unstable/IFlowV4.sol"; + ERC1155Transfer +} from "../interface/unstable/IFlowV5.sol"; import {IInterpreterStoreV2} from "rain.interpreter.interface/interface/unstable/IInterpreterStoreV2.sol"; import {LibStackSentinel} from "rain.solmem/lib/LibStackSentinel.sol"; import {DEFAULT_STATE_NAMESPACE} from "rain.interpreter.interface/interface/unstable/IInterpreterV2.sol"; @@ -20,6 +17,11 @@ import {IERC20} from "openzeppelin-contracts/contracts/token/ERC20/IERC20.sol"; import {SafeERC20} from "openzeppelin-contracts/contracts/token/ERC20/utils/SafeERC20.sol"; import {IERC721} from "openzeppelin-contracts/contracts/token/ERC721/IERC721.sol"; import {IERC1155} from "openzeppelin-contracts/contracts/token/ERC1155/IERC1155.sol"; +import { + UnsupportedERC20Flow, + UnsupportedERC721Flow, + UnsupportedERC1155Flow +} from "../error/ErrFlow.sol"; /// @title LibFlow /// Standard processing used by all variants of `Flow`. These utilities can't diff --git a/test/interface/unstable/IFlowV4.t.sol b/test/interface/unstable/IFlowV4.t.sol index b6325e5e..9ea6c4d2 100644 --- a/test/interface/unstable/IFlowV4.t.sol +++ b/test/interface/unstable/IFlowV4.t.sol @@ -3,7 +3,7 @@ pragma solidity =0.8.19; import "forge-std/Test.sol"; -import {IFlowV4, RAIN_FLOW_SENTINEL} from "src/interface/unstable/IFlowV4.sol"; +import {IFlowV4, RAIN_FLOW_SENTINEL} from "src/interface/deprecated/v4/IFlowV4.sol"; import {Sentinel} from "rain.solmem/lib/LibStackSentinel.sol"; contract IFlowV4Test is Test { From 5f2cae7a9966e66bb37045039ce8da43cab2b36d Mon Sep 17 00:00:00 2001 From: thedavidmeister Date: Wed, 28 Feb 2024 09:33:50 +0400 Subject: [PATCH 06/13] wip on i9r --- src/concrete/erc721/FlowERC721.sol | 7 +++++-- src/error/ErrFlow.sol | 23 +++++++++++++++++++++++ 2 files changed, 28 insertions(+), 2 deletions(-) create mode 100644 src/error/ErrFlow.sol diff --git a/src/concrete/erc721/FlowERC721.sol b/src/concrete/erc721/FlowERC721.sol index 9840f984..12b2287a 100644 --- a/src/concrete/erc721/FlowERC721.sol +++ b/src/concrete/erc721/FlowERC721.sol @@ -36,6 +36,7 @@ import {IInterpreterStoreV2} from "rain.interpreter.interface/interface/unstable import {Pointer} from "rain.solmem/lib/LibPointer.sol"; import {BurnerNotOwner} from "../../error/ErrFlow.sol"; + /// @dev The hash of the meta data expected to be passed to `FlowCommon`'s /// constructor. bytes32 constant CALLER_META_HASH = bytes32(0xf0003e81ff90467c9933f3ac68db3ca49df8b30ab83a0b88e1ed8381ed28fdd6); @@ -46,6 +47,7 @@ contract FlowERC721 is ICloneableV2, IFlowERC721V5, FlowCommon, ERC721 { using LibUint256Matrix for uint256[]; using LibUint256Array for uint256[]; using LibStackSentinel for Pointer; + using LibNamespace for StateNamespace; /// @dev True if we need to eval `handleTransfer` on every transfer. For many /// tokens this will be false, so we don't want to invoke the external @@ -201,7 +203,7 @@ contract FlowERC721 is ICloneableV2, IFlowERC721V5, FlowCommon, ERC721 { EvaluableV2 memory evaluable = sEvaluable; (uint256[] memory stack, uint256[] memory kvs) = evaluable.interpreter.eval2( evaluable.store, - DEFAULT_STATE_NAMESPACE, + DEFAULT_STATE_NAMESPACE.qualifyNamespace(address(this)), LibEncodedDispatch.encode2( evaluable.expression, FLOW_ERC721_HANDLE_TRANSFER_ENTRYPOINT, @@ -213,7 +215,8 @@ contract FlowERC721 is ICloneableV2, IFlowERC721V5, FlowCommon, ERC721 { // transfer is NOT called for mints. LibUint256Array.arrayFrom(uint256(uint160(from)), uint256(uint160(to)), tokenId).matrixFrom(), new SignedContextV1[](0) - ) + ), + new uint256[](0) ); (stack); if (kvs.length > 0) { diff --git a/src/error/ErrFlow.sol b/src/error/ErrFlow.sol new file mode 100644 index 00000000..8a9f03e5 --- /dev/null +++ b/src/error/ErrFlow.sol @@ -0,0 +1,23 @@ +// SPDX-License-Identifier: CAL +pragma solidity ^0.8.18; + +/// Thrown when the flow being evaluated is unregistered. +/// @param unregisteredHash Hash of the unregistered flow. +error UnregisteredFlow(bytes32 unregisteredHash); + +/// Thrown for unsupported native transfers. +error UnsupportedNativeFlow(); + +/// Thrown for unsupported erc20 transfers. +error UnsupportedERC20Flow(); + +/// Thrown for unsupported erc721 transfers. +error UnsupportedERC721Flow(); + +/// Thrown for unsupported erc1155 transfers. +error UnsupportedERC1155Flow(); + +contract ErrFLow {} + +/// Thrown when burner of tokens is not the owner of tokens. +error BurnerNotOwner(); \ No newline at end of file From 0ea3300506e700e390213795be5e2ef85a783f1f Mon Sep 17 00:00:00 2001 From: thedavidmeister Date: Wed, 28 Feb 2024 10:04:11 +0400 Subject: [PATCH 07/13] bump i9r --- lib/rain.interpreter.interface | 2 +- src/abstract/FlowCommon.sol | 32 +++++++++++-- src/concrete/erc1155/FlowERC1155.sol | 35 ++++++++++++-- src/concrete/erc20/FlowERC20.sol | 33 ++++++++++--- src/concrete/erc721/FlowERC721.sol | 58 +++++++++++++++++------ src/error/ErrFlow.sol | 9 +++- src/interface/unstable/IFlowERC1155V5.sol | 4 +- src/interface/unstable/IFlowERC20V5.sol | 4 +- src/interface/unstable/IFlowERC721V5.sol | 7 +-- 9 files changed, 147 insertions(+), 37 deletions(-) diff --git a/lib/rain.interpreter.interface b/lib/rain.interpreter.interface index 7a782504..dcdee287 160000 --- a/lib/rain.interpreter.interface +++ b/lib/rain.interpreter.interface @@ -1 +1 @@ -Subproject commit 7a78250485c9dd45fc8d877832b547f85223bbe0 +Subproject commit dcdee287da6dcc30739bc454b5de914d210c0b38 diff --git a/src/abstract/FlowCommon.sol b/src/abstract/FlowCommon.sol index faa9ef8d..b3b89953 100644 --- a/src/abstract/FlowCommon.sol +++ b/src/abstract/FlowCommon.sol @@ -29,6 +29,11 @@ import { import {ReentrancyGuardUpgradeable as ReentrancyGuard} from "openzeppelin-contracts-upgradeable/contracts/security/ReentrancyGuardUpgradeable.sol"; import {LibUint256Matrix} from "rain.solmem/lib/LibUint256Matrix.sol"; +import {LibNamespace, StateNamespace} from "rain.interpreter.interface/lib/ns/LibNamespace.sol"; +import { + UnsupportedFlowInputs, + InsufficientFlowOutputs +} from "../error/ErrFlow.sol"; /// Thrown when the min outputs for a flow is fewer than the sentinels. /// This is always an implementation bug as the min outputs and sentinel count @@ -84,6 +89,7 @@ abstract contract FlowCommon is ERC721Holder, ERC1155Holder, Multicall, Reentran using LibUint256Array for uint256[]; using LibUint256Matrix for uint256[]; using LibEvaluable for EvaluableV2; + using LibNamespace for StateNamespace; /// @dev This mapping tracks all flows that are registered at initialization. /// This is used to ensure that only registered flows are evaluated. @@ -148,9 +154,26 @@ abstract contract FlowCommon is ERC721Holder, ERC1155Holder, Multicall, Reentran // Reentrancy is just one of many ways that a malicious deployer // can cause problems, and it's probably the least of your // worries if you're using a malicious deployer. - (IInterpreterV2 interpreter, IInterpreterStoreV2 store, address expression) = config + (IInterpreterV2 interpreter, IInterpreterStoreV2 store, address expression, bytes memory io) = config .deployer - .deployExpression2(config.bytecode, config.constants, LibUint256Array.arrayFrom(flowMinOutputs)); + .deployExpression2(config.bytecode, config.constants); + + { + uint256 flowInputs; + uint256 flowOutputs; + assembly ("memory-safe") { + let ioWord := mload(add(io, 0x20)) + flowInputs := byte(0, ioWord) + flowOutputs := byte(1, ioWord) + } + if (flowInputs != 0) { + revert UnsupportedFlowInputs(); + } + if (flowOutputs < flowMinOutputs) { + revert InsufficientFlowOutputs(); + } + } + evaluable = EvaluableV2(interpreter, store, expression); // There's no way to set this mapping before the external // contract call because the output of the external contract @@ -200,9 +223,10 @@ abstract contract FlowCommon is ERC721Holder, ERC1155Holder, Multicall, Reentran (uint256[] memory stack, uint256[] memory kvs) = evaluable.interpreter.eval2( evaluable.store, - DEFAULT_STATE_NAMESPACE, + DEFAULT_STATE_NAMESPACE.qualifyNamespace(address(this)), LibEncodedDispatch.encode2(evaluable.expression, FLOW_ENTRYPOINT, FLOW_MAX_OUTPUTS), - context + context, + new uint256[](0) ); return (stack.dataPointer(), stack.endPointer(), kvs); } diff --git a/src/concrete/erc1155/FlowERC1155.sol b/src/concrete/erc1155/FlowERC1155.sol index 4a086719..42e1d097 100644 --- a/src/concrete/erc1155/FlowERC1155.sol +++ b/src/concrete/erc1155/FlowERC1155.sol @@ -32,6 +32,11 @@ import {LibFlow} from "../../lib/LibFlow.sol"; import {SourceIndexV2} from "rain.interpreter.interface/interface/unstable/IInterpreterV2.sol"; import {FlowCommon, ERC1155Receiver} from "../../abstract/FlowCommon.sol"; import {LibContext} from "rain.interpreter.interface/lib/caller/LibContext.sol"; +import {LibNamespace, StateNamespace} from "rain.interpreter.interface/lib/ns/LibNamespace.sol"; +import { + InsufficientHandleTransferOutputs, + UnsupportedHandleTransferInputs +} from "../../error/ErrFlow.sol"; /// @title FlowERC1155 /// See `IFlowERC1155V4` for documentation. @@ -39,6 +44,7 @@ contract FlowERC1155 is ICloneableV2, IFlowERC1155V4, FlowCommon, ERC1155 { using LibStackSentinel for Pointer; using LibUint256Matrix for uint256[]; using LibUint256Array for uint256[]; + using LibNamespace for StateNamespace; /// True if the evaluable needs to be called on every transfer. bool private sEvalHandleTransfer; @@ -68,14 +74,32 @@ contract FlowERC1155 is ICloneableV2, IFlowERC1155V4, FlowCommon, ERC1155 { flowCommonInit(flowERC1155Config.flowConfig, FLOW_ERC1155_MIN_FLOW_SENTINELS); if (evalHandleTransfer) { - (IInterpreterV2 interpreter, IInterpreterStoreV2 store, address expression) = flowERC1155Config + (IInterpreterV2 interpreter, IInterpreterStoreV2 store, address expression, bytes memory io) = flowERC1155Config .evaluableConfig .deployer .deployExpression2( flowERC1155Config.evaluableConfig.bytecode, - flowERC1155Config.evaluableConfig.constants, - LibUint256Array.arrayFrom(FLOW_ERC1155_HANDLE_TRANSFER_MIN_OUTPUTS) + flowERC1155Config.evaluableConfig.constants ); + + { + uint256 handleTransferInputs; + uint256 handleTransferOutputs; + assembly ("memory-safe") { + let ioWord := mload(add(io, 0x20)) + handleTransferInputs := byte(0, ioWord) + handleTransferOutputs := byte(1, ioWord) + } + + if (handleTransferInputs != 0) { + revert UnsupportedHandleTransferInputs(); + } + + if (handleTransferOutputs < FLOW_ERC1155_HANDLE_TRANSFER_MIN_OUTPUTS) { + revert InsufficientHandleTransferOutputs(); + } + } + // There's no way to set this before the external call because the // output of the `deployExpression` call is the input to `Evaluable`. // Even if we could set it before the external call, we wouldn't want @@ -134,13 +158,14 @@ contract FlowERC1155 is ICloneableV2, IFlowERC1155V4, FlowCommon, ERC1155 { (uint256[] memory stack, uint256[] memory kvs) = evaluable.interpreter.eval2( evaluable.store, - DEFAULT_STATE_NAMESPACE, + DEFAULT_STATE_NAMESPACE.qualifyNamespace(address(this)), LibEncodedDispatch.encode2( evaluable.expression, FLOW_ERC1155_HANDLE_TRANSFER_ENTRYPOINT, FLOW_ERC1155_HANDLE_TRANSFER_MAX_OUTPUTS ), - context + context, + new uint256[](0) ); (stack); if (kvs.length > 0) { diff --git a/src/concrete/erc20/FlowERC20.sol b/src/concrete/erc20/FlowERC20.sol index 20bb18be..d3143947 100644 --- a/src/concrete/erc20/FlowERC20.sol +++ b/src/concrete/erc20/FlowERC20.sol @@ -32,6 +32,8 @@ import {IInterpreterStoreV2} from "rain.interpreter.interface/interface/unstable import {Pointer} from "rain.solmem/lib/LibPointer.sol"; import {EvaluableV2} from "rain.interpreter.interface/lib/caller/LibEvaluable.sol"; import {LibContext} from "rain.interpreter.interface/lib/caller/LibContext.sol"; +import {LibNamespace, StateNamespace} from "rain.interpreter.interface/lib/ns/LibNamespace.sol"; +import {UnsupportedHandleTransferInputs, InsufficientHandleTransferOutputs} from "../../error/ErrFlow.sol"; /// @dev The hash of the meta data expected to be passed to `FlowCommon`'s /// constructor. @@ -43,6 +45,7 @@ contract FlowERC20 is ICloneableV2, IFlowERC20V5, FlowCommon, ERC20 { using LibStackSentinel for Pointer; using LibUint256Matrix for uint256[]; using LibUint256Array for uint256[]; + using LibNamespace for StateNamespace; /// @dev True if we need to eval `handleTransfer` on every transfer. For many /// tokens this will be false, so we don't want to invoke the external @@ -75,14 +78,31 @@ contract FlowERC20 is ICloneableV2, IFlowERC20V5, FlowCommon, ERC20 { flowCommonInit(flowERC20Config.flowConfig, FLOW_ERC20_MIN_FLOW_SENTINELS); if (evalHandleTransfer) { - (IInterpreterV2 interpreter, IInterpreterStoreV2 store, address expression) = flowERC20Config + (IInterpreterV2 interpreter, IInterpreterStoreV2 store, address expression, bytes memory io) = flowERC20Config .evaluableConfig .deployer .deployExpression2( flowERC20Config.evaluableConfig.bytecode, - flowERC20Config.evaluableConfig.constants, - LibUint256Array.arrayFrom(FLOW_ERC20_HANDLE_TRANSFER_MIN_OUTPUTS) - ); + flowERC20Config.evaluableConfig.constants); + + { + uint256 handleTransferInputs; + uint256 handleTransferOutputs; + assembly ("memory-safe") { + let ioWord := mload(add(io, 0x20)) + handleTransferInputs := byte(0, ioWord) + handleTransferOutputs := byte(1, ioWord) + } + + if (handleTransferInputs != 0) { + revert UnsupportedHandleTransferInputs(); + } + + if (handleTransferOutputs < FLOW_ERC20_HANDLE_TRANSFER_MIN_OUTPUTS) { + revert InsufficientHandleTransferOutputs(); + } + } + // There's no way to set this before the external call because the // output of the `deployExpression` call is the input to `Evaluable`. // Even if we could set it before the external call, we wouldn't want @@ -126,7 +146,7 @@ contract FlowERC20 is ICloneableV2, IFlowERC20V5, FlowCommon, ERC20 { EvaluableV2 memory evaluable = sEvaluable; (uint256[] memory stack, uint256[] memory kvs) = evaluable.interpreter.eval2( evaluable.store, - DEFAULT_STATE_NAMESPACE, + DEFAULT_STATE_NAMESPACE.qualifyNamespace(address(this)), LibEncodedDispatch.encode2( evaluable.expression, FLOW_ERC20_HANDLE_TRANSFER_ENTRYPOINT, @@ -137,7 +157,8 @@ contract FlowERC20 is ICloneableV2, IFlowERC20V5, FlowCommon, ERC20 { // is triggering the transfer. LibUint256Array.arrayFrom(uint256(uint160(from)), uint256(uint160(to)), amount).matrixFrom(), new SignedContextV1[](0) - ) + ), + new uint256[](0) ); (stack); if (kvs.length > 0) { diff --git a/src/concrete/erc721/FlowERC721.sol b/src/concrete/erc721/FlowERC721.sol index 12b2287a..551b60b3 100644 --- a/src/concrete/erc721/FlowERC721.sol +++ b/src/concrete/erc721/FlowERC721.sol @@ -35,11 +35,13 @@ import { import {IInterpreterStoreV2} from "rain.interpreter.interface/interface/unstable/IInterpreterStoreV2.sol"; import {Pointer} from "rain.solmem/lib/LibPointer.sol"; import {BurnerNotOwner} from "../../error/ErrFlow.sol"; - - -/// @dev The hash of the meta data expected to be passed to `FlowCommon`'s -/// constructor. -bytes32 constant CALLER_META_HASH = bytes32(0xf0003e81ff90467c9933f3ac68db3ca49df8b30ab83a0b88e1ed8381ed28fdd6); +import {LibNamespace, StateNamespace} from "rain.interpreter.interface/lib/ns/LibNamespace.sol"; +import { + InsufficientHandleTransferOutputs, + InsufficientTokenURIOutputs, + UnsupportedHandleTransferInputs, + UnsupportedTokenURIInputs +} from "../../error/ErrFlow.sol"; /// @title FlowERC721 /// See `IFlowERC721V4` for documentation. @@ -110,18 +112,43 @@ contract FlowERC721 is ICloneableV2, IFlowERC721V5, FlowCommon, ERC721 { flowCommonInit(flowERC721Config.flowConfig, FLOW_ERC721_MIN_FLOW_SENTINELS); if (evalHandleTransfer) { - // Include the token URI min outputs if we expect to eval it, - // otherwise only include the handle transfer min outputs. - uint256[] memory minOutputs = evalTokenURI - ? LibUint256Array.arrayFrom(FLOW_ERC721_HANDLE_TRANSFER_MIN_OUTPUTS, FLOW_ERC721_TOKEN_URI_MIN_OUTPUTS) - : LibUint256Array.arrayFrom(FLOW_ERC721_HANDLE_TRANSFER_MIN_OUTPUTS); - - (IInterpreterV2 interpreter, IInterpreterStoreV2 store, address expression) = flowERC721Config + (IInterpreterV2 interpreter, IInterpreterStoreV2 store, address expression, bytes memory io) = flowERC721Config .evaluableConfig .deployer .deployExpression2( - flowERC721Config.evaluableConfig.bytecode, flowERC721Config.evaluableConfig.constants, minOutputs + flowERC721Config.evaluableConfig.bytecode, flowERC721Config.evaluableConfig.constants ); + + { + uint256 handleTransferInputs; + uint256 handleTransferOutputs; + uint256 tokenURIInputs; + uint256 tokenURIOutputs; + assembly ("memory-safe") { + let ioWords := add(io, 0x20) + handleTransferInputs := byte(0, ioWords) + handleTransferOutputs := byte(1, ioWords) + tokenURIInputs := byte(2, ioWords) + tokenURIOutputs := byte(3, ioWords) + } + + if (handleTransferInputs != 0) { + revert UnsupportedHandleTransferInputs(); + } + + if (handleTransferOutputs < FLOW_ERC721_HANDLE_TRANSFER_MIN_OUTPUTS) { + revert InsufficientHandleTransferOutputs(); + } + + if (evalTokenURI && tokenURIInputs != 0) { + revert UnsupportedTokenURIInputs(); + } + + if (evalTokenURI && tokenURIOutputs < FLOW_ERC721_TOKEN_URI_MIN_OUTPUTS) { + revert InsufficientTokenURIOutputs(); + } + } + // There's no way to set this before the external call because the // output of the `deployExpression` call is the input to `Evaluable`. // Even if we could set it before the external call, we wouldn't want @@ -154,11 +181,12 @@ contract FlowERC721 is ICloneableV2, IFlowERC721V5, FlowCommon, ERC721 { EvaluableV2 memory evaluable = sEvaluable; (uint256[] memory stack, uint256[] memory kvs) = evaluable.interpreter.eval2( evaluable.store, - DEFAULT_STATE_NAMESPACE, + DEFAULT_STATE_NAMESPACE.qualifyNamespace(address(this)), LibEncodedDispatch.encode2( evaluable.expression, FLOW_ERC721_TOKEN_URI_ENTRYPOINT, FLOW_ERC721_TOKEN_URI_MAX_OUTPUTS ), - LibContext.build(LibUint256Array.arrayFrom(tokenId).matrixFrom(), new SignedContextV1[](0)) + LibContext.build(LibUint256Array.arrayFrom(tokenId).matrixFrom(), new SignedContextV1[](0)), + new uint256[](0) ); // @todo it would be nice if we could do something with the kvs here, // but the interface is view. diff --git a/src/error/ErrFlow.sol b/src/error/ErrFlow.sol index 8a9f03e5..a412a766 100644 --- a/src/error/ErrFlow.sol +++ b/src/error/ErrFlow.sol @@ -20,4 +20,11 @@ error UnsupportedERC1155Flow(); contract ErrFLow {} /// Thrown when burner of tokens is not the owner of tokens. -error BurnerNotOwner(); \ No newline at end of file +error BurnerNotOwner(); + +error UnsupportedHandleTransferInputs(); +error InsufficientHandleTransferOutputs(); +error UnsupportedTokenURIInputs(); +error InsufficientTokenURIOutputs(); +error UnsupportedFlowInputs(); +error InsufficientFlowOutputs(); \ No newline at end of file diff --git a/src/interface/unstable/IFlowERC1155V5.sol b/src/interface/unstable/IFlowERC1155V5.sol index aa1c8e51..b24ec66a 100644 --- a/src/interface/unstable/IFlowERC1155V5.sol +++ b/src/interface/unstable/IFlowERC1155V5.sol @@ -1,6 +1,7 @@ // SPDX-License-Identifier: CAL pragma solidity ^0.8.18; +import {SourceIndexV2} from "rain.interpreter.interface/interface/unstable/IInterpreterV2.sol"; import {SignedContextV1, EvaluableConfigV3} from "rain.interpreter.interface/interface/IInterpreterCallerV2.sol"; import {EvaluableV2} from "rain.interpreter.interface/lib/caller/LibEvaluable.sol"; import {Sentinel} from "rain.solmem/lib/LibStackSentinel.sol"; @@ -10,11 +11,12 @@ import { FlowERC1155IOV1, ERC1155SupplyChange, FLOW_ERC1155_HANDLE_TRANSFER_MAX_OUTPUTS, - FLOW_ERC1155_HANDLE_TRANSFER_ENTRYPOINT, FLOW_ERC1155_HANDLE_TRANSFER_MIN_OUTPUTS, FLOW_ERC1155_MIN_FLOW_SENTINELS } from "../deprecated/v4/IFlowERC1155V4.sol"; +SourceIndexV2 constant FLOW_ERC1155_HANDLE_TRANSFER_ENTRYPOINT = SourceIndexV2.wrap(0); + /// Initialization config. /// @param uri As per Open Zeppelin `ERC1155Upgradeable`. /// @param evaluableConfig The `EvaluableConfigV2` to use to build the diff --git a/src/interface/unstable/IFlowERC20V5.sol b/src/interface/unstable/IFlowERC20V5.sol index feca5cf7..95223cb4 100644 --- a/src/interface/unstable/IFlowERC20V5.sol +++ b/src/interface/unstable/IFlowERC20V5.sol @@ -1,19 +1,21 @@ // SPDX-License-Identifier: CAL pragma solidity ^0.8.18; +import {SourceIndexV2} from "rain.interpreter.interface/interface/unstable/IInterpreterV2.sol"; import {SignedContextV1, EvaluableConfigV3} from "rain.interpreter.interface/interface/IInterpreterCallerV2.sol"; import {EvaluableV2} from "rain.interpreter.interface/lib/caller/LibEvaluable.sol"; import {Sentinel} from "rain.solmem/lib/LibStackSentinel.sol"; import { FlowERC20IOV1, ERC20SupplyChange, - FLOW_ERC20_HANDLE_TRANSFER_ENTRYPOINT, FLOW_ERC20_HANDLE_TRANSFER_MIN_OUTPUTS, FLOW_ERC20_HANDLE_TRANSFER_MAX_OUTPUTS, FLOW_ERC20_MIN_FLOW_SENTINELS } from "../deprecated/v4/IFlowERC20V4.sol"; import {RAIN_FLOW_SENTINEL} from "./IFlowV5.sol"; +SourceIndexV2 constant FLOW_ERC20_HANDLE_TRANSFER_ENTRYPOINT = SourceIndexV2.wrap(0); + /// Initialization config. /// @param name As per Open Zeppelin `ERC20Upgradeable`. /// @param symbol As per Open Zeppelin `ERC20Upgradeable`. diff --git a/src/interface/unstable/IFlowERC721V5.sol b/src/interface/unstable/IFlowERC721V5.sol index 2032c143..152a5dad 100644 --- a/src/interface/unstable/IFlowERC721V5.sol +++ b/src/interface/unstable/IFlowERC721V5.sol @@ -3,7 +3,7 @@ pragma solidity ^0.8.18; import {SignedContextV1, EvaluableConfigV3} from "rain.interpreter.interface/interface/IInterpreterCallerV2.sol"; import {EvaluableV2} from "rain.interpreter.interface/lib/caller/LibEvaluable.sol"; - +import {SourceIndexV2} from "rain.interpreter.interface/interface/unstable/IInterpreterV2.sol"; import { FlowERC721IOV1, ERC721SupplyChange, @@ -11,11 +11,12 @@ import { FLOW_ERC721_TOKEN_URI_MAX_OUTPUTS, FLOW_ERC721_HANDLE_TRANSFER_MIN_OUTPUTS, FLOW_ERC721_HANDLE_TRANSFER_MAX_OUTPUTS, - FLOW_ERC721_TOKEN_URI_ENTRYPOINT, - FLOW_ERC721_HANDLE_TRANSFER_ENTRYPOINT, FLOW_ERC721_MIN_FLOW_SENTINELS } from "../deprecated/v4/IFlowERC721V4.sol"; +SourceIndexV2 constant FLOW_ERC721_HANDLE_TRANSFER_ENTRYPOINT = SourceIndexV2.wrap(0); +SourceIndexV2 constant FLOW_ERC721_TOKEN_URI_ENTRYPOINT = SourceIndexV2.wrap(1); + import {RAIN_FLOW_SENTINEL} from "../deprecated/v4/IFlowV4.sol"; /// Initialization config. From d1a6c74f2c4a6612a115c81a01be9f977e03e910 Mon Sep 17 00:00:00 2001 From: thedavidmeister Date: Wed, 28 Feb 2024 10:04:19 +0400 Subject: [PATCH 08/13] fmt --- src/abstract/FlowCommon.sol | 10 +++------- src/concrete/erc1155/FlowERC1155.sol | 25 +++++++++---------------- src/concrete/erc20/FlowERC20.sol | 21 +++++++++------------ src/concrete/erc721/FlowERC721.sol | 17 +++++++---------- src/error/ErrFlow.sol | 2 +- src/interface/unstable/IFlowV5.sol | 4 +--- src/lib/LibFlow.sol | 13 ++----------- 7 files changed, 32 insertions(+), 60 deletions(-) diff --git a/src/abstract/FlowCommon.sol b/src/abstract/FlowCommon.sol index b3b89953..4f338ce3 100644 --- a/src/abstract/FlowCommon.sol +++ b/src/abstract/FlowCommon.sol @@ -30,10 +30,7 @@ import {ReentrancyGuardUpgradeable as ReentrancyGuard} from "openzeppelin-contracts-upgradeable/contracts/security/ReentrancyGuardUpgradeable.sol"; import {LibUint256Matrix} from "rain.solmem/lib/LibUint256Matrix.sol"; import {LibNamespace, StateNamespace} from "rain.interpreter.interface/lib/ns/LibNamespace.sol"; -import { - UnsupportedFlowInputs, - InsufficientFlowOutputs -} from "../error/ErrFlow.sol"; +import {UnsupportedFlowInputs, InsufficientFlowOutputs} from "../error/ErrFlow.sol"; /// Thrown when the min outputs for a flow is fewer than the sentinels. /// This is always an implementation bug as the min outputs and sentinel count @@ -154,9 +151,8 @@ abstract contract FlowCommon is ERC721Holder, ERC1155Holder, Multicall, Reentran // Reentrancy is just one of many ways that a malicious deployer // can cause problems, and it's probably the least of your // worries if you're using a malicious deployer. - (IInterpreterV2 interpreter, IInterpreterStoreV2 store, address expression, bytes memory io) = config - .deployer - .deployExpression2(config.bytecode, config.constants); + (IInterpreterV2 interpreter, IInterpreterStoreV2 store, address expression, bytes memory io) = + config.deployer.deployExpression2(config.bytecode, config.constants); { uint256 flowInputs; diff --git a/src/concrete/erc1155/FlowERC1155.sol b/src/concrete/erc1155/FlowERC1155.sol index 42e1d097..572a16a3 100644 --- a/src/concrete/erc1155/FlowERC1155.sol +++ b/src/concrete/erc1155/FlowERC1155.sol @@ -33,10 +33,7 @@ import {SourceIndexV2} from "rain.interpreter.interface/interface/unstable/IInte import {FlowCommon, ERC1155Receiver} from "../../abstract/FlowCommon.sol"; import {LibContext} from "rain.interpreter.interface/lib/caller/LibContext.sol"; import {LibNamespace, StateNamespace} from "rain.interpreter.interface/lib/ns/LibNamespace.sol"; -import { - InsufficientHandleTransferOutputs, - UnsupportedHandleTransferInputs -} from "../../error/ErrFlow.sol"; +import {InsufficientHandleTransferOutputs, UnsupportedHandleTransferInputs} from "../../error/ErrFlow.sol"; /// @title FlowERC1155 /// See `IFlowERC1155V4` for documentation. @@ -74,12 +71,9 @@ contract FlowERC1155 is ICloneableV2, IFlowERC1155V4, FlowCommon, ERC1155 { flowCommonInit(flowERC1155Config.flowConfig, FLOW_ERC1155_MIN_FLOW_SENTINELS); if (evalHandleTransfer) { - (IInterpreterV2 interpreter, IInterpreterStoreV2 store, address expression, bytes memory io) = flowERC1155Config - .evaluableConfig - .deployer - .deployExpression2( - flowERC1155Config.evaluableConfig.bytecode, - flowERC1155Config.evaluableConfig.constants + (IInterpreterV2 interpreter, IInterpreterStoreV2 store, address expression, bytes memory io) = + flowERC1155Config.evaluableConfig.deployer.deployExpression2( + flowERC1155Config.evaluableConfig.bytecode, flowERC1155Config.evaluableConfig.constants ); { @@ -226,12 +220,11 @@ contract FlowERC1155 is ICloneableV2, IFlowERC1155V4, FlowCommon, ERC1155 { /// of the flow contract itself. This involves consuming the mint/burn /// sentinels from the stack and minting/burning the tokens accordingly, then /// calling `LibFlow.flow` to handle the rest of the flow. - function _flow(EvaluableV2 memory evaluable, uint256[] memory callerContext, SignedContextV1[] memory signedContexts) - internal - virtual - nonReentrant - returns (FlowERC1155IOV1 memory) - { + function _flow( + EvaluableV2 memory evaluable, + uint256[] memory callerContext, + SignedContextV1[] memory signedContexts + ) internal virtual nonReentrant returns (FlowERC1155IOV1 memory) { unchecked { (Pointer stackBottom, Pointer stackTop, uint256[] memory kvs) = _flowStack(evaluable, callerContext, signedContexts); diff --git a/src/concrete/erc20/FlowERC20.sol b/src/concrete/erc20/FlowERC20.sol index d3143947..c5dd758c 100644 --- a/src/concrete/erc20/FlowERC20.sol +++ b/src/concrete/erc20/FlowERC20.sol @@ -78,12 +78,10 @@ contract FlowERC20 is ICloneableV2, IFlowERC20V5, FlowCommon, ERC20 { flowCommonInit(flowERC20Config.flowConfig, FLOW_ERC20_MIN_FLOW_SENTINELS); if (evalHandleTransfer) { - (IInterpreterV2 interpreter, IInterpreterStoreV2 store, address expression, bytes memory io) = flowERC20Config - .evaluableConfig - .deployer - .deployExpression2( - flowERC20Config.evaluableConfig.bytecode, - flowERC20Config.evaluableConfig.constants); + (IInterpreterV2 interpreter, IInterpreterStoreV2 store, address expression, bytes memory io) = + flowERC20Config.evaluableConfig.deployer.deployExpression2( + flowERC20Config.evaluableConfig.bytecode, flowERC20Config.evaluableConfig.constants + ); { uint256 handleTransferInputs; @@ -203,12 +201,11 @@ contract FlowERC20 is ICloneableV2, IFlowERC20V5, FlowCommon, ERC20 { /// the mints and burns from the `FlowERC20IOV1` struct. The mints are /// processed first, then the burns, then the remaining flow is processed /// as normal. - function _flow(EvaluableV2 memory evaluable, uint256[] memory callerContext, SignedContextV1[] memory signedContexts) - internal - virtual - nonReentrant - returns (FlowERC20IOV1 memory) - { + function _flow( + EvaluableV2 memory evaluable, + uint256[] memory callerContext, + SignedContextV1[] memory signedContexts + ) internal virtual nonReentrant returns (FlowERC20IOV1 memory) { unchecked { (Pointer stackBottom, Pointer stackTop, uint256[] memory kvs) = _flowStack(evaluable, callerContext, signedContexts); diff --git a/src/concrete/erc721/FlowERC721.sol b/src/concrete/erc721/FlowERC721.sol index 551b60b3..a4cc9cd3 100644 --- a/src/concrete/erc721/FlowERC721.sol +++ b/src/concrete/erc721/FlowERC721.sol @@ -112,10 +112,8 @@ contract FlowERC721 is ICloneableV2, IFlowERC721V5, FlowCommon, ERC721 { flowCommonInit(flowERC721Config.flowConfig, FLOW_ERC721_MIN_FLOW_SENTINELS); if (evalHandleTransfer) { - (IInterpreterV2 interpreter, IInterpreterStoreV2 store, address expression, bytes memory io) = flowERC721Config - .evaluableConfig - .deployer - .deployExpression2( + (IInterpreterV2 interpreter, IInterpreterStoreV2 store, address expression, bytes memory io) = + flowERC721Config.evaluableConfig.deployer.deployExpression2( flowERC721Config.evaluableConfig.bytecode, flowERC721Config.evaluableConfig.constants ); @@ -290,12 +288,11 @@ contract FlowERC721 is ICloneableV2, IFlowERC721V5, FlowCommon, ERC721 { /// from the stack as additional sentinel separated tuples. The mints are /// consumed first, then the burns, then the remaining stack is converted to /// a flow as normal. - function _flow(EvaluableV2 memory evaluable, uint256[] memory callerContext, SignedContextV1[] memory signedContexts) - internal - virtual - nonReentrant - returns (FlowERC721IOV1 memory) - { + function _flow( + EvaluableV2 memory evaluable, + uint256[] memory callerContext, + SignedContextV1[] memory signedContexts + ) internal virtual nonReentrant returns (FlowERC721IOV1 memory) { unchecked { (Pointer stackBottom, Pointer stackTop, uint256[] memory kvs) = _flowStack(evaluable, callerContext, signedContexts); diff --git a/src/error/ErrFlow.sol b/src/error/ErrFlow.sol index a412a766..27160f0e 100644 --- a/src/error/ErrFlow.sol +++ b/src/error/ErrFlow.sol @@ -27,4 +27,4 @@ error InsufficientHandleTransferOutputs(); error UnsupportedTokenURIInputs(); error InsufficientTokenURIOutputs(); error UnsupportedFlowInputs(); -error InsufficientFlowOutputs(); \ No newline at end of file +error InsufficientFlowOutputs(); diff --git a/src/interface/unstable/IFlowV5.sol b/src/interface/unstable/IFlowV5.sol index 97e6cd97..95906770 100644 --- a/src/interface/unstable/IFlowV5.sol +++ b/src/interface/unstable/IFlowV5.sol @@ -14,9 +14,7 @@ import { RAIN_FLOW_SENTINEL, MIN_FLOW_SENTINELS } from "../deprecated/v4/IFlowV4.sol"; -import { - UnregisteredFlow -} from "../../error/ErrFlow.sol"; +import {UnregisteredFlow} from "../../error/ErrFlow.sol"; /// @title IFlowV4 /// @notice Interface for a flow contract that does NOT require native minting diff --git a/src/lib/LibFlow.sol b/src/lib/LibFlow.sol index 5be3e153..f8986337 100644 --- a/src/lib/LibFlow.sol +++ b/src/lib/LibFlow.sol @@ -3,12 +3,7 @@ pragma solidity ^0.8.18; import {IFlowV4, RAIN_FLOW_SENTINEL} from "../interface/unstable/IFlowV5.sol"; import {Pointer} from "rain.solmem/lib/LibPointer.sol"; -import { - FlowTransferV1, - ERC20Transfer, - ERC721Transfer, - ERC1155Transfer -} from "../interface/unstable/IFlowV5.sol"; +import {FlowTransferV1, ERC20Transfer, ERC721Transfer, ERC1155Transfer} from "../interface/unstable/IFlowV5.sol"; import {IInterpreterStoreV2} from "rain.interpreter.interface/interface/unstable/IInterpreterStoreV2.sol"; import {LibStackSentinel} from "rain.solmem/lib/LibStackSentinel.sol"; import {DEFAULT_STATE_NAMESPACE} from "rain.interpreter.interface/interface/unstable/IInterpreterV2.sol"; @@ -17,11 +12,7 @@ import {IERC20} from "openzeppelin-contracts/contracts/token/ERC20/IERC20.sol"; import {SafeERC20} from "openzeppelin-contracts/contracts/token/ERC20/utils/SafeERC20.sol"; import {IERC721} from "openzeppelin-contracts/contracts/token/ERC721/IERC721.sol"; import {IERC1155} from "openzeppelin-contracts/contracts/token/ERC1155/IERC1155.sol"; -import { - UnsupportedERC20Flow, - UnsupportedERC721Flow, - UnsupportedERC1155Flow -} from "../error/ErrFlow.sol"; +import {UnsupportedERC20Flow, UnsupportedERC721Flow, UnsupportedERC1155Flow} from "../error/ErrFlow.sol"; /// @title LibFlow /// Standard processing used by all variants of `Flow`. These utilities can't From 7f91df8b06f637b4a506bdfee33a6a8de3251790 Mon Sep 17 00:00:00 2001 From: thedavidmeister Date: Wed, 28 Feb 2024 10:06:22 +0400 Subject: [PATCH 09/13] test --- .../{unstable => deprecated/v4}/IFlowV4.t.sol | 2 +- test/interface/unstable/IFlowV5.t.sol | 15 +++++++++++++++ 2 files changed, 16 insertions(+), 1 deletion(-) rename test/interface/{unstable => deprecated/v4}/IFlowV4.t.sol (91%) create mode 100644 test/interface/unstable/IFlowV5.t.sol diff --git a/test/interface/unstable/IFlowV4.t.sol b/test/interface/deprecated/v4/IFlowV4.t.sol similarity index 91% rename from test/interface/unstable/IFlowV4.t.sol rename to test/interface/deprecated/v4/IFlowV4.t.sol index 9ea6c4d2..6eac05ce 100644 --- a/test/interface/unstable/IFlowV4.t.sol +++ b/test/interface/deprecated/v4/IFlowV4.t.sol @@ -1,7 +1,7 @@ // SPDX-License-Identifier: CAL pragma solidity =0.8.19; -import "forge-std/Test.sol"; +import {Test} from "forge-std/Test.sol"; import {IFlowV4, RAIN_FLOW_SENTINEL} from "src/interface/deprecated/v4/IFlowV4.sol"; import {Sentinel} from "rain.solmem/lib/LibStackSentinel.sol"; diff --git a/test/interface/unstable/IFlowV5.t.sol b/test/interface/unstable/IFlowV5.t.sol new file mode 100644 index 00000000..64024ef2 --- /dev/null +++ b/test/interface/unstable/IFlowV5.t.sol @@ -0,0 +1,15 @@ +// SPDX-License-Identifier: CAL +pragma solidity =0.8.19; + +import {Test} from "forge-std/Test.sol"; + +import {IFlowV4, RAIN_FLOW_SENTINEL} from "src/interface/deprecated/v4/IFlowV4.sol"; +import {Sentinel} from "rain.solmem/lib/LibStackSentinel.sol"; + +contract IFlowV5Test is Test { + function testSentinelValue() external { + assertEq( + 0xfea74d0c9bf4a3c28f0dd0674db22a3d7f8bf259c56af19f4ac1e735b156974f, Sentinel.unwrap(RAIN_FLOW_SENTINEL) + ); + } +} From 2ad3e61eaa3160cec3db269e4c756ecfd2b3c204 Mon Sep 17 00:00:00 2001 From: thedavidmeister Date: Wed, 28 Feb 2024 10:08:42 +0400 Subject: [PATCH 10/13] ci --- .github/workflows/docs.yaml | 27 ---------------- .github/workflows/manual-sol-artifacts.yaml | 35 ++++++++++++++++++++ .github/workflows/rainix.yaml | 31 ++++++++++++++++++ .github/workflows/slither.yaml | 8 ----- .github/workflows/snapshot.yaml | 28 ---------------- .github/workflows/test.yaml | 36 --------------------- 6 files changed, 66 insertions(+), 99 deletions(-) delete mode 100644 .github/workflows/docs.yaml create mode 100644 .github/workflows/manual-sol-artifacts.yaml create mode 100644 .github/workflows/rainix.yaml delete mode 100644 .github/workflows/slither.yaml delete mode 100644 .github/workflows/snapshot.yaml delete mode 100644 .github/workflows/test.yaml diff --git a/.github/workflows/docs.yaml b/.github/workflows/docs.yaml deleted file mode 100644 index 25a8245f..00000000 --- a/.github/workflows/docs.yaml +++ /dev/null @@ -1,27 +0,0 @@ -name: Build docs - -on: - push: - branches: - - main - -jobs: - docs: - runs-on: ubuntu-latest - steps: - - name: Checkout - uses: actions/checkout@v3 - - name: Install Foundry - uses: foundry-rs/foundry-toolchain@v1 - with: - version: nightly - - name: Generate docs - run: forge doc -b - - name: Deploy to GitHub Pages - if: success() - uses: crazy-max/ghaction-github-pages@v3 - with: - target_branch: gh-pages - build_dir: docs/book - env: - GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} \ No newline at end of file diff --git a/.github/workflows/manual-sol-artifacts.yaml b/.github/workflows/manual-sol-artifacts.yaml new file mode 100644 index 00000000..7f772d82 --- /dev/null +++ b/.github/workflows/manual-sol-artifacts.yaml @@ -0,0 +1,35 @@ +name: Manual sol artifacts +on: + workflow_dispatch: + inputs: + network: + description: 'Network to deploy to' + required: true + type: choice + options: + - polygon + - songbird + - flare + +jobs: + deploy: + runs-on: ubuntu-latest + env: + DEPLOYMENT_KEY: ${{ github.ref == 'refs/heads/main' && secrets.PRIVATE_KEY || secrets.PRIVATE_KEY_DEV }} + steps: + - uses: actions/checkout@v4 + with: + submodules: recursive + fetch-depth: 0 + + - uses: DeterminateSystems/nix-installer-action@v4 + - uses: DeterminateSystems/magic-nix-cache-action@v2 + + - run: nix develop --command rainix-sol-prelude + - run: nix develop --command rainix-sol-artifacts + env: + ETH_RPC_URL: ${{ inputs.network == 'polygon' && secrets.CI_DEPLOY_POLYGON_RPC_URL || inputs.network == 'songbird' && secrets.CI_DEPLOY_SONGBIRD_RPC_URL || inputs.network == 'flare' && secrets.CI_DEPLOY_FLARE_RPC_URL || '' }} + # Flare has hardcoded api key https://flarescan.com/documentation/recipes/foundry-verification + ETHERSCAN_API_KEY: ${{ inputs.network == 'flare' && 'verifyContract' || secrets.EXPLORER_VERIFICATION_KEY }} + DEPLOY_VERIFIER: ${{ inputs.network == 'songbird' && 'blockscout' || inputs.network == 'polygon' && 'etherscan' || '' }} + DEPLOY_VERIFIER_URL: ${{ inputs.network == 'songbird' && 'https://songbird-explorer.flare.network/api' || inputs.network == 'flare' && 'https://api.routescan.io/v2/network/mainnet/evm/14/etherscan' || '' }} diff --git a/.github/workflows/rainix.yaml b/.github/workflows/rainix.yaml new file mode 100644 index 00000000..97d666b3 --- /dev/null +++ b/.github/workflows/rainix.yaml @@ -0,0 +1,31 @@ +name: Rainix CI +on: [push] + +jobs: + standard-tests: + strategy: + matrix: + os: [ubuntu-latest] + task: [rainix-sol-test, rainix-sol-static] + fail-fast: false + runs-on: ${{ matrix.os }} + env: + DEPLOYMENT_KEY: ${{ github.ref == 'refs/heads/main' && secrets.PRIVATE_KEY || secrets.PRIVATE_KEY_DEV }} + steps: + - uses: actions/checkout@v4 + with: + submodules: recursive + fetch-depth: 0 + + - name: Install Nix + uses: DeterminateSystems/nix-installer-action@v4 + - uses: DeterminateSystems/magic-nix-cache-action@v2 + + - run: nix develop --command rainix-sol-prelude + + - name: Run ${{ matrix.task }} + env: + ETH_RPC_URL: ${{ secrets.CI_DEPLOY_RPC_URL }} + ETHERSCAN_API_KEY: ${{ secrets.EXPLORER_VERIFICATION_KEY }} + DEPLOY_VERIFIER: 'etherscan' + run: nix develop --command ${{ matrix.task }} \ No newline at end of file diff --git a/.github/workflows/slither.yaml b/.github/workflows/slither.yaml deleted file mode 100644 index 50d96461..00000000 --- a/.github/workflows/slither.yaml +++ /dev/null @@ -1,8 +0,0 @@ -name: Slither Analysis -on: [push] -jobs: - slither-analyze: - runs-on: ubuntu-latest - steps: - - uses: actions/checkout@v3 - - uses: crytic/slither-action@v0.3.0 diff --git a/.github/workflows/snapshot.yaml b/.github/workflows/snapshot.yaml deleted file mode 100644 index 2d3f2dec..00000000 --- a/.github/workflows/snapshot.yaml +++ /dev/null @@ -1,28 +0,0 @@ -name: Gas snapshot - -on: [push] - -env: - FOUNDRY_PROFILE: ci - -jobs: - snapshot: - strategy: - fail-fast: true - - name: Gas snapshot - runs-on: ubuntu-latest - steps: - - uses: actions/checkout@v3 - - - name: Install Foundry - uses: foundry-rs/foundry-toolchain@v1 - with: - version: nightly - - - name: Foundry shallow install - run: forge install --shallow - - - name: Check gas snapshots - run: forge snapshot --check - id: snapshot diff --git a/.github/workflows/test.yaml b/.github/workflows/test.yaml deleted file mode 100644 index aa8907d7..00000000 --- a/.github/workflows/test.yaml +++ /dev/null @@ -1,36 +0,0 @@ -name: Test - -on: [push] - -env: - FOUNDRY_PROFILE: ci - -jobs: - test: - strategy: - fail-fast: true - - name: Tests - runs-on: ubuntu-latest - steps: - - uses: actions/checkout@v3 - - - name: Install Foundry - uses: foundry-rs/foundry-toolchain@v1 - with: - version: nightly - - - name: Foundry shallow install - run: forge install --shallow - - - name: Run Forge fmt - run: forge fmt --check - id: fmt - - - name: Run Forge build - run: forge build --sizes - id: build - - - name: Run Forge tests - run: forge test -vvv --gas-report - id: test From 79b567f50a5c04a4490041ecc293e5fc5df298b3 Mon Sep 17 00:00:00 2001 From: thedavidmeister Date: Wed, 28 Feb 2024 10:16:06 +0400 Subject: [PATCH 11/13] v5 1155 --- src/concrete/erc1155/FlowERC1155.sol | 20 +++++++++---------- .../deprecated/v4/IFlowERC1155V4.sol | 9 +++++---- src/interface/unstable/IFlowERC1155V5.sol | 16 +++++++-------- 3 files changed, 23 insertions(+), 22 deletions(-) diff --git a/src/concrete/erc1155/FlowERC1155.sol b/src/concrete/erc1155/FlowERC1155.sol index 572a16a3..b08f576f 100644 --- a/src/concrete/erc1155/FlowERC1155.sol +++ b/src/concrete/erc1155/FlowERC1155.sol @@ -10,23 +10,23 @@ import {ICloneableV2, ICLONEABLE_V2_SUCCESS} from "rain.factory/src/interface/IC import {LibUint256Array} from "rain.solmem/lib/LibUint256Array.sol"; import {LibUint256Matrix} from "rain.solmem/lib/LibUint256Matrix.sol"; import { - IFlowERC1155V4, + IFlowERC1155V5, FlowERC1155IOV1, SignedContextV1, - FlowERC1155ConfigV2, + FlowERC1155ConfigV3, ERC1155SupplyChange, RAIN_FLOW_SENTINEL, FLOW_ERC1155_HANDLE_TRANSFER_ENTRYPOINT, FLOW_ERC1155_HANDLE_TRANSFER_MAX_OUTPUTS, FLOW_ERC1155_HANDLE_TRANSFER_MIN_OUTPUTS, - FLOW_ERC1155_MIN_FLOW_SENTINELS + FLOW_ERC1155_MIN_FLOW_SENTINELS, + EvaluableV2 } from "../../interface/unstable/IFlowERC1155V5.sol"; import {LibBytecode} from "rain.interpreter.interface/lib/bytecode/LibBytecode.sol"; import { IInterpreterV2, DEFAULT_STATE_NAMESPACE } from "rain.interpreter.interface/interface/unstable/IInterpreterV2.sol"; import {IInterpreterStoreV2} from "rain.interpreter.interface/interface/unstable/IInterpreterStoreV2.sol"; -import {EvaluableV2} from "rain.interpreter.interface/lib/caller/LibEvaluable.sol"; import {Pointer} from "rain.solmem/lib/LibPointer.sol"; import {LibFlow} from "../../lib/LibFlow.sol"; import {SourceIndexV2} from "rain.interpreter.interface/interface/unstable/IInterpreterV2.sol"; @@ -36,8 +36,8 @@ import {LibNamespace, StateNamespace} from "rain.interpreter.interface/lib/ns/Li import {InsufficientHandleTransferOutputs, UnsupportedHandleTransferInputs} from "../../error/ErrFlow.sol"; /// @title FlowERC1155 -/// See `IFlowERC1155V4` for documentation. -contract FlowERC1155 is ICloneableV2, IFlowERC1155V4, FlowCommon, ERC1155 { +/// See `IFlowERC1155V5` for documentation. +contract FlowERC1155 is ICloneableV2, IFlowERC1155V5, FlowCommon, ERC1155 { using LibStackSentinel for Pointer; using LibUint256Matrix for uint256[]; using LibUint256Array for uint256[]; @@ -51,13 +51,13 @@ contract FlowERC1155 is ICloneableV2, IFlowERC1155V4, FlowCommon, ERC1155 { /// Overloaded typed initialize function MUST revert with this error. /// As per `ICloneableV2` interface. - function initialize(FlowERC1155ConfigV2 memory) external pure { + function initialize(FlowERC1155ConfigV3 memory) external pure { revert InitializeSignatureFn(); } /// @inheritdoc ICloneableV2 function initialize(bytes calldata data) external initializer returns (bytes32) { - FlowERC1155ConfigV2 memory flowERC1155Config = abi.decode(data, (FlowERC1155ConfigV2)); + FlowERC1155ConfigV3 memory flowERC1155Config = abi.decode(data, (FlowERC1155ConfigV3)); emit Initialize(msg.sender, flowERC1155Config); __ERC1155_init(flowERC1155Config.uri); @@ -169,7 +169,7 @@ contract FlowERC1155 is ICloneableV2, IFlowERC1155V4, FlowCommon, ERC1155 { } } - /// @inheritdoc IFlowERC1155V4 + /// @inheritdoc IFlowERC1155V5 function stackToFlow(uint256[] memory stack) external pure @@ -179,7 +179,7 @@ contract FlowERC1155 is ICloneableV2, IFlowERC1155V4, FlowCommon, ERC1155 { return _stackToFlow(stack.dataPointer(), stack.endPointer()); } - /// @inheritdoc IFlowERC1155V4 + /// @inheritdoc IFlowERC1155V5 function flow(EvaluableV2 memory evaluable, uint256[] memory callerContext, SignedContextV1[] memory signedContexts) external virtual diff --git a/src/interface/deprecated/v4/IFlowERC1155V4.sol b/src/interface/deprecated/v4/IFlowERC1155V4.sol index 37100940..ea122c86 100644 --- a/src/interface/deprecated/v4/IFlowERC1155V4.sol +++ b/src/interface/deprecated/v4/IFlowERC1155V4.sol @@ -1,7 +1,8 @@ // SPDX-License-Identifier: CAL pragma solidity ^0.8.18; -import {SignedContextV1, EvaluableConfigV3} from "rain.interpreter.interface/interface/IInterpreterCallerV2.sol"; +import {EvaluableConfigV2, Evaluable} from "rain.interpreter.interface/interface/deprecated/IInterpreterCallerV1.sol"; +import {SignedContextV1} from "rain.interpreter.interface/interface/IInterpreterCallerV2.sol"; import {EvaluableV2} from "rain.interpreter.interface/lib/caller/LibEvaluable.sol"; import {Sentinel} from "rain.solmem/lib/LibStackSentinel.sol"; import {RAIN_FLOW_SENTINEL} from "./IFlowV4.sol"; @@ -23,8 +24,8 @@ import { /// flow behaviours outside self mints/burns. struct FlowERC1155ConfigV2 { string uri; - EvaluableConfigV3 evaluableConfig; - EvaluableConfigV3[] flowConfig; + EvaluableConfigV2 evaluableConfig; + EvaluableConfigV2[] flowConfig; } /// @title IFlowERC1155V4 @@ -61,7 +62,7 @@ interface IFlowERC1155V4 { /// @return flowERC1155IO The `FlowERC1155IOV1` representing all token /// mint/burns and transfers that occurred during the flow. function flow( - EvaluableV2 calldata evaluable, + Evaluable calldata evaluable, uint256[] calldata callerContext, SignedContextV1[] calldata signedContexts ) external returns (FlowERC1155IOV1 calldata); diff --git a/src/interface/unstable/IFlowERC1155V5.sol b/src/interface/unstable/IFlowERC1155V5.sol index b24ec66a..5c0aad17 100644 --- a/src/interface/unstable/IFlowERC1155V5.sol +++ b/src/interface/unstable/IFlowERC1155V5.sol @@ -19,18 +19,18 @@ SourceIndexV2 constant FLOW_ERC1155_HANDLE_TRANSFER_ENTRYPOINT = SourceIndexV2.w /// Initialization config. /// @param uri As per Open Zeppelin `ERC1155Upgradeable`. -/// @param evaluableConfig The `EvaluableConfigV2` to use to build the -/// `evaluable` that can be used to handle transfers. +/// @param evaluableConfig Config to use to build the `evaluable` that can be +/// used to handle transfers. /// @param flowConfig Initialization config for the `Evaluable`s that define the /// flow behaviours outside self mints/burns. -struct FlowERC1155ConfigV2 { +struct FlowERC1155ConfigV3 { string uri; EvaluableConfigV3 evaluableConfig; EvaluableConfigV3[] flowConfig; } -/// @title IFlowERC1155V4 -/// Conceptually identical to `IFlowV4`, but the flow contract itself is an +/// @title IFlowERC1155V5 +/// Conceptually identical to `IFlowV5`, but the flow contract itself is an /// ERC1155 token. This means that ERC1155 self mints and burns are included in /// the stack that the flows must evaluate to. As stacks are processed by flow /// from bottom to top, this means that the self mint/burn will be the last thing @@ -42,12 +42,12 @@ struct FlowERC1155ConfigV2 { /// allows expression authors to prevent transfers from occurring if they don't /// want them to, by reverting within the expression. /// -/// Otherwise the flow contract is identical to `IFlowV4`. -interface IFlowERC1155V4 { +/// Otherwise the flow contract is identical to `IFlowV5`. +interface IFlowERC1155V5 { /// Contract has initialized. /// @param sender `msg.sender` initializing the contract (factory). /// @param config All initialized config. - event Initialize(address sender, FlowERC1155ConfigV2 config); + event Initialize(address sender, FlowERC1155ConfigV3 config); /// As per `IFlowV4` but returns a `FlowERC1155IOV1` instead of a /// `FlowTransferV1`. From 3be517941ed2ee354eac23505001f4ad662b2c58 Mon Sep 17 00:00:00 2001 From: thedavidmeister Date: Wed, 28 Feb 2024 10:19:29 +0400 Subject: [PATCH 12/13] iflow5 --- src/concrete/basic/Flow.sol | 10 +++++----- src/concrete/erc20/FlowERC20.sol | 4 ---- src/interface/deprecated/v4/IFlowV4.sol | 7 ++++--- src/interface/unstable/IFlowV5.sol | 4 ++-- src/lib/LibFlow.sol | 2 +- 5 files changed, 12 insertions(+), 15 deletions(-) diff --git a/src/concrete/basic/Flow.sol b/src/concrete/basic/Flow.sol index e7a07b7c..840b5f13 100644 --- a/src/concrete/basic/Flow.sol +++ b/src/concrete/basic/Flow.sol @@ -3,7 +3,7 @@ pragma solidity =0.8.19; import {ICloneableV2, ICLONEABLE_V2_SUCCESS} from "rain.factory/src/interface/ICloneableV2.sol"; import {FlowCommon, LibContext} from "../../abstract/FlowCommon.sol"; -import {IFlowV4, MIN_FLOW_SENTINELS, FlowTransferV1} from "../../interface/unstable/IFlowV5.sol"; +import {IFlowV5, MIN_FLOW_SENTINELS, FlowTransferV1} from "../../interface/unstable/IFlowV5.sol"; import {LibFlow} from "../../lib/LibFlow.sol"; import {LibUint256Matrix} from "rain.solmem/lib/LibUint256Matrix.sol"; import {Pointer} from "rain.solmem/lib/LibPointer.sol"; @@ -12,8 +12,8 @@ import {EvaluableV2} from "rain.interpreter.interface/lib/caller/LibEvaluable.so import {SignedContextV1, EvaluableConfigV3} from "rain.interpreter.interface/interface/IInterpreterCallerV2.sol"; /// @title Flow -/// See `IFlowV4` docs. -contract Flow is ICloneableV2, IFlowV4, FlowCommon { +/// See `IFlowV5` docs. +contract Flow is ICloneableV2, IFlowV5, FlowCommon { using LibUint256Matrix for uint256[]; using LibUint256Array for uint256[]; @@ -32,12 +32,12 @@ contract Flow is ICloneableV2, IFlowV4, FlowCommon { return ICLONEABLE_V2_SUCCESS; } - /// @inheritdoc IFlowV4 + /// @inheritdoc IFlowV5 function stackToFlow(uint256[] memory stack) external pure virtual override returns (FlowTransferV1 memory) { return LibFlow.stackToFlow(stack.dataPointer(), stack.endPointer()); } - /// @inheritdoc IFlowV4 + /// @inheritdoc IFlowV5 function flow(EvaluableV2 memory evaluable, uint256[] memory callerContext, SignedContextV1[] memory signedContexts) external virtual diff --git a/src/concrete/erc20/FlowERC20.sol b/src/concrete/erc20/FlowERC20.sol index c5dd758c..86225a16 100644 --- a/src/concrete/erc20/FlowERC20.sol +++ b/src/concrete/erc20/FlowERC20.sol @@ -35,10 +35,6 @@ import {LibContext} from "rain.interpreter.interface/lib/caller/LibContext.sol"; import {LibNamespace, StateNamespace} from "rain.interpreter.interface/lib/ns/LibNamespace.sol"; import {UnsupportedHandleTransferInputs, InsufficientHandleTransferOutputs} from "../../error/ErrFlow.sol"; -/// @dev The hash of the meta data expected to be passed to `FlowCommon`'s -/// constructor. -bytes32 constant CALLER_META_HASH = bytes32(0xff0499e4ee7171a54d176cfe13165a7ea512d146dbd99d42b3d3ec9963025acf); - /// @title FlowERC20 /// See `IFlowERC20V5` for documentation. contract FlowERC20 is ICloneableV2, IFlowERC20V5, FlowCommon, ERC20 { diff --git a/src/interface/deprecated/v4/IFlowV4.sol b/src/interface/deprecated/v4/IFlowV4.sol index d0e66fc5..a225df2e 100644 --- a/src/interface/deprecated/v4/IFlowV4.sol +++ b/src/interface/deprecated/v4/IFlowV4.sol @@ -1,7 +1,8 @@ // SPDX-License-Identifier: CAL pragma solidity ^0.8.18; -import {SignedContextV1, EvaluableConfigV3} from "rain.interpreter.interface/interface/IInterpreterCallerV2.sol"; +import {EvaluableConfigV2, Evaluable} from "rain.interpreter.interface/interface/deprecated/IInterpreterCallerV1.sol"; +import {SignedContextV1} from "rain.interpreter.interface/interface/IInterpreterCallerV2.sol"; import {EvaluableV2} from "rain.interpreter.interface/lib/caller/LibEvaluable.sol"; import {Sentinel} from "rain.solmem/lib/LibStackSentinel.sol"; import {Pointer} from "rain.solmem/lib/LibPointer.sol"; @@ -122,7 +123,7 @@ interface IFlowV4 { /// MUST be emitted when the flow contract is initialized. /// @param sender The EOA that deployed the flow contract. /// @param config The list of evaluable configs that define the flows. - event Initialize(address sender, EvaluableConfigV3[] config); + event Initialize(address sender, EvaluableConfigV2[] config); /// Given a stack of values, convert it to a flow transfer. MUST NOT modify /// state but MAY revert if the stack is malformed. The intended workflow is @@ -151,7 +152,7 @@ interface IFlowV4 { /// @param signedContexts The signed contexts to pass to the evaluable. /// @return flowTransfer The resulting flow transfer. function flow( - EvaluableV2 calldata evaluable, + Evaluable calldata evaluable, uint256[] calldata callerContext, SignedContextV1[] calldata signedContexts ) external returns (FlowTransferV1 calldata flowTransfer); diff --git a/src/interface/unstable/IFlowV5.sol b/src/interface/unstable/IFlowV5.sol index 95906770..38ba0df8 100644 --- a/src/interface/unstable/IFlowV5.sol +++ b/src/interface/unstable/IFlowV5.sol @@ -16,7 +16,7 @@ import { } from "../deprecated/v4/IFlowV4.sol"; import {UnregisteredFlow} from "../../error/ErrFlow.sol"; -/// @title IFlowV4 +/// @title IFlowV5 /// @notice Interface for a flow contract that does NOT require native minting /// or burning of itself as a token. This is the base case that all other flow /// interfaces model themselves after, with the addition of token minting and @@ -119,7 +119,7 @@ import {UnregisteredFlow} from "../../error/ErrFlow.sol"; /// native gas movements. This will be fixed in a future version of the interface /// where batching is handled by the flow contract itself, rather than relying /// on `Multicall`. -interface IFlowV4 { +interface IFlowV5 { /// MUST be emitted when the flow contract is initialized. /// @param sender The EOA that deployed the flow contract. /// @param config The list of evaluable configs that define the flows. diff --git a/src/lib/LibFlow.sol b/src/lib/LibFlow.sol index f8986337..c4c88bdb 100644 --- a/src/lib/LibFlow.sol +++ b/src/lib/LibFlow.sol @@ -1,7 +1,7 @@ // SPDX-License-Identifier: CAL pragma solidity ^0.8.18; -import {IFlowV4, RAIN_FLOW_SENTINEL} from "../interface/unstable/IFlowV5.sol"; +import {IFlowV5, RAIN_FLOW_SENTINEL} from "../interface/unstable/IFlowV5.sol"; import {Pointer} from "rain.solmem/lib/LibPointer.sol"; import {FlowTransferV1, ERC20Transfer, ERC721Transfer, ERC1155Transfer} from "../interface/unstable/IFlowV5.sol"; import {IInterpreterStoreV2} from "rain.interpreter.interface/interface/unstable/IInterpreterStoreV2.sol"; From 8b7c7e4cfc63bf47bc81bf8126e130faaef5edee Mon Sep 17 00:00:00 2001 From: thedavidmeister Date: Wed, 28 Feb 2024 10:27:08 +0400 Subject: [PATCH 13/13] slither fix --- src/concrete/erc20/FlowERC20.sol | 3 ++- src/concrete/erc721/FlowERC721.sol | 3 ++- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/src/concrete/erc20/FlowERC20.sol b/src/concrete/erc20/FlowERC20.sol index 86225a16..a266d8d5 100644 --- a/src/concrete/erc20/FlowERC20.sol +++ b/src/concrete/erc20/FlowERC20.sol @@ -50,7 +50,8 @@ contract FlowERC20 is ICloneableV2, IFlowERC20V5, FlowCommon, ERC20 { /// @dev The evaluable that will be used to evaluate `handleTransfer` on /// every transfer. This is only set if `sEvalHandleTransfer` is true. - EvaluableV2 internal sEvaluable; + EvaluableV2 internal sEvaluable = + EvaluableV2(IInterpreterV2(address(0)), IInterpreterStoreV2(address(0)), address(0)); /// Overloaded typed initialize function MUST revert with this error. /// As per `ICloneableV2` interface. diff --git a/src/concrete/erc721/FlowERC721.sol b/src/concrete/erc721/FlowERC721.sol index a4cc9cd3..958c438d 100644 --- a/src/concrete/erc721/FlowERC721.sol +++ b/src/concrete/erc721/FlowERC721.sol @@ -64,7 +64,8 @@ contract FlowERC721 is ICloneableV2, IFlowERC721V5, FlowCommon, ERC721 { /// @dev The evaluable that contains the entrypoints for `handleTransfer` and /// `tokenURI`. This is only set if `sEvalHandleTransfer` or `sEvalTokenURI` /// is true. - EvaluableV2 internal sEvaluable; + EvaluableV2 internal sEvaluable = + EvaluableV2(IInterpreterV2(address(0)), IInterpreterStoreV2(address(0)), address(0)); /// @dev The base URI for all token URIs. This is set during initialization /// and cannot be changed. The token URI evaluable can be used for dynamic