Idempotent mapping
Map any Telegram ID (for example 123456789) to a permanent EVM address. First call creates the wallet; later calls return the same address.
Build server-side Telegram bots that give each user a stable on-chain identity and sign transactions with AWS KMS. No browser wallet, no per-tx popups. This guide uses the @0xgasless/core SDK (OxGasServerWallet) with a pattern that maps Telegram user IDs to wallets and optionally enforces policies from the 0xGasless Dashboard.
Idempotent mapping
Map any Telegram ID (for example 123456789) to a permanent EVM address. First call creates the wallet; later calls return the same address.
Non-custodial KMS
Keys are generated and held in AWS KMS. Bot operators never see raw private key material.
Instant signing
Sign on the server in milliseconds, ideal for commands, cron jobs, and automated flows.
Policy guardrails
Use the dashboard for spend limits, contract allowlists, and optional gas sponsorship via a paymaster.
npm install @0xgasless/coreInitialize OxGasServerWallet with your project API key from the 0xGasless Dashboard.
import { OxGasServerWallet } from '@0xgasless/core';
const wallet = new OxGasServerWallet({ apiKey: '0xgas_live_sk_...', // Your project secret key defaultChainId: 137, // Optional: default chain (e.g. Polygon)});Use the Telegram user id as userId. Prefixing (for example tg_${id}) keeps namespaces clear if you reuse the same project elsewhere.
const telegramId = ctx.from.id.toString();const address = await wallet.getAddress(`tg_${telegramId}`);
console.log(`User ${telegramId} has address ${address}`);Build calldata and sign server-side. The SDK returns an RLP-encoded raw transaction hex string.
const signResult = await wallet.signTransaction(`tg_${telegramId}`, { to: '0xTargetContract...', value: '1000000000000000', // 0.001 native token in wei (string) chainId: 137, data: '0x...', // Optional contract call data});
// signResult.rawTx: signed RLP-encoded hexSend rawTx through any compatible RPC (public or private).
const { txHash } = await wallet.broadcastTransaction( signResult.rawTx, 'https://polygon-rpc.com');
console.log(`Transaction submitted: ${txHash}`);Below is a minimal Telegraf bot: /start shows the user’s wallet; /send signs and broadcasts a native transfer on Polygon.
import { Telegraf } from 'telegraf';import { OxGasServerWallet, PolicyViolationError } from '@0xgasless/core';
const bot = new Telegraf(process.env.BOT_TOKEN);const sdk = new OxGasServerWallet({ apiKey: process.env.OXGAS_API_KEY });
bot.start(async (ctx) => { const address = await sdk.getAddress(`tg_${ctx.from.id}`); ctx.reply(`Welcome! Your permanent bot wallet is:\n\n\`${address}\``, { parse_mode: 'MarkdownV2', });});
bot.command('send', async (ctx) => { const [_, to, value] = ctx.message.text.split(' '); const userId = `tg_${ctx.from.id}`;
try { ctx.reply('⏳ Signing and sending...');
const { rawTx } = await sdk.signTransaction(userId, { to: to as `0x${string}`, value: value, chainId: 137, });
const { txHash } = await sdk.broadcastTransaction(rawTx, 'https://polygon-rpc.com');
ctx.reply(`✅ Success!\nHash: ${txHash}`); } catch (err) { if (err instanceof PolicyViolationError) { ctx.reply(`❌ Blocked by dashboard policy: ${err.reason}`); } else { ctx.reply(`❌ Failed: ${(err as Error).message}`); } }});
bot.launch();Tune safety and spend from the dashboard:
userId spend (for example per day in USD terms, per product configuration).Wrap SDK calls in try / catch. Common error types:
| Class | When it happens |
|---|---|
WalletNotFoundError | No wallet exists yet for the given userId. |
PolicyViolationError | Transaction rejected by dashboard rules. |
ServerSigningError | Signing failed (KMS or invalid transaction params). |
NetworkError | Could not reach the 0xGasless API or the RPC endpoint. |