Skip to content

Commit 9370531

Browse files
author
abel
committed
(feat) Added from chain price and value translation to all market classes. Fixed an error SendToInjective example script
1 parent 203500c commit 9370531

File tree

6 files changed

+131
-43
lines changed

6 files changed

+131
-43
lines changed

README.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -88,7 +88,7 @@ make tests
8888

8989
### Changelogs
9090
**0.8.4**
91-
* Added keepalive options to gRPC channels.
91+
* Added methods to SpotMarket, DerivativeMarket and BianaryOptionMarket to translate chain prices and quantities to human-readable format.
9292

9393
**0.8.3**
9494
* Fix dependency issue in setup.py.

examples/SendToInjective.py

Lines changed: 0 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,9 @@
11
import json
2-
import requests
3-
42
import asyncio
5-
import logging
63

74
from pyinjective.core.network import Network
85
from pyinjective.sendtocosmos import Peggo
96

10-
import importlib.resources as pkg_resources
11-
import pyinjective
12-
137
async def main() -> None:
148
# select network: testnet, mainnet
159
network = Network.testnet()

pyinjective/async_client.py

Lines changed: 6 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -70,13 +70,6 @@
7070
DEFAULT_SESSION_RENEWAL_OFFSET = 120 # seconds
7171
DEFAULT_BLOCK_TIME = 2 # seconds
7272

73-
GRPC_CHANNEL_OPTIONS = [
74-
("grpc.keepalive_time_ms", 45000),
75-
("grpc.keepalive_timeout_ms", 5000),
76-
("grpc.http2.max_pings_without_data", 5),
77-
("grpc.keepalive_permit_without_calls", 1),
78-
]
79-
8073

