def refund():
	"""
	"	Refund real bet:
	"		This step make sure user's feed will update pending status
	"""
	try:
		uid = int(request.headers['Uid'])
		user = User.find_user_with_id(uid)

		data = request.json
		if data is None:
			return response_error(MESSAGE.INVALID_DATA, CODE.INVALID_DATA)

		offchain = data.get('offchain', '')
		if len(offchain) == 0:
			return response_error(MESSAGE.MISSING_OFFCHAIN, CODE.MISSING_OFFCHAIN)

		offchain = offchain.replace(CONST.CRYPTOSIGN_OFFCHAIN_PREFIX, '')
		outcome = None
		if 'm' in offchain:
			offchain = int(offchain.replace('m', ''))
			handshake = db.session.query(Handshake).filter(and_(Handshake.id==offchain, Handshake.user_id==user.id)).first()
			if handshake is None:
				return response_error(MESSAGE.HANDSHAKE_CANNOT_REFUND, CODE.HANDSHAKE_CANNOT_REFUND)

			outcome = Outcome.find_outcome_by_id(handshake.outcome_id)

		elif 's' in offchain:
			offchain = int(offchain.replace('s', ''))
			shaker = db.session.query(Shaker).filter(and_(Shaker.id==offchain, Shaker.shaker_id==user.id)).first()
			if shaker is None:
				return response_error(MESSAGE.HANDSHAKE_CANNOT_REFUND, CODE.HANDSHAKE_CANNOT_REFUND)

			handshake = Handshake.find_handshake_by_id(shaker.handshake_id)
			outcome = Outcome.find_outcome_by_id(handshake.outcome_id)


		if outcome is None:
			return response_error(MESSAGE.OUTCOME_INVALID, CODE.OUTCOME_INVALID)

		handshakes = db.session.query(Handshake).filter(and_(Handshake.status.in_([HandshakeStatus['STATUS_INITED'], HandshakeStatus['STATUS_RESOLVED']]), Handshake.user_id==user.id, Handshake.outcome_id==outcome.id)).all()
		shakers = db.session.query(Shaker).filter(and_(Shaker.status.in_([HandshakeStatus['STATUS_SHAKER_SHAKED'], HandshakeStatus['STATUS_RESOLVED']]), Shaker.shaker_id==user.id, Shaker.handshake_id.in_(db.session.query(Handshake.id).filter(Handshake.outcome_id==outcome.id)))).all()

		for h in handshakes:
			h.bk_status = h.status
			h.status = HandshakeStatus['STATUS_REFUND_PENDING']
			db.session.merge(h)

		for s in shakers:
			s.bk_status = s.status
			s.status = HandshakeStatus['STATUS_REFUND_PENDING']
			db.session.merge(s)
			
		db.session.commit()
		handshake_bl.update_handshakes_feed(handshakes, shakers)

		return response_ok()
	except Exception, ex:
		db.session.rollback()
		return response_error(ex.message)
def can_withdraw(handshake, shaker=None):
    outcome = None
    result = None

    if shaker is None:
        if handshake is not None:
            if handshake.status == HandshakeStatus[
                    'STATUS_INITED'] or handshake.status == HandshakeStatus[
                        'STATUS_RESOLVED']:
                outcome = Outcome.find_outcome_by_id(handshake.outcome_id)
                result = handshake.side
            else:
                return MESSAGE.CANNOT_WITHDRAW
        else:
            return MESSAGE.CANNOT_WITHDRAW
    else:
        if shaker.status == HandshakeStatus[
                'STATUS_SHAKER_SHAKED'] or shaker.status == HandshakeStatus[
                    'STATUS_RESOLVED']:
            handshake = Handshake.find_handshake_by_id(shaker.handshake_id)
            outcome = Outcome.find_outcome_by_id(handshake.outcome_id)
            result = shaker.side
        else:
            return MESSAGE.CANNOT_WITHDRAW

    if outcome is not None:
        if outcome.result != result:
            return MESSAGE.HANDSHAKE_NOT_THE_SAME_RESULT

        if match_bl.is_exceed_dispute_time(outcome.match_id) == False:
            return MESSAGE.HANDSHAKE_WITHDRAW_AFTER_DISPUTE
    else:
        return MESSAGE.OUTCOME_INVALID

    return ''
