Server wallets

Server wallets are in early access and we’d love to hear how you’re using them! Contact us at [email protected] or through your Slack channel if you’re interested in using this feature- we’d love to help you get up and running.

Server wallets can be programmatically controlled using access keys. This enables backend applications to sign transactions and messages on behalf of users without requiring interactive authentication.

Prerequisites

Get your API key by creating a new app in your Alchemy Dashboard. Make sure your desired network is enabled for your app under the Networks tab.

Step 1: Generate an Access Key

Generate a secure access key for authentication. This key will never be sent to our servers - we’ll derive a public key from it when interacting with Alchemy.

Critical: Save your access key securely!

This access key is required to control your server wallet and cannot be recovered if lost. Make sure to store it in a secure location.

import { 
import generateAccessKey
generateAccessKey
} from "@account-kit/signer";
// Generate a random access key const
const accessKey: any
accessKey
=
import generateAccessKey
generateAccessKey
();
var console: Console

The console module provides a simple debugging console that is similar to the JavaScript console mechanism provided by web browsers.

The module exports two specific components:

  • A Console class with methods such as console.log(), console.error() and console.warn() that can be used to write to any Node.js stream. * A global console instance configured to write to process.stdout and process.stderr. The global console can be used without importing the node:console module.

Warning: The global console object's methods are neither consistently synchronous like the browser APIs they resemble, nor are they consistently asynchronous like all other Node.js streams. See the note on process I/O for more information.

Example using the global console:


const name = 'Will Robinson'; console.warn(`Danger $name! Danger!`); // Prints: Danger Will Robinson! Danger!, to stderr ```

Example using the `Console` class:

```js const out = getStreamSomehow(); const err = getStreamSomehow(); const myConsole = new console.Console(out, err);

myConsole.log('hello world'); // Prints: hello world, to out myConsole.log('hello %s', 'world'); // Prints: hello world, to out myConsole.error(new Error('Whoops, something bad happened')); // Prints: [Error: Whoops, something bad happened], to err

const name = 'Will Robinson'; myConsole.warn(`Danger $name! Danger!`); // Prints: Danger Will Robinson! Danger!, to err ```
console
.
Console.log(message?: any, ...optionalParams: any[]): void (+2 overloads)

Prints to stdout with newline. Multiple arguments can be passed, with the first used as the primary message and all additional used as substitution values similar to printf(3) (the arguments are all passed to util.format()).

js const count = 5; console.log('count: %d', count); // Prints: count: 5, to stdout console.log('count:', count); // Prints: count: 5, to stdout

See util.format() for more information.

log
("Access key:",
const accessKey: any
accessKey
);
// Store this securely - you'll need it to control the server signer

Step 2: Create the Server Signer

Before we can send transactions we need a way to sign them. Let’s create a server signer using the access key you just created to handle this:

import { 
import createServerSigner
createServerSigner
} from "@account-kit/signer";
const
const signer: any
signer
= await
import createServerSigner
createServerSigner
({
auth: { accessKey: string; }
auth
: {
accessKey: string
accessKey
: "your-access-key-here",
},
connection: { apiKey: string; }
connection
: {
apiKey: string
apiKey
: "your-alchemy-api-key",
}, });
var console: Console

The console module provides a simple debugging console that is similar to the JavaScript console mechanism provided by web browsers.

The module exports two specific components:

  • A Console class with methods such as console.log(), console.error() and console.warn() that can be used to write to any Node.js stream. * A global console instance configured to write to process.stdout and process.stderr. The global console can be used without importing the node:console module.

Warning: The global console object's methods are neither consistently synchronous like the browser APIs they resemble, nor are they consistently asynchronous like all other Node.js streams. See the note on process I/O for more information.

Example using the global console:


const name = 'Will Robinson'; console.warn(`Danger $name! Danger!`); // Prints: Danger Will Robinson! Danger!, to stderr ```

Example using the `Console` class:

