[Ethereum] 아비트라지를 위한 여정 7편 - SPELL & sSPELL bot

0xDave·2022년 10월 10일
0

Ethereum

목록 보기
39/112

Snowtrace API Key

snowtrace에 가입해서 api 키를 만들 수 있다. 무료로 초당 5회 요청이 가능하다. .env 파일을 만들어서 api key를 저장해두자.


1. Setting

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를 가져온다. 코드를 짜며서 좀 더 직관적으로 짤 수 있게 각 표현방식을 변수로 만들어준다.


2. Bot option

# 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

나중에 편리하게 조작하기 위해 옵션을 설정해둔다.


3. Thresholds & Slippage

# 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

4. Functions

#현재 잔액 가져오기
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

파이썬에서 두 변수가 가리키는 메모리 주소가 같으면 서로의 에일리어스(alias)라고 말한다. list와 dictionary 및 사용자가 정의한 클래스의 경우 어느 한 쪽을 수정했을 때 aliasing 한 다른 변수도 같이 수정되므로 주의할 필요가 있다. brownie에서 set_alias를 통해 컨트랙트에 대한 alias를 설정할 수 있다.

raise

인위적으로 에러를 발생시키고 싶을 때 사용한다. 위 코드에서 except로 함수에 어떤 문제가 발생했을 때 raise로 에러를 발생시킨다.

profile
Just BUIDL :)

0개의 댓글