def test_import():
    m = mock_provider
    m.reset_mocks()

    keys = HDKey.from_path(master, "m/44'/0'/0'")
    m.hd_master_key = master

    m.set_num_used_accounts(0)
    m.set_txn_side_effect_for_hd_discovery()

    wallet = Two1Wallet.import_from_mnemonic(
        data_provider=m,
        mnemonic=master_seed,
        passphrase=passphrase,
        account_type="BIP44BitcoinMainnet")

    assert wallet._root_keys[1].to_b58check() == keys[1].to_b58check()
    assert wallet._root_keys[2].to_b58check() == keys[2].to_b58check()
    assert wallet._accounts[0].key.to_b58check() == keys[3].to_b58check()

    assert len(wallet._accounts) == 1

    # Now test where the first account has transactions
    m.reset_mocks()
    m.set_num_used_accounts(2)  # Set this to 2 so that we get the side effects
    m.set_num_used_addresses(account_index=0, n=10, change=0)
    m.set_num_used_addresses(account_index=0, n=20, change=1)

    m.set_txn_side_effect_for_hd_discovery()

    wallet = Two1Wallet.import_from_mnemonic(
        data_provider=m,
        mnemonic=master_seed,
        passphrase=passphrase,
        account_type="BIP44BitcoinMainnet")

    assert len(wallet._accounts) == 1
    assert wallet._accounts[0].has_txns()

    # Test where multiple accounts have transactions
    m.reset_mocks()
    m.set_num_used_accounts(5)
    for i in range(4):
        m.set_num_used_addresses(account_index=i, n=1, change=0)
        m.set_num_used_addresses(account_index=i, n=2, change=1)

    m.set_txn_side_effect_for_hd_discovery()

    wallet = Two1Wallet.import_from_mnemonic(
        data_provider=m,
        mnemonic=master_seed,
        passphrase=passphrase,
        account_type="BIP44BitcoinMainnet")

    assert len(wallet._accounts) == 4
    for i in range(4):
        assert wallet._accounts[i].has_txns()
Beispiel #2
0
def restore(ctx):
    """ Restore a wallet from a mnemonic

    \b
    If you accidently deleted your wallet file or the file
    became corrupted, use this command to restore your wallet. You
    must have your 12 word phrase (mnemonic) that was displayed
    when you created your wallet.
    """
    # Stop daemon if it's running.
    d = None
    try:
        d = get_daemonizer()
    except OSError as e:
        pass

    if d:
        try:
            d.stop()
        except exceptions.DaemonizerError as e:
            click.echo("ERROR: Couldn't stop daemon: %s" % e)
            ctx.exit(code=4)

    # Check to see if the current wallet path exists
    if os.path.exists(ctx.obj['wallet_path']):
        if click.confirm("Wallet file already exists and may have a balance. Do you want to delete it?"):
            os.remove(ctx.obj['wallet_path'])
        else:
            click.echo("Not continuing.")
            ctx.exit(code=4)

    # Ask for mnemonic
    mnemonic = click.prompt("Please enter the wallet's 12 word mnemonic").strip()

    # Sanity check the mnemonic
    def check_mnemonic(mnemonic):
        try:
            return Mnemonic(language='english').check(mnemonic)
        except ConfigurationError:
            return False
    if not check_mnemonic(mnemonic):
        click.echo("ERROR: Invalid mnemonic.")
        ctx.exit(code=5)

    # Try creating the wallet
    click.echo("\nRestoring...")
    wallet = Two1Wallet.import_from_mnemonic(
        data_provider=ctx.obj['data_provider'],
        mnemonic=mnemonic,
    )

    wallet.to_file(ctx.obj['wallet_path'])
    if Two1Wallet.check_wallet_file(ctx.obj['wallet_path']):
        click.echo("Wallet successfully restored. Run '21 login' to connect this wallet to your 21 account.")
    else:
        click.echo("Wallet not restored.")
        ctx.exit(code=6)
Beispiel #3
0
def test_import():
    m = mock_provider
    m.reset_mocks()

    keys = HDKey.from_path(master, "m/44'/0'/0'")
    m.hd_master_key = master

    m.set_num_used_accounts(0)
    m.set_txn_side_effect_for_hd_discovery()

    wallet = Two1Wallet.import_from_mnemonic(data_provider=m,
                                             mnemonic=master_seed,
                                             passphrase=passphrase,
                                             account_type="BIP44BitcoinMainnet")

    assert wallet._root_keys[1].to_b58check() == keys[1].to_b58check()
    assert wallet._root_keys[2].to_b58check() == keys[2].to_b58check()
    assert wallet._accounts[0].key.to_b58check() == keys[3].to_b58check()

    assert len(wallet._accounts) == 1

    # Now test where the first account has transactions
    m.reset_mocks()
    m.set_num_used_accounts(2)  # Set this to 2 so that we get the side effects
    m.set_num_used_addresses(account_index=0, n=10, change=0)
    m.set_num_used_addresses(account_index=0, n=20, change=1)

    m.set_txn_side_effect_for_hd_discovery()

    wallet = Two1Wallet.import_from_mnemonic(data_provider=m,
                                             mnemonic=master_seed,
                                             passphrase=passphrase,
                                             account_type="BIP44BitcoinMainnet")

    assert len(wallet._accounts) == 1
    assert wallet._accounts[0].has_txns()

    # Test where multiple accounts have transactions
    m.reset_mocks()
    m.set_num_used_accounts(5)
    for i in range(4):
        m.set_num_used_addresses(account_index=i, n=1, change=0)
        m.set_num_used_addresses(account_index=i, n=2, change=1)

    m.set_txn_side_effect_for_hd_discovery()

    wallet = Two1Wallet.import_from_mnemonic(data_provider=m,
                                             mnemonic=master_seed,
                                             passphrase=passphrase,
                                             account_type="BIP44BitcoinMainnet")

    assert len(wallet._accounts) == 4
    for i in range(4):
        assert wallet._accounts[i].has_txns()
