Skip to content

Commit

Permalink
feat: business logic for getting a token transfer
Browse files Browse the repository at this point in the history
  • Loading branch information
danut13 committed Jul 12, 2024
1 parent 73d0317 commit cec15c7
Show file tree
Hide file tree
Showing 5 changed files with 442 additions and 29 deletions.
14 changes: 7 additions & 7 deletions pantos/client/library/api.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,9 @@
"""
__all__ = [
'Blockchain', 'BlockchainAddress', 'PantosClientError', 'PrivateKey',
'ServiceNodeBid', 'TokenSymbol', 'decrypt_private_key',
'retrieve_service_node_bids', 'retrieve_token_balance', 'transfer_tokens',
'ServiceNodeBid', 'TokenSymbol', 'TokenTransferInfo',
'decrypt_private_key', 'retrieve_service_node_bids',
'retrieve_token_balance', 'transfer_tokens',
'deploy_pantos_compatible_token'
]

Expand Down Expand Up @@ -33,10 +34,9 @@
TokenInteractor as _TokenInteractor
from pantos.client.library.business.transfers import \
TransferInteractor as _TransferInteractor
from pantos.client.library.business.transfers import \
TransferTokensResponse as _TransferTokensResponse
from pantos.client.library.constants import \
TOKEN_SYMBOL_PAN as _TOKEN_SYMBOL_PAN
from pantos.client.library.entitites import TokenTransferInfo
from pantos.client.library.exceptions import ClientError as _ClientError

# Exception to be used by external client library users
Expand Down Expand Up @@ -150,7 +150,7 @@ def transfer_tokens(
sender_private_key: PrivateKey, recipient_address: BlockchainAddress,
source_token_id: _TokenId, token_amount: _Amount,
service_node_bid: _typing.Optional[_BlockchainAddressBidPair] = None) \
-> _TransferTokensResponse:
-> TokenTransferInfo:
"""Transfer tokens from a sender's account on a source blockchain to
a recipient's account on a (possibly different) destination blockchain.
Expand Down Expand Up @@ -181,8 +181,8 @@ def transfer_tokens(
Returns
-------
TransferTokensResponse
The response of the token transfer.
TokenTransferInfo
The information of the token transfer.
Raises
------
Expand Down
139 changes: 117 additions & 22 deletions pantos/client/library/business/transfers.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
from pantos.common.blockchains.base import Blockchain
from pantos.common.entities import BlockchainAddressBidPair
from pantos.common.entities import ServiceNodeBid
from pantos.common.entities import ServiceNodeTransferStatus
from pantos.common.servicenodes import ServiceNodeClient
from pantos.common.types import Amount
from pantos.common.types import BlockchainAddress
Expand All @@ -18,10 +19,15 @@

from pantos.client.library.blockchains import BlockchainClient
from pantos.client.library.blockchains import get_blockchain_client
from pantos.client.library.blockchains.base import UnknownTransferError
from pantos.client.library.business.base import Interactor
from pantos.client.library.business.base import InteractorError
from pantos.client.library.business.bids import BidInteractor
from pantos.client.library.business.tokens import TokenInteractor
from pantos.client.library.configuration import get_blockchain_config
from pantos.client.library.entitites import DestinationTransferStatus
from pantos.client.library.entitites import TokenTransferInfo
from pantos.client.library.entitites import TokenTransferStatus

_DEFAULT_VALID_UNTIL_BUFFER = 120
"""Default "valid until" timestamp buffer for a token transfer in seconds."""
Expand All @@ -34,28 +40,33 @@ class TransferInteractorError(InteractorError):
pass


@dataclasses.dataclass
class TransferTokensResponse:
"""Response data for a new token transfer.
Attributes
----------
task_id : uuid.UUID
The task ID of the chosen service node for the token
transfer.
service_node_address : BlockchainAddress
The address of the chosen service node for the token
transfer.
class TransferInteractor(Interactor):
"""Interactor for handling Pantos token transfers.
"""
task_id: uuid.UUID
service_node_address: BlockchainAddress
@dataclasses.dataclass
class TokenTransferStatusRequest:
"""Request data for the status of a token transfer.
Attributes
----------
source_blockchain : Blockchain
The token transfer's source blockchain.
service_node_address : BlockchainAddress
The address of the service node that is processing the
token transfer.
task_id : uuid.UUID
The task ID of the token transfer.
blocks_to_search : int or None
The number of blocks to search for the token transfer
(default: None).
class TransferInteractor(Interactor):
"""Interactor for handling Pantos token transfers.
"""
source_blockchain: Blockchain
service_node_address: BlockchainAddress
task_id: uuid.UUID
blocks_to_search: int | None = None

"""
@dataclasses.dataclass
class TransferTokensRequest:
"""Request data for a new token transfer.
Expand Down Expand Up @@ -98,8 +109,8 @@ class TransferTokensRequest:
service_node_bid: typing.Optional[BlockchainAddressBidPair] = None
valid_until_buffer: int = _DEFAULT_VALID_UNTIL_BUFFER

def transfer_tokens(
self, request: TransferTokensRequest) -> TransferTokensResponse:
def transfer_tokens(self,
request: TransferTokensRequest) -> TokenTransferInfo:
"""Transfer tokens from a sender's account on a source
blockchain to a recipient's account on a (possibly different)
destination blockchain.
Expand All @@ -111,8 +122,8 @@ def transfer_tokens(
Returns
-------
TransferTokensResponse
The response data of the token transfer.
TokenTransferInfo
The information of the token transfer.
Raises
------
Expand Down Expand Up @@ -178,13 +189,75 @@ def transfer_tokens(
signature)
task_id = ServiceNodeClient().submit_transfer(
submit_transfer_request)
return TransferTokensResponse(task_id, service_node_address)
return TokenTransferInfo(task_id, service_node_address)
except TransferInteractorError:
raise
except Exception:
raise TransferInteractorError('unable to execute a token transfer',
request=request)

def get_token_transfer_status(self, request: TokenTransferStatusRequest) \
-> TokenTransferStatus:
"""Get the status of a token transfer.
Parameters
----------
request : TokenTransferStatusRequest
The request data for the status of a token transfer.
Returns
-------
TokenTransferStatus
The data of the token transfer status.
Raises
------
TransferInteractorError
If the token transfer status cannot be retrieved.
"""
try:
service_node_url = get_blockchain_client(
request.source_blockchain).read_service_node_url(
request.service_node_address)
source_status = ServiceNodeClient().status(service_node_url,
request.task_id)
token_transfer_status = \
self.__create_token_transfer_status_response(source_status)
if source_status.status is not ServiceNodeTransferStatus.CONFIRMED:
return token_transfer_status
source_transaction_id = source_status.transaction_id
token_transfer_status.source_transaction_id = source_transaction_id
token_transfer_status.source_transfer_id = \
source_status.transfer_id
destination_transfer_request = \
BlockchainClient.DestinationTransferRequest(
request.source_blockchain, source_transaction_id)
try:
destination_response = get_blockchain_client(
source_status.destination_blockchain
).read_destination_transfer(destination_transfer_request)
except UnknownTransferError:
return token_transfer_status
token_transfer_status.destination_transfer_status = \
self.__get_destination_transfer_status(
destination_response.latest_block_number,
destination_response.transaction_block_number,
source_status.destination_blockchain)
token_transfer_status.destination_transaction_id = \
destination_response.destination_transaction_id
token_transfer_status.destination_transfer_id = \
destination_response.destination_transfer_id
token_transfer_status.validator_nonce = \
destination_response.validator_nonce
token_transfer_status.signer_addresses = \
destination_response.signer_addresses
token_transfer_status.signatures = destination_response.signatures
return token_transfer_status
except Exception:
raise TransferInteractorError(
'unable to get token transfer status', request=request)

def __compute_token_amount(self, request: TransferTokensRequest,
source_token_address: BlockchainAddress) -> int:
if isinstance(request.token_amount, int):
Expand Down Expand Up @@ -225,3 +298,25 @@ def __validate_recipient_address(self, request: TransferTokensRequest):
recipient_address):
raise TransferInteractorError('invalid recipient address',
recipient_address=recipient_address)

def __create_token_transfer_status_response(
self,
transfer_status: ServiceNodeClient.TransferStatusResponse) \
-> TokenTransferStatus:
return TokenTransferStatus(
destination_blockchain=transfer_status.destination_blockchain,
source_transfer_status=transfer_status.status,
destination_transfer_status=DestinationTransferStatus.UNKNOWN,
sender_address=transfer_status.sender_address,
recipient_address=transfer_status.recipient_address,
source_token_address=transfer_status.source_token_address,
destination_token_address=transfer_status.
destination_token_address, amount=transfer_status.token_amount)

def __get_destination_transfer_status(
self, latest_block_number: int, transaction_block_number: int,
blockchain: Blockchain) -> DestinationTransferStatus:
confirmations = get_blockchain_config(blockchain)['confirmations']
if latest_block_number - transaction_block_number < confirmations:
return DestinationTransferStatus.SUBMITTED
return DestinationTransferStatus.CONFIRMED
101 changes: 101 additions & 0 deletions pantos/client/library/entitites.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,101 @@
"""Module that defines the Pantos client library entities.
"""
import dataclasses
import enum
import uuid

from pantos.common.blockchains.enums import Blockchain
from pantos.common.servicenodes import ServiceNodeTransferStatus
from pantos.common.types import BlockchainAddress


class DestinationTransferStatus(enum.Enum):
"""Enumeration of the possible destination transfer statuses.
"""
UNKNOWN = 0
SUBMITTED = 1
CONFIRMED = 2


@dataclasses.dataclass
class TokenTransferInfo:
"""Information about a token transfer.
Attributes
----------
task_id : uuid.UUID
The task ID of the chosen service node for the token
transfer.
service_node_address : BlockchainAddress
The address of the chosen service node for the token
transfer.
"""
task_id: uuid.UUID
service_node_address: BlockchainAddress


@dataclasses.dataclass
class TokenTransferStatus:
"""Data for the status of a token transfer.
Attributes
----------
destination_blockchain : Blockchain
The token transfer's destination blockchain.
source_transfer_status : ServiceNodeTransferStatus
The status of the token transfer on the source blockchain.
destination_transfer_status : DestinationTransferStatus
The status of the token transfer on the destination blockchain.
source_transaction_id : str or None
The transaction ID of the token transfer on the source
blockchain (default: None).
destination_transaction_id : str or None
The transaction ID of the token transfer on the destination
blockchain (default: None).
source_transfer_id : int or None
The transfer ID of the token transfer on the source
blockchain (default: None).
destination_transfer_id : int or None
The transfer ID of the token transfer on the destination
blockchain (default: None).
sender_address : BlockchainAddress or None
The address of the sender's account on the source blockchain
(default: None).
recipient_address : BlockchainAddress or None
The address of the recipient's account on the destination
blockchain (default: None).
source_token_address : BlockchainAddress or None
The address of the token on the source blockchain (default:
None).
destination_token_address : BlockchainAddress or None
The address of the token on the destination blockchain
(default: None).
amount : int or None
The amount of tokens transferred (default: None).
validator_nonce : int or None
The validator nonce of the token transfer (default: None).
signer_addresses : list[BlockchainAddress] or None
The addresses of the signers of the token transfer (default:
None).
signatures : list[str] or None
The signatures of the token transfer (default: None).
"""
destination_blockchain: Blockchain
source_transfer_status: ServiceNodeTransferStatus
destination_transfer_status: DestinationTransferStatus
source_transaction_id: str | None = None
destination_transaction_id: str | None = None
source_transfer_id: int | None = None
destination_transfer_id: int | None = None
sender_address: BlockchainAddress | None = None
recipient_address: BlockchainAddress | None = None
source_token_address: BlockchainAddress | None = None
destination_token_address: BlockchainAddress | None = None
amount: int | None = None
validator_nonce: int | None = None
signer_addresses: list[BlockchainAddress] | None = None
signatures: list[str] | None = None
Loading

0 comments on commit cec15c7

Please sign in to comment.