Skip to content

Commit

Permalink
added auto-approvals and a simple rebalancing function
Browse files Browse the repository at this point in the history
  • Loading branch information
jwarmuz99 committed May 28, 2024
1 parent 7d5f882 commit 4f6f770
Show file tree
Hide file tree
Showing 15 changed files with 89 additions and 32 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
from dotenv import find_dotenv, load_dotenv
import logging

from giza_actions.integrations.uniswap.uniswap import Uniswap
from giza.agents.integrations.uniswap.uniswap import Uniswap

load_dotenv(find_dotenv())
dev_passphrase = os.environ.get("DEV_PASSPHRASE")
Expand Down Expand Up @@ -44,7 +44,7 @@
token0.deposit(value=int(1e18), sender=sender)
token0_balance = token0.balanceOf(sender)
logger.info(f"--------- Balances before swap: {token0_balance} {token1.balanceOf(sender)}")
token0.approve(uni.router.contract, token0_balance, sender=sender)
# token0.approve(uni.router.contract, token0_balance, sender=sender)
uni.swap_exact_input_single(
token0_balance, token_in=token0, token_out=token1, fee=fee
)
Expand All @@ -55,7 +55,7 @@
token0_amount_out = int(1e16) # 0.01 eth
accepted_slippage = 0.01 # 1%
amount_in_max = int(token1.balanceOf(sender) * (1 - accepted_slippage))
uni.swap_exact_output_single(
tx = uni.swap_exact_output_single(
token0_amount_out,
token_in=token1,
token_out=token0,
Expand All @@ -67,16 +67,16 @@
)

### NFT Manager ###
token0.approve(uni.nft_manager.contract, token0.balanceOf(sender), sender=sender)
token1.approve(uni.nft_manager.contract, token1.balanceOf(sender), sender=sender)
# token0.approve(uni.nft_manager.contract, token0.balanceOf(sender), sender=sender)
# token1.approve(uni.nft_manager.contract, token1.balanceOf(sender), sender=sender)
user_positions = uni.get_all_user_positions()
logger.info(f"--------- User Positions Init: {user_positions}")
amount0_to_mint = int(0.5 * token0.balanceOf(sender))
amount1_to_mint = int(0.5 * token1.balanceOf(sender))
price = pool.get_pool_price(invert=True)
price = pool.get_pool_price()
pct_dev = 0.1
lower_price = int(price * (1 - pct_dev))
upper_price = int(price * (1 + pct_dev))
lower_price = price * (1 - pct_dev)
upper_price = price * (1 + pct_dev)
uni.mint_position(
pool,
lower_price,
Expand All @@ -90,8 +90,9 @@
slippage_tolerance=1,
)
user_positions = uni.get_all_user_positions()
price = pool.get_pool_price()
logger.info(f"--------- User Positions after minting: {user_positions}")
nft_id = user_positions[0]
nft_id = user_positions[-1]
pos_info = uni.get_pos_info(nft_id)
logger.info(f"--------- {nft_id} Info: {pos_info}")
increase_fraction = 0.1
Expand All @@ -102,6 +103,15 @@
)
pos_info = uni.get_pos_info(nft_id)
logger.info(f"--------- {nft_id} Info Add Liq: {pos_info}")
price = pool.get_pool_price()
pct_dev = 0.5
lower_price = price * (1 - pct_dev)
upper_price = price * (1 + pct_dev)
uni.rebalance_lp(nft_id, lower_price, upper_price)
user_positions = uni.get_all_user_positions()
nft_id = user_positions[-1]
pos_info = uni.get_pos_info(nft_id)
logger.info(f"--------- {nft_id} Info after rebalance: {pos_info}")
uni.close_position(nft_id)
user_positions = uni.get_all_user_positions()
logger.info(f"--------- {nft_id} Burnt, user_pos: {user_positions}")
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,9 @@

from ape import Contract

