如何使用 Python 构建 Solana Discord 钱包

在本教程中,我们将学习如何使用 Python、discord.py 和 Solana Python SDK 构建 Solana Discord 聊天机器人钱包。该聊天机器人将能够通过 Discord 创建帐户、为帐户注资、检查帐户余额以及将 Solana 代币发送到另一个帐户。

Solana是一个公共区块链网络,允许用户创建NFT、金融应用程序和其他智能合约应用程序。 Solana 的原生代币称为 SOL,根据coinmarketcap.com在撰写本文时的数据,其市值在加密货币中排名第七。 Solana 钱包是一款应用程序,可让您创建 Solana 账户、存储、发送和接收 SOL 及其他代币,以及与智能合约交互。

Discord是一款流行的免费语音、视频和文本聊天应用程序,拥有超过 3.5 亿用户,可在 Windows、macOS、Android、iOS、iPadOS、Linux 和 Web 浏览器中运行。 Discord 聊天机器人是一种能够响应命令并自动执行某些任务的机器人,例如欢迎新成员、审核内容和禁止违反规则的人。我们要创建的机器人将帮助我们创建和管理 Solana 钱包。

在本教程结束时,您将拥有一个如下所示的 Solana Discord 钱包:

最终 Solana Discord 聊天机器人的 Gif 演示

先决条件

  • Discord 帐户
  • 您的设备上已安装或可访问 Discord
  • Python 3.6+

创建一个 Discord 机器人

在本节中,我们将创建一个新的 Discord 机器人帐户,检索机器人令牌,并邀请机器人到我们的一台服务器。

使用您喜欢的浏览器,导航到 Discord 开发人员门户并使用您的 Discord 帐户登录。导航到“应用程序”页面并单击“新建应用程序”按钮。

为您的应用程序命名,例如“Solana wallet”,然后按Create

在 Discord 中创建应用程序屏幕

接下来,导航到机器人选项卡并单击添加机器人按钮以创建机器人用户。

Discord 机器人选项卡

向下滚动到页面的“Build-A-Bot”部分,然后单击“复制”按钮以复制机器人令牌。我们将在下一节中使用此机器人令牌,因此请将其保存在安全的地方。该令牌应保密,因为任何有权访问该令牌的人都可以控制您的机器人。

完成上述步骤后,您就成功创建了机器人帐户!现在,为了能够与该机器人帐户进行交互,您需要将其邀请到您的服务器。

导航到OAuth2选项卡,然后导航到URL 生成器子选项卡。在范围部分中,选择bot

Discord OAuth2 选项卡

在下面显示的机器人权限部分中,选择文本权限列 中的所有字段。转到“生成的 URL”部分,然后单击“复制”按钮复制机器人邀请 URL。

将复制的 URL 粘贴到新选项卡中,选择要添加机器人的服务器,然后单击“继续”按钮。

将机器人添加到不和谐服务器的按钮的屏幕截图

检查机器人的权限,如果满意,请单击“授权”按钮。

现在,您的机器人将被邀请到您的服务器,一旦我们对其进行编码,您就可以与它进行交互。

创建项目结构

在本节中,我们将创建项目目录。在此目录中,我们将创建并激活一个虚拟环境,然后安装构建此聊天机器人所需的 Python 包。最后,我们将创建一个名为 的文件,并在该文件中存储我们的 Discord 机器人令牌。.env

打开终端窗口并输入以下命令:

mkdir solana-discord-wallet
cd solana-discord-wallet

在我们的工作目录中,创建一个虚拟环境并激活它。如果您使用的是Unix或MacOS系统,请运行以下命令:

python3 -m venv venv
source venv/bin/activate

如果您在 Windows 上遵循本教程,请改为运行以下命令:

python -m venv venv
venvScriptsactivate

现在我们已经创建并激活了虚拟环境,我们可以安装创建应用程序所需的库:

pip install discord.py solana python-dotenv 

