-
Notifications
You must be signed in to change notification settings - Fork 240
About Call Proxies
The design of the Superfluid protocol requires that the protocol logic is executed within a context. Such context is called "Superfluid Call Context". An inner transaction involves the superfluid protocol is also called a "superfluid transaction". To queue an operation in a superfluid transaction, one must use a type of "call proxy": if it is the initial call, a contextless call proxy must be used; or else, contextful call proxy must be used along with a valid "call context stamp".
A Superfluid transaction involves external calls between multiple contracts. At minimum, it involves the host, a token and an agreement. When Super app is involved, it involves the super app, more super apps (multi-level super apps) or contracts that are not super apps.
Such transaction is conducted within a "superfluid call context", where a verifiable chunk of shared memory is passed between external calls as bytes that is often dubbed as "ctx". The specifics of this technique can be found in the technical topic "Stamped Ctx" in the following page.
The use cases of the "superfluid call context" are:
- Provide the rightful msgSender.
- App credit system uses the call contexts to store the accounting information.
- Tracking super app nesting levels. In production, max-level being 1 conveniently provides a some re-entrance protection.
- Provide the abstracted timestamp.
- Provider callback context to the agreements.
- Provide
userData
attached by the original sender.
callAgreement
callAppAction
It is a technique to provide a transactional, secure and efficient heap-like shared memory data in EVM called "stamped Ctx" for both agreements and super app actions.
Related: EIP-1153: Transient storage opcodes
- No polymorphic approach: always add new entry functions for new agreement in host contract.
- Pros: avoid duck tapes (hence type-safe)
- Cons: more boiler plate.
- callAgreement: duck tape "polymorphic" solution.
- Pros: extremely flexible.
- Cons: type-unsafe, may have security implications when handling calldata.
- Better approach, e.g. "spec-haskell" type class, define
AgreementOperation
instances.- Pros: CORRECT WAY OF DOING THINGS.
- Cons: not supported by dumb languages.
Context (and its serialized version ctx) is a technique used in Superfluid framework to pass validatable serialized context structure between external calls within the same context.
The purpose of Context is to enable composable agreements. E.g. you send a stream, which starts another stream, the states need to be shared between the two agreement calls. This shared state may entail: the number of nested calls (for SuperApp callbacks), borrowed deposit, the original msg.sender, etc. (refer to ISuperfluid.sol and the Context struct for the full list of properties). Context can be thought of as trusted data which can only be altered by the Superfluid host, if the data can be altered at will, then it is not secure. It is important to note that this state is tracked within one transaction, at the end of the transaction, the Context is cleared.
In order to be able to pass ctx to the agreement function, such as:
function createFlow(
ISuperfluidToken token,
address receiver,
int96 flowRate,
bytes calldata ctx
)
from top-level call:
function callAgreement(
ISuperAgreement agreementClass,
bytes memory callData,
bytes memory userData
)
_replacePlaceholderCtx
was used, this requires that the user provided abi encoded function call ends with a "0x" zero bytes data, a.k.a "placeholder" ctx, then the superfluid framework will reflate it with the actual stamped ctx, so that no one else can fake the ctx.
How the process looks like:
DATA PACKING:
0 : subscriber (32B)
32 : token (32B)
64 : indexId (32B)
96 : &placeHodlerCtx :: data (32B)
128: *placeHodlerCtx: [0, 0x] (32B) <--- to be replaced _replacePlaceholderCtx
=> _replacePlaceholderCtx replaces the actual *placeHodlerCtx 0x with ctx
STEP 1.b => reduce the length of data by 32B
0 : subscriber (32B)
32 : token (32B)
64 : indexId (32B)
96 : &placeHodlerCtx :: data (32B)
STEP 1.c => append actualCtx
0 : subscriber (32B)
32 : token (32B)
64 : indexId (32B)
96 : &actualCtx :: data (32B)
128: actualCtx: [CTX_LENGTH, CTX_RAW_DATA]
Purpose: A way for the target contract to get msgSender (at the time this method is created, EIP-2771 was not popular yet).
How does it work:
- The target function should have a function signature with the last parameter of type
bytes ctx
. - The
ctx
should initialized as placeHolderCtx (zero length bytes), and host contract will replace it with the actualctx
. - The target function should also follow the linear-type (use at least once, and always return the latest value) convention of using ctx.
About the Standalone callAppAction
Not implemented.
Trusted forwarders (trusted by Superfluid governance) can forward a batch call with a different msgSender
.
- Governance Overview
- For Contributors
- Development Process
- Protocol EVMv1 Operations
- Protocol EVMv1 Technical Notes
- Protocol EVMv1 Core Subgraph