Beispiel #4
0
def create(ctx, account_type, testnet):
    """ Creates a new wallet
    """
    # txn_data_provider and related params come from the
    # global context.
    passphrase = ""
    if ctx.obj['passphrase']:
        # Let's prompt for a passphrase
        conf = "a"
        i = 0
        while passphrase != conf and i < 3:
            passphrase = getpass.getpass("Enter desired passphrase: ")
            conf = getpass.getpass("Confirm passphrase: ")
            i += 1

        if passphrase != conf:
            ctx.fail("Passphrases don't match. Quitting.")

    options = {
        "account_type": account_type,
        "passphrase": passphrase,
        "data_provider": ctx.obj['data_provider'],
        "testnet": testnet,
        "wallet_path": ctx.obj['wallet_path']
    }

    logger.info("Creating wallet with options: %r" % options)
    created = Two1Wallet.configure(options)

    if created:
        # Make sure it opens
        logger.info("Wallet created.")
        try:
            wallet = Two1Wallet(params_or_file=ctx.obj['wallet_path'],
                                data_provider=ctx.obj['data_provider'],
                                passphrase=passphrase)

            click.echo("Wallet successfully created!")

            adder = " (and your passphrase) " if passphrase else " "
            click.echo(
                "Your wallet can be recovered using the following set of words (in that order)."
            )
            click.echo("Please store them%ssafely." % adder)
            click.echo("\n%s\n" % wallet._orig_params['master_seed'])
        except Exception as e:
            logger.debug("Error opening created wallet: %s" % e)
            click.echo("Wallet was not created properly.")
            ctx.exit(code=3)
    else:
        ctx.fail("Wallet was not created.")
Beispiel #5
0
def restore(ctx):
    """ Restore a wallet from a mnemonic

    \b
    If you accidently deleted your wallet file or the file
    became corrupted, use this command to restore your wallet. You
    must have your 12 word phrase (mnemonic) that was displayed
    when you created your wallet.
    """
    # Check to see if the current wallet path exists
    if os.path.exists(ctx.obj['wallet_path']):
        if click.confirm(
                "Wallet file already exists and may have a balance. Do you want to delete it?"
        ):
            os.remove(ctx.obj['wallet_path'])
        else:
            click.echo("Not continuing.")
            ctx.exit(code=4)

    # Ask for mnemonic
    mnemonic = click.prompt(
        "Please enter the wallet's 12 word mnemonic").strip()

    # Sanity check the mnemonic
    def check_mnemonic(mnemonic):
        try:
            return Mnemonic(language='english').check(mnemonic)
        except ConfigurationError:
            return False

    if not check_mnemonic(mnemonic):
        click.echo("ERROR: Invalid mnemonic.")
        ctx.exit(code=5)

    # Try creating the wallet
    click.echo("\nRestoring...")
    wallet = Two1Wallet.import_from_mnemonic(
        data_provider=ctx.obj['data_provider'],
        mnemonic=mnemonic,
    )

    wallet.to_file(ctx.obj['wallet_path'])
    if Two1Wallet.check_wallet_file(ctx.obj['wallet_path']):
        click.echo(
            "Wallet successfully restored. Run '21 login' to connect this wallet to your 21 account."
        )
    else:
        click.echo("Wallet not restored.")
        ctx.exit(code=6)
def login_21():
    """ Restore wallet to disk and log in to 21.
    """
    mnemonic = os.environ["TWO1_WALLET_MNEMONIC"]

    provider = TwentyOneProvider()
    wallet = Two1Wallet.import_from_mnemonic(provider, mnemonic)

    if not os.path.exists(os.path.dirname(Two1Wallet.DEFAULT_WALLET_PATH)):
        os.makedirs(os.path.dirname(Two1Wallet.DEFAULT_WALLET_PATH))
    wallet.to_file(Two1Wallet.DEFAULT_WALLET_PATH)

    # login
    config = Config()
    machine_auth = machine_auth_wallet.MachineAuthWallet(wallet)

    username = os.environ["TWO1_USERNAME"]
    password = os.environ["TWO1_PASSWORD"]

    rest_client = _rest_client.TwentyOneRestClient(two1.TWO1_HOST,
                                                   machine_auth, username)

    machine_auth_pubkey_b64 = base64.b64encode(
        machine_auth.public_key.compressed_bytes).decode()
    payout_address = machine_auth.wallet.current_address

    rest_client.login(payout_address=payout_address, password=password)

    config.set("username", username)
    config.set("mining_auth_pubkey", machine_auth_pubkey_b64)
    config.save()