Exemple #3
0
def run_bots_for_tx(tx, debug=False):
    if tx is not None:
        # Run bots
        if tx.contract_method in [
                'init', 'shake', 'initTestDrive', 'shakeTestDrive'
        ] and tx.offchain is not None:
            offchain = tx.offchain.replace(CONST.CRYPTOSIGN_OFFCHAIN_PREFIX,
                                           '')
            if 'm' in offchain:
                offchain = offchain.replace('m', '')
                h = Handshake.find_handshake_by_id(offchain)
                if h is not None:
                    if debug:
                        return h.outcome_id
                    else:
                        run_bots.delay(h.outcome_id)

            elif 's' in offchain:
                offchain = offchain.replace('s', '')
                s = Shaker.find_shaker_by_id(offchain)
                if s is not None:
                    if debug:
                        return s.handshake.outcome_id
                    else:
                        run_bots.delay(s.handshake.outcome_id)
    return None
def dispute():
	"""
	"	Dispute real bet:
	"		This step make sure user's feed will update pending status
	"""
	try:
		handshakes = []
		shakers = []
		uid = int(request.headers['Uid'])
		user = User.find_user_with_id(uid)
		data = request.json
		if data is None:
			return response_error(MESSAGE.INVALID_DATA, CODE.INVALID_DATA)

		offchain = data.get('offchain', '')
		if len(offchain) == 0:
			return response_error(MESSAGE.MISSING_OFFCHAIN, CODE.MISSING_OFFCHAIN)

		offchain = offchain.replace(CONST.CRYPTOSIGN_OFFCHAIN_PREFIX, '')

		if 'm' in offchain:
			offchain = int(offchain.replace('m', ''))
			handshake = db.session.query(Handshake).filter(and_(Handshake.id==offchain, Handshake.user_id==user.id)).first()
			if handshake is None:
				return response_error(MESSAGE.HANDSHAKE_CANNOT_REFUND, CODE.HANDSHAKE_CANNOT_REFUND)

			# check: handshake didn't match with any shaker
			if handshake.remaining_amount >= handshake.amount:
				return response_error(MESSAGE.HANDSHAKE_CANNOT_DISPUTE, CODE.HANDSHAKE_CANNOT_DISPUTE)

			handshake.bk_status = handshake.status
			handshake.status = HandshakeStatus['STATUS_DISPUTE_PENDING']
			db.session.flush()
			handshakes.append(handshake)

		elif 's' in offchain:
			offchain = int(offchain.replace('s', ''))
			shaker = db.session.query(Shaker).filter(and_(Shaker.id==offchain, Shaker.shaker_id==user.id)).first()
			if shaker is None:
				return response_error(MESSAGE.HANDSHAKE_CANNOT_REFUND, CODE.HANDSHAKE_CANNOT_REFUND)

			shaker.bk_status = shaker.status
			shaker.status = HandshakeStatus['STATUS_DISPUTE_PENDING']
			db.session.flush()
			shakers.append(shaker)
			handshake = Handshake.find_handshake_by_id(shaker.handshake_id)
			if handshake is None:
				return response_error(MESSAGE.HANDSHAKE_CANNOT_REFUND, CODE.HANDSHAKE_CANNOT_REFUND)

		db.session.commit()
		handshake_bl.update_handshakes_feed(handshakes, shakers)

		return response_ok()
	except Exception, ex:
		db.session.rollback()
		return response_error(ex.message)
def update_feed_status():
	try:
		data = request.json
		is_maker = int(data.get('is_maker', -1))
		item_id = int(data.get('id', -1))
		status = int(data.get('status', -1))
		amount = data.get('amount') # string
		remaining_amount = data.get('remaining_amount') # string

		if is_maker == -1 or status == -1 or item_id == -1:
			return response_error(MESSAGE.INVALID_DATA, CODE.INVALID_DATA)

		handshake = None

		if is_maker == 1:
			handshake = Handshake.find_handshake_by_id(item_id)
			if handshake is not None:
				handshake.status = status
				if amount is not None:
					handshake.amount = amount
				if remaining_amount is not None:
					handshake.remaining_amount = remaining_amount
		else:
			shaker = Shaker.find_shaker_by_id(item_id)
			if shaker is not None:
				shaker.status = status
				handshake = Handshake.find_handshake_by_id(shaker.handshake_id)
				if handshake is not None:
					status = handshake.status

					if amount is not None:
						handshake.amount = amount
					if remaining_amount is not None:
						handshake.remaining_amount = remaining_amount

		db.session.flush()
		db.session.commit()
		update_status_feed.delay(handshake.id, status, amount=amount, remaining_amount=remaining_amount)
		return response_ok()

	except Exception, ex:
		db.session.rollback()
		return response_error(ex.message)
	def test_data_need_set_result_for_outcome_failed(self):
		self.clear_data_before_test()
		arr_hs = []
		
		outcome = Outcome.find_outcome_by_id(88)
		outcome.result = 1

		# -----
		handshake = Handshake(
						hs_type=3,
						chain_id=4,
						user_id=88,
						outcome_id=88,
						odds=1.5,
						amount=1,
						currency='ETH',
						side=2,
						remaining_amount=0,
						from_address='0x123',
						status=-1
					)
		db.session.add(handshake)
		db.session.commit()
		arr_hs.append(handshake)

		handshake_bl.data_need_set_result_for_outcome(outcome)
		hs = Handshake.find_handshake_by_id(handshake.id)
		self.assertEqual(hs.status, -1)

		hs.status = 0
		db.session.merge(hs)
		db.session.commit()

		handshake_bl.data_need_set_result_for_outcome(outcome)
		hs = Handshake.find_handshake_by_id(handshake.id)
		self.assertEqual(hs.status, HandshakeStatus['STATUS_MAKER_SHOULD_UNINIT'])

		for item in arr_hs:
			db.session.delete(item)
			db.session.commit()
