forked from Foundation-Devices/passport-firmware
-
Notifications
You must be signed in to change notification settings - Fork 0
/
accounts.py
139 lines (114 loc) · 5.06 KB
/
accounts.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
# SPDX-FileCopyrightText: 2021 Foundation Devices, Inc. <[email protected]>
# SPDX-License-Identifier: GPL-3.0-or-later
#
# accounts.py - Single sig and multisig accounts feature for better organization and privacy/isolation
#
from menu import MenuSystem, MenuItem
from flow import SettingsMenu, AccountMenu
import stash
import common
from common import settings, system
from utils import UXStateMachine, to_json, to_str, save_new_account, make_account_name_num, account_exists, get_accounts
from wallets.utils import get_next_account_num
from ux import ux_enter_text, ux_show_story
from constants import DEFAULT_ACCOUNT_ENTRY, MAX_ACCOUNT_NAME_LEN
# from wallets.constants import *
# Set the account reference in common and update xfp/xpub with the current account
def set_active_account(label=None, arg=None, menu_title=None, index=None):
account = arg
# print('Setting active_account={}'.format(account))
common.active_account = account
def clear_active_account(label=None, arg=None, menu_title=None, index=None):
# print('Clearing active_account')
common.active_account = None
async def new_account(*a):
new_account_ux = NewAccountUX()
await new_account_ux.show()
class NewAccountUX(UXStateMachine):
def __init__(self):
# States
self.SELECT_ACCOUNT_NUM = 1
self.ENTER_ACCOUNT_NAME = 2
self.account_num = 0
self.account_name = ''
super().__init__(self.SELECT_ACCOUNT_NUM)
async def show(self):
while True:
# print('show: state={}'.format(self.state))
if self.state == self.SELECT_ACCOUNT_NUM:
# Pick the next expected acct_num as the default value here
next_acct_num = get_next_account_num()
acct_num = await ux_enter_text(
title="Account",
label="Account Number",
initial_text='{}'.format(next_acct_num),
left_btn='BACK',
right_btn='ENTER',
num_only=True,
max_length=9)
if acct_num == None:
return
# Use the entered account number
self.account_num = acct_num
self.goto(self.ENTER_ACCOUNT_NAME)
elif self.state == self.ENTER_ACCOUNT_NAME:
name = await ux_enter_text(
'Account Name',
label='New Account Name',
initial_text=self.account_name,
right_btn='SAVE',
max_length=MAX_ACCOUNT_NAME_LEN)
if name == None:
self.goto_prev()
continue
# See if an account with this name already exists
if account_exists(name):
result = await ux_show_story('An account with the name "{}" already exists. Please choose a different name.'.format(name),
title='Duplicate', center=True, center_vertically=True, right_btn='EDIT')
if result == 'x':
self.goto_prev()
continue
else:
self.account_name = name # Start off with the name the user entered
continue
await save_new_account(name, self.account_num)
return
MAX_ACCOUNTS = 20
def max_accounts_reached():
accounts = get_accounts()
return len(accounts) >= MAX_ACCOUNTS
class AllAccountsMenu(MenuSystem):
@classmethod
def construct(cls):
# Dynamic menu with user-defined names of accounts
# from actions import import_multisig_from_sd, import_multisig_from_qr
rv = []
try:
accounts = get_accounts()
# print('accounts={}'.format(to_str(accounts)))
for acct in accounts:
acct_num = acct.get('acct_num')
name_num = make_account_name_num(acct.get('name'), acct_num)
rv.append(
MenuItem(
name_num,
menu=AccountMenu,
menu_title=name_num,
action=set_active_account,
arg=acct))
# Show Resume or new account menu depending on status
rv.append(MenuItem('New Account', f=new_account, predicate=lambda: not max_accounts_reached()))
except Exception as e:
# print('accounts={}'.format(accounts))
print('e={}'.format(e))
rv.append(MenuItem('<Account Data Corrupted>', f=lambda: None))
# print('rv={}'.format(rv))
return rv
def update_contents(self):
# Reconstruct the list of wallets on this dynamic menu, because
# we added or changed them and are showing that same menu again.
tmp = self.construct()
self.replace_items(tmp, True)
# Clear active account, if any, usually when menu is activated after returning from an account submenu
if common.active_account != None:
clear_active_account()