Atlas SDK Quickstart
The Atlas SDK is a TypeScript library designed to interact with the Atlas protocol. It provides a set of tools and interfaces to work with user operations, solver operations, and dApp operations within the Atlas ecosystem.
Installation
To use the Atlas SDK in your TypeScript project, install it using npm or yarn:
npm install atlas-sdk
or
yarn add atlas-sdk
Core Components
AtlasSdk
The AtlasSdk
class is the main entry point for interacting with the Atlas protocol. It provides methods for creating and managing operations, simulating transactions, and interacting with the Atlas contracts.
Initialization
import { JsonRpcProvider } from "ethers";
import { AtlasSdk } from "atlas-sdk";
import { MockBackend } from "atlas-sdk/backend";
const chainId = 11155111; // Replace with your network's chain ID
const provider = new JsonRpcProvider("https://rpc.sepolia.org/", chainId);
const backend = new MockBackend(); // Replace with your backend implementation
const sdk = new AtlasSdk(provider, chainId, backend);
Key Methods
newUserOperation(userOpParams: UserOperationParams, generateSessionKey?: boolean): Promise<UserOperation>
signUserOperation(userOp: UserOperation, signer: AbstractSigner): Promise<UserOperation>
submitUserOperation(userOp: UserOperation, hints?: string[]): Promise<SolverOperation[]>
sortSolverOperations(userOp: UserOperation, solverOps: SolverOperation[]): Promise<SolverOperation[]>
createDAppOperation(userOp: UserOperation, solverOps: SolverOperation[], bundler?: string): Promise<DAppOperation>
getMetacallCalldata(userOp: UserOperation, solverOps: SolverOperation[], dAppOp: DAppOperation): string
submitBundle(userOp: UserOperation, solverOps: SolverOperation[], dAppOp: DAppOperation): Promise<string>
Configuration
Proper configuration is essential for the seamless operation of the Atlas SDK. This section outlines the necessary configuration parameters and their usage.
Chain Configuration
Specify the blockchain network's chain ID and RPC endpoint.
const chainId = 11155111; // Replace with your network's chain ID
const rpcEndpoint = "https://rpc.sepolia.org/"; // Replace with your network's RPC URL
Backend Configuration
Select and configure the appropriate backend client based on your environment.
import { MockBackend, FastlaneBackend } from "atlas-sdk/backend";
// For testing purposes
const backend = new MockBackend();
// For production use
const backend = new FastlaneBackend({ basePath: "https://api.your-backend.com" });
Note: Ensure that the backend implementation aligns with your deployment environment.
EIP-712 Domain Configuration
Ensure that the EIP-712 domain is correctly set to enable signing and verification of operations.
import { chainConfig } from "atlas-sdk/config";
const eip712Domain = chainConfig[chainId].eip712Domain;
Ensure that the chainConfig
accurately reflects your network's configuration.
Types
The SDK defines several important types for working with Atlas operations:
UserOperationParams
Defines the parameters required to create a user operation.
interface UserOperationParams {
from: string;
to?: string;
value?: bigint;
gas?: bigint;
maxFeePerGas?: bigint;
nonce?: bigint;
deadline?: bigint;
dapp?: string;
control?: string;
callConfig?: bigint;
sessionKey?: string;
data?: string;
signature?: string;
}
IBackend
Interface defining the backend client responsible for handling operations. Different backend implementations (e.g., MockBackend, FastlaneBackend) should adhere to this interface.
interface IBackend {
addHooksControllers(hooksControllers: IHooksControllerConstructable[]): void;
submitUserOperation(userOp: UserOperation, hints: string[]): Promise<string>;
getSolverOperations(
userOp: UserOperation,
userOpHash: string,
waitForSolvers: boolean
): Promise<SolverOperation[]>;
submitBundle(bundle: Bundle): Promise<string>;
getBundleHash(userOpHash: string, waitForBundle: boolean): Promise<string>;
}
UserOperation
Represents a user operation within the Atlas network.
class UserOperation {
from: string;
to: string;
value: bigint;
gas: bigint;
maxFeePerGas: bigint;
nonce: bigint;
deadline: bigint;
dapp: string;
control: string;
callConfig: bigint;
sessionKey: string;
data: string;
signature: string;
constructor(params: UserOperationParams) {
// ... initialization ...
}
// Additional methods for validation, signing, etc.
}
SolverOperation
Represents a solver operation that processes user operations.
class SolverOperation {
from: string;
to: string;
value: bigint;
gas: bigint;
maxFeePerGas: bigint;
deadline: bigint;
solver: string;
control: string;
userOpHash: string;
bidToken: string;
bidAmount: bigint;
data: string;
signature: string;
score: number;
constructor(params: SolverOperationParams, score: number = 0) {
// ... initialization ...
}
// Additional methods for validation, scoring, etc.
}
DAppOperation
Represents a dApp operation that coordinates user and solver operations.
class DAppOperation {
from: string;
to: string;
nonce: bigint;
deadline: bigint;
control: string;
bundler: string;
userOpHash: string;
callChainHash: string;
signature: string;
constructor(params: DAppOperationParams) {
// ... initialization ...
}
// Additional methods for validation, signing, etc.
}
Utilities
The SDK provides various utility functions to help with common tasks:
Validation Functions
Ensure that inputs conform to expected formats and constraints.
import { isAddress } from "ethers";
export function validateAddress(address: string): boolean {
return isAddress(address) && address.length === 42;
}
export function validateUint32(value: bigint): boolean {
return value <= 2n ** 32n - 1n;
}
export function validateUint256(value: bigint): boolean {
return value <= 2n ** 256n - 1n;
}
export function validateBytes32(value: string): boolean {
return /^0x[0-9a-f]{64}$/.test(value);
}
export function validateBytes(value: string): boolean {
return /^0x([0-9a-f][0-9a-f])*$/.test(value);
}
Encoding Functions
Encode operations using ABI encoding standards.
import { AbiCoder } from "ethers";
const abiCoder = new AbiCoder();
export function abiEncodeUserOperation(userOp: UserOperation): string {
const fields = [
userOp.from,
userOp.to,
userOp.value,
userOp.gas,
userOp.maxFeePerGas,
userOp.nonce,
userOp.deadline,
userOp.dapp,
userOp.control,
userOp.callConfig,
userOp.sessionKey,
userOp.data,
userOp.signature,
];
return abiCoder.encode(
["tuple(address from,address to,uint256 value,uint256 gas,uint256 maxFeePerGas,uint256 nonce,uint256 deadline,address dapp,address control,uint32 callConfig,address sessionKey,bytes data,bytes signature)"],
[fields]
);
}
Call Chain Hash Computation
Compute the call chain hash for operations.
import { keccak256, solidityPacked } from "ethers";
import { UserOperation, SolverOperation } from "../operation";
export function getCallChainHash(
userOp: UserOperation,
solverOps: SolverOperation[],
requirePreOps: boolean,
dAppControl: string
): string {
let callSequence = "0x";
if (requirePreOps) {
callSequence = solidityPacked(["address"], [dAppControl]);
}
callSequence = solidityPacked(
["bytes", "bytes", "bytes"],
[
callSequence,
userOp.abiEncode(),
SolverOperation.abiEncodeArray(solverOps),
]
);
return keccak256(callSequence);
}
Signing and Recovery
Ensure the authenticity and integrity of operations through digital signatures.
Signing Operations
Use Ethereum signers to sign operations following the EIP-712 standard.
import { Wallet } from "ethers";
// Initialize signer
const signer = Wallet.fromMnemonic("your mnemonic phrase");
// Sign a user operation
const signedUserOp = await sdk.signUserOperation(userOp, signer);
Verifying Signatures
Validate the signatures to ensure operations are authorized.
import { verifyTypedData } from "ethers";
const signerAddress = verifyTypedData(
eip712Domain,
userOp.toTypedDataTypes(),
userOp.toTypedDataValues(),
userOp.signature
);
if (signerAddress !== userOp.from) {
throw new Error("Invalid signature");
}
Call Config Flags
Configure operation behaviors using predefined flags. These flags control various aspects of how operations are processed.
Flag Definitions
export enum CallConfigIndex {
UserNoncesSequential,
DAppNoncesSequential,
RequirePreOps,
TrackPreOpsReturnData,
TrackUserReturnData,
DelegateUser,
PreSolver,
PostSolver,
RequirePostOpsCall,
ZeroSolvers,
ReuseUserOp,
UserAuctioneer,
SolverAuctioneer,
UnknownAuctioneer,
VerifyCallChainHash,
ForwardReturnData,
RequireFulfillment,
TrustedOpHash,
InvertBidValue,
ExPostBids,
AllowAllocateValueFailure,
}
Flag Utilities
Check if specific flags are set within the callConfig.
export function flagUserNoncesSequential(callConfig: number): boolean {
return (
(Number(callConfig) & (1 << CallConfigIndex.UserNoncesSequential)) != 0
);
}
export function flagZeroSolvers(callConfig: number): boolean {
return (Number(callConfig) & (1 << CallConfigIndex.ZeroSolvers)) != 0;
}
// Add similar functions for other flags as needed
Example Usage:
const callConfig = userOp.callConfig();
if (flagUserNoncesSequential(callConfig)) {
console.log("User nonces are sequential.");
}
if (flagZeroSolvers(callConfig)) {
console.log("Zero solvers are allowed.");
}
Usage Examples
Practical examples demonstrate how to utilize the Atlas SDK's key functionalities.
Initializing the SDK
import { JsonRpcProvider } from "ethers";
import { AtlasSdk } from "atlas-sdk";
import { MockBackend } from "atlas-sdk/backend";
const chainId = 11155111; // Replace with your network's chain ID
const provider = new JsonRpcProvider("https://rpc.sepolia.org/", chainId);
const backend = new MockBackend(); // Replace with your backend implementation
const sdk = new AtlasSdk(provider, chainId, backend);
Creating and Simulating a User Operation
import { Wallet } from "ethers";
// Initialize signer
const signer = Wallet.fromMnemonic("your mnemonic phrase");
// Define user operation parameters
const userOpParams: UserOperationParams = {
from: signer.address,
to: "0xRecipientAddress",
value: 0n,
gas: 100000n,
maxFeePerGas: 30000000000n,
deadline: 1638316800n, // Example timestamp
dapp: "0xDAppControlAddress",
control: "0xDAppControlAddress",
callConfig: 0n, // Replace with your call configuration
data: "0x", // Transaction data
};
// Create a new user operation
let userOp = await sdk.newUserOperation(userOpParams, true);
// Sign the user operation
userOp = await sdk.signUserOperation(userOp, signer);
// Submit the user operation
const solverOps = await sdk.submitUserOperation(userOp);
// Sort solver operations
const sortedSolverOps = await sdk.sortSolverOperations(userOp, solverOps);
// Create a dApp operation
const dAppOp = await sdk.createDAppOperation(userOp, sortedSolverOps);
// Submit the bundle
const atlasTxHash = await sdk.submitBundle(userOp, sortedSolverOps, dAppOp);
console.log("Atlas Transaction Hash:", atlasTxHash);
Executing a Metacall
const metacallCalldata = sdk.getMetacallCalldata(userOp, sortedSolverOps, dAppOp);
// Execute the metacall using your provider or smart contract interaction
const tx = await provider.sendTransaction({
to: "0xAtlasContractAddress",
data: metacallCalldata,
// Include other transaction parameters as needed
});
console.log("Metacall Transaction Hash:", tx.hash);
Disclaimer: This SDK is provided "as is" without warranty of any kind. Use at your own risk.