def save_failed_handshake_method_for_event(method, tx):
    if method == 'init' or method == 'initTestDrive':
        offchain = tx.offchain.replace(CONST.CRYPTOSIGN_OFFCHAIN_PREFIX, '')
        offchain = int(offchain.replace('m', ''))
        handshake = Handshake.find_handshake_by_id(offchain)
        if handshake is not None:
            handshake.status = HandshakeStatus['STATUS_INIT_FAILED']
            db.session.flush()

            arr = []
            arr.append(handshake)
            return arr, None

    elif method == 'shake' or method == 'shakeTestDrive':
        offchain = tx.offchain.replace(CONST.CRYPTOSIGN_OFFCHAIN_PREFIX, '')
        offchain = int(offchain.replace('s', ''))
        shaker = Shaker.find_shaker_by_id(offchain)
        if shaker is not None:
            if shaker.status == HandshakeStatus['STATUS_PENDING']:
                shaker = rollback_shake_state(shaker)

            shaker.status = HandshakeStatus['STATUS_SHAKE_FAILED']
            db.session.flush()

            arr = []
            arr.append(shaker)
            return None, arr

    elif method == 'report':
        payload = tx.payload
        data = json.loads(payload)

        if '_options' in data:
            options = data['_options']
            if 'onchainData' in options:
                onchain = options['onchainData']
                if 'hid' in onchain:
                    hid = int(onchain['hid'])
                    outcome = Outcome.find_outcome_by_hid(hid)
                    if outcome is not None and outcome.result == CONST.RESULT_TYPE[
                            'PROCESSING']:
                        outcome.result = CONST.RESULT_TYPE['REPORT_FAILED']
                        db.session.flush()
        send_report_slack.delay(outcome.id, result, status=2)
        return None, None

    return None, None
	def test_save_collect_state_for_shaker(self):
		self.clear_data_before_test()
		# -----
		handshake = Handshake(
				hs_type=3,
				chain_id=4,
				user_id=88,
				outcome_id=88,
				odds=1.2,
				amount=1,
				currency='ETH',
				side=2,
				remaining_amount=0,
				from_address='0x123',
				status=0
		)
		db.session.add(handshake)
		db.session.commit()

		# -----
		shaker = Shaker(
					shaker_id=66,
					amount=0.2,
					currency='ETH',
					odds=6,
					side=1,
					handshake_id=handshake.id,
					from_address='0x123',
					chain_id=4,
					status=2
				)
		db.session.add(shaker)
		db.session.commit()

		outcome = Outcome.find_outcome_by_id(88)
		outcome.result = 1
		db.session.flush()

		handshake_bl.save_collect_state_for_shaker(shaker)
		db.session.commit()

		h = Handshake.find_handshake_by_id(handshake.id)
		s = Shaker.find_shaker_by_id(shaker.id)

		self.assertEqual(h.status, 6)
		self.assertEqual(s.status, 6)
	def test_rollback_shake_state(self):
		self.clear_data_before_test()

		# -----
		handshake = Handshake(
				hs_type=3,
				chain_id=4,
				user_id=88,
				outcome_id=88,
				odds=1.2,
				amount=1,
				currency='ETH',
				side=2,
				remaining_amount=0,
				from_address='0x123',
				status=0
		)
		db.session.add(handshake)
		db.session.commit()

		# -----
		shaker = Shaker(
					shaker_id=88,
					amount=0.2,
					currency='ETH',
					odds=6,
					side=1,
					handshake_id=handshake.id,
					from_address='0x123',
					chain_id=4
				)
		db.session.add(shaker)
		db.session.commit()

		handshake_bl.rollback_shake_state(shaker)

		h = Handshake.find_handshake_by_id(handshake.id)
		s = Shaker.find_shaker_by_id(shaker.id)

		self.assertEqual(h.remaining_amount, 1)
		self.assertEqual(s.status, HandshakeStatus['STATUS_SHAKER_ROLLBACK'])
