当前位置:   article > 正文

小试牛刀-Telebot区块链游戏机器人

小试牛刀-Telebot区块链游戏机器人

目录

1.编写目的

2.实现功能

2.1 Wallet功能

2.2  游戏功能

2.3  提出功能

2.4  辅助功能

3.功能实现详解

3.1 wallet功能

3.2 游戏功能

3.3 提出功能

3.4 辅助功能

4.测试视频 


Welcome to Code Block's blog

本篇文章主要介绍了

[Telebot区块链游戏机器人]
❤博主广交技术好友,喜欢文章的可以关注一下❤

1.编写目的

        本文章为记录自己开发基于区块链和Telebot实现的[石头、剪刀、布]游戏的过程,加深自己对区块链知识的理解和使用,加深对TeleBot依赖库的使用,同时希望可以帮助到有想实现相关功能的朋友.     

2.实现功能

2.1 Wallet功能

       用户可以通过/create命令命令创建游戏wallet,同时可以输入地址或扫码向该wallet发送一定数量的游戏代币,使用/wallet命令可以显示当前游戏wallet内的剩余代币数量。

2.2  游戏功能

        用户可以将bot机器人添加到公开群组,同时在群组内发送/game命令创建具有奖励随机结果的游戏,使用不同的人向群组内回复该游戏/pk进行对战,获取对战结果并向游戏wallet发送设定的奖励游戏代币,用户可以使用/del删除当前已创建游戏。

2.3  提出功能

        用户可以通过/bind命令绑定外部wallet并进行代币提出.

2.4  辅助功能

        用户可以输入/rules查看游戏规则,输入/help命令查看机器人命令及解释。

3.功能实现详解

3.1 wallet功能

        用户通过/create命令命令创建游戏wallet可以参考我的博客生成solana公私钥,/wallet显示wallet信息是通过solana.py根据保存的用户公钥查询.

  1. def getBalance(publicKey:str):
  2. solana_client = Client(rpc_url)
  3. #公钥转换
  4. pubkey=Pubkey.from_string(publicKey)
  5. tokenPublicKey=Pubkey.from_string(BOGGY_TOKEN_MINT)
  6. #获取SOL余额
  7. sol_balance = solana_client.get_balance(pubkey)
  8. #获取SPL代币余额
  9. token_account=solana_client.get_token_accounts_by_owner_json_parsed(pubkey,TokenAccountOpts(mint=tokenPublicKey))
  10. if noTokenAccount(token_account):
  11. #不存在代币账户时,则余额为0
  12. token_balance=0.0
  13. else:
  14. token_account_json=token_account.value[0].account.to_json()
  15. token_balance=json.loads(token_account_json)['data']['parsed']['info']['tokenAmount']['uiAmount']
  16. sol_balance=(sol_balance.value/10**9)
  17. return sol_balance,token_balance

        同时为方便用户使用,这边会将用户公钥通过qrcode库转换为二维码供用户扫码,主要代码为:

  1. import qrcode
  2. from io import BytesIO
  3. from PIL import Image
  4. import qrcode.main
  5. def generate_qr(data):
  6. # 生成普通二维码
  7. qr = qrcode.main.QRCode(
  8. version=1,
  9. box_size=10,
  10. border=4,
  11. )
  12. qr.add_data(data)
  13. qr.make(fit=True)
  14. qr_img = qr.make_image(fill_color="black", back_color="white")
  15. # 将二维码图片保存到 BytesIO 对象中
  16. img_io = BytesIO()
  17. qr_img.save(img_io, format='PNG')
  18. img_io.seek(0)
  19. return img_io

实现效果:

3.2 游戏功能

        游戏功能的设计思路是当用户在群组内输入/game时,根据(群组id+用户id+消息id)生成唯一的游戏id并通过json文件存储创建者生成的随机值信息.存储信息如下:

  1. {
  2. "create_user_id": 5385955983,
  3. "create_username": "GameOfBoggy",
  4. "create_select": 0,
  5. "pk_user_id": 2038830708,
  6. "pk_username": "USERT1223",
  7. "pk_select": 1,
  8. "pk_select_hex": "4b32e3c83744655cd4ab5cc991a342c99f52c73fa83f2393a995d53baf7aeb42",
  9. "amount": 20,
  10. "winner": "USERT1223",
  11. "create_select_hex": "bd55d5aa6e461c63c811ff78bb00753c517eba47f086e563783a5e023ff342af",
  12. "timestamp": 1721092512.869742,
  13. "create_drand_hex": "e3b4d8b6af061ddc40449d87c57c06d93de8fa73dff0055a07cc8dadb047dd1e",
  14. "pk_drand_hex": "808391bb3761db7f5be8ba296e143154f043ecced8e7a693698c8490300fe34f"
  15. }

