Skip to content

Commit

Permalink
feat: dynamic messages from dict
Browse files Browse the repository at this point in the history
  • Loading branch information
ctrl-Felix committed Aug 3, 2024
1 parent 0278b2b commit 5ad8760
Show file tree
Hide file tree
Showing 10 changed files with 172 additions and 12 deletions.
33 changes: 33 additions & 0 deletions examples/add_message_as_dict.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
from mospy import Account, Transaction
from mospy.clients import HTTPClient

account = Account(
seed_phrase="",
hrp='elys'
)
tx = Transaction(
account=account,
chain_id='elystestnet-1',
gas=800000,
)


msg = {
"creator": account.address,
"amount": "1000"
}


tx.add_dict_msg(msg, type_url="/elys.stablestake.MsgBond")

client = HTTPClient(
api="https://api.testnet.elys.network"
)

tx.set_fee(
amount=100,
denom="uelys"
)

client.load_account_data(account=account)
response = client.broadcast_transaction(transaction=tx)
2 changes: 1 addition & 1 deletion examples/evmos_transfer.py
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@
tx.add_msg(
tx_type="transfer",
sender=account,
receipient=account.address,
recipient=account.address,
amount=3500000000000000,
denom="aevmos",
)
Expand Down
2 changes: 1 addition & 1 deletion pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ build-backend = "hatchling.build"

