Skip to content

Quickstart

End-to-end in five steps. By the end you’ll have a server wallet that holds funds, signs transactions instantly, and broadcasts them to Avalanche Fuji.

Terminal window
npm install @0xgasless/core

Requires Node 18+. Pure ESM and CommonJS exports both ship.

  1. Open the 0xGasless Dashboard.
  2. Create a project (or pick an existing one).
  3. Copy the Project API key — it starts with 0xgas_live_sk_.

The API key authenticates every server-wallet call. It’s project-scoped, so every wallet you create is automatically tied to this project.

import { OxGasServerWallet } from '@0xgasless/core';
const wallet = new OxGasServerWallet({
apiKey: process.env.OXGAS_API_KEY!,
defaultChainId: 43113, // Avalanche Fuji testnet
});

That’s the whole config. Defaults work in production; see API reference for overrides.

A “wallet” here is identified by any string you choose — typically the user’s stable ID in your system: a Telegram user ID, a UUID, an email. Pass the same userId again later and you get the same wallet back.

const address = await wallet.getAddress('telegram_123456789');
console.log('Wallet address:', address);
// → 0x1a2b3c4d5e6f7a8b9c0d1e2f3a4b5c6d7e8f9a0b

First call creates the wallet (one round-trip to the platform, key materialised in KMS). Every subsequent call returns the same address instantly.

Now fund the wallet — send Fuji AVAX or USDC to the address from the Avalanche faucet (faucet covers both).

const userId = 'telegram_123456789';
// 5a — sign the transaction
const result = await wallet.signTransaction(userId, {
to: '0x000000000000000000000000000000000000dEaD',
value: '1000000000000000', // 0.001 AVAX (wei as string)
nonce: 0, // fetch from RPC if you don't track it
chainId: 43113,
gas: 21000, // optional, default 21000
gasPrice: '30000000000', // optional, 30 gwei default
});
console.log('Signed:', result.txHash, result.rawTx);
// 5b — broadcast to any EVM RPC
const { txHash } = await wallet.broadcastTransaction(
result.rawTx,
'https://api.avax-test.network/ext/bc/C/rpc',
);
console.log('Sent on-chain:', txHash);

signTransaction returns the signed RLP-encoded transaction (rawTx) plus the pre-computed hash. The platform never broadcasts for you — your code chooses where to send it.

That’s it. Your wallet just sent its first transaction. Check it on Snowtrace Testnet.

Your server Platform Chain
─────────── ──────── ─────
│ │
wallet.getAddress(uid) ─────────► │ │
│ KMS create-or-lookup │
◄──────────────────────│ return EOA │
│ │
[user sends Fuji AVAX] │
wallet.signTransaction(uid, tx)─►│ │
│ KMS signs │
◄──────────────────────│ return rawTx + hash │
│ │
wallet.broadcastTransaction()────────────────────────────────►│ submit
◄──────────────────────────────────────────────── │ block

Three notes:

  • Signing is instant. No human approval — your code is fully autonomous.
  • signTransactionsendTransaction. The platform signs; your code broadcasts. That gives you full control of nonce tracking, RPC selection, and confirmation handling.
  • Nonces are your responsibility. The simplest pattern is to read the current nonce from the RPC before signing. For high-throughput bots, track nonces in your own DB or Redis.

Read the nonce from the RPC before signing

Section titled “Read the nonce from the RPC before signing”
async function nextNonce(address: string, rpcUrl: string) {
const r = await fetch(rpcUrl, {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({
jsonrpc: '2.0', id: 1,
method: 'eth_getTransactionCount',
params: [address, 'pending'],
}),
}).then((r) => r.json());
return parseInt(r.result, 16);
}
const address = await wallet.getAddress(userId);
const nonce = await nextNonce(address, FUJI_RPC);
const result = await wallet.signTransaction(userId, { to, value, nonce, chainId: 43113 });
import { ethers } from 'ethers';
// Encode the transfer() call data
const data = new ethers.Interface([
'function transfer(address to, uint256 amount)',
]).encodeFunctionData('transfer', [recipient, amountAtomic]);
const result = await wallet.signTransaction(userId, {
to: USDC_TOKEN_ADDRESS,
value: '0',
data,
nonce: await nextNonce(address, FUJI_RPC),
chainId: 43113,
gas: 80000,
gasPrice: '30000000000',
});
await wallet.broadcastTransaction(result.rawTx, FUJI_RPC);