这里的是使用本地secrets库和调用远程的drand随机数链生成两个hash值(create_drand_hex和create_select_hex为创建者游戏结果计算hash,pk_select_hex和pk_drand_hex为pk者游戏结果计算hash,这些结果面会保存到链上以保证游戏结果公平性和随机性.),这两个hash值转换为整数相加并对3取余获得随机结果,以保证游戏的随机性和不可预测性:

调用远程drand API:

  1. def get_drand_randomness():
  2. # Drand API endpoint
  3. url = "https://api.drand.sh/52db9ba70e0cc0f6eaf7803dd07447a1f5477735fd3f661792ba94600c84e971/public/latest"
  4. # Send request to Drand
  5. response = requests.get(url)
  6. if response.status_code == 200:
  7. # Parse the JSON response
  8. data = response.json()
  9. randomness = data['randomness']
  10. return randomness
  11. else:
  12. return secrets.token_hex()

计算游戏随机结果:

  1. def get_random_hex_int():
  2. select_hex=secrets.token_hex()
  3. drand_hex=get_drand_randomness()
  4. hex_int = int(select_hex, 16)
  5. drand_int = int(drand_hex,16)
  6. select=(drand_int+hex_int)%3
  7. return select,select_hex,drand_hex

为保证游戏的美观性,这边使用图片+文字方式让机器人回复用户随机结果:

  1. def random_game(bot,message,type,create_username):
  2. select,select_hex,drand_hex = get_random_hex_int()
  3. imgPath="./img/{}.png".format(img[select])
  4. msgText="<b>[{}] You random [{}]! @{}</b>".format(type,img[select],create_username)
  5. send_message=bot.send_photo(message.chat.id, open(imgPath, 'rb'), caption=msgText,parse_mode='HTML')
  6. return select,send_message,select_hex,drand_hex

游戏奖励发放给获胜者为代币转移操作,实现代码如下(这里的draw_data即为计算出结果的hash值,将其备注添加链上):

  1. #向绑定账户发送代币
  2. def drawTokenAccount(sender_public_key:str,privateKey:str,draw_public_key:str,tokenAmount,draw_data):
  3. solana_client = Client(rpc_url)
  4. #发送者
  5. sender_pubkey = Pubkey.from_string(sender_public_key)
  6. #接收者
  7. draw_pubkey = Pubkey.from_string(draw_public_key)
  8. #Token代币地址
  9. token_mint_address = Pubkey.from_string(BOGGY_TOKEN_MINT)
  10. #发送者keypair
  11. sender_keypair=Keypair.from_base58_string(privateKey)
  12. try:
  13. #spl_client客户端
  14. source_token_account=get_associated_token_address(sender_pubkey,token_mint_address)
  15. dest_token_account=get_associated_token_address(draw_pubkey,token_mint_address)
  16. #交易
  17. transfer_instruction = transfer_checked(
  18. TransferCheckedParams(
  19. program_id=TOKEN_PROGRAM_ID,
  20. source=source_token_account,
  21. mint=token_mint_address,
  22. dest=dest_token_account,
  23. owner=sender_pubkey,
  24. amount=int(float(tokenAmount) * 1000000000),
  25. decimals=9,
  26. )
  27. )
  28. memo_instruction=create_memo(MemoParams(
  29. program_id=MEMO_PROGRAM_ID,
  30. signer=sender_pubkey,
  31. message=draw_data.encode('utf-8')
  32. ))
  33. # #获取最新的区块hash
  34. recent_blockhash_resp = solana_client.get_latest_blockhash()
  35. recent_blockhash=recent_blockhash_resp.value.blockhash
  36. # # 创建交易并添加转账指令
  37. transaction = Transaction()
  38. transaction.add(set_compute_unit_limit(200000))
  39. transaction.add(set_compute_unit_price(7500))
  40. transaction.add(transfer_instruction)
  41. transaction.add(memo_instruction)
  42. #设置最新区块hash
  43. transaction.recent_blockhash=recent_blockhash
  44. #设置手续费支付地址为发送者
  45. transaction.fee_payer=sender_pubkey
  46. #签名
  47. transaction.sign(sender_keypair)
  48. #发送交易
  49. response = solana_client.send_raw_transaction(transaction.serialize())
  50. #打印交易
  51. return response.value
  52. except Exception as e:
  53. print(f"Exception occurred: {str(e)}")
  54. return "error"

