def payments_from_envelope( cls, envelope: te.TransactionEnvelope, invoice_list: Optional[model_pb2.InvoiceList] = None ) -> List['ReadOnlyPayment']: """Returns a list of read only payments from a transaction envelope. :param envelope: A :class:`TransactionEnvelope <kin_base.transaction_envelope.TransactionEnvelope>. :param invoice_list: (optional) A protobuf invoice list associated with the transaction. :return: A List of :class:`ReadOnlyPayment <ReadOnlyPayment>` objects. """ if invoice_list and invoice_list.invoices and len( invoice_list.invoices) != len(envelope.tx.operations): raise ValueError( "number of invoices ({}) does not match number of transaction operations ({})" .format(len(invoice_list.invoices), len(envelope.tx.operations))) tx = envelope.tx text_memo = None agora_memo = None if isinstance(tx.memo, memo.HashMemo): try: agora_memo = AgoraMemo.from_base_memo(tx.memo, False) except ValueError: pass elif isinstance(tx.memo, memo.TextMemo): text_memo = tx.memo payments = [] for idx, op in enumerate(envelope.tx.operations): # Currently, only payment operations are supported in this method. Eventually, create account and merge # account operations could potentially be supported, but currently this is primarily only used for payment # operations if not isinstance(op, operation.Payment): continue inv = invoice_list.invoices[ idx] if invoice_list and invoice_list.invoices else None payments.append( ReadOnlyPayment( sender=PublicKey.from_string( op.source if op.source else tx.source.decode()), destination=PublicKey.from_string(op.destination), tx_type=agora_memo.tx_type() if agora_memo else TransactionType.UNKNOWN, quarks=kin_to_quarks(op.amount), invoice=Invoice.from_proto(inv) if inv else None, memo=text_memo.text.decode() if text_memo else None, )) return payments
def _set_successful_get_account_info_response( channel: grpc_testing.Channel, pk: PrivateKey, sequence: int, balance: int = kin_to_quarks("1000") ) -> account_pb.GetAccountInfoRequest: resp = account_pb.GetAccountInfoResponse( result=account_pb.GetAccountInfoResponse.Result.OK, account_info=account_pb.AccountInfo( account_id=model_pb2.StellarAccountId( value=pk.public_key.stellar_address ), sequence_number=sequence, balance=balance, ) ) return TestAgoraClient._set_get_account_info_response(channel, resp)
required=True, help= 'A comma-delimited list of account public addresses to send earns to (e.g. add1,addr2,add3' ) args = vars(ap.parse_args()) client = Client(Environment.TEST, 1) # 1 is the test app index source = PrivateKey.from_string(args['sender']) destinations = [ PublicKey.from_string(addr) for addr in args['destinations'].split(',') ] # Send an earn batch with 1 Kin each earns = [ Earn(dest, kin_to_quarks('1')) for idx, dest in enumerate(destinations) ] batch_result = client.submit_earn_batch(source, earns) print( f'{len(batch_result.succeeded)} succeeded, {len(batch_result.failed)} failed' ) for result in batch_result.succeeded: print( f'Sent 1 kin to {result.earn.destination.stellar_address} in transaction {result.tx_id.hex()}' ) for result in batch_result.failed: print( f'Failed to send 1 kin to {result.earn.destination.stellar_address} in transaction {result.tx_id.hex()} ' f'(error: {repr(result.error)})') # Send an earn batch of earns with 1 Kin each, with invoices
def test_kin_to_quarks(self): assert kin_to_quarks("0.000009") == 0 assert kin_to_quarks("0.00015") == 15 assert kin_to_quarks("5") == 500000 assert kin_to_quarks("5.1") == 510000 assert kin_to_quarks("5.123459") == 512345
def payments_from_envelope( cls, envelope: te.TransactionEnvelope, invoice_list: Optional[model_pb2.InvoiceList] = None, kin_version: Optional[int] = 3, ) -> List['ReadOnlyPayment']: """Returns a list of read only payments from a transaction envelope. :param envelope: A :class:`TransactionEnvelope <kin_base.transaction_envelope.TransactionEnvelope>. :param invoice_list: (optional) A protobuf invoice list associated with the transaction. :param kin_version: (optional) The version of Kin to parse payments for. :return: A List of :class:`ReadOnlyPayment <ReadOnlyPayment>` objects. """ if invoice_list and invoice_list.invoices and len( invoice_list.invoices) != len(envelope.tx.operations): raise ValueError( f'number of invoices ({len(invoice_list.invoices)}) does not match number of transaction ' f'operations ({len(envelope.tx.operations)})') tx = envelope.tx text_memo = None agora_memo = None if isinstance(tx.memo, memo.HashMemo): try: agora_memo = AgoraMemo.from_base_memo(tx.memo, False) except ValueError: pass elif isinstance(tx.memo, memo.TextMemo): text_memo = tx.memo payments = [] for idx, op in enumerate(envelope.tx.operations): # Currently, only payment operations are supported in this method. Eventually, create account and merge # account operations could potentially be supported, but currently this is primarily only used for payment # operations if not isinstance(op, operation.Payment): continue # Only Kin payment operations are supported in this method. if kin_version == 2 and (op.asset.type != 'credit_alphanum4' or op.asset.code != 'KIN'): continue inv = invoice_list.invoices[ idx] if invoice_list and invoice_list.invoices else None # Inside the kin_base module, the base currency has been 'scaled' by a factor of 100 from # Stellar (i.e., the smallest denomination used is 1e-5 instead of 1e-7). However, Kin 2 uses the minimum # Stellar denomination of 1e-7. # # When parsing an XDR transaction, `kin_base` assumes a smallest denomination of 1e-5. Therefore, for Kin 2 # transactions, we must divide the resulting amounts by 100 to account for the 100x scaling factor. payments.append( ReadOnlyPayment( sender=PublicKey.from_string( op.source if op.source else tx.source.decode()), destination=PublicKey.from_string(op.destination), tx_type=agora_memo.tx_type() if agora_memo else TransactionType.UNKNOWN, quarks=int(kin_to_quarks(op.amount) / 100) if kin_version == 2 else kin_to_quarks(op.amount), invoice=Invoice.from_proto(inv) if inv else None, memo=text_memo.text.decode() if text_memo else None, )) return payments
'--sender', required=True, help='The private seed of the sender account') ap.add_argument('-d', '--destination', required=True, help='The public address of the destination account') args = vars(ap.parse_args()) client = Client(Environment.TEST, 1) # 1 is the test app index source = PrivateKey.from_base58(args['sender']) dest = PublicKey.from_base58(args['destination']) # Send a payment of 1 Kin payment = Payment(source, dest, TransactionType.EARN, kin_to_quarks('1')) try: tx_id = client.submit_payment(p) print( f'transaction successfully submitted with hash: {base58.b58encode(tx_id)}' ) except Error as e: print(f'transaction failed: {repr(e)}') if isinstance(e, TransactionErrors): print( f'tx_error={repr(e.tx_error)}, len(op_errors)={len(e.op_errors)}') for op_error in e.op_errors: print(f'op_error={repr(op_error)}') # Send a payment of 1 Kin with a text memo payment = Payment(source,
retry_config = RetryConfig(max_retries=0, min_delay=0, max_delay=0, max_nonce_refreshes=0) client = Client(Environment.TEST, 1, retry_config=retry_config) # 1 is the test app index source = PrivateKey.from_string(args['sender']) destinations = [ PublicKey.from_string(addr) for addr in args['destinations'].split(',') ] # Send an earn batch with 1 Kin each earns = [ Earn(dest, kin_to_quarks("1")) for idx, dest in enumerate(destinations) ] batch_result = client.submit_earn_batch(source, earns) print("{} succeeded, {} failed".format(len(batch_result.succeeded), len(batch_result.failed))) for result in batch_result.succeeded: print("Sent 1 kin to {} in transaction {}".format( result.earn.destination.stellar_address, result.tx_hash.hex(), )) for result in batch_result.failed: print("Failed to send 1 kin to {} in transaction {} (error: {})".format( result.earn.destination.stellar_address, result.tx_hash.hex(), repr(result.error), ))
import argparse from agora.client import Client, Environment from agora.keys import PublicKey from agora.utils import kin_to_quarks ap = argparse.ArgumentParser() ap.add_argument( '-s', '--destination', required=True, help= 'The base58-encoded Kin token account address of the airdrop destination account' ) args = vars(ap.parse_args()) client = Client(Environment.TEST, 1) # 1 is the test app index dest = PublicKey.from_base58(args['destination']) print(f'requesting airdrop for {dest.to_base58()}') # Note: the airdrop service is only available when using Environment.TEST. airdrop_resp = client.request_airdrop(dest, kin_to_quarks("5")) print(f'funded {dest.to_base58()} with {5} Kin') # The client should be closed once it is no longer needed. client.close()
def submit_payment(self, sender: PrivateKey, destination: PublicKey, amount: str, tx_type: TransactionType, memo: Optional[str]): payment = Payment(sender, destination, tx_type, kin_to_quarks(amount), memo) return self.client.submit_payment(payment)
def request_airdrop(self, public_key: PublicKey, amount: str): return self.client.request_airdrop(public_key, kin_to_quarks(amount))