```js const out = getStreamSomehow(); const err = getStreamSomehow(); const myConsole = new console.Console(out, err);

myConsole.log('hello world'); // Prints: hello world, to out myConsole.log('hello %s', 'world'); // Prints: hello world, to out myConsole.error(new Error('Whoops, something bad happened')); // Prints: [Error: Whoops, something bad happened], to err

const name = 'Will Robinson'; myConsole.warn(`Danger $name! Danger!`); // Prints: Danger Will Robinson! Danger!, to err ```
console
.
Console.log(message?: any, ...optionalParams: any[]): void (+2 overloads)

Prints to stdout with newline. Multiple arguments can be passed, with the first used as the primary message and all additional used as substitution values similar to printf(3) (the arguments are all passed to util.format()).

js const count = 5; console.log('count: %d', count); // Prints: count: 5, to stdout console.log('count:', count); // Prints: count: 5, to stdout

See util.format() for more information.

log
("Signer address:", await
const signer: any
signer
.
any
getAddress
());

Want to use the same access key to control multiple server signers? Check out the example below to learn how to use auth.accountId to create multiple signers that you can control with the same access key.

import { 
import createServerSigner
createServerSigner
} from "@account-kit/signer";
const
const businessSigner: any
businessSigner
= await
import createServerSigner
createServerSigner
({
auth: { accessKey: string; accountId: string; }
auth
: {
accessKey: string
accessKey
: "your-access-key-here",
accountId: string
accountId
: "business",
},
connection: { apiKey: string; }
connection
: {
apiKey: string
apiKey
: "your-alchemy-api-key",
}, }); const
const personalSigner: any
personalSigner
= await
import createServerSigner
createServerSigner
({
auth: { accessKey: string; accountId: string; }
auth
: {
accessKey: string
accessKey
: "your-access-key-here", // same access key
accountId: string
accountId
: "personal", // different account ID
},
connection: { apiKey: string; }
connection
: {
apiKey: string
apiKey
: "your-alchemy-api-key",
}, }); // These will have different addresses despite using the same access key
var console: Console

The console module provides a simple debugging console that is similar to the JavaScript console mechanism provided by web browsers.

The module exports two specific components:

  • A Console class with methods such as console.log(), console.error() and console.warn() that can be used to write to any Node.js stream. * A global console instance configured to write to process.stdout and process.stderr. The global console can be used without importing the node:console module.

Warning: The global console object's methods are neither consistently synchronous like the browser APIs they resemble, nor are they consistently asynchronous like all other Node.js streams. See the note on process I/O for more information.

Example using the global console:


const name = 'Will Robinson'; console.warn(`Danger $name! Danger!`); // Prints: Danger Will Robinson! Danger!, to stderr ```

Example using the `Console` class:

```js const out = getStreamSomehow(); const err = getStreamSomehow(); const myConsole = new console.Console(out, err);

myConsole.log('hello world'); // Prints: hello world, to out myConsole.log('hello %s', 'world'); // Prints: hello world, to out myConsole.error(new Error('Whoops, something bad happened')); // Prints: [Error: Whoops, something bad happened], to err

const name = 'Will Robinson'; myConsole.warn(`Danger $name! Danger!`); // Prints: Danger Will Robinson! Danger!, to err ```
console
.
Console.log(message?: any, ...optionalParams: any[]): void (+2 overloads)

Prints to stdout with newline. Multiple arguments can be passed, with the first used as the primary message and all additional used as substitution values similar to printf(3) (the arguments are all passed to util.format()).

js const count = 5; console.log('count: %d', count); // Prints: count: 5, to stdout console.log('count:', count); // Prints: count: 5, to stdout

See util.format() for more information.

log
("Business address:", await
const businessSigner: any
businessSigner
.
any
getAddress
());
var console: Console

The console module provides a simple debugging console that is similar to the JavaScript console mechanism provided by web browsers.

The module exports two specific components:

  • A Console class with methods such as console.log(), console.error() and console.warn() that can be used to write to any Node.js stream. * A global console instance configured to write to process.stdout and process.stderr. The global console can be used without importing the node:console module.

Warning: The global console object's methods are neither consistently synchronous like the browser APIs they resemble, nor are they consistently asynchronous like all other Node.js streams. See the note on process I/O for more information.

