Ejemplo n.º 1
0
def opt_in(
    algod_client: algod.AlgodClient,
    user: Account,
    nft_id: int,
):
    nft_name = algod_client.asset_info(nft_id)['params']['name']
    optin = ''
    while not optin:
        optin = str(
            input(
                f"Do you want to opt-in the {nft_name} (ID: {nft_id})? (Y/n) ")
        )
        print("")
        if optin.lower() == 'y':
            params = algod_client.suggested_params()

            opt_in_txn = transaction.AssetOptInTxn(
                sender=user.address,
                sp=params,
                index=nft_id,
            )
            return sign_send_wait(algod_client, user, opt_in_txn)

        elif optin.lower() == 'n':
            return
        else:
            optin = ''
Ejemplo n.º 2
0
def wait_for_confirmation(client: algod.AlgodClient,
                          transaction_id: str,
                          timeout: int = 100) -> Dict[str, str or int]:
    """
    Check for when the transaction is confirmed by the network. Once confirmed, return
    the transaction information.

    :param client -> ``algod.AlgodClient``: an algorand client object.
    :param transaction_id -> ``str``: id for the transaction.
    """
    start_round = client.status()["last-round"] + 1
    current_round = start_round

    while current_round < start_round + timeout:
        try:
            pending_txn = client.pending_transaction_info(transaction_id)
        except Exception:
            return
        if pending_txn.get("confirmed-round", 0) > 0:
            return pending_txn
        elif pending_txn["pool-error"]:
            raise Exception('pool error: {}'.format(pending_txn["pool-error"]))
        client.status_after_block(current_round)
        current_round += 1
    raise Exception(
        'pending tx not found in timeout rounds, timeout value = : {}'.format(
            timeout))
Ejemplo n.º 3
0
def sign_send_wait(algod_client: algod.AlgodClient, account: Account, txn):
    """Sign a transaction, submit it, and wait for its confirmation."""
    signed_txn = sign(account, txn)
    tx_id = signed_txn.transaction.get_txid()
    algod_client.send_transactions([signed_txn])
    wait_for_confirmation(algod_client, tx_id)
    return algod_client.pending_transaction_info(tx_id)
Ejemplo n.º 4
0
def notify(algod_client: algod.AlgodClient, user: Account, seller: Account,
           trade_gtxn: list):
    params = algod_client.suggested_params()

    note = {
        'buy_order': 'AlgoRealm Special Card',
        'asset_id': CARD_ID,
        'algo_amount': trade_gtxn[2].transaction.amt / 10**6,
        'algo_royalty': (trade_gtxn[3].amt + trade_gtxn[4].amt) / 10**6,
        'last_valid_block': trade_gtxn[2].transaction.last_valid_round
    }

    bytes_note = msgpack.packb(note)

    notification_txn = transaction.PaymentTxn(
        sender=user.address,
        sp=params,
        receiver=seller.address,
        amt=0,
        note=bytes_note,
    )

    signed_txn = sign(user, notification_txn)
    tx_id = signed_txn.transaction.get_txid()
    print("✉️  Sending buy order notification to the Seller...\n")
    algod_client.send_transactions([signed_txn])
    wait_for_confirmation(algod_client, tx_id)
    print("\n📄 Buy order notification:\n"
          "https://algoexplorer.io/tx/" + tx_id)
Ejemplo n.º 5
0
def check_from_algod(args):
    global graceful_stop
    token, addr = token_addr_from_args(args)
    algod = AlgodClient(token, addr)
    if args.genesis or args.algod:
        gpath = args.genesis or os.path.join(args.algod, 'genesis.json')
        getGenesisVars(gpath)
    else:
        process_genesis(algod.algod_request("GET", "/genesis"))
    status = algod.status()
    iloadstart = time.time()
    indexer_headers = None
    gtaddr = args.gtaddr
    maxaddr = None
    if args.shard:
        minaddr, maxaddr = shard_bounds(args.shard)
        if minaddr is not None:
            gtaddr = algosdk.encoding.encode_address(minaddr)
    if args.indexer_token:
        indexer_headers = {'X-Indexer-API-Token': token}

    lastlog = time.time()
    i2a_checker = CheckContext(sys.stderr)
    # for each account in indexer, get it from algod, and maybe re-get it from indexer at the round algod had
    ia_queue = queue.Queue(maxsize=10)
    threads = []
    for i in range(args.threads):
        t = threading.Thread(target=compare_thread, args=(ia_queue, i2a_checker, algod, args.indexer, indexer_headers))
        t.start()
        threads.append(t)
    lastaddr = None
    for indexer_account in indexerAccounts(args.indexer, addrlist=(args.accounts and args.accounts.split(',')), headers=indexer_headers, gtaddr=gtaddr):
        lastaddr = indexer_account['address']
        if maxaddr is not None:
            la = algosdk.encoding.decode_address(lastaddr)
            if la > maxaddr:
                break
        ia_queue.put(indexer_account)
        if graceful_stop:
            break
        now = time.time()
        if (now - lastlog) > 5:
            with i2a_checker.lock:
                logger.info('%d match, %d neq, through about %s', i2a_checker.match, i2a_checker.neq, lastaddr)
            lastlog = now
    for t in threads:
        ia_queue.put(None) # signal end
    for t in threads:
        t.join()
    if graceful_stop:
        logger.info('last addr %s', lastaddr)
    return i2a_checker