Beispiel #7
0
def login_21():
    """ Restore wallet to disk and log in to 21.
    """
    mnemonic = os.environ["TWO1_WALLET_MNEMONIC"]

    provider = TwentyOneProvider()
    wallet = Two1Wallet.import_from_mnemonic(provider, mnemonic)

    if not os.path.exists(os.path.dirname(Two1Wallet.DEFAULT_WALLET_PATH)):
        os.makedirs(os.path.dirname(Two1Wallet.DEFAULT_WALLET_PATH))
    wallet.to_file(Two1Wallet.DEFAULT_WALLET_PATH)

    # login
    config = Config()
    machine_auth = machine_auth_wallet.MachineAuthWallet(wallet)

    username = os.environ["TWO1_USERNAME"]
    password = os.environ["TWO1_PASSWORD"]

    rest_client = _rest_client.TwentyOneRestClient(two1.TWO1_HOST, machine_auth, username)

    machine_auth_pubkey_b64 = base64.b64encode(machine_auth.public_key.compressed_bytes).decode()
    payout_address = machine_auth.wallet.current_address

    rest_client.login(payout_address=payout_address, password=password)

    config.set("username", username)
    config.set("mining_auth_pubkey", machine_auth_pubkey_b64)
    config.save()
Beispiel #8
0
def test_encrypt_decrypt():
    mkey_enc, mseed_enc = Two1Wallet.encrypt(master_key=config['master_key'],
                                             master_seed=config['master_seed'],
                                             passphrase=passphrase,
                                             key_salt=enc_key_salt)

    mkey, mseed = Two1Wallet.decrypt(master_key_enc=mkey_enc,
                                     master_seed_enc=mseed_enc,
                                     passphrase=passphrase,
                                     key_salt=enc_key_salt)

    assert mkey == config['master_key']
    assert mseed == config['master_seed']

    for i in range(1000):
        s = ''.join(random.choice(string.ascii_letters + string.digits)
                    for _ in range(random.randint(1, 200)))
        key = rand_bytes(Two1Wallet.AES_BLOCK_SIZE)

        enc = Two1Wallet._encrypt_str(s, key)
        dec = Two1Wallet._decrypt_str(enc, key)
        assert dec == s
def test_encrypt_decrypt():
    mkey_enc, mseed_enc = Two1Wallet.encrypt(master_key=config['master_key'],
                                             master_seed=config['master_seed'],
                                             passphrase=passphrase,
                                             key_salt=enc_key_salt)

    mkey, mseed = Two1Wallet.decrypt(master_key_enc=mkey_enc,
                                     master_seed_enc=mseed_enc,
                                     passphrase=passphrase,
                                     key_salt=enc_key_salt)

    assert mkey == config['master_key']
    assert mseed == config['master_seed']

    for i in range(1000):
        s = ''.join(
            random.choice(string.ascii_letters + string.digits)
            for _ in range(random.randint(1, 200)))
        key = rand_bytes(Two1Wallet.AES_BLOCK_SIZE)

        enc = Two1Wallet._encrypt_str(s, key)
        dec = Two1Wallet._decrypt_str(enc, key)
        assert dec == s
Beispiel #10
0
def startdaemon(ctx):
    """ Starts the daemon
    """
    # Check to sere if we're in a venv and don't do anything if we are
    if os.environ.get("VIRTUAL_ENV"):
        click.echo(
            "Not starting daemon while inside a virtualenv. It can be manually "
            + "started by doing 'walletd' and backgrounding the process.")
        return

    # Check if the wallet path exists
    if not Two1Wallet.check_wallet_file(ctx.obj['wallet_path']):
        click.echo("ERROR: Wallet does not exist! Not starting daemon.")
        ctx.exit(code=7)

    try:
        d = get_daemonizer()
    except OSError as e:
        logger.debug(str(e))
        click.echo("Error: %s" % e)
        return

    if d.started():
        click.echo("walletd already running.")
        return

    if not d.installed():
        if isinstance(ctx.obj['data_provider'], TwentyOneProvider):
            dpo = dict(provider='twentyone')

        try:
            d.install(dpo)
        except exceptions.DaemonizerError as e:
            logger.debug(str(e))
            click.echo("Error: %s" % e)
            return

    msg = ""
    try:
        if d.start():
            msg = "walletd successfully started."
        else:
            msg = "walletd not started."
    except exceptions.DaemonizerError as e:
        msg = "Error: %s" % e

    logger.debug(msg)
    click.echo(msg)
Beispiel #11
0
def startdaemon(ctx):
    """ Starts the daemon
    """
    # Check to sere if we're in a venv and don't do anything if we are
    if os.environ.get("VIRTUAL_ENV"):
        click.echo("Not starting daemon while inside a virtualenv. It can be manually " +
                   "started by doing 'walletd' and backgrounding the process.")
        return

    # Check if the wallet path exists
    if not Two1Wallet.check_wallet_file(ctx.obj['wallet_path']):
        click.echo("ERROR: Wallet does not exist! Not starting daemon.")
        ctx.exit(code=7)

    try:
        d = get_daemonizer()
    except OSError as e:
        logger.debug(str(e))
        click.echo("Error: %s" % e)
        return

    if d.started():
        click.echo("walletd already running.")
        return

    if not d.installed():
        if isinstance(ctx.obj['data_provider'], TwentyOneProvider):
            dpo = dict(provider='twentyone')

        try:
            d.install(dpo)
        except exceptions.DaemonizerError as e:
            logger.debug(str(e))
            click.echo("Error: %s" % e)
            return

    msg = ""
    try:
        if d.start():
            msg = "walletd successfully started."
        else:
            msg = "walletd not started."
    except exceptions.DaemonizerError as e:
        msg = "Error: %s" % e

    logger.debug(msg)
    click.echo(msg)
