예제 #1
0
def send_coins(wallet: PushWallet, to=None, amount=None, payload='', wait=True, gas_coin=None):
    private_key = MinterWallet.create(mnemonic=wallet.mnemonic)['private_key']
    response = NodeAPI.get_balance(wallet.address)
    nonce = int(response['transaction_count']) + 1
    balances = response['balance']
    balances_bip = effective_balance(balances)
    main_coin, main_balance_bip = max(balances_bip.items(), key=lambda i: i[1])
    main_balance = float(to_bip(balances[main_coin]))

    gas_coin, tx_fee = find_gas_coin(balances, get_fee=True, payload=payload)
    gas_coin_balance = float(to_bip(balances.get(gas_coin, 0)))

    if not gas_coin or not tx_fee or gas_coin_balance < tx_fee:
        return 'Not enough balance to pay commission'
    tx_fee = float(tx_fee)

    # если в обычной пересылке пришлют сумму без учета комиссии - не будем мучать ошибками
    amount = main_balance - tx_fee if amount == truncate(main_balance, 4) \
        and gas_coin == main_coin and not payload else amount
    tx_fee = tx_fee if gas_coin == main_coin else 0
    if amount > main_balance - tx_fee:
        return 'Not enough balance'
    tx = send_coin_tx(private_key, main_coin, amount, to, nonce, payload=payload, gas_coin=gas_coin)
    NodeAPI.send_tx(tx, wait=wait)
    return True
예제 #2
0
def estimate_custom_fee(coin):
    if coin == BASE_COIN:
        return Decimal('0.01')
    coin_info = NodeAPI.get_coin_info(coin)
    if coin_info['reserve_balance'] < to_pip(MIN_RESERVE_BIP + 0.01):
        return
    w = MinterWallet.create()
    tx = send_coin_tx(w['private_key'],
                      coin,
                      0,
                      w['address'],
                      1,
                      gas_coin=coin)
    return to_bip(NodeAPI.estimate_tx_commission(tx.signed_tx)['commission'])
예제 #3
0
 def get(self, campaign_id):
     campaign = RewardCampaign.get_or_none(link_id=campaign_id,
                                           status='open')
     if not campaign:
         return {}
     balances = NodeAPI.get_balance(campaign.address)['balance']
     campaign_balance = to_bip(balances.get(campaign.coin, '0'))
     # if not campaign_balance:
     #     return {}
     times_completed = campaign.times_completed
     reward = float(to_bip(campaign.action_reward))
     value_spent = times_completed * reward
     return {
         'id': campaign.link_id,
         'name': campaign.name,
         'address': campaign.address,
         'count': campaign.count,
         'coin': campaign.coin,
         'balance': float(campaign_balance),
         'times_completed': times_completed,
         'value_spent': value_spent,
         'icon_url': campaign.icon.url if campaign.icon else None,
         'action': {
             'type': campaign.action_type,
             'link': campaign.action_params['link'],
             'reward': reward,
         }
     }
예제 #4
0
def get_address_balance(address, virtual=None):
    if virtual:
        balances = {'BIP': virtual}
        balances_bip = {'BIP': Decimal(to_bip(virtual))}
    else:
        balances = NodeAPI.get_balance(address)['balance']
        balances_bip = effective_balance(balances)

    main_coin, main_balance_bip = max(balances_bip.items(), key=lambda i: i[1])
    bip_value_total = truncate(float(main_balance_bip), 4)

    usd_value_total = truncate(bip_to_usdt(bip_value_total), 4)
    usd_rates = fiat_to_usd_rates()
    local_fiat = 'RUB'
    local_fiat_value = truncate(usd_value_total * usd_rates[local_fiat], 4)
    coin_value = to_bip(balances[main_coin])
    coin_value = truncate(float(effective_value(coin_value, main_coin)), 4)
    return {
        'balance': {
            'coin': main_coin,
            'value': coin_value,
            'bip_value': bip_value_total,
            'usd_value': usd_value_total,
            'local_fiat': local_fiat,
            'local_fiat_value': local_fiat_value
        },
        'fiat_rates': {
            symbol: rate
            for symbol, rate in usd_rates.items()
            if symbol in ['UAH', 'USD', 'RUB']
        }
    }
예제 #5
0
def mobile_top_up(wallet: PushWallet, phone=None, amount=None, confirm=True):
    if not confirm:
        return get_info()

    phone_reqs = get_tx_requirements(phone)
    if not phone_reqs:
        return f'Phone number {phone} not supported or invalid'

    response = NodeAPI.get_balance(wallet.address)
    balance = response['balance']
    balances_bip = effective_balance(balance)
    main_coin, main_balance_bip = max(balances_bip.items(), key=lambda i: i[1])
    balance_coin = to_bip(balance[main_coin])
    nonce = int(response['transaction_count']) + 1
    to_send = amount or balance_coin

    private_key = MinterWallet.create(mnemonic=wallet.mnemonic)['private_key']

    gas_coin = find_gas_coin(balance)
    if not gas_coin:
        return 'Coin not spendable. Send any coin to pay fee'
    # fee = estimate_custom_fee(gas_coin)
    min_topup = phone_reqs['min_bip_value']
    effective_topup = rub_to_bip(
        to_send) if main_coin == 'ROUBLE' else main_balance_bip

    if balance_coin < to_send:
        return 'Not enough balance'
    if effective_topup < min_topup:
        return f"Minimal top-up: {min_topup} BIP"

    tx = send_coin_tx(private_key,
                      main_coin,
                      to_send,
                      BIP2PHONE_PAYMENT_ADDRESS,
                      nonce,
                      payload=phone_reqs['payload'],
                      gas_coin=gas_coin)
    try:
        NodeAPI.send_tx(tx, wait=True)
    except MinterAPIException as exc:
        return exc.message
    return True
