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.
1. Install the package
Section titled “1. Install the package”npm install @0xgasless/coreRequires Node 18+. Pure ESM and CommonJS exports both ship.
2. Get an API key
Section titled “2. Get an API key”- Open the 0xGasless Dashboard.
- Create a project (or pick an existing one).
- 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.
3. Initialise the client
Section titled “3. Initialise the client”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.
4. Create or get a wallet
Section titled “4. Create or get a wallet”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);// → 0x1a2b3c4d5e6f7a8b9c0d1e2f3a4b5c6d7e8f9a0bFirst 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).
5. Sign and broadcast a transaction
Section titled “5. Sign and broadcast a transaction”const userId = 'telegram_123456789';
// 5a — sign the transactionconst 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 RPCconst { 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.
What just happened
Section titled “What just happened”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 ◄──────────────────────────────────────────────── │ blockThree notes:
- Signing is instant. No human approval — your code is fully autonomous.
signTransaction≠sendTransaction. 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.
Common follow-up patterns
Section titled “Common follow-up patterns”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 });Send an ERC-20 transfer
Section titled “Send an ERC-20 transfer”import { ethers } from 'ethers';
// Encode the transfer() call dataconst 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);Next steps
Section titled “Next steps”- API reference — every method and option.
- Telegram bot example — full integration walkthrough.
- Errors — what each typed error means and how to recover.
- Security model — what the platform sees, what it doesn’t.