Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Implemented account transactions factory #15

Merged
merged 2 commits into from
Mar 6, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -0,0 +1,115 @@
from typing import Dict, List, Protocol

from multiversx_sdk.core.interfaces import IAddress
from multiversx_sdk.core.transaction import Transaction
from multiversx_sdk.core.transactions_factories.transaction_builder import \
TransactionBuilder


class IConfig(Protocol):
chain_id: str
min_gas_limit: int
gas_limit_per_byte: int
gas_limit_save_key_value: int
gas_limit_persist_per_byte: int
gas_limit_store_per_byte: int
gas_limit_set_guardian: int
gas_limit_guard_account: int
gas_limit_unguard_account: int
extra_gas_limit_for_guarded_transaction: int


class AccountTransactionsFactory:
def __init__(self, config: IConfig) -> None:
self.config = config

def create_transaction_for_saving_key_value(
self,
sender: IAddress,
key_value_pairs: Dict[bytes, bytes]
ssd04 marked this conversation as resolved.
Show resolved Hide resolved
) -> Transaction:
function = "SaveKeyValue"

extra_gas = self._compute_extra_gas_for_saving_key_value(key_value_pairs)
data_parts = self._compute_data_parts_for_saving_key_value(key_value_pairs)

data_parts.insert(0, function)

return TransactionBuilder(
config=self.config,
sender=sender,
receiver=sender,
data_parts=data_parts,
gas_limit=extra_gas,
add_data_movement_gas=True
).build()

def create_transaction_for_setting_guardian(
self,
sender: IAddress,
guardian_address: IAddress,
service_id: str
) -> Transaction:
data_parts = [
"SetGuardian",
guardian_address.to_hex(),
service_id.encode().hex()
]

gas_limit = self.config.gas_limit_set_guardian + self.config.extra_gas_limit_for_guarded_transaction

return TransactionBuilder(
config=self.config,
sender=sender,
receiver=sender,
data_parts=data_parts,
gas_limit=gas_limit,
add_data_movement_gas=True
).build()

def create_transaction_for_guarding_account(self, sender: IAddress) -> Transaction:
data_parts = ["GuardAccount"]

gas_limit = self.config.gas_limit_guard_account + self.config.extra_gas_limit_for_guarded_transaction

return TransactionBuilder(
config=self.config,
sender=sender,
receiver=sender,
data_parts=data_parts,
gas_limit=gas_limit,
add_data_movement_gas=True
).build()

def create_transaction_for_unguarding_account(self, sender: IAddress) -> Transaction:
data_parts = ["UnGuardAccount"]

gas_limit = self.config.gas_limit_unguard_account + self.config.extra_gas_limit_for_guarded_transaction

transaction = TransactionBuilder(
config=self.config,
sender=sender,
receiver=sender,
data_parts=data_parts,
gas_limit=gas_limit,
add_data_movement_gas=True
).build()
transaction.options = 2

return transaction

def _compute_data_parts_for_saving_key_value(self, key_value_pairs: Dict[bytes, bytes]) -> List[str]:
data_parts: List[str] = []

for key, value in key_value_pairs.items():
data_parts.extend([key.hex(), value.hex()])

return data_parts

def _compute_extra_gas_for_saving_key_value(self, key_value_pairs: Dict[bytes, bytes]) -> int:
extra_gas = 0

for key, value in key_value_pairs.items():
extra_gas += self.config.gas_limit_persist_per_byte * (len(key) + len(value)) + self.config.gas_limit_store_per_byte * len(value)

return extra_gas + self.config.gas_limit_save_key_value
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
from typing import Dict

from multiversx_sdk.core.address import Address
from multiversx_sdk.core.transactions_factories.account_transactions_factory import \
AccountTransactionsFactory
from multiversx_sdk.core.transactions_factories.transactions_factory_config import \
TransactionsFactoryConfig


class TestAccountTransactionsFactory:
config = TransactionsFactoryConfig("D")
factory = AccountTransactionsFactory(config)

def test_save_key_value(self):
sender = Address.new_from_bech32("erd1qyu5wthldzr8wx5c9ucg8kjagg0jfs53s8nr3zpz3hypefsdd8ssycr6th")
pairs: Dict[bytes, bytes] = {}
key = bytes.fromhex("6b657930")
value = bytes.fromhex("76616c756530")
pairs[key] = value

tx = self.factory.create_transaction_for_saving_key_value(
sender=sender,
key_value_pairs=pairs
)