实现效果:

/game 20 即创建了一个奖励为20代币的游戏,这里随机的是[剪刀]

/pk pk者出了[布],所以创建者获得了奖励.

我们可以点击按钮在链上查看奖励内容.

可以看到这里包含了一个转移代币操作,是从pk者转移到创建者中的,同时包含了生成随机结果的hash值以保证游戏的公开和公平性。 

3.3 提出功能

        用户输入/bind 绑定自己的链上地址后,提出功能即为代币转移操作,主要实现代码如下,这边直接根据用户的ID查到用户的创建的游戏wallet公钥私钥并进行转移:

  1. def drawTokenFromUserId(send_user_id,draw_user_id,gameId,draw_data):
  2. publicKey,privateKey=get_account(send_user_id)
  3. drawPublicKey=getPublicKey(draw_user_id)
  4. amount=get_game_amount(gameId)
  5. tx=drawTokenAccount(publicKey,privateKey,drawPublicKey,amount,draw_data)
  6. return amount,tx

3.4 辅助功能

        辅助功能即为telebot消息的回复,实现代码如下:

/rules:

  1. from telebot import types
  2. def handle_rules(bot, message):
  3. # 处理 /start 命令
  4. markup = types.InlineKeyboardMarkup()
  5. item1 = types.InlineKeyboardButton("BOGGY GROUP",url="https://t.me/BoggyCoin")
  6. markup.add(item1)
  7. welcome_message=(
  8. "<b>"
  9. "1.Before starting the game, you need to create(/create) a game wallet and transfer a small amount of sol and BOGGY tokens inward\n\n"
  10. "2.You can send '/game [amount]' create a game(default amount:500),and the Pker reply /pk with [GAME](need enough sol and BOGGY)\n\n"
  11. "3.Waiting for the results, the winner will receive the bonus set by the game creator\n\n"
  12. "4.The [Scissors] will win [Paper],[Parer] will win [Rock],[Rock] will win [Scissors]\n\n"
  13. "5.You Can at /wallet,draw you all token in you bind wallet,you can send '/bind [address]' bind you wallet\n\n"
  14. "[Create With #BOGGY]"
  15. "</b>"
  16. )
  17. bot.send_photo(message.chat.id,open("./img/rules.jpeg","rb"),welcome_message,parse_mode='HTML',reply_markup=markup)
  18. def register_handlers(bot):
  19. bot.message_handler(commands=['rules'])(lambda message: handle_rules(bot, message))

/help:

  1. from telebot import types
  2. def handle_help(bot, message):
  3. markup = types.InlineKeyboardMarkup()
  4. item1 = types.InlineKeyboardButton("BOGGY GROUP",url="https://t.me/BoggyCoin")
  5. markup.add(item1)
  6. help_text = (
  7. "<b>Welcome!</b>\n"
  8. "<b>Here are the available commands:</b>\n"
  9. "<b>[/create] Create you game wallet [DM*]</b>\n"
  10. "<b>[/bind] Bind you draw wallet [DM*]</b> \n"
  11. "<b>[/wallet] Show you wallet Info and Draw [DM*]</b>\n\n"
  12. "<b>[/game] Create Game with amount</b>\n"
  13. "<b>[/pk] Reply the Game Message and Pk it</b>\n"
  14. "<b>[/rules] View more detailed game rules</b>\n\n"
  15. "<b>The [DM*] need DM Bot</b>"
  16. )
  17. bot.send_photo(message.chat.id,open("./img/help.jpeg","rb"),help_text, parse_mode='HTML',reply_markup=markup)
  18. def register_handlers(bot):
  19. bot.message_handler(commands=['help'])(lambda message: handle_help(bot, message))

4.测试视频 

video_2024-07-16_11-48-41

 
感谢您的关注和收藏!!!!!!

 

 

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/爱喝兽奶帝天荒/article/detail/857146
推荐阅读
相关标签
  

闽ICP备14008679号