Flap Trigger Service
Overview
FlapTriggerService is a decentralized on-chain scheduler that allows smart contracts to request delayed or immediate function callbacks executed by a trusted backend. It bridges on-chain logic with off-chain coordination, enabling complex time-sensitive operations without requiring the caller to manage execution timing directly.
Deployed addresses:
BNB Chain Mainnet
0xcf4EE25035CF883895110f367F5BA8172416a7F9
2,000,000
BNB Chain Testnet
0x560E9830926C9e0EB98a59c6b9902383Fc0D9Eb2
2,000,000
Robinhood Chain Mainnet
0xD3421B1b616a72bB88993A0cf75709BB8D532cc1
2,000,000
Robinhood Chain Testnet
0x34e7624e2c8F944Db1adD9a604fdB7C439CaEa1c
2,000,000
Max Gas Limit: The maximum gas limit supported for a trigger callback.
Primary use cases:
Time-delayed operations (vesting unlocks, periodic distributions, deferred settlements)
Backend-coordinated operations requiring MEV protection
Operations that need external computation before on-chain execution
How it works
Step by step:
The requester contract calls
requestTrigger(), paying the required gas fee and specifying anexecuteAftertimestamp (or0for immediate execution).The service records the request and emits a
FlapTriggerRequestedevent.The off-chain backend monitors for these events and indexes all pending requests.
When the scheduled time arrives, the backend submits a
trigger(requestId)transaction via an MEV-protected RPC (e.g., Flashbots, BloXroute).FlapTriggerService calls back
requester.trigger(requestId)with a bounded gas limit.The requester's callback uses the
requestIdto identify and execute the intended operation.
Timing guarantees
executeAfter is a lower bound, not a hard deadline. The service only guarantees that execution happens after executeAfter.
Integrators must assume there can be an unpredictable delay due to:
Network congestion
Backend processing latency
Block inclusion delays
MEV protection overhead
Requester contracts must be designed to handle late execution gracefully and must not rely on execution at a precise time.
Trigger pricing
A fixed native-currency fee is charged per trigger request, set independently per network:
BNB Chain Mainnet
0.0002 BNB
BNB Chain Testnet
0.0002 BNB
Robinhood Chain Mainnet
0.0004 ETH
Robinhood Chain Testnet
0.0004 ETH
This fee covers:
Gas costs for the backend's
trigger()transactionGas costs for the callback to the requester contract
A small service fee
Robinhood Chain fee is temporarily elevated. Due to gas-price fluctuation on Robinhood Chain, the current fee is set higher than strictly necessary while we evaluate a more precise pricing approach. This fee is expected to change.
Always call getFee() at call time β never hardcode the fee value. This applies to every network, including BNB Chain. BNB Chain's fee is fixed today, but Robinhood Chain's fee is expected to become dynamic in the future: when Ethereum L1 (which Robinhood Chain settles to) is congested and gas is expensive, the fee may be increased; when the network is quiet, it may be decreased. A contract that hardcodes the fee instead of calling getFee() on every requestTrigger() call will eventually either underpay (causing InsufficientGasFee reverts) or overpay unnecessarily once dynamic pricing is in effect.
Getting the current fee:
The fee is paid upfront when calling requestTrigger() as msg.value. Excess payment above the required fee is accumulated as protocol fees β there is no refund for overpayment.
Callback gas limit:
Each trigger callback is forwarded at most getMaxCallbackGas() gas. Requester contracts must ensure their trigger() callback completes within this limit. Exceeding the limit will cause the callback to fail (status becomes FAILED).
Failed callbacks and retry:
If a callback fails (e.g., out of gas or revert), the request status is set to FAILED. Anyone can retry a failed request by calling retryTrigger(requestId) β this forwards all available gas to the callback, allowing the caller to supply sufficient gas. The fee stored in the request is transferred to the fee receiver on successful retry.
How to integrate
Step 1 β Import the interfaces
Step 2 β Implement ITriggerReceiver
ITriggerReceiverYour contract must implement the trigger(uint256 requestId) callback. This function is called by FlapTriggerService when the scheduled time has passed.
Security requirements for the callback:
Must validate
msg.sender == address(triggerService)Should implement a reentrancy guard if performing external calls or state changes
Must complete within
getMaxCallbackGas()gasMust not assume execution happens exactly at
executeAfterβ always assume potential delay
Step 3 β Schedule a trigger
Call requestTrigger() with the desired executeAfter timestamp. Store the returned requestId to map it back to the intended operation in your callback.
Pseudo-code example
Scheduling for immediate execution
Pass 0 as executeAfter to request execution as soon as the backend processes the event:
Querying request status
Retrying a failed trigger
If a callback fails (e.g., the callback used more gas than the limit), anyone can retry:
Reference
Full interface
Last updated