Skip to main content

Quickstart: Send Your First UserOperation

This guide helps you send a UserOperation (UserOp) using ERC-4337 Account Abstraction with the Startale SCS AA SDK. You'll interact with a Counter smart contract and submit a sponsored UserOp via a Bundler and Paymaster.


Prerequisites

Ensure the following:

  • Node.js v18+
  • .env file with configuration values
  • A Bundler URL from SCS Portal
  • (Optional) Paymaster URL
  • Your EOA Private Key
  • A deployed Counter smart contract on Soneium Minato

Project Setup

  1. Initialize a Node.js project
mkdir aa-quickstart && cd aa-quickstart
npm init -y
  1. Install dependencies
npm install dotenv ora viem @startale-scs/aa-sdk cli-table3 chalk
  1. Install TypeScript + CLI runner
npm install -D typescript ts-node @types/node
  1. Create a tsconfig.json
{
"compilerOptions": {
"target": "ES2020",
"module": "CommonJS",
"moduleResolution": "node",
"esModuleInterop": true,
"strict": true,
"resolveJsonModule": true,
"outDir": "dist"
},
"include": ["*.ts"]
}
  1. Create a .env file
MINATO_BUNDLER_URL="https://soneium-minato.bundler.scs.startale.com?apikey=YOUR_API_KEY"
PAYMASTER_SERVICE_URL="https://paymaster.scs.startale.com/v1?apikey=YOUR_API_KEY"
OWNER_PRIVATE_KEY="0xYourPrivateKey"
COUNTER_CONTRACT_ADDRESS="0xCounterContractAddress"
# Counter deployed on Minato: 0x6bcf154A6B80fDE9bd1556d39C9bCbB19B539Bd8

Write Your Script

Create a file called quickstart.ts with the following code:


1. Initialize Smart Account

Create Paymaster Client

Before creating the smart account client, initialize the SCS Paymaster Client:

// create API key here to obtain URLs: https://portal.scs.startale.com/api-keys
const scsPaymasterClient = createSCSPaymasterClient({
transport: http("<YOUR_PAYMASTER_URL_FROM_PORTAL>") as any,
});
const smartAccountClient = createSmartAccountClient({
account: await toStartaleSmartAccount({
signer: signer,
chain: chain,
transport: http(),
index: BigInt(2132) // Account index (salt)
}),
// create API key here to obtain URLs: https://portal.scs.startale.com/api-keys
transport: http("<YOUR_BUNDLER_URL_FROM_PORTAL>"), // from .env
client: publicClient,
paymaster: scsPaymasterClient,
paymasterContext: { calculateGasLimits: true, paymasterId: "<YOUR_PAYMASTER_ID_FROM_PORTAL>" }
});
info

If you do not wish to use a paymaster right now, you can simply comment out the paymaster and paymasterContext fields in the createSmartAccountClient arguments.

However, make sure your smart account has enough ETH to cover gas fees.

You can get the counterfactual address (before deployment) with:

const address = smartAccountClient.account.address;
console.log("address", address);

Send some ETH to this address before submitting the UserOperation.

You can check the tutorial on how to create a Paymaster, set up policies, and obtain a Paymaster ID in the Portal Setup Guide.

2. Prepare Contract Interaction

Let’s assume you’ve already deployed a Counter contract that has a count() method. Encode the call:

const callData = encodeFunctionData({
abi: CounterAbi,
functionName: "count",
});

3. Send a UserOperation

You can now submit a UserOperation to the bundler. Note: If the smart account hasn't been deployed yet, this step will deploy it automatically.

const hash = await smartAccountClient.sendUserOperation({
calls: [{
to: counterContract as Address,
value: BigInt(0),
data: callData,
}],
});

const receipt = await smartAccountClient.waitForUserOperationReceipt({ hash });
console.log("receipt", receipt);
  • calls: Specifies the target contract and the function to execute.

  • waitForUserOperationReceipt: Waits until the UserOp is confirmed on-chain.


Key Features

  • Gasless Transactions — Optional Paymaster support covers gas fees
  • Smart Account — No direct private key use for end-users
  • Bundler Integration — Handles mempool, simulation, and submission to EntryPoint

Run the Script

Make sure you have the necessary .env variables and dependencies set up:

1. Install Dependencies

npm install dotenv ora viem @startale-scs/aa-sdk cli-table3 chalk

2. Execute the Quickstart Script

Use ts-node to run your script:

npx ts-node quickstart.ts

Make sure your .env file includes:

MINATO_BUNDLER_URL="https://bundler.example.com"
PAYMASTER_SERVICE_URL="https://paymaster.example.com"
OWNER_PRIVATE_KEY="0xYourPrivateKey"
COUNTER_CONTRACT_ADDRESS="0xCounterContractAddress"