def save_collect_state_for_shaker(shaker):
    if shaker is not None:
        handshake = Handshake.find_handshake_by_id(shaker.handshake_id)
        outcome = Outcome.find_outcome_by_id(handshake.outcome_id)

        if outcome is not None:
            if shaker.side == outcome.result:
                handshake.bk_status = handshake.status
                handshake.status = HandshakeStatus['STATUS_DONE']

                db.session.merge(handshake)
                db.session.flush()
                handshakes, shakers = save_status_all_bet_which_user_win(
                    shaker.shaker_id, outcome)

                if handshakes is None:
                    handshakes = []
                handshakes.append(handshake)
                return handshakes, shakers

    return None, None
def can_refund(handshake, shaker=None):
    if handshake is None and shaker is None:
        return False

    outcome = None
    if handshake is not None:
        if handshake.status == HandshakeStatus['STATUS_REFUNDED']:
            return False

        outcome = Outcome.find_outcome_by_id(handshake.outcome_id)

    else:
        if shaker.status == HandshakeStatus['STATUS_REFUNDED']:
            return False

        handshake = Handshake.find_handshake_by_id(shaker.handshake_id)
        outcome = Outcome.find_outcome_by_id(handshake.outcome_id)

    if outcome is not None and outcome.hid is not None:
        if outcome.result == CONST.RESULT_TYPE['DRAW'] or (
                match_bl.is_exceed_report_time(outcome.match_id)
                and outcome.result == -1):
            return True
    return False
