This guide will walk through setting up a Telegram Solana trading bot using Privy’s server wallets and the Jup.ag API.

Resources

Configure your Telegram bot

Create a new bot on telegram and get bot token, learn more here

Get set up with managed wallets

If your app does not have access to managed wallets, request managed wallets access on your dashboard here

Privy managed wallets provide a secure way to manage wallets on your backend, allowing you to create and control wallets programmatically. Learn more about getting started with managed wallets.

Using wallets

In our example application, we will build three basic interactions with Privy wallets:

In this trading bot example, we will create a single wallet for each user that interacts with our bot. We can use the id associated from the sender to verifiably identify the user. This value comes directly from Telegram’s servers and is only sent from verified users.

Create a wallet (/start)

Create a new wallet for every user that interacts with your bot.

1

Create Telegram bot command

Create a Telegram bot command that will be used to start the bot.

bot.onText(/\/start/, (msg) => {
    const userId = msg.from.id;
    bot.sendMessage(msg.chat.id, `Hello from the trading bot!`);
});
2

Create a wallet

Create a wallet with the createWallet function. Learn more about the createWallet function here.

bot.onText(/\/start/, async (msg) => {
    const userId = msg.from.id;
    const wallet = await privy.walletApi.createWallet({chainType: 'solana'});
    bot.sendMessage(msg.chat.id, `Hello from the trading bot! Your wallet address is ${wallet.address}`);
});
3

Save wallet to database

Save the wallet id to your database and associate it with the user’s id.

bot.onText(/\/start/, async (msg) => {
    const userId = msg.from.id;
    const wallet = await privy.walletApi.createWallet({chainType: 'solana'});
    // EXAMPLE: Save wallet id to your database with userId as the key
    await db.wallets.set(userId.toString(), wallet.id);

    bot.sendMessage(msg.chat.id, `Hello from the trading bot! Your wallet address is ${wallet.address}`);
});
4

(optional) Block users from creating multiple wallets

Block users from creating multiple wallets by checking if a wallet already exists for the user.

bot.onText(/\/start/, async (msg) => {
    const userId = msg.from.id;
    // EXAMPLE: Get wallet id from database using userId as the key
    const walletId = await db.wallets.get(userId.toString());
    if (walletId) {
        bot.sendMessage(msg.chat.id, `You already have a wallet!`);
        return;
    }
    const wallet = await privy.walletApi.createWallet({chainType: 'solana'});
    // EXAMPLE: Save wallet id to your database with userId as the key
    await db.wallets.set(userId.toString(), wallet.id);

    bot.sendMessage(msg.chat.id, `Hello from the trading bot! Your wallet address is ${wallet.address}`);
});

Get a wallet (/getwallet)

Retrieve the wallet address for the user and fetch the balance of the wallet.

1

Create a /getwallet command

Get a wallet with the /getwallet command. Learn more here.

bot.onText(/\/getwallet/, async (msg) => {
    const userId = msg.from.id;

    // EXAMPLE: Get wallet id from database using userId as the key
    const walletId = await db.wallets.get(userId.toString());

    const wallet = await privy.walletApi.getWallet({id: walletId})
    bot.sendMessage(msg.chat.id, `Your wallet address is ${wallet?.address || 'No wallet found'}`);
});
2

Get balance

Get the balance of the wallet with the getJupiterUltraBalances function. Learn more here.

bot.onText(/\/getwallet/, async (msg) => {
    const userId = msg.from.id;

    // EXAMPLE: Get wallet id from database using userId as the key
    const walletId = await db.wallets.get(userId.toString());

    const wallet = await privy.walletApi.getWallet({id: walletId})
    const balances = await getJupiterUltraBalances(wallet.address);

    let balanceMessage = `Wallet Balance:\n\n`;
    for (const [token, balance] of Object.entries(balances)) {
        if (balance.amount !== "0") {
            balanceMessage += `${token}: ${balance.uiAmount.toFixed(4)}\n`;
        }
    }
    bot.sendMessage(msg.chat.id, balanceMessage);
});

Swap tokens (/swap)

To swap tokens in our trading bot, we will be utilizing the Jupiter Ultra API. With just a few lines of code, we can allow users to swap tokens.

1

Create a swap command

Take in the token address and amount from the user /swap <token_address> <amount>. We will validate the token address and amount before proceeding.

bot.onText(/\/swap (.+) (.+)/, async (msg, match) => {
    const userId = msg.from.id;
    const tokenMint = match[1]; // First capture group is token address. (optional) validate this is a valid solana token address
    const amount = parseFloat(match[2]); // Second capture group is amount. (optional) validate this is a valid number

    // EXAMPLE: Get wallet id from database using userId as the key
    const walletId = await db.wallets.get(userId.toString());

    const wallet = await privy.walletApi.getWallet({id: walletId})

    bot.sendMessage(msg.chat.id, `Your wallet address is ${wallet?.address || 'No wallet found'}`);
});
2

Create order

We will use a helper function getJupiterUltraOrder to create an order with the Jupiter Ultra API.

Call this helper function in the /swap command.

bot.onText(/\/swap (.+) (.+)/, async (msg, match) => {
    const userId = msg.from.id;
    const tokenMint = match[1]; // First capture group is token address.
    const amount = parseFloat(match[2]); // Second capture group is amount.
    // ...
    const lamports = Math.floor(amount * 1e9);
    const order = await getJupiterUltraOrder({
        inputMint: SOL_MINT, // SOL mint address
        outputMint: tokenMint,
        amount: lamports.toString(),
        taker: wallet.address
        });
    // ...
});
3

Sign transaction

Sign the transaction with the signTransaction function. Learn more about the signTransaction function here.

    bot.onText(/\/swap (.+) (.+)/, async (msg, match) => {
    const userId = msg.from.id;
    const tokenMint = match[1]; // First capture group is token address.
    const amount = parseFloat(match[2]); // Second capture group is amount.
    // ...
    const transaction = VersionedTransaction.deserialize(Buffer.from(order.transaction, 'base64'));
    const {signedTransaction} = await privy.walletApi.solana.signTransaction({
        walletId: wallet.id,
        transaction: transaction
    });
    // ...
});
4

Execute transaction

Send the transaction with the executeJupiterUltraOrder function. Learn more here.

bot.onText(/\/swap (.+) (.+)/, async (msg, match) => {
    const userId = msg.from.id;
    const tokenMint = match[1]; // First capture group is token address.
    const amount = parseFloat(match[2]); // Second capture group is amount.
    // ...
    const executeResult = await executeJupiterUltraOrder(
        Buffer.from(signedTransaction.serialize()).toString('base64'),
        order.requestId
    );
    // ...
    bot.sendMessage(
        msg.chat.id,
        `✅ Swap successful!\n` +
        `Transaction: https://solscan.io/tx/${executeResult.signature}\n` +
        `You swapped ${amount} SOL for approximately ${order.outAmount / 1e9} tokens`
    );
    // ...
});

Your app has now successfully swapped tokens! Checkout our full Github example for more details here