Example using the global console:


const name = 'Will Robinson'; console.warn(`Danger $name! Danger!`); // Prints: Danger Will Robinson! Danger!, to stderr ```

Example using the `Console` class:

```js const out = getStreamSomehow(); const err = getStreamSomehow(); const myConsole = new console.Console(out, err);

myConsole.log('hello world'); // Prints: hello world, to out myConsole.log('hello %s', 'world'); // Prints: hello world, to out myConsole.error(new Error('Whoops, something bad happened')); // Prints: [Error: Whoops, something bad happened], to err

const name = 'Will Robinson'; myConsole.warn(`Danger $name! Danger!`); // Prints: Danger Will Robinson! Danger!, to err ```
console
.
Console.log(message?: any, ...optionalParams: any[]): void (+2 overloads)

Prints to stdout with newline. Multiple arguments can be passed, with the first used as the primary message and all additional used as substitution values similar to printf(3) (the arguments are all passed to util.format()).

js const count = 5; console.log('count: %d', count); // Prints: count: 5, to stdout console.log('count:', count); // Prints: count: 5, to stdout

See util.format() for more information.

log
("Personal address:", await
const personalSigner: any
personalSigner
.
any
getAddress
());

Step 3: Send a Transaction

We can now send transactions using the Smart Account Client:

import { 
function createSmartWalletClient<TAccount extends Address | undefined = undefined>(params: SmartWalletClientParams<TAccount>): SmartWalletClient<TAccount>

Creates a smart wallet client that can be used to interact with a smart account.

createSmartWalletClient
} from "@account-kit/wallet-client";
import {
function alchemy(config: AlchemyTransportConfig): AlchemyTransport

Creates an Alchemy transport with the specified configuration options. When sending all traffic to Alchemy, you must pass in one of rpcUrl, apiKey, or jwt. If you want to send Bundler and Paymaster traffic to Alchemy and Node traffic to a different RPC, you must pass in alchemyConnection and nodeRpcUrl.

alchemy
,
const baseSepolia: Chain
baseSepolia
} from "@account-kit/infra";
// Create Smart Account Client using the signer from Step 2 const
const client: SmartWalletClient<undefined>
client
=
createSmartWalletClient<undefined>(params: SmartWalletClientParams<undefined>): SmartWalletClient<undefined>

Creates a smart wallet client that can be used to interact with a smart account.

createSmartWalletClient
({
transport: AlchemyTransport
transport
:
function alchemy(config: AlchemyTransportConfig): AlchemyTransport

Creates an Alchemy transport with the specified configuration options. When sending all traffic to Alchemy, you must pass in one of rpcUrl, apiKey, or jwt. If you want to send Bundler and Paymaster traffic to Alchemy and Node traffic to a different RPC, you must pass in alchemyConnection and nodeRpcUrl.

alchemy
({
apiKey: string
apiKey
: "your-alchemy-api-key",
}),
chain: Chain
chain
:
const baseSepolia: Chain
baseSepolia
,
signer: SmartAccountSigner<any>
signer
,
policyId?: string | undefined
policyId
: "your-sponsor-gas-policy-id", // Make sure enabled on Base Sepolia
}); // Retrieve account const
const account: RequestAccountResult
account
= await
const client: SmartWalletClient<undefined>
client
.
requestAccount: (params?: RequestAccountParams) => Promise<RequestAccountResult>
requestAccount
();
var console: Console

The console module provides a simple debugging console that is similar to the JavaScript console mechanism provided by web browsers.

The module exports two specific components:

  • A Console class with methods such as console.log(), console.error() and console.warn() that can be used to write to any Node.js stream. * A global console instance configured to write to process.stdout and process.stderr. The global console can be used without importing the node:console module.

Warning: The global console object's methods are neither consistently synchronous like the browser APIs they resemble, nor are they consistently asynchronous like all other Node.js streams. See the note on process I/O for more information.

Example using the global console:


const name = 'Will Robinson'; console.warn(`Danger $name! Danger!`); // Prints: Danger Will Robinson! Danger!, to stderr ```