在上面的命令中pip,我们使用 Python 包安装程序来安装我们将在该项目中使用的以下包:

  • Discord.py是一个现代的、易于使用的、功能丰富的、异步就绪的 Discord API 包装器,我们将用它来与 Discord 的 API 进行交互
  • solana-py是一个基于JSON RPC API构建的 Solana Python 库
  • python-dotenv是一个从.env文件中读取键值对并将它们添加为环境变量的库。我们将使用此模块来检索将存储在.env文件中的机器人令牌

现在让我们开始构建我们的应用程序。创建一个名为 .env的文件,然后粘贴您在上一节中保存为 的 Discord 机器人令牌 BOT_TOKEN

创建文件main.py

在本节中,我们将创建 Python 脚本,该脚本将允许我们的 Discord 聊天机器人发送和接收消息。

在项目的根目录中,创建一个名为main.py的文件,使用您喜欢的文本编辑器打开它并添加以下代码:

import os
import discord
from discord.ext import commands
from dotenv import load_dotenv

在这里,我们导入了聊天机器人应用程序发送和接收消息所需的所有包:

  • os将同时用于从python-dotenv.env文件中检索我们的 Discord 机器人令牌
  • discord包将用于与 Discord 的 API 交互并创建命令处理程序,从而允许我们发送和接收 Discord 消息

将以下代码添加到main.py文件底部:

load_dotenv()
description = ''' A bot that allows you to create and manage a Solana wallet  '''
intents = discord.Intents.default()
bot = commands.Bot(command_prefix='/', description=description, intents=intents)

@bot.event
async def on_ready():
    print('Bot is online')
    print(bot.user.name)
    print(bot.user.id)
    print('------ n')

在上面的代码中,我们通过调用load_dotenv()导入了存储在.env文件中的环境变量。

加载变量后,我们为机器人创建了基本描述,并将机器人的意图设置为default。意图允许机器人订阅特定的事件桶,例如直接消息、反应或打字。

然后,我们创建了一个新的机器人实例,并将命令前缀(/)、描述和意图作为参数传递给构造函数。我们将机器人实例存储在名为 bot 的变量中。

最后,我们为机器人运行时创建了一个事件监听器。当此事件监听器被触发时,我们会在控制台打印几行文字,表示机器人已上线,并显示机器人的用户名和用户ID。

现在,在 on_ready() 函数下面添加以下代码:

@bot.command(description='Create a new solana account')
async def create(ctx):
    await ctx.send('Create account')

@bot.command(description='Fund your account')
async def fund(ctx):
    await ctx.send('Fund your account')

@bot.command(description='Check account balance')
async def balance(ctx):
    await ctx.send('Check account balance')

@bot.command(description='Send SOL to another account')
async def send(ctx):
    await ctx.send('Send SOL to another account')


bot.run(os.environ['BOT_TOKEN'])

在上面的代码块中,我们创建了所有聊天机器人的命令处理程序。上面的代码确定用户试图调用哪个命令,并采取相应的操作。

请注意,我们不需要在每个命令处理程序中指定命令前缀,因为我们在创建机器人实例时已经做了这个操作。

我们的聊天机器人钱包将能够处理以下命令:

/create - 创建一个新的Solana账户
/fund amount - 用特定数量的SOL为现有的Solana账户提供资金
/balance - 检查现有Solana账户的余额
/send amount receiver - 负责将一定数量的SOL发送到另一个Solana账户

目前,每个命令处理程序只会发送一条描述用户想要执行的操作的文本。为了向用户发送消息,我们使用了每个命令处理程序中可用的上下文(ctx)对象提供的send()方法。

最后,我们调用了bot对象提供的run()方法,并将机器人令牌作为参数传递,以启动我们的聊天机器人。

你的main.py文件应该如下所示:

import os
import discord
from discord.ext import commands
from dotenv import load_dotenv

