def _swap_close(self, context, signer_pubkey, swap_close_payload): """ Bob or Alice closes the swap by providing the secret key which matches secret lock. Requires "is_approved = True" Requires hash of secret key to match secret lock """ swap_info = self.get_swap_info_from_swap_id(context, swap_close_payload.swap_id) if not swap_info.secret_lock: raise InvalidTransaction( 'Secret lock is required to close the swap!') if hash256(swap_close_payload.secret_key) != swap_info.secret_lock: raise InvalidTransaction( 'Secret key doesn\'t match specified secret lock!') if not swap_info.is_approved: raise InvalidTransaction( 'Transaction cannot be closed before it\'s approved.') transfer_payload = AccountClient.get_transfer_payload( swap_info.receiver_address, swap_info.amount) token_updated_state = AccountHandler._transfer_from_address( context, ZERO_ADDRESS, transfer_payload) swap_info.is_closed = True return {**self.get_state_update(swap_info), **token_updated_state}
def _swap_expire(self, context, signer_pubkey, swap_expire_payload): """ Transaction initiator (Alice) decides to withdraw deposit in 24 hours, or Bob in 48 hours """ swap_info = self.get_swap_info_from_swap_id( context, swap_expire_payload.swap_id) if AccountHandler.make_address_from_data( signer_pubkey) != swap_info.sender_address: raise InvalidTransaction( 'Signer is not the one who opened the swap.') now = datetime.datetime.utcnow() created_at = self.get_datetime_from_timestamp(swap_info.created_at) time_delta = INITIATOR_TIME_DELTA_LOCK if swap_info.is_initiator else NON_INITIATOR_TIME_DELTA_LOCK if (created_at + time_delta) > now: intiator_name = "initiator" if swap_info.is_initiator else "non initiator" raise InvalidTransaction( 'Swap {} needs to wait {} hours since timestamp: {} to withdraw.' .format(intiator_name, INTIATOR_TIME_LOCK, swap_info.created_at)) swap_info.is_closed = True transfer_payload = AccountClient.get_transfer_payload( swap_info.sender_address, swap_info.amount) token_updated_state = AccountHandler._transfer_from_address( context, ZERO_ADDRESS, transfer_payload) return {**self.get_state_update(swap_info), **token_updated_state}
def _swap_init(self, context, signer_pubkey, swap_init_payload): """ if SecretLockOptionalBob is provided, Bob uses _swap_init to respond to requested swap Otherwise, Alice uses _swap_init to request a swap and thus, Bob can't receive funds until Alice "approves". """ LOGGER.info("0. Check if swap ID already exists") # 0. Check if swap ID already exists if self.get_swap_info_from_swap_id(context, swap_init_payload.swap_id, to_raise_exception=False): raise InvalidTransaction( 'Atomic swap ID has already been taken, please use a different one!' ) # END swap_info = AtomicSwapInfo() swap_info.swap_id = swap_init_payload.swap_id swap_info.is_closed = False swap_info.amount = swap_init_payload.amount swap_info.created_at = swap_init_payload.created_at swap_info.email_address_encrypted_optional = swap_init_payload.email_address_encrypted_by_initiator swap_info.sender_address = AccountHandler.make_address_from_data( signer_pubkey) swap_info.sender_address_non_local = swap_init_payload.sender_address_non_local swap_info.receiver_address = swap_init_payload.receiver_address if not AccountHandler.is_handler_address(swap_info.receiver_address): raise InvalidTransaction( 'Receiver address is not of a Token type.') LOGGER.info("1. Ensure transaction initiated within an hour") # 1. Ensure transaction initiated within an hour swap_info.secret_lock = swap_init_payload.secret_lock_by_solicitor created_at = self.get_datetime_from_timestamp(swap_info.created_at) now = datetime.datetime.utcnow() if not (now - datetime.timedelta(hours=1) < created_at < now): raise InvalidTransaction( 'Transaction is created a long time ago or timestamp is assigned set.' ) # END LOGGER.info("2. Check weather the sender is Alice") # 2. Check weather the sender is Alice: swap_info.is_initiator = not swap_init_payload.secret_lock_by_solicitor # if Bob swap_info.is_approved = not swap_info.is_initiator # END # 3. Transfer funds to zero address. LOGGER.info("3. Transfer funds to zero address") commission = int(_get_setting_value(context, SETTINGS_SWAP_COMMISSION)) if commission < 0: raise InvalidTransaction('Wrong commission address.') LOGGER.info("4. Get sender's account {}".format( swap_info.sender_address)) account = get_account_by_address(context, swap_info.sender_address) total_amount = swap_info.amount + commission if account.balance < total_amount: raise InvalidTransaction( 'Not enough balance to perform the transaction in ' 'the amount (with a commission) {}.'.format(total_amount)) transfer_payload = AccountClient.get_transfer_payload( ZERO_ADDRESS, total_amount) token_updated_state = AccountHandler._transfer_from_address( context, swap_info.sender_address, transfer_payload) LOGGER.info("Save state") return {**self.get_state_update(swap_info), **token_updated_state}