Skip to content
Open
4 changes: 3 additions & 1 deletion .vscode/settings.json
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
{
"python.envFile": "${workspaceFolder}/.env"
"python.envFile": "${workspaceFolder}/.env",
"editor.tabSize": 4,
"editor.insertSpaces": true
}
Empty file.
28 changes: 28 additions & 0 deletions packages/eth_protocols/src/eth_protocols/gmx/datastore.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
from typing import Literal

from eth_typing import HexAddress
from eth_rpc.types.primitives import bytes32
from pydantic import BaseModel, Field, PrivateAttr

from eth_typeshed.gmx import GMXEnvironment, Datastore as DatastoreContract

PRECISION = 30


class Datastore(BaseModel):
network: Literal["arbitrum", "avalanche"] = Field(default="arbitrum")
_environment: GMXEnvironment = PrivateAttr()
_contract: DatastoreContract = PrivateAttr()

@property
def address(self) -> HexAddress:
return self._environment.datastore

def model_post_init(self, __context):
super().model_post_init(__context)

self._environment = GMXEnvironment.get_environment(self.network)
self._contract = DatastoreContract[self.network_type](address=self._environment.datastore)

async def get_uint(self, key: bytes32) -> int:
return await self._contract.get_uint(key).get()
51 changes: 51 additions & 0 deletions packages/eth_protocols/src/eth_protocols/gmx/exchange_router.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
from typing import Literal

from eth_rpc import PrivateKeyWallet
from eth_rpc.networks import Arbitrum, Avalanche
from eth_typeshed.gmx import GMXEnvironment, ExchangeRouter as ExchangeRouterContract
from eth_typeshed.gmx.exchange_router import CreateDepositParams
from eth_typing import HexAddress, HexStr
from pydantic import BaseModel, Field, PrivateAttr
from .loaders import MarketsLoader


class ExchangeRouter(BaseModel):
network: Literal["arbitrum", "avalanche"] = Field(default="arbitrum")
_environment: GMXEnvironment = PrivateAttr()
_contract: ExchangeRouterContract

@property
def network_type(self) -> type[Arbitrum] | type[Avalanche]:
return Arbitrum if self.network == "arbitrum" else Avalanche

def model_post_init(self, __context):
super().model_post_init(__context)

self._environment = GMXEnvironment.get_environment(self.network)
self._contract = ExchangeRouterContract[self.network_type](address=self._environment.exchange_router)

async def load_markets(self):
self.all_markets_info = MarketsLoader(network=self.network).get_available_markets()

def encode_send_tokens(self, token_address: HexAddress, amount: int) -> bytes:
return self._contract.send_tokens(
token_address,
HexAddress(HexStr('0xF89e77e8Dc11691C9e8757e84aaFbCD8A67d7A55')),
amount,
).encode()

def encode_send_wnt(self, amount: int) -> bytes:
return self._contract.send_wnt(
HexAddress(HexStr('0xF89e77e8Dc11691C9e8757e84aaFbCD8A67d7A55')),
amount,
).encode()

def encode_create_deposit(self, params: CreateDepositParams):
return self._contract.create_deposit(
params,
).encode()

async def multicall(self, calls: list[bytes], wallet: PrivateKeyWallet, **kwargs):
return await self._contract.multicall(
calls,
).execute(wallet, **kwargs)
54 changes: 54 additions & 0 deletions packages/eth_protocols/src/eth_protocols/gmx/executors/approve.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
from eth_typing import HexAddress, HexStr

from eth_rpc import PrivateKeyWallet
from eth_rpc.utils import to_checksum
from eth_typeshed.erc20 import ERC20, OwnerSpenderRequest, ApproveRequest


async def check_if_approved(
wallet: PrivateKeyWallet,
spender: HexAddress,
token: HexAddress,
amount: int,
max_fee_per_gas: int | None = None,
approve: bool = True,
):
if token == "0x47904963fc8b2340414262125aF798B9655E58Cd":
token = HexAddress(HexStr("0x2f2a2543B76A4166549F7aaB2e75Bef0aefC5B0f"))

token_checksum_address = to_checksum(token)

# TODO - for AVAX support this will need to incl WAVAX address
if token_checksum_address == "0x82aF49447D8a07e3bd95BD0d56f35241523fBab1":
balance_of = await wallet.balance()
else:
balance_of = await ERC20(address=token).balance_of(wallet.address).get()

if balance_of < amount:
raise Exception("Insufficient balance!")

amount_approved = await ERC20(address=token).allowance(
OwnerSpenderRequest(owner=wallet.address, spender=spender)
).get()

print("Checking coins for approval..")
if amount_approved < amount and approve:
print('Approving contract "{}" to spend {} tokens belonging to token address: {}'.format(
spender, amount, token_checksum_address))

txn_hash = await ERC20(address=token).approve(
ApproveRequest(
spender=spender,
amount=amount,
)
).execute(wallet, max_fee_per_gas=max_fee_per_gas)

print("Txn submitted!")
print("Check status: https://arbiscan.io/tx/{}".format(txn_hash))

if amount_approved < amount and not approve:
raise Exception("Token not approved for spend, please allow first!")

print('Contract "{}" approved to spend {} tokens belonging to token address: {}'.format(
spender, amount, token_checksum_address))
print("Coins Approved for spend!")
Loading