Example using the `Console` class:

```js const out = getStreamSomehow(); const err = getStreamSomehow(); const myConsole = new console.Console(out, err);

myConsole.log('hello world'); // Prints: hello world, to out myConsole.log('hello %s', 'world'); // Prints: hello world, to out myConsole.error(new Error('Whoops, something bad happened')); // Prints: [Error: Whoops, something bad happened], to err

const name = 'Will Robinson'; myConsole.warn(`Danger $name! Danger!`); // Prints: Danger Will Robinson! Danger!, to err ```
console
.
Console.log(message?: any, ...optionalParams: any[]): void (+1 overload)

Prints to stdout with newline. Multiple arguments can be passed, with the first used as the primary message and all additional used as substitution values similar to printf(3) (the arguments are all passed to util.format()).

js const count = 5; console.log('count: %d', count); // Prints: count: 5, to stdout console.log('count:', count); // Prints: count: 5, to stdout

See util.format() for more information.

log
("Smart account address:",
const account: RequestAccountResult
account
.
address: `0x${string}`
address
);
// Send a transaction const {
const preparedCallIds: `0x${string}`[]
preparedCallIds
} = await
const client: SmartWalletClient<undefined>
client
.
sendCalls: (params: SendCallsParams<undefined>) => Promise<SendCallsResult>
sendCalls
({
calls: { value?: `0x${string}` | undefined; data?: `0x${string}` | undefined; to: `0x${string}`; }[]
calls
: [
{
to: `0x${string}`
to
: "0x1234567890123456789012345678901234567890",
value?: `0x${string}` | undefined
value
: "0x0",
data?: `0x${string}` | undefined
data
: "0x",
}, ],
from: `0x${string}`
from
:
const account: RequestAccountResult
account
.
address: `0x${string}`
address
,
});
var console: Console

The console module provides a simple debugging console that is similar to the JavaScript console mechanism provided by web browsers.

The module exports two specific components:

  • A Console class with methods such as console.log(), console.error() and console.warn() that can be used to write to any Node.js stream. * A global console instance configured to write to process.stdout and process.stderr. The global console can be used without importing the node:console module.

Warning: The global console object's methods are neither consistently synchronous like the browser APIs they resemble, nor are they consistently asynchronous like all other Node.js streams. See the note on process I/O for more information.

Example using the global console:


const name = 'Will Robinson'; console.warn(`Danger $name! Danger!`); // Prints: Danger Will Robinson! Danger!, to stderr ```

Example using the `Console` class:

```js const out = getStreamSomehow(); const err = getStreamSomehow(); const myConsole = new console.Console(out, err);

myConsole.log('hello world'); // Prints: hello world, to out myConsole.log('hello %s', 'world'); // Prints: hello world, to out myConsole.error(new Error('Whoops, something bad happened')); // Prints: [Error: Whoops, something bad happened], to err

const name = 'Will Robinson'; myConsole.warn(`Danger $name! Danger!`); // Prints: Danger Will Robinson! Danger!, to err ```
console
.
Console.log(message?: any, ...optionalParams: any[]): void (+1 overload)

Prints to stdout with newline. Multiple arguments can be passed, with the first used as the primary message and all additional used as substitution values similar to printf(3) (the arguments are all passed to util.format()).

js const count = 5; console.log('count: %d', count); // Prints: count: 5, to stdout console.log('count:', count); // Prints: count: 5, to stdout

See util.format() for more information.

log
("Transaction sent:",
const preparedCallIds: `0x${string}`[]
preparedCallIds
[0]);

Solana Support

Server wallet can also easily be used on Solana. To start sending sponsored transactions on Solana, set up a Solana sponsor gas policy in our dashboard and follow the guide below.

import { 
import createServerSigner
createServerSigner
} from "@account-kit/signer";
import {
class Connection

A connection to a fullnode JSON RPC endpoint

Connection
,
class SystemProgram

Factory class for transactions to interact with the System program

SystemProgram
,
class PublicKey

A public key

PublicKey
} from "@solana/web3.js";
// Set up Solana connection const
const connection: Connection
connection
= new
new Connection(endpoint: string, commitmentOrConfig?: Commitment | ConnectionConfig): Connection

