def _evaluate_kyc_data(self, command: offchain.Command) -> typing.Tuple[ActionResultType, offchain.Command]: command = typing.cast(offchain.PaymentCommand, command) op_kyc_data = command.opponent_actor_obj().kyc_data assert op_kyc_data is not None ret = self.evaluate_kyc_data_result.get(str(op_kyc_data.given_name), ActionResult.PASS) if ret == ActionResult.SOFT_MATCH: return (ret, command.new_command(status=offchain.Status.soft_match)) return (ret, self._kyc_data_result("evaluate key data", ret, command))
def _send_additional_kyc_data(self, command: offchain.Command) -> typing.Tuple[ActionResultType, offchain.Command]: command = typing.cast(offchain.PaymentCommand, command) account_id = command.my_actor_obj().address _, subaddress = identifier.decode_account(account_id, self.hrp) if subaddress: user = self._find_user_by_subaddress(subaddress) else: raise ValueError(f"{account_id} has no sub-address") new_cmd = command.new_command(additional_kyc_data=user.additional_kyc_data()) return (ActionResult.SENT_ADDITIONAL_KYC_DATA, new_cmd)
def _manual_review( self, command: offchain.Command ) -> typing.Tuple[ActionResult, offchain.PaymentCommand]: command = typing.cast(offchain.PaymentCommand, command) op_kyc_data = command.opponent_actor_obj().kyc_data ret = self.manual_review_result.get(op_kyc_data.given_name, ActionResult.PASS) return (ret, self._kyc_data_result("review", ret, command))
def _manual_review( self, command: offchain.Command ) -> typing.Tuple[ActionResultType, offchain.Command]: command = typing.cast(offchain.PaymentCommand, command) op_kyc_data = command.counterparty_actor_obj().kyc_data assert op_kyc_data is not None ret = self.manual_review_result.get(str(op_kyc_data.given_name), ActionResult.PASS) return (ret, self._kyc_data_result("review", ret, command))
def _submit_travel_rule_txn( self, command: offchain.Command, ) -> ActionResultType: command = typing.cast(offchain.PaymentCommand, command) child_vasp = self._find_child_vasp(command.sender_account_address(self.hrp)) assert command.payment.recipient_signature child_vasp.submit_and_wait_for_txn( self.jsonrpc_client, stdlib.encode_peer_to_peer_with_metadata_script( currency=utils.currency_code(command.payment.action.currency), payee=command.receiver_account_address(self.hrp), amount=command.payment.action.amount, metadata=command.travel_rule_metadata(self.hrp), metadata_signature=bytes.fromhex(command.payment.recipient_signature), ), ) return ActionResult.TXN_EXECUTED
def save_command(self, command: offchain.Command) -> None: """save command locks prior command by reference id, validate and save new command. in a production implementation, the lock should be database / distributed lock to ensure atomic process(read and write) command by the reference id. """ lock = self.lock(command.reference_id()) if not lock.acquire(blocking=False): msg = "command(reference_id=%s) is locked" % command.reference_id() raise offchain.command_error(offchain.ErrorCode.conflict, msg) try: prior = self.saved_commands.get(command.reference_id()) if command == prior: return command.validate(prior) self.saved_commands[command.reference_id()] = command if command.is_inbound(): self._enqueue_follow_up_action(command) else: # outbound self.task_queue.append(lambda app: app._send_request(command)) finally: lock.release()
def _enqueue_follow_up_action(self, command: offchain.Command) -> None: if command.follow_up_action(): self.task_queue.append(lambda app: app._offchain_business_action(command.reference_id()))