load_dotenv()
description = ''' A bot that allows you to create and manage a Solana wallet  '''
intents = discord.Intents.default()
bot = commands.Bot(command_prefix='/', description=description, intents=intents)

@bot.event
async def on_ready():
    print('Bot is online')
    print(bot.user.name)
    print(bot.user.id)
    print('------ n')

@bot.command(description='Create a new solana account')
async def create(ctx):
    await ctx.send('Create account')

@bot.command(description='Fund your account')
async def fund(ctx):
    await ctx.send('Fund your account')

@bot.command(description='Check account balance')
async def balance(ctx):
    await ctx.send('Check account balance')

@bot.command(description='Send SOL to another account')
async def send(ctx):
    await ctx.send('Send SOL to another account')

bot.run(os.environ['BOT_TOKEN'])

转到终端,然后运行以下命令以启动应用程序:

请使用您喜欢的Discord客户端,向机器人发送/create命令,您应该会收到类似以下的响应:

Discord 中的 /Create 命令

创建文件wallet.py

在本部分中,我们将创建一个文件,该文件允许我们创建 Solana 帐户、为帐户注资、检查帐户余额以及将资金从该帐户发送到另一个帐户。

创建 Solana 帐户时,会生成 KeyPair 对象。该对象包含用于访问帐户的公钥和相应的私钥。

公钥类似于可以与任何人公开共享以接收资金的帐号,而私钥则授予 Solana 用户对给定帐户上资金的所有权。顾名思义,该私钥不应公开共享。

Solana 账户可能持有称为“lamports”的资金。 Lamport 是价值 0.000000001 SOL 的分数原生代币。

在项目的根目录中,创建一个名为wallet.py 的文件使用您喜欢的文本编辑器打开它,然后添加以下代码:

from solana.keypair import Keypair
from solana.publickey import PublicKey
from solana.rpc.api import Client
from solana.transaction import Transaction
from solana.system_program import TransferParams, transfer

import json

solana_client = Client("https://api.devnet.solana.com")

在这里,我们从Solana包中导入了以下对象:

  • Keypair,用于创建新的Solana账户
  • PublicKey,将字符串格式的公钥转换为PublicKey对象,以便将Solana代币发送到另一个账户
  • Client,用于创建Solana客户端实例,允许该应用程序与Solana区块链进行交互
  • Transaction,用于创建Solana交易。交易是由客户端使用单个或多个Keypairs签名的指令,与只有两种可能结果的原子性执行:成功或失败
  • TransferParams,用于创建包含转账交易参数的对象
  • 转移,用于创建允许账户向另一个账户发送资金的对象

之后,我们导入了json,用于将创建的Solana账户的公钥和私钥存储在文件中。

最后,我们在一个名为solana_client的变量中创建了一个Solana客户端实例,并将RPC端点设置为devnet。RPC(远程过程调用)端点是可以发送请求以获取区块链数据的URL。

构建一个用于创建新Solana账户的函数

将以下代码添加到wallet.py的底部:

def create_account(sender_username):
    try:
        kp = Keypair.generate()
        public_key = str(kp.public_key)
        secret_key = kp.secret_key

        data = {
            'public_key': public_key,
            'secret_key': secret_key.decode("latin-1"),
        }

        file_name = '{}.txt'.format(sender_username)
        with open(file_name, 'w') as outfile:
            json.dump(data, outfile)

        return public_key

    except Exception as e:
        print('error:', e)
        return None

上面创建的create_account()函数接收一个参数,即发送/create命令的用户的用户名,它负责创建一个新的Solana账户,并将账户详情存储在本地的.txt文件中。

我们首先通过生成一个新的Solana账户KeyPair对象并将其存储在一个名为kp的变量中来启动代码。

然后,我们将其存储在一个名为data的对象中,该对象是生成的账户的public_key和secret_key的字符串化值。

最后,我们使用存储在sender_username变量中的值创建一个.txt文件,将数据倾倒进去,并在没有异常时返回账户的public_key。如果出现问题,我们返回None。