def check_from_algod(args):
    gpath = args.genesis or os.path.join(args.algod, 'genesis.json')
    getGenesisVars(gpath)
    token, addr = token_addr_from_args(args)
    algod = AlgodClient(token, addr)
    status = algod.status()
    #logger.debug('status %r', status)
    iloadstart = time.time()
    if args.indexer:
        i2a = indexerAccounts(args.indexer,
                              addrlist=(args.accounts
                                        and args.accounts.split(',')))
        i2a_checker = CheckContext(i2a, sys.stderr)
    else:
        logger.warn('no indexer, nothing to do')
        return None, None
    iloadtime = time.time() - iloadstart
    logger.info('loaded %d accounts from indexer in %.1f seconds, %.1f a/s',
                len(i2a), iloadtime,
                len(i2a) / iloadtime)
    aloadstart = time.time()
    rawad = []
    for address in i2a.keys():
        niceaddr = algosdk.encoding.encode_address(address)
        rawad.append(algod.account_info(niceaddr))
    aloadtime = time.time() - aloadstart
    logger.info('loaded %d accounts from algod in %.1f seconds, %.1f a/s',
                len(rawad), aloadtime,
                len(rawad) / aloadtime)
    lastlog = time.time()
    count = 0
    for ad in rawad:
        niceaddr = ad['address']
        # fetch indexer account at round algod got it at
        na = indexerAccounts(args.indexer,
                             blockround=ad['round'],
                             addrlist=[niceaddr])
        i2a.update(na)
        microalgos = ad['amount-without-pending-rewards']
        address = algosdk.encoding.decode_address(niceaddr)
        i2a_checker.check(address, niceaddr, microalgos, ad.get('assets'),
                          ad.get('created-assets'), ad.get('created-apps'),
                          ad.get('apps-local-state'))
        count += 1
        now = time.time()
        if (now - lastlog) > 5:
            logger.info('%d accounts checked, %d mismatches', count,
                        len(i2a_checker.mismatches))
            lastlog = now
    return i2a_checker
Ejemplo n.º 7
0
def claim_nft(
    algod_client: algod.AlgodClient,
    indexer_client: indexer.IndexerClient,
    claimer: Account,
    claim_arg: str,
    new_majesty: str,
    donation_amount: int,
    nft_id: int,
):
    params = algod_client.suggested_params()

    claim_txn = transaction.ApplicationNoOpTxn(
        sender=claimer.address,
        sp=params,
        index=ALGOREALM_APP_ID,
        app_args=[claim_arg.encode(), new_majesty.encode()])

    donation_txn = transaction.PaymentTxn(
        sender=claimer.address,
        sp=params,
        receiver=REWARDS_POOL,
        amt=donation_amount,
    )

    nft_transfer = transaction.AssetTransferTxn(
        sender=ALGOREALM_LAW.address,
        sp=params,
        receiver=claimer.address,
        amt=1,
        index=nft_id,
        revocation_target=current_owner(indexer_client, nft_id),
    )

    signed_group = group_and_sign(
        [claimer, claimer, ALGOREALM_LAW],
        [claim_txn, donation_txn, nft_transfer],
    )

    nft_name = algod_client.asset_info(nft_id)['params']['name']

    print(f"Claiming the {nft_name} as {new_majesty}, "
          f"donating {donation_amount / 10 ** 6} ALGO...\n")
    try:
        gtxn_id = algod_client.send_transactions(signed_group)
        wait_for_confirmation(algod_client, gtxn_id)
    except AlgodHTTPError:
        quit("\n☹️  Were you too stingy? Only generous hearts will rule over "
             "Algorand Realm!\n️")
Ejemplo n.º 8
0
def sign_and_send(transaction: str, passphrase: str,
                  client: algod.AlgodClient) -> Dict[str, str or int]:
    """
    sign and send a transaction to the algorand network. Return the transaction
    info when the transaction is completed.

    :param transaction -> ``algosdk.transaction.AssetTransferTxn``: the transaction object.
    :param passphrase -> ``str``: the public key for the user involved in the transaction.
    :param client -> ``algod.AlgodClient``: an algorand client object.
    """
    private_key = mnemonic.to_private_key(passphrase)
    signed_transaction = transaction.sign(private_key)
    transaction_id = signed_transaction.transaction.get_txid()
    client.send_transaction(signed_transaction,
                            headers={'content-type': 'application/x-binary'})
    transaction_info = wait_for_confirmation(client, transaction_id)
    return transaction_info
