def payment_key(self): '''Generates the Payment Transaction Key, or PTK. It does not communicate with the server.''' #------------------------------------ # PTK Payload v1 Block #------------------------------------ p1 = pcos.create_output_block( 'P1' ) # membership ID device_id = self.args['device_id'] p1.write_string( device_id ) #------------------------------------ # PTK M1HW Block #------------------------------------ m1hw = pcos.create_output_block( 'M1' ) # tag serial number m1hw.write_bytestr( binascii.unhexlify(self.args['serial_number']) ) # app challenge seed m1hw.write_bytestr( binascii.unhexlify(self.args['seed']) ) # transaction key ID m1hw.write_bytes( binascii.unhexlify(self.args['keyid']) ) # PUF response m1hw.write_bytestr( binascii.unhexlify(self.args['puf_response']) ) # fake challenge-response time (ms) m1hw.write_uint( 92 ) #------------------------------------ # PTK Message # * Payload Block # * M1HW Block #------------------------------------ ptk = pcos.Doc( name="PaymentKey" ) ptk.add( p1 ) ptk.add( m1hw ) ptk_bytes = ptk.as_bytearray() # write serialized data as binary and qr-code payload_file = open('ptk.pcos', 'w') payload_file.write( ptk_bytes ) payload_file.close() print ("Saved PTK object to 'ptk.pcos'") return ptk_bytes
def transfer(self): '''Sends a Transfer Request''' apta_bytes = self.payment() #------------------------------------ # Armored-PTA Block #------------------------------------ apta_block = pcos.create_output_block( 'Pa' ) # we use "fixstr" becase we don't want size-prefix apta_block.write_fixstr(apta_bytes, len(apta_bytes)) #------------------------------------ # Transfer Request Block #------------------------------------ trnfs_req_block = pcos.create_output_block( 'R1' ) # mat trnfs_req_block.write_varstr( binascii.unhexlify( self.args['receiver_mat'] ) ) # ref data trnfs_req_block.write_varstr( '' ) # create-time trnfs_req_block.write_ulong( long( time.time() + 0.5 ) ) (charge_int, charge_scale) = decimal_to_parts(Decimal(self.args['charge'])) trnfs_req_block.write_long( charge_int ) # value trnfs_req_block.write_int( charge_scale ) # scale # currency trnfs_req_block.write_fixstr( "USD", size=3 ) # note trnfs_req_block.write_varstr( 'John paid his dept' ) # no geo-location available trnfs_req_block.write_bool(False) #------------------------------------ # Transfer Message #------------------------------------ req = pcos.Doc( name="Tt" ) req.add( trnfs_req_block ) req.add( apta_block ) res = self.send( req ) self.expect_success( res )
def balance(self): '''Returns account balance''' #------------------------------------ # Request Body Block #------------------------------------ out_bo = pcos.create_output_block( 'Bo' ) out_bo.write_varstr( binascii.unhexlify( self.args['mat'] ) ) # mat out_bo.write_varstr( '' ) # ref_data req = pcos.Doc( name="Bq" ) req.add( out_bo ) res = self.send( req ) assert res.message_id == 'Br' #------------------------------------ # Response Body Block #------------------------------------ body = res.block( 'Bo' ) ref_data = body.read_varstr( ) # ref_data value = body.read_long() # value scale = body.read_int() # scale balance_asofepoch = body.read_ulong(); balance = value * math.pow(10, scale) balance_asofdate = time.strftime("%a, %d %b %Y %H:%M:%S +0000", time.gmtime(balance_asofepoch)) log.info('Balance is $%s as of %s', balance, balance_asofdate)
def provision(self): '''Provision a device''' #------------------------------------ # Body Block #------------------------------------ out_bo = pcos.create_output_block( 'Bo' ) # MAT out_bo.write_varstr( binascii.unhexlify( self.args['mat'] ) ) # Serial number ID out_bo.write_varstr( binascii.unhexlify(self.args['serial_number']) ) #------------------------------------ # Provision Message #------------------------------------ req = pcos.Doc( name="Ov" ) req.add( out_bo ) # send the message and process the result. res = self.send( req ) self.expect_message(res, 'Cr') # jump to the block of interest in_bo = res.block( 'Bo' ) # read MAT returned by the server device_id = in_bo.read_varstr() registration_id =in_bo.read_varstr() log.info('provision-success| device-ID: %s, registration-ID: %s', binascii.hexlify( device_id ), registration_id )
def preauth(self): '''Generates the PTA and submits to server for validation.''' apta_bytes = self.payment() #------------------------------------ # Armored-PTA Block #------------------------------------ apta_block = pcos.create_output_block( 'Pa' ) # we use "fixstr" becase we don't want size-prefix apta_block.write_fixstr(apta_bytes, len(apta_bytes)) #------------------------------------ # Preauthorizaton Block #------------------------------------ preauth_block = pcos.create_output_block( 'Pr' ) # mat preauth_block.write_varstr( binascii.unhexlify( self.args['preauth_mat'] ) ) # ref data preauth_block.write_varstr( '' ) # preauth amount (charge_int, charge_scale) = decimal_to_parts(Decimal(self.args['charge'])) preauth_block.write_long( charge_int ) # value preauth_block.write_int( charge_scale ) # scale # currency preauth_block.write_fixstr( "USD", size=3 ) #------------------------------------ # Preauth Message #------------------------------------ req = pcos.Doc( name="Pr" ) req.add( preauth_block ) req.add( apta_block ) res = self.send( req ) self.expect_success( res )
def register(self): '''Register command''' #------------------------------------ # Body Block #------------------------------------ bo = pcos.create_output_block( 'Bo' ) # registration ID bo.write_string( self.args['registration_id'] ) # DER encoded public key -- signature verification key bo.write_bytestr( base64.b64decode(TEST_DSA_KEY_PUB_PEM) ) # # user-agent attributes # user_agent = [ # ('appname', 'IceBreaker'), # ('appver', '2.0'), # ('appurl', 'https://pushcoin.com/Pub/SDK/WelcomeDevelopers'), # ('author', 'PushCoin <*****@*****.**>'), # ('os', '%s %s' % (sys.platform, sys.version)), # ] # bo.write_uint( len(user_agent) ) # for kv in user_agent: # bo.write_varstr( kv[0] ) # bo.write_varstr( kv[1] ) #------------------------------------ # Register Message #------------------------------------ req = pcos.Doc( name="Re" ) req.add( bo ) # send the message and process the result. res = self.send( req ) assert res.message_id == 'Ac' # jump to the block of interest out_bo = res.block( 'Bo' ) # read MAT returned by the server mat = out_bo.read_bytestr() log.info('Success (MAT: %s)', binascii.hexlify( mat ))
def error_report(self): '''Submits an error report''' #------------------------------------ # Request Body Block #------------------------------------ out_bo = pcos.create_output_block( 'Bo' ) # MAT out_bo.write_bytestr( binascii.unhexlify( self.args['mat'] ) ) # mime out_bo.write_string( 'text/plain' ) # report content out_bo.write_bytestr( self.args['report'] ) req = pcos.Doc( name="Er" ) req.add( out_bo ) res = self.send( req ) self.expect_success( res )
def transaction_challenge(self): req = pcos.Doc( name="Tc" ) out_bo = pcos.create_output_block( 'Bo' ) out_bo.write_bytestr( binascii.unhexlify( self.args['mat'] ) ) req.add( out_bo ) res = self.send( req ) # jump to the block of interest body = res.block( 'Bo' ) # number of keys challenge_count = body.read_uint() for ix in xrange(0,challenge_count): response_length = body.read_uint() challenge = body.read_bytestr() challenge_id = body.read_bytestr() key_expiry = body.read_ulong() log.info('challenge %s, ID %s, expires on %s, exp-response-length: %s', binascii.hexlify( challenge), binascii.hexlify( challenge_id ), time.strftime("%a, %d %b %Y %H:%M:%S +0000", time.gmtime(key_expiry)), response_length)
def payment_pta(self): '''Generates the Payment Transaction Authorization, or PTA. It does not communicate with the server.''' #------------------------------------ # PTA Payment Block #------------------------------------ p1 = pcos.create_output_block( 'P1' ) # member authentication token mat = self.args['mat'] if len( mat ) != 40: raise RuntimeError("MAT must be 40-characters long" % self.cmd) p1.write_varstr( binascii.unhexlify( mat ) ) # cert. create time and expiry now = long( time.time() + 0.5 ) p1.write_ulong( now ) # certificate create-time p1.write_ulong( now + 24 * 3600 ) # certificate expires in 24 hrs # payment-limit (payment_int, payment_scale) = decimal_to_parts(Decimal(self.args['limit'])) p1.write_long( payment_int ) # value p1.write_int( payment_scale ) # scale # currency p1.write_fixstr( "USD", size=3 ) # recipient p1.write_varstr( "" ) # ref-data p1.write_varstr( "" ) # note p1.write_varstr( "" ) print (" %s bytes => Payment Block" % p1.size()) #------------------------------------ # PTA Signature Block #------------------------------------ s1 = pcos.create_output_block( 'S1' ) # checksum Payment Block digest = hashlib.sha1(p1.as_bytearray()).digest() # sign the checksum dsa_priv_key = BIO.MemoryBuffer( TEST_DSA_KEY_PRV_PEM ) signer = DSA.load_key_bio( dsa_priv_key ) signature = signer.sign_asn1( digest ) # store the signature of the Payment Block s1.write_varstr( signature ) print (" %s bytes => Signature Block" % s1.size()) #------------------------------------ # PTA Message # * Payment Block # * Signature Block #------------------------------------ pta = pcos.Doc( name="Pa" ) pta.add( p1 ) pta.add( s1 ) #------------------------------------ # A-PTA Private (PTA) Block #------------------------------------ a1 = pcos.create_output_block( 'A1' ) # encrypt the PTA message txn_pub_key = BIO.MemoryBuffer( API_TRANSACTION_KEY_PEM ) encrypter = RSA.load_pub_key_bio( txn_pub_key ) # RSA Encryption Scheme w/ Optimal Asymmetric Encryption Padding input_data = pta.as_bytearray() print (" %s bytes => header+meta" % (len(input_data) - s1.size() - p1.size())) print ("-------------\n %s bytes => Total PTA\n---------" % len(input_data)) encrypted = encrypter.public_encrypt( pta.as_bytearray(), RSA.pkcs1_padding ) a1.write_fixstr( encrypted, size=len(encrypted) ) #------------------------------------ # A-PTA Public Block #------------------------------------ k1 = pcos.create_output_block( 'K1' ) # encryption key identifier k1.write_fixstr( API_TRANSACTION_KEY_ID, size=len(API_TRANSACTION_KEY_ID) ) #------------------------------------ # A-PTA Message #------------------------------------ apta = pcos.Doc( name="Ap" ) apta.add( a1 ) apta.add( k1 ) apta_bytes = apta.as_bytearray() # write serialized data as binary and qr-code payload_file = open('apta.pcos', 'w') payload_file.write( apta_bytes ) payload_file.close() print ("Saved APTA object to 'apta.pcos'") # optionally generate qr-code try: import qrcode qr = qrcode.QRCode(version=None, box_size=3, error_correction=qrcode.constants.ERROR_CORRECT_L) qr.add_data( apta_bytes ) qr.make(fit=True) img = qr.make_image() img.save('apta.png') print ("APTA-QR: apta.png, version %s" % (qr.version)) except ImportError: log.warn("QR-Code not written -- qrcode module not found") return apta_bytes
def payment_key(self): '''Generates the Payment Transaction Key, or PTK. It does not communicate with the server.''' #------------------------------------ # PTK Key Block #------------------------------------ k1 = pcos.create_output_block( 'K1' ) # membership ID device_id = self.args['device_id'] k1.write_varstr( device_id ) # passcode k1.write_varstr( self.args['passcode'] ) # key create time and expiry now = long( time.time() + 0.5 ) # utc_ctime k1.write_ulong( now ) # key create-time # transaction footprint queue k1.write_bool( True ) footprint = binascii.unhexlify(self.args['footprint']) # write transaction queue k1.write_uint( 10 ) for i in xrange(0,10): k1.write_fixstr( footprint, 4 ) # counter k1.write_uint( 0 ) # source_id (aka serial number) k1.write_varstr( binascii.unhexlify(self.args['serial_number']) ) print (" %s bytes => Key Block" % k1.size()) #------------------------------------ # PTK Checksum Block #------------------------------------ c1 = pcos.create_output_block( 'C1' ) # checksum Key Block digest = hashlib.sha1(k1.as_bytearray()).digest() # store the signature of the Payment Block c1.write_varstr( digest ) print (" %s bytes => Checksum Block" % c1.size()) #------------------------------------ # PTK Message # * Key Block # * Checksum Block #------------------------------------ ptk = pcos.Doc( name="Pk" ) ptk.add( k1 ) ptk.add( c1 ) ptk_bytes = ptk.as_bytearray() # write serialized data as binary and qr-code payload_file = open('ptk.pcos', 'w') payload_file.write( ptk_bytes ) payload_file.close() print ("Saved PTK object to 'ptk.pcos'") return ptk_bytes
def charge(self, payment_type, payment_bytes): #------------------------------------ # Payment Block #------------------------------------ payment_block = pcos.create_output_block( payment_type ) # we use "fixstr" becase we don't want size-prefix payment_block.write_fixstr(payment_bytes, len(payment_bytes)) #------------------------------------ # Payment Request Block #------------------------------------ paymnt_req_block = pcos.create_output_block( 'R1' ) # mat paymnt_req_block.write_varstr( binascii.unhexlify( self.args['receiver_mat'] ) ) # ref data paymnt_req_block.write_varstr( '' ) # create-time paymnt_req_block.write_ulong( long( time.time() + 0.5 ) ) (charge_int, charge_scale) = decimal_to_parts(Decimal(self.args['charge'])) paymnt_req_block.write_long( charge_int ) # value paymnt_req_block.write_int( charge_scale ) # scale # tax paymnt_req_block.write_bool(True) # optional indicator (tax_value, tax_scale) = decimal_to_parts(Decimal(self.args['tax'])) paymnt_req_block.write_long( tax_value ) # value paymnt_req_block.write_int( tax_scale ) # scale # tip paymnt_req_block.write_bool(True) # optional indicator (tip_value, tip_scale) = decimal_to_parts(Decimal(self.args['tip'])) paymnt_req_block.write_long( tip_value ) # value paymnt_req_block.write_int( tip_scale ) # scale # currency paymnt_req_block.write_fixstr( "USD", size=3 ) # invoice ID paymnt_req_block.write_varstr( 'inv-123' ) # note paymnt_req_block.write_varstr( 'happy meal' ) # no geo-location available paymnt_req_block.write_bool(False) # list of purchased goods paymnt_req_block.write_int(0) #------------------------------------ # Payment Request Signature Block #------------------------------------ paymnt_req_signature_block = pcos.create_output_block( 'S1' ) # checksum Payment Request Block digest = hashlib.sha1(paymnt_req_block.as_bytearray()).digest() # sign the checksum dsa_priv_key = BIO.MemoryBuffer( TEST_DSA_KEY_PRV_PEM ) signer = DSA.load_key_bio( dsa_priv_key ) signature = signer.sign_asn1( digest ) # store the signature of the Payment Block paymnt_req_signature_block.write_varstr( signature ) #------------------------------------ # Payment Request Message #------------------------------------ req = pcos.Doc( name="Pt" ) req.add( paymnt_req_block ) req.add( paymnt_req_signature_block ) req.add( payment_block ) res = self.send( req ) # there can be two types of results: Ap or Np, depending # success or failure due to insufficient funds if res.message_id != 'Ap' and res.message_id != 'Np': raise RuntimeError("Unexpected payment result '%s'" % res.message_id) # read balance balance = res.block( 'Bo' ) ref_data = balance.read_varstr() # ref_data transaction_id = balance.read_varstr() # tx-id if res.message_id == 'Np': code = er.read_uint() what = er.read_varstr() # exact amount given? if balance.read_bool(): exact_balance = 'is' else: exact_balance = 'is greater than' # amount value = balance.read_long() # value scale = balance.read_int() # scale balance_amount = value * math.pow(10, scale) # time of last update tm_epoch = balance.read_ulong(); balance_asofdate = time.strftime("%a, %d %b %Y %H:%M:%S +0000", time.gmtime(tm_epoch)) if res.message_id == 'Np': log.warn('%s (tx_id: %s). Balance %s $%s as of %s', what, base64.b32encode(transaction_id), exact_balance, balance_amount, balance_asofdate) else: log.info('Success (tx_id: %s). Balance %s $%s as of %s', base64.b32encode(transaction_id), exact_balance, balance_amount, balance_asofdate)
def history(self): '''Returns transaction history''' #------------------------------------ # Request Body Block #------------------------------------ out_bo = pcos.create_output_block( 'Bo' ) # MAT out_bo.write_varstr( binascii.unhexlify( self.args['mat'] ) ) # ref-data out_bo.write_varstr( '' ) # search keywords out_bo.write_varstr( '' ) # page number and page-size out_bo.write_uint( int(self.args['page']) ) out_bo.write_uint( int(self.args['size']) ) #------------------------------------ # History Query Message #------------------------------------ req = pcos.Doc( name="Hq" ) req.add( out_bo ) res = self.send( req ) assert res.message_id == 'Hr' #------------------------------------ # Response Body Block #------------------------------------ body = res.block( 'Bo' ) # ref-data ref_data = body.read_varstr() # read number of transactions count = body.read_uint() for i in xrange(1, count+1): # transaction ID tx_id = binascii.hexlify( body.read_varstr() ) # counterparty ID counterparty = binascii.hexlify( body.read_varstr() ) # transaction time of day epoch_tx_time = body.read_ulong() tx_time = time.strftime("%a, %d %b %Y %H:%M:%S +0000", time.gmtime(epoch_tx_time)) # transaction type tx_type = body.read_fixstr(1) # transaction context: (P)ayment or (T)ransfer tx_context = body.read_fixstr(1) #amount value = body.read_long() # value scale = body.read_int() # scale amount = value * math.pow(10, scale) # tax if body.read_bool(): value = body.read_long() # value scale = body.read_int() # scale tax = value * math.pow(10, scale) else: tax = 'not provided' #tip if body.read_bool(): value = body.read_long() # value scale = body.read_int() # scale tip = value * math.pow(10, scale) else: tip = 'not provided' # currency currency = body.read_fixstr(3) # merchant name merchant_name = body.read_varstr() # PTA recipient recipient = body.read_varstr() # ref_data ref_data = binascii.hexlify( body.read_varstr() ) # invoice invoice = body.read_varstr() # note note = body.read_varstr() # address of the POS station if body.read_bool(): street = body.read_varstr() city = body.read_varstr() state = body.read_varstr() zipc = body.read_varstr() country = body.read_fixstr(2) address = '%s, %s, %s %s, %s' % (street, city, state, zipc, country) else: address = 'not provided' # contact info at the place of transaction origination if body.read_bool(): phone = body.read_varstr() email = body.read_varstr() contact = 'phone: %s, email: %s' % (phone, email) else: contact = 'not provided' # geo-location of the place of transaction origination if body.read_bool(): latitude = body.read_double() longitude = body.read_double() geolocation = '%s, %s' % (latitude, longitude) else: geolocation = 'not provided' print "--- %s/%s ---\ntx-id: %s\ncounterparty: %s\ntx_time: %s\naddress: %s\ngeolocation: %s\ncontact: %s\ntx_type: %s\ntx_context: %s\namount: %s\ntip: %s\ntax: %s\ncurrency: %s\nmerchant_name: %s\nrecipient: %s\nref-data: %s\ninvoice: %s\nnote: %s\n" % (i, count, tx_id, counterparty, tx_time, address, geolocation, contact, tx_type, tx_context, amount, tip, tax, currency, merchant_name, recipient, ref_data, invoice, note) log.info('Returned %s records', count)
def charge(self, payment_bytes): #------------------------------------ # Payment Authorization Block #------------------------------------ payment_auth_block = pcos.create_output_block( 'Py' ) payment_auth_block.write_bytes(payment_bytes) #------------------------------------ # Payment Request Block #------------------------------------ paymnt_req_block = pcos.create_output_block( 'R1' ) # mat paymnt_req_block.write_bytestr( binascii.unhexlify( self.args['receiver_mat'] ) ) # ref data paymnt_req_block.write_bytestr( '' ) # create-time paymnt_req_block.write_ulong( long( time.time() + 0.5 ) ) (charge_int, charge_scale) = decimal_to_parts(Decimal(self.args['charge'])) paymnt_req_block.write_long( charge_int ) # value paymnt_req_block.write_int( charge_scale ) # scale # tax paymnt_req_block.write_bool(True) # optional indicator (tax_value, tax_scale) = decimal_to_parts(Decimal(self.args['tax'])) paymnt_req_block.write_long( tax_value ) # value paymnt_req_block.write_int( tax_scale ) # scale # tip paymnt_req_block.write_bool(True) # optional indicator (tip_value, tip_scale) = decimal_to_parts(Decimal(self.args['tip'])) paymnt_req_block.write_long( tip_value ) # value paymnt_req_block.write_int( tip_scale ) # scale # passcode paymnt_req_block.write_string( '1111' ) # currency paymnt_req_block.write_bytes( b"USD" ) # invoice ID paymnt_req_block.write_string( 'inv-123' ) # note paymnt_req_block.write_string( 'happy meal' ) # no geo-location available paymnt_req_block.write_bool(False) # list of purchased goods paymnt_req_block.write_int(0) #------------------------------------ # Payment Request Message #------------------------------------ req = pcos.Doc( name="PaymentReq" ) req.add( payment_auth_block ) req.add( paymnt_req_block ) res = self.send( req ) self.expect_message(res, 'PaymentAck')
def history(self): '''Returns transaction history''' # page number and page-size page_num = int(self.args['page']) page_size = int(self.args['size']) #------------------------------------ # Request Body Block #------------------------------------ out_bo = pcos.create_output_block( 'Bo' ) # MAT out_bo.write_bytestr( binascii.unhexlify( self.args['mat'] ) ) # page size and offset out_bo.write_uint( page_num ) out_bo.write_uint( page_size ) #------------------------------------ # History Query Message #------------------------------------ req = pcos.Doc( name="TxnHistoryQuery" ) req.add( out_bo ) res = self.send( req ) assert res.message_id == 'TxnHistoryReply' #------------------------------------ # Balanace segment #------------------------------------ balance_seg = res.block( 'Bl' ) rs={} #amount value = balance_seg.read_long() # value scale = balance_seg.read_int() # scale balance_amount = value * math.pow(10, scale) # read block field(s) tm_epoch = balance_seg.read_ulong(); balance_as_of_date = time.strftime("%a, %d %b %Y %H:%M:%S +0000", time.gmtime(tm_epoch)) #------------------------------------ # Transaction History segment #------------------------------------ hist_seg = res.block( 'Tr' ) # total transactions found total_count = hist_seg.read_uint() # read number of transactions count = hist_seg.read_uint() for i in xrange(1, count+1): print( '-- [ Row %s ] --' % (i+page_num) ) rs['txn_id'] = hist_seg.read_string() rs['device_name'] = hist_seg.read_string() rs['txn_as_of_date'] = time.strftime("%a, %d %b %Y %H:%M:%S +0000", time.gmtime(hist_seg.read_ulong())) rs['txn_type'] = hist_seg.read_string() rs['txn_context'] = hist_seg.read_string() rs['currency'] = hist_seg.read_string() value = hist_seg.read_long() # value scale = hist_seg.read_int() # scale rs['txn_amount'] = value * math.pow(10, scale) # tax if hist_seg.read_bool(): value = hist_seg.read_long() # value scale = hist_seg.read_int() # scale rs['txn_tax'] = value * math.pow(10, scale) #tip if hist_seg.read_bool(): value = hist_seg.read_long() # value scale = hist_seg.read_int() # scale rs['txn_tip'] = value * math.pow(10, scale) rs['counterparty'] = hist_seg.read_string() rs['invoice'] = hist_seg.read_string() rs['note'] = hist_seg.read_string() # address of the POS station if hist_seg.read_bool(): street = hist_seg.read_string() city = hist_seg.read_string() state = hist_seg.read_string() zipc = hist_seg.read_string() country = hist_seg.read_string() rs['merchant_address'] = '%s, %s, %s %s, %s' % (street, city, state, zipc, country) # contact info if hist_seg.read_bool(): rs['merchant_phone'] = hist_seg.read_string() rs['merchant_email'] = hist_seg.read_string() # geo location if hist_seg.read_bool(): rs['txn_latitude'] = hist_seg.read_double() rs['txn_longitude'] = hist_seg.read_double() rs['txn_status'] = hist_seg.read_string() # rating and score rs['user_rating'] = hist_seg.read_uint() rs['merchant_score'] = hist_seg.read_double() rs['vote_count'] = hist_seg.read_uint() printplus( rs ) print( '------' ) page_size = int(self.args['size']) log.info('Returned page %s of %s, balance %s as of %s', self.args['page'], int(math.ceil(total_count/page_size)), balance_amount, balance_as_of_date )