Skip to content

Commit

Permalink
intent identifier params should be optional
Browse files Browse the repository at this point in the history
changed to allow optional currency and amount params in intent identifier
  • Loading branch information
Xiao Li committed Feb 24, 2021
1 parent 4edb06d commit f5de5ec
Show file tree
Hide file tree
Showing 3 changed files with 50 additions and 20 deletions.
5 changes: 4 additions & 1 deletion examples/vasp/wallet.py
Original file line number Diff line number Diff line change
Expand Up @@ -107,11 +107,14 @@ def pay(
"""make payment from given user account to intent_id"""

intent = identifier.decode_intent(intent_id, self.hrp)
if not intent.amount or not intent.currency_code:
raise ValueError("should provide currency_code and amount")

command = offchain.PaymentCommand.init(
self.gen_user_account_id(user_name),
self.users[user_name].kyc_data(),
intent.account_id,
intent.amount,
intent.amount, # pyre-ignore
intent.currency_code,
original_payment_reference_id=original_payment_reference_id,
description=desc,
Expand Down
23 changes: 16 additions & 7 deletions src/diem/identifier/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -40,15 +40,15 @@ class Intent:

account_address: diem_types.AccountAddress
sub_address: typing.Optional[bytes]
currency_code: str
amount: int
currency_code: typing.Optional[str]
amount: typing.Optional[int]

def __init__(
self,
account_address: diem_types.AccountAddress,
sub_address: typing.Optional[bytes],
currency_code: str,
amount: int,
currency_code: typing.Optional[str],
amount: typing.Optional[int],
hrp: str,
) -> None:
self.account_address = account_address
Expand All @@ -66,13 +66,22 @@ def account_id(self) -> str:
return encode_account(self.account_address, self.sub_address, self.hrp)


def encode_intent(encoded_account_identifier: str, currency_code: str, amount: int) -> str:
def encode_intent(
encoded_account_identifier: str, currency_code: typing.Optional[str] = None, amount: typing.Optional[int] = None
) -> str:
"""
Encode account identifier string(encoded), currency code and amount into
Diem intent identifier (https://dip.diem.com/dip-5/)
"""

return "diem://%s?c=%s&am=%d" % (encoded_account_identifier, currency_code, amount)
params = []
if currency_code:
params.append("c=%s" % currency_code)
if amount is not None and amount > 0:
params.append("am=%s" % amount)
if params:
return "diem://%s?%s" % (encoded_account_identifier, "&".join(params))
return "diem://%s" % encoded_account_identifier


def decode_intent(encoded_intent_identifier: str, hrp: str) -> Intent:
Expand Down Expand Up @@ -113,7 +122,7 @@ def decode_intent(encoded_intent_identifier: str, hrp: str) -> Intent:

def _decode_param(name, params, field, convert): # pyre-ignore
if field not in params:
raise InvalidIntentIdentifierError(f"Can't decode {name}: not found in params {params}")
return None

if not isinstance(params[field], list):
raise InvalidIntentIdentifierError(f"Can't decode {name}: unknown type {params}")
Expand Down
42 changes: 30 additions & 12 deletions tests/test_identifier.py
Original file line number Diff line number Diff line change
Expand Up @@ -154,6 +154,22 @@ def test_intent_identifier(hrp_addresses):
assert account_id == intent.account_id


def test_intent_identifier_without_params(hrp_addresses):
hrp, enocded_addr_with_none_subaddr, enocded_addr_with_subaddr = hrp_addresses
account_id = identifier.encode_account(test_onchain_address, None, hrp)
intent_id = identifier.encode_intent(account_id)
assert intent_id == "diem://%s" % enocded_addr_with_none_subaddr

intent = identifier.decode_intent(intent_id, hrp)
assert intent.account_address == utils.account_address(test_onchain_address)
assert intent.account_address_bytes.hex() == test_onchain_address
assert intent.sub_address is None
assert intent.currency_code is None
assert intent.amount is None

assert account_id == intent.account_id


def test_intent_identifier_with_sub_address(hrp_addresses):
hrp, enocded_addr_with_none_subaddr, enocded_addr_with_subaddr = hrp_addresses
account_id = identifier.encode_account(test_onchain_address, test_sub_address, hrp)
Expand All @@ -167,28 +183,30 @@ def test_intent_identifier_with_sub_address(hrp_addresses):
assert intent.amount == 123


def test_intent_identifier_with_one_param():
account_id = "dm1p7ujcndcl7nudzwt8fglhx6wxnvqqqqqqqqqqqqqd8p9cq"
intent_id = identifier.encode_intent(account_id, currency_code="XUS")
assert intent_id == "diem://%s?c=%s" % (account_id, "XUS")
intent_id = identifier.encode_intent(account_id, currency_code="")
assert intent_id == "diem://%s" % account_id
intent_id = identifier.encode_intent(account_id, amount=122)
assert intent_id == "diem://%s?am=%s" % (account_id, 122)
intent_id = identifier.encode_intent(account_id, amount=0)
assert intent_id == "diem://%s" % account_id
intent_id = identifier.encode_intent(account_id, amount=-1)
assert intent_id == "diem://%s" % account_id


def test_intent_identifier_decode_errors(hrp_addresses):
hrp, enocded_addr_with_none_subaddr, enocded_addr_with_subaddr = hrp_addresses
# amount is not int
with pytest.raises(identifier.InvalidIntentIdentifierError):
identifier.decode_intent("diem://%s?c=XUS&am=str" % (enocded_addr_with_none_subaddr), hrp)

# amount not exist
with pytest.raises(identifier.InvalidIntentIdentifierError):
identifier.decode_intent("diem://%s?c=XUS" % (enocded_addr_with_none_subaddr), hrp)

# too many amount
with pytest.raises(identifier.InvalidIntentIdentifierError):
identifier.decode_intent("diem://%s?c=XUS&am=2&am=3" % (enocded_addr_with_none_subaddr), hrp)

# amount is none
with pytest.raises(identifier.InvalidIntentIdentifierError):
identifier.decode_intent("diem://%s?c=XUS&am=" % (enocded_addr_with_none_subaddr), hrp)

# currency code not exist
with pytest.raises(identifier.InvalidIntentIdentifierError):
identifier.decode_intent("diem://%s?am=2" % (enocded_addr_with_none_subaddr), hrp)

# scheme not match
with pytest.raises(identifier.InvalidIntentIdentifierError):
identifier.decode_intent("hello://%s?am=2&c=XUS" % (enocded_addr_with_none_subaddr), hrp)
Expand Down

0 comments on commit f5de5ec

Please sign in to comment.