Beispiel #12
0
def create(ctx, account_type, testnet):
    """ Creates a new wallet
    """
    # txn_data_provider and related params come from the
    # global context.
    passphrase = ""
    if ctx.obj['passphrase']:
        # Let's prompt for a passphrase
        conf = "a"
        i = 0
        while passphrase != conf and i < 3:
            passphrase = getpass.getpass("Enter desired passphrase: ")
            conf = getpass.getpass("Confirm passphrase: ")
            i += 1

        if passphrase != conf:
            ctx.fail("Passphrases don't match. Quitting.")

    options = {"account_type": account_type,
               "passphrase": passphrase,
               "data_provider": ctx.obj['data_provider'],
               "testnet": testnet,
               "wallet_path": ctx.obj['wallet_path']}

    logger.info("Creating wallet with options: %r" % options)
    created = Two1Wallet.configure(options)

    if created:
        # Make sure it opens
        logger.info("Wallet created.")
        try:
            wallet = Two1Wallet(params_or_file=ctx.obj['wallet_path'],
                                data_provider=ctx.obj['data_provider'],
                                passphrase=passphrase)

            click.echo("Wallet successfully created!")

            adder = " (and your passphrase) " if passphrase else " "
            click.echo("Your wallet can be recovered using the following set of words (in that order).")
            click.echo("Please store them%ssafely." % adder)
            click.echo("\n%s\n" % wallet._orig_params['master_seed'])
        except Exception as e:
            logger.debug("Error opening created wallet: %s" % e)
            click.echo("Wallet was not created properly.")
            ctx.exit(code=3)
    else:
        ctx.fail("Wallet was not created.")
def test_create():
    # Here we just check to see that the config was created properly,
    # there is only 1 account associated w/the wallet and that there
    # are no txns, etc.

    mock_provider.set_txn_side_effect_for_hd_discovery()

    wallet, _ = Two1Wallet.create(data_provider=mock_provider,
                                  passphrase=passphrase)

    assert len(wallet._accounts) == 1
    assert wallet._accounts[0].name == "default"
    assert wallet._accounts[0].index == 0x80000000

    wallet_config = wallet.to_dict()
    assert wallet_config['account_map'] == {"default": 0}
    assert wallet_config['accounts'][0]['last_payout_index'] == -1
    assert wallet_config['accounts'][0]['last_change_index'] == -1
Beispiel #14
0
def test_create():
    # Here we just check to see that the config was created properly,
    # there is only 1 account associated w/the wallet and that there
    # are no txns, etc.

    mock_provider.set_txn_side_effect_for_hd_discovery()

    wallet, _ = Two1Wallet.create(data_provider=mock_provider,
                                  passphrase=passphrase)

    assert len(wallet._accounts) == 1
    assert wallet._accounts[0].name == "default"
    assert wallet._accounts[0].index == 0x80000000

    wallet_config = wallet.to_dict()
    assert wallet_config['account_map'] == {"default": 0}
    assert wallet_config['accounts'][0]['last_payout_index'] == -1
    assert wallet_config['accounts'][0]['last_change_index'] == -1
Beispiel #15
0
def load_wallet(wallet_path, data_provider, passphrase):
    """ Loads a wallet.

    Args:
        wallet_path (str): The path to the wallet to be loaded.
        data_provider (BaseProvider): A blockchain data provider object.
        passphrase (str): Passphrase to use to unlock the wallet if the
            wallet requires unlocking.
    """
    global wallet

    try:
        logger.debug("In load_wallet...")
        logger.debug("\twallet_path = %s" % wallet_path)
        logger.debug("\tdata_provider = %r" % data_provider)
        logger.debug("\tpassphrase = %r" % bool(passphrase))
        wallet['obj'] = Two1Wallet(params_or_file=wallet_path,
                                   data_provider=data_provider,
                                   passphrase=passphrase)
        wallet['locked'] = False
    except Exception as e:
        raise WalletNotLoadedError("Wallet loading failed: %s" % e)
Beispiel #16
0
from two1.bitcoin.crypto import HDKey, HDPrivateKey
from two1.bitcoin.utils import bytes_to_str
from two1.bitcoin.utils import rand_bytes
from two1.blockchain.mock_provider import MockProvider
from two1.wallet import exceptions
from two1.wallet.two1_wallet import Two1Wallet

enc_key_salt = b'\xaa\xbb\xcc\xdd'
passphrase = "test_wallet"
passphrase_hash = PBKDF2.crypt(passphrase)

master_key = "xprv9s21ZrQH143K2dUcTctuNw8oV8e7gi4ZbHFGAnyGJtWwmKbKTbLGtx48DQGzioGDdhVn8zFhJe8hbDdfDnK19ykxjwXLzd6EpxnTqi4zQGN"  # nopep8
master_seed = "tuna object element cancel hard nose faculty noble swear net subway offer"

mkey_enc, mseed_enc = Two1Wallet.encrypt(master_key=master_key,
                                         master_seed=master_seed,
                                         passphrase=passphrase,
                                         key_salt=enc_key_salt)

config = {'master_key': mkey_enc,
          'master_seed': mseed_enc,
          'locked': True,
          'passphrase_hash': passphrase_hash,
          'key_salt': bytes_to_str(enc_key_salt),
          'account_type': "BIP44BitcoinMainnet",
          'accounts': [{'public_key': "xpub6CNX3TRAXGpoV1a3ai3Hs9R85t63V3k6BGsTaxZZMJJ4DL6kRY8riYA1r6hxyeuxgeb33FfBgrJrV6wxv6VXEVHAfPGJNw8ZzbEJHgsbmpz",  # nopep8
                        'last_payout_index': 2,
                        'last_change_index': 1}],
          'account_map': {'default': 0}}

