Skip to content

Commit 8ae7ad3

Browse files
Merge pull request #8 from InjectiveLabs/unit-tests
Pytest - Unit tests
2 parents 2577912 + 605a65d commit 8ae7ad3

File tree

1 file changed

+209
-0
lines changed

1 file changed

+209
-0
lines changed

compatibility-tests/unit_tests.py

Lines changed: 209 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,209 @@
1+
import pytest
2+
import aiohttp
3+
import json
4+
import ecdsa
5+
import sha3
6+
import grpc
7+
import base64
8+
9+
from typing import Any, Dict, List
10+
from injective.chain_client._wallet import (
11+
generate_wallet,
12+
privkey_to_address,
13+
privkey_to_pubkey,
14+
pubkey_to_address,
15+
seed_to_privkey,
16+
DEFAULT_BECH32_HRP,
17+
)
18+
19+
from injective.chain_client._typings import SyncMode
20+
import injective.exchange_api.injective_accounts_rpc_pb2 as accounts_rpc_pb
21+
import injective.exchange_api.injective_accounts_rpc_pb2_grpc as accounts_rpc_grpc
22+
23+
MIN_GAS_PRICE = 500000000
24+
25+
class Transaction:
26+
27+
def __init__(
28+
self,
29+
*,
30+
privkey: bytes,
31+
account_num: int,
32+
sequence: int,
33+
fee: int,
34+
gas: int,
35+
fee_denom: str = "inj",
36+
memo: str = "",
37+
chain_id: str = "injective-888",
38+
hrp: str = DEFAULT_BECH32_HRP,
39+
sync_mode: SyncMode = "block",
40+
) -> None:
41+
self._privkey = privkey
42+
self._account_num = account_num
43+
self._sequence = sequence
44+
self._fee = fee
45+
self._fee_denom = fee_denom
46+
self._gas = gas
47+
self._memo = memo
48+
self._chain_id = chain_id
49+
self._hrp = hrp
50+
self._sync_mode = sync_mode
51+
self._msgs: List[dict] = []
52+
53+
54+
def add_cosmos_bank_msg_send(self, recipient: str, amount: int, denom: str = "inj") -> None:
55+
msg = {
56+
"type": "cosmos-sdk/MsgSend",
57+
"value": {
58+
"from_address": privkey_to_address(self._privkey, hrp=self._hrp),
59+
"to_address": recipient,
60+
"amount": [{"denom": denom, "amount": str(amount)}],
61+
},
62+
}
63+
self._msgs.append(msg)
64+
65+
# Injective • Exchange Module
66+
67+
def add_exchange_msg_deposit(self, subaccount: str, amount: int, denom: str = "inj") -> None:
68+
msg = {
69+
"type": "exchange/MsgDeposit",
70+
"value": {
71+
"sender": privkey_to_address(self._privkey, hrp=self._hrp),
72+
"subaccount_id": subaccount,
73+
"amount": {"denom": denom, "amount": str(amount)},
74+
},
75+
}
76+
self._msgs.append(msg)
77+
78+
def get_signed(self) -> str:
79+
pubkey = privkey_to_pubkey(self._privkey)
80+
base64_pubkey = base64.b64encode(pubkey).decode("utf-8")
81+
signed_tx = {
82+
"tx": {
83+
"msg": self._msgs,
84+
"fee": {
85+
"gas": str(self._gas),
86+
"amount": [{"denom": self._fee_denom, "amount": str(self._fee)}],
87+
},
88+
"memo": self._memo,
89+
"signatures": [
90+
{
91+
"signature": self._sign(),
92+
"pub_key": {"type": "injective/PubKeyEthSecp256k1", "value": base64_pubkey},
93+
"account_number": str(self._account_num),
94+
"sequence": str(self._sequence),
95+
}
96+
],
97+
},
98+
"mode": self._sync_mode,
99+
}
100+
return json.dumps(signed_tx, separators=(",", ":"))
101+
102+
def _sign(self) -> str:
103+
message_str = json.dumps(
104+
self._get_sign_message(), separators=(",", ":"), sort_keys=True)
105+
message_bytes = message_str.encode("utf-8")
106+
107+
privkey = ecdsa.SigningKey.from_string(
108+
self._privkey, curve=ecdsa.SECP256k1)
109+
signature_compact_keccak = privkey.sign_deterministic(
110+
message_bytes, hashfunc=sha3.keccak_256, sigencode=ecdsa.util.sigencode_string_canonize
111+
)
112+
signature_base64_str = base64.b64encode(
113+
signature_compact_keccak).decode("utf-8")
114+
return signature_base64_str
115+
116+
def _get_sign_message(self) -> Dict[str, Any]:
117+
return {
118+
"chain_id": self._chain_id,
119+
"account_number": str(self._account_num),
120+
"fee": {
121+
"gas": str(self._gas),
122+
"amount": [{"amount": str(self._fee), "denom": self._fee_denom}],
123+
},
124+
"memo": self._memo,
125+
"sequence": str(self._sequence),
126+
"msgs": self._msgs,
127+
}
128+
129+
130+
async def get_account_num_seq(address: str) -> (int, int):
131+
async with aiohttp.ClientSession() as session:
132+
async with session.request(
133+
'GET', 'http://staking-lcd-testnet.injective.network/cosmos/auth/v1beta1/accounts/' + address,
134+
headers={'Accept-Encoding': 'application/json'},
135+
) as response:
136+
if response.status != 200:
137+
print(await response.text())
138+
raise ValueError("HTTP response status", response.status)
139+
140+
resp = json.loads(await response.text())
141+
acc = resp['account']['base_account']
142+
return acc['account_number'], acc['sequence']
143+
144+
async def post_tx(tx_json: str):
145+
async with aiohttp.ClientSession() as session:
146+
async with session.request(
147+
'POST', 'http://staking-lcd-testnet.injective.network/txs', data=tx_json,
148+
headers={'Content-Type': 'application/json'},
149+
) as response:
150+
if response.status != 200:
151+
print(await response.text())
152+
raise ValueError("HTTP response status", response.status)
153+
154+
resp = json.loads(await response.text())
155+
if 'code' in resp:
156+
print("Response:", resp)
157+
raise ValueError('sdk error %d: %s' % (resp['code'], resp['raw_log']))
158+
159+
return resp['txhash']
160+
161+
@pytest.fixture
162+
async def msg_send():
163+
sender_pk = seed_to_privkey(
164+
"physical page glare junk return scale subject river token door mirror title"
165+
)
166+
sender_acc_addr = privkey_to_address(sender_pk)
167+
print("Sender Account:", sender_acc_addr)
168+
169+
acc_num, acc_seq = await get_account_num_seq(sender_acc_addr)
170+
171+
async with grpc.aio.insecure_channel('testnet-sentry0.injective.network:9910') as channel:
172+
accounts_rpc = accounts_rpc_grpc.InjectiveAccountsRPCStub(channel)
173+
account_addr = "inj14au322k9munkmx5wrchz9q30juf5wjgz2cfqku"
174+
175+
subacc = await accounts_rpc.SubaccountsList(accounts_rpc_pb.SubaccountsListRequest(account_address = account_addr))
176+
for sub in subacc.subaccounts:
177+
print("Primary subaccount:", sub)
178+
break
179+
180+
tx = Transaction(
181+
privkey=sender_pk,
182+
account_num=acc_num,
183+
sequence=acc_seq,
184+
gas=200000,
185+
fee=200000 * MIN_GAS_PRICE,
186+
sync_mode="block",
187+
)
188+
tx.add_cosmos_bank_msg_send(
189+
recipient="inj1qy69k458ppmj45c3vqwcd6wvlcuvk23x0hsz58",
190+
amount=10000000000000000,
191+
denom="inj",
192+
)
193+
tx.add_exchange_msg_deposit(
194+
subaccount= sub,
195+
amount=10000000000000000,
196+
denom="inj",
197+
)
198+
199+
tx_json = tx.get_signed()
200+
tx_result = await post_tx(tx_json)
201+
202+
print("Signed Tx:", tx_json)
203+
print("Sent Tx:", tx_result)
204+
205+
return len(tx_result)
206+
207+
@pytest.mark.asyncio
208+
async def test_msg_send(msg_send):
209+
assert msg_send == 64

0 commit comments

Comments
 (0)