Establish a JSON RPC connection

Connection
(
`https://solana-devnet.g.alchemy.com/v2/your-alchemy-api-key`, ); const
const signer: any
signer
= await
import createServerSigner
createServerSigner
({
auth: { accessKey: string; }
auth
: {
accessKey: string
accessKey
: "your-access-key" },
connection: { apiKey: string; }
connection
: {
apiKey: string
apiKey
: "your-alchemy-api-key" },
}); // Convert the signer to a Solana-compatible signer const
const solanaSigner: any
solanaSigner
=
const signer: any
signer
.
any
toSolanaSigner
();
// Build transaction instructions const
const instructions: TransactionInstruction[]
instructions
= [
class SystemProgram

Factory class for transactions to interact with the System program

SystemProgram
.
SystemProgram.transfer(params: TransferParams | TransferWithSeedParams): TransactionInstruction

Generate a transaction instruction that transfers lamports from one account to another

transfer
({
fromPubkey: PublicKey
fromPubkey
: new
new PublicKey(value: PublicKeyInitData): PublicKey

Create a new PublicKey object

PublicKey
(
const solanaSigner: any
solanaSigner
.
any
address
),
toPubkey: PublicKey
toPubkey
: new
new PublicKey(value: PublicKeyInitData): PublicKey

Create a new PublicKey object

PublicKey
(
const solanaSigner: any
solanaSigner
.
any
address
),
lamports: number
lamports
: 0,
}), ]; // Add sponsorship const
const tx: any
tx
= await
const solanaSigner: any
solanaSigner
.
any
addSponsorship
(
const instructions: TransactionInstruction[]
instructions
,
const connection: Connection
connection
,
"your-solana-sponsorship-policy-id", // Make sure enabled on Solana devnet ); // Sign the transaction await
const solanaSigner: any
solanaSigner
.
any
addSignature
(
const tx: any
tx
);
// Send the transaction const
const hash: string
hash
= await
const connection: Connection
connection
.
Connection.sendTransaction(transaction: VersionedTransaction, options?: SendOptions): Promise<TransactionSignature> (+1 overload)

Send a signed transaction

sendTransaction
(
const tx: any
tx
);
var console: Console

The console module provides a simple debugging console that is similar to the JavaScript console mechanism provided by web browsers.

The module exports two specific components:

  • A Console class with methods such as console.log(), console.error() and console.warn() that can be used to write to any Node.js stream. * A global console instance configured to write to process.stdout and process.stderr. The global console can be used without importing the node:console module.

Warning: The global console object's methods are neither consistently synchronous like the browser APIs they resemble, nor are they consistently asynchronous like all other Node.js streams. See the note on process I/O for more information.

Example using the global console:


const name = 'Will Robinson'; console.warn(`Danger $name! Danger!`); // Prints: Danger Will Robinson! Danger!, to stderr ```

Example using the `Console` class:

```js const out = getStreamSomehow(); const err = getStreamSomehow(); const myConsole = new console.Console(out, err);

myConsole.log('hello world'); // Prints: hello world, to out myConsole.log('hello %s', 'world'); // Prints: hello world, to out myConsole.error(new Error('Whoops, something bad happened')); // Prints: [Error: Whoops, something bad happened], to err

const name = 'Will Robinson'; myConsole.warn(`Danger $name! Danger!`); // Prints: Danger Will Robinson! Danger!, to err ```
console
.
Console.log(message?: any, ...optionalParams: any[]): void (+2 overloads)

Prints to stdout with newline. Multiple arguments can be passed, with the first used as the primary message and all additional used as substitution values similar to printf(3) (the arguments are all passed to util.format()).

js const count = 5; console.log('count: %d', count); // Prints: count: 5, to stdout console.log('count:', count); // Prints: count: 5, to stdout

See util.format() for more information.

log
("Transaction sent:",
const hash: string
hash
);