diff --git a/.gitignore b/.gitignore index 400ea89..6afae43 100644 --- a/.gitignore +++ b/.gitignore @@ -114,6 +114,6 @@ ENV/ site/ .history -trader +*trader node_modules diff --git a/lyra/cli.py b/lyra/cli.py index 3b8f753..09aa460 100644 --- a/lyra/cli.py +++ b/lyra/cli.py @@ -39,7 +39,10 @@ def set_client(ctx): env = Environment.PROD else: env = Environment.TEST - ctx.client = LyraClient(**auth, env=env) + + subaccount_id = os.environ.get("SUBACCOUNT_ID") + wallet = os.environ.get("WALLET") + ctx.client = LyraClient(**auth, env=env, subaccount_id=subaccount_id, wallet=wallet) if ctx.logger.level == "DEBUG": print(f"Client created for environment `{ctx.client.env.value}`") diff --git a/lyra/constants.py b/lyra/constants.py index 6855e6d..73619ca 100644 --- a/lyra/constants.py +++ b/lyra/constants.py @@ -19,5 +19,10 @@ Environment.PROD: { "BASE_URL": "https://api.lyra.finance", "WS_ADDRESS": "wss://api.lyra.finance/ws", + "ACTION_TYPEHASH": '0x4d7a9f27c403ff9c0f19bce61d76d82f9aa29f8d6d4b0c5474607d9770d1af17', + "DOMAIN_SEPARATOR": '0xd96e5f90797da7ec8dc4e276260c7f3f87fedf68775fbe1ef116e996fc60441b', + "ETH_PERP_ADDRESS": '0xAf65752C4643E25C02F693f9D4FE19cF23a095E3', + "BTC_PERP_ADDRESS": '0xDBa83C0C654DB1cd914FA2710bA743e925B53086', + "TRADE_MODULE_ADDRESS": '0xB8D20c2B7a1Ad2EE33Bc50eF10876eD3035b5e7b', }, } diff --git a/lyra/lyra.py b/lyra/lyra.py index bac7d1d..ff52ed3 100644 --- a/lyra/lyra.py +++ b/lyra/lyra.py @@ -27,7 +27,9 @@ def to_32byte_hex(val): class LyraClient: """Client for the lyra dex.""" - def _create_signature_headers(self): + def _create_signature_headers( + self, + ): """ Create the signature headers """ @@ -35,14 +37,14 @@ def _create_signature_headers(self): msg = encode_defunct( text=timestamp, ) - signature = self.wallet.sign_message(msg) + signature = self.signer.sign_message(msg) return { - "X-LyraWallet": self.wallet.address, + "X-LyraWallet": self.wallet, "X-LyraTimestamp": timestamp, "X-LyraSignature": Web3.to_hex(signature.signature), } - def __init__(self, private_key, env, logger=None, verbose=False, subaccount_id=None): + def __init__(self, private_key, env, logger=None, verbose=False, subaccount_id=None, wallet=None): """ Initialize the LyraClient class. """ @@ -51,9 +53,15 @@ def __init__(self, private_key, env, logger=None, verbose=False, subaccount_id=N self.contracts = CONTRACTS[env] self.logger = logger or get_logger() self.web3_client = Web3() - self.wallet = self.web3_client.eth.account.from_key(private_key) + self.signer = self.web3_client.eth.account.from_key(private_key) + self.wallet = self.signer.address if not wallet else wallet + print(f"Signing address: {self.signer.address}") + if wallet: + print(f"Using wallet: {wallet}") if not subaccount_id: - self.subaccount_id = self.fetch_subaccounts(self.wallet.address)['subaccount_ids'][0] + self.subaccount_id = self.fetch_subaccounts()['subaccount_ids'][0] + else: + self.subaccount_id = subaccount_id def create_account(self, wallet): """Call the create account endpoint.""" @@ -91,12 +99,12 @@ def fetch_instruments( results = response.json()["result"] return results - def fetch_subaccounts(self, wallet=None): + def fetch_subaccounts(self): """ Returns the subaccounts for a given wallet """ url = f"{self.contracts['BASE_URL']}/private/get_subaccounts" - payload = {"wallet": wallet if wallet else self.wallet.address} + payload = {"wallet": self.wallet} headers = self._create_signature_headers() response = requests.post(url, json=payload, headers=headers) results = json.loads(response.content)["result"] @@ -167,7 +175,7 @@ def _define_order( 'signature_expiry_sec': int(ts) + 3000, 'max_fee': '200.01', 'nonce': int(f"{int(ts)}{random.randint(100, 999)}"), - 'signer': self.wallet.address, + 'signer': self.signer.address, 'order_type': 'limit', 'mmp': False, 'signature': 'filled_in_below', @@ -187,10 +195,10 @@ def sign_authentication_header(self): text=timestamp, ) signature = self.web3_client.eth.account.sign_message( - msg, private_key=self.wallet._private_key + msg, private_key=self.signer._private_key ).signature.hex() # pylint: disable=protected-access return { - 'wallet': self.wallet.address, + 'wallet': self.wallet, 'timestamp': str(timestamp), 'signature': signature, } @@ -210,6 +218,8 @@ def login_client(self, ws): while True: message = json.loads(ws.recv()) if message['id'] == login_request['id']: + if "result" not in message: + raise Exception(f"Unable to login {message}") break def create_subaccount( @@ -264,7 +274,7 @@ def _sign_order(self, order, base_asset_sub_id, instrument_type, currency): self.contracts['TRADE_MODULE_ADDRESS'], trade_module_data, order['signature_expiry_sec'], - self.wallet.address, + self.wallet, order['signer'], ], ) @@ -272,7 +282,7 @@ def _sign_order(self, order, base_asset_sub_id, instrument_type, currency): action_hash = self.web3_client.keccak(encoded_action_hash) encoded_typed_data_hash = "".join(['0x1901', self.contracts['DOMAIN_SEPARATOR'][2:], action_hash.hex()[2:]]) typed_data_hash = self.web3_client.keccak(hexstr=encoded_typed_data_hash) - order['signature'] = self.wallet.signHash(typed_data_hash).signature.hex() + order['signature'] = self.signer.signHash(typed_data_hash).signature.hex() return order def fetch_ticker(self, instrument_name): diff --git a/tests/test_main.py b/tests/test_main.py index 2fdde0e..273a0d6 100644 --- a/tests/test_main.py +++ b/tests/test_main.py @@ -50,7 +50,7 @@ def test_fetch_subaccounts(lyra_client): """ Test the LyraClient class. """ - accounts = lyra_client.fetch_subaccounts(TEST_WALLET) + accounts = lyra_client.fetch_subaccounts() assert accounts['subaccount_ids']