[project]
name = "mospy-wallet"
version = "0.5.5"
version = "0.6.0"
description = "This package is a fork of cosmospy and is a light framework for the cosmos ecosystem"
authors = [
{ name = "ctrl-felix", email = "[email protected]" },
Expand Down
22 changes: 22 additions & 0 deletions src/mospy/Transaction.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,10 @@
import ecdsa
from sha3 import keccak_256
from google.protobuf import any_pb2 as any

from mospy._transactions import ALL_TRANSACTION_HELPERS
from mospy.Account import Account
from mospy.protobuf.GenericProtobuf import GenericProtobuf

built_in_transactions = {}
for transaction_adapter in ALL_TRANSACTION_HELPERS:
Expand Down Expand Up @@ -97,6 +99,26 @@ def add_raw_msg(self, unpacked_msg, type_url: str) -> None:
msg_any.type_url = type_url
self._tx_body.messages.append(msg_any)

def add_dict_msg(self, msg_dict: dict, type_url: str) -> None:
"""
Add a message as dictionary to the tx body manually.
Args:
msg_dict: Transaction dict
type_url: Type url for the transaction
"""
generic_proto = GenericProtobuf()
msg_any = generic_proto.create_any_message(type_url=type_url, msg_dict=msg_dict)
self._tx_body.messages.append(msg_any)

def add_send_msg(self, recipient: str, amount: int, denom: str = "uatom") -> None:
self.add_msg(
tx_type="transfer",
sender=self._account,
recipient=recipient,
amount=amount,
denom=denom,
)
def set_fee(self, amount: int, denom: str = "uatom"):
"""
Set the fee manually
Expand Down
6 changes: 3 additions & 3 deletions src/mospy/_transactions/_transfer.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ def __init__(
self,
protobuf_package: str,
sender: Account,
receipient: str,
recipient: str,
amount: int,
denom: str,
):
Expand All @@ -30,12 +30,12 @@ def __init__(
_tx_coin.amount = str(amount)
self._amount = _tx_coin
self._sender = sender.address
self._receipient = receipient
self._recipient = recipient

def format(self) -> (str, object):
msg = self._tx_pb2.MsgSend(
from_address=self._sender,
to_address=self._receipient,
to_address=self._recipient,
)
msg.amount.append(self._amount)

Expand Down
78 changes: 78 additions & 0 deletions src/mospy/protobuf/GenericProtobuf.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,78 @@
from google.protobuf import descriptor_pb2, descriptor_pool, message_factory, any_pb2
from google.protobuf.json_format import ParseDict
import json

class GenericProtobuf:
def __init__(self):
self.pool = descriptor_pool.Default()
self.factory = message_factory.MessageFactory()

def create_message_type(self, type_url, fields):
# Create a DescriptorProto for the message type
type_name = type_url.split('.')[-1]

# Check if the type is already existing in the pool
try:
self.pool.FindMessageTypeByName(type_name)
except KeyError:
pass
else:
return

descriptor_proto = descriptor_pb2.DescriptorProto()
descriptor_proto.name = type_name

# Add key - value pairs as fields to the Descriptor
for idx, (field_name, field_value) in enumerate(fields.items(), start=1):
field_descriptor = descriptor_proto.field.add()
field_descriptor.name = field_name
field_descriptor.number = idx

if isinstance(field_value, int):
field_descriptor.type = descriptor_pb2.FieldDescriptorProto.TYPE_INT32
elif isinstance(field_value, float):
field_descriptor.type = descriptor_pb2.FieldDescriptorProto.TYPE_FLOAT
elif isinstance(field_value, bool):
field_descriptor.type = descriptor_pb2.FieldDescriptorProto.TYPE_BOOL
elif isinstance(field_value, list):
nested_type_name = f"{type_name}_{field_name}"
self.create_message_type(nested_type_name, field_value[0])
field_descriptor.type = descriptor_pb2.FieldDescriptorProto.TYPE_MESSAGE
field_descriptor.type_name = f"{nested_type_name}"
field_descriptor.label = descriptor_pb2.FieldDescriptorProto.LABEL_REPEATED
elif isinstance(field_value, dict):
nested_type_name = f"{type_name}_{field_name}"
self.create_message_type(nested_type_name, field_value[0])
field_descriptor.type = descriptor_pb2.FieldDescriptorProto.TYPE_MESSAGE
field_descriptor.type_name = f"{nested_type_name}"

else:
field_descriptor.type = descriptor_pb2.FieldDescriptorProto.TYPE_STRING

# Create a FileDescriptorProto for the new descriptor
file_descriptor_proto = descriptor_pb2.FileDescriptorProto()
file_descriptor_proto.name = f'{type_name}.proto'
file_descriptor_proto.message_type.add().MergeFrom(descriptor_proto)

# Add the file descriptor
self.pool.Add(file_descriptor_proto)

def get_message_class(self, type_name):
message_descriptor = self.pool.FindMessageTypeByName(type_name.split('.')[-1])
return self.factory.GetPrototype(message_descriptor)

def create_any_message(self, msg_dict, type_url):
type_name = type_url.split('/')[-1]

self.create_message_type(type_name, msg_dict)

message_class = self.get_message_class(type_name)

message_instance = message_class()
ParseDict(msg_dict, message_instance)

msg_any = any_pb2.Any()
msg_any.Pack(message_instance)
msg_any.type_url = type_url

return msg_any
2 changes: 1 addition & 1 deletion tests/clients/test_grpcclient.py
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,7 @@ def test_transaction_submitting(self):
tx.add_msg(
tx_type="transfer",
sender=account,
receipient=account.address,
recipient=account.address,
amount=1000,
denom="uatom",
)
Expand Down
2 changes: 1 addition & 1 deletion tests/clients/test_httpclient.py
Original file line number Diff line number Diff line change
Expand Up @@ -61,7 +61,7 @@ def test_transaction_submitting(self):
tx.add_msg(
tx_type="transfer",
sender=account,
receipient=account.address,
recipient=account.address,
amount=1000,
denom="uatom",
)
Expand Down
2 changes: 1 addition & 1 deletion tests/test_eth.py
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ def test_eth_transaction_creation(self):
tx.add_msg(
tx_type="transfer",
sender=account,
receipient=account.address,
recipient=account.address,
amount=3500000000000000,
denom="aevmos",
)
Expand Down
35 changes: 31 additions & 4 deletions tests/test_transaction.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,14 +3,13 @@
from mospy import Transaction

expected_tx_bytes = "CpABCo0BChwvY29zbW9zLmJhbmsudjFiZXRhMS5Nc2dTZW5kEm0KLWNvc21vczFxZWNuMHVqcDRydzhobjkzbDlqcHN4eXc0ZmEyOGE1MjM3YTRweBItY29zbW9zMXRrdjlycXV4cjg4cjdzbnJnNDJreGRqOWdzbmZ4eGcwMjhrdWg5Gg0KBXVhdG9tEgQxMDAwEmYKUApGCh8vY29zbW9zLmNyeXB0by5zZWNwMjU2azEuUHViS2V5EiMKIQIkQVvG9OBetDe7bYUgl2vwgbJFxmmGuquytVSEwhQ0uBIECgIIARgBEhIKDQoFdWF0b20SBDEwMDAQ6AcaQJqww3jDNgn4UMDpaFq34xPbdwTAsn4VnRvZ1rjYGCMEa6fDKnu9T5xlQV5IEpCDeMzmNBEhTo9QtcOIzjjPzes="

expected_tx_bytes2 = "Ck8KTQoZL2VseXMuc3RhYmxlc3Rha2UuTXNnQm9uZBIwCitlbHlzMXFlY24wdWpwNHJ3OGhuOTNsOWpwc3h5dzRmYTI4YTUyMzd5anZ5EgExEmYKUApGCh8vY29zbW9zLmNyeXB0by5zZWNwMjU2azEuUHViS2V5EiMKIQIkQVvG9OBetDe7bYUgl2vwgbJFxmmGuquytVSEwhQ0uBIECgIIARgFEhIKDAoFdWVseXMSAzEyNRCgwh4aQLoR5z302GPGh9YfAS4lM/JeRLrkkNW0lEdc94mkYG3qTiWuJMLDL5653PkJ/w9qZOBjOcZn1huVDu7XTzUSajo="
class TestTransactionClass:
seed_phrase = "law grab theory better athlete submit awkward hawk state wedding wave monkey audit blame fury wood tag rent furnace exotic jeans drift destroy style"

def test_transaction_creation(self):
account = Account(
seed_phrase=
"law grab theory better athlete submit awkward hawk state wedding wave monkey audit blame fury wood tag rent furnace exotic jeans drift destroy style",
seed_phrase=self.seed_phrase,
account_number=1,
next_sequence=1,
)
Expand All @@ -26,7 +25,7 @@ def test_transaction_creation(self):
tx.add_msg(
tx_type="transfer",
sender=account,
receipient="cosmos1tkv9rquxr88r7snrg42kxdj9gsnfxxg028kuh9",
recipient="cosmos1tkv9rquxr88r7snrg42kxdj9gsnfxxg028kuh9",
amount=1000,
denom="uatom",
)
Expand All @@ -35,3 +34,31 @@ def test_transaction_creation(self):
tx_bytes = tx.get_tx_bytes_as_string()
assert tx_bytes == expected_tx_bytes

def test_transaction_creation_from_dict(self):
account = Account(
seed_phrase=self.seed_phrase,
hrp='elys',
account_number=114923,
next_sequence=5
)
tx = Transaction(
account=account,
chain_id='elystestnet-1',
gas=500000,
)

msg = {
"creator": account.address,
"amount": "1"
}

tx.add_dict_msg(msg, type_url="/elys.stablestake.MsgBond")


tx.set_fee(
amount=125,
denom="uelys"
)

tx_bytes = tx.get_tx_bytes_as_string()
assert tx_bytes == expected_tx_bytes2

0 comments on commit 5ad8760

Please sign in to comment.