def save_handshake_for_event(event_name, inputs):
    offchain, hid, state, outcome_result = parse_inputs(inputs)
    offchain = offchain.replace(CONST.CRYPTOSIGN_OFFCHAIN_PREFIX, '')

    if event_name == '__createMarket':
        print '__createMarket'
        offchain = int(offchain.replace('createMarket', ''))
        outcome = Outcome.find_outcome_by_id(offchain)
        if outcome is not None:
            outcome.hid = hid

            if 'closingTime' in inputs and \
             'reportTime' in inputs and \
             'disputeTime' in inputs:
                m = Match.find_match_by_id(outcome.match_id)
                m.date = int(inputs['closingTime'])
                m.reportTime = int(inputs['reportTime'])
                m.disputeTime = int(inputs['disputeTime'])

            db.session.flush()

            if outcome_bl.is_outcome_created_by_user(outcome):
                send_email_event_verification_success.delay(
                    outcome.match_id, outcome.created_user_id)

        return None, None

    elif event_name == '__report':
        print '__report'
        # report{outcome_id}_{side}
        # side 1: SUPPORT, 2: OPPOSE, 3: DRAW
        outcome_id, result = offchain.replace('report', '').split('_')
        if outcome_id is None or result is None:
            return None, None

        outcome = Outcome.find_outcome_by_id(outcome_id)
        if len(result) > -1 and outcome is not None:
            result = int(result)
            outcome.result = result
            db.session.flush()

            handshakes, shakers = data_need_set_result_for_outcome(outcome)

            # send result email to users who play in
            send_result_email(outcome.id, result)

            send_report_slack.delay(outcome.id, result, status=1)

            return handshakes, shakers

        return None, None

    elif event_name == '__shake':
        print '__shake'
        offchain = offchain.replace('s', '')
        shaker = Shaker.find_shaker_by_id(int(offchain))
        if shaker is not None:
            shaker.status = HandshakeStatus['STATUS_SHAKER_SHAKED']
            shaker.bk_status = HandshakeStatus['STATUS_SHAKER_SHAKED']
            db.session.flush()

            # Add shuriken
            if shaker.free_bet == 1:
                add_shuriken.delay(shaker.shaker_id,
                                   CONST.SHURIKEN_TYPE['FREE'])
            else:
                add_shuriken.delay(shaker.shaker_id,
                                   CONST.SHURIKEN_TYPE['REAL'])

            # Give redeem code for referral user
            u = User.find_user_with_id(shaker.shaker_id)
            if u is not None and u.played_bet == 0:
                referral_bl.give_redeem_code_for_referred_user(
                    shaker.shaker_id)
                u.played_bet = 1
                db.session.flush()

            arr = []
            arr.append(shaker)

            return None, arr

        return None, None

    elif event_name == '__collect':
        print '__collect'

        if 's' in offchain:
            offchain = offchain.replace('s', '')
            shaker = Shaker.find_shaker_by_id(int(offchain))
            if shaker is not None:
                # update status of shaker and handshake to done
                # find all bets belongs to this outcome which user join
                # update all statuses (shaker and handshake) of them to done
                return save_collect_state_for_shaker(shaker)

        elif 'm' in offchain:
            offchain = offchain.replace('m', '')
            handshake = Handshake.find_handshake_by_id(int(offchain))
            if handshake is not None:
                # update status of shaker and handshake to done
                # find all bets belongs to this outcome which user join
                # update all statuses (shaker and handshake) of them to done
                return save_collect_state_for_maker(handshake)

        return None, None

    elif event_name == '__init':
        print '__init'
        offchain = offchain.replace('m', '')
        handshake = Handshake.find_handshake_by_id(int(offchain))
        if handshake is not None:
            handshake.status = HandshakeStatus['STATUS_INITED']
            handshake.bk_status = HandshakeStatus['STATUS_INITED']

            db.session.flush()

            arr = []
            arr.append(handshake)

            # Add shuriken
            if handshake.free_bet == 1:
                add_shuriken.delay(handshake.user_id,
                                   CONST.SHURIKEN_TYPE['FREE'])
            else:
                add_shuriken.delay(handshake.user_id,
                                   CONST.SHURIKEN_TYPE['REAL'])

            # Give redeem code for referral user
            u = User.find_user_with_id(handshake.user_id)
            if u is not None and u.played_bet == 0:
                referral_bl.give_redeem_code_for_referred_user(
                    handshake.user_id)
                u.played_bet = 1
                db.session.flush()

            return arr, None

        return None, None

    elif event_name == '__uninit':
        print '__uninit'
        offchain = offchain.replace('m', '')
        handshake = Handshake.find_handshake_by_id(int(offchain))
        if handshake is not None:
            handshake.status = HandshakeStatus['STATUS_MAKER_UNINITED']
            handshake.bk_status = HandshakeStatus['STATUS_MAKER_UNINITED']
            db.session.flush()

            arr = []
            arr.append(handshake)
            return arr, None
        return None, None

    elif event_name == '__refund':
        print '__refund'
        handshake = None
        user_id = None
        free_bet = False
        if 's' in offchain:
            offchain = offchain.replace('s', '')
            shaker = Shaker.find_shaker_by_id(int(offchain))
            if shaker is None:
                return None, None

            user_id = shaker.shaker_id
            free_bet = shaker.free_bet
            handshake = Handshake.find_handshake_by_id(shaker.handshake_id)

        elif 'm' in offchain:
            offchain = offchain.replace('m', '')
            handshake = Handshake.find_handshake_by_id(int(offchain))
            user_id = handshake.user_id
            free_bet = handshake.free_bet

        if handshake is None or user_id is None:
            return None, None

        if free_bet is True:
            redeem_bl.issue_new_redeem_code_for_user(user_id)

        return save_refund_state_for_all(user_id, handshake.outcome_id)

    elif event_name == '__dispute':
        print '__dispute'
        shaker_dispute = []
        handshake_dispute = []
        handshake = None
        user_id = None
        side = None

        if outcome_result is None:
            return None, None

        if state < 2:
            return None, None

        if 's' in offchain:
            offchain = offchain.replace('s', '')
            shaker = Shaker.find_shaker_by_id(int(offchain))
            user_id = shaker.shaker_id
            side = shaker.side

            if shaker is not None:
                handshake = Handshake.find_handshake_by_id(shaker.handshake_id)

        elif 'm' in offchain:
            offchain = offchain.replace('m', '')
            handshake = Handshake.find_handshake_by_id(int(offchain))
            user_id = handshake.user_id
            side = handshake.side

        if handshake is None or user_id is None:
            return None, None

        outcome = Outcome.find_outcome_by_id(handshake.outcome_id)
        if outcome is None:
            return None, None

        update_amount_for_outcome(outcome.id, user_id, side, outcome_result)

        if state == 3 and outcome.result != CONST.RESULT_TYPE['DISPUTED']:
            outcome.result = CONST.RESULT_TYPE['DISPUTED']
            db.session.flush()
            handshake_dispute, shaker_dispute = save_disputed_state(outcome.id)

            # Send mail to admin
            send_dispute_email.delay(outcome.match.name)

        else:
            handshake_dispute, shaker_dispute = save_user_disputed_state(
                handshake, user_id, side, outcome_result)

        return handshake_dispute, shaker_dispute

    elif event_name == '__resolve':
        # resolve{outcome_id}_{side}
        print '__resolve'
        outcome_id, result = offchain.replace('resolve', '').split('_')
        if outcome_id is None or result is None:
            return None, None

        # 1: SUPPORT, 2: OPPOSE, 3: DRAW: It's depended on smart contract definition.
        if len(result) == 0 or int(result) not in [1, 2, 3]:
            return None, None
        outcome = Outcome.find_outcome_by_id(outcome_id)
        if outcome is None:
            return None, None

        result = int(result)
        outcome.total_dispute_amount = 0
        outcome.result = result
        db.session.flush()

        handshakes, shakers = save_resolve_state_for_outcome(outcome.id)

        # send result email to users who play in
        send_result_email(outcome.id, result)
        return handshakes, shakers
