예제 #1
0
    def from_proto(
            cls, item: tx_pb_v4.HistoryItem,
            state: tx_pb_v4.GetTransactionResponse.State) -> 'TransactionData':
        payments = []
        if item.invoice_list and item.invoice_list.invoices:
            if len(item.payments) != len(item.invoice_list.invoices):
                raise ValueError(
                    'number of invoices does not match number of payments')
            il = InvoiceList.from_proto(item.invoice_list)
        else:
            il = None

        tx_type = TransactionType.UNKNOWN
        memo = None
        if item.solana_transaction.value:
            solana_tx = solana.Transaction.unmarshal(
                item.solana_transaction.value)
            program_idx = solana_tx.message.instructions[0].program_index
            if solana_tx.message.accounts[
                    program_idx] == solana.MEMO_PROGRAM_KEY:
                decompiled_memo = solana.decompile_memo(solana_tx.message, 0)
                memo_data = decompiled_memo.data.decode('utf-8')
                try:
                    agora_memo = AgoraMemo.from_b64_string(memo_data)
                    tx_type = agora_memo.tx_type()
                except ValueError:
                    memo = memo_data
        elif item.stellar_transaction.envelope_xdr:
            env = te.TransactionEnvelope.from_xdr(
                base64.b64encode(item.stellar_transaction.envelope_xdr))
            tx = env.tx
            if isinstance(tx.memo, stellar_memo.HashMemo):
                try:
                    agora_memo = AgoraMemo.from_base_memo(tx.memo)
                    tx_type = agora_memo.tx_type()
                except ValueError:
                    pass
            elif isinstance(tx.memo, stellar_memo.TextMemo):
                memo = tx.memo.text.decode()

        for idx, p in enumerate(item.payments):
            inv = il.invoices[idx] if il and il.invoices else None
            payments.append(
                ReadOnlyPayment(PublicKey(p.source.value),
                                PublicKey(p.destination.value),
                                tx_type,
                                p.amount,
                                invoice=inv,
                                memo=memo))

        return cls(
            item.transaction_id.value,
            TransactionState.from_proto_v4(state),
            payments,
            error=TransactionErrors.from_proto_error(item.transaction_error)
            if item.transaction_error else None,
        )
예제 #2
0
    def payments_from_transaction(
        cls,
        tx: solana.Transaction,
        invoice_list: Optional[model_pb2.InvoiceList] = None
    ) -> List['ReadOnlyPayment']:
        """Returns a list of read only payments from a Solana transaction.

        :param tx: The transaction.
        :param invoice_list: (optional) A protobuf invoice list associated with the transaction.
        :return: A List of :class:`ReadOnlyPayment <ReadOnlyPayment>` objects.
        """
        text_memo = None
        agora_memo = None
        start_index = 0
        program_idx = tx.message.instructions[0].program_index
        if tx.message.accounts[program_idx] == solana.MEMO_PROGRAM_KEY:
            decompiled_memo = solana.decompile_memo(tx.message, 0)
            start_index = 1
            memo_data = decompiled_memo.data.decode('utf-8')
            try:
                agora_memo = AgoraMemo.from_b64_string(memo_data)
            except ValueError:
                text_memo = memo_data

        transfer_count = (len(tx.message.instructions) - 1 if
                          (text_memo or agora_memo) else len(
                              tx.message.instructions))
        if invoice_list and invoice_list.invoices and len(
                invoice_list.invoices) != transfer_count:
            raise ValueError(
                f'number of invoices ({len(invoice_list.invoices)}) does not match number of non-memo '
                f'transaction instructions ({transfer_count})')

        payments = []
        for idx, op in enumerate(tx.message.instructions[start_index:]):
            try:
                decompiled_transfer = solana.decompile_transfer(
                    tx.message, idx + start_index)
            except ValueError as e:
                continue

            inv = invoice_list.invoices[
                idx] if invoice_list and invoice_list.invoices else None
            payments.append(
                ReadOnlyPayment(
                    sender=decompiled_transfer.source,
                    destination=decompiled_transfer.dest,
                    tx_type=agora_memo.tx_type()
                    if agora_memo else TransactionType.UNKNOWN,
                    quarks=decompiled_transfer.amount,
                    invoice=Invoice.from_proto(inv) if inv else None,
                    memo=text_memo if text_memo else None,
                ))

        return payments