在create_account()函数下面添加以下代码:

def load_wallet(sender_username):
    try:
        file_name = '{}.txt'.format(sender_username)
        with open(file_name) as json_file:
            account = json.load(json_file)
            account['secret_key'] = account['secret_key'].encode("latin-1")
            return account

    except Exception as e:
        print(e)
        return None  

在这里,我们创建了一个名为load_wallet()的函数。该函数接收用户的用户名作为参数,并使用它从本地的.txt文件中检索他的Solana账户的公钥和私钥,这个文件是在调用create_account()函数时创建的。

创建一个资助Solana账户的函数
在load_wallet()函数下面添加以下代码:

def fund_account(sender_username, amount):
    try:
        amount = int(1000000000 * amount)
        account = load_wallet(sender_username)
        resp = solana_client.request_airdrop(
            account['public_key'], amount)   
        print(resp)    

        transaction_id = resp['result']
        if transaction_id != None:
            return transaction_id
        else:
            return None

    except Exception as e:
        print('error:', e)
        return None

在上面的代码中,我们创建了一个名为fund_account()的函数。这个函数负责请求特定账户的 SOL,并接收发送/fund命令的用户的用户名以及用户请求的 SOL 金额作为参数。

首先,我们使用一些基本的数学运算来防止 Solana 将我们希望请求的 SOL 金额转换为应有的分数。比如说,我们希望请求将一个 SOL 添加到我们的账户中。如果我们只输入“1”作为金额,Solana 将这个金额转换为 0.000000001。因此,为了防止这种行为,我们将我们想要的金额乘以十亿(1,000,000,000)。

然后,使用load_wallet()函数获取用户的 Solana 账户数据,并将其存储在一个名为account的变量中。

最后,我们使用solana_client对象提供的request_airdrop()方法为我们提供的公钥请求一些 SOL 代币。如果请求成功,我们返回交易ID,但如果出现问题,我们返回None。

为了我们认为请求成功,request_airdrop()方法应该返回类似于以下内容的响应:

{
    "jsonrpc": "2.0",
    "result":"uK6gbLbhnTEgjgmwn36D5BRTRkG4AT8r7Q162TLnJzQnHUZVL9r6BYZVfRttrhmkmno6Fp4VQELzL4AiriCo61U",
    "id": 1
}

您在上面看到的jsonrpc是使用的协议,id是请求ID,result是响应结果,而在这个特定的情况下,是一个交易ID。

您可以通过首先导航到Solana区块链浏览器,选择Devnet网络,然后输入您在result属性中看到的交易ID来检查Solana交易的详细信息。

创建一个函数来检查Solana账户的余额

在fund_account()方法下面添加以下代码:

def get_balance(sender_username):
    try:
        account = load_wallet(sender_username)
        resp = solana_client.get_balance(account['public_key'])
        print(resp)
        balance = resp['result']['value'] / 1000000000
        data = {
            "publicKey": account['public_key'],
            "balance": str(balance),
        }
        return data
    except Exception as e:
        print('error:', e)
        return None

这里我们创建了一个名为get_balance()的函数。这个函数接收一个参数,即发送/balance命令的用户的用户名,它负责获取用户的Solana账户余额。

首先,我们使用load_wallet()方法获取用户的Solana账户,然后调用Solana客户端提供的get_balance()方法来获取账户余额,将账户的公钥作为参数传递,并将响应赋值给一个名为resp的变量。

在获取账户余额后,我们将余额除以十亿,以使其更易读。

最后,我们将公钥和账户余额存储在一个名为data的对象中,然后返回这个对象。

如果get_balance()方法发送的请求成功,您应该会看到类似以下的响应:

{
    "jsonrpc": "2.0", 
    "result": {
        "context": { "slot": 228 }, 
        "value": 0
    }, 
    "id": 1
}

