Skip to content

Commit

Permalink
offchain module
Browse files Browse the repository at this point in the history
  • Loading branch information
Xiao Li committed Dec 19, 2020
1 parent d4cecfc commit e671444
Show file tree
Hide file tree
Showing 29 changed files with 3,514 additions and 8 deletions.
4 changes: 4 additions & 0 deletions examples/vasp/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
# Copyright (c) The Diem Core Contributors
# SPDX-License-Identifier: Apache-2.0

from .wallet import WalletApp
66 changes: 66 additions & 0 deletions examples/vasp/conftest.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
# Copyright (c) The Diem Core Contributors
# SPDX-License-Identifier: Apache-2.0

from . import WalletApp
import pytest, typing


def launch_wallet_app(name: str) -> WalletApp:
app = WalletApp.generate(f"{name}'s wallet app")
app.start_server()
return app


@pytest.fixture(scope="module")
def wallet_apps() -> typing.List[WalletApp]:
return {name: launch_wallet_app(name) for name in ["sender", "receiver"]}


@pytest.fixture
def sender_app(wallet_apps):
yield from with_users(wallet_apps["sender"], ["foo", "user-x", "hello"])


@pytest.fixture
def receiver_app(wallet_apps):
yield from with_users(wallet_apps["receiver"], ["bar", "user-y", "world"])


def with_users(app, users):
for user in users:
app.add_user(user)
yield app
app.clear_data()


@pytest.fixture()
def assert_final_status(sender_app, receiver_app):
sender_vasp_balance = sender_app.vasp_balance()
receiver_vasp_balance = receiver_app.vasp_balance()

def assert_fn(
final_status: typing.Dict[str, str],
balance_change: typing.Optional[int] = 0,
) -> None:

sender_cmd = sender_app.saved_commands
receiver_cmd = receiver_app.saved_commands
assert len(sender_cmd) == 1
assert len(receiver_cmd) == 1

ref_id = list(sender_cmd.keys())[0]
sender_record = sender_cmd[ref_id]
assert sender_record.cid == receiver_cmd[ref_id].cid
assert sender_record.payment == receiver_cmd[ref_id].payment

assert sender_record.payment.sender.status.status == final_status["sender"]
assert sender_record.payment.receiver.status.status == final_status["receiver"]

assert sender_app.vasp_balance() == sender_vasp_balance - balance_change
assert receiver_app.vasp_balance() == receiver_vasp_balance + balance_change

# nothing left
assert sender_app.run_once_background_job() is None
assert receiver_app.run_once_background_job() is None

return assert_fn
321 changes: 321 additions & 0 deletions examples/vasp/test_offchain.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,321 @@
# Copyright (c) The Diem Core Contributors
# SPDX-License-Identifier: Apache-2.0

from diem.offchain import Status, Action
from .wallet import ActionResult


AMOUNT = 1_000_000_000
BOTH_READY = {
"sender": Status.ready_for_settlement,
"receiver": Status.ready_for_settlement,
}


def test_travel_rule_data_exchange_happy_path(sender_app, receiver_app, assert_final_status):
intent_id = receiver_app.gen_intent_id("bar", AMOUNT)
sender_app.pay("foo", intent_id)

assert len(sender_app.saved_commands) == 1
assert len(receiver_app.saved_commands) == 0

assert sender_app.run_once_background_job() == ActionResult.SEND_REQUEST_SUCCESS
assert len(receiver_app.saved_commands) == 1

assert receiver_app.run_once_background_job() == (
Action.EVALUATE_KYC_DATA,
ActionResult.PASS,
)
assert sender_app.run_once_background_job() is None
assert receiver_app.run_once_background_job() == ActionResult.SEND_REQUEST_SUCCESS
assert sender_app.run_once_background_job() == (
Action.EVALUATE_KYC_DATA,
ActionResult.PASS,
)
assert receiver_app.run_once_background_job() is None
assert sender_app.run_once_background_job() == ActionResult.SEND_REQUEST_SUCCESS
assert receiver_app.run_once_background_job() is None
assert sender_app.run_once_background_job() == (
Action.SUBMIT_TXN,
ActionResult.TXN_EXECUTED,
)
assert receiver_app.run_once_background_job() is None

assert_final_status(BOTH_READY, AMOUNT)