8174
class AsyncClient:
8275
def __init__(
@@ -95,16 +88,9 @@ def __init__(
9588

9689
# chain stubs
9790
self.chain_channel = (
98-
grpc.aio.secure_channel(
99-
target=network.grpc_endpoint,
100-
credentials=credentials,
101-
options=GRPC_CHANNEL_OPTIONS,
102-
)
91+
grpc.aio.secure_channel(network.grpc_endpoint, credentials)
10392
if (network.use_secure_connection and credentials is not None)
104-
else grpc.aio.insecure_channel(
105-
target=network.grpc_endpoint,
106-
options=GRPC_CHANNEL_OPTIONS,
107-
)
93+
else grpc.aio.insecure_channel(network.grpc_endpoint)
10894
)
10995

11096
self.stubCosmosTendermint = tendermint_query_grpc.ServiceStub(
@@ -120,16 +106,9 @@ def __init__(
120106

121107
# exchange stubs
122108
self.exchange_channel = (
123-
grpc.aio.secure_channel(
124-
target=network.grpc_exchange_endpoint,
125-
credentials=credentials,
126-
options=GRPC_CHANNEL_OPTIONS,
127-
)
109+
grpc.aio.secure_channel(network.grpc_exchange_endpoint, credentials)
128110
if (network.use_secure_connection and credentials is not None)
129-
else grpc.aio.insecure_channel(
130-
target=network.grpc_exchange_endpoint,
131-
options=GRPC_CHANNEL_OPTIONS,
132-
)
111+
else grpc.aio.insecure_channel(network.grpc_exchange_endpoint)
133112
)
134113
self.stubMeta = exchange_meta_rpc_grpc.InjectiveMetaRPCStub(
135114
self.exchange_channel
@@ -158,16 +137,9 @@ def __init__(
158137

159138
# explorer stubs
160139
self.explorer_channel = (
161-
grpc.aio.secure_channel(
162-
target=network.grpc_explorer_endpoint,
163-
credentials=credentials,
164-
options=GRPC_CHANNEL_OPTIONS,
165-
)
140+
grpc.aio.secure_channel(network.grpc_explorer_endpoint, credentials)
166141
if (network.use_secure_connection and credentials is not None)
167-
else grpc.aio.insecure_channel(
168-
target=network.grpc_explorer_endpoint,
169-
options=GRPC_CHANNEL_OPTIONS,
170-
)
142+
else grpc.aio.insecure_channel(network.grpc_explorer_endpoint)
171143
)
172144
self.stubExplorer = explorer_rpc_grpc.InjectiveExplorerRPCStub(
173145
self.explorer_channel

pyinjective/core/market.py

Lines changed: 26 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,13 @@ def price_to_chain_format(self, human_readable_value: Decimal) -> Decimal:
3434

3535
return extended_chain_formatted_value
3636

37+
def quantity_from_chain_format(self, chain_value: Decimal) -> Decimal:
38+
return chain_value / Decimal(f"1e{self.base_token.decimals}")
39+
40+
def price_from_chain_format(self, chain_value: Decimal) -> Decimal:
41+
decimals = self.base_token.decimals - self.quote_token.decimals
42+
return chain_value * Decimal(f"1e{decimals}")
43+
3744
@dataclass(eq=True, frozen=True)
3845
class DerivativeMarket:
3946
id: str
@@ -92,6 +99,15 @@ def calculate_margin_in_chain_format(
9299

93100
return extended_chain_formatted_margin
94101

102+
def quantity_from_chain_format(self, chain_value: Decimal) -> Decimal:
103+
return chain_value
104+
105+
def price_from_chain_format(self, chain_value: Decimal) -> Decimal:
106+
return chain_value * Decimal(f"1e-{self.quote_token.decimals}")
107+
108+
def margin_from_chain_format(self, chain_value: Decimal) -> Decimal:
109+
return chain_value * Decimal(f"1e-{self.quote_token.decimals}")
110+
95111
@dataclass(eq=True, frozen=True)
96112
class BinaryOptionMarket:
97113
id: str
@@ -148,4 +164,13 @@ def calculate_margin_in_chain_format(
148164
quantized_margin = (margin // min_quantity_tick_size) * min_quantity_tick_size
149165
extended_chain_formatted_margin = quantized_margin * Decimal(f"1e{ADDITIONAL_CHAIN_FORMAT_DECIMALS}")
150166

151-
return extended_chain_formatted_margin
167+
return extended_chain_formatted_margin
168+
169+
def quantity_from_chain_format(self, chain_value: Decimal, special_denom: Optional[Denom] = None) -> Decimal:
170+
# Binary option markets do not have a base market to provide the number of decimals
171+
decimals = 0 if special_denom is None else special_denom.base
172+
return chain_value * Decimal(f"1e-{decimals}")
173+
174+
def price_from_chain_format(self, chain_value: Decimal, special_denom: Optional[Denom] = None) -> Decimal:
175+
decimals = self.quote_token.decimals if special_denom is None else special_denom.quote
176+
return chain_value * Decimal(f"1e-{decimals}")

pyinjective/sendtocosmos.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@
66
class Peggo:
77
def __init__(self, network: str):
88
self.network = network
9-
def sendToInjective(self, ethereum_endpoint: str, private_key: str, token_contract: str, receiver: str, amount: int,
9+
def sendToInjective(self, ethereum_endpoint: str, private_key: str, token_contract: str, receiver: str, amount: float,
1010
maxFeePerGas: int, maxPriorityFeePerGas: int, peggo_abi: str, data: str, decimals=18):
1111
if self.network == 'testnet':
1212
peggy_proxy_address = "0xd2C6753F6B1783EF0a3857275e16e79D91b539a3"

tests/core/test_market.py

Lines changed: 97 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,24 @@ def test_convert_price_to_chain_format(self, inj_usdt_spot_market: SpotMarket):
3939

4040
assert (quantized_chain_format_value == chain_value)
4141

42+
def test_convert_quantity_from_chain_format(self, inj_usdt_spot_market: SpotMarket):
43+
expected_quantity = Decimal("123.456")
44+
45+
chain_format_quantity = expected_quantity * Decimal(f"1e{inj_usdt_spot_market.base_token.decimals}")
46+
human_readable_quantity = inj_usdt_spot_market.quantity_from_chain_format(chain_value=chain_format_quantity)
47+
48+
assert (expected_quantity == human_readable_quantity)
49+
50+
def test_convert_price_from_chain_format(self, inj_usdt_spot_market: SpotMarket):
51+
expected_price = Decimal("123.456")
52+
53+
price_decimals = inj_usdt_spot_market.quote_token.decimals - inj_usdt_spot_market.base_token.decimals
54+
chain_format_price = expected_price * Decimal(f"1e{price_decimals}")
55+
human_readable_price = inj_usdt_spot_market.price_from_chain_format(chain_value=chain_format_price)
56+
57+
assert (expected_price == human_readable_price)
58+
59+
4260

4361
class TestDerivativeMarket:
4462

@@ -76,6 +94,32 @@ def test_convert_margin_to_chain_format(self, btc_usdt_perp_market: DerivativeMa
7694

7795
assert (quantized_chain_format_value == chain_value)
7896

97+
def test_convert_quantity_from_chain_format(self, btc_usdt_perp_market: DerivativeMarket):
98+
expected_quantity = Decimal("123.456")
99+
100+
chain_format_quantity = expected_quantity
101+
human_readable_quantity = btc_usdt_perp_market.quantity_from_chain_format(chain_value=chain_format_quantity)
102+
103+
assert (expected_quantity == human_readable_quantity)
104+
105+
def test_convert_price_from_chain_format(self, btc_usdt_perp_market: DerivativeMarket):
106+
expected_price = Decimal("123.456")
107+
108+
price_decimals = btc_usdt_perp_market.quote_token.decimals
109+
chain_format_price = expected_price * Decimal(f"1e{price_decimals}")
110+
human_readable_price = btc_usdt_perp_market.price_from_chain_format(chain_value=chain_format_price)
111+
112+
assert (expected_price == human_readable_price)
113+
114+
def test_convert_margin_from_chain_format(self, btc_usdt_perp_market: DerivativeMarket):
115+
expected_margin = Decimal("123.456")
116+
117+
price_decimals = btc_usdt_perp_market.quote_token.decimals
118+
chain_format_margin = expected_margin * Decimal(f"1e{price_decimals}")
119+
human_readable_margin = btc_usdt_perp_market.margin_from_chain_format(chain_value=chain_format_margin)
120+
121+
assert (expected_margin == human_readable_margin)
122+
79123
class TestBinaryOptionMarket:
80124

81125
def test_convert_quantity_to_chain_format_with_fixed_denom(self, first_match_bet_market: BinaryOptionMarket):
@@ -211,3 +255,56 @@ def test_calculate_margin_for_sell_without_fixed_denom(self, first_match_bet_mar
211255
quantized_chain_format_margin = quantized_margin * Decimal(f"1e18")
212256

213257
assert (quantized_chain_format_margin == chain_value)
258+
259+
def test_convert_quantity_from_chain_format_with_fixed_denom(self, first_match_bet_market: BinaryOptionMarket):
260+
original_quantity = Decimal("123.456789")
261+
fixed_denom = Denom(
262+
description="Fixed denom",
263+
base=2,
264+
quote=4,
265+
min_quantity_tick_size=100,
266+
min_price_tick_size=10000,
267+
)
268+
269+
chain_formatted_quantity = original_quantity * Decimal(f"1e{fixed_denom.base}")
270+
271+
human_readable_quantity = first_match_bet_market.quantity_from_chain_format(
272+
chain_value=chain_formatted_quantity, special_denom=fixed_denom
273+
)
274+
275+
assert (original_quantity == human_readable_quantity)
276+
277+
def test_convert_quantity_from_chain_format_without_fixed_denom(self, first_match_bet_market: BinaryOptionMarket):
278+
original_quantity = Decimal("123.456789")
279+
280+
chain_formatted_quantity = original_quantity
281+
282+
human_readable_quantity = first_match_bet_market.quantity_from_chain_format(chain_value=chain_formatted_quantity)
283+
284+
assert (original_quantity == human_readable_quantity)
285+
286+
def test_convert_price_from_chain_format_with_fixed_denom(self, first_match_bet_market: BinaryOptionMarket):
287+
original_price = Decimal("123.456789")
288+
fixed_denom = Denom(
289+
description="Fixed denom",
290+
base=2,
291+
quote=4,
292+
min_quantity_tick_size=100,
293+
min_price_tick_size=10000,
294+
)
295+
296+
chain_formatted_price = original_price * Decimal(f"1e{fixed_denom.quote}")
297+
298+
human_readable_price = first_match_bet_market.price_from_chain_format(
299+
chain_value=chain_formatted_price, special_denom=fixed_denom
300+
)
301+
302+
assert (original_price == human_readable_price)
303+
304+
def test_convert_price_from_chain_format_without_fixed_denom(self, first_match_bet_market: BinaryOptionMarket):
305+
original_price = Decimal("123.456789")
306+
chain_formatted_price = original_price * Decimal(f"1e{first_match_bet_market.quote_token.decimals}")
307+
308+
human_readable_price = first_match_bet_market.price_from_chain_format(chain_value=chain_formatted_price)
309+
310+
assert (original_price == human_readable_price)

0 commit comments

Comments
 (0)