Batch Call
Perform multiple steps in a single transaction
The Batch Call feature allows you to perform multiple steps in a single transaction, including calls for Super Tokens, Super Apps, and both at the same time.
The primary goal of the Batch Call is to provide you (and your users) with an easy on/off-ramp to your Super App. It allows smooth user-experiences, without spending precious resources on solidity research and engineering for ad-hoc multi-step transactions.
Instead, you can focus on writing your Super App quickly and intuitively. Once you're satisfied with the basic functionality, it's only a matter of "wrapping up" functions into a Batch Call.

Example

To get a better understanding of what is possible, lets look at the canonical "Flow Lottery" example. In this app, when a new user wishes to participate in the lottery, they are required to perform the following steps:
    1.
    Approve DAI spending by the Superfluid Host
    2.
    Upgrade DAI to DAIx
    3.
    Approve DAI spending by the app for the ticket fee
    4.
    Call the app function participate to pay the ticket fee
    5.
    Start a new flow of DAIx to the app
Since step #1 in the list above involves the DAI ERC20 contract, we cannot batch this. However, we can combine steps #2-5 into a single transaction, since the user is now within the Superfluid Framework.
1
function createPlayBatchCall(upgradeAmount = 0) {
2
return [
3
[
4
101, // upgrade 100 daix to play the game
5
daix.address,
6
web3.eth.abi.encodeParameters(
7
["uint256"],
8
[toWad(upgradeAmount).toString()]
9
)
10
],
11
[
12
1, // approve the ticket fee
13
daix.address,
14
web3.eth.abi.encodeParameters(
15
["address", "uint256"],
16
[app.address, toWad("1").toString()]
17
)
18
],
19
[
20
202, // callAppAction to participate
21
app.address,
22
app.contract.methods.participate("0x").encodeABI()
23
],
24
[
25
201, // create constant flow (10/mo)
26
sf.agreements.cfa.address,
27
web3.eth.abi.encodeParameters(
28
["bytes", "bytes"],
29
[
30
sf.agreements.cfa.contract.methods
31
.createFlow(
32
daix.address,
33
app.address,
34
MINIMUM_GAME_FLOW_RATE.toString(),
35
"0x"
36
)
37
.encodeABI(), // callData
38
"0x" // userData
39
]
40
)
41
]
42
];
43
}
44
45
// Call the host with the batch call parameters
46
await sf.host.batchCall(createPlayBatchCall(100))
Copied!
To see full code, check out the Flow Lottery example​

Usage

In total, there are three main types of batch calls. Each type executes a function on either the host contract (Superfluid.sol), or a specific SuperToken. This table shows each possible combination:
Type
interface
internal call
Super Token
ISuperToken.sol
operationApprove, operationTransferFrom, operationUpgrade, or operationDowngrade
Agreement
Superfluid.sol
_callAgreement
Super App
Superfluid.sol
_callAppAction
In order to select which operation you want, the BatchOperation helper library is provided, which just stores constants like this:
1
library BatchOperation {
2
uint32 constant internal OPERATION_TYPE_ERC20_APPROVE = 1;
3
uint32 constant internal OPERATION_TYPE_ERC20_TRANSFER_FROM = 2;
4
uint32 constant internal OPERATION_TYPE_SUPERTOKEN_UPGRADE = 1 + 100;
5
// ...
6
}
Copied!
Simply import the library and reference the appropriate constant:
1
import {
2
BatchOperation
3
} from "@superfluid-finance/ethereum-contracts/interfaces/superfluid/ISuperfluid.sol";
4
​
5
sf.host.batchCall([
6
BatchOperation.OPERATION_TYPE_ERC20_APPROVE,
7
daix.address,
8
web3.eth.abi.encodeParameters(
9
["address", "uint256"],
10
[app.address, toWad("1").toString()]
11
)
12
],
13
[
14
BatchOperation.OPERATION_TYPE_SUPERFLUID_CALL_APP_ACTION
15
app.address,
16
app.contract.methods.participate("0x").encodeABI()
17
]
18
)
Copied!
Alternatively, you can manually enter the numerical value for the operation you want. Use the quick-reference table here to see all available options:
Operation
Value
OPERATION_TYPE_ERC20_APPROVE
1
OPERATION_TYPE_ERC20_TRANSFER_FROM
2
OPERATION_TYPE_SUPERTOKEN_UPGRADE
101
OPERATION_TYPE_SUPERTOKEN_DOWNGRADE
102
OPERATION_TYPE_SUPERFLUID_CALL_AGREEMENT
201
OPERATION_TYPE_SUPERFLUID_CALL_APP_ACTION
202
For example in your Super App you would write the following:
1
sf.host.batchCall([
2
1, // OPERATION_TYPE_ERC20_APPROVE
3
daix.address,
4
web3.eth.abi.encodeParameters(
5
["address", "uint256"],
6
[app.address, toWad("1").toString()]
7
)
8
],
Copied!
Depending on which operation you select, the host contract will execute the appropriate function. For transferFrom the host exectues the following:
1
} else if (operationType == BatchOperation.OPERATION_TYPE_ERC20_TRANSFER_FROM) {
2
(address sender, address receiver, uint256 amount) =
3
abi.decode(operations[i].data, (address, address, uint256));
4
ISuperToken(operations[i].target).operationTransferFrom(
5
msgSender,
6
sender,
7
receiver,
8
amount);
Copied!
For an agreement call (IDA or CFA) thie host executes the following:
1
} else if (operationType == BatchOperation.OPERATION_TYPE_SUPERFLUID_CALL_AGREEMENT) {
2
(bytes memory callData, bytes memory userData) = abi.decode(operations[i].data, (bytes, bytes));
3
_callAgreement(
4
msgSender,
5
ISuperAgreement(operations[i].target),
6
callData,
7
userData);
Copied!

Putting it all together

Now that you understand what is possible, you should ask yourself the following questions. After answering these, you should be able to identify which parts of your app can be improved by combining multiple transactions into a Batch Call.
    Onboarding: What tokens does the user show up with? How can I quickly get them "into the system" with as few transactions as possible?
    Ongoing Actions: What types of transactions are users making often? Can I combine them together to reduce the user's burden?
    Exiting: Users should typically leave with a feeling of accomplishment. How can I leave a lasting impression on users while they are exiting.
Last modified 4mo ago