def test_travel_rule_data_exchange_receiver_reject_sender_kyc_data(sender_app, receiver_app, assert_final_status):
receiver_app.evaluate_kyc_data_result = {"foo": ActionResult.REJECT}

intent_id = receiver_app.gen_intent_id("bar", AMOUNT)
sender_app.pay("foo", intent_id)

assert sender_app.run_once_background_job() == ActionResult.SEND_REQUEST_SUCCESS
assert receiver_app.run_once_background_job() == (
Action.EVALUATE_KYC_DATA,
ActionResult.REJECT,
)
assert receiver_app.run_once_background_job() == ActionResult.SEND_REQUEST_SUCCESS

assert_final_status({"sender": Status.needs_kyc_data, "receiver": Status.abort})


def test_travel_rule_data_exchange_receiver_soft_match_reject(sender_app, receiver_app, assert_final_status):
receiver_app.evaluate_kyc_data_result = {"foo": ActionResult.SOFT_MATCH}
receiver_app.manual_review_result = {"foo": ActionResult.REJECT}

intent_id = receiver_app.gen_intent_id("bar", AMOUNT)
sender_app.pay("foo", intent_id)

assert sender_app.run_once_background_job() == ActionResult.SEND_REQUEST_SUCCESS
assert receiver_app.run_once_background_job() == (
Action.EVALUATE_KYC_DATA,
ActionResult.SOFT_MATCH,
)
assert receiver_app.run_once_background_job() == ActionResult.SEND_REQUEST_SUCCESS
assert sender_app.run_once_background_job() == (
Action.CLEAR_SOFT_MATCH,
ActionResult.SENT_ADDITIONAL_KYC_DATA,
)
assert sender_app.run_once_background_job() == ActionResult.SEND_REQUEST_SUCCESS
assert receiver_app.run_once_background_job() == (
Action.REVIEW_KYC_DATA,
ActionResult.REJECT,
)
assert receiver_app.run_once_background_job() == ActionResult.SEND_REQUEST_SUCCESS

assert_final_status({"sender": Status.needs_kyc_data, "receiver": Status.abort})


def test_travel_rule_data_exchange_receiver_soft_match_pass(sender_app, receiver_app, assert_final_status):
receiver_app.evaluate_kyc_data_result = {"foo": ActionResult.SOFT_MATCH}
receiver_app.manual_review_result = {"foo": ActionResult.PASS}

intent_id = receiver_app.gen_intent_id("bar", AMOUNT)
sender_app.pay("foo", intent_id)

assert sender_app.run_once_background_job() == ActionResult.SEND_REQUEST_SUCCESS
assert receiver_app.run_once_background_job() == (
Action.EVALUATE_KYC_DATA,
ActionResult.SOFT_MATCH,
)
assert receiver_app.run_once_background_job() == ActionResult.SEND_REQUEST_SUCCESS
assert sender_app.run_once_background_job() == (
Action.CLEAR_SOFT_MATCH,
ActionResult.SENT_ADDITIONAL_KYC_DATA,
)
assert sender_app.run_once_background_job() == ActionResult.SEND_REQUEST_SUCCESS
assert receiver_app.run_once_background_job() == (
Action.REVIEW_KYC_DATA,
ActionResult.PASS,
)
assert receiver_app.run_once_background_job() == ActionResult.SEND_REQUEST_SUCCESS
assert sender_app.run_once_background_job() == (
Action.EVALUATE_KYC_DATA,
ActionResult.PASS,
)
assert sender_app.run_once_background_job() == ActionResult.SEND_REQUEST_SUCCESS
assert receiver_app.run_once_background_job() is None

assert sender_app.run_once_background_job() == (
Action.SUBMIT_TXN,
ActionResult.TXN_EXECUTED,
)
assert receiver_app.run_once_background_job() is None

assert_final_status(BOTH_READY, AMOUNT)


def test_travel_rule_data_exchange_sender_rejects_receiver_kyc_data(sender_app, receiver_app, assert_final_status):
sender_app.evaluate_kyc_data_result = {"bar": ActionResult.REJECT}

intent_id = receiver_app.gen_intent_id("bar", AMOUNT)
sender_app.pay("foo", intent_id)