from giza_actions.integrations.uniswap.constants import MAX_UINT_128
from giza_actions.integrations.uniswap.utils import (
from giza.agents.integrations.uniswap.constants import MAX_UINT_128
from giza.agents.integrations.uniswap.pool import Pool
from giza.agents.integrations.uniswap.utils import (
calc_amount0,
calc_amount1,
liquidity0,
Expand Down Expand Up @@ -82,8 +83,18 @@ def add_liquidity(
amount1Min: int = 0,
deadline: int = None,
):
pos = self.contract.positions(nft_id)
token0 = Contract(pos["token0"], abi=os.path.join(os.path.dirname(__file__), "assets/erc20.json"))
token1 = Contract(pos["token1"], abi=os.path.join(os.path.dirname(__file__), "assets/erc20.json"))
# give allowances if needed
if amount0Desired > token0.allowance(self.sender, self.contract.address):
token0.approve(self.contract.address, amount0Desired, sender=self.sender)
if amount1Desired > token1.allowance(self.sender, self.contract.address):
token1.approve(self.contract.address, amount1Desired, sender=self.sender)

if deadline is None:
deadline = int(time.time() + 60)

receipt = self.contract.increaseLiquidity(
(nft_id, amount0Desired, amount1Desired, amount0Min, amount1Min, deadline),
sender=self.sender,
Expand All @@ -105,10 +116,12 @@ def mint_position(
):
fee = pool.fee
token0 = pool.token0
token0_decimals = token0.decimals()
token1 = pool.token1
token1_decimals = token1.decimals()

lower_tick = price_to_tick(lower_price)
upper_tick = price_to_tick(upper_price)
lower_tick = price_to_tick(lower_price, token0_decimals, token1_decimals)
upper_tick = price_to_tick(upper_price, token0_decimals, token1_decimals)
lower_tick = nearest_tick(lower_tick, fee)
upper_tick = nearest_tick(upper_tick, fee)

Expand All @@ -124,6 +137,11 @@ def mint_position(
amount0 = calc_amount0(liq, sqrtp_upp, sqrtp_cur)
amount1 = calc_amount1(liq, sqrtp_low, sqrtp_cur)

if amount0 > token0.allowance(self.sender, self.contract.address):
token0.approve(self.contract.address, amount0, sender=self.sender)
if amount1 > token1.allowance(self.sender, self.contract.address):
token1.approve(self.contract.address, amount1, sender=self.sender)

if recipient is None:
recipient = self.sender
if deadline is None:
Expand All @@ -146,4 +164,6 @@ def mint_position(
"recipient": recipient,
"deadline": deadline,
}

return self.contract.mint(mint_params, sender=self.sender)

Original file line number Diff line number Diff line change
Expand Up @@ -2,16 +2,14 @@

from ape import Contract, chain

from giza_actions.integrations.uniswap.utils import tick_to_price
from giza.agents.integrations.uniswap.utils import tick_to_price


class Pool:
def __init__(
self,
address: str,
sender: str,
token0: str = None,
token1: str = None,
fee: int = None,
):
self.contract = Contract(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

from ape import Contract

from giza_actions.integrations.uniswap.pool import Pool
from giza.agents.integrations.uniswap.pool import Pool


class PoolFactory:
Expand All @@ -17,7 +17,7 @@ def get_pool(self, token0: str, token1: str, fee: int):
if type(fee) == float:
fee = int(fee * 1e6)
pool_address = self.contract.getPool(token0, token1, fee)
return Pool(pool_address, self.sender, token0=token0, token1=token1, fee=fee)
return Pool(pool_address, self.sender)

def create_pool(self, token0: str, token1: str, fee: int):
if type(fee) == float:
Expand Down
File renamed without changes.
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@

from ape import Contract

from giza_actions.integrations.uniswap.pool import Pool
from giza.agents.integrations.uniswap.pool import Pool


class Router:
Expand All @@ -24,8 +24,6 @@ def swap_exact_input_single(
sqrt_price_limit_x96: int = 0,
deadline: int = None,
):
if deadline is None:
deadline = int(time.time()) + 60

if pool is None and (token_in is None or token_out is None or fee is None):
raise Exception("Must provide pool or token_in, token_out, and fee")
Expand All @@ -35,10 +33,19 @@ def swap_exact_input_single(
token_out = pool.token1 if token_out is None else token_out
fee = pool.fee if fee is None else fee

if type(token_in)==str:
token_in = Contract(token_in, abi=os.path.join(os.path.dirname(__file__), "assets/erc20.json"))

if amount_in > token_in.allowance(self.sender, self.contract.address):
token_in.approve(self.contract.address, amount_in, sender=self.sender)

# TODO:
# add slippage and pool price impact protection
# if amount_out_min or sqrt_price_limit_x96 are floats

if deadline is None:
deadline = int(time.time()) + 60

swap_params = {
"tokenIn": token_in,
"tokenOut": token_out,
Expand Down
Original file line number Diff line number Diff line change
@@ -1,11 +1,12 @@
from ape import chain
from ape import chain, Contract
import os

from giza_actions.integrations.uniswap.constants import ADDRESSES, MAX_UINT_128
from giza_actions.integrations.uniswap.nft_manager import NFTManager
from giza_actions.integrations.uniswap.pool import Pool
from giza_actions.integrations.uniswap.pool_factory import PoolFactory
from giza_actions.integrations.uniswap.quoter import Quoter
from giza_actions.integrations.uniswap.router import Router
from giza.agents.integrations.uniswap.constants import ADDRESSES, MAX_UINT_128
from giza.agents.integrations.uniswap.nft_manager import NFTManager
from giza.agents.integrations.uniswap.pool import Pool
from giza.agents.integrations.uniswap.pool_factory import PoolFactory
from giza.agents.integrations.uniswap.quoter import Quoter
from giza.agents.integrations.uniswap.router import Router


class Uniswap:
Expand Down Expand Up @@ -133,6 +134,28 @@ def mint_position(
slippage_tolerance=slippage_tolerance,
)

def rebalance_lp(
self,
nft_id: int,
lower_price: float,
upper_price: float,
amount0Min: int = None,
amount1Min: int = None,
recipient: str = None,
deadline: int = None,
slippage_tolerance: float = 1,
):
pos = self.nft_manager.contract.positions(nft_id)
pool = self.get_pool(pos["token0"], pos["token1"], pos["fee"])

token0 = Contract(pos["token0"], abi=os.path.join(os.path.dirname(__file__), "assets/erc20.json"))
token1 = Contract(pos["token1"], abi=os.path.join(os.path.dirname(__file__), "assets/erc20.json"))
self.nft_manager.close_position(nft_id)
amount0 = token0.balanceOf(self.sender)
amount1 = token1.balanceOf(self.sender)
return self.nft_manager.mint_position(pool, lower_price, upper_price, amount0, amount1, amount0Min= amount0Min, amount1Min=amount1Min, recipient=recipient, deadline=deadline, slippage_tolerance=slippage_tolerance)


def quote_exact_input_single(
self,
amount_in: int,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@

from ape import Contract

from giza_actions.integrations.uniswap.constants import (
from giza.agents.integrations.uniswap.constants import (
MAX_TICK,
MIN_TICK,
Q96,
Expand All @@ -16,9 +16,8 @@ def load_contract(address):
return Contract(address)


def price_to_tick(price):
sqrtPriceX96 = int(price * 2**96)
tick = math.floor(math.log((sqrtPriceX96 / Q96) ** 2) / math.log(TICKS_Q))
def price_to_tick(price, decimals0, decimals1):
tick = math.floor(math.log(price * 10**(decimals1 - decimals0), TICKS_Q))
return tick


Expand Down

0 comments on commit 4f6f770

Please sign in to comment.