master = HDPrivateKey.master_key_from_mnemonic(master_seed, passphrase)
mock_provider = MockProvider("BIP44BitcoinMainnet", master)
Beispiel #17
0
def main(ctx, wallet_path, blockchain_data_provider,
         insight_url, insight_api_path,
         data_update_interval, debug):
    """ Two1 Wallet daemon
    """
    global DEF_WALLET_UPDATE_INTERVAL

    wp = Path(wallet_path)
    # Initialize some logging handlers
    ch = logging.handlers.TimedRotatingFileHandler(wp.dirname().joinpath("walletd.log"),
                                                   when='midnight',
                                                   backupCount=5)
    ch_formatter = logging.Formatter(
        '%(asctime)s %(levelname)s %(name)-8s: %(message)s')
    ch.setFormatter(ch_formatter)
    ch.setLevel(logging.DEBUG if debug else logging.INFO)
    logging.getLogger().addHandler(ch)

    console = logging.StreamHandler()
    console.setLevel(logging.CRITICAL)
    logging.getLogger().addHandler(console)

    logging.getLogger().setLevel(logging.DEBUG)

    global wallet

    wallet['path'] = wallet_path
    if not Two1Wallet.check_wallet_file(wallet['path']):
        logger.critical("Wallet file does not exist or have the right parameters.")
        sys.exit(-1)

    wallet['data_provider'] = ctx.obj['data_provider']
    if data_update_interval is not None:
        DEF_WALLET_UPDATE_INTERVAL = data_update_interval
        wallet['update_info']['interval'] = data_update_interval

    logger.info("Starting daemon for wallet %s" % wallet_path)
    logger.info("Blockchain data provider: %s" %
                ctx.obj['data_provider'].__class__.__name__)
    logger.info("Update interval: %ds" % data_update_interval)

    # Check whether the wallet is locked
    if Two1Wallet.is_locked(wallet_path):
        wallet['locked'] = True
        logger.info("Wallet is locked.")
    else:
        logger.info("Wallet unlocked. Loading ...")
        try:
            load_wallet(wallet_path=wallet_path,
                        data_provider=ctx.obj['data_provider'],
                        passphrase="")
            logger.info("... loading complete.")
        except WalletNotLoadedError as e:
            logger.error(str(e))
            logger.info("Terminating.")
            sys.exit(-1)

    create_daemon_methods()

    # Setup a signal handler
    signal.signal(signal.SIGINT, sig_handler)
    signal.signal(signal.SIGTERM, sig_handler)
    server_thread = threading.Thread(target=rpc_server.serve_forever,
                                     daemon=True)
    update_thread = threading.Thread(target=data_updater,
                                     daemon=True)
    server_thread.start()
    update_thread.start()
    logger.info("Daemon started.")
    server_thread.join()

    rpc_server.server_close()

    try:
        _check_wallet_loaded()
        wallet['obj'].sync_wallet_file(force_cache_write=True)
    except:
        pass

    sys.exit(0)
Beispiel #18
0
import random
from two1.blockchain.twentyone_provider import TwentyOneProvider
from two1.wallet.two1_wallet import Two1Wallet

mnemonics = ['absent paddle capable spell bag reflect rally there swear swallow cook rubber',
             'stairs art mirror spoon clap talk exclude tuna absurd exact grape relief',
             'poem into dune liar already rain swear thunder spread kangaroo monster wise',
             'business lyrics news image duty stone clerk salad harvest shallow follow evoke',
             'another student leg ladder jeans hello cluster type network wrist before sense']

cp = TwentyOneProvider()

# Create wallet objects
wallets = [Two1Wallet.import_from_mnemonic(data_provider=cp,
                                           mnemonic=m,
                                           account_type='BIP32')
           for m in mnemonics]

max_balance_index = -1
max_balance = 0
for i, w in enumerate(wallets):
    balance = w.balances

    if balance['confirmed'] > max_balance:
        max_balance = balance['confirmed']
        max_balance_index = i

    print("\nWallet %d:" % i)
    print("----------")
    print("Num accounts: %d" % (len(w._accounts)))
