Skip to content

feat: add offline_key_reg transaction to sender/creator/composer abstractions #129

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

Merged
merged 1 commit into from
Dec 23, 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
4 changes: 0 additions & 4 deletions src/algokit_utils/applications/app_client.py
Original file line number Diff line number Diff line change
Expand Up @@ -63,7 +63,6 @@
from algokit_utils.models.amount import AlgoAmount
from algokit_utils.models.state import BoxIdentifier, BoxReference, TealTemplateParams
from algokit_utils.protocols.client import AlgorandClientProtocol
from algokit_utils.transactions.transaction_composer import TransactionComposer

__all__ = [
"AppClient",
Expand Down Expand Up @@ -1299,9 +1298,6 @@ def get_box_values_from_abi_type(
# Return list of BoxABIValue objects
return [BoxABIValue(name=name, value=values[i]) for i, name in enumerate(names)]

def new_group(self) -> TransactionComposer:
return self._algorand.new_group()

def fund_app_account(self, params: FundAppAccountParams) -> SendSingleTransactionResult:
return self.send.fund_app_account(params)

Expand Down
71 changes: 52 additions & 19 deletions src/algokit_utils/transactions/transaction_composer.py
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,7 @@
"AssetOptInParams",
"AssetOptOutParams",
"AssetTransferParams",
"OfflineKeyRegistrationParams",
"OnlineKeyRegistrationParams",
"PaymentParams",
"SendAtomicTransactionComposerResults",
Expand Down Expand Up @@ -232,6 +233,15 @@ class OnlineKeyRegistrationParams(
state_proof_key: bytes | None = None


@dataclass(kw_only=True, frozen=True)
class OfflineKeyRegistrationParams(_CommonTxnWithSendParams):
"""
Offline key registration parameters.
"""

prevent_account_from_ever_participating_again: bool


@dataclass(kw_only=True, frozen=True)
class AssetTransferParams(
_CommonTxnWithSendParams,
Expand Down Expand Up @@ -306,7 +316,7 @@ class AppCallParams(_CommonTxnWithSendParams):
app_references: list[int] | None = None
asset_references: list[int] | None = None
extra_pages: int | None = None
box_references: list[BoxReference] | None = None
box_references: list[BoxReference | BoxIdentifier] | None = None


@dataclass(kw_only=True, frozen=True)
Expand Down Expand Up @@ -336,7 +346,7 @@ class AppCreateParams(_CommonTxnWithSendParams):
account_references: list[str] | None = None
app_references: list[int] | None = None
asset_references: list[int] | None = None
box_references: list[BoxReference] | None = None
box_references: list[BoxReference | BoxIdentifier] | None = None
extra_program_pages: int | None = None


Expand Down Expand Up @@ -416,7 +426,7 @@ class AppMethodCallParams(_CommonTxnWithSendParams):
account_references: list[str] | None = None
app_references: list[int] | None = None
asset_references: list[int] | None = None
box_references: list[BoxReference] | None = None
box_references: list[BoxReference | BoxIdentifier] | None = None


@dataclass(kw_only=True, frozen=True)
Expand Down Expand Up @@ -513,6 +523,7 @@ class AppDeleteMethodCallParams(_BaseAppMethodCall):
AppUpdateParams,
AppDeleteParams,
MethodCallParams,
OfflineKeyRegistrationParams,
]


Expand Down Expand Up @@ -802,6 +813,10 @@ def add_online_key_registration(self, params: OnlineKeyRegistrationParams) -> Tr
self._txns.append(params)
return self

def add_offline_key_registration(self, params: OfflineKeyRegistrationParams) -> TransactionComposer:
self._txns.append(params)
return self

def add_atc(self, atc: AtomicTransactionComposer) -> TransactionComposer:
self._txns.append(atc)
return self
Expand Down Expand Up @@ -1080,7 +1095,7 @@ def _build_method_call( # noqa: C901, PLR0912
txn = self._build_asset_freeze(arg, suggested_params)
case AssetTransferParams():
txn = self._build_asset_transfer(arg, suggested_params)
case OnlineKeyRegistrationParams():
case OnlineKeyRegistrationParams() | OfflineKeyRegistrationParams():
txn = self._build_key_reg(arg, suggested_params)
case _:
raise ValueError(f"Unsupported method arg transaction type: {arg!s}")
Expand Down Expand Up @@ -1288,22 +1303,40 @@ def _build_asset_transfer(
return self._common_txn_build_step(lambda x: algosdk.transaction.AssetTransferTxn(**x), params, txn_params)

def _build_key_reg(
self, params: OnlineKeyRegistrationParams, suggested_params: algosdk.transaction.SuggestedParams
self,
params: OnlineKeyRegistrationParams | OfflineKeyRegistrationParams,
suggested_params: algosdk.transaction.SuggestedParams,
) -> algosdk.transaction.Transaction:
txn_params = {
"sender": params.sender,
"sp": suggested_params,
"votekey": params.vote_key,
"selkey": params.selection_key,
"votefst": params.vote_first,
"votelst": params.vote_last,
"votekd": params.vote_key_dilution,
"rekey_to": params.rekey_to,
"nonpart": False,
"sprfkey": params.state_proof_key,
}
if isinstance(params, OnlineKeyRegistrationParams):
txn_params = {
"sender": params.sender,
"sp": suggested_params,
"votekey": params.vote_key,
"selkey": params.selection_key,
"votefst": params.vote_first,
"votelst": params.vote_last,
"votekd": params.vote_key_dilution,
"rekey_to": params.rekey_to,
"nonpart": False,
"sprfkey": params.state_proof_key,
}

return self._common_txn_build_step(lambda x: algosdk.transaction.KeyregTxn(**x), params, txn_params)
return self._common_txn_build_step(lambda x: algosdk.transaction.KeyregTxn(**x), params, txn_params)

return self._common_txn_build_step(
lambda x: algosdk.transaction.KeyregTxn(**x),
params,
{
"sender": params.sender,
"sp": suggested_params,
"nonpart": params.prevent_account_from_ever_participating_again,
"votekey": None,
"selkey": None,
"votefst": None,
"votelst": None,
"votekd": None,
},
)

def _is_abi_value(self, x: bool | float | str | bytes | list | TxnParams) -> bool:
if isinstance(x, list | tuple):
Expand Down Expand Up @@ -1369,7 +1402,7 @@ def _build_txn( # noqa: C901, PLR0912, PLR0911
suggested_params,
)
return [TransactionWithSigner(txn=asset_transfer, signer=signer)]
case OnlineKeyRegistrationParams():
case OnlineKeyRegistrationParams() | OfflineKeyRegistrationParams():
key_reg = self._build_key_reg(txn, suggested_params)
return [TransactionWithSigner(txn=key_reg, signer=signer)]
case _:
Expand Down
6 changes: 6 additions & 0 deletions src/algokit_utils/transactions/transaction_creator.py
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@
AssetOptOutParams,
AssetTransferParams,
BuiltTransactions,
OfflineKeyRegistrationParams,
OnlineKeyRegistrationParams,
PaymentParams,
TransactionComposer,
Expand Down Expand Up @@ -152,3 +153,8 @@ def app_call_method_call(self) -> Callable[[AppCallMethodCallParams], BuiltTrans
def online_key_registration(self) -> Callable[[OnlineKeyRegistrationParams], Transaction]:
"""Create an online key registration transaction."""
return self._transaction(lambda c: c.add_online_key_registration)

@property
def offline_key_registration(self) -> Callable[[OfflineKeyRegistrationParams], Transaction]:
"""Create an offline key registration transaction."""
return self._transaction(lambda c: c.add_offline_key_registration)
10 changes: 10 additions & 0 deletions src/algokit_utils/transactions/transaction_sender.py
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@
AssetOptInParams,
AssetOptOutParams,
AssetTransferParams,
OfflineKeyRegistrationParams,
OnlineKeyRegistrationParams,
PaymentParams,
SendAtomicTransactionComposerResults,
Expand Down Expand Up @@ -397,3 +398,12 @@ def online_key_registration(self, params: OnlineKeyRegistrationParams) -> SendSi
f"Registering online key for {params.sender} via transaction {transaction.get_txid()}"
),
)(params)

def offline_key_registration(self, params: OfflineKeyRegistrationParams) -> SendSingleTransactionResult:
"""Register an offline key."""
return self._send(
lambda c: c.add_offline_key_registration,
pre_log=lambda params, transaction: (
f"Registering offline key for {params.sender} via transaction {transaction.get_txid()}"
),
)(params)
14 changes: 13 additions & 1 deletion tests/transactions/test_transaction_sender.py
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@
AssetOptInParams,
AssetOptOutParams,
AssetTransferParams,
OfflineKeyRegistrationParams,
OnlineKeyRegistrationParams,
PaymentParams,
TransactionComposer,
Expand Down Expand Up @@ -449,7 +450,7 @@ def test_payment_logging(
assert receiver.address in log_message


def test_online_key_registration(transaction_sender: AlgorandClientTransactionSender, sender: Account) -> None:
def test_key_registration(transaction_sender: AlgorandClientTransactionSender, sender: Account) -> None:
sp = transaction_sender._algod.suggested_params() # noqa: SLF001

params = OnlineKeyRegistrationParams(
Expand All @@ -465,3 +466,14 @@ def test_online_key_registration(transaction_sender: AlgorandClientTransactionSe
result = transaction_sender.online_key_registration(params)
assert len(result.tx_ids) == 1
assert result.confirmations[-1]["confirmed-round"] > 0 # type: ignore[call-overload]

sp = transaction_sender._algod.suggested_params() # noqa: SLF001

off_key_reg_params = OfflineKeyRegistrationParams(
sender=sender.address,
prevent_account_from_ever_participating_again=True,
)

result = transaction_sender.offline_key_registration(off_key_reg_params)
assert len(result.tx_ids) == 1
assert result.confirmations[-1]["confirmed-round"] > 0 # type: ignore[call-overload]
Loading