Skip to content

Commit

Permalink
added postCheck function and recommendation for getParams to IUserDef…
Browse files Browse the repository at this point in the history
…inedMacro
  • Loading branch information
d10r committed Mar 21, 2024
1 parent 54fd386 commit 1d4d64c
Show file tree
Hide file tree
Showing 3 changed files with 77 additions and 0 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -18,4 +18,34 @@ interface IUserDefinedMacro {
*/
function buildBatchOperations(ISuperfluid host, bytes memory params, address msgSender) external view
returns (ISuperfluid.Operation[] memory operations);

/**
* @dev A post-check function which is called after execution.
* It allows to do arbitrary checks based on the state after execution,
* and to revert if the result is not as expected.
* Can be an empty implementation if no check is needed.
*/
function postCheck() external view;

/*
* Additional to the required interface, we recommend to implement the following function:
* `function getParams(...) external view returns (bytes memory);`
*
* It shall return abi encoded params as required as second argument of `MacroForwarder.runMacro()`.
*
* The function name shall be `getParams` and the return type shall be `bytes memory`.
* The number, type and name of arguments are free to choose such that they best fit the macro use case.
*
* In conjunction with the name of the Macro contract, the signature should be as self-explanatory as possible.
*
* Example for a contract `MultiFlowDeleteMacro` which lets a user delete multiple flows in one transaction:
* `function getParams(ISuperToken superToken, address[] memory receivers) external view returns (bytes memory)`
*
*
* Implementing this view function has several advantages:
* - Allows to use generic tooling like Explorers to interact with the macro
* - Allows to build auto-generated UIs based on the contract ABI
* - Makes it easier to interface with the macro from Dapps
*
*/
}
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@ contract MacroForwarder is ForwarderBase {
function runMacro(IUserDefinedMacro m, bytes calldata params) external returns (bool)
{
ISuperfluid.Operation[] memory operations = buildBatchOperations(m, params);
m.postCheck();
return _forwardBatchCall(operations);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import { FoundrySuperfluidTester, SuperTokenV1Library } from "../FoundrySuperflu

using SuperTokenV1Library for ISuperToken;

// not overriding IUserDefinedMacro here in order to avoid the compiler enforcing the function to be view-only.
contract NaugthyMacro {
int naughtyCounter = -1;

Expand All @@ -26,6 +27,8 @@ contract NaugthyMacro {
}
return new ISuperfluid.Operation[](0);
}

function postCheck() external view { }
}

contract GoodMacro is IUserDefinedMacro {
Expand Down Expand Up @@ -56,6 +59,13 @@ contract GoodMacro is IUserDefinedMacro {
});
}
}

function postCheck() external view { }

// recommended view function for parameter encoding
function getParams(ISuperToken token, int96 flowRate, address[] calldata recipients) external pure returns (bytes memory) {
return abi.encode(token, flowRate, recipients);
}
}

// deletes a bunch of flows of the msgSender
Expand Down Expand Up @@ -87,6 +97,20 @@ contract MultiFlowDeleteMacro is IUserDefinedMacro {
});
}
}

function postCheck() external view { }
}

contract MacroWithRevertingPostCheck is IUserDefinedMacro {
function buildBatchOperations(ISuperfluid, bytes memory, address /*msgSender*/) external override pure
returns (ISuperfluid.Operation[] memory /*operation*/)
{
return new ISuperfluid.Operation[](0);
}

function postCheck() external pure {
revert("I'm a bad macro");
}
}

/*
Expand Down Expand Up @@ -134,6 +158,8 @@ contract StatefulMacro is IUserDefinedMacro {
});
}
}

function postCheck() external view { }
}

contract MacroForwarderTest is FoundrySuperfluidTester {
Expand Down Expand Up @@ -176,6 +202,20 @@ contract MacroForwarderTest is FoundrySuperfluidTester {
vm.stopPrank();
}

function testGoodMacroUsingGetParams() external {
GoodMacro m = new GoodMacro();
address[] memory recipients = new address[](2);
recipients[0] = bob;
recipients[1] = carol;
vm.startPrank(admin);
// NOTE! This is different from abi.encode(superToken, int96(42), [bob, carol]),
// which is a fixed array: address[2].
macroForwarder.runMacro(m, m.getParams(superToken, int96(42), recipients));
assertEq(sf.cfa.getNetFlow(superToken, bob), 42);
assertEq(sf.cfa.getNetFlow(superToken, carol), 42);
vm.stopPrank();
}

function testStatefulMacro() external {
address[] memory recipients = new address[](2);
recipients[0] = bob;
Expand Down Expand Up @@ -211,4 +251,10 @@ contract MacroForwarderTest is FoundrySuperfluidTester {
}
vm.stopPrank();
}

function testRevertingPostCheck() external {
MacroWithRevertingPostCheck m = new MacroWithRevertingPostCheck();
vm.expectRevert();
macroForwarder.runMacro(m, new bytes(0));
}
}

0 comments on commit 1d4d64c

Please sign in to comment.