assert sender_app.run_once_background_job() == ActionResult.SEND_REQUEST_SUCCESS
assert receiver_app.run_once_background_job() == (
Action.EVALUATE_KYC_DATA,
ActionResult.PASS,
)
assert receiver_app.run_once_background_job() == ActionResult.SEND_REQUEST_SUCCESS
assert sender_app.run_once_background_job() == (
Action.EVALUATE_KYC_DATA,
ActionResult.REJECT,
)
assert sender_app.run_once_background_job() == ActionResult.SEND_REQUEST_SUCCESS
assert receiver_app.run_once_background_job() is None

assert_final_status({"sender": Status.abort, "receiver": Status.ready_for_settlement})


def test_travel_rule_data_exchange_sender_soft_match_reject(sender_app, receiver_app, assert_final_status):
sender_app.evaluate_kyc_data_result = {"bar": ActionResult.SOFT_MATCH}
sender_app.manual_review_result = {"bar": ActionResult.REJECT}

intent_id = receiver_app.gen_intent_id("bar", AMOUNT)
sender_app.pay("foo", intent_id)

assert sender_app.run_once_background_job() == ActionResult.SEND_REQUEST_SUCCESS
assert receiver_app.run_once_background_job() == (
Action.EVALUATE_KYC_DATA,
ActionResult.PASS,
)
assert receiver_app.run_once_background_job() == ActionResult.SEND_REQUEST_SUCCESS
assert sender_app.run_once_background_job() == (
Action.EVALUATE_KYC_DATA,
ActionResult.SOFT_MATCH,
)
assert sender_app.run_once_background_job() == ActionResult.SEND_REQUEST_SUCCESS
assert receiver_app.run_once_background_job() == (
Action.CLEAR_SOFT_MATCH,
ActionResult.SENT_ADDITIONAL_KYC_DATA,
)
assert receiver_app.run_once_background_job() == ActionResult.SEND_REQUEST_SUCCESS
assert sender_app.run_once_background_job() == (
Action.REVIEW_KYC_DATA,
ActionResult.REJECT,
)
assert sender_app.run_once_background_job() == ActionResult.SEND_REQUEST_SUCCESS
assert receiver_app.run_once_background_job() is None

assert_final_status({"sender": Status.abort, "receiver": Status.ready_for_settlement})


def test_travel_rule_data_exchange_sender_soft_match_pass(sender_app, receiver_app, assert_final_status):
sender_app.evaluate_kyc_data_result = {"bar": ActionResult.SOFT_MATCH}
sender_app.manual_review_result = {"bar": ActionResult.PASS}

intent_id = receiver_app.gen_intent_id("bar", AMOUNT)
sender_app.pay("foo", intent_id)

assert sender_app.run_once_background_job() == ActionResult.SEND_REQUEST_SUCCESS
assert receiver_app.run_once_background_job() == (
Action.EVALUATE_KYC_DATA,
ActionResult.PASS,
)
assert receiver_app.run_once_background_job() == ActionResult.SEND_REQUEST_SUCCESS
assert sender_app.run_once_background_job() == (
Action.EVALUATE_KYC_DATA,
ActionResult.SOFT_MATCH,
)
assert sender_app.run_once_background_job() == ActionResult.SEND_REQUEST_SUCCESS
assert receiver_app.run_once_background_job() == (
Action.CLEAR_SOFT_MATCH,
ActionResult.SENT_ADDITIONAL_KYC_DATA,
)
assert receiver_app.run_once_background_job() == ActionResult.SEND_REQUEST_SUCCESS
assert sender_app.run_once_background_job() == (
Action.REVIEW_KYC_DATA,
ActionResult.PASS,
)
assert sender_app.run_once_background_job() == ActionResult.SEND_REQUEST_SUCCESS
assert receiver_app.run_once_background_job() is None
assert sender_app.run_once_background_job() == (
Action.SUBMIT_TXN,
ActionResult.TXN_EXECUTED,
)
assert receiver_app.run_once_background_job() is None

assert_final_status(BOTH_READY, AMOUNT)


def test_travel_rule_data_exchange_receiver_soft_match_pass_sender_soft_match_reject(
sender_app, receiver_app, assert_final_status
):
receiver_app.evaluate_kyc_data_result = {"foo": ActionResult.SOFT_MATCH}
receiver_app.manual_review_result = {"foo": ActionResult.PASS}
sender_app.evaluate_kyc_data_result = {"bar": ActionResult.SOFT_MATCH}
sender_app.manual_review_result = {"bar": ActionResult.REJECT}

