pythonを用いたBEX@Berachainでのswap
少し前に挑戦はしていたのですが、挫折していたのがberachainのswap。
ここ2回、個人的には結構重いswap案件をこなしたのでそろそろいけるんじゃないかと思い、戻ってきてみると、あっさりできたので報告です。
ちなみに重かったのは以下2つ。
まずはpythonコード
雑に言ってしまうと、DocsのExampleをpythonコードに書き直しただけです。
1WBERA→HONEYにスワップするコードです。
#bera_swap.py
import json
from web3 import Web3
from datetime import datetime
beraRpc = "https://bartio.rpc.berachain.com"
walletAddress = 'my_wallet_address'
walletKey = 'my_private_key'
WBERA = '0x7507c1dc16935B82698e4C63f2746A2fCf994dF8'
HONEY = '0x0E4aaF1351de4c0264C5c7056Ef3777b41BD8e03'
MultiSwapRouter = '0x21e2C0AFd058A89FCf7caf3aEA3cB84Ae977B73D'
gas = 2000000
web3 = Web3(Web3.HTTPProvider(beraRpc))
#Swap Parameters
poolIdx = 36000
base = HONEY
quote = WBERA
isBuy = False
amount = web3.to_wei(1, 'ether')
minOut = 0
with open('bera_MultiSwapRouter_ABI.json') as f:
routerABI = json.load(f)
routerContract = web3.eth.contract(address=MultiSwapRouter, abi=routerABI)
swap_steps = [
{
'poolIdx': poolIdx,
'base': base,
'quote': quote,
'isBuy': isBuy
},
]
now = int(datetime.now().timestamp())
nonce = web3.eth.get_transaction_count(walletAddress)
#MultiSwap function
MultiSwapfunction = routerContract.functions.multiSwap(swap_steps, amount, minOut)
tx = MultiSwapfunction.build_transaction({
'from': walletAddress,
'value': 0,
'gas': gas,
'gasPrice': web3.eth.gas_price,
'nonce': nonce
})
signedTx = web3.eth.account.sign_transaction(tx, walletKey)
txHash = web3.eth.send_raw_transaction(signedTx.raw_transaction)
print('Send Swap transaction')
print(web3.to_hex(txHash))
result = web3.eth.wait_for_transaction_receipt(txHash)
status = result['status']
if status == 1:
print('Swap Succeeded')
else:
print('Swap Failed')
実行結果とトランザクションを貼っておきます。
また、bera_swap.pyと同じディレクトリにbera_MultiSwapRouter_ABI.jsonファイルを作成して、MultiSwapRouterのABIを貼り付けています。
以下のコントラクトのABIです。
説明
さすがにこれで終わり、では何も学びが無いので、このプログラムを作成したときの流れとそこで気が付いたポイントを書いておきます。
まずはpythonプログラムからではなく、WebページからSwapしてみます。
そして、ブロックエクスプローラで確認。
すると、Bera Croc Multi SwapというRouterのmultiSwap関数を使っているということが分かります。
となれば、この関数が必要とする引数とその引数の仕様を確認です。
最初はもちろんここを見ました。
そして、Docsを読みにかかったら(今までも読んではいたのですが今回のページになかなかたどりつけませんでした)、親切なページに出会いました。
冒頭に挙げた2つをこなしてからのこれだったのでさすがに簡単すぎました。
で、ポイントはというと、
WBERAとHONEYをスワップしたいわけですが、どちらをbaseにしてどちらをquoteにするかが意外と大切です。当初逆にしてエラーが出ました。
感覚的には、WBERA→HONEYにスワップするんだったら、
・base(入力)をWBERAにして
・quote(出力)をHONEYにして
・isBuy(売買の方向)を順方向(base→quote):True
にしたい、と思うんです。私もそうしていました。
(根拠のソースまでたどりつけなくて想像になってしまうのですが)、過去の記事でも取り上げたようにDEXのtoken0とtoken1のPoolというのは、token0がどちらでtoken1がどちら、と決まっています。
要は、token0がWBERAでtoken1がHONEYのPool1とtoken0がHONEYでtoken1がWBERAのPool2があるわけではなくて、WBERAとHONEYのPoolと言われれば一つしかありません(2つ作ることも技術的には可能ですが効率が悪いですよね?)。なので、token0がHONEY、token1がWBERAと決まっていてbaseがtoken0みたいなもの、quoteがtoken1みたいなもの、ということだから、逆にするとエラーするんだ、と解釈しました。
なので、WBERAをHONEYにスワップする場合は、
・base(入力)をHONEYにして
・quote(出力)をWBERAにして
・isBuy(売買の方向)を逆方向(base←quote):False
と考えることになるというように私は解釈しました。
ちなみに、逆方向スワップのコード
15HONEY→WBERAにスワップするコードも載せておきます。
isBuyをTrue
amountをweb3.to_wei(15, 'ether')
に変更するだけです。
import json
from web3 import Web3
from datetime import datetime
beraRpc = "https://bartio.rpc.berachain.com"
walletAddress = 'my_wallet_address'
walletKey = 'my_private_key'
WBERA = '0x7507c1dc16935B82698e4C63f2746A2fCf994dF8'
HONEY = '0x0E4aaF1351de4c0264C5c7056Ef3777b41BD8e03'
MultiSwapRouter = '0x21e2C0AFd058A89FCf7caf3aEA3cB84Ae977B73D'
gas = 2000000
web3 = Web3(Web3.HTTPProvider(beraRpc))
#Swap Parameters
poolIdx = 36000
base = HONEY
quote = WBERA
isBuy = True
amount = web3.to_wei(15, 'ether')
minOut = 0
with open('bera_MultiSwapRouter_ABI.json') as f:
routerABI = json.load(f)
routerContract = web3.eth.contract(address=MultiSwapRouter, abi=routerABI)
swap_steps = [
{
'poolIdx': poolIdx,
'base': base,
'quote': quote,
'isBuy': isBuy
},
]
now = int(datetime.now().timestamp())
nonce = web3.eth.get_transaction_count(walletAddress)
#MultiSwap function
MultiSwapfunction = routerContract.functions.multiSwap(swap_steps, amount, minOut)
tx = MultiSwapfunction.build_transaction({
'from': walletAddress,
'value': 0,
'gas': gas,
'gasPrice': web3.eth.gas_price,
'nonce': nonce
})
signedTx = web3.eth.account.sign_transaction(tx, walletKey)
txHash = web3.eth.send_raw_transaction(signedTx.raw_transaction)
print('Send Swap transaction')
print(web3.to_hex(txHash))
result = web3.eth.wait_for_transaction_receipt(txHash)
status = result['status']
if status == 1:
print('Swap Succeeded')
else:
print('Swap Failed')
実行結果とトランザクションです。