Ejemplo n.º 9
0
def order_summary(algod_client: algod.AlgodClient, trade_gtxn: list):

    current_round = algod_client.status()["last-round"]
    last_valid_round = trade_gtxn[2].transaction.last_valid_round
    remaning_rounds = last_valid_round - current_round
    if remaning_rounds <= 0:
        remaning_rounds = 'Buy order expired!'

    return f"""
Ejemplo n.º 10
0
def wait_for_confirmation(client: algod.AlgodClient, txid: str):
    """
    Utility function to wait until the transaction is confirmed before
    proceeding.
    """
    last_round = client.status().get("last-round")
    txinfo = client.pending_transaction_info(txid)

    while not txinfo.get("confirmed-round", -1) > 0:
        print(f"Waiting for transaction {txid} confirmation.")
        last_round += 1
        client.status_after_block(last_round)
        txinfo = client.pending_transaction_info(txid)

    print(
        f"Transaction {txid} confirmed in round {txinfo.get('confirmed-round')}."
    )
    return txinfo
Ejemplo n.º 11
0
 def algod(self):
     "return an open algosdk.v2client.algod.AlgodClient"
     if self._algod is None:
         if self.algorand_data:
             token, addr = token_addr_from_algod(self.algorand_data)
         else:
             token = self.token
             addr = self.addr
         self._algod = AlgodClient(token, addr, headers=self.headers)
     return self._algod
Ejemplo n.º 12
0
def claim_card(algod_client: algod.AlgodClient, claimer: Account):
    params = algod_client.suggested_params()

    proof_crown_ownership = proof_asa_amount_eq_txn(
        algod_client=algod_client,
        sender=claimer,
        asa_id=CROWN_ID,
        asa_amount=1,
    )

    proof_sceptre_ownership = proof_asa_amount_eq_txn(
        algod_client=algod_client,
        sender=claimer,
        asa_id=SCEPTRE_ID,
        asa_amount=1,
    )

    nft_card_xfer = transaction.AssetTransferTxn(
        sender=CARD_CONTRACT.address,
        sp=params,
        receiver=claimer.address,
        amt=1,
        index=CARD_ID,
        revocation_target=CARD_CONTRACT.address,
    )

    signed_group = group_and_sign(
        [claimer, claimer, CARD_CONTRACT],
        [proof_crown_ownership, proof_sceptre_ownership, nft_card_xfer],
    )

    try:
        gtxn_id = algod_client.send_transactions(signed_group)
        wait_for_confirmation(algod_client, gtxn_id)
    except AlgodHTTPError:
        quit("\nOnly the generous heart of the Great Majesty of Algorand "
             "can break the spell!\n"
             "Conquer both the 👑 Crown of Entropy and the 🪄 Sceptre "
             "of Proof first!\n")
Ejemplo n.º 13
0
def add_network_params(
        client: algod.AlgodClient,
        tx_data: Dict[str, str or int]) -> Dict[str, str or int]:
    """
    Adds network-related parameters to supplied transaction data.

    :param client -> ``algod.AlgodClient``: an algorand client object.
    :param tx_data -> ``Dict[str, str or int]``: data for the transaction.
    """
    params = client.suggested_params()
    tx_data["first"] = params.first
    tx_data["last"] = params.last
    tx_data["gh"] = params.gh
    tx_data["gen"] = params.gen
    tx_data["fee"] = round(convert_algos_to_microalgo(.01))
    tx_data["flat_fee"] = True
    return tx_data
Ejemplo n.º 14
0
def proof_asa_amount_eq_txn(
    algod_client: algod.AlgodClient,
    sender: Account,
    asa_id: int,
    asa_amount: int,
):
    params = algod_client.suggested_params()

    proof_txn = transaction.ApplicationNoOpTxn(
        sender=sender.address,
        sp=params,
        index=ASA_STATE_OBSERVER_APP_ID,
        app_args=["AsaAmountEq".encode(), asa_amount],
        foreign_assets=[asa_id],
        accounts=[sender.address],
    )
    return proof_txn
Ejemplo n.º 15
0
    def restart(self):
        """
        This method restart the application from the point when it tries to connect to a node to display wallets.
        This method can also be used to do the first start.

        This is done by deleting any existing WalletFrame and creating a new one.
        This method also makes sure that new settings are refreshed into new rest endpoints.
        """
        # This will be enabled in the future when it can be called. (i.e.: there exists at least one wallet)
        self.menuAction_NewTransaction.setEnabled(False)

        if self.queuedWidget.count() >= 1:
            self.queuedWidget.clear_queue()

        endpoints = SettingsWindow.calculate_rest_endpoints()

        # TODO: Check that those settings actually point to an online daemon.
        if "kmd" in endpoints:
            self.kmd_client = KMDClient(
                endpoints["kmd"]["token"],
                endpoints["kmd"]["address"]
            )
        if "algod" in endpoints:
            self.algod_client = AlgodClient(
                endpoints["algod"]["token"],
                endpoints["algod"]["address"]
            )
        if "indexer" in endpoints:
            self.indexer_client = IndexerClient(
                endpoints["indexer"]["token"],
                endpoints["indexer"]["address"]
            )

        if self.kmd_client:
            try:
                self.kmd_client.versions()
            except Exception:
                QtWidgets.QMessageBox.critical(self, "kmd settings", "Please check kmd settings.\n"
                                                                     "Kmd daemon could be offline.")
            else:
                self.queuedWidget.add_widget(
                    WalletsFrame(self, self.kmd_client, self.algod_client, self.indexer_client)
                )
        else:
            QtWidgets.QMessageBox.critical(self, "kmd settings", "kmd settings not found.")
Ejemplo n.º 16
0
def sell_card(algod_client: algod.AlgodClient, user: Account):
    trade_gtxn = transaction.retrieve_from_file('trade_raw.gtxn')

    signed_crown_proof = trade_gtxn[0].sign(user.private_key)
    signed_sceptre_proof = trade_gtxn[1].sign(user.private_key)
    signed_royalty_1 = trade_gtxn[3].sign(user.private_key)
    signed_royalty_2 = trade_gtxn[4].sign(user.private_key)

    trade_gtxn[0] = signed_crown_proof
    trade_gtxn[1] = signed_sceptre_proof
    trade_gtxn[3] = signed_royalty_1
    trade_gtxn[4] = signed_royalty_2

    print(f"🤝 Selling the AlgoRealm Special Card for "
          f"{trade_gtxn[2].transaction.amt / 10 ** 6} ALGO:\n")
    try:
        gtxn_id = algod_client.send_transactions(trade_gtxn)
    except AlgodHTTPError:
        quit("You must hold the 👑 Crown and the 🪄 Scepter to sell the Card!\n")
    else:
        return wait_for_confirmation(algod_client, gtxn_id)
Ejemplo n.º 17
0
def card_order(
    algod_client: algod.AlgodClient,
    buyer: Account,
    seller: Account,
    price: int,
):
    params = algod_client.suggested_params()

    proof_crown_ownership = proof_asa_amount_eq_txn(
        algod_client=algod_client,
        sender=seller,
        asa_id=CROWN_ID,
        asa_amount=1,
    )

    proof_sceptre_ownership = proof_asa_amount_eq_txn(
        algod_client=algod_client,
        sender=seller,
        asa_id=SCEPTRE_ID,
        asa_amount=1,
    )

    nft_card_payment = transaction.PaymentTxn(
        sender=buyer.address,
        sp=params,
        receiver=seller.address,
        amt=price,
    )

    royalty_amount = math.ceil(price * ROYALTY_PERC / 100)

    royalty_1_payment = transaction.PaymentTxn(
        sender=seller.address,
        sp=params,
        receiver=ROYALTY_COLLECTOR_1.address,
        amt=royalty_amount,
    )

    royalty_2_payment = transaction.PaymentTxn(
        sender=seller.address,
        sp=params,
        receiver=ROYALTY_COLLECTOR_2.address,
        amt=royalty_amount,
    )

    nft_card_xfer = transaction.AssetTransferTxn(
        sender=CARD_CONTRACT.address,
        sp=params,
        receiver=buyer.address,
        amt=1,
        index=CARD_ID,
        revocation_target=seller.address,
    )

    trade_gtxn = [
        proof_crown_ownership, proof_sceptre_ownership, nft_card_payment,
        royalty_1_payment, royalty_2_payment, nft_card_xfer
    ]

    transaction.assign_group_id(trade_gtxn)
    signed_nft_card_payment = trade_gtxn[2].sign(buyer.private_key)
    trade_gtxn[2] = signed_nft_card_payment
    trade_gtxn[5] = transaction.LogicSigTransaction(trade_gtxn[5],
                                                    CARD_CONTRACT.lsig)
    transaction.write_to_file(trade_gtxn, 'trade_raw.gtxn', overwrite=True)

    print(
        "📝 Partially signed trade group transaction saved as: 'trade.gtxn'\n")

    return trade_gtxn