assert tx.sender == "erd1qyu5wthldzr8wx5c9ucg8kjagg0jfs53s8nr3zpz3hypefsdd8ssycr6th"
assert tx.receiver == "erd1qyu5wthldzr8wx5c9ucg8kjagg0jfs53s8nr3zpz3hypefsdd8ssycr6th"
assert tx.data.decode() == "SaveKeyValue@6b657930@76616c756530"
assert tx.gas_limit == 271000

def test_set_guardian(self):
sender = Address.new_from_bech32("erd1qyu5wthldzr8wx5c9ucg8kjagg0jfs53s8nr3zpz3hypefsdd8ssycr6th")
guardian = Address.new_from_bech32("erd1spyavw0956vq68xj8y4tenjpq2wd5a9p2c6j8gsz7ztyrnpxrruqzu66jx")
service_id = "MultiversXTCSService"

tx = self.factory.create_transaction_for_setting_guardian(
sender=sender,
guardian_address=guardian,
service_id=service_id
)

assert tx.sender == "erd1qyu5wthldzr8wx5c9ucg8kjagg0jfs53s8nr3zpz3hypefsdd8ssycr6th"
assert tx.receiver == "erd1qyu5wthldzr8wx5c9ucg8kjagg0jfs53s8nr3zpz3hypefsdd8ssycr6th"
assert tx.data.decode() == "SetGuardian@8049d639e5a6980d1cd2392abcce41029cda74a1563523a202f09641cc2618f8@4d756c7469766572735854435353657276696365"
assert tx.gas_limit == 525500

def test_guard_account(self):
sender = Address.new_from_bech32("erd1qyu5wthldzr8wx5c9ucg8kjagg0jfs53s8nr3zpz3hypefsdd8ssycr6th")
tx = self.factory.create_transaction_for_guarding_account(sender)

assert tx.sender == "erd1qyu5wthldzr8wx5c9ucg8kjagg0jfs53s8nr3zpz3hypefsdd8ssycr6th"
assert tx.receiver == "erd1qyu5wthldzr8wx5c9ucg8kjagg0jfs53s8nr3zpz3hypefsdd8ssycr6th"
assert tx.data.decode() == "GuardAccount"
assert tx.gas_limit == 368000

def test_unguard_account(self):
sender = Address.new_from_bech32("erd1qyu5wthldzr8wx5c9ucg8kjagg0jfs53s8nr3zpz3hypefsdd8ssycr6th")
tx = self.factory.create_transaction_for_unguarding_account(sender)

assert tx.sender == "erd1qyu5wthldzr8wx5c9ucg8kjagg0jfs53s8nr3zpz3hypefsdd8ssycr6th"
assert tx.receiver == "erd1qyu5wthldzr8wx5c9ucg8kjagg0jfs53s8nr3zpz3hypefsdd8ssycr6th"
assert tx.data.decode() == "UnGuardAccount"
assert tx.gas_limit == 371000
Original file line number Diff line number Diff line change
Expand Up @@ -207,3 +207,33 @@ def test_create_transaction_for_upgrade(self):
assert transaction.data.decode().startswith("upgradeContract@")
assert transaction.gas_limit == gas_limit
assert transaction.value == 0

def test_create_transaction_for_claiming_developer_rewards(self):
sender = Address.new_from_bech32("erd1qyu5wthldzr8wx5c9ucg8kjagg0jfs53s8nr3zpz3hypefsdd8ssycr6th")
contract_address = Address.new_from_bech32("erd1qqqqqqqqqqqqqpgqhy6nl6zq07rnzry8uyh6rtyq0uzgtk3e69fqgtz9l4")

transaction = self.factory.create_transaction_for_claiming_developer_rewards(
sender=sender,
contract=contract_address
)

assert transaction.sender == "erd1qyu5wthldzr8wx5c9ucg8kjagg0jfs53s8nr3zpz3hypefsdd8ssycr6th"
assert transaction.receiver == "erd1qqqqqqqqqqqqqpgqhy6nl6zq07rnzry8uyh6rtyq0uzgtk3e69fqgtz9l4"
assert transaction.data.decode() == "ClaimDeveloperRewards"
assert transaction.gas_limit == 6_000_000

