>>> lp = Contract.from_explorer('0x033c3fc1fc13f803a233d262e24d1ec3fd4efb48')
>>> lp.token0()
'0x3Ee97d514BBef95a2f110e6B9b73824719030f7a'
>>> lp.token1()
'0xCE1bFFBD5374Dac86a2893119683F4911a2F7814'
>>> Contract.from_explorer(lp.token0()).symbol()
'sSPELL'
>>> Contract.from_explorer(lp.token1()).symbol()
'SPELL'
sSPELL과 SPELL의 LP 풀을 가져왔다.
function getReserves()
public
view
returns (
uint112 _reserve0,
uint112 _reserve1,
uint32 _blockTimestampLast
)
{
_reserve0 = reserve0;
_reserve1 = reserve1;
_blockTimestampLast = blockTimestampLast;
}
trader Joe LP 풀의 컨트랙트에는 getReserves()
라는 함수가 있는데 유니스왑V2에서 가져온 것 같다.
time을 import하고 가장 마지막 리턴 값을 빼면 풀이 변동 되고나서 얼마나 지났는지 알 수 있다. 초 단위로 표시되기 때문에 현재 약 33시간 정도 지난 것을 알 수 있다.(짜게 식은 spell..)
>>> lp.getReserves()
(1353632461902232159063440, 1852835505753373256745497, 1667635790)
>>> import time
>>> int(time.time()) - lp.getReserves()[-1]
120280
아래와 같은 방법으로 풀에 해당 토큰이 얼마나 있는지 알 수 있다.
>>> x0, y0 = lp.getReserves()[0:2]
>>> x0
1353632461902232159063440
>>> y0
1852835505753373256745497
dx만큼의 토큰(token0)을 풀을 예치할 때 dy만큼 토큰(token1)을 얻을 수 있다. X * Y = K
공식을 조금만 이용하면 된다.
x0y0 = (x0 + dx(1-fee))*(y0 - dy)
예치량인 dx에 수수료를 곱해준다. 이 식을 정리하면 dy 값을 구할 수 있다.
dy = y0dx(1-fee) / (x0 + dx*(1-fee))
반대의 경우도 같은 방법으로 구할 수 있다.
x0y0 = (x0 - dx)(y0 + dy*(1-fee))
이 식을 정리하면 dy 값이 나온다.
dx = x0dy(1-fee) / (y0 + dy*(1-fee))
def get_tokens_out_from_tokens_in(
pool_reserves_token0,
pool_reserves_token1,
quantity_token0_in=0,
quantity_token1_in=0,
fee=0,
):
# fails if two input tokens are passed, or if both are 0
assert not (quantity_token0_in and quantity_token1_in)
assert quantity_token0_in or quantity_token1_in
if quantity_token0_in:
return (pool_reserves_token1 * quantity_token0_in * (1 - fee)) // (
pool_reserves_token0 + quantity_token0_in * (1 - fee)
)
if quantity_token1_in:
return (pool_reserves_token0 * quantity_token1_in * (1 - fee)) // (
pool_reserves_token1 + quantity_token1_in * (1 - fee)
)
import sys
import time
import os
from brownie import *
from decimal import Decimal
# Change to match your explorer API key
SNOWTRACE_API_KEY = "XXX"
# Contract addresses
TRADERJOE_ROUTER_CONTRACT_ADDRESS = "0x60aE616a2155Ee3d9A68541Ba4544862310933d4"
TOKEN_POOL_CONTRACT_ADDRESS = "0x033C3Fc1fC13F803A233D262e24d1ec3fd4EFB48"
os.environ["SNOWTRACE_TOKEN"] = SNOWTRACE_API_KEY
def get_tokens_out_from_tokens_in(
pool_reserves_token0,
pool_reserves_token1,
quantity_token0_in=0,
quantity_token1_in=0,
fee=0,
):
# fails if two input tokens are passed, or if both are 0
assert not (quantity_token0_in and quantity_token1_in)
assert quantity_token0_in or quantity_token1_in
if quantity_token0_in:
return (pool_reserves_token1 * quantity_token0_in * (1 - fee)) // (
pool_reserves_token0 + quantity_token0_in * (1 - fee)
)
if quantity_token1_in:
return (pool_reserves_token0 * quantity_token1_in * (1 - fee)) // (
pool_reserves_token1 + quantity_token1_in * (1 - fee)
)
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_swap_rate(token_in_quantity, token_in_address, token_out_address, contract):
try:
return contract.getAmountsOut(
token_in_quantity, [token_in_address, token_out_address]
)
except Exception as e:
print(f"Exception in get_swap_rate: {e}")
return False
try:
network.connect("avax-main")
except:
sys.exit(
"Could not connect to Avalanche! Verify that brownie lists the Avalanche Mainnet using 'brownie networks list'"
)
print("\nContracts loaded:")
lp = contract_load(TOKEN_POOL_CONTRACT_ADDRESS, "TraderJoe LP: SPELL-sSPELL")
router = contract_load(TRADERJOE_ROUTER_CONTRACT_ADDRESS, "TraderJoe: Router")
token0 = Contract.from_explorer(lp.token0.call())
token1 = Contract.from_explorer(lp.token1.call())
print()
print(f"token0 = {token0.symbol.call()}")
print(f"token1 = {token1.symbol.call()}")
print()
print("*** Getting Pool Reserves *** ")
x0, y0 = lp.getReserves.call()[0:2]
print(f"token0: \t\t\t{x0}")
print(f"token1: \t\t\t{y0}")
print()
print("*** Calculating hypothetical swap: 500,000 SPELL to sSPELL @ 0.3% fee ***")
quote = router.getAmountsOut(500_000 * (10 ** 18), [token1.address, token0.address])[-1]
tokens_out = get_tokens_out_from_tokens_in(
pool_reserves_token0=x0,
pool_reserves_token1=y0,
quantity_token1_in=500_000 * (10 ** 18),
fee=Decimal("0.003"),
)
print()
print(f"Calculated Tokens Out: \t\t{tokens_out}")
print(f"Router Quoted getAmountsOut: \t{quote}")
print(f"Difference: \t\t\t{quote - tokens_out}")
print()
print("*** Calculating hypothetical swap: 500,000 sSPELL to SPELL @ 0.3% fee ***")
quote = router.getAmountsOut(
500_000 * (10 ** 18),
[token0.address, token1.address],
)[-1]
tokens_out = get_tokens_out_from_tokens_in(
pool_reserves_token0=x0,
pool_reserves_token1=y0,
quantity_token0_in=500_000 * (10 ** 18),
fee=Decimal("0.003"),
)
print()
print(f"Calculated Tokens Out: \t\t{tokens_out}")
print(f"Router Quoted getAmountsOut: \t{quote}")
print(f"Difference: \t\t\t{quote - tokens_out}")