「これはプログラミングを書けない素人が数日間、試行錯誤してpythonによるコントラクト叩きを成功させた物語である」
(注意:この記事はブロックチェーンエクスプローラーをある程度読めるという読者想定で書いています。なので諸々の超初歩的な部分の説明は省いたりしております。あと、生成されたコードが最適なものであるという保証はありません。実行は自己責任でお願いします。
あと、本記事の内容は当時(2024年9月〜10月)にMORCHIをプレイしてない人、MOOARマーケットプレイスを使ったことがない人にとっては再現が難しい箇所がいくつかあります。
そのうえ本記事は筆者の回顧録、備忘録的な側面が強いため冗長な作りとなっています。その点、ご理解いただける人のみこの先をご覧くださいませ)
もくじ
ここから本題
タイトルにある「自動BCGタスク消化プログラム」。
これは具体的に何を目的としてるのかと言うと、MORCHIというブロックチェーンゲームのキャラクター育成を自動化するプログラムを書こう、ということです。
MORCHIは2024年9月にFSLという会社(STEPNで有名)がローンチしたプロジェクトです。
どんなゲームかを超単純に説明しますと、毎日退屈なタスクをこなしてレベル上げをしてトークンを稼ごうって感じのやつです。(深掘ると超面白いんですが、説明がめんどくさいので割愛)
んで、「この毎日退屈なタスクってやつを自動化したら楽じゃね?直コンの入門にもなるし」ってのが今回の目的なわけです。
しかし私はプログラミングが書けません。(Youtube動画を参考にしながらPython超基礎などは経験したことある程度)
直コンするにしても何の言語が適しているの?
solidityなにそれおいしいの?
スマコンって自動販売機みたいなやつだよね?
ってレベル感です。
イントロ(筆者が生成AIに目覚めるまで)
さて、素人のみなさんは直コンするにあたってどのようなアプローチを取りますか?
当時の私は以下のようなアプローチを取りました。
「直コン」でググる
↓
検索上位のブログ(noteとか)を参考にする。
↓
載ってたソースコードをエディタにコピペして実行
↓
エラーが出る
↓
エラー文をコピペしてググる
↓
いくつもの英語ページや専門的なページ(qiitaとか)を苦しみながら解読し、エラー解消を行う
↓
次のエラーが発生
↓
またいくつもの英語ページや専門的ry
↓
次のエラーry
↓
以下略
あと同時並行で無料solidity学習ツール「CryptoZombies」を使って勉強を開始しました。
結論から言うとこのアプローチはダメダメでした。
なぜならプログラミング言語を習得するのが大変。エラー原因特定が困難。学ばなくてはならない範囲が多すぎる(言語の他にスマコンとか)。
ぶっちゃけ非効率過ぎです。こんな作業のやり方は令和じゃありません。ただの平成です。一万円札が渋沢栄一になったのと同様、スキル習得方法も刷新していきましょう。
平成スタイルで突き進んでいた私はこんな感じ↓で無駄にエラー解消に苦しんでました…
うーん、今度は
AttributeError: 'Eth' object has no attribute 'getBalance'
かぁもう一個のコピペコードでは
AttributeError: 'Eth' object has no attribute 'blockNumber'
って出る。とっても眠くなってきたぞ pic.twitter.com/4qciEwMMXj
— せんがく(浅学) (@fool_flatfish) September 7, 2024
じゃあどうするか?答えは単純。
生成AIにコードなり疑問を投げて効率よく直コンコード(bot)を完成させようって算段です。
エラーコードをググるのではなく生成AIに投げる。そして解答をもらう。これをやっているのとやらないのとは天と地ほどの差がでると悟りました。
ググらずに生成AIに聞けば一発解決だったじゃん…
ワタクシ、完全に無能旧世代でした。すみません pic.twitter.com/gn02o9zoda— せんがく(浅学) (@fool_flatfish) September 8, 2024
生成AIに質問を投げる(プロンプト作成)前にやっておいたこと
あ、そうそう。このページくらいは最低限読んでおいた方が良いと思いました。
スマートコントラクトの構造が少しは理解できるようになります。(私は若干は理解してる気になってます)
何となくでいいから「コントラクトのここの工程をAI生成されたコードのこの部分がやってるんだろうなー」って思ってるのと「何起こってるか知らんけど、このブログの手順真似たら関数実行できたわ」ってのでは、今後のプロンプトの正確性、指示する内容の具体性って点でかなり差が出てくると思われます。
機械学習分野でよく言われる「Garbage in, Garbage out(ゴミを入れたら、ゴミが出てくる)」ってやつですね。
「直コンで儲ける方法教えて」とかいううんこプロンプトを投げ入れてもでてくるのはうんこです。臭いだけです。
とはいえこだわりすぎると進まないのでほどほどにして…
まぁ「スマコンとかの概要、輪郭みたいのは分かった気がするぞ」レベルに達したらコード生成に着手して良いと素人の私は思ってます。自己責任で自分が使うコードですし。
さて、長い前置きはここまでにして…次の章から実際に生成AIで自動関数実行プログラム(bot)を作っていきましょう。
エディタや生成AIソフトは無料でOK(筆者が用意したもの)
筆者が用意したものはこれ
・M1 MacBook air(パソコン)
・jupyterlab desktop(エディタ)
・perplexity AI(生成AI)
・MORCHINFT(筆者はフリーミント(無料)でゲット)
【MORCHINFTマーケット】
https://mooar.com/collection/morchi
Macは当たり前ですがお金を払って買いました。
エディタ、生成AIは無料で使える好きなもので良いと思います。各種ツールの選び方、使い方はご自身で調べてください。
事前に注意しておきたいこと
pythonやpythonライブラリを事前にインストールしてないと正しいコードを実行してもエラーでます。他にもPC環境が異なることによるエラーが出ることが想定されます。
でも、エラーメッセージを生成AIに投げれば原因がそれらだと判明したりしますし、インストール方法も提示してくれるので無問題。とりあえず始めるのが大事さ、きっと。
2024/11/20現在の状況
MORCHIシーズン1が終了してる現在、エディタでは成功メッセージが出ますが、エクスプローラーではトランザクションが通りません。これは運営がトランザクションを通さないように制御しているからでしょう。
エディタ上だけでも成功すればよい、MORCHI直コンとやらを試してみたい!という特殊な人はこの先にお進みください。
あと、一応言っておくとトランザクションに失敗してもガス代は取られます。(超少額ですが)
実際に生成AIとやりとりしていく
(注意:このパートでのやり取りは生成AIの挙動によって適宜変わります。またプログラミング開発環境は個々のPCで異なります。今回と全く同じシチュエーションで作業が進むことはまずないと思います。その点ご注意ください)
まずは生成AIにこちらが質問したい内容のバックグラウンド、世界観みたいなのを伝えます。
そのために実行したい関数に関わるトランザクションデータを読み取らせます。
MORCHIはPolygonチェーンなのでPolygonスキャン(エクスプローラーってやつ)を開きます。
<https://polygonscan.com/
MORCHIの入っている自身のウォレットアドレスを検索して、餌やり(タスク)実行の関数である【grindAtTheGym, haveAColdShower, chugEnergyDrink】の3つのうちどれか1つのトランザクション(以降Txと表記)※の詳細を見ます。
今回はgrindAtTheGym(画像赤枠)のTx Hash(0Xで始まる数列)をクリックして詳細を見ていきます。
(※事前に手動で餌やりしておかないとこれらの関数が実行されたTxはでてきません。)
アドレスバーをコピーします。
このあと生成AIのページにいきますが、このTx詳細ページは閉じずに開きっぱなしにしておきましょう。(また戻ってきますので)
今回はperplexity AIという生成AIツール(現在は無料で使える)を使います。
perplexity AIにこのような↓プロンプトを投げます。
するとこんな感じ↓の応答が返ってきました。
日付、送信元、送信先、関数の内容、全て間違ってます。
とりあえずUSDCトークンの転送とか意味不明なことを訂正していきましょう。(本当はgrindAtTheGym関数の実行なんですけどね)
先ほど開きっぱなしにしたTx詳細ページにいきます。スクロールして「+ Click to show more」ってところをクリックするとこんな画面になります↓
Input Data:の横にあるFunction: grindAtTheGym(uint256 tokenId)をコピーしときます。(生成AIに投げるときに使うので)
perplexity AIに戻り、彼(彼女?)の間違いをツッコんでいきます。
”読み取りに間違っている部分があります。 USDCの転送は行われていません。 入力データ: Function: grindAtTheGym(uint256 tokenId)”
修正してくれました。
しかし特定のコントラクトの数列が間違ったままです。ここもツッコんでおきましょう。
ツッコむための素材をコピーするために、もう一度Tx詳細ページにいきます。
To:(送信先)の横の数列が生成AIの言ういわゆる「特定のコントラクト」ってやつです。(この特定のコントラクトページはこちら)
ルーターコントラクトってもので、これはかなり重要になってきます。アドレスをコピーします。
すぐ上のFrom:(送信元)のアドレスもコピーします。
perplexity AIに戻り、以下のプロンプトを投げました。
”送信元と送信先も間違っています。
正しくは 送信元: (さっきコピーしたFromアドレス) 送信先: 0xBAB028f7ac84EB4A90BC4eE5c3725437fFbA806e となります”
相変わらずタイムスタンプが変ですが、コントラクトアドレスは修正してくれてます。これで十分です。(タイムスタンプはコードを生成する上で関係ないのでどうでもヨシ)
続いて
”Pythonを使ってこのトランザクションを実行するためのコードを書いてください”
と指示しました。
あとは画像の通りにプロンプトを投げてコードを付け足し生成していきました。
(※Function: haveAColdShower(uint256 tokenId)とFunction: chugEnergyDrink(uint256 tokenId)についての調べ方は、この章序盤のFunction: grindAtTheGym(uint256 tokenId)の調べ方と一緒のやり方です。)
こんな感じでゴテゴテとコードを追加していきましたが、生成AIから「クラウドサーバーを契約した方がよいかもしれません」的なことを言われたので一度仕切り直す(コードをシンプルに書き換える)ことにしました。
(※ちょっとここから先の作業手順の一部を忘れてしまいました。作業に邪魔だと思ったプロンプトは消去しながらの作業だったので記録も途中抜けしています。現在まで開きっぱなしだったperplexity AIタブやエディタのコード、Xの投稿などの状態から当時の状態をできるだけ再現してみますが、それでもある程度の抜け漏れはあると思われます。ご容赦ください)
いろいろと生成AIとの対話を経て(本当にいろいろあった)作ったコードを実行したらトランザクションが通るようになりました!
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 |
from web3 import Web3 # Polygonネットワークの設定 polygon_rpc_url = "https://polygon-rpc.com/" web3 = Web3(Web3.HTTPProvider(polygon_rpc_url)) # アカウント設定 sender_address = "YOUR_WALLET_ADDRESS_HERE" # 注意: 実際のウォレットアドレスを使用してください sender_private_key = "YOUR_PRIVATE_KEY_HERE" # 注意: 実際の秘密鍵を使用してください # コントラクト設定 contract_address = "0xBAB028f7ac84EB4A90BC4eE5c3725437fFbA806e" contract_abi = [ { "inputs": [{"internalType": "uint256", "name": "tokenId", "type": "uint256"}], "name": "grindAtTheGym", "outputs": [], "stateMutability": "nonpayable", "type": "function" }, { "inputs": [{"internalType": "uint256", "name": "tokenId", "type": "uint256"}], "name": "haveAColdShower", "outputs": [], "stateMutability": "nonpayable", "type": "function" }, { "inputs": [{"internalType": "uint256", "name": "tokenId", "type": "uint256"}], "name": "chugEnergyDrink", "outputs": [], "stateMutability": "nonpayable", "type": "function" } ] contract = web3.eth.contract(address=contract_address, abi=contract_abi) # トランザクションパラメータの設定 token_id = 123 # 実際のtokenIdを指定してください gas_price = web3.to_wei('30', 'gwei') gas_limit = 51750 def send_transaction(func_name): nonce = web3.eth.get_transaction_count(sender_address) tx = getattr(contract.functions, func_name)(token_id).build_transaction({ 'chainId': 137, 'gas': gas_limit, 'gasPrice': gas_price, 'nonce': nonce, }) signed_tx = web3.eth.account.sign_transaction(tx, sender_private_key) # ここを修正: rawTransaction を raw_transaction に変更 tx_hash = web3.eth.send_raw_transaction(signed_tx.raw_transaction) tx_receipt = web3.eth.wait_for_transaction_receipt(tx_hash) print(f"{func_name} transaction successful. Hash: {tx_receipt.transactionHash.hex()}") # 3つの関数を順番に実行 functions = ['grindAtTheGym', 'haveAColdShower', 'chugEnergyDrink'] for func in functions: send_transaction(func) # Web3.pyのバージョンを確認 import web3 print(f"Web3.py version: {web3.__version__}") |
(注意:秘密鍵を扱います。実行は捨てアドレスでやるなどして自己責任でお願いします)
「やったぜ!!」
と思ったのも束の間、エクスプローラを見るとchugEnergyDrink関数実行のTxにエラーが出ています。
#MOORCH
とうとうpythonライブラリhttps://t.co/2GT5dJHouwを使った餌やりに成功したぞ!…と思ったらchugEnergyDrinkのトランザクションステータスがfallになってて、こいつだけ失敗しとる。
エディタだと成功してるんだけどね。疲れたから原因追究は後でやろう pic.twitter.com/vE3TDaXtHx
— せんがく(浅学) (@fool_flatfish) September 9, 2024
(ちなみにトランザクションステータスはFallじゃなくてFailです…)
エクスプローラーのエラーメッセージを生成AIに投げると、原因はおそらく
・ガズ代上限の低さ
・Nonce問題
・その他諸々(詳細書くの面倒くさい)
あたりなのではないか、とのこと。
そして私のXの投稿への有識者の方々からのリプ(アドバイス)にも「ガス代の上限が低いんじゃないか?」という指摘が複数ありました。
他にも色々なアドバイスがあり、いろいろ試しているうちにエラーのオンパレード状態に…
#MORCHI
ガス代上げたけどFailになるなぁ
Nonceの問題かな? https://t.co/fRNICFmrjB pic.twitter.com/DLJUaol7JO— せんがく(浅学) (@fool_flatfish) September 10, 2024
ドツボにハマりかけていたのでまた仕切り直すことにしました。
一つのNFTに対する関数実行は成功
一部だけTxが通ったシンプルなコード(さっき上に貼ったやつ)を流用することにしました。
そのままだとまたエラー出るので【gas_limit = 51750】を約3倍の【gas_limit = 160000】にしてみました。
すると全部の関数のTxが正常に通りました!
#MORCHI
餌やり成功した〜✨付け足しすぎてエラー特定が困難になっちゃったので部分的にだがTx成功してた最初のコード(web3モジュールのみ)を流用。
こいつのgas_limitを3倍くらいにしたら全Tx成功。
複数の方にご指摘いただいていたとおりStatus:Failの原因はガス代不足なことが解明 https://t.co/yweAhR04bJ pic.twitter.com/kGamGDdSuS— せんがく(浅学) (@fool_flatfish) September 11, 2024
どうやらいろいろコードを増やしすぎてしたのがよくなかったみたいです。
とりあえずこれでMORCHI1体の餌やり(タスク消化)botはできました。
複数NFTに対する関数実行も成功
次にやりたいのは複数MORCHIの同時餌やり。
生成AIに書いてもらいましょう。
”上記コードは単一のtoken_idで関数を実行するものです。 これを複数のtoken_idで関数を実行するコードに更新することは可能でしょうか?”
ここでいうtoken_idってのはMORCHINFTのidってこと。
この時生成されたコードを試してみると…ちゃんとTxが成功してました。
#MORCHI
複数猫同時餌やり成功✨(最初3つTxエラーはすでに餌やり済みの個体)
今後はレベルアップも自動化したいね。 https://t.co/gZdhVQc1RN pic.twitter.com/WFznmhOiwK— せんがく(浅学) (@fool_flatfish) September 11, 2024
最終的に出来上がったコード
最終的な自動餌やりコードはこちら↓
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 |
# Polygonネットワークの設定 polygon_rpc_url = "https://polygon-rpc.com/" web3 = Web3(Web3.HTTPProvider(polygon_rpc_url)) # アカウント設定 sender_address = "YOUR_WALLET_ADDRESS_HERE" # 注意: 実際のウォレットアドレスを使用してください sender_private_key = "YOUR_PRIVATE_KEY_HERE" # 注意: 実際の秘密鍵を使用してください # コントラクト設定 contract_address = "0xBAB028f7ac84EB4A90BC4eE5c3725437fFbA806e" contract_abi = [ { "inputs": [{"internalType": "uint256", "name": "tokenId", "type": "uint256"}], "name": "grindAtTheGym", "outputs": [], "stateMutability": "nonpayable", "type": "function" }, { "inputs": [{"internalType": "uint256", "name": "tokenId", "type": "uint256"}], "name": "haveAColdShower", "outputs": [], "stateMutability": "nonpayable", "type": "function" }, { "inputs": [{"internalType": "uint256", "name": "tokenId", "type": "uint256"}], "name": "chugEnergyDrink", "outputs": [], "stateMutability": "nonpayable", "type": "function" } ] contract = web3.eth.contract(address=contract_address, abi=contract_abi) # トランザクションパラメータの設定 token_ids = [123, 456, 789] # 複数のtokenIdを指定 gas_price = web3.to_wei('30', 'gwei') gas_limit = 160000 def send_transaction(func_name, token_id): nonce = web3.eth.get_transaction_count(sender_address) tx = getattr(contract.functions, func_name)(token_id).build_transaction({ 'chainId': 137, 'gas': gas_limit, 'gasPrice': gas_price, 'nonce': nonce, }) signed_tx = web3.eth.account.sign_transaction(tx, sender_private_key) tx_hash = web3.eth.send_raw_transaction(signed_tx.raw_transaction) tx_receipt = web3.eth.wait_for_transaction_receipt(tx_hash) print(f"{func_name} transaction for tokenId {token_id} successful. Hash: {tx_receipt.transactionHash.hex()}") # 各token_idに対して3つの関数を順番に実行 functions = ['grindAtTheGym', 'haveAColdShower', 'chugEnergyDrink'] for token_id in token_ids: for func in functions: send_transaction(func, token_id) # Web3.pyのバージョンを確認 import web3 print(f"Web3.py version: {web3.__version__}") |
(注意:生成されたコードが最適なものであるという保証はありません。秘密鍵を扱います。実行は捨てアドレスでやるなどして自己責任でお願いします)
やったぜ!!
後日談:謎のエラー発生
いつも通り餌やりを実行したら…全然成功メッセージがでない…
そしてしばらくしたらタイムエラーメッセージがでて、トランザクションが通らない。
なぜかタイムアウトエラーが出るようになってしまった。
生成AIにエラーメッセージ投げた際の返答の一部↓
”使用している RPC エンドポイントに問題がある可能性があります。別の RPC プロバイダーを試してみることをお勧めします” https://t.co/wiRGy2gzLO pic.twitter.com/9gpqpF3u16— せんがく(浅学) (@fool_flatfish) September 14, 2024
これは困りました。
タイムアウトエラーの他にも
”An RPC error was returned by the node. Check the message provided in the error and any available logs for more information.”
っていうエラーも出ました。
とにかくRPC周りがクセーってことで、RPCプロバイダーを変えるといいのかもしれないと思いました。
”# Polygonネットワークの設定
polygon_rpc_url = "https://polygon-rpc.com/"
↑この【https://polygon-rpc.com/】の部分を変えたい。
詳細は忘れましたが、トランザクションを叩くのにINFURAってところでキーを取得すると便利(ってのをどこかのブログ記事で読んだ)
おかげでキーの準備はできていました。(INFURAが気になる人は各自調べてください)
しかし【https://polygon-rpc.com/】の部分をINFURAで取得したキーに変える前に、ダメ元でもう一度エラーを吐いたコードを実行してみました。すると今度は成功。
一体どういうことなのでしょうか?
どうやらPolygonチェーンに何かしら不具合があったらしく、他のbotterもトランザクションエラーに苦しめられていました。(同じコードを使った人もそうでない人も)
結果として【https://polygon-rpc.com/】をINFURAのものに変更する必要がなくなったわけですが、以降同様のエラーが出たときは試してみるかもしれません。
後日談の後日談
もうちょっと複雑な制御がしたくてmorchi_info内の値を取得するコードを生成してたのにどうしてもうまくいかない。その旨を投稿したら有識者からアドバイスをいただきました!
#MORCHI
なぜか「IndexError: tuple index out of range」ってなるなぁ。morchi_info[0][6]にポイント残高の値入ってるはずなんだけど pic.twitter.com/bkgCXfhJRr
— せんがく(浅学) (@fool_flatfish) September 22, 2024
どうやらmorchi_states関数を呼び出す方法のがこの先のことを考えると適切らしい…。
しかしここまでmorchi_info関数を使った直コン手順を書いてしまったし、アドバイスいただいてから数日経ったらMORCHI直コンへのモチベーションもなくなってしまったので、本記事を書き直すことはしません。(最低限機能するbotはつくれましたし)
もしこの先のレベルに進みたかったらご自身で試してみてください。(とはいえ序盤で書いた通り2024/11/20現在、MORCHIの
シーズン1が終わったのでエクスプローラーの方でfailになりますが)
さいごに(有識者への謝辞)
ネット上の色々な人の投稿や助言があってなんとか目的を達成することができました。
私のX投稿へのリプやDMにてアドバイスをくれた@HatiRoku778916氏、@shinjibusiness氏、@bitcoinvestor氏、@inkyoman_bcg氏、@atarashii_fab氏、@zai_choco氏6名への感謝の意をこの場にて表明させていただきます。
ありがとうございましたm(_ _)m