您在上面看到的上下文是一个RpcResponseContext JSON结构,其中包含了操作评估的槽位字段。值是操作本身返回的值,在这种情况下,是账户余额。

创建一个在Solana钱包之间发送SOL的函数

在get_balance()函数下面添加以下代码:

def send_sol(sender_username, amount, receiver):
    try:
        account = load_wallet(sender_username)
        sender = Keypair.from_secret_key(account['secret_key'])
        amount = int(1000000000 * amount)

        txn = Transaction().add(transfer(TransferParams(
            from_pubkey=sender.public_key, to_pubkey=PublicKey(receiver), lamports=amount)))
        resp = solana_client.send_transaction(txn, sender)
        print(resp)

        transaction_id = resp['result']
        if transaction_id != None:
            return transaction_id
        else:
            return None

    except Exception as e:
        print('error:', e)
        return None

上面创建的send_sol()函数接收的参数是发送/send命令的用户的用户名、用户希望发送的SOL数量以及她希望发送的Solana账户地址。正如其名称所示,该函数负责向用户提供的Solana账户地址发送一定数量的SOL。

首先,我们使用load_wallet()函数获取用户的Solana账户,然后将用户的Solana账户KeyPair存储在名为sender的变量中。她希望发送的数量存储在名为amount的变量中。

接下来,我们创建一个交易对象,将发送方和接收方的公钥添加到其中,添加她希望发送的SOL数量,并将该对象分配给一个名为txn的变量。

为了发送和签署交易,我们调用了Solana客户端提供的send_transaction()方法,将交易对象和发送方的KeyPair作为参数传递,并将响应存储在名为resp的变量中。send_transaction()方法发送的请求的响应类似于我们之前看到的request_airdrop()方法的响应。

最后,我们从resp对象的result属性中获取存储的交易ID,将其存储在名为transaction_id的变量中,并将其返回。

wallet.py文件应该如下所示:

from solana.keypair import Keypair
from solana.publickey import PublicKey
from solana.rpc.api import Client
from solana.transaction import Transaction
from solana.system_program import TransferParams, transfer

import json

solana_client = Client("https://api.devnet.solana.com")


def create_account(sender_username):
    try:
        kp = Keypair.generate()
        public_key = str(kp.public_key)
        secret_key = kp.secret_key
         data = {
            'public_key': public_key,
            'secret_key': secret_key.decode("latin-1"),
        }

        file_name = '{}.txt'.format(sender_username)
        with open(file_name, 'w') as outfile:
            json.dump(data, outfile)

        return public_key

    except Exception as e:
        print('error:', e)
        return None


def load_wallet(sender_username):
    try:
    file_name = '{}.txt'.format(sender_username)
        with open(file_name) as json_file:
            account = json.load(json_file)
            account['secret_key'] = account['secret_key'].encode("latin-1")
            return account

    except Exception as e:
        print(e)
        return None   


def fund_account(sender_username, amount):
    try:
        amount = int(1000000000 * amount)
        account = load_wallet(sender_username)
        resp = solana_client.request_airdrop(
            account['public_key'], amount)   
        print(resp)    

        transaction_id = resp['result']
        if transaction_id != None:
            return transaction_id
        else:
        return None

    except Exception as e:
        print('error:', e)
        return None


def get_balance(sender_username):
    try:
        account = load_wallet(sender_username)
        resp = solana_client.get_balance(account['public_key'])
        print(resp)
        balance = resp['result']['value'] / 1000000000
        data = {
            "publicKey": account['public_key'],
            "balance": str(balance),
        }
        return data
    except Exception as e:
        print('error:', e)
        return None


def send_sol(sender_username, amount, receiver):
    try:
        account = load_wallet(sender_username)
        sender = Keypair.from_secret_key(account['secret_key'])
        amount = int(1000000000 * amount)

        txn = Transaction().add(transfer(TransferParams(
            from_pubkey=sender.public_key, to_pubkey=PublicKey(receiver), lamports=amount)))
        resp = solana_client.send_transaction(txn, sender)
        print(resp)

        transaction_id = resp['result']
        if transaction_id != None:
            return transaction_id
        else:
            return None

    except Exception as e:
        print('error:', e)
        return None                

