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.
JavaScript
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 generateAccessKeygenerateAccessKey } from "@account-kit/signer";
// Generate a random access key
const const accessKey: anyaccessKey = import generateAccessKeygenerateAccessKey();
var console: ConsoleThe 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: anyaccessKey);
// 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 createServerSignercreateServerSigner } from "@account-kit/signer";
const const signer: anysigner = await import createServerSignercreateServerSigner({
auth: {
accessKey: string;
}auth: {
accessKey: stringaccessKey: "your-access-key-here",
},
connection: {
apiKey: string;
}connection: {
apiKey: stringapiKey: "your-alchemy-api-key",
},
});
var console: ConsoleThe 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: anysigner.anygetAddress());
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.
Multiple signers per access key
import { import createServerSignercreateServerSigner } from "@account-kit/signer";
const const businessSigner: anybusinessSigner = await import createServerSignercreateServerSigner({
auth: {
accessKey: string;
accountId: string;
}auth: {
accessKey: stringaccessKey: "your-access-key-here",
accountId: stringaccountId: "business",
},
connection: {
apiKey: string;
}connection: {
apiKey: stringapiKey: "your-alchemy-api-key",
},
});
const const personalSigner: anypersonalSigner = await import createServerSignercreateServerSigner({
auth: {
accessKey: string;
accountId: string;
}auth: {
accessKey: stringaccessKey: "your-access-key-here", // same access key
accountId: stringaccountId: "personal", // different account ID
},
connection: {
apiKey: string;
}connection: {
apiKey: stringapiKey: "your-alchemy-api-key",
},
});
// These will have different addresses despite using the same access key
var console: ConsoleThe 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: anybusinessSigner.anygetAddress());
var console: ConsoleThe 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: anypersonalSigner.anygetAddress());
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): AlchemyTransportCreates 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: ChainbaseSepolia } 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: AlchemyTransporttransport: function alchemy(config: AlchemyTransportConfig): AlchemyTransportCreates 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: stringapiKey: "your-alchemy-api-key",
}),
chain: Chainchain: const baseSepolia: ChainbaseSepolia,
signer: SmartAccountSigner<any>signer,
policyId?: string | undefinedpolicyId: "your-sponsor-gas-policy-id", // Make sure enabled on Base Sepolia
});
// Retrieve account
const const account: RequestAccountResultaccount = await const client: SmartWalletClient<undefined>client.requestAccount: (params?: RequestAccountParams) => Promise<RequestAccountResult>requestAccount();
var console: ConsoleThe 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: RequestAccountResultaccount.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}` | undefinedvalue: "0x0",
data?: `0x${string}` | undefineddata: "0x",
},
],
from: `0x${string}`from: const account: RequestAccountResultaccount.address: `0x${string}`address,
});
var console: ConsoleThe 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 createServerSignercreateServerSigner } from "@account-kit/signer";
import { class ConnectionA connection to a fullnode JSON RPC endpoint
Connection, class SystemProgramFactory class for transactions to interact with the System program
SystemProgram, class PublicKeyA public key
PublicKey } from "@solana/web3.js";
// Set up Solana connection
const const connection: Connectionconnection = new new Connection(endpoint: string, commitmentOrConfig?: Commitment | ConnectionConfig): ConnectionEstablish a JSON RPC connection
Connection(
`https://solana-devnet.g.alchemy.com/v2/your-alchemy-api-key`,
);
const const signer: anysigner = await import createServerSignercreateServerSigner({
auth: {
accessKey: string;
}auth: { accessKey: stringaccessKey: "your-access-key" },
connection: {
apiKey: string;
}connection: { apiKey: stringapiKey: "your-alchemy-api-key" },
});
// Convert the signer to a Solana-compatible signer
const const solanaSigner: anysolanaSigner = const signer: anysigner.anytoSolanaSigner();
// Build transaction instructions
const const instructions: TransactionInstruction[]instructions = [
class SystemProgramFactory class for transactions to interact with the System program
SystemProgram.SystemProgram.transfer(params: TransferParams | TransferWithSeedParams): TransactionInstructionGenerate a transaction instruction that transfers lamports from one account to another
transfer({
fromPubkey: PublicKeyfromPubkey: new new PublicKey(value: PublicKeyInitData): PublicKeyCreate a new PublicKey object
PublicKey(const solanaSigner: anysolanaSigner.anyaddress),
toPubkey: PublicKeytoPubkey: new new PublicKey(value: PublicKeyInitData): PublicKeyCreate a new PublicKey object
PublicKey(const solanaSigner: anysolanaSigner.anyaddress),
lamports: numberlamports: 0,
}),
];
// Add sponsorship
const const tx: anytx = await const solanaSigner: anysolanaSigner.anyaddSponsorship(
const instructions: TransactionInstruction[]instructions,
const connection: Connectionconnection,
"your-solana-sponsorship-policy-id", // Make sure enabled on Solana devnet
);
// Sign the transaction
await const solanaSigner: anysolanaSigner.anyaddSignature(const tx: anytx);
// Send the transaction
const const hash: stringhash = await const connection: Connectionconnection.Connection.sendTransaction(transaction: VersionedTransaction, options?: SendOptions): Promise<TransactionSignature> (+1 overload)Send a signed transaction
sendTransaction(const tx: anytx);
var console: ConsoleThe 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: stringhash);