Account Abstraction SDK
Introduction
Shiba’s account abstraction implementation allows for transaction batching, sponsored transactions and paying for gas fees out of the user’s balance. This SDK provides a simple interface to interact with the Account Abstraction service.
Audience
Developers.
Installation
Prerequisites
- Node.js
- npm
Installing the SDK
To install the SDK, you can clone the repository and install the dependencies. Once this gets published to npm, you can install it using npm, till then you can follow the below steps:
- Clone the repository
git clone https://github.com/shibaone/account-abstraction-sdk.git
- Navigate to the project directory
cd account-abstraction-sdk
- Install the dependencies
npm install
- Build the project
npm run build
- Install yalc to publish it locally
npm install -g yalc
- Publish the package locally
yalc publish
- Now go to your project and install this package in your project
yalc add shib-account-abstraction-sdk@1.0.0
- Link the package
yalc link shib-account-abstraction-sdk@1.0.0
- Now you can use this package in your project
npm install shib-account-abstraction-sdk
Getting Started
The Account Abstraction SDK has implemented the Shib4337 class underneath the hood. The Shib4337 class provides an interface to interact with Ethereum's Account Abstraction (EIP-4337) functionality. It allows developers to create and manage smart contract wallets (Safes), handle meta-transactions, and integrate with bundlers and paymasters.
Methods
Class Overview
The Shib4337 class is designed to:
- Initialize and manage a smart contract wallet (Safe) using Account Abstraction.
- Queue meta-transactions to be executed.
- Create user operations (
UserOperation) compatible with EIP-4337. - Interact with bundler services to send user operations.
- Integrate with paymaster services for gas sponsorship.
Constructor
constructor(options: Safe4337Options)
Description
Creates an instance of the Shib4337 class.
This constructor is typically called internally by the init static method and not directly by developers.
Parameters
-
options: Safe4337Options: Configuration options for initializing theShib4337instance.interface Safe4337Options {
chainId: number;
safeAddress: string;
initCode: string;
bundlerClient: ethers.JsonRpcProvider;
publicClient: ethers.JsonRpcProvider;
bundlerUrl: string;
paymasterOptions?: PaymasterOptions;
entryPointAddress: string;
safe4337ModuleAddress: string;
}parameter required/optional type description chainId Required number Blockchain network identifier. safeAddress Required string Contract address of the Safe (smart contract wallet). initCode Required string Initialization code that is used to deploy a new Safe if it doesn’t already exist. bundlerClient Required ethers.JsonRpcProvider A JSON RPC provider specifically for interacting with the bundler. publicClient Required ethers.JsonRpcProvider A standard JSON RPC provider that enables general communication with the Ethereum network. bundlerUrl Required string A URL that specifies the endpoint for the bundler service. paymasterOptions Optional PaymasterOptions Paymaster configuration. For more information, head to its documentation page. entryPointAddress Required string The address of the EntryPoint contract safe4337ModuleAddress Required string The address of the Safe4337 module contract
Example
Not typically used directly; use Shib4337.init() instead.
Static Methods
init
static init(initOptions: Safe4337InitOptions): Shib4337
Description
Initializes a new instance of the Shib4337 class. It sets up the necessary configurations, including chain IDs, contract addresses, and clients for interacting with the blockchain and bundler services.
- If
safeAddressis provided, it uses the existing Safe. - If
safeAddressis not provided, it calculates the predicted Safe address based on the owners, threshold, and salt nonce.
Parameters
-
initOptions: Safe4337InitOptions: Initialization parameters.interface Safe4337InitOptions {
chainId: number;
signer: ethers.Signer;
options: {
safeAddress?: string;
owners?: string[ ];
threshold?: number;
saltNonce?: string;
};
bundlerUrl: string;
rpcUrl?: string;
customContracts?: {
safe4337ModuleAddress?: string;
entryPointAddress?: string;
};
paymasterOptions?: PaymasterOptions;
}parameter required/optional type description chainId Required number Blockchain network identifier. signer Required ethers.Signer An account with the ability to sign transactions. options Required Configuration settings for the Safe smart contract wallet. safeAddress Optional string Contract address of the Safe (smart contract wallet). owners Optional string[ ] Array of addresses that will act as owners of the Safe. threshold Optional number Defines the minimum number of owner approvals required for transactions. saltNonce Optional string Unique value (salt) used for deploying a new Safe instance if no existing safeAddress is provided. bundlerUrl Required string A URL that specifies the endpoint for the bundler service. rpcUrl Optional string URL for the JSON-RPC endpoint to connect to the network. customContracts Optional An object containing custom contract addresses for specific components in the EIP-4337 setup. safe4337ModuleAddress Optional string Address of a custom Safe4337 module. entryPointAddress Optional string Address of a custom Entry Point contract. paymasterOptions Optional PaymasterOptions Paymaster configuration. For more information, head to its documentation page.
Returns
Shib4337: An instance of theShib4337class.
Example
import { Shib4337 } from './Shib4337';
import { ethers } from 'ethers';
const provider = new ethers.JsonRpcProvider('<https://rpc-url>');
const signer = new ethers.Wallet(PRIVATE_KEY, provider);
const shibAAservice = Shib4337.init({
chainId: 109, // Shibarium
signer,
options: {
owners: [signer.address],
threshold: 1,
saltNonce: '0',
},
bundlerUrl: '<https://bundler-url>',
paymasterOptions: {
paymasterUrl: '<https://paymaster-url>',
isSponsored: true,
},
});
Instance Methods
getSupportedEntryPoints
async getSupportedEntryPoints(): Promise<string[]>
Description
Fetches the list of supported entry point contract addresses from the bundler service.
Returns
Promise<string[]>: An array of entry point contract addresses.
Example
const entryPoints = await shibAAservice.getSupportedEntryPoints();
console.log('Supported Entry Points:', entryPoints);
getWalletAddress
async getWalletAddress(): Promise<string>
Description
Retrieves the smart contract wallet (Safe) address associated with the Shib4337 instance.
Returns
Promise<string>: The wallet address.
Example
const walletAddress = await shibAAservice.getWalletAddress();
console.log('Wallet Address:', walletAddress);
addTransaction
async addTransaction(transaction: MetaTransactionData): Promise<MetaTransactionData[]>
Description
Adds a transaction to the internal transaction queue. These transactions can later be batched and executed together.
Parameters
-
transaction: MetaTransactionData: The transaction data to add to the queue.interface MetaTransactionData {
to: string;
value: string | number | bigint;
data: string;
operation?: OperationType;
}parameter required/optional type description to Required string The address of the recipient (contract or wallet) that will receive the transaction. value Required string, number or bigint The amount of tokens to be sent with the transaction. data Required string The calldata to be sent along with the transaction, typically used to interact with smart contracts. For example, it could contain function signatures and parameters. operation Optional OperationType Specifies the type of operation to be performed. The default operation is usually CALL, but it may also support DELEGATECALL or other types, depending on the setup.
Returns
Promise<MetaTransactionData[]>: The updated list of transactions in the queue.
Example
await shibAAservice.addTransaction({
to: '0xRecipientAddress',
value: ethers.parseEther('0.1').toString(),
data: '0x',
operation: OperationType.Call,
});
getTransactions
async getTransactions(): Promise<MetaTransactionData[]>
Description
Retrieves the list of transactions currently in the internal queue.
Returns
Promise<MetaTransactionData[]>: The list of queued transactions.
Example
const transactions = await shibAAservice.getTransactions();
console.log('Queued Transactions:', transactions);
createTransaction
async createTransaction(props: Safe4337CreateTransactionProps): Promise<UserOperation>
Description
Creates a user operation (UserOperation) that can be sent to the bundler for execution. It handles the encoding of transactions, estimation of gas, and integration with paymasters.
Parameters
-
props: Safe4337CreateTransactionPropsinterface Safe4337CreateTransactionProps {
transactions?: MetaTransactionData[];
options?: Safe4337CreateTransactionOptions;
}parameter required/optional type description transactions Optional string An array of transactions to include. If not provided, uses the queued transactions. options Optional string Additional options for transaction creation. interface Safe4337CreateTransactionOptions {
type?: PaymasterType;
amountToApprove?: BigNumberish;
validUntil?: number;
validAfter?: number;
feeEstimator?: Function;
paymasterAndData?: string;
}parameter required/optional type description type Optional PaymasterType The PaymasterType. Check Paymaster page. amountToApprove Optional BigNumberish The amount (in the blockchain's native currency, like ETH) to be approved for spending by the smart contract. validUntil Optional number A timestamp representing the time until which the transaction remains valid. validAfter Optional number A timestamp indicating the time from which the transaction becomes valid. feeEstimator Optional Function A function that estimates the transaction fees. paymasterAndData Optional string Encoded data that contains information about the paymaster to be used and any additional parameters required by the paymaster.
Returns
Promise<UserOperation>: The constructed user operation ready to be sent to the bundler.
Example
const userOp = await shibAAservice.createTransaction({
options: {
type: PaymasterType.VerifyingPaymaster,
},
});
executeTransaction
async executeTransaction(props: Safe4337ExecuteTransactionProps): Promise<SendExecuteTransactionResponse>
Description
Executes the user operation by sending it to the bundler service. It handles the signing of the operation and waits for the transaction to be mined.
Parameters
-
props: Safe4337ExecuteTransactionPropsinterface Safe4337ExecuteTransactionProps {
userOp: UserOperation;
signer: ethers.Signer;
}parameter required/optional type description userOp Required UserOperation The user operation to execute. signer Required ethers.Signer The signer used to sign the transaction
Description
Executes the user operation by sending it to the bundler service. It handles the signing of the operation and waits for the transaction to be mined.
Returns
-
Promise<SendExecuteTransactionResponse>interface SendExecuteTransactionResponse {
userOpHash: string;
wait: () => Promise<UserOperationWithPayload>;
}
Example
const executeResponse = await shibAAservice.executeTransaction({
userOp,
signer,
});
const userOpHash = executeResponse.userOpHash;
const receipt = await executeResponse.wait();
console.log('Transaction Receipt:', receipt);
getUserOpsByHash
async getUserOpsByHash(userOpHash: string): Promise<UserOperationWithPayload>
Description
Fetches the details of a user operation from the bundler service using its hash.
Parameters
| parameter | required/optional | type | description |
|---|---|---|---|
| userOpHash | string | The hash of the user operation. |
Returns
Promise<UserOperationWithPayload>: The user operation details.
Example
const userOpDetails = await shibAAservice.getUserOpsByHash(userOpHash);
console.log('User Operation Details:', userOpDetails);
Examples
Initializing the Shib4337 Instance
import { Shib4337 } from 'shib-account-abstraction-sdk';
import { ethers } from 'ethers';
const provider = new ethers.JsonRpcProvider('<https://rpc-url>');
const signer = new ethers.Wallet(PRIVATE_KEY, provider);
const shibAAservice = Shib4337.init({
chainId: 157, // Puppynet
signer,
options: {
owners: [signer.address],
threshold: 1,
saltNonce: '0',
},
bundlerUrl: '<https://bundler-url>',
paymasterOptions: {
paymasterUrl: '<https://paymaster-url>',
isSponsored: true,
},
});
Adding and Executing Transactions
// Add a transaction to the queue
await shibAAservice.addTransaction({
to: '0xRecipientAddress',
value: ethers.parseEther('0.1').toString(),
data: '0x',
operation: OperationType.Call,
});
// Create a user operation
const userOp = await shibAAservice.createTransaction({
options: {
type: PaymasterType.VerifyingPaymaster,
},
});
// Execute the transaction
const executeResponse = await shibAAservice.executeTransaction({
userOp,
signer,
});
const userOpHash = executeResponse.userOpHash;
const receipt = await executeResponse.wait();
console.log('Transaction Receipt:', receipt);
Error Handling
Bundler Errors
ERC-4337 error responses have this format:
{
"jsonrpc": "2.0",
"id": 1
"error": {
code,
message
}
}
Below are the common error codes specified by the protocol.
Many of these errors will also be accompanied by an additional error message from the EntryPoint.
| Code | Description |
|---|---|
| -32521 | Transaction reverted (or will revert) during execution phase. |
| -32602 | Invalid UserOperation struct/fields. |
| -32500 | Transaction rejected by entryPoint's simulateValidation, during account creation or validation. |
| -32501 | Transaction rejected by paymaster's validatePaymasterUserOp. |
| -32502 | Transaction rejected because of opcode validation. |
| -32503 | UserOperation out of time-range: either account or paymaster returned a time-range, and it is already expired (or will expire soon). |
| -32504 | Transaction rejected because paymaster (or signature aggregator) is throttled/banned. |
| -32505 | Transaction rejected because paymaster (or signature aggregator) stake or unstake-delay is too low. |
| -32506 | Transaction rejected because account specified unsupported signature aggregator. |
| -32507 | Either validateUserOp or validatePaymasterUserOp returned an invalid signature check. |
EntryPoint Errors
Bundler error codes often are accompanied by an additional AAxx code provided by the EntryPoint to give additional guidance.
AA1xerror codes relate to creating an accountAA2xerror codes relate to the sender of the user operationAA3xerror codes relate to paymastersAA4xerror codes relate to verification generallyAA5xerrors relate to actions after the user operation was executed
Additional Methods and Functionality
The Shib4337 class includes several advanced features:
- Paymaster Integration: Supports various paymaster types for gas sponsorship.
- Gas Estimation: Estimates gas requirements for user operations.
- Transaction Batching: Allows batching multiple transactions into a single operation.
- Error Handling: Provides informative error messages for troubleshooting.