Wallets API Quickstart
This guide outlines exactly what you need to use Wallet Server with your app! We’ll go over the wallet_requestAccount
, wallet_createSession
, wallet_prepareCalls
, and wallet_sendPreparedCalls
endpoints in this tutorial.
The logical flow is to get an account for a given signer, create a session for use with that account, prepare the calls you’re looking to send, and send them! If you’re looking for a typescript SDK guide, you’ll find that here too.
Session keys are useful if you are looking to grant your app’s server partial, secure access to user’s wallets so that the server can sign and send transactions on a user’s behalf within certain permissions.
In API calls, it’s as simple as:
If instead, you don’t want to use session keys and you want the user to sign all of the transactions, you can simply skip the createSession step and use the client side signer to sign prepared calls.
This guide assumes you have an account you can sign with, like an Alchemy Signer. You will also need an Alchemy API key and a gas manager policy ID.
Don't have an API key?
Start using the Alchemy Wallets API today! Get started for free
Using The Account Kit SDK
Install Prerequisities
You’re going to need the @account-kit/wallet-client
, @account-kit/infra
, and optionally @aa-sdk/core
if you use a LocalAccountSigner
.
Create A Smart Account Client
Given a signer (e.g. a LocalAccountSigner
imported from @aa-sdk/core
or an Alchemy Signer), all you need to do is follow a few simple steps to start sending user ops with Wallet APIs!
Request The Account
A counterfactual address is the account address associated with the given signer— but the account contract hasn’t been deployed yet.
Sign A Message
Sign Typed Data
Send A UserOp
Create A Session With Permissions
Session keys allow another account to operate on a user’s smart account with given permissions. See here for a list of permissions!
Using The JSON-RPC APIs Directly
1. Request an Account for the Owner Signer
Given an owner address, call wallet_requestAccount
to return the smart account address for that owner. The owner address can be any signer (or public key) that has the ability to sign transactions.
- If you want to use social sign up / log in, you can simply use the SDK to authenticate user’s and retrieve their signer address
- If instead, you want to generate and control wallets with a custodied owner, you can generate any public private key pair (e.g. any EOA)
This will return the account address associated with the given signer, as well as a uuid you could use to differentiate between accounts for the same signer in the future.
This will return the smart account address associated with the given signer:
2. Create a Session With the Session Key Signer
Session keys are useful if you are looking to define on-chain policies or grant your app’s server partial, secure access to user’s wallets so that the server can sign and send transactions on a user’s behalf within certain permissions. If you don’t want to use session keys for server side signing, you can skip to step 4.
After creating a session, you will be able to sign transactions for the generated wallet within the defined permissioned using that session key.
To create a session key using onchain policies:
- Get the public address of a key you want to use as a session key. This can be any key pair that has the ability to sign (aka a signer that is either an local signer like an EOA or signer generated with a signer provider)
- Create a session for that key using your session key public address - here passed in
publicKey
callwallet_createSession
.
Note that the expiry is in seconds and represents a UNIX timestamp. (E.g. 1776657600 for April 20th, 2077)
This will return two key elements:
- The session ID
- The signature request you’ve got to sign to authorize the session key
Keep note of the session ID, you’ll need it later!
3. Sign the Session Key Authorization
Sign the signature request from the owner key (used in step 1), then store the resulting signature.
4. Prepare Calls With the Session Key
With the session ID received in step 2 and the signature from step 3, we’re now ready to prepare some calls!
If you aren’t using a session key, you can omit the “permissions” parameter in the capabilities object.
This will return the userop request (the data
field) and a signature request, for example:
5. Sign the userop
With the returned signature request, all you have to do is sign the userop hash returned in the signatureRequest.data.raw
field from step 4.
- If not using session keys, you’ll sign this with the owner of the account (from step 1). You can learn how to stamp the request on the frontend here.
- If using session keys, you can sign this with the session key that was added in step 2 and 3. This signature will be valid as long as it is within the permissions the session key has.
Note that the type
field in the signatureRequest
indicates the signature type needed, in this case, we need to personal_sign
the hash.
6. Send the Prepared Calls!
With the signature from step 5 and the useropRequest
from step 4, you’re good to go to send the call!
If you are signing with the owner of the account and not a session key, you can omit the entire capabilities object.
This will return the array of prepared call IDs! These are concatenations of the chainID padded to 32 bytes and the userOp Hash.
Permission Types
To set specific permissions on a session key installation, add an object to the permissions array when calling client.grantPermission()
via the SDK or when calling wallet_createSession
via APIs directly.
Native Token Transfer
This permission allows transfer of native tokens (like Ether) from the account.
ERC20 Token Transfer
This permission allows transfer or approval of erc20 tokens from the account. Both transfers and approvals count towards the limit.
Gas Limit
This permission allows the session key to spend gas for user operations up to a specified limit.
Contract Access
This permission grants access to all functions in a specific contract.
Account Functions
This permission grants access to specific functions on the smart account itself.
Functions On All Contracts
This permission grants access to a set of function selectors across any address.
Functions On Contract
This permission grants access to specific function selectors on one contract.
Root
This permission grants full access to everything. Needless to say, this is a very dangerous permission to grant.