将所有内容整合在一起
在前面的部分,我们创建了包含函数的文件,这些函数将允许我们的聊天机器人在Solana区块链上执行交易。在本节中,我们将这些函数与我们的聊天机器人的命令处理程序集成。

转到您的main.py并将以下代码添加到导入语句中:

from wallet import create_account, fund_account, get_balance, send_sol

在上面的代码行中,我们导入了在wallet.py文件的前面部分创建的所有函数。让我们逐个命令地审查并将它们集成到我们的聊天机器人的命令处理程序中。

/create 命令

在main.py文件中,将/create命令处理程序的代码替换为以下内容:

async def create(ctx):
    sender_username = ctx.message.author
    try:
        public_key = create_account(sender_username)
        if public_key is not None:
            message = "Solana Account created successfully.n"
            message += "Your account public key is {}".format(public_key)
            await ctx.send(message)
        else:
            message = "Failed to create account.n"
            await ctx.send(message)
    except Exception as e:
        print('error:',e)
        await ctx.send('Failed to create account')
        return

在这里,我们获取发送/create命令的用户的用户名,并将其存储在一个名为sender_username的变量中。

接下来,我们在wallet.py文件中调用create_account()函数,将用户的用户名作为参数传递,并将其存储在一个名为public_key的变量中。create_account()函数返回新创建的Solana账户的公钥。

然后,我们使用条件逻辑来检查public_key的值是否不等于None,如果是这样,我们将一条消息存储在一个名为message的变量中,说明Solana账户已成功创建并显示公钥。之后,我们使用send()方法将消息发送给用户。

但是,如果public_key等于None,则发送一条消息,说明机器人未能创建帐户。

/fund命令

现在,用以下内容替换/fund命令处理程序中的代码:

async def fund(ctx):
    sender_username = ctx.message.author
    incoming_msg = ctx.message.content
    try:
        amount = float(incoming_msg.split(" ")[1])
        if amount <= 2 :
            message = "Requesting {} SOL to your Solana account, please wait !!!".format(amount)
            await ctx.send(message)
            transaction_id = fund_account(sender_username, amount)
            if transaction_id is not None:
                message = "You have successfully requested {} SOL for your Solana account n".format(
                    amount)
                message += "The transaction id is {}".format(transaction_id)
                await ctx.send(message)
            else:
                message = "Failed to fund your Solana account"
                await ctx.send(message)
        else:
            message = "The maximum amount allowed is 2 SOL"
            await ctx.send(message)
    except Exception as e:
        print('error:',e)
        await ctx.send('Failed to fund account')
        return

在上面的代码中,我们获取发送/fund命令的用户的用户名和接收到的消息,然后分别将这些值存储在名为sender_username和incoming_msg的变量中。

然后,我们从接收到的消息中检索用户希望请求的SOL数量,并将其存储在名为amount的变量中。

在检索到数量之后,我们检查数量是否不大于2,因为在撰写本教程时,2是您可以请求的SOL的最大数量。如果数量不大于2,我们将一条消息存储在名为message的变量中,说明用户请求的金额正在添加到他的帐户,并请他等待。然后,我们使用send()方法将此消息发送给用户。

在通知用户之后,我们在wallet.py文件中调用fund_account()函数。我们将用户的用户名和他希望添加到他的帐户中的SOL数量作为参数传递。调用fund_account()函数后,我们将返回的交易ID存储在名为transaction_id的变量中。

最后,我们使用条件逻辑来检查交易ID是否不等于None,如果是这样,我们将一条消息存储在名为message的变量中,说明他请求的资金已添加到他的帐户中。我们在此消息中添加了交易ID,然后将此消息发送给用户。

