Skip to content

Commit

Permalink
Merge branch 'master' of https://github.com/InjectiveLabs/sdk-python
Browse files Browse the repository at this point in the history
…into feat/replace_pipenv_with_poetry
  • Loading branch information
abel committed Sep 19, 2023
2 parents 9b8421e + c247dbe commit 870af10
Show file tree
Hide file tree
Showing 12 changed files with 765 additions and 31 deletions.
1 change: 1 addition & 0 deletions Pipfile
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ protobuf = "*"
requests = "*"
safe-pysha3 = "*"
urllib3 = "<2"
web3 = ">=6.0.0"
websockets = "*"

[dev-packages]
Expand Down
264 changes: 251 additions & 13 deletions Pipfile.lock

Large diffs are not rendered by default.

16 changes: 16 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -87,6 +87,22 @@ make tests
```

### Changelogs
**0.9**
* Replace Pipenv with Poetry
* Add pre-commit validations to the project

**0.8.5**
* Added NEOK/USDT and ORAI/USDT spot markets to the mainnet .ini file

**0.8.4**
* Added methods to SpotMarket, DerivativeMarket and BianaryOptionMarket to translate chain prices and quantities to human-readable format.

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

**0.8.2**
* Add web3 library as a dependency for the project.

**0.8.1**
* Moved the configuration to use a secure or insecure connection inside the Network class. The AsyncClient's `insecure` parameter is no longer used for anything and will be removed in the future.
* Made the new load balanced bare-metal node the default one for mainnet (it is called `lb`). The legacy one (load balanced k8s node) is called `lb_k8s`
Expand Down
8 changes: 3 additions & 5 deletions examples/SendToInjective.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,9 +5,6 @@
from pyinjective.core.network import Network
from pyinjective.sendtocosmos import Peggo

import importlib.resources as pkg_resources
import pyinjective


async def main() -> None:
# select network: testnet, mainnet
Expand All @@ -30,8 +27,9 @@ async def main() -> None:
'"amount": {"denom": "inj","amount": "1000000000000000000"}}'
)

import_peggo = pkg_resources.read_text(pyinjective, 'Peggo_ABI.json')
peggo_abi = json.loads(import_peggo)
with open("../pyinjective/Peggo_ABI.json") as pego_file:
peggo_data = pego_file.read()
peggo_abi = json.loads(peggo_data)

peggo_composer.sendToInjective(
ethereum_endpoint=ethereum_endpoint,
Expand Down
331 changes: 330 additions & 1 deletion poetry.lock

Large diffs are not rendered by default.

25 changes: 25 additions & 0 deletions pyinjective/core/market.py
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,13 @@ def price_to_chain_format(self, human_readable_value: Decimal) -> Decimal:

return extended_chain_formatted_value

def quantity_from_chain_format(self, chain_value: Decimal) -> Decimal:
return chain_value / Decimal(f"1e{self.base_token.decimals}")

def price_from_chain_format(self, chain_value: Decimal) -> Decimal:
decimals = self.base_token.decimals - self.quote_token.decimals
return chain_value * Decimal(f"1e{decimals}")


@dataclass(eq=True, frozen=True)
class DerivativeMarket:
Expand Down Expand Up @@ -93,6 +100,15 @@ def calculate_margin_in_chain_format(

return extended_chain_formatted_margin

def quantity_from_chain_format(self, chain_value: Decimal) -> Decimal:
return chain_value

def price_from_chain_format(self, chain_value: Decimal) -> Decimal:
return chain_value * Decimal(f"1e-{self.quote_token.decimals}")

def margin_from_chain_format(self, chain_value: Decimal) -> Decimal:
return chain_value * Decimal(f"1e-{self.quote_token.decimals}")


@dataclass(eq=True, frozen=True)
class BinaryOptionMarket:
Expand Down Expand Up @@ -155,3 +171,12 @@ def calculate_margin_in_chain_format(
extended_chain_formatted_margin = quantized_margin * Decimal(f"1e{ADDITIONAL_CHAIN_FORMAT_DECIMALS}")

return extended_chain_formatted_margin

def quantity_from_chain_format(self, chain_value: Decimal, special_denom: Optional[Denom] = None) -> Decimal:
# Binary option markets do not have a base market to provide the number of decimals
decimals = 0 if special_denom is None else special_denom.base
return chain_value * Decimal(f"1e-{decimals}")

def price_from_chain_format(self, chain_value: Decimal, special_denom: Optional[Denom] = None) -> Decimal:
decimals = self.quote_token.decimals if special_denom is None else special_denom.quote
return chain_value * Decimal(f"1e-{decimals}")
26 changes: 26 additions & 0 deletions pyinjective/denoms_mainnet.ini
Original file line number Diff line number Diff line change
Expand Up @@ -394,6 +394,24 @@ min_display_price_tick_size = 9.999999999999999e-05
min_quantity_tick_size = 10000000
min_display_quantity_tick_size = 0.1

[0xe8fe754e16233754e2811c36aca89992e35951cfd61376f1cbdc44be6ac8d3fb]
description = 'Mainnet Spot NEOK/USDT'
base = 18
quote = 6
min_price_tick_size = 0.0000000000000001
min_display_price_tick_size = 9.999999999999999e-05
min_quantity_tick_size = 100000000000000000
min_display_quantity_tick_size = 0.1

[0xa04adeed0f09ed45c73b344b520d05aa31eabe2f469dcbb02a021e0d9d098715]
description = 'Mainnet Spot ORAI/USDT'
base = 6
quote = 6
min_price_tick_size = 0.0001
min_display_price_tick_size = 9.999999999999999e-05
min_quantity_tick_size = 100000
min_display_quantity_tick_size = 0.1

[0x4ca0f92fc28be0c9761326016b5a1a2177dd6375558365116b5bdda9abc229ce]
description = 'Mainnet Derivative BTC/USDT PERP'
base = 0
Expand Down Expand Up @@ -680,3 +698,11 @@ decimals = 8
[NBLA]
peggy_denom = factory/inj1d0zfq42409a5mhdagjutl8u6u9rgcm4h8zfmfq/nbla
decimals = 6

[NEOK]
peggy_denom = ibc/F6CC233E5C0EA36B1F74AB1AF98471A2D6A80E2542856639703E908B4D93E7C4
decimals = 18

[ORAI]
peggy_denom = ibc/C20C0A822BD22B2CEF0D067400FCCFB6FAEEE9E91D360B4E0725BD522302D565
decimals = 6
19 changes: 10 additions & 9 deletions pyinjective/sendtocosmos.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ def sendToInjective(
private_key: str,
token_contract: str,
receiver: str,
amount: int,
amount: float,
maxFeePerGas: int,
maxPriorityFeePerGas: int,
peggo_abi: str,
Expand All @@ -29,21 +29,22 @@ def sendToInjective(
peggy_proxy_address = "0x4F38F75606d046819638f909b66B112aF1095e8d"
else:
LoggerProvider().logger_for_class(logging_class=self.__class__).info("Network is not supported")
raise RuntimeError(f"Network {self.network} not supported")
web3 = Web3(Web3.HTTPProvider(ethereum_endpoint))
contract = web3.eth.contract(address=peggy_proxy_address, abi=peggo_abi)

token_contract_address = web3.toChecksumAddress(token_contract)
token_contract_address = web3.to_checksum_address(token_contract)

receiver_address = Address.from_acc_bech32(receiver)
receiver_ethereum_address = Address.get_ethereum_address(receiver_address)
receiver_address_checksum = web3.toChecksumAddress(receiver_ethereum_address)
receiver_address_checksum = web3.to_checksum_address(receiver_ethereum_address)
receiver_slice = receiver_address_checksum[2:]
receiver_padded_address = '0x' + receiver_slice.zfill(64)

destination = web3.toBytes(hexstr=receiver_padded_address)
destination = web3.to_bytes(hexstr=receiver_padded_address)

sender_ethereum_address = web3.eth.account.privateKeyToAccount(private_key).address
sender_address_checksum = web3.toChecksumAddress(sender_ethereum_address)
sender_ethereum_address = web3.eth.account.from_key(private_key).address
sender_address_checksum = web3.to_checksum_address(sender_ethereum_address)
nonce = web3.eth.get_transaction_count(sender_address_checksum)

amount_to_send = int(amount * pow(10, decimals))
Expand All @@ -53,13 +54,13 @@ def sendToInjective(
destination,
amount_to_send,
data
).estimateGas({'from': sender_address_checksum})
).estimate_gas({'from': sender_address_checksum})

transaction_body = {
'nonce': nonce,
'gas': gas,
'maxFeePerGas': web3.toWei(maxFeePerGas, 'gwei'),
'maxPriorityFeePerGas': web3.toWei(maxPriorityFeePerGas, 'gwei'),
'maxFeePerGas': web3.to_wei(maxFeePerGas, 'gwei'),
'maxPriorityFeePerGas': web3.to_wei(maxPriorityFeePerGas, 'gwei'),
}

tx = contract.functions.sendToInjective(
Expand Down
3 changes: 2 additions & 1 deletion pyproject.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[tool.poetry]
name = "injective-py"
version = "0.8.1"
version = "0.9.dev"
description = "Injective Python SDK, with Exchange API Client"
authors = ["Injective Labs <[email protected]>"]
license = "Apache Software License 2.0"
Expand Down Expand Up @@ -32,6 +32,7 @@ requests = "*"
safe-pysha3 = "*"
urllib3 = "<2"
websockets = "*"
web3 = "^6.0"

[tool.poetry.group.test.dependencies]
pytest = "*"
Expand Down
5 changes: 3 additions & 2 deletions setup.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@
EMAIL = "[email protected]"
AUTHOR = "Injective Labs"
REQUIRES_PYTHON = ">=3.9"
VERSION = "0.8.1"
VERSION = "0.8.5"

REQUIRED = [
"aiohttp",
Expand All @@ -35,7 +35,8 @@
"protobuf",
"requests",
"safe-pysha3",
"urllib3",
"urllib3<2",
"web3>=6.0.0",
"websockets",
]

Expand Down
98 changes: 98 additions & 0 deletions tests/core/test_market.py
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,23 @@ def test_convert_price_to_chain_format(self, inj_usdt_spot_market: SpotMarket):

assert (quantized_chain_format_value == chain_value)

def test_convert_quantity_from_chain_format(self, inj_usdt_spot_market: SpotMarket):
expected_quantity = Decimal("123.456")

chain_format_quantity = expected_quantity * Decimal(f"1e{inj_usdt_spot_market.base_token.decimals}")
human_readable_quantity = inj_usdt_spot_market.quantity_from_chain_format(chain_value=chain_format_quantity)

assert (expected_quantity == human_readable_quantity)

def test_convert_price_from_chain_format(self, inj_usdt_spot_market: SpotMarket):
expected_price = Decimal("123.456")

price_decimals = inj_usdt_spot_market.quote_token.decimals - inj_usdt_spot_market.base_token.decimals
chain_format_price = expected_price * Decimal(f"1e{price_decimals}")
human_readable_price = inj_usdt_spot_market.price_from_chain_format(chain_value=chain_format_price)

assert (expected_price == human_readable_price)


class TestDerivativeMarket:

Expand Down Expand Up @@ -75,6 +92,32 @@ def test_convert_margin_to_chain_format(self, btc_usdt_perp_market: DerivativeMa

assert (quantized_chain_format_value == chain_value)

def test_convert_quantity_from_chain_format(self, btc_usdt_perp_market: DerivativeMarket):
expected_quantity = Decimal("123.456")

chain_format_quantity = expected_quantity
human_readable_quantity = btc_usdt_perp_market.quantity_from_chain_format(chain_value=chain_format_quantity)

assert (expected_quantity == human_readable_quantity)

def test_convert_price_from_chain_format(self, btc_usdt_perp_market: DerivativeMarket):
expected_price = Decimal("123.456")

price_decimals = btc_usdt_perp_market.quote_token.decimals
chain_format_price = expected_price * Decimal(f"1e{price_decimals}")
human_readable_price = btc_usdt_perp_market.price_from_chain_format(chain_value=chain_format_price)

assert (expected_price == human_readable_price)

def test_convert_margin_from_chain_format(self, btc_usdt_perp_market: DerivativeMarket):
expected_margin = Decimal("123.456")

price_decimals = btc_usdt_perp_market.quote_token.decimals
chain_format_margin = expected_margin * Decimal(f"1e{price_decimals}")
human_readable_margin = btc_usdt_perp_market.margin_from_chain_format(chain_value=chain_format_margin)

assert (expected_margin == human_readable_margin)


class TestBinaryOptionMarket:

Expand Down Expand Up @@ -217,3 +260,58 @@ def test_calculate_margin_for_sell_without_fixed_denom(self, first_match_bet_mar
quantized_chain_format_margin = quantized_margin * Decimal("1e18")

assert (quantized_chain_format_margin == chain_value)

def test_convert_quantity_from_chain_format_with_fixed_denom(self, first_match_bet_market: BinaryOptionMarket):
original_quantity = Decimal("123.456789")
fixed_denom = Denom(
description="Fixed denom",
base=2,
quote=4,
min_quantity_tick_size=100,
min_price_tick_size=10000,
)

chain_formatted_quantity = original_quantity * Decimal(f"1e{fixed_denom.base}")

human_readable_quantity = first_match_bet_market.quantity_from_chain_format(
chain_value=chain_formatted_quantity, special_denom=fixed_denom
)

assert (original_quantity == human_readable_quantity)

def test_convert_quantity_from_chain_format_without_fixed_denom(self, first_match_bet_market: BinaryOptionMarket):
original_quantity = Decimal("123.456789")

chain_formatted_quantity = original_quantity

human_readable_quantity = first_match_bet_market.quantity_from_chain_format(
chain_value=chain_formatted_quantity
)

assert (original_quantity == human_readable_quantity)

def test_convert_price_from_chain_format_with_fixed_denom(self, first_match_bet_market: BinaryOptionMarket):
original_price = Decimal("123.456789")
fixed_denom = Denom(
description="Fixed denom",
base=2,
quote=4,
min_quantity_tick_size=100,
min_price_tick_size=10000,
)

chain_formatted_price = original_price * Decimal(f"1e{fixed_denom.quote}")

human_readable_price = first_match_bet_market.price_from_chain_format(
chain_value=chain_formatted_price, special_denom=fixed_denom
)

assert (original_price == human_readable_price)

def test_convert_price_from_chain_format_without_fixed_denom(self, first_match_bet_market: BinaryOptionMarket):
original_price = Decimal("123.456789")
chain_formatted_price = original_price * Decimal(f"1e{first_match_bet_market.quote_token.decimals}")

human_readable_price = first_match_bet_market.price_from_chain_format(chain_value=chain_formatted_price)

assert (original_price == human_readable_price)

0 comments on commit 870af10

Please sign in to comment.