# Your First Gasless Smart Account Transaction

**Create a Smart Account and send gasless batched transactions in under 10 minutes.**

This guide walks you through creating your first smart account and sending multiple gasless transactions in a single UserOperation. Learn the core concepts of account abstraction while building a practical example that requires no ETH for gas fees.

#### What You'll Build[​](#what-youll-build "Direct link to What You'll Build")

By the end of this tutorial, you'll have:

* Created a smart contract wallet (smart account)
* Batched two NFT minting transactions into one operation
* Sent your first gasless UserOperation using a paymaster

#### What is a UserOperation?[​](#what-is-a-useroperation "Direct link to What is a UserOperation?")

A UserOperation is the mechanism smart accounts use to interact with Ethereum. Unlike regular transactions sent directly to the network, UserOperations offer:

* **Batching**: Group multiple transactions into a single atomic operation
* **Gas Flexibility**: Sponsor transactions or pay with any ERC-20 token
* **Programmability**: Include custom validation and execution logic

## Quickstart[​](#quickstart "Direct link to Quickstart")

[YouTube video player](https://www.youtube-nocookie.com/embed/t1ycwhN-Lvw?si=OMAiB7lK50XMkF68)

## Prerequisites[​](#prerequisites "Direct link to Prerequisites")

Before starting, make sure you have:

* **Node.js 18+** and npm/yarn
* **Basic TypeScript knowledge** - We'll explain the smart account concepts

Complete Example

You can also [fork the complete code](https://github.com/candidelabs/abstractionkit-examples/blob/main/sponsor-gas/sponsor-gas.ts) and follow along.

## Step 1: Project Setup[​](#step-1-project-setup "Direct link to Step 1: Project Setup")

#### Create Project Directory[​](#create-project-directory "Direct link to Create Project Directory")

```
mkdir candide-smart-account
cd candide-smart-account
npx tsc --init
```

#### Install Dependencies[​](#install-dependencies "Direct link to Install Dependencies")

```
npm install typescript --save-dev
npm install abstractionkit dotenv
```

**What each package does:**

* `abstractionkit` - Candide's SDK for smart account operations
* `dotenv` - Loads environment variables from .env file

#### Configure Environment Variables[​](#configure-environment-variables "Direct link to Configure Environment Variables")

Create a `.env` file in your project root:

.env

```
CHAIN_ID=11155111
BUNDLER_URL=https://api.candide.dev/public/v3/sepolia
JSON_RPC_NODE_PROVIDER=https://ethereum-sepolia-rpc.publicnode.com
PAYMASTER_URL=https://api.candide.dev/public/v3/sepolia
SPONSORSHIP_POLICY_ID= # optional

PRIVATE_KEY=YOUR_PRIVATE_KEY_HERE
PUBLIC_ADDRESS=YOUR_PUBLIC_ADDRESS_HERE
```

#### Create Main Script[​](#create-main-script "Direct link to Create Main Script")

Create an `index.ts` file:

index.ts

```
async function main(): Promise<void> {
  // We'll build our smart account logic here
}

main().catch(console.error);
```

## Step 2: Create Your Smart Account[​](#step-2-create-your-smart-account "Direct link to Step 2: Create Your Smart Account")

#### Understanding Smart Accounts[​](#understanding-smart-accounts "Direct link to Understanding Smart Accounts")

Smart accounts are smart contracts. Unlike regular wallets (EOAs), they can:

* Execute multiple transactions atomically
* Implement custom validation logic
* Support multiple signers or alternative signature schemes

This guide uses Safe's smart account implementation, which is battle-tested and widely adopted.

#### Generate Account Address[​](#generate-account-address "Direct link to Generate Account Address")

index.ts

```
import * as dotenv from "dotenv";
import { SafeAccountV0_3_0 as SafeAccount } from "abstractionkit";
  
async function main(): Promise<void> {
  // Load environment variables
  dotenv.config();

  const ownerPublicAddress = process.env.PUBLIC_ADDRESS as string;
  
  // Create a new smart account controlled by your EOA
  const smartAccount = SafeAccount.initializeNewAccount([ownerPublicAddress]);
  
  console.log("Smart Account Address:", smartAccount.accountAddress);
}

main().catch(console.error);
```

#### Test Your Setup[​](#test-your-setup "Direct link to Test Your Setup")

Run the code to generate your smart account address:

```
npx ts-node index.ts
```

**Expected output:**

```
Smart Account Address: 0x32afdcfa1e3bfe70d03ecb55b5c8045c26515c9d
```

How It Works

The `initializeNewAccount()` method deterministically computes your smart account address locally using only the provided inputs—no network calls required. The account contract is not deployed at this stage; deployment occurs automatically when you send your first transaction.

## Step 3: Prepare Your Transactions[​](#step-3-prepare-your-transactions "Direct link to Step 3: Prepare Your Transactions")

#### What We're Building[​](#what-were-building "Direct link to What We're Building")

We'll create two NFT minting transactions and batch them together, demonstrating smart accounts' ability to execute multiple operations atomically.

#### Understanding Transaction Data[​](#understanding-transaction-data "Direct link to Understanding Transaction Data")

Every transaction needs three things:

* `to`: The contract address to interact with
* `value`: ETH amount to send (0 for most contract calls)
* `data`: Encoded function call data

#### Build the Transactions[​](#build-the-transactions "Direct link to Build the Transactions")

Add this to your `index.ts` (after the account creation code):

index.ts

```
import {
  SafeAccountV0_3_0 as SafeAccount,
  MetaTransaction,
  getFunctionSelector,
  createCallData,
} from "abstractionkit";

// Inside your main() function, after creating smartAccount:

// NFT contract we'll interact with (a test contract on Sepolia)
const nftContractAddress = "0x9a7af758aE5d7B6aAE84fe4C5Ba67c041dFE5336";

// Prepare the function call data
const mintFunctionSignature = 'mint(address)';
const mintFunctionSelector = getFunctionSelector(mintFunctionSignature);
const mintTransactionCallData = createCallData(
  mintFunctionSelector, 
  ["address"], 
  [smartAccount.accountAddress] // Mint NFT to our smart account
);

// Create two identical transactions (we'll mint 2 NFTs)
const transaction1: MetaTransaction = {
  to: nftContractAddress,
  value: 0n, // No ETH needed for minting
  data: mintTransactionCallData, 
};

const transaction2: MetaTransaction = {
  to: nftContractAddress, 
  value: 0n,
  data: mintTransactionCallData,
};

console.log("Prepared 2 NFT minting transactions");
```

Why Batch Transactions?

Instead of sending two separate transactions, batch them into one UserOperation for a seamless one-click user experience.

## Step 4: Create UserOperation[​](#step-4-create-useroperation "Direct link to Step 4: Create UserOperation")

index.ts

```
const jsonRpcNodeProvider = process.env.JSON_RPC_NODE_PROVIDER as string;
const bundlerUrl = process.env.BUNDLER_URL as string;

// Create the UserOperation (batching both transactions)
let userOperation = await smartAccount.createUserOperation(
  [transaction1, transaction2], // Batch both NFT mints together
  jsonRpcNodeProvider, // Used for nonce and gas price data
  bundlerUrl // Used for gas limit estimation
);
```

## Step 5: Get Paymaster Data[​](#step-5-get-paymaster-data "Direct link to Step 5: Get Paymaster Data")

We'll use a paymaster to sponsor the gas fees, making this transaction completely gasless for the user.

index.ts

```
import {
  SafeAccountV0_3_0 as SafeAccount,
  MetaTransaction,
  getFunctionSelector,
  createCallData,
  CandidePaymaster,
} from "abstractionkit";

const paymasterUrl = process.env.PAYMASTER_URL as string;
const paymaster = new CandidePaymaster(paymasterUrl);
const sponsorshipPolicyId = process.env.SPONSORSHIP_POLICY_ID;

let [paymasterUserOperation, _sponsorMetadata] = await paymaster.createSponsorPaymasterUserOperation(
    userOperation, 
    bundlerUrl, 
    sponsorshipPolicyId // sponsorshipPolicyId will have no effect if empty
  ) 

userOperation = paymasterUserOperation;
```

## Step 6: Sign and Submit[​](#step-6-sign-and-submit "Direct link to Step 6: Sign and Submit")

#### Sign the UserOperation[​](#sign-the-useroperation "Direct link to Sign the UserOperation")

Your smart account needs to be authorized by your EOA. Add this signing code:

index.ts

```
const chainId = BigInt(process.env.CHAIN_ID as string);
const privateKey = process.env.PRIVATE_KEY as string;

// Sign the UserOperation with your private key
userOperation.signature = smartAccount.signUserOperation(
  userOperation,
  [privateKey], // Array because Safe supports multiple signers
  chainId,
);

console.log("UserOperation signed successfully");
```

#### Submit to Network[​](#submit-to-network "Direct link to Submit to Network")

Now send your UserOperation to the bundler:

index.ts

```
// Submit the UserOperation
const sendUserOperationResponse = await smartAccount.sendUserOperation(
  userOperation, 
  bundlerUrl
);

console.log("UserOperation submitted! Waiting for confirmation...");
```

#### Wait for Confirmation[​](#wait-for-confirmation "Direct link to Wait for Confirmation")

Track your UserOperation until it's included in a block:

index.ts

```
let userOperationReceiptResult = await sendUserOperationResponse.included()

console.log("UserOperation receipt received.")
console.log(userOperationReceiptResult)

if (userOperationReceiptResult.success) {
    console.log("Two NFTs were minted. The transaction hash is : " + userOperationReceiptResult.receipt.transactionHash)
} else {
    console.log("UserOperation execution failed")
}
```

#### Run Your Complete Code[​](#run-your-complete-code "Direct link to Run Your Complete Code")

Execute your smart account transaction:

```
npx ts-node index.ts
```

**Expected output:**

Example Receipt Result

```
Useroperation sent. Waiting to be included ......
Useroperation receipt received.
{
  userOpHash: '0x1acede61123ab7116eb29c797aeaec3c03615c37732ba66428524aebdb4b4514',
  entryPoint: '0x5FF137D4b0FDCD49DcA30c7CF57E578a026d2789',
  sender: '0xb8741a449d50ed0dcfe395287f85be152884c8d9',
  nonce: 0n,
  paymaster: '0x3fe285dcd76bcce4ac92d38a6f2f8e964041e020',
  actualGasCost: 8078496n,
  actualGasUsed: 504906n,
  success: true,
  logs: '[{"address":"0x5ff137d4b0fdcd49dca30c7cf57e578a026d2789","blockHash":"0xe19e52b4c222c1cdbc765f1a4e196ff4bf40c5550926e02974570e1845e88e2c","blockNumber":"0x9efe5f","data":"0x0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000007b44a0000000000000000000000000000000000000000000000000000000000007b44a","logIndex":"0x9a","removed":false,"topics":["0x49628fd1471006c1482da88028e9ce4dbb080b815c9b0344d39e5a8e6ec1419f","0x1acede61123ab7116eb29c797aeaec3c03615c37732ba66428524aebdb4b4514","0x000000000000000000000000b8741a449d50ed0dcfe395287f85be152884c8d9","0x0000000000000000000000003fe285dcd76bcce4ac92d38a6f2f8e964041e020"],"transactionHash":"0xf43576a07f39660737a342c99a187eb70ac59d89bc0df92ff3c1bb8a8da370aa","transactionIndex":"0x1d"}]',
  receipt: {
    blockHash: '0xe19e52b4c222c1cdbc765f1a4e196ff4bf40c5550926e02974570e1845e88e2c',
    blockNumber: 10419807n,
    from: '0x3cfdc212769c890907bce93d3d8c2c53de6a7a89',
    cumulativeGasUsed: 6978990n,
    gasUsed: 507053n,
    logs: '[{"address":"0xb8741a449d50ed0dcfe395287f85be152884c8d9","blockHash":"0xe19e52b4c222c1cdbc765f1a4e196ff4bf40c5550926e02974570e1845e88e2c","blockNumber":"0x9efe5f","data":"0x","logIndex":"0x90","removed":false,"topics":["0xecdf3a3effea5783a3c4c2140e677577666428d44ed9d474a0b3a4c9943f8440","0x000000000000000000000000a581c4a4db7175302464ff3c06380bc3270b4037"],"transactionHash":"0xf43576a07f39660737a342c99a187eb70ac59d89bc0df92ff3c1bb8a8da370aa","transactionIndex":"0x1d"},{"address":"0xb8741a449d50ed0dcfe395287f85be152884c8d9","blockHash":"0xe19e52b4c222c1cdbc765f1a4e196ff4bf40c5550926e02974570e1845e88e2c","blockNumber":"0x9efe5f","data":"0x000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000010000000000000000000000008ecd4ec46d4d2a6b64fe960b3d64e8b94b2234eb000000000000000000000000a581c4a4db7175302464ff3c06380bc3270b40370000000000000000000000000000000000000000000000000000000000000001000000000000000000000000bdbc5fbc9ca8c3f514d073ec3de840ac84fc6d31","logIndex":"0x91","removed":false,"topics":["0x141df868a6331af528e38c83b7aa03edc19be66e37ae67f9285bf4f8e3c6a1a8","0x0000000000000000000000004e1dcf7ad4e460cfd30791ccc4f9c8a4f820ec67"],"transactionHash":"0xf43576a07f39660737a342c99a187eb70ac59d89bc0df92ff3c1bb8a8da370aa","transactionIndex":"0x1d"},{"address":"0x4e1dcf7ad4e460cfd30791ccc4f9c8a4f820ec67","blockHash":"0xe19e52b4c222c1cdbc765f1a4e196ff4bf40c5550926e02974570e1845e88e2c","blockNumber":"0x9efe5f","data":"0x00000000000000000000000029fcb43b46531bca003ddc8fcb67ffe91900c762","logIndex":"0x92","removed":false,"topics":["0x4f51faf6c4561ff95f067657e43439f0f856d97c04d9ec9070a6199ad418e235","0x000000000000000000000000b8741a449d50ed0dcfe395287f85be152884c8d9"],"transactionHash":"0xf43576a07f39660737a342c99a187eb70ac59d89bc0df92ff3c1bb8a8da370aa","transactionIndex":"0x1d"},{"address":"0x5ff137d4b0fdcd49dca30c7cf57e578a026d2789","blockHash":"0xe19e52b4c222c1cdbc765f1a4e196ff4bf40c5550926e02974570e1845e88e2c","blockNumber":"0x9efe5f","data":"0x0000000000000000000000004e1dcf7ad4e460cfd30791ccc4f9c8a4f820ec670000000000000000000000003fe285dcd76bcce4ac92d38a6f2f8e964041e020","logIndex":"0x93","removed":false,"topics":["0xd51a9c61267aa6196961883ecf5ff2da6619c37dac0fa92122513fb32c032d2d","0x1acede61123ab7116eb29c797aeaec3c03615c37732ba66428524aebdb4b4514","0x000000000000000000000000b8741a449d50ed0dcfe395287f85be152884c8d9"],"transactionHash":"0xf43576a07f39660737a342c99a187eb70ac59d89bc0df92ff3c1bb8a8da370aa","transactionIndex":"0x1d"},{"address":"0x5ff137d4b0fdcd49dca30c7cf57e578a026d2789","blockHash":"0xe19e52b4c222c1cdbc765f1a4e196ff4bf40c5550926e02974570e1845e88e2c","blockNumber":"0x9efe5f","data":"0x","logIndex":"0x94","removed":false,"topics":["0xbb47ee3e183a558b1a2ff0874b079f3fc5478b7454eacf2bfc5af2ff5878f972"],"transactionHash":"0xf43576a07f39660737a342c99a187eb70ac59d89bc0df92ff3c1bb8a8da370aa","transactionIndex":"0x1d"},{"address":"0xb8741a449d50ed0dcfe395287f85be152884c8d9","blockHash":"0xe19e52b4c222c1cdbc765f1a4e196ff4bf40c5550926e02974570e1845e88e2c","blockNumber":"0x9efe5f","data":"0x000000000000000000000000a581c4a4db7175302464ff3c06380bc3270b403700000000000000000000000038869bf66a61cf6bdb996a6ae40d5853fd43b526000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a0000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000001048d80ff0a000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000b200d9de104e3386d9a45a61bce269c43e48b534e4e7000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000041249c58b00d9de104e3386d9a45a61bce269c43e48b534e4e7000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000041249c58b000000000000000000000000000000000000000000000000000000000000000000000000000000000000","logIndex":"0x95","removed":false,"topics":["0xb648d3644f584ed1c2232d53c46d87e693586486ad0d1175f8656013110b714e"],"transactionHash":"0xf43576a07f39660737a342c99a187eb70ac59d89bc0df92ff3c1bb8a8da370aa","transactionIndex":"0x1d"},{"address":"0xd9de104e3386d9a45a61bce269c43e48b534e4e7","blockHash":"0xe19e52b4c222c1cdbc765f1a4e196ff4bf40c5550926e02974570e1845e88e2c","blockNumber":"0x9efe5f","data":"0x","logIndex":"0x96","removed":false,"topics":["0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef","0x0000000000000000000000000000000000000000000000000000000000000000","0x000000000000000000000000b8741a449d50ed0dcfe395287f85be152884c8d9","0x0000000000000000000000000000000000000000000000000000000000000056"],"transactionHash":"0xf43576a07f39660737a342c99a187eb70ac59d89bc0df92ff3c1bb8a8da370aa","transactionIndex":"0x1d"},{"address":"0xd9de104e3386d9a45a61bce269c43e48b534e4e7","blockHash":"0xe19e52b4c222c1cdbc765f1a4e196ff4bf40c5550926e02974570e1845e88e2c","blockNumber":"0x9efe5f","data":"0x","logIndex":"0x97","removed":false,"topics":["0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef","0x0000000000000000000000000000000000000000000000000000000000000000","0x000000000000000000000000b8741a449d50ed0dcfe395287f85be152884c8d9","0x0000000000000000000000000000000000000000000000000000000000000057"],"transactionHash":"0xf43576a07f39660737a342c99a187eb70ac59d89bc0df92ff3c1bb8a8da370aa","transactionIndex":"0x1d"},{"address":"0xb8741a449d50ed0dcfe395287f85be152884c8d9","blockHash":"0xe19e52b4c222c1cdbc765f1a4e196ff4bf40c5550926e02974570e1845e88e2c","blockNumber":"0x9efe5f","data":"0x","logIndex":"0x98","removed":false,"topics":["0x6895c13664aa4f67288b25d7a21d7aaa34916e355fb9b6fae0a139a9085becb8","0x000000000000000000000000a581c4a4db7175302464ff3c06380bc3270b4037"],"transactionHash":"0xf43576a07f39660737a342c99a187eb70ac59d89bc0df92ff3c1bb8a8da370aa","transactionIndex":"0x1d"},{"address":"0x3fe285dcd76bcce4ac92d38a6f2f8e964041e020","blockHash":"0xe19e52b4c222c1cdbc765f1a4e196ff4bf40c5550926e02974570e1845e88e2c","blockNumber":"0x9efe5f","data":"0x0000000000000000000000000000000000000000000000000000000000000000","logIndex":"0x99","removed":false,"topics":["0xa050a122b4c0e369e3385eb6b7cccd8019638b2764de67bec0af99130ddf8471","0x1acede61123ab7116eb29c797aeaec3c03615c37732ba66428524aebdb4b4514","0x000000000000000000000000b8741a449d50ed0dcfe395287f85be152884c8d9","0x0000000000000000000000000000000000000000000000000000000000000000"],"transactionHash":"0xf43576a07f39660737a342c99a187eb70ac59d89bc0df92ff3c1bb8a8da370aa","transactionIndex":"0x1d"},{"address":"0x5ff137d4b0fdcd49dca30c7cf57e578a026d2789","blockHash":"0xe19e52b4c222c1cdbc765f1a4e196ff4bf40c5550926e02974570e1845e88e2c","blockNumber":"0x9efe5f","data":"0x0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000007b44a0000000000000000000000000000000000000000000000000000000000007b44a","logIndex":"0x9a","removed":false,"topics":["0x49628fd1471006c1482da88028e9ce4dbb080b815c9b0344d39e5a8e6ec1419f","0x1acede61123ab7116eb29c797aeaec3c03615c37732ba66428524aebdb4b4514","0x000000000000000000000000b8741a449d50ed0dcfe395287f85be152884c8d9","0x0000000000000000000000003fe285dcd76bcce4ac92d38a6f2f8e964041e020"],"transactionHash":"0xf43576a07f39660737a342c99a187eb70ac59d89bc0df92ff3c1bb8a8da370aa","transactionIndex":"0x1d"}]',
    logsBloom: '0x0000040000009000000000000000010080000000000000000000000000000000000800000000000000020001000004040010000000000000800002000000000000001000000000000000000c0002000000000000010000080040000000000000020000000a0000000500002000000800008000000100000000000014000000000800010020000200008000000040000000000200000400000000000000000000000004000000000000500000000004000210000000000000000002001000000020200082000000000001000008000000000000002060000000100000000026000000082000010000000000000008100220000000000000000000000010000200',
    transactionHash: '0xf43576a07f39660737a342c99a187eb70ac59d89bc0df92ff3c1bb8a8da370aa',
    transactionIndex: 29n,
    effectiveGasPrice: 16n
  }
}
Two Nfts were minted. The transaction hash is : 0xf43576a07f39660737a342c99a187eb70ac59d89bc0df92ff3c1bb8a8da370aa
```

🎉 **Congratulations!** You've successfully sent your first batched gasless smart account transaction.

## Full Example[​](#full-example "Direct link to Full Example")

Below is the complete example code that you can copy directly to implement the functionality described in the tutorial.

index.js

```
import * as dotenv from 'dotenv'

import { 
    SafeAccountV0_3_0 as SafeAccount,
    MetaTransaction,
    CandidePaymaster,
    getFunctionSelector,
    createCallData,
} from "abstractionkit";

async function main(): Promise<void> {
    //get values from .env
    dotenv.config()
    const chainId = BigInt(process.env.CHAIN_ID as string)
    const bundlerUrl = process.env.BUNDLER_URL as string
    const jsonRpcNodeProvider = process.env.JSON_RPC_NODE_PROVIDER as string
    const paymasterURL = process.env.PAYMASTER_URL as string
    const ownerPublicAddress = process.env.PUBLIC_ADDRESS as string
    const ownerPrivateKey = process.env.PRIVATE_KEY as string

    //initializeNewAccount only needed when the smart account
    //have not been deployed yet for its first useroperation.
    //You can store the accountAddress to use it to initialize 
    //the SafeAccount object for the following useroperations
    let smartAccount = SafeAccount.initializeNewAccount(
        [ownerPublicAddress],
    )

    //After the account contract is deployed, no need to call initializeNewAccount
    //let smartAccount = new SafeAccount(accountAddress)

    console.log("Account address(sender) : " + smartAccount.accountAddress)

    //create two meta transaction to mint two NFTs
    //you can use favorite method (like ethers.js) to construct the call data 
    const nftContractAddress = "0x9a7af758aE5d7B6aAE84fe4C5Ba67c041dFE5336";
    const mintFunctionSignature =  'mint(address)';
    const mintFunctionSelector =  getFunctionSelector(mintFunctionSignature);
    const mintTransactionCallData = createCallData(
        mintFunctionSelector, 
        ["address"],
        [smartAccount.accountAddress]
    );
    const transaction1 :MetaTransaction ={
        to: nftContractAddress,
        value: 0n,
        data: mintTransactionCallData,
    }

    const transaction2 :MetaTransaction ={
        to: nftContractAddress,
        value: 0n,
        data: mintTransactionCallData,
    }

    //createUserOperation will determine the nonce, fetch the gas prices,
    //estimate gas limits and return a useroperation to be signed.
    //you can override all these values using the overrides parameter.
    let userOperation = await smartAccount.createUserOperation(
		[
            //You can batch multiple transactions to be executed in one useroperation.
            transaction1, transaction2,
        ],
        jsonRpcNodeProvider, //the node rpc is used to fetch the current nonce and fetch gas prices.
        bundlerUrl, //the bundler rpc is used to estimate the gas limits.
	)

    // Get paymaster data to sponsor the transaction
    const paymasterUrl = process.env.PAYMASTER_URL as string;
    const paymaster: CandidePaymaster = new CandidePaymaster(paymasterUrl);
    const sponsorshipPolicyId = process.env.SPONSORSHIP_POLICY_ID;

    let [paymasterUserOperation, _sponsorMetadata] = await paymaster.createSponsorPaymasterUserOperation(
        userOperation, 
        bundlerUrl, 
        sponsorshipPolicyId // sponsorshipPolicyId will have no effect if empty
    ) 
    userOperation = paymasterUserOperation;
    
    console.log("Transaction will be sponsored - no ETH required!");
 
    //Safe is a multisig that can have multiple owners/signers
    //signUserOperation will create a signature for the provided
    //privateKeys
    userOperation.signature = smartAccount.signUserOperation(
		userOperation,
        [ownerPrivateKey],
        chainId
	)
    console.log(userOperation)

    //use the bundler rpc to send a userOperation
    //sendUserOperation will return a SendUseroperationResponse object
    //that can be awaited for the useroperation to be included onchain
    const sendUserOperationResponse = await smartAccount.sendUserOperation(
        userOperation, bundlerUrl
    )

    console.log("Useroperation sent. Waiting to be included ......")
    //included will return a UserOperationReceiptResult when 
    //useroperation is included onchain
    let userOperationReceiptResult = await sendUserOperationResponse.included()

    console.log("Useroperation receipt received.")
    console.log(userOperationReceiptResult)
    if(userOperationReceiptResult.success){
        console.log("Two Nfts were minted. The transaction hash is : " + userOperationReceiptResult.receipt.transactionHash)
    }else{
        console.log("Useroperation execution failed")
    }
}

main()
```

## Troubleshooting[​](#troubleshooting "Direct link to Troubleshooting")

**"Insufficient funds" error**

* Make sure your smart account address has enough Sepolia ETH, or are using a paymaster to sponsor gas fees

**"Invalid signature" error**

* Verify your `PRIVATE_KEY` matches your `PUBLIC_ADDRESS`
* Ensure you're using the correct chain ID

**Network/timeout errors**

* Try a different node endpoint if the current one is down
* Check your internet connection

#### Getting Help[​](#getting-help "Direct link to Getting Help")

If you're still stuck:

* Ask questions in abstractionkit's [GitHub Discussions](https://github.com/candidelabs/abstractionkit/discussions)
* Join our [Discord](https://discord.gg/7R4g9XcxDQ)
* Check the [complete example code](https://github.com/candidelabs/abstractionkit-examples/blob/main/batch-transactions/batch-transactions.ts)

You can view your transaction on block explorers that support UserOperations like [Blockscout](https://www.blockscout.com/).

## What's Next?[​](#whats-next "Direct link to What's Next?")

Now that you've mastered the basics, explore more advanced smart account features:

#### Recommended Next Steps[​](#recommended-next-steps "Direct link to Recommended Next Steps")

1. **[Pay Gas in ERC-20](https://docs.candide.dev/wallet/guides/pay-gas-in-erc20.md)** - Let users pay fees with USDC or other tokens
2. **[Passkeys](https://docs.candide.dev/wallet/plugins/passkeys.md)** - Let users secure their account with biometrics login
3. **[Enable Account Recovery](https://docs.candide.dev/wallet/plugins/recovery-with-guardians.md)** - Let users add recovery methods through guardians or traditional sms/email
