Bootstrapping From an Existing Module
Please visit the modules section to discover what modules are already available to bootstrap from.
In this guide, we'll analyze the V2RewardDAppControl contract from the official Atlas repository.
1. Module Summary
This is a DEX backrun module for Uniswap v2 forks. Users usually make their swaps on the dApp frontend, and sign their transactions (swaps) with the dApp router as target. By integrating this module, the user swaps will now be wrapped into Atlas user operations, and sent to the Atlas auctioneer, for auctioning.
Users no longer approve the dApp's router to transfer tokens from them, but Atlas.
Solvers interested in backrunning a user's swap (i.e., for arbitrage) will bid in the auction, and eventually, an Atlas bundler will group all those operations together and send a single transaction to the blockchain.
Here, we're interested in the dApp control contract, where these rules and options are defined.
2. Module Structure
a. Inheritance
The module is inheriting from DAppControl (Atlas official repository). This is the recommended pattern, so we can focus on the customization of our module. This is also true when writing a module from scratch.
b. Call Config
The call config defines the options of our module, and must be passed to the parent DAppControl
during initialization. These options must be carefully reviewed as they will influence the behavior of the Atlas transactions for this module. Here is the full call config of V2RewardDAppControl
and its meaning.
{
// User operations nonces are not required to be included sequentially
userNoncesSequential: false,
// DApp operations nonces are not required to be included sequentially
dappNoncesSequential: false,
// The `preOps` hooks (defined in this module) will be run during Atlas execution
requirePreOps: true,
// The data returned by the `preOps` hook will be passed down to other hooks
trackPreOpsReturnData: true,
// The data returned by the user operation execution will not be passed down to other hooks
trackUserReturnData: false,
// The user operation will not be executed by delegatecalling (standard call)
delegateUser: false,
// The `preSolver` hook will not be executed
requirePreSolver: false,
// The `postSolver` hook will not be executed
requirePostSolver: false,
// The Atlas transaction remains valid even when no solvers are included (we still want the user's swap to go through)
zeroSolvers: true,
// Forces an Atlas transaction to not revert when preliminary validation fails, to ensure the user operation nonce is consumed
reuseUserOp: false,
// The user is allowed to be the auctioneer (they can generate the dApp operations)
userAuctioneer: true,
// Solvers are not allowed to be the auctioneer
solverAuctioneer: false,
// Auctioneer role can be taken by any party
unknownAuctioneer: true,
// The call chain hash generated in the dApp operation will be validated by the Atlas contract
verifyCallChainHash: true,
// The data returned by the previous hooks will be passed down the solver call
forwardReturnData: false,
// Do not revert an Atlas transaction when all solvers fail (we still want the user's swap to go through)
requireFulfillment: false,
// User operation hash will be computed using the trusted approach
trustedOpHash: true,
// Do not invert the solver bid values (highest bid should win)
invertBidValue: false,
// Solver bids will be computed at execution time, and not assumed from their solver operation `bid` field value
exPostBids: true
// Solvers sequence execution will stop whn a successful one is found
multipleSuccessfulSolvers: false
}
c. Auction rules
This module enforces solvers to bid in the REWARD_TOKEN
currency. This token is set in the constructor during initialization, and the rule is enforced by overriding the getBidFormat
function.
d. Hooks
This module is defining custom code for the following hooks.
_checkUserOperation
In this hook, we check that the user operation's dapp
field is equal to the dApp's router contract, as defined in the constructor of the module. Remember the user's swap which used to be an actual transaction is now wrapped into an Atlas user operation. The dapp
field of this operation must be the router contract (as it was the to
field of the former transaction). This check ensures the user operation will be routed to the correct destination.
_preOpsCall
This hook is run before the actual user operation's execution. It takes the user operation's data
field and extract the token being swapped (or sold) from it. It takes the right amount of those tokens from the user (remember the user must have approved Atlas to transfer from them instead of the dApp's router), and in turn, approve the dApp's router to transfer from it. It then returns the address of the token being swapped out (the trackPreOpsReturnData
call config option is enabled), that will be passed down to the _allocateValueCall
hook.
This hook is delegatecalled, all actions are taken on behalf of the execution environment.
_allocateValueCall
This hook is called after the user operation and a solver operation successfully execute. It dispatches the full paid bid amount back to the user.
3. Initialization
Once deployed, the module needs to be enabled on Atlas. This is done by calling the initializeGovernance
function on the AtlasVerification
contract. The function must be called by the module's deployer (referred as governance
in Atlas).
interface IAtlasVerification {
function initializeGovernance(address control) external;
}
address atlasVerificationAddress = address(0x01);
address moduleAddress = address(0x02);
// Activating our module (dApp control)
IAtlasVerification(atlasVerificationAddress).initializeGovernance(moduleAddress);
4. Conclusion
If we are a Uniswap v2 fork DEX looking at integrating Atlas, we can do so easily by bootstrapping from the V2RewardDAppControl
. The module can be deployed as is, or we can alter its behavior as needed, by tweaking the call config options and further customizing the hooks.
Once deployed and initialized, we would need to make the appropriate changes to our frontend. Find a complete example in the frontend changes for dApps integration guide.