def test_create_transaction_for_changing_owner_address(self):
sender = Address.new_from_bech32("erd1qyu5wthldzr8wx5c9ucg8kjagg0jfs53s8nr3zpz3hypefsdd8ssycr6th")
contract_address = Address.new_from_bech32("erd1qqqqqqqqqqqqqpgqhy6nl6zq07rnzry8uyh6rtyq0uzgtk3e69fqgtz9l4")
new_owner = Address.from_bech32("erd1spyavw0956vq68xj8y4tenjpq2wd5a9p2c6j8gsz7ztyrnpxrruqzu66jx")

transaction = self.factory.create_transaction_for_changing_owner_address(
sender=sender,
contract=contract_address,
new_owner=new_owner
)

assert transaction.sender == "erd1qyu5wthldzr8wx5c9ucg8kjagg0jfs53s8nr3zpz3hypefsdd8ssycr6th"
assert transaction.receiver == "erd1qqqqqqqqqqqqqpgqhy6nl6zq07rnzry8uyh6rtyq0uzgtk3e69fqgtz9l4"
assert transaction.data.decode() == "ChangeOwnerAddress@8049d639e5a6980d1cd2392abcce41029cda74a1563523a202f09641cc2618f8"
assert transaction.gas_limit == 6_000_000
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,8 @@ class IConfig(Protocol):
chain_id: str
min_gas_limit: int
gas_limit_per_byte: int
gas_limit_claim_developer_rewards: int
gas_limit_change_owner_address: int


class ITokenComputer(Protocol):
Expand Down Expand Up @@ -58,7 +60,7 @@ def create_transaction_for_deploy(self,

parts += args_to_strings(arguments)

transaction = TransactionBuilder(
return TransactionBuilder(
config=self.config,
sender=sender,
receiver=Address.new_from_bech32(CONTRACT_DEPLOY_ADDRESS),
Expand All @@ -68,8 +70,6 @@ def create_transaction_for_deploy(self,
amount=native_transfer_amount
).build()

return transaction

def create_transaction_for_execute(self,
sender: IAddress,
contract: IAddress,
Expand Down Expand Up @@ -103,7 +103,7 @@ def create_transaction_for_execute(self,
data_parts.append(function) if not data_parts else data_parts.append(arg_to_string(function))
data_parts.extend(args_to_strings(arguments))

transaction = TransactionBuilder(
return TransactionBuilder(
config=self.config,
sender=sender,
receiver=receiver,
Expand All @@ -113,8 +113,6 @@ def create_transaction_for_execute(self,
amount=native_transfer_amount
).build()

return transaction

def create_transaction_for_upgrade(self,
sender: IAddress,
contract: IAddress,
Expand All @@ -139,7 +137,7 @@ def create_transaction_for_upgrade(self,

parts += args_to_strings(arguments)

intent = TransactionBuilder(
return TransactionBuilder(
config=self.config,
sender=sender,
receiver=contract,
Expand All @@ -149,4 +147,31 @@ def create_transaction_for_upgrade(self,
amount=native_transfer_amount
).build()

return intent
def create_transaction_for_claiming_developer_rewards(self,
sender: IAddress,
contract: IAddress) -> Transaction:
data_parts = ["ClaimDeveloperRewards"]

return TransactionBuilder(
config=self.config,
sender=sender,
receiver=contract,
data_parts=data_parts,
gas_limit=self.config.gas_limit_claim_developer_rewards,
add_data_movement_gas=False
).build()

def create_transaction_for_changing_owner_address(self,
sender: IAddress,
contract: IAddress,
new_owner: IAddress) -> Transaction:
data_parts = ["ChangeOwnerAddress", new_owner.to_hex()]

return TransactionBuilder(
config=self.config,
sender=sender,
receiver=contract,
data_parts=data_parts,
gas_limit=self.config.gas_limit_change_owner_address,
add_data_movement_gas=False,
).build()
Original file line number Diff line number Diff line change
Expand Up @@ -41,3 +41,16 @@ def __init__(self, chain_id: str) -> None:
self.gas_limit_esdt_transfer = 200_000
self.gas_limit_esdt_nft_transfer = 200_000
self.gas_limit_multi_esdt_nft_transfer = 200_000

# Configuration for account operations
self.gas_limit_save_key_value = 100_000
self.gas_limit_persist_per_byte = 1_000
self.gas_limit_store_per_byte = 10_000
self.gas_limit_set_guardian = 250_000
self.gas_limit_guard_account = 250_000
self.gas_limit_unguard_account = 250_000
self.extra_gas_limit_for_guarded_transaction = 50_000

# Configuration for smart contract operations
self.gas_limit_claim_developer_rewards = 6_000_000
self.gas_limit_change_owner_address = 6_000_000
Loading