但是,如果交易ID等于None,则发送一条消息,说明机器人未能为帐户提供资金。

/balance命令

现在,让我们处理/balance命令。将/balance命令处理程序中的代码替换为以下内容:

async def balance(ctx):
    sender_username = ctx.message.author
    try:
        data = get_balance(sender_username)
        if data is not None:
            public_key = data['publicKey']
            balance = data['balance']
            message = "Your Solana account {} balance is {} SOL".format(
                public_key, balance)
            await ctx.send(message)
        else:
            message = "Failed to retrieve balance"
            await ctx.send(message)
    except Exception as e:
        print('error:',e)
        await ctx.send('Failed to check account balance')
        return

在这里,首先,我们获取发送/balance命令的用户的用户名,并将其存储在名为sender_username的变量中。

然后,我们在wallet.py文件中调用get_balance()函数。我们将用户的用户名作为参数传递,并将其存储在名为data的变量中,作为此函数返回的对象。此对象应包含用户的Solana帐户公钥和余额。

最后,我们使用条件逻辑来检查返回的值是否不等于None。如果是这样,我们将一条消息存储在名为message的变量中,其中包含用户的Solana帐户公钥和余额,然后将消息发送给用户。

但是,如果get_balance()返回的值等于None,则发送一条消息,说明机器人未能检索帐户余额。

/send命令

接下来处理/send命令。将/send命令处理程序中的代码替换为以下内容:

async def send(ctx):
    sender_username = ctx.message.author
    incoming_msg = ctx.message.content
    try:
        split_msg = incoming_msg.split(" ")
        amount = float(split_msg[1])
        receiver = split_msg[2]
        message = "Sending {} SOL to {}, please wait !!!".format(
            amount, receiver)
        await ctx.send(message)
        transaction_id = send_sol(sender_username, amount, receiver)
        if transaction_id is not None:
            message = "You have successfully sent {} SOL to {} n".format(
                amount, receiver)
            message += "The transaction id is {}".format(transaction_id)
            await ctx.send(message)
        else:
            message = "Failed to send SOL"
            await ctx.send(message)
    except Exception as e:
        print('error:',e)
        await ctx.send('Failed to send SOL')
        return

在上面的代码中,我们获取发送/send命令的用户的用户名、接收到的消息,然后分别将这些值存储在名为sender_username和incoming_msg的变量中。

然后,我们解析接收到的消息,从中获取用户希望发送的SOL数量和接收方帐户的地址,并将这些值分别存储在名为amount和receiver的变量中。

在存储了金额和接收方之后,向用户发送一条消息,通知她希望发送的SOL数量正在发送给接收方,并请用户稍候。

在通知用户之后,我们在wallet.py文件中调用send_sol()函数。我们将用户的用户名、她希望转账的SOL数量以及接收方的地址作为参数传递。然后,我们将此函数返回的交易ID存储在名为transaction_id的变量中。

最后,我们使用条件逻辑来检查交易ID是否不等于None。如果是这样,我们将一条消息存储在名为message的变量中,说明用户已成功将SOL发送到所需的帐户。我们将交易ID附加到消息中,并将消息发送给用户。

但是,如果send_sol()函数返回的值等于None,则发送一条消息,说明机器人未能发送SOL。

在替换了每个命令处理程序中的代码后,main.py文件应如下所示:

import os
import discord
from discord.ext import commands
from dotenv import load_dotenv
from wallet import create_account, fund_account, get_balance, send_sol

load_dotenv()
description = ''' A bot that allows you to create and manage a Solana wallet  '''
intents = discord.Intents.default()
bot = commands.Bot(command_prefix='/', description=description, intents=intents)

@bot.event
async def on_ready():
    print('Bot is online')
    print(bot.user.name)
    print(bot.user.id)
    print('------ n')