Beispiel #19
0
def main(ctx, wallet_path, passphrase, blockchain_data_provider, insight_url,
         insight_api_path, debug):
    """ Command-line Interface for the Two1 Wallet
    """
    if wallet_path is None:
        try:
            config = two1_config.Config(config_file)
            wallet_path = config.wallet_path
        except two1exceptions.FileDecodeError as e:
            raise click.ClickException(
                uxstring.UxString.Error.file_decode.format((str(e))))

    wp = Path(wallet_path)

    # Initialize some logging handlers
    ch = logging.StreamHandler()
    ch_formatter = logging.Formatter('%(levelname)s: %(message)s')
    ch.setFormatter(ch_formatter)

    if not os.path.exists(wp.dirname()):
        os.makedirs(wp.dirname())
    fh = logging.handlers.TimedRotatingFileHandler(
        wp.dirname().joinpath("wallet_cli.log"),
        when='midnight',
        backupCount=5)
    fh_formatter = logging.Formatter('%(asctime)s %(levelname)s: %(message)s')
    fh.setFormatter(fh_formatter)

    logger.addHandler(ch)
    logger.addHandler(fh)

    fh.setLevel(logging.DEBUG if debug else logging.INFO)
    ch.setLevel(logging.DEBUG if debug else logging.WARNING)
    logger.setLevel(logging.DEBUG if debug else logging.INFO)

    logger.info("Wallet client started.")

    if ctx.obj is None:
        ctx.obj = {}

    ctx.obj['wallet_path'] = wallet_path
    ctx.obj['passphrase'] = passphrase

    if ctx.invoked_subcommand not in ['create', 'restore']:
        # Check that the wallet path exists
        if not Two1Wallet.check_wallet_file(ctx.obj['wallet_path']):
            click.echo("ERROR: Wallet file does not exist or is corrupt.")
            ctx.exit(code=7)

        p = get_passphrase() if passphrase else ''

        try:
            logger.info("Loading wallet %s ..." % (wp))
            ctx.obj['wallet'] = Wallet(wallet_path=wallet_path,
                                       data_provider=ctx.obj['data_provider'],
                                       passphrase=p)
            logger.info("... loading complete.")
        except exceptions.PassphraseError as e:
            click.echo(str(e))
            ctx.exit(code=1)
        except (TypeError, ValueError) as e:
            logger.error("Internal wallet error. Please report this as a bug.")
            logger.debug("".join(traceback.format_tb(e.__traceback__)))
            ctx.exit(code=2)

        def _on_close():
            try:
                ctx.obj['wallet'].sync_wallet_file()
            except:
                pass

        ctx.call_on_close(_on_close)
Beispiel #20
0
#!/usr/bin/env python3

from two1.wallet.two1_wallet import Two1Wallet
from two1.blockchain.twentyone_provider import TwentyOneProvider
from two1.bitcoin import utils
from two1.bitcoin import Script
from two1.bitcoin import Transaction, TransactionInput, TransactionOutput

# Create application objects

wallet = Two1Wallet(Two1Wallet.DEFAULT_WALLET_PATH, TwentyOneProvider())


def write_ew_message(msg):
    """Write a message to the blockchain."""
    print("write_ew_message({})" % msg)

    # Create a bitcoin script object with our message
    if len(msg) > 72:
        raise Exception('Message is too long and may not be accepted.')
    msg = "EW " + msg
    message_script = Script('OP_RETURN 0x{}'.format(utils.bytes_to_str(msg.encode())))

    # Define the fee we're willing to pay for the tx
    tx_fee = 11000

    # Get the first UTXO from our set that can cover the fee
    utxo = None
    for utxo_addr, utxos in wallet.get_utxos().items():
        for u in utxos:
            if u.value > tx_fee:
from two1.bitcoin.crypto import HDKey, HDPrivateKey
from two1.bitcoin.utils import bytes_to_str
from two1.bitcoin.utils import rand_bytes
from two1.blockchain.mock_provider import MockProvider
from two1.wallet import exceptions
from two1.wallet.two1_wallet import Two1Wallet

enc_key_salt = b'\xaa\xbb\xcc\xdd'
passphrase = "test_wallet"
passphrase_hash = PBKDF2.crypt(passphrase)

master_key = "xprv9s21ZrQH143K2dUcTctuNw8oV8e7gi4ZbHFGAnyGJtWwmKbKTbLGtx48DQGzioGDdhVn8zFhJe8hbDdfDnK19ykxjwXLzd6EpxnTqi4zQGN"  # nopep8
master_seed = "tuna object element cancel hard nose faculty noble swear net subway offer"

mkey_enc, mseed_enc = Two1Wallet.encrypt(master_key=master_key,
                                         master_seed=master_seed,
                                         passphrase=passphrase,
                                         key_salt=enc_key_salt)

