Skip to content

Commit f3f4a7d

Browse files
authored
[ETHEREUM-CONTRACTS] payable macro forwarder (#2025)
1 parent 345d564 commit f3f4a7d

File tree

19 files changed

+270
-116
lines changed

19 files changed

+270
-116
lines changed

packages/automation-contracts/autowrap/package.json

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,8 +4,8 @@
44
"version": "0.3.0",
55
"devDependencies": {
66
"@openzeppelin/contracts": "^4.9.6",
7-
"@superfluid-finance/ethereum-contracts": "^1.11.0",
8-
"@superfluid-finance/metadata": "^1.5.1"
7+
"@superfluid-finance/ethereum-contracts": "^1.11.1",
8+
"@superfluid-finance/metadata": "^1.5.2"
99
},
1010
"license": "MIT",
1111
"scripts": {

packages/automation-contracts/scheduler/package.json

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,8 +4,8 @@
44
"version": "1.2.0",
55
"devDependencies": {
66
"@openzeppelin/contracts": "^4.9.6",
7-
"@superfluid-finance/ethereum-contracts": "^1.11.0",
8-
"@superfluid-finance/metadata": "^1.5.1"
7+
"@superfluid-finance/ethereum-contracts": "^1.11.1",
8+
"@superfluid-finance/metadata": "^1.5.2"
99
},
1010
"license": "MIT",
1111
"scripts": {

packages/ethereum-contracts/CHANGELOG.md

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,10 +3,11 @@ All notable changes to the ethereum-contracts will be documented in this file.
33

44
This project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
55

6-
## [Unreleased]
6+
## [v1.11.1]
77

88
### Changed
99

10+
* `MacroForwarder` made payable.
1011
* `IUserDefinedMacro`: added a method `postCheck()` which allows to verify state changes after running the macro.
1112
* `SuperfluidFrameworkDeployer` now also deploys and `MacroForwarder` and enables it as trusted forwarder.
1213
* `deploy-test-environment.js` now deploys fUSDC (the underlying) with 6 decimals (instead of 18) to better resemble the actual USDC.

packages/ethereum-contracts/contracts/interfaces/utils/IUserDefinedMacro.sol

Lines changed: 7 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -31,23 +31,16 @@ interface IUserDefinedMacro {
3131
function postCheck(ISuperfluid host, bytes memory params, address msgSender) external view;
3232

3333
/*
34-
* Additional to the required interface, we recommend to implement the following function:
35-
* `function getParams(...) external view returns (bytes memory);`
34+
* Additional to the required interface, we recommend to implement one or multiple view functions
35+
* which take operation specific typed arguments and return the abi encoded bytes.
36+
* As a convention, the name of those functions shall start with `params`.
3637
*
37-
* It shall return abi encoded params as required as second argument of `MacroForwarder.runMacro()`.
38-
*
39-
* The function name shall be `getParams` and the return type shall be `bytes memory`.
40-
* The number, type and name of arguments are free to choose such that they best fit the macro use case.
41-
*
42-
* In conjunction with the name of the Macro contract, the signature should be as self-explanatory as possible.
43-
*
44-
* Example for a contract `MultiFlowDeleteMacro` which lets a user delete multiple flows in one transaction:
45-
* `function getParams(ISuperToken superToken, address[] memory receivers) external view returns (bytes memory)`
46-
*
47-
*
48-
* Implementing this view function has several advantages:
38+
* Implementing this view function(s) has several advantages:
39+
* - Allows to build more complex macros with internally encapsulated dispatching logic
4940
* - Allows to use generic tooling like Explorers to interact with the macro
5041
* - Allows to build auto-generated UIs based on the contract ABI
5142
* - Makes it easier to interface with the macro from Dapps
43+
*
44+
* You can consult the related test code in `MacroForwarderTest.t.sol` for examples.
5245
*/
5346
}

packages/ethereum-contracts/contracts/utils/ForwarderBase.sol

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -25,12 +25,20 @@ abstract contract ForwarderBase {
2525
}
2626

2727
function _forwardBatchCall(ISuperfluid.Operation[] memory ops) internal returns (bool) {
28+
return _forwardBatchCallWithValue(ops, 0);
29+
}
30+
31+
function _forwardBatchCallWithValue(ISuperfluid.Operation[] memory ops, uint256 valueToForward)
32+
internal
33+
returns (bool)
34+
{
2835
bytes memory fwBatchCallData = abi.encodeCall(_host.forwardBatchCall, (ops));
2936

3037
// https://eips.ethereum.org/EIPS/eip-2771
3138
// we encode the msg.sender as the last 20 bytes per EIP-2771 to extract the original txn signer later on
3239
// solhint-disable-next-line avoid-low-level-calls
33-
(bool success, bytes memory returnedData) = address(_host).call(abi.encodePacked(fwBatchCallData, msg.sender));
40+
(bool success, bytes memory returnedData) = address(_host)
41+
.call{value: valueToForward}(abi.encodePacked(fwBatchCallData, msg.sender));
3442

3543
if (!success) {
3644
CallUtils.revertFromReturnedData(returnedData);

packages/ethereum-contracts/contracts/utils/MacroForwarder.sol

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -7,8 +7,8 @@ import { ForwarderBase } from "../utils/ForwarderBase.sol";
77

88

99
/**
10-
* @dev This is a trusted forwarder with high degree of extensibility through permission-less and user-defined "macro
11-
* contracts". This is a vanilla version without EIP-712 support.
10+
* @dev This is a minimal version of a trusted forwarder with high degree of extensibility
11+
* through permissionless and user-defined "macro contracts".
1212
*/
1313
contract MacroForwarder is ForwarderBase {
1414
constructor(ISuperfluid host) ForwarderBase(host) {}
@@ -29,11 +29,12 @@ contract MacroForwarder is ForwarderBase {
2929
* @dev Run the macro defined by the provided macro contract and params.
3030
* @param m Target macro.
3131
* @param params Parameters to run the macro.
32+
* If value (native coins) is provided, it is forwarded.
3233
*/
33-
function runMacro(IUserDefinedMacro m, bytes calldata params) external returns (bool)
34+
function runMacro(IUserDefinedMacro m, bytes calldata params) external payable returns (bool)
3435
{
3536
ISuperfluid.Operation[] memory operations = buildBatchOperations(m, params);
36-
bool retVal = _forwardBatchCall(operations);
37+
bool retVal = _forwardBatchCallWithValue(operations, msg.value);
3738
m.postCheck(_host, params, msg.sender);
3839
return retVal;
3940
}

packages/ethereum-contracts/ops-scripts/deploy-deterministically.js

Lines changed: 5 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@ const MacroForwarder = artifacts.require("MacroForwarder");
2121
* @param web3 The web3 instance to be used
2222
* @param from address to use for funding the deployer account
2323
*
24-
* Usage: npx truffle exec ops-scripts/deploy-deterministically.js : {CONTRACT NAME} [{NONCE}]
24+
* Usage: npx truffle exec ops-scripts/deploy-deterministically.js : {CONTRACT NAME}
2525
* CONTRACT NAME must be one of SuperfluidLoader, AgreementForwarder
2626
* If NONCE is not defined, 0 is assumed (-> first tx done from the deployer account)
2727
*
@@ -32,6 +32,7 @@ const MacroForwarder = artifacts.require("MacroForwarder");
3232
* GAS_PRICE: override the estimated gas price
3333
* EST_TX_COST: override the estimated tx cost (amount to be sent to deployer)
3434
* for networks with different cost derivation structure (Optimism)
35+
* NONCE: if NONCE is not defined, 0 is assumed (-> first tx done from the deployer account)
3536
*/
3637
module.exports = eval(`(${S.toString()})()`)(async function (
3738
args,
@@ -41,18 +42,12 @@ module.exports = eval(`(${S.toString()})()`)(async function (
4142

4243
console.log("======== Deploying deterministically ========");
4344

44-
let nonce = 0;
45-
if (args.length === 2) {
46-
nonce = parseInt(args.pop());
47-
if (nonce < 0) {
48-
console.error("nonce must be >= 0");
49-
process.exit(1);
50-
}
51-
} else if (args.length !== 1) {
45+
if (args.length !== 1) {
5246
throw new Error("Wrong number of arguments");
5347
}
5448
const contractName = args.pop();
5549

50+
const nonce = parseInt(process.env.NONCE) || 0;
5651
const privKey = process.env.DETERMINISTIC_DEPLOYER_PK;
5752
const deployer = web3.eth.accounts.privateKeyToAccount(privKey);
5853
console.log("deployer:", deployer.address);
@@ -100,10 +95,7 @@ module.exports = eval(`(${S.toString()})()`)(async function (
10095

10196
const deployerTxCnt = await web3.eth.getTransactionCount(deployer.address);
10297
if (nonce !== deployerTxCnt) {
103-
console.error(
104-
`### ERR: requested nonce is ${nonce}, but next usable nonce is ${deployerTxCnt}`
105-
);
106-
process.exit(1);
98+
throw new Error(`### ERR: requested nonce is ${nonce}, but next usable nonce is ${deployerTxCnt}`);
10799
}
108100

109101
const deployerBalance = await web3.eth.getBalance(deployer.address);

packages/ethereum-contracts/package.json

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
{
22
"name": "@superfluid-finance/ethereum-contracts",
33
"description": " Ethereum contracts implementation for the Superfluid Protocol",
4-
"version": "1.11.0",
4+
"version": "1.11.1",
55
"dependencies": {
66
"@decentral.ee/web3-helpers": "0.5.3",
77
"@nomiclabs/hardhat-ethers": "2.2.3",
@@ -18,7 +18,7 @@
1818
"@safe-global/safe-service-client": "^2.0.3",
1919
"@safe-global/safe-web3-lib": "^1.9.4",
2020
"@superfluid-finance/js-sdk": "^0.6.3",
21-
"@superfluid-finance/metadata": "^1.5.1",
21+
"@superfluid-finance/metadata": "^1.5.2",
2222
"async": "^3.2.6",
2323
"csv-writer": "^1.6.0",
2424
"ethers": "^5.7.2",

packages/ethereum-contracts/tasks/deploy-macro-forwarder.sh

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
#!/usr/bin/env bash
22
set -eu
3+
set -o pipefail
34

45
# Usage:
56
# tasks/deploy-macro-forwarder.sh <network>
@@ -23,7 +24,7 @@ source .env
2324
set -x
2425

2526
network=$1
26-
expectedContractAddr="0xfD01285b9435bc45C243E5e7F978E288B2912de6"
27+
expectedContractAddr="0xFD0268E33111565dE546af2675351A4b1587F89F"
2728
deployerPk=$MACROFWD_DEPLOYER_PK
2829

2930
tmpfile="/tmp/$(basename "$0").addr"
@@ -35,13 +36,18 @@ rm "$tmpfile"
3536

3637
echo "deployed to $contractAddr"
3738
if [[ $contractAddr != "$expectedContractAddr" ]]; then
38-
echo "oh no!"
39-
exit
39+
echo "contract address not as expected!"
40+
if [ -z "$SKIP_ADDRESS_CHECK" ]; then
41+
exit
42+
fi
4043
fi
4144

4245
# verify (give it a few seconds to pick up the code)
4346
sleep 5
47+
# allow to fail
48+
set +e
4449
npx truffle run --network "$network" verify MacroForwarder@"$contractAddr"
50+
set -e
4551

4652
# set resolver
4753
ALLOW_UPDATE=1 npx truffle exec --network "$network" ops-scripts/resolver-set-key-value.js : MacroForwarder "$contractAddr"

0 commit comments

Comments
 (0)