Skip to content

Commit

Permalink
docs
Browse files Browse the repository at this point in the history
  • Loading branch information
thedavidmeister committed Sep 15, 2023
1 parent 019910e commit 4d0b775
Show file tree
Hide file tree
Showing 14 changed files with 590 additions and 180 deletions.
12 changes: 6 additions & 6 deletions src/abstract/FlowCommon.sol
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ 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 {LibContext} from "rain.interpreter/src/lib/caller/LibContext.sol";
import {UnregisteredFlow} from "../interface/unstable/IFlowV4.sol";
import {UnregisteredFlow, MIN_FLOW_SENTINELS} from "../interface/unstable/IFlowV4.sol";
import {
DeployerDiscoverableMetaV2,
DeployerDiscoverableMetaV2ConstructionConfig
Expand Down Expand Up @@ -38,10 +38,6 @@ import {LibUint256Matrix} from "rain.solmem/lib/LibUint256Matrix.sol";
/// @param flowMinOutputs The min outputs for the flow.
error BadMinStackLength(uint256 flowMinOutputs);

/// @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 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.
Expand Down Expand Up @@ -220,7 +216,11 @@ abstract contract FlowCommon is
}

/// TODO merge both flowStack functions into one.
function _flowStack(Evaluable memory evaluable, uint256[] memory callerContext, SignedContextV1[] memory signedContexts) internal returns (Pointer, Pointer, uint256[] memory) {
function _flowStack(
Evaluable memory evaluable,
uint256[] memory callerContext,
SignedContextV1[] memory signedContexts
) internal returns (Pointer, Pointer, uint256[] memory) {
uint256[][] memory context = LibContext.build(callerContext.matrixFrom(), signedContexts);
emit Context(msg.sender, context);
return _flowStack(evaluable, context);
Expand Down
13 changes: 5 additions & 8 deletions src/concrete/basic/Flow.sol
Original file line number Diff line number Diff line change
Expand Up @@ -2,13 +2,9 @@
pragma solidity =0.8.19;

import {ICloneableV2, ICLONEABLE_V2_SUCCESS} from "rain.factory/src/interface/ICloneableV2.sol";
import {
FlowCommon,
DeployerDiscoverableMetaV2ConstructionConfig,
LibContext,
MIN_FLOW_SENTINELS
} from "../../abstract/FlowCommon.sol";
import {IFlowV4, LibFlow} from "../../lib/LibFlow.sol";
import {FlowCommon, DeployerDiscoverableMetaV2ConstructionConfig, 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";
Expand Down Expand Up @@ -56,7 +52,8 @@ contract Flow is ICloneableV2, IFlowV4, FlowCommon {
nonReentrant
returns (FlowTransferV1 memory)
{
(Pointer stackBottom, Pointer stackTop, uint256[] memory kvs) = _flowStack(evaluable, callerContext, signedContexts);
(Pointer stackBottom, Pointer stackTop, uint256[] memory kvs) =
_flowStack(evaluable, callerContext, signedContexts);
FlowTransferV1 memory flowTransfer = LibFlow.stackToFlow(stackBottom, stackTop);
LibFlow.flow(flowTransfer, evaluable.store, kvs);
return flowTransfer;
Expand Down
117 changes: 65 additions & 52 deletions src/concrete/erc1155/FlowERC1155.sol
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,11 @@ import {
SignedContextV1,
FlowERC1155ConfigV2,
ERC1155SupplyChange,
RAIN_FLOW_SENTINEL
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
} from "../../interface/unstable/IFlowERC1155V4.sol";
import {LibBytecode} from "lib/rain.interpreter/src/lib/bytecode/LibBytecode.sol";
import {IInterpreterV1} from "rain.interpreter/src/interface/IInterpreterV1.sol";
Expand All @@ -25,28 +29,27 @@ import {Pointer} from "rain.solmem/lib/LibPointer.sol";
import {LibFlow} from "../../lib/LibFlow.sol";
import {SourceIndex} from "rain.interpreter/src/interface/IInterpreterV1.sol";
import {
MIN_FLOW_SENTINELS,
FlowCommon,
DeployerDiscoverableMetaV2ConstructionConfig,
ERC1155Receiver
FlowCommon, DeployerDiscoverableMetaV2ConstructionConfig, ERC1155Receiver
} from "../../abstract/FlowCommon.sol";
import {LibContext} from "rain.interpreter/src/lib/caller/LibContext.sol";

/// @dev The hash of the meta data expected by the `FlowCommon` constructor.
bytes32 constant CALLER_META_HASH = bytes32(0x7ea70f837234357ec1bb5b777e04453ebaf3ca778a98805c4bb20a738d559a21);

SourceIndex constant HANDLE_TRANSFER_ENTRYPOINT = SourceIndex.wrap(0);
uint256 constant HANDLE_TRANSFER_MIN_OUTPUTS = 0;
uint16 constant HANDLE_TRANSFER_MAX_OUTPUTS = 0;

uint256 constant FLOW_ERC1155_MIN_OUTPUTS = MIN_FLOW_SENTINELS + 2;

/// @title FlowERC1155
/// See `IFlowERC1155V4` for documentation.
contract FlowERC1155 is ICloneableV2, IFlowERC1155V4, FlowCommon, ERC1155 {
using LibStackSentinel for Pointer;
using LibUint256Matrix for uint256[];
using LibUint256Array for uint256[];

/// True if the evaluable needs to be called on every transfer.
bool private sEvalHandleTransfer;

/// The `Evaluable` that handles transfers.
Evaluable internal sEvaluable;

/// Forwards the `FlowCommon` constructor.
constructor(DeployerDiscoverableMetaV2ConstructionConfig memory config) FlowCommon(CALLER_META_HASH, config) {}

/// Overloaded typed initialize function MUST revert with this error.
Expand All @@ -64,11 +67,11 @@ contract FlowERC1155 is ICloneableV2, IFlowERC1155V4, FlowCommon, ERC1155 {
// Set state before external calls here.
bool evalHandleTransfer = LibBytecode.sourceCount(flowERC1155Config.evaluableConfig.bytecode) > 0
&& LibBytecode.sourceOpsLength(
flowERC1155Config.evaluableConfig.bytecode, SourceIndex.unwrap(HANDLE_TRANSFER_ENTRYPOINT)
flowERC1155Config.evaluableConfig.bytecode, SourceIndex.unwrap(FLOW_ERC1155_HANDLE_TRANSFER_ENTRYPOINT)
) > 0;
sEvalHandleTransfer = evalHandleTransfer;

flowCommonInit(flowERC1155Config.flowConfig, FLOW_ERC1155_MIN_OUTPUTS);
flowCommonInit(flowERC1155Config.flowConfig, FLOW_ERC1155_MIN_FLOW_SENTINELS);

if (evalHandleTransfer) {
(IInterpreterV1 interpreter, IInterpreterStoreV1 store, address expression) = flowERC1155Config
Expand All @@ -77,7 +80,7 @@ contract FlowERC1155 is ICloneableV2, IFlowERC1155V4, FlowCommon, ERC1155 {
.deployExpression(
flowERC1155Config.evaluableConfig.bytecode,
flowERC1155Config.evaluableConfig.constants,
LibUint256Array.arrayFrom(HANDLE_TRANSFER_MIN_OUTPUTS)
LibUint256Array.arrayFrom(FLOW_ERC1155_HANDLE_TRANSFER_MIN_OUTPUTS)
);
// There's no way to set this before the external call because the
// output of the `deployExpression` call is the input to `Evaluable`.
Expand All @@ -92,10 +95,6 @@ contract FlowERC1155 is ICloneableV2, IFlowERC1155V4, FlowCommon, ERC1155 {
return ICLONEABLE_V2_SUCCESS;
}

function _dispatchHandleTransfer(address expression) internal pure returns (EncodedDispatch) {
return LibEncodedDispatch.encode(expression, HANDLE_TRANSFER_ENTRYPOINT, HANDLE_TRANSFER_MAX_OUTPUTS);
}

/// Needed here to fix Open Zeppelin implementing `supportsInterface` on
/// multiple base contracts.
function supportsInterface(bytes4 interfaceId)
Expand Down Expand Up @@ -140,7 +139,14 @@ contract FlowERC1155 is ICloneableV2, IFlowERC1155V4, FlowCommon, ERC1155 {
}

(uint256[] memory stack, uint256[] memory kvs) = evaluable.interpreter.eval(
evaluable.store, DEFAULT_STATE_NAMESPACE, _dispatchHandleTransfer(evaluable.expression), context
evaluable.store,
DEFAULT_STATE_NAMESPACE,
LibEncodedDispatch.encode(
evaluable.expression,
FLOW_ERC1155_HANDLE_TRANSFER_ENTRYPOINT,
FLOW_ERC1155_HANDLE_TRANSFER_MAX_OUTPUTS
),
context
);
(stack);
if (kvs.length > 0) {
Expand All @@ -150,15 +156,36 @@ contract FlowERC1155 is ICloneableV2, IFlowERC1155V4, FlowCommon, ERC1155 {
}
}

function _previewFlow(Evaluable memory evaluable, uint256[][] memory context)
internal
view
returns (FlowERC1155IOV1 memory, uint256[] memory)
/// @inheritdoc IFlowERC1155V4
function stackToFlow(uint256[] memory stack)
external
pure
override
returns (FlowERC1155IOV1 memory flowERC1155IO)
{
return _stackToFlow(stack.dataPointer(), stack.endPointer());
}

/// @inheritdoc IFlowERC1155V4
function flow(Evaluable memory evaluable, uint256[] memory callerContext, SignedContextV1[] memory signedContexts)
external
virtual
returns (FlowERC1155IOV1 memory)
{
return _flow(evaluable, callerContext, signedContexts);
}

/// Wraps the standard `LibFlow.stackToFlow` function with the addition of
/// consuming the mint/burn sentinels from the stack and returning them in
/// the `FlowERC1155IOV1`.
/// @param stackBottom The bottom of the stack.
/// @param stackTop The top of the stack.
/// @return flowERC1155IO The `FlowERC1155IOV1` representation of the stack.
function _stackToFlow(Pointer stackBottom, Pointer stackTop) internal pure returns (FlowERC1155IOV1 memory) {
ERC1155SupplyChange[] memory mints;
ERC1155SupplyChange[] memory burns;
Pointer tuplesPointer;
(Pointer stackBottom, Pointer stackTop, uint256[] memory kvs) = _flowStack(evaluable, context);

// mints
// https://github.com/crytic/slither/issues/2126
//slither-disable-next-line unused-return
Expand All @@ -173,46 +200,32 @@ contract FlowERC1155 is ICloneableV2, IFlowERC1155V4, FlowCommon, ERC1155 {
assembly ("memory-safe") {
burns := tuplesPointer
}
return (FlowERC1155IOV1(mints, burns, LibFlow.stackToFlow(stackBottom, stackTop)), kvs);
return FlowERC1155IOV1(mints, burns, LibFlow.stackToFlow(stackBottom, stackTop));
}

/// Wraps the standard `LibFlow.flow` function to handle minting and burning
/// 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)
internal
virtual
nonReentrant
returns (FlowERC1155IOV1 memory)
{
unchecked {
uint256[][] memory context = LibContext.build(callerContext.matrixFrom(), signedContexts);
emit Context(msg.sender, context);
(FlowERC1155IOV1 memory flowIO, uint256[] memory kvs) = _previewFlow(evaluable, context);
for (uint256 i = 0; i < flowIO.mints.length; i++) {
(Pointer stackBottom, Pointer stackTop, uint256[] memory kvs) =
_flowStack(evaluable, callerContext, signedContexts);
FlowERC1155IOV1 memory flowERC1155IO = _stackToFlow(stackBottom, stackTop);
for (uint256 i = 0; i < flowERC1155IO.mints.length; i++) {
// @todo support data somehow.
_mint(flowIO.mints[i].account, flowIO.mints[i].id, flowIO.mints[i].amount, "");
_mint(flowERC1155IO.mints[i].account, flowERC1155IO.mints[i].id, flowERC1155IO.mints[i].amount, "");
}
for (uint256 i = 0; i < flowIO.burns.length; i++) {
_burn(flowIO.burns[i].account, flowIO.burns[i].id, flowIO.burns[i].amount);
for (uint256 i = 0; i < flowERC1155IO.burns.length; i++) {
_burn(flowERC1155IO.burns[i].account, flowERC1155IO.burns[i].id, flowERC1155IO.burns[i].amount);
}
LibFlow.flow(flowIO.flow, evaluable.store, kvs);
return flowIO;
LibFlow.flow(flowERC1155IO.flow, evaluable.store, kvs);
return flowERC1155IO;
}
}

function previewFlow(
Evaluable memory evaluable,
uint256[] memory callerContext,
SignedContextV1[] memory signedContexts
) external view virtual returns (FlowERC1155IOV1 memory) {
uint256[][] memory context = LibContext.build(callerContext.matrixFrom(), signedContexts);
(FlowERC1155IOV1 memory flowERC1155IO,) = _previewFlow(evaluable, context);
return flowERC1155IO;
}

function flow(Evaluable memory evaluable, uint256[] memory callerContext, SignedContextV1[] memory signedContexts)
external
virtual
returns (FlowERC1155IOV1 memory)
{
return _flow(evaluable, callerContext, signedContexts);
}
}
16 changes: 9 additions & 7 deletions src/concrete/erc20/FlowERC20.sol
Original file line number Diff line number Diff line change
Expand Up @@ -14,18 +14,18 @@ import {
SignedContextV1,
FLOW_ERC20_HANDLE_TRANSFER_ENTRYPOINT,
FLOW_ERC20_HANDLE_TRANSFER_MIN_OUTPUTS,
FLOW_ERC20_HANDLE_TRANSFER_MAX_OUTPUTS
FLOW_ERC20_HANDLE_TRANSFER_MAX_OUTPUTS,
RAIN_FLOW_SENTINEL,
FLOW_ERC20_MIN_FLOW_SENTINELS
} from "../../interface/unstable/IFlowERC20V4.sol";
import {LibBytecode} from "lib/rain.interpreter/src/lib/bytecode/LibBytecode.sol";
import {EncodedDispatch, LibEncodedDispatch} from "rain.interpreter/src/lib/caller/LibEncodedDispatch.sol";
import {RAIN_FLOW_SENTINEL} from "../../interface/unstable/IFlowERC20V4.sol";
import {Sentinel, LibStackSentinel} from "rain.solmem/lib/LibStackSentinel.sol";
import {LibFlow} from "../../lib/LibFlow.sol";
import {
FlowCommon,
DeployerDiscoverableMetaV2,
DeployerDiscoverableMetaV2ConstructionConfig,
MIN_FLOW_SENTINELS
DeployerDiscoverableMetaV2ConstructionConfig
} from "../../abstract/FlowCommon.sol";
import {SourceIndex, IInterpreterV1} from "rain.interpreter/src/interface/IInterpreterV1.sol";
import {IInterpreterStoreV1} from "rain.interpreter/src/interface/IInterpreterStoreV1.sol";
Expand Down Expand Up @@ -53,7 +53,7 @@ contract FlowERC20 is ICloneableV2, IFlowERC20V4, FlowCommon, ERC20 {
/// every transfer. This is only set if `sEvalHandleTransfer` is true.
Evaluable internal sEvaluable;

/// Forwards the `FlowCommon` constructor arguments to the `FlowCommon`
/// Forwards the `FlowCommon` constructor arguments to the `FlowCommon`.
constructor(DeployerDiscoverableMetaV2ConstructionConfig memory config) FlowCommon(CALLER_META_HASH, config) {}

/// Overloaded typed initialize function MUST revert with this error.
Expand All @@ -75,7 +75,7 @@ contract FlowERC20 is ICloneableV2, IFlowERC20V4, FlowCommon, ERC20 {
) > 0;
sEvalHandleTransfer = evalHandleTransfer;

flowCommonInit(flowERC20Config.flowConfig, MIN_FLOW_SENTINELS + 2);
flowCommonInit(flowERC20Config.flowConfig, FLOW_ERC20_MIN_FLOW_SENTINELS);

if (evalHandleTransfer) {
(IInterpreterV1 interpreter, IInterpreterStoreV1 store, address expression) = flowERC20Config
Expand Down Expand Up @@ -162,6 +162,7 @@ contract FlowERC20 is ICloneableV2, IFlowERC20V4, FlowCommon, ERC20 {
ERC20SupplyChange[] memory mints;
ERC20SupplyChange[] memory burns;
Pointer tuplesPointer;

// mints
// https://github.com/crytic/slither/issues/2126
//slither-disable-next-line unused-return
Expand Down Expand Up @@ -191,7 +192,8 @@ contract FlowERC20 is ICloneableV2, IFlowERC20V4, FlowCommon, ERC20 {
returns (FlowERC20IOV1 memory)
{
unchecked {
(Pointer stackBottom, Pointer stackTop, uint256[] memory kvs) = _flowStack(evaluable, callerContext, signedContexts);
(Pointer stackBottom, Pointer stackTop, uint256[] memory kvs) =
_flowStack(evaluable, callerContext, signedContexts);
FlowERC20IOV1 memory flowERC20IO = _stackToFlow(stackBottom, stackTop);
for (uint256 i = 0; i < flowERC20IO.mints.length; ++i) {
_mint(flowERC20IO.mints[i].account, flowERC20IO.mints[i].amount);
Expand Down
Loading

0 comments on commit 4d0b775

Please sign in to comment.