Feb 17, 2025
In this post, we’ll talk about how to deploy and test our custom paymaster contract (from our previous post) and our paymaster service on Base Sepolia, the testnet for Base.
By the end of this post, we’ll have 1) a deployed paymaster smart contract, 2) a compatible off-chain paymaster service, and 3) modify our MassPay code so we can send user operations specifying our own custom paymaster.
If you'd like to follow along, you can reference the code from our i) paymaster service and ii) masspay repositories.
Overview
On a high level, we are taking the verifying paymaster from our mock-aa-environment and modifying it for testnet. When deployed, it should be a publicly reachable service capable of handling at least two JSON-RPC calls, pm_getPaymasterStubData
and pm_getPaymasterData
, which are required from the ERC4337 specifications.
The idea is to have a Paymaster Service to sign the desired user operation using a signature scheme recognized by the paymaster smart contract. The service returns this signature along with a specified paymaster contract address, which is later used by the EntryPoint to validate against the specified deployed paymaster contract. For simplicity’s sake, we are using an “Approve all” contract, which does not check for any signature and will sponsor any user operations sent to it.
Compile your custom paymaster contract
First let’s deploy our custom paymaster smart contract on Base Sepolia. In your project root directory, run:
These two commands will first compile our paymaster contract from source and copy back the contract ABI and bytecode into the contracts/abi
sub-directory.
Deploy your custom paymaster contract
We set our target chain to Base Sepolia (see getChain
in src/helpers/utils.ts
). We also see that the private key from our environment variable is used to return a wallet client for Base Sepolia.

You can set up these environment variables in your .env
file. You can use a RPC_URL
from public services or use your own (e.g. Infura, Alchemy, etc.). The BUNDLER_URL
should be using Pimlico's API Key. The PRIVATE_KEY
is the private key of your wallet that will be used to deploy and fund the paymaster contract.

To go further, you’d need a wallet which has some ETH on Base Sepolia. If you need some testnet ETH on Base Sepolia, reach out to us on our Telegram. Alternatively, you can find it from either Alchemy or Coinbase Developer Platform testnet faucets.
Setup RPC endpoint routes
We can see in the setupHandler
function in src/routes/index.ts
that the wallet client is being used to i) deploy and ii) fund our paymaster, by calling deploySbcPaymasterV07
and fundSbcPaymasterV07
functions respectively.
The deploy function will deploy the paymaster contract deterministically to the same address if there is no code found in that pre-calculated address (using the CREATE2
opcode). The fund function will look to fund 0.01 ETH to the EntryPoint on behalf of our custom paymaster, if it has less than that amount.
Note that your contract address will change if you change its source code or the
SALT
variable (a Hex string of length is 66, including its0x
prefix). Once you’ve run the app locally, you need to replace theSBC_PAYMASTER_V07_Address
constant so the rest of the code uses the correct address.
The rest of the setup function uses Pimlico’s Bundler (using their API key from their dashboard), and sets up the necessary endpoints and returns the routes
necessary to register as a Fastify plugin and used by the main code.

Running and testing locally
To test this locally, you can run the start
npm script. By default, you can access it on http://0.0.0.0:3000. You can specify another port by using the PORT
environment variable, too.

Deploying Paymaster Service to Vercel
We’ve chosen Vercel to deploy our paymaster service. Because Vercel is a serverless platform, and Fastify is plugin-centric, we can simply register our application routes
as a plugin and have a special handler file api/serverless.js
to emit requests to it.
We need to tell Vercel where to send requests, hence we create a vercel.json
file like this:
Now we can deploy the app normally by pushing (or merging) changes to the main
branch.
Modifying MassPay to use our custom paymaster
Now that we have our paymaster contract and service deployed, we can use it to sponsor user operations. Let’s revisit MassPay, our utility to send SBC to multiple recipient addresses at once. To follow along, checkout the testnet
branch from our MassPay repository.
We’ll first set up a new environment variable NEXT_PUBLIC_PAYMASTER_SERVICE_URL
to point to our custom paymaster service’s deployed URL. If you’re running locally, it’s just http://localhost:3000/v1/rpc
.
The only key function that requires changes is the prepareMassPay
function. Instead of using Pimlico’s paymaster, we replace it with our own, and pass it into our createSmartAccountClient
function:

That’s it. Easy-peasy.
You’re now able to run the same MassPay tool with your custom paymaster, “live” on Base Sepolia testnet.
Next steps
If you have thoughts, or improvements, or would like to contribute to the project, please let us know via Telegram.