config = {
    'master_key':
    mkey_enc,
    'master_seed':
    mseed_enc,
    'locked':
    True,
    'passphrase_hash':
    passphrase_hash,
    'key_salt':
    bytes_to_str(enc_key_salt),
    'account_type':
    "BIP44BitcoinMainnet",
def test_rest():
    m = mock_provider
    m.hd_master_key = master
    m.reset_mocks()

    m.set_num_used_accounts(1)
    m.set_num_used_addresses(account_index=0, n=1, change=0)
    m.set_num_used_addresses(account_index=0, n=2, change=1)

    m.set_txn_side_effect_for_hd_discovery()

    wallet = Two1Wallet(params_or_file=config,
                        data_provider=m,
                        passphrase=passphrase)

    # First 5 internal addresses of account 0
    # These can be gotten from https://dcpos.github.io/bip39/
    ext_addrs = [
        "1Kv1QLXekeE42rKhvZ41kHS1auE7R3t21o",
        "1CYhVFaBwmTQRQwdyLc4rq9HwaxdqtQ68G",
        "18KCKKB5MGs4Rqu4t8jL9Bkt9SAp7NpUvm",
        "1FqUrpUpqWfHoPVga4uMKYCPHHoApvNiPa",
        "12zb1hJP5WEHCSKz5LyoPM9iaCwXtTthRc"
    ]

    int_addrs = [
        "1Hiv6LroFmqcaVV9rhY6eNUjnFQh4y6kL7",
        "1GTUuNbgk4sv7LPQd2WqSP9PiinzeuBmay",
        "14fpkEZZ6QP3QEcQnfSjH7adkC2RsMuiZw",
        "1LPNyqqX6RU5b4oPumePR72tFfwiNUho4s",
        "1FqvNKJb8au82PhtGP8D1odXWVC1Ae4jN9"
    ]

    bad_addrs = [
        "1CEDwjjtYjCQUoRZQW9RUXHH5Ao7PWYKf",
        "1CbHFUNsyCzZSDu7hYae7HHqgzMjBfqoP9"
    ]

    paths = wallet.find_addresses(int_addrs + ext_addrs + bad_addrs)

    assert len(paths.keys()) == 10

    for i in range(5):
        # Hardened account key derivation, thus 0x80000000
        assert paths[ext_addrs[i]] == (0x80000000, 0, i)
        assert paths[int_addrs[i]] == (0x80000000, 1, i)

        # Check address belongs
        assert wallet.address_belongs(ext_addrs[i]) == "m/44'/0'/0'/0/%d" % i
        assert wallet.address_belongs(int_addrs[i]) == "m/44'/0'/0'/1/%d" % i

    for b in bad_addrs:
        assert b not in paths
        assert wallet.address_belongs(b) is None

    # Check that there's an account name
    assert wallet.get_account_name(0) == "default"

    # Check the balance
    assert wallet.balances == {'confirmed': 100000, 'total': 200000}

    # Check that we can get a new payout address
    ext_addr = wallet.get_payout_address("default")
    assert ext_addr == ext_addrs[1]
    assert wallet.accounts[0].last_indices[0] == 0

    # Check the balance again - should be the same
    m.set_num_used_addresses(0, 1, 0)
    assert wallet.balances == {'confirmed': 100000, 'total': 200000}

    # Try sending below the dust limit
    with pytest.raises(ValueError):
        wallet.send_to(address="14ocdLGpBp7Yv3gsPDszishSJUv3cpLqUM",
                       amount=544)

    # Try sending a non-integer amount (mistaken user tries to send in btc
    # instead of satoshi)
    with pytest.raises(exceptions.SatoshiUnitsError):
        wallet.send_to(address="14ocdLGpBp7Yv3gsPDszishSJUv3cpLqUM",
                       amount=0.0001)

    # Try sending more than we have and make sure it raises an exception
    with pytest.raises(exceptions.WalletBalanceError):
        wallet.send_to(address="14ocdLGpBp7Yv3gsPDszishSJUv3cpLqUM",
                       amount=10000000)

    # Should still fail when using unconfirmed if amount is greater
    # than unconfirmed balance
    with pytest.raises(exceptions.WalletBalanceError):
        wallet.send_to(address="14ocdLGpBp7Yv3gsPDszishSJUv3cpLqUM",
                       use_unconfirmed=True,
                       amount=10000000)

    # Should fail when not using unconfirmed txns and
    # confirmed < amount < unconfirmed.
    with pytest.raises(exceptions.WalletBalanceError):
        wallet.send_to(address="14ocdLGpBp7Yv3gsPDszishSJUv3cpLqUM",
                       use_unconfirmed=False,
                       amount=150000)

    # Should get past checking balance but raise a NotImplementedError
    with pytest.raises(NotImplementedError):
        wallet.send_to(address="14ocdLGpBp7Yv3gsPDszishSJUv3cpLqUM",
                       use_unconfirmed=False,
                       amount=7700)

    # Should get past checking balance but raise a signing error
    with pytest.raises(NotImplementedError):
        wallet.send_to(address="14ocdLGpBp7Yv3gsPDszishSJUv3cpLqUM",
                       use_unconfirmed=True,
                       amount=12581)

    # test number of addresses in spread_utxos
    with pytest.raises(ValueError):
        wallet.spread_utxos(threshold=500000, num_addresses=0, accounts=[])
    with pytest.raises(ValueError):
        wallet.spread_utxos(threshold=500000, num_addresses=101, accounts=[])

    # test units for spread_utxos
    with pytest.raises(exceptions.SatoshiUnitsError):
        wallet.spread_utxos(threshold=0.0001, num_addresses=1, accounts=[])

    # Finally check storing to a file
    params = {}
    with tempfile.NamedTemporaryFile(delete=True) as tf:
        wallet.to_file(tf)

        # Read it back
        tf.seek(0, 0)
        params = json.loads(tf.read().decode('utf-8'))

        # Check that the params match expected
        assert params['master_key'] == config['master_key']
        assert params['master_seed'] == config['master_seed']
        assert params['locked']
        assert params['key_salt'] == bytes_to_str(enc_key_salt)
        assert params['passphrase_hash'] == passphrase_hash
        assert params['account_type'] == "BIP44BitcoinMainnet"
        assert params['account_map']['default'] == 0
        assert len(params['accounts']) == 1
        assert params['accounts'][0]['last_payout_index'] == 0
        assert params['accounts'][0]['last_change_index'] == 1
        assert params['accounts'][0]['public_key'] == config['accounts'][0][
            'public_key']

        # Now create the wallet from the file
        with pytest.raises(exceptions.PassphraseError):
            w2 = Two1Wallet(params_or_file=tf.name,
                            data_provider=m,
                            passphrase='wrong_pass')

        # Now do with the correct passphrase
        m.set_txn_side_effect_for_hd_discovery()
        w2 = Two1Wallet(params_or_file=tf.name,
                        data_provider=m,
                        passphrase=passphrase)

        assert len(w2.accounts) == 1
        assert not w2._testnet

        acct = w2.accounts[0]
        assert acct.last_indices[0] == 0
        assert acct.last_indices[1] == 1
Beispiel #23
0
def main(ctx, wallet_path, blockchain_data_provider,
         insight_url, insight_api_path,
         data_update_interval, debug):
    """ Two1 Wallet daemon
    """
    global DEF_WALLET_UPDATE_INTERVAL

    wp = Path(wallet_path)
    # Initialize some logging handlers
    ch = logging.handlers.TimedRotatingFileHandler(wp.dirname().joinpath("walletd.log"),
                                                   when='midnight',
                                                   backupCount=5)
    ch_formatter = logging.Formatter(
        '%(asctime)s %(levelname)s %(name)-8s: %(message)s')
    ch.setFormatter(ch_formatter)
    ch.setLevel(logging.DEBUG if debug else logging.INFO)
    logging.getLogger().addHandler(ch)

    console = logging.StreamHandler()
    console.setLevel(logging.CRITICAL)
    logging.getLogger().addHandler(console)

    logging.getLogger().setLevel(logging.DEBUG)

    global wallet

    wallet['path'] = wallet_path
    if not Two1Wallet.check_wallet_file(wallet['path']):
        logger.critical("Wallet file does not exist or have the right parameters.")
        sys.exit(-1)

    wallet['data_provider'] = ctx.obj['data_provider']
    if data_update_interval is not None:
        DEF_WALLET_UPDATE_INTERVAL = data_update_interval
        wallet['update_info']['interval'] = data_update_interval

    logger.info("Starting daemon for wallet %s" % wallet_path)
    logger.info("Blockchain data provider: %s" %
                ctx.obj['data_provider'].__class__.__name__)
    logger.info("Update interval: %ds" % data_update_interval)

    # Check whether the wallet is locked
    if Two1Wallet.is_locked(wallet_path):
        wallet['locked'] = True
        logger.info("Wallet is locked.")
    else:
        logger.info("Wallet unlocked. Loading ...")
        try:
            load_wallet(wallet_path=wallet_path,
                        data_provider=ctx.obj['data_provider'],
                        passphrase="")
            logger.info("... loading complete.")
        except WalletNotLoadedError as e:
            logger.error(str(e))
            logger.info("Terminating.")
            sys.exit(-1)

    create_daemon_methods()

    # Setup a signal handler
    signal.signal(signal.SIGINT, sig_handler)
    signal.signal(signal.SIGTERM, sig_handler)
    server_thread = threading.Thread(target=rpc_server.serve_forever,
                                     daemon=True)
    update_thread = threading.Thread(target=data_updater,
                                     daemon=True)
    server_thread.start()
    update_thread.start()
    logger.info("Daemon started.")
    server_thread.join()

    rpc_server.server_close()

    try:
        _check_wallet_loaded()
        wallet['obj'].sync_wallet_file(force_cache_write=True)
    except:
        pass

    sys.exit(0)
Beispiel #24
0
def main(ctx, wallet_path, passphrase,
         blockchain_data_provider,
         insight_url, insight_api_path,
         debug):
    """ Command-line Interface for the Two1 Wallet
    """
    if wallet_path is None:
        try:
            config = two1_config.Config(config_file)
            wallet_path = config.wallet_path
        except two1exceptions.FileDecodeError as e:
            raise click.ClickException(uxstring.UxString.Error.file_decode.format((str(e))))

    wp = Path(wallet_path)

    # Initialize some logging handlers
    ch = logging.StreamHandler()
    ch_formatter = logging.Formatter(
        '%(levelname)s: %(message)s')
    ch.setFormatter(ch_formatter)

    if not os.path.exists(wp.dirname()):
        os.makedirs(wp.dirname())
    fh = logging.handlers.TimedRotatingFileHandler(wp.dirname().joinpath("wallet_cli.log"),
                                                   when='midnight',
                                                   backupCount=5)
    fh_formatter = logging.Formatter(
        '%(asctime)s %(levelname)s: %(message)s')
    fh.setFormatter(fh_formatter)

    logger.addHandler(ch)
    logger.addHandler(fh)

    fh.setLevel(logging.DEBUG if debug else logging.INFO)
    ch.setLevel(logging.DEBUG if debug else logging.WARNING)
    logger.setLevel(logging.DEBUG if debug else logging.INFO)

    logger.info("Wallet client started.")

    if ctx.obj is None:
        ctx.obj = {}

    ctx.obj['wallet_path'] = wallet_path
    ctx.obj['passphrase'] = passphrase

    if ctx.invoked_subcommand not in ['create', 'restore',
                                      'startdaemon', 'stopdaemon',
                                      'uninstalldaemon']:
        # Check that the wallet path exists
        if not Two1Wallet.check_wallet_file(ctx.obj['wallet_path']):
            click.echo("ERROR: Wallet file does not exist or is corrupt.")
            ctx.exit(code=7)

        p = get_passphrase() if passphrase else ''

        try:
            logger.info("Loading wallet %s ..." % (wp))
            ctx.obj['wallet'] = Wallet(wallet_path=wallet_path,
                                       data_provider=ctx.obj['data_provider'],
                                       passphrase=p)
            logger.info("... loading complete.")
        except exceptions.PassphraseError as e:
            click.echo(str(e))
            ctx.exit(code=1)
        except (TypeError, ValueError) as e:
            logger.error("Internal wallet error. Please report this as a bug.")
            logger.debug("".join(traceback.format_tb(e.__traceback__)))
            ctx.exit(code=2)

        def _on_close():
            try:
                ctx.obj['wallet'].sync_wallet_file()
            except:
                pass

        ctx.call_on_close(_on_close)