intent_id = receiver_app.gen_intent_id("bar", AMOUNT)
sender_app.pay("foo", intent_id)

assert sender_app.run_once_background_job() == ActionResult.SEND_REQUEST_SUCCESS
assert receiver_app.run_once_background_job() == (
Action.EVALUATE_KYC_DATA,
ActionResult.SOFT_MATCH,
)
assert receiver_app.run_once_background_job() == ActionResult.SEND_REQUEST_SUCCESS
assert sender_app.run_once_background_job() == (
Action.CLEAR_SOFT_MATCH,
ActionResult.SENT_ADDITIONAL_KYC_DATA,
)
assert sender_app.run_once_background_job() == ActionResult.SEND_REQUEST_SUCCESS
assert receiver_app.run_once_background_job() == (
Action.REVIEW_KYC_DATA,
ActionResult.PASS,
)
assert receiver_app.run_once_background_job() == ActionResult.SEND_REQUEST_SUCCESS

assert sender_app.run_once_background_job() == (
Action.EVALUATE_KYC_DATA,
ActionResult.SOFT_MATCH,
)
assert sender_app.run_once_background_job() == ActionResult.SEND_REQUEST_SUCCESS
assert receiver_app.run_once_background_job() == (
Action.CLEAR_SOFT_MATCH,
ActionResult.SENT_ADDITIONAL_KYC_DATA,
)
assert receiver_app.run_once_background_job() == ActionResult.SEND_REQUEST_SUCCESS
assert sender_app.run_once_background_job() == (
Action.REVIEW_KYC_DATA,
ActionResult.REJECT,
)
assert sender_app.run_once_background_job() == ActionResult.SEND_REQUEST_SUCCESS
assert receiver_app.run_once_background_job() is None

assert_final_status({"sender": Status.abort, "receiver": Status.ready_for_settlement})


def test_travel_rule_data_exchange_receiver_soft_match_pass_sender_soft_match_pass(
sender_app, receiver_app, assert_final_status
):
receiver_app.evaluate_kyc_data_result = {"foo": ActionResult.SOFT_MATCH}
receiver_app.manual_review_result = {"foo": ActionResult.PASS}
sender_app.evaluate_kyc_data_result = {"bar": ActionResult.SOFT_MATCH}
sender_app.manual_review_result = {"bar": ActionResult.PASS}

intent_id = receiver_app.gen_intent_id("bar", AMOUNT)
sender_app.pay("foo", intent_id)

assert sender_app.run_once_background_job() == ActionResult.SEND_REQUEST_SUCCESS
assert receiver_app.run_once_background_job() == (
Action.EVALUATE_KYC_DATA,
ActionResult.SOFT_MATCH,
)
assert receiver_app.run_once_background_job() == ActionResult.SEND_REQUEST_SUCCESS
assert sender_app.run_once_background_job() == (
Action.CLEAR_SOFT_MATCH,
ActionResult.SENT_ADDITIONAL_KYC_DATA,
)
assert sender_app.run_once_background_job() == ActionResult.SEND_REQUEST_SUCCESS
assert receiver_app.run_once_background_job() == (
Action.REVIEW_KYC_DATA,
ActionResult.PASS,
)
assert receiver_app.run_once_background_job() == ActionResult.SEND_REQUEST_SUCCESS

assert sender_app.run_once_background_job() == (
Action.EVALUATE_KYC_DATA,
ActionResult.SOFT_MATCH,
)
assert sender_app.run_once_background_job() == ActionResult.SEND_REQUEST_SUCCESS
assert receiver_app.run_once_background_job() == (
Action.CLEAR_SOFT_MATCH,
ActionResult.SENT_ADDITIONAL_KYC_DATA,
)
assert receiver_app.run_once_background_job() == ActionResult.SEND_REQUEST_SUCCESS
assert sender_app.run_once_background_job() == (
Action.REVIEW_KYC_DATA,
ActionResult.PASS,
)
assert sender_app.run_once_background_job() == ActionResult.SEND_REQUEST_SUCCESS
assert receiver_app.run_once_background_job() is None

assert sender_app.run_once_background_job() == (
Action.SUBMIT_TXN,
ActionResult.TXN_EXECUTED,
)
assert receiver_app.run_once_background_job() is None

assert_final_status(BOTH_READY, AMOUNT)
Loading

0 comments on commit e671444

Please sign in to comment.