@bot.command(description='Create a new solana account')
async def create(ctx):
    sender_username = ctx.message.author
    try:
        public_key = create_account(sender_username)
        if public_key is not None:
            message = "Solana Account created successfully.n"
            message += "Your account public key is {}".format(public_key)
            await ctx.send(message)
            else:
            message = "Failed to create account.n"
            await ctx.send(message)
    except Exception as e:
        print('error:',e)
        await ctx.send('Failed to create account')
        return

@bot.command(description='Fund your account')
async def fund(ctx):
    sender_username = ctx.message.author
    incoming_msg = ctx.message.content
    try:
        amount = float(incoming_msg.split(" ")[1])
        if amount <= 2 :
            message = "Requesting {} SOL to your Solana account, please wait !!!".format(amount)
            await ctx.send(message)
            transaction_id = fund_account(sender_username, amount)
            if transaction_id is not None:
                message = "You have successfully requested {} SOL for your Solana account n".format(
                    amount)
                message += "The transaction id is {}".format(transaction_id)
                await ctx.send(message)
            else:
                message = "Failed to fund your Solana account"
                await ctx.send(message)
                else:
            message = "The maximum amount allowed is 2 SOL"
            await ctx.send(message)
    except Exception as e:
        print('error:',e)
        await ctx.send('Failed to fund account')
        return

@bot.command(description='Check your account balance')
async def balance(ctx):
    sender_username = ctx.message.author
    try:
        data = get_balance(sender_username)
        if data is not None:
            public_key = data['publicKey']
            balance = data['balance']
            message = "Your Solana account {} balance is {} SOL".format(
                public_key, balance)
            await ctx.send(message)
        else:
            message = "Failed to retrieve balance"
            await ctx.send(message)
    except Exception as e:
    print('error:',e)
        await ctx.send('Failed to check account balance')
        return

@bot.command(description='Send SOL to another account')
async def send(ctx):
    sender_username = ctx.message.author
    incoming_msg = ctx.message.content
    try:
        split_msg = incoming_msg.split(" ")
        amount = float(split_msg[1])
        receiver = split_msg[2]
        message = "Sending {} SOL to {}, please wait !!!".format(
            amount, receiver)
        await ctx.send(message)
        transaction_id = send_sol(sender_username, amount, receiver)
        if transaction_id is not None:
            message = "You have successfully sent {} SOL to {} n".format(
                amount, receiver)
            message += "The transaction id is {}".format(transaction_id)
            await ctx.send(message)
        else:
            message = "Failed to send SOL"
            await ctx.send(message)
    except Exception as e:
    print('error:',e)
        await ctx.send('Failed to send SOL')
        return

bot.run(os.environ['BOT_TOKEN'])

返回到运行main.py文件的终端窗口,停止该进程,然后使用以下命令再次运行它:

python main.py

打开你偏好的Discord客户端,向你的机器人发送“/create”命令以创建一个新的Solana账户。你应该会看到类似以下的内容:

复制公钥并妥善存放以备后用。再次发送“/create”命令以生成一个新的Solana账户。

现在,发送“/fund 2”命令以向你的Solana账户充值两个SOL代币。你应该会看到类似以下的内容:

Screenshot of the fund 2 command in action

请确保测试其他命令,以确保它们都按预期运行。

结论
在本教程中,你学会了如何创建一个Solana Discord聊天机器人钱包,能够创建Solana账户、为账户充值、检索账户余额,并向另一个Solana账户发送SOL。

在本教程中构建的Solana Discord钱包还不适用于生产环境,我建议在将SOL发送到另一个账户之前添加更多功能,例如身份验证和账户余额检查。完整的应用程序代码可在此存储库中找到。

有关Solana和discord.py包的更多信息,请访问Solana文档和discord.py文档。

💡
原文链接:How to build a Solana Discord wallet with Python
本文由SlerfTools翻译,转载请注明出处。

SlerfTools专为Solana设计的工具箱,致力于简化区块链操作,提供无编程全可视化界面,使发币管理流动性无代码创建Dapp等复杂过程变得安全简单。