# create a monitor monitor_id = mobilecoind.add_monitor(account_key, first_subaddress=args.subaddress, first_block=args.first_block).monitor_id # Wait for the monitor to process the complete ledger (this also downloads the complete ledger) (monitor_is_behind, next_block, remote_count, blocks_per_second) = mobilecoind.wait_for_monitor(monitor_id) if monitor_is_behind: print("\n# waiting for the monitor to process {} blocks".format(remote_count - next_block)) while monitor_is_behind: blocks_remaining = (remote_count - next_block) if blocks_per_second > 0: time_remaining_seconds = blocks_remaining / blocks_per_second print("# {} blocks remain ({} seconds)".format(blocks_remaining, round(time_remaining_seconds,1))) else: print("# {} blocks remain (? seconds)".format(blocks_remaining)) (monitor_is_behind, next_block, remote_count, blocks_per_second) = mobilecoind.wait_for_monitor(monitor_id, max_blocks_to_sync=2000, timeout_seconds=20) print("# monitor has processed all {} blocks\n".format(remote_count)) balance_picoMOB = mobilecoind.get_balance(monitor_id, subaddress_index=args.subaddress).balance public_address = mobilecoind.get_public_address(monitor_id, subaddress_index=args.subaddress).public_address # print account information print("\n") print(" {:<18}{}".format("Master Key:", entropy_display)) print(" {:<18}{}".format("Subaddress Index:", args.subaddress)) print(" {:<18}{}".format("Address Code:", public_address.b58_code)) print(" {:<18}{}".format("Address URL:", "mob58://"+ public_address.b58_code)) print(" {:<18}{} pMOB".format("Balance:", balance_picoMOB)) print(" {:<18}{}".format(" ", mobilecoin.display_as_MOB(balance_picoMOB))) print("\n")
def allocate_MOB(mailchimp_member_record, amount_picoMOB): """generates a new master key, allocates funds, stores data at Mailchimp and triggers the welcome email""" new_user_email = mailchimp_member_record["email_address"] new_user_hash = mailchimp_member_record["id"] # Wait for mobilecoind to sync ledger block_count = wait_for_monitor(sender_monitor_id) # abort if sender's balance is too low sender_balance_picoMOB = mobilecoind.get_balance(sender_monitor_id).balance if sender_balance_picoMOB < (amount_picoMOB + mobilecoin.MINIMUM_FEE): print("# sender's balance is too low ({})... aborting!".format( mobilecoin.display_as_MOB(sender_balance_picoMOB))) sys.exit() # create and fund a new MobileCoin TestNet account recipient_entropy = mobilecoind.generate_entropy().entropy recipient_account_key = mobilecoind.get_account_key( recipient_entropy).account_key print("# generated entropy {} for email {}".format(recipient_entropy.hex(), new_user_email)) # no need to start the recipient from the origin block since we know we just created this account recipient_monitor_id = mobilecoind.add_monitor( recipient_account_key, first_block=block_count).monitor_id recipient_public_address = mobilecoind.get_public_address( recipient_monitor_id).public_address print("# adding monitor {} for {} (first block = {})".format( recipient_monitor_id.hex(), new_user_email, block_count)) # Construct and send the token allocation transaction tx_list = mobilecoind.get_unspent_tx_output_list( sender_monitor_id).output_list outlays = [{'value': amount_picoMOB, 'receiver': recipient_public_address}] tx_proposal = mobilecoind.generate_tx(sender_monitor_id, mobilecoin.DEFAULT_SUBADDRESS_INDEX, tx_list, outlays).tx_proposal sender_tx_receipt = mobilecoind.submit_tx(tx_proposal).sender_tx_receipt # Wait for the transaction to clear tx_status = mobilecoin.TxStatus.Unknown while tx_status == mobilecoin.TxStatus.Unknown: time.sleep(TX_RECEIPT_CHECK_INTERVAL_SECONDS) tx_status = mobilecoind.get_tx_status_as_sender( sender_tx_receipt).status print("# transaction status is {}".format( mobilecoin.parse_tx_status(tx_status))) if tx_status != mobilecoin.TxStatus.Verified: print("ERROR... Transaction failed with status {}".format(tx_status)) mobilecoind.remove_monitor(recipient_monitor_id) print("# removed monitor {} for {}".format(recipient_monitor_id.hex(), new_user_email)) return 0 # no email was sent # Check that balances are as expected wait_for_monitor(sender_monitor_id) sender_balance = mobilecoind.get_balance(sender_monitor_id).balance wait_for_monitor(recipient_monitor_id) recipient_balance = mobilecoind.get_balance(recipient_monitor_id).balance print( "# recipient balance = {} picoMOB ({}), sender balance = {} picoMOB ({})" .format(recipient_balance, mobilecoin.display_as_MOB(recipient_balance), sender_balance, mobilecoin.display_as_MOB(sender_balance))) # If the recipient's balance is not as expected, complain and do not trigger the email in Mailchimp if recipient_balance != amount_picoMOB: print( "ERROR... recipient balance is not correct! Entropy {} has only {}. Expected {}." .format(recipient_entropy.hex(), mobilecoin.display_as_MOB(recipient_balance), mobilecoin.display_as_MOB(amount_picoMOB))) email_sent = 0 else: # set the entropy value at MailChimp data = {"merge_fields": {"ENTROPY": recipient_entropy.hex()}} response = mailchimp.lists.members.update( list_id, subscriber_hash=new_user_hash, data=data) # adding "send_key_now" tag triggers the welcome email automation! data = { "tags": [{ "name": "has_entropy", "status": "active" }, { "name": "send_key_now", "status": "active" }] } mailchimp.lists.members.tags.update(list_id, subscriber_hash=new_user_hash, data=data) print("# setting welcome email trigger for {}!".format(new_user_email)) email_sent = 1 # remove recipient monitor mobilecoind.remove_monitor(recipient_monitor_id) print("# removed monitor {} for {}".format(recipient_monitor_id.hex(), new_user_email)) return email_sent
entropy_bytes).account_key monitor_id = mobilecoind.add_monitor(account_key).monitor_id (monitor_is_behind, next_block, remote_count, blocks_per_second) = mobilecoind.wait_for_monitor(monitor_id) if monitor_is_behind: print("#\n# waiting for the monitor {} to process {} blocks". format(monitor_id.hex(), remote_count - next_block)) while monitor_is_behind: blocks_remaining = (remote_count - next_block) if blocks_per_second > 0: time_remaining_seconds = blocks_remaining / blocks_per_second print("# {} blocks remain ({} seconds)".format( blocks_remaining, round(time_remaining_seconds, 1))) else: print("# {} blocks remain (? seconds)".format( blocks_remaining)) (monitor_is_behind, next_block, remote_count, blocks_per_second) = mobilecoind.wait_for_monitor( monitor_id, max_blocks_to_sync=10000, timeout_seconds=60) print("# monitor has processed all {} blocks\n#".format( remote_count)) balance_picoMOB = mobilecoind.get_balance(monitor_id).balance print("{}, {}, {}, {}".format( entropy, email, balance_picoMOB, mobilecoin.display_as_MOB(balance_picoMOB)))
# print(mailchimp.lists.all(get_all=True, fields="lists.name,lists.id")) list_id = '5f47419453' # The "MobileCoin" Audience # go through all the subscribers in chunks and find any who don't have an assigned entropy print("# * Processing all existing records") fields = "members.id,members.email_address,members.merge_fields,members.status" # important: no spaces! offset = 0 count = 200 # can be up to 1000 emails_sent = 0 while count > 0: members = mailchimp.lists.members.all(list_id, count=count, offset=offset, fields=fields)["members"] count = len(members) offset += count if count > 0: print("# processed {} records found at MailChimp".format(offset)) for member_record in members: if member_record["status"] == "subscribed" and not member_record[ "merge_fields"]["ENTROPY"]: emails_sent += allocate_MOB(member_record, args.value) if emails_sent > 0: print("# sent {} to each of {} new records found at MailChimp".format( mobilecoin.display_as_MOB(args.value), emails_sent)) else: print("# no new records found.") print("# * Finished processing all existing records\n")
print("# {} blocks remain (? seconds)".format( blocks_remaining)) (monitor_is_behind, next_block, remote_count, blocks_per_second ) = mobilecoind.wait_for_monitor(sender_monitor_id) print( "# monitor has processed all {} blocks\n#".format(local_count)) balance_picoMOB = mobilecoind.get_balance( sender_monitor_id, subaddress_index=args.sender_subaddress).balance # send as much as possible after accounting for the fee value_to_send_picoMOB = balance_picoMOB - mobilecoin.MINIMUM_FEE if value_to_send_picoMOB <= 0: print("\nSender's balance is too low to cover fee. ({} < {})\n". format(mobilecoin.display_as_MOB(balance_picoMOB), mobilecoin.display_as_MOB(mobilecoin.MINIMUM_FEE))) sys.exit(0) else: value_to_send_picoMOB = args.value # build and send the payment tx_list = mobilecoind.get_unspent_tx_output_list( sender_monitor_id, args.sender_subaddress).output_list receiver = mobilecoind.parse_address_code(recipient_address_code).receiver outlays = [{'value': value_to_send_picoMOB, 'receiver': receiver}] tx_proposal = mobilecoind.generate_tx(sender_monitor_id, args.sender_subaddress, tx_list, outlays).tx_proposal sender_tx_receipt = mobilecoind.submit_tx(tx_proposal).sender_tx_receipt
count = len(chunk_of_members) offset += count members.extend(chunk_of_members) print("# mailing list contains {} members.".format(len(members))) for member_record in members: if member_record["merge_fields"]["ENTROPY"]: entropy = member_record["merge_fields"]["ENTROPY"] email = member_record["email_address"] entropy_bytes = bytes.fromhex(entropy) account_key = mobilecoind.get_account_key(entropy_bytes).account_key monitor_id = mobilecoind.add_monitor(account_key).monitor_id (monitor_is_behind, next_block, remote_count, blocks_per_second) = mobilecoind.wait_for_monitor(monitor_id) if monitor_is_behind: print("#\n# waiting for the monitor {} to process {} blocks".format(monitor_id.hex(), remote_count - next_block)) while monitor_is_behind: blocks_remaining = (remote_count - next_block) if blocks_per_second > 0: time_remaining_seconds = blocks_remaining / blocks_per_second print("# {} blocks remain ({} seconds)".format(blocks_remaining, round(time_remaining_seconds, 1))) else: print("# {} blocks remain (? seconds)".format(blocks_remaining)) (monitor_is_behind, next_block, remote_count, blocks_per_second) = mobilecoind.wait_for_monitor(monitor_id, max_blocks_to_sync=10000, timeout_seconds=60) print("# monitor has processed all {} blocks\n#".format(remote_count)) balance_picoMOB = mobilecoind.get_balance(monitor_id).balance print("{}, {}, {}, {}".format(entropy, email, balance_picoMOB, mobilecoin.display_as_MOB(balance_picoMOB)))
def test_display_as_MOB(self): nMOB = 1e3 μMOB = 1e6 MOB = 1e12 kMOB = 1e15 MMOB = 1e18 test_pairs = [ # negative values (-9999.05 * kMOB, "-9999.05 kMOB"), (-1, "-0.001 nMOB"), # zero (0, "0.000 MOB"), # nano (0.001 * nMOB, "0.001 nMOB"), (0.012 * nMOB, "0.012 nMOB"), (0.123 * nMOB, "0.123 nMOB"), (0.500 * nMOB, "0.500 nMOB"), (0.999 * nMOB, "0.999 nMOB"), (0.9991 * nMOB, "0.999 nMOB"), (0.9995 * nMOB, "0.001 μMOB"), # micro (0.001 * μMOB, "0.001 μMOB"), (0.012 * μMOB, "0.012 μMOB"), (0.123 * μMOB, "0.123 μMOB"), (0.5 * μMOB, "0.500 μMOB"), (0.999 * μMOB, "0.999 μMOB"), (0.9991 * μMOB, "0.999 μMOB"), (0.9995 * μMOB, "0.000001 MOB"), (1 * μMOB, "0.000001 MOB"), (12 * μMOB, "0.000012 MOB"), (123 * μMOB, "0.000123 MOB"), (500 * μMOB, "0.000500 MOB"), # base precision 6 (0.000099 * MOB, "0.000099 MOB"), (0.000090 * MOB, "0.000090 MOB"), (0.0009991 * MOB, "0.000999 MOB"), (0.0009995 * MOB, "0.001 MOB"), # base precision 3 (0.0009999 * MOB, "0.001 MOB"), (0.0015 * MOB, "0.002 MOB"), (0.0030005 * MOB, "0.003 MOB"), (0.999 * MOB, "0.999 MOB"), (0.9991 * MOB, "0.999 MOB"), (0.9995 * MOB, "1.000 MOB"), (1 * MOB, "1.000 MOB"), (12 * MOB, "12.000 MOB"), (123 * MOB, "123.000 MOB"), (0.012 * MOB, "0.012 MOB"), (0.1 * MOB, "0.100 MOB"), (0.25 * MOB, "0.250 MOB"), (0.22342 * MOB, "0.223 MOB"), (1.2349 * MOB, "1.235 MOB"), (34.5 * MOB, "34.500 MOB"), (1234.234323 * MOB, "1234.234 MOB"), (9999.999 * MOB, "9999.999 MOB"), (9999.9991 * MOB, "9999.999 MOB"), (9999.9995 * MOB, "10.00 kMOB"), # kilo (9.9999994 * kMOB, "9999.999 MOB"), (9.9999995 * kMOB, "10.00 kMOB"), (12 * kMOB, "12.00 kMOB"), (123.02 * kMOB, "123.02 kMOB"), (500 * kMOB, "500.00 kMOB"), (9999.05 * kMOB, "9999.05 kMOB"), (9999.994 * kMOB, "9999.99 kMOB"), (9999.995 * kMOB, "10.00 MMOB"), #mega (9.999994 * MMOB, "9999.99 kMOB"), (9.999995 * MMOB, "10.00 MMOB"), (10 * MMOB, "10.00 MMOB"), (123.02 * MMOB, "123.02 MMOB"), (200.01 * MMOB, "200.01 MMOB"), (250 * MMOB, "250.00 MMOB"), (250.000_000_000_001 * MMOB, "overflow"), ] for (picoMOB, expected_str) in test_pairs: str = mobilecoin.display_as_MOB(picoMOB) print(str, expected_str) self.assertTrue(str == expected_str)
print("# {} blocks remain ({} seconds)".format(blocks_remaining, round(time_remaining_seconds, 1))) else: print("# {} blocks remain (? seconds)".format(blocks_remaining)) (monitor_is_behind, next_block, remote_count, blocks_per_second) = mobilecoind.wait_for_monitor(sender_monitor_id) print("# monitor has processed all {} blocks\n#".format(local_count)) balance_picoMOB = mobilecoind.get_balance(sender_monitor_id, subaddress_index=args.sender_subaddress).balance # send as much as possible after accounting for the fee value_to_send_picoMOB = balance_picoMOB - mobilecoin.MINIMUM_FEE if value_to_send_picoMOB <= 0: print( "\nSender's balance is too low to cover fee. ({} < {})\n" .format( mobilecoin.display_as_MOB(balance_picoMOB), mobilecoin.display_as_MOB(mobilecoin.MINIMUM_FEE) ) ) sys.exit(0) else: value_to_send_picoMOB = args.value # build and send the payment tx_list = mobilecoind.get_unspent_tx_output_list(sender_monitor_id, args.sender_subaddress).output_list receiver = mobilecoind.parse_address_code(recipient_address_code).receiver outlays = [{'value': value_to_send_picoMOB, 'receiver': receiver}] tx_proposal = mobilecoind.generate_tx(sender_monitor_id, args.sender_subaddress, tx_list, outlays).tx_proposal submit_response = mobilecoind.submit_tx(tx_proposal) # Wait for the transaction to clear