def save_handshake_method_for_event(method, inputs):
    offchain, hid, state, outcome_result = parse_inputs(inputs)
    if method == 'init' or method == 'initTestDrive':
        offchain = offchain.replace(CONST.CRYPTOSIGN_OFFCHAIN_PREFIX, '')
        offchain = int(offchain.replace('m', ''))
        handshake = Handshake.find_handshake_by_id(offchain)
        if handshake is not None:
            handshake.bk_status = handshake.status
            handshake.status = HandshakeStatus['STATUS_INIT_FAILED']
            db.session.flush()

            arr = []
            arr.append(handshake)
            return arr, None

    elif method == 'shake' or method == 'shakeTestDrive':
        offchain = offchain.replace(CONST.CRYPTOSIGN_OFFCHAIN_PREFIX, '')
        offchain = int(offchain.replace('s', ''))
        shaker = Shaker.find_shaker_by_id(offchain)
        if shaker is not None:
            if shaker.status == HandshakeStatus['STATUS_PENDING']:
                shaker = rollback_shake_state(shaker)

            shaker.bk_status = shaker.status
            shaker.status = HandshakeStatus['STATUS_SHAKE_FAILED']
            db.session.flush()

            arr = []
            arr.append(shaker)
            return None, arr

    elif method == 'uninit' or method == 'uninitTestDrive':
        offchain = offchain.replace(CONST.CRYPTOSIGN_OFFCHAIN_PREFIX, '')
        offchain = int(offchain.replace('m', ''))
        handshake = Handshake.find_handshake_by_id(offchain)
        if handshake is not None:
            handshake.bk_status = handshake.status
            handshake.status = HandshakeStatus['STATUS_MAKER_UNINIT_FAILED']
            db.session.flush()

            arr = []
            arr.append(handshake)
            return arr, None

    elif method == 'collect' or method == 'collectTestDrive':
        offchain = offchain.replace(CONST.CRYPTOSIGN_OFFCHAIN_PREFIX, '')

        if 'm' in offchain:
            offchain = int(offchain.replace('m', ''))
            handshake = Handshake.find_handshake_by_id(offchain)
            if handshake is not None:
                handshake.bk_status = handshake.status
                handshake.status = HandshakeStatus['STATUS_COLLECT_FAILED']
                db.session.flush()

                arr = []
                arr.append(handshake)
                return arr, None

        elif 's' in offchain:
            offchain = int(offchain.replace('s', ''))
            shaker = Shaker.find_shaker_by_id(offchain)
            if shaker is not None:
                shaker.bk_status = shaker.status
                shaker.status = HandshakeStatus['STATUS_COLLECT_FAILED']
                db.session.flush()

                arr = []
                arr.append(shaker)
                return None, arr

    elif method == 'refund':
        offchain = offchain.replace(CONST.CRYPTOSIGN_OFFCHAIN_PREFIX, '')

        if 'm' in offchain:
            offchain = int(offchain.replace('m', ''))
            handshake = Handshake.find_handshake_by_id(offchain)
            if handshake is not None:
                handshake.bk_status = handshake.status
                handshake.status = HandshakeStatus['STATUS_REFUND_FAILED']
                db.session.flush()

                arr = []
                arr.append(handshake)
                return arr, None

        elif 's' in offchain:
            offchain = int(offchain.replace('s', ''))
            shaker = Shaker.find_shaker_by_id(offchain)
            if shaker is not None:
                shaker.bk_status = shaker.status
                shaker.status = HandshakeStatus['STATUS_REFUND_FAILED']
                db.session.flush()

                arr = []
                arr.append(shaker)
                return None, arr

    elif method == 'report':
        outcome_id, result = offchain.replace('cryptosign_report',
                                              '').split('_')
        if outcome_id is None:
            return None, None
        print 'report fail with outcome_id {}'.format(outcome_id)
        outcome = Outcome.find_outcome_by_id(outcome_id)

        if outcome is not None and outcome.result == CONST.RESULT_TYPE[
                'PROCESSING']:
            outcome.result = CONST.RESULT_TYPE['REPORT_FAILED']
            db.session.flush()
        send_report_slack.delay(outcome.id, result, status=0)

    elif method == 'resolve':
        outcome_id, result = offchain.replace('cryptosign_resolve',
                                              '').split('_')
        if outcome_id is None:
            return None, None
        print 'resolve fail with outcome_id {}'.format(outcome_id)
        outcome = Outcome.find_outcome_by_id(outcome_id)

        if outcome is not None and outcome.result == CONST.RESULT_TYPE[
                'DISPUTED']:
            outcome.result = CONST.RESULT_TYPE['REPORT_FAILED']
            db.session.flush()

    return None, None
