Skip to content

Commit

Permalink
Add reference ID exchange object types (#274)
Browse files Browse the repository at this point in the history
Add reference ID exchange object types
  • Loading branch information
sunmilee authored Apr 27, 2021
1 parent 2e18398 commit 5bbe291
Show file tree
Hide file tree
Showing 5 changed files with 132 additions and 0 deletions.
2 changes: 2 additions & 0 deletions src/diem/offchain/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,8 @@
PaymentObject,
PaymentActorObject,
PaymentActionObject,
ReferenceIDCommandResultObject,
ReferenceIDCommandObject,
Status,
StatusObject,
KycDataObjectType,
Expand Down
59 changes: 59 additions & 0 deletions src/diem/offchain/reference_id_command.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
# Copyright (c) The Diem Core Contributors
# SPDX-License-Identifier: Apache-2.0

"""This module defines `ReferenceIDCommand` class provides utils for processing `ReferenceIDCommand` properly."""

import dataclasses, uuid
from .types import (
ReferenceIDCommandObject,
)


@dataclasses.dataclass(frozen=True)
class ReferenceIDCommand:
"""Wrapper object of `ReferenceIDCommand` with request information
Defined in DIP-10: https://github.com/diem/dip/blob/main/dips/dip-10.md
"""

reference_id_command_object: ReferenceIDCommandObject
cid: str = dataclasses.field(default_factory=lambda: str(uuid.uuid4()))

@staticmethod
def init(
sender: str,
sender_address: str,
receiver: str,
reference_id: str,
) -> "ReferenceIDCommand":
"""init functon initializes a new `ReferenceIDCommand` for starting the DiemID to address resolution"""

return ReferenceIDCommand(
reference_id_command_object=ReferenceIDCommandObject(
sender=sender, sender_address=sender_address, receiver=receiver, reference_id=reference_id
)
)

def id(self) -> str:
"""returns `cid` from the request object"""
return self.cid

def reference_id(self) -> str:
"""returns `reference_id` of `ReferenceIDCommand`"""

return self.reference_id_command_object.reference_id

def sender(self) -> str:
"""returns sender pay address"""

return self.reference_id_command_object.sender

def receiver(self) -> str:
"""returns receiver pay address"""

return self.reference_id_command_object.receiver

def sender_address(self) -> str:
"""returns sender address"""

return self.reference_id_command_object.sender_address
2 changes: 2 additions & 0 deletions src/diem/offchain/types/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,8 @@
OffChainErrorObject,
CommandRequestObject,
CommandResponseStatus,
ReferenceIDCommandObject,
ReferenceIDCommandResultObject,
FundPullPreApprovalCommandObject,
UUID_REGEX,
)
Expand Down
44 changes: 44 additions & 0 deletions src/diem/offchain/types/command_types.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ class CommandType:
PaymentCommand = "PaymentCommand"
FundPullPreApprovalCommand = "FundPullPreApprovalCommand"
PingCommand = "PingCommand"
ReferenceIDCommand = "ReferenceIDCommand"


class CommandResponseStatus:
Expand Down Expand Up @@ -79,6 +80,12 @@ class ErrorCode:
# Field payment.action.currency value is a valid Diem currency code, but it is not supported / acceptable by the receiver VASP.
unsupported_currency = "unsupported_currency"

# Duplicate Reference ID was rejected by the receiving end
duplicate_reference_id = "duplicate_reference_id"

# Receiving end could not find the user with the given user_identifier
invalid_receiver = "invalid_receiver"


class OffChainErrorType:
"""command_error occurs in response to a Command failing to be applied -
Expand All @@ -90,6 +97,12 @@ class OffChainErrorType:
protocol_error = "protocol_error"


class OffChainCommandResponseResultType:
""" Type of result in a CommandResponseObject"""

ReferenceIDCommandResponse = "ReferenceIDCommandResponse"


@dataclass(frozen=True)
class FundPullPreApprovalCommandObject:
_ObjectType: str = datafield(metadata={"valid-values": [CommandType.FundPullPreApprovalCommand]})
Expand Down Expand Up @@ -124,6 +137,20 @@ class OffChainErrorObject:
message: typing.Optional[str] = datafield(default=None)


@dataclass(frozen=True)
class ReferenceIDCommandResultObject:
# ReferenceIDCommandResponse: Receiver's onchain account identifier
receiver_address: str
_ObjectType: str = datafield(
default=OffChainCommandResponseResultType.ReferenceIDCommandResponse,
metadata={
"valid-values": [
OffChainCommandResponseResultType.ReferenceIDCommandResponse,
]
},
)


@dataclass(frozen=True)
class CommandResponseObject:
# Either success or failure.
Expand All @@ -134,3 +161,20 @@ class CommandResponseObject:
error: typing.Optional[OffChainErrorObject] = datafield(default=None)
# The Command identifier to which this is a response.
cid: typing.Optional[str] = datafield(default=None)
# An result JSON object that may be defined when status == "success"
result: typing.Optional[dict] = datafield(default=None) # pyre-ignore


@dataclass(frozen=True)
class ReferenceIDCommandObject:
# Sender's full DiemID
sender: str
# Sender's onchain account identifier with subaddress set to `None` or the zero subaddress
sender_address: str
# Receiver's full DiemID
receiver: str
# Reference ID of this transaction
reference_id: str
_ObjectType: str = datafield(
default=CommandType.ReferenceIDCommand, metadata={"valid-values": [CommandType.ReferenceIDCommand]}
)
25 changes: 25 additions & 0 deletions tests/test_offchain_types.py
Original file line number Diff line number Diff line change
Expand Up @@ -421,6 +421,31 @@ def test_missing_required_field():
)


def test_reference_id_command_result_object():
# Test can encode and decode correct response format
ref_id_command_result = offchain.ReferenceIDCommandResultObject(
receiver_address="dm1p7ujcndcl7nudzwt8fglhx6wxnvqqqqqqqqqqqqelu3xv",
)
response = offchain.CommandResponseObject(
status=offchain.CommandResponseStatus.success,
cid="3185027f-0574-6f55-2668-3a38fdb5de98",
result=offchain.to_dict(ref_id_command_result),
)
assert offchain.from_json(offchain.to_json(response), offchain.CommandResponseObject) == response
assert offchain.from_json(offchain.to_json(response)) == response
assert json.loads(offchain.to_json(response)) == json.loads(
"""{
"status": "success",
"_ObjectType": "CommandResponseObject",
"cid": "3185027f-0574-6f55-2668-3a38fdb5de98",
"result": {
"_ObjectType": "ReferenceIDCommandResponse",
"receiver_address": "dm1p7ujcndcl7nudzwt8fglhx6wxnvqqqqqqqqqqqqelu3xv"
}
}"""
)


def assert_cid(cid: str):
assert isinstance(cid, str)
assert uuid.UUID(cid)
Expand Down

0 comments on commit 5bbe291

Please sign in to comment.