Shib Paymasters
Shib Paymasters provide two different types of paymasters to help abstract away gas fees for users in the Shibarium ecosystem using the ERC-4337 standard. These paymasters allow for more flexibility in how gas fees are handled, either by sponsoring them on behalf of users or by letting users pay using ERC-20 tokens.
Types of Shib Paymasters
- Verifying Paymaster
- ERC-20 Paymaster
Verifying Paymaster
The Shib Verifying Paymaster is a system that allows you to sponsor gas fees for your users on Shibarium. By utilizing an off-chain API and an on-chain smart contract, this paymaster lets users perform actions on-chain without needing to worry about gas fees. Here's how it works:
- Developers who wish to use our Paymaster-as-a-service feature go to the Developer Portal and acquire an API key.
- They will then append their API key to the Paymaster URL, which will be required during the integration through the Account Abstraction SDK.
- Users, when interacting with an app integrated with Shib’s account-abstraction SDK, can generate on-chain operations. This SDK can submit these operations behind the scenes.
- The paymaster works by receiving an API call from SDK where a signature is generated and returned to the caller.
- This signature is used by the on-chain smart contract to verify that the gas fees for the user operation should be sponsored.
- The gas fees are paid from funds added by the developers who built the application into the paymaster smart contract.
ERC-20 Paymaster
The Shib ERC-20 Paymaster is a permissionless, on-chain smart contract that allows your users to pay for gas fees using their ERC-20 tokens. This provides flexibility by enabling users to cover gas costs with a wide variety of tokens, such as USDC, rather than native tokens like ETH.
How it works:
- Users perform operations on-chain and can use their ERC-20 tokens to pay for gas fees.
- Developers register on the Developer Portal, create an ERC-20 paymaster and integrate it in their transactions, via Shib's Account Abstraction sdk. The Shib ERC-20 Paymaster contracts will be deployed on Shibarium for a specific ERC-20 token, allowing users to pay gas in ERC-20 tokens seamlessly.
- This ERC-20 Paymaster contract will have an owner address, ERC-20 token address and oracles that fetch the latest price of ERC-20 token and native asset.
Usage
Using the Account abstraction SDK, you can create an instance of the Shib4337 class and call its methods.
const shibAAservice = Shib4337.init({
signer,
options,
paymasterOptions
});
signer: An optional signer object for transaction signing.options: Configuration options for the wallet.owners: An array of owner addresses for the smart contract wallet.threshold: The number of required signatures for executing transactions.saltNonce: A nonce value to ensure unique wallet addresses.
paymasterOptions: Configuration options for the Paymaster service, as seen below.
Paymaster Options
To use Paymaster-as-a-service, you need to provide the configuration for the paymaster in the options object. The options in the paymasterOptions object should have the following properties:
| Property | Description |
|---|---|
| paymasterUrl | The URL of the paymaster service. This will probably have this format https://paymaster.shib.io/shibarium/<api-key>, where the API key is acquired from the developer portal. |
| isSponsored | A boolean value to determine if the transactions are sponsored. |
| sponsorshipPolicyId | The sponsorship policy ID for the paymaster. |
| paymasterAddress | The address of the paymaster contract. |
| paymasterTokenAddress | The address of the token used by the ERC20 paymaster. |
| amountToApprove | The amount to approve for the ERC20 paymaster. |
Creating transactions
Use the createTransaction method to prepare transactions for execution. You can add multiple transactions to a queue and then create a single user operation (userOp).
Here is how you can add transactions to the queue, where transactionObj is an object representing the transaction details:
await shibAAservice.addTransaction(transactionObj);
The transactionObj has the following keys and values:
| Key | Value |
|---|---|
to | The destination address. |
value | The amount of Ether to send (in wei). |
data | The transaction data (e.g., encoded function call). |
operation | The operation type (0 for call, 1 for delegate call). |
Creating the User Operation
To create a user operation, you need to provide the settings:
const userOp = await shibAAservice.createTransaction({
transactions: [],
options: paymasterOptions
});
where:
transactionsis an array of transactions or leave empty to use the queued transactions.- and
optionsrepresents the paymaster options which are specific to this transaction. It will change as per the type of Paymaster you want to integrate
The options object should have the following properties:
| Property | Required | Description |
|---|---|---|
| type | YES | The Paymaster type (see below). |
| paymasterAndData | For CustomPaymaster, a string specifying custom Paymaster data. | |
| amountToApprove | Amount of tokens to approve for the ERC-20 Paymaster. | |
| validUntil | Expiry time for the Paymaster (timestamp). | |
| validAfter | Start time for the Paymaster (timestamp). | |
| feeEstimator | A function or value to estimate fees for the Paymaster. |
The first property is used to specify the type of Paymaster to use. The SDK supports several Paymaster types, each with different requirements. In most of the times, our requirement is fulfilled by VerifyingPaymaster(type 2) and ERC20Paymaster(type 3) based on our Paymaster-as-a-service portal. The other types are also present to let users choose how they want to integrate the Paymaster.
| Type | Number | Description |
|---|---|---|
| NoPaymaster (Default) | 0 | No Paymaster is used; standard transaction fees apply. |
| PaymasterContract | 1 | Uses an on-chain Paymaster contract. Requires paymasterAddress. |
| VerifyingPaymaster | 2 | Uses a sponsored off-chain Paymaster service. Requires paymasterUrl. |
| ERC20Paymaster | 3 | Uses an on-chain ERC-20 Paymaster. Requires paymasterAddress and paymasterTokenAddress. |
| OffchainPaymaster | 4 | Uses a non-sponsored off-chain Paymaster service. Requires paymasterUrl and paymasterTokenAddress. |
| CustomPaymaster | 5 | Allows custom Paymaster configurations. Requires paymasterAndData. |
Examples
Here is an example for sponsored paymaster:
///
/// For sponsored paymaster
///
import { Shib4337 } from 'shib-account-abstraction-sdk';
import { ethers } from 'ethers';
// creating `signer` for Shib4337 service, you can use ethers.js or any other library to create ethers-signers
// providing the signer to Shib4337 init is optional but it is required for the methods that require executing transactions
// Replace PRIVATE_KEY with your private key
const provider = new ethers.JsonRpcProvider('https://puppynet.shibrpc.com');
const signer = new ethers.Wallet(PRIVATE_KEY, provider);
const paymasterUrl = 'https://offchainpaymaster.shibinternal.com/';
// initializing the Shib4337 service to interact with the Account Abstraction service
const shibAAservice = Shib4337.init({
signer,
options: {
owners: [signer.address],
threshold: 1,
saltNonce: '0'
},
paymasterOptions: {
paymasterUrl: paymasterUrl,
isSponsored: true,
sponsorshipPolicyId: ''
}
})
// calling the methods on the Shib4337 service
// determining the safe smart contract address of user
const address = await shibAAservice.getWalletAddress()
// the trxn should be in this format, it can be for anything like transfer, approve, createIdentity, sns etc.
const transactionObj = {
to: destinationAddress,
value: etherValue,
data: transactionData,
operation: operationType // 0 for call, 1 for delegate call
}
// adding trxn to the queue, it can be called multiple times to add multiple trxns to the queue separately
const res = await shibAAservice.addTransaction(transaction1)
// getting the trxn queue
const res = await shibAAservice.getTransactions()
// create options for sponsored paymaster
const sponsoredPaymasterOptions = {
type: 2
}
// creating the trxn operation, it is repsonsible for batching added trxns together and creating userOp
const userOp = await shibAAservice.createTransaction({
transactions:[],
options: sponsoredPaymasterOptions
});
// executing the trxn
const executeRespopnse = await shibAAservice.executeTransaction({
userOp,
signer
});
const userOpHash = executeRespopnse.userOpHash;
const receipt = await executeRespopnse.wait();
console.log({receipt});
// getting the trxn status
const res = await shibAAservice.getUserOpsByHash(userOpHash);
console.log(`Find the transaction on explorer at: https://puppynet.shib.io/tx/${res.transactionHash}`);
Here is an example for non-sponsored paymaster:
///
/// For non-sponsored paymaster
///
import { Shib4337 } from 'shib-account-abstraction-sdk';
import { ethers } from 'ethers';
// creating `signer` for Shib4337 service, you can use ethers.js or any other library to create ethers-signers
// providing the signer to Shib4337 init is optional but it is required for the methods that require executing transactions
// Replace PRIVATE_KEY with your private key
const provider = new ethers.JsonRpcProvider('https://puppynet.shibrpc.com');
const signer = new ethers.Wallet(PRIVATE_KEY, provider);
const paymasterTokenAddress = "0x2258900dE1261D70D6D1643B190f3111aC056bD1"
const paymasterAddress = "0x72717b4f7d7af24739992C9B1D22BAf2203E618c"
// initializing the Shib4337 service to interact with the Account Abstraction service
const shibAAservice = Shib4337.init({
signer,
options: {
owners: [signer.address],
threshold: 1,
saltNonce: '0'
},
paymasterOptions: {
paymasterAddress: paymasterAddress,
paymasterTokenAddress: paymasterTokenAddress,
isSponsored: false
}
})
// calling the methods on the Shib4337 service
// determining the safe smart contract address of user
const address = await shibAAservice.getWalletAddress()
// the trxn should be in this format, it can be for anything like transfer, approve, createIdentity, sns etc.
const transactionObj = {
to: destinationAddress,
value: etherValue,
data: transactionData,
operation: operationType // 0 for call, 1 for delegate call
}
// adding trxn to the queue, it can be called multiple times to add multiple trxns to the queue separately
const res = await shibAAservice.addTransaction(transaction1)
// getting the trxn queue
const res = await shibAAservice.getTransactions()
// create options for non-sponsored paymaster
const erc20paymasterOptions = {
type: 3,
amountToApprove: 0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffn
}
// creating the trxn operation, it is repsonsible for batching added trxns together and creating userOp
const userOp = await shibAAservice.createTransaction({
transactions:[],
options: erc20paymasterOptions
});
// executing the trxn
const executeRespopnse = await shibAAservice.executeTransaction({
userOp,
signer
});
const userOpHash = executeRespopnse.userOpHash;
const receipt = await executeRespopnse.wait();
console.log({receipt});
// getting the trxn status
const res = await shibAAservice.getUserOpsByHash(userOpHash);
console.log(`Find the transaction on explorer at: https://puppynet.shib.io/tx/${res.transactionHash}`);