def collect_free_bet():
	"""
	"	Collect free-bet in ETH
	"""
	try:
		uid = int(request.headers['Uid'])
		chain_id = int(request.headers.get('ChainId', CONST.BLOCKCHAIN_NETWORK['RINKEBY']))
		user = User.find_user_with_id(uid)

		data = request.json
		if data is None:
			return response_error(MESSAGE.INVALID_DATA, CODE.INVALID_DATA)

		offchain = data.get('offchain', '')
		if len(offchain) == 0:
			return response_error(MESSAGE.MISSING_OFFCHAIN, CODE.MISSING_OFFCHAIN)

		h = []
		s = []
		offchain = offchain.replace(CONST.CRYPTOSIGN_OFFCHAIN_PREFIX, '')
		if 's' in offchain:
			offchain = int(offchain.replace('s', ''))
			shaker = db.session.query(Shaker).filter(and_(Shaker.id==offchain, Shaker.shaker_id==user.id)).first()
			msg = handshake_bl.can_withdraw(handshake=None, shaker=shaker)
			if len(msg) != 0:
				return response_error(msg, CODE.CANNOT_WITHDRAW)
			
			hs = Handshake.find_handshake_by_id(shaker.handshake_id)
			outcome = Outcome.find_outcome_by_id(hs.outcome_id)

			# check erc20 token or not
			token = Token.find_token_by_id(outcome.token_id)
			if token is not None:
				return response_error(MESSAGE.HANDSHAKE_CANNOT_WITHDRAW_FREEBET_IN_ERC20, CODE.HANDSHAKE_CANNOT_WITHDRAW_FREEBET_IN_ERC20)

			h = db.session.query(Handshake).filter(and_(Handshake.user_id==user.id, Handshake.outcome_id==hs.outcome_id, Handshake.side==shaker.side, Handshake.status==HandshakeStatus['STATUS_INITED'])).all()
			s = db.session.query(Shaker).filter(and_(Shaker.shaker_id==user.id, Shaker.side==shaker.side, Shaker.status==HandshakeStatus['STATUS_SHAKER_SHAKED'], Shaker.handshake_id.in_(db.session.query(Handshake.id).filter(Handshake.outcome_id==hs.outcome_id)))).all()

			data['hid'] = outcome.hid
			data['winner'] = shaker.from_address

		else:
			offchain = int(offchain.replace('m', ''))
			handshake = db.session.query(Handshake).filter(and_(Handshake.id==offchain, Handshake.user_id==user.id)).first()
			msg = handshake_bl.can_withdraw(handshake)
			if len(msg) != 0:
				return response_error(msg, CODE.CANNOT_WITHDRAW)

			outcome = Outcome.find_outcome_by_id(handshake.outcome_id)

			# check erc20 token or not
			token = Token.find_token_by_id(outcome.token_id)
			if token is not None:
				return response_error(MESSAGE.HANDSHAKE_CANNOT_WITHDRAW_FREEBET_IN_ERC20, CODE.HANDSHAKE_CANNOT_WITHDRAW_FREEBET_IN_ERC20)

			h = db.session.query(Handshake).filter(and_(Handshake.user_id==user.id, Handshake.outcome_id==handshake.outcome_id, Handshake.side==handshake.side, Handshake.status==HandshakeStatus['STATUS_INITED'])).all()
			s = db.session.query(Shaker).filter(and_(Shaker.shaker_id==user.id, Shaker.side==handshake.side, Shaker.status==HandshakeStatus['STATUS_SHAKER_SHAKED'], Shaker.handshake_id.in_(db.session.query(Handshake.id).filter(Handshake.outcome_id==handshake.outcome_id)))).all()

			data['hid'] = outcome.hid
			data['winner'] = handshake.from_address


		handshakes = []
		shakers = []
		response = {}
		# update status
		for hs in h:
			hs.status = HandshakeStatus['STATUS_COLLECT_PENDING']
			db.session.flush()
			handshakes.append(hs)

			if hs.id == offchain:
				response = hs.to_json()
			
		for sk in s:
			sk.status = HandshakeStatus['STATUS_COLLECT_PENDING']
			db.session.flush()
			shakers.append(sk)

			if sk.id == offchain:
				response = sk.to_json()

		data['uid'] = uid
		data['payload'] = user.payload
		data['free_bet'] = 1

		contract = Contract.find_contract_by_id(outcome.contract_id)
		if contract is None:
			return response_error(MESSAGE.CONTRACT_INVALID, CODE.CONTRACT_INVALID)

		# add task
		task = Task(
			task_type=CONST.TASK_TYPE['FREE_BET'],
			data=json.dumps(data),
			action=CONST.TASK_ACTION['COLLECT'],
			status=-1,
			contract_address=contract.contract_address,
			contract_json=contract.json_name
		)
		db.session.add(task)
		db.session.commit()

		handshake_bl.update_handshakes_feed(handshakes, shakers)
		return response_ok(response)

	except Exception, ex:
		db.session.rollback()
		return response_error(ex.message)
	def test_test_save_refund_state_for_all(self):
		self.clear_data_before_test()
		arr_hs = []
		arr_sk = []

		# -----
		handshake1 = Handshake(
						hs_type=3,
						chain_id=4,
						user_id=88,
						outcome_id=88,
						odds=1.5,
						amount=1,
						currency='ETH',
						side=2,
						remaining_amount=0,
						from_address='0x123',
						status=HandshakeStatus['STATUS_REFUND_PENDING']
					)
		db.session.add(handshake1)
		db.session.commit()
		arr_hs.append(handshake1)

		handshake2 = Handshake(
						hs_type=3,
						chain_id=4,
						user_id=88,
						outcome_id=88,
						odds=1.5,
						amount=1,
						currency='ETH',
						side=2,
						remaining_amount=0,
						from_address='0x123',
						status=HandshakeStatus['STATUS_MAKER_UNINITED']
					)
		db.session.add(handshake2)
		db.session.commit()
		arr_hs.append(handshake2)

		handshake3 = Handshake(
						hs_type=3,
						chain_id=4,
						user_id=99,
						outcome_id=88,
						odds=1.5,
						amount=1,
						currency='ETH',
						side=2,
						remaining_amount=0,
						from_address='0x123',
						status=HandshakeStatus['STATUS_INITED']
					)
		db.session.add(handshake3)
		db.session.commit()
		arr_hs.append(handshake3)

		# -----
		shaker1 = Shaker(
					shaker_id=88,
					amount=0.2,
					currency='ETH',
					odds=6,
					side=1,
					handshake_id=handshake1.id,
					from_address='0x123',
					chain_id=4,
					status=HandshakeStatus['STATUS_REFUND_PENDING']
				)
		db.session.add(shaker1)
		db.session.commit()
		arr_sk.append(shaker1)

		# -----
		shaker2 = Shaker(
					shaker_id=88,
					amount=0.2,
					currency='ETH',
					odds=6,
					side=1,
					handshake_id=handshake3.id,
					from_address='0x123',
					chain_id=4,
					status=HandshakeStatus['STATUS_REFUND_PENDING']
				)
		db.session.add(shaker2)
		db.session.commit()
		arr_sk.append(shaker2)

		handshakes, shakers = handshake_bl.save_refund_state_for_all(88, 88)
		actual = None

		hs1 = Handshake.find_handshake_by_id(handshake1.id)
		self.assertEqual(hs1.status, HandshakeStatus['STATUS_REFUNDED'])
		hs2 = Handshake.find_handshake_by_id(handshake2.id)
		self.assertEqual(hs2.status, HandshakeStatus['STATUS_MAKER_UNINITED'])
		hs3 = Handshake.find_handshake_by_id(handshake3.id)
		self.assertEqual(hs3.status, HandshakeStatus['STATUS_INITED'])

		sk1 = Shaker.find_shaker_by_id(shaker1.id)
		self.assertEqual(sk1.status, HandshakeStatus['STATUS_REFUNDED'])
		sk2 = Shaker.find_shaker_by_id(shaker2.id)
		self.assertEqual(sk2.status, HandshakeStatus['STATUS_REFUNDED'])

		for item in arr_hs:
			db.session.delete(item)
			db.session.commit()
		for item in arr_sk:
			db.session.delete(item)
			db.session.commit()