snowtrace에 가입해서 api 키를 만들 수 있다. 무료로 초당 5회 요청이 가능하다. .env
파일을 만들어서 api key를 저장해두자.
import sys
import time
import datetime
import requests
import os
from brownie import *
from dotenv import load_dotenv
# Contract addresses (verify on Snowtrace)
TRADERJOE_ROUTER_CONTRACT_ADDRESS = "0x60aE616a2155Ee3d9A68541Ba4544862310933d4"
SPELL_CONTRACT_ADDRESS = "0xce1bffbd5374dac86a2893119683f4911a2f7814"
SSPELL_CONTRACT_ADDRESS = "0x3ee97d514bbef95a2f110e6b9b73824719030f7a"
# Change to match your API key from Snowtrace
load_dotenv()
os.environ["SNOWTRACE_TOKEN"] = os.environ.get("SNOWTRACE_API_KEY")
#Helper Values
SECOND = 1
MINUTE = 60 * SECOND
HOUR = 60 * MINUTE
DAY = 24 * HOUR
PERCENT = 0.01
컨트랙트 주소는 바뀔 일이 없으므로 Constant 값으로 넣어주고, env에 저장해놨던 snowtrace api key를 가져온다. 코드를 짜며서 좀 더 직관적으로 짤 수 있게 각 표현방식을 변수로 만들어준다.
# Simulate swaps and approvals
DRY_RUN = False
# Quit after the first successful trade
ONE_SHOT = False
# How often to run the main loop (in seconds)
LOOP_TIME = 1.0
나중에 편리하게 조작하기 위해 옵션을 설정해둔다.
# SPELL -> sSPELL swap targets
# a zero value will trigger a swap when the ratio matches base_staking_rate exactly
# a negative value will trigger a swap when the rate is below base_staking_rate
# a positive value will trigger a swap when the rate is above base_staking_rate
THRESHOLD_SPELL_TO_SSPELL = 0.2 * PERCENT
# sSPELL -> SPELL swap targets
# a positive value will trigger a (sSPELL -> SPELL) swap when the ratio is above base_staking_rate
THRESHOLD_SSPELL_TO_SPELL = 1.2 * PERCENT
# tolerated slippage in swap price (used to calculate amountOutMin)
SLIPPAGE = 0.1 * PERCENT
#현재 잔액 가져오기
def account_get_balance(account):
try:
return account.balance()
except Exception as e:
print(f"Exception in account_get_balance: {e}")
#컨트랙트 가져오기. 없을 경우 다시 할당해서 가져온다.
def contract_load(address, alias):
# Attempts to load the saved contract by alias.
# If not found, fetch from network explorer and set alias.
try:
contract = Contract(alias)
except ValueError:
contract = Contract.from_explorer(address)
contract.set_alias(alias)
finally:
print(f"• {alias}")
return contract
## 위임된 권한 확인
def get_approval(token, router, user):
try:
return token.allowance.call(user, router.address)
except Exception as e:
print(f"Exception in get_approval: {e}")
return False
#토큰 이름 가져오기
def get_token_name(token):
try:
return token.name.call()
except Exception as e:
print(f"Exception in get_token_name: {e}")
raise
#토큰 심볼 가져오기
def get_token_symbol(token):
try:
return token.symbol.call()
except Exception as e:
print(f"Exception in get_token_symbol: {e}")
raise
#토큰 보유량 가져오기
def get_token_balance(token, user):
try:
return token.balanceOf.call(user)
except Exception as e:
print(f"Exception in get_token_balance: {e}")
raise
#토큰 decimal 가져오기
def get_token_decimals(token):
try:
return token.decimals.call()
except Exception as e:
print(f"Exception in get_token_decimals: {e}")
raise
#router에게 권한 위임(default == unlimited)
def token_approve(token, router, value="unlimited"):
if DRY_RUN:
return True
if value == "unlimited":
try:
token.approve(
router,
2 ** 256 - 1,
{"from": user},
)
return True
except Exception as e:
print(f"Exception in token_approve: {e}")
raise
else:
try:
token.approve(
router,
value,
{"from": user},
)
return True
except Exception as e:
print(f"Exception in token_approve: {e}")
raise
#스왑 비율 확인
def get_swap_rate(token_in_quantity, token_in_address, token_out_address, router):
try:
return router.getAmountsOut(
token_in_quantity, [token_in_address, token_out_address]
)
except Exception as e:
print(f"Exception in get_swap_rate: {e}")
return False
def token_swap(
token_in_quantity,
token_in_address,
token_out_quantity,
token_out_address,
router,
):
if DRY_RUN:
return True
try:
router.swapExactTokensForTokens(
token_in_quantity,
int(token_out_quantity * (1 - SLIPPAGE)),
[token_in_address, token_out_address],
user.address,
int(1000 * (time.time()) + 30 * SECOND),
{"from": user},
)
return True
except Exception as e:
print(f"Exception: {e}")
return False
함수는 최대한 재사용할 수 있도록 설계한다.
파이썬에서 두 변수가 가리키는 메모리 주소가 같으면 서로의 에일리어스(alias)라고 말한다. list와 dictionary 및 사용자가 정의한 클래스의 경우 어느 한 쪽을 수정했을 때 aliasing 한 다른 변수도 같이 수정되므로 주의할 필요가 있다. brownie에서 set_alias
를 통해 컨트랙트에 대한 alias를 설정할 수 있다.
인위적으로 에러를 발생시키고 싶을 때 사용한다. 위 코드에서 except
로 함수에 어떤 문제가 발생했을 때 raise
로 에러를 발생시킨다.