예제 #6
0
def generate_push(campaign):
    response = NodeAPI.get_balance(campaign.address)
    balances = response['balance']
    campaign_balance = to_bip(balances.get(campaign.coin, '0'))
    if not campaign_balance:
        logging.info(
            f'Campaign {campaign.link_id} {campaign.name}: balance too low {campaign_balance}'
        )
        return

    tx_fee = estimate_custom_fee(campaign.coin)
    reward = to_bip(campaign.action_reward)

    if campaign_balance < reward + tx_fee:
        logging.info(
            f'Campaign {campaign.link_id} {campaign.name}: balance too low {campaign_balance}'
        )
        return

    push = generate_and_save_wallet()
    private_key = MinterWallet.create(
        mnemonic=campaign.mnemonic)['private_key']
    nonce = int(response['transaction_count']) + 1

    tx = send_coin_tx(private_key,
                      campaign.coin,
                      reward + tx_fee,
                      push.address,
                      nonce,
                      gas_coin=campaign.coin)
    NodeAPI.send_tx(tx, wait=True)
    logging.info(
        f'Campaign {campaign.link_id} {campaign.name} rewarded {reward} {campaign.coin}, fee {tx_fee}'
    )

    campaign.times_completed += 1
    if campaign.times_completed == campaign.count:
        campaign.status = 'close'
        logging.info(f'Campaign {campaign.link_id} {campaign.name} finished!')
    campaign.save()
    return YYY_PUSH_URL + push.link_id
예제 #7
0
    def delete(self, campaign_id):
        campaign = RewardCampaign.get_or_none(link_id=campaign_id,
                                              status='open')
        if not campaign:
            return {}, HTTPStatus.NOT_FOUND

        response = NodeAPI.get_balance(campaign.address)
        balances = response['balance']
        campaign_balance = to_bip(balances.get(campaign.coin, '0'))
        if campaign_balance:
            tx_fee = estimate_custom_fee(campaign.coin)
            gas_coin = find_gas_coin(
                balances) if tx_fee is None else campaign.coin
            if not gas_coin:
                return {
                    'error':
                    f'Campaign coin not spendable.'
                    f'Send any coin to campaign address {campaign.address} to pay fee'
                }, HTTPStatus.BAD_REQUEST
            private_key = MinterWallet.create(
                mnemonic=campaign.mnemonic)['private_key']
            refund_address = get_first_transaction(campaign.address)
            nonce = int(response['transaction_count']) + 1

            tx_fee = 0 if tx_fee is None else tx_fee
            tx = send_coin_tx(private_key,
                              campaign.coin,
                              campaign_balance - tx_fee,
                              refund_address,
                              nonce,
                              gas_coin=campaign.coin)
            NodeAPI.send_tx(tx, wait=True)

        campaign.status = 'closed'
        campaign.save()
        return {'success': True}
예제 #8
0
def effective_balance(balances):
    balances_bip = {}
    for coin, balance in balances.items():
        if coin == BASE_COIN:
            balances_bip[coin] = max(Decimal(0),
                                     to_bip(balance) - Decimal('0.01'))
            continue

        # ROUBLE WORKAROUND
        coin_info = NodeAPI.get_coin_info(coin)
        if coin_info['reserve_balance'] < to_pip(
                Decimal(MIN_RESERVE_BIP) + Decimal('0.01')):
            return {coin: Decimal(0)}

        est_sell_response = NodeAPI.estimate_coin_sell(coin, balance,
                                                       BASE_COIN)
        will_get_pip, comm_pip = est_sell_response[
            'will_get'], est_sell_response['commission']
        if int(balance) < int(comm_pip):
            continue
        will_get_pip = int(will_get_pip) - to_pip(0.01)
        if will_get_pip > 0:
            balances_bip[coin] = to_bip(will_get_pip)
    return balances_bip or {'BIP': Decimal(0)}
예제 #9
0
def push_create():
    """
    swagger: swagger/core/push-create.yml
    """
    payload = request.get_json() or {}
    sender, recipient = payload.get('sender'), payload.get('recipient')
    password = payload.get('password')
    amount = payload.get('amount')
    coin = payload.get('coin', 'BIP')

    customization_setting_id = payload.get('customization_setting_id')
    setting = CustomizationSetting.get_or_none(id=customization_setting_id)
    if not setting:
        jsonify({'error': 'Customization setting does not exist'
                 }), HTTPStatus.BAD_REQUEST

    wallet = generate_and_save_wallet(
        sender=sender,
        recipient=recipient,
        password=password,
        customization_setting_id=customization_setting_id)
    response = {'address': wallet.address, 'link_id': wallet.link_id}
    if amount:
        w = MinterWallet.create()
        tx = send_coin_tx(w['private_key'],
                          coin,
                          float(amount),
                          w['address'],
                          1,
                          gas_coin=coin)
        tx_fee = float(
            to_bip(NodeAPI.estimate_tx_comission(tx.signed_tx)['commission']))
        response['deeplink'] = TxDeeplink.create('send',
                                                 to=wallet.address,
                                                 value=float(amount) + tx_fee,
                                                 coin=coin).mobile
    return jsonify(response)
예제 #10
0
def get_first_transaction(address):
    tx = NodeAPI.get_transactions(f"tags.tx.to='{address[2:]}'", limit=1)
    if not tx:
        return None
    return tx[0]['tags']['tx.from']
예제 #11
0
def get_balance(address, coin='BIP', bip=True):
    balance = NodeAPI.get_balance(address)['balance']
    balance_pip = balance[coin]
    return float(to_bip(balance_pip)) if bip else balance_pip