Project template for hardware wallet workshop

Dependencies:   mbed QSPI_DISCO_F469NI BSP_DISCO_F469NI

Committer:
stepansnigirev
Date:
Tue Jul 30 19:29:37 2019 +0000
Revision:
1:6fea6c7dce1c
Parent:
0:176af1483f18
Child:
2:8b42ea8491ae
template code

Who changed what in which revision?

UserRevisionLine numberNew contents of line
stepansnigirev 1:6fea6c7dce1c 1 #include "mbed.h"
stepansnigirev 1:6fea6c7dce1c 2 #include "helpers.h"
stepansnigirev 1:6fea6c7dce1c 3
stepansnigirev 1:6fea6c7dce1c 4 // bitcoin lib
stepansnigirev 1:6fea6c7dce1c 5 #include "Bitcoin.h" // Public, Private, HD keys, scripts, raw transactions and stuff
stepansnigirev 1:6fea6c7dce1c 6 #include "PSBT.h" // Partially Signed Bitcoin Transaction format
stepansnigirev 1:6fea6c7dce1c 7
stepansnigirev 1:6fea6c7dce1c 8 /***************** bitcoin stuff ***************/
stepansnigirev 1:6fea6c7dce1c 9
stepansnigirev 1:6fea6c7dce1c 10 string mnemonic;
stepansnigirev 1:6fea6c7dce1c 11 HDPrivateKey root; // root private key
stepansnigirev 1:6fea6c7dce1c 12 HDPrivateKey account; // account master private key
stepansnigirev 1:6fea6c7dce1c 13 HDPublicKey xpub; // account master public key
stepansnigirev 1:6fea6c7dce1c 14 bool change = false; // internal or external address
stepansnigirev 1:6fea6c7dce1c 15 unsigned int child_index = 0; // current child index
stepansnigirev 1:6fea6c7dce1c 16
stepansnigirev 1:6fea6c7dce1c 17 PSBT psbt; // psbt transaction we will be signing
stepansnigirev 1:6fea6c7dce1c 18
stepansnigirev 1:6fea6c7dce1c 19 /****************** GUI elements ****************/
stepansnigirev 1:6fea6c7dce1c 20
stepansnigirev 1:6fea6c7dce1c 21 // some global scope GUI objects we will be changing in callbacks
stepansnigirev 1:6fea6c7dce1c 22 Label titleLbl;
stepansnigirev 1:6fea6c7dce1c 23 Label dataLbl;
stepansnigirev 1:6fea6c7dce1c 24 QR qr;
stepansnigirev 1:6fea6c7dce1c 25
stepansnigirev 1:6fea6c7dce1c 26 Button btn;
stepansnigirev 1:6fea6c7dce1c 27 Button printBtn;
stepansnigirev 1:6fea6c7dce1c 28 Label lbl;
stepansnigirev 1:6fea6c7dce1c 29
stepansnigirev 1:6fea6c7dce1c 30 /*********** forward declarations **************/
stepansnigirev 1:6fea6c7dce1c 31
stepansnigirev 1:6fea6c7dce1c 32 // handy function to display information to the user
stepansnigirev 1:6fea6c7dce1c 33 // with a title, a message and OK button that goes to the menu
stepansnigirev 1:6fea6c7dce1c 34 void showMessage(const string title, const string message);
stepansnigirev 1:6fea6c7dce1c 35 // signs transaction after user confirmation
stepansnigirev 1:6fea6c7dce1c 36 static lv_res_t signConfirmCallback(lv_obj_t * btn);
stepansnigirev 1:6fea6c7dce1c 37 // derives keys from mnemonic and password
stepansnigirev 1:6fea6c7dce1c 38 void initKeys(const string mnemonic, const string password = "");
stepansnigirev 1:6fea6c7dce1c 39 // if mnemonic is not present we can generate or recover it
stepansnigirev 1:6fea6c7dce1c 40 void showInitScreen();
stepansnigirev 1:6fea6c7dce1c 41 // if mnemonic is there we go directly to the main menu
stepansnigirev 1:6fea6c7dce1c 42 void showMenu();
stepansnigirev 1:6fea6c7dce1c 43 // some functions that handle button clicks
stepansnigirev 1:6fea6c7dce1c 44 static lv_res_t toMenuCallback(lv_obj_t * btn);
stepansnigirev 1:6fea6c7dce1c 45 static lv_res_t showAddressesCallback(lv_obj_t * btn);
stepansnigirev 1:6fea6c7dce1c 46 static lv_res_t showMnemonicCallback(lv_obj_t * btn);
stepansnigirev 1:6fea6c7dce1c 47 static lv_res_t wipeCallback(lv_obj_t * btn);
stepansnigirev 1:6fea6c7dce1c 48 static lv_res_t enterMnemonicCallback(lv_obj_t * btn);
stepansnigirev 1:6fea6c7dce1c 49 // shows address on the screen
stepansnigirev 1:6fea6c7dce1c 50 void showAddress(unsigned int child_index, bool change);
stepansnigirev 1:6fea6c7dce1c 51
stepansnigirev 1:6fea6c7dce1c 52 /*********** functions to complete **************/
stepansnigirev 1:6fea6c7dce1c 53
stepansnigirev 1:6fea6c7dce1c 54 // generates a new mnemonic
stepansnigirev 1:6fea6c7dce1c 55 string generateNewMnemonic(){
stepansnigirev 1:6fea6c7dce1c 56 // TODO:
stepansnigirev 1:6fea6c7dce1c 57 // - generate random buffer (16 or 32 bytes) - getRandomBuffer(buf, size)
stepansnigirev 1:6fea6c7dce1c 58 // - create a new mnemonic from it - generateMnemonic(buf, size)
stepansnigirev 1:6fea6c7dce1c 59 // - save this mnemonic
stepansnigirev 1:6fea6c7dce1c 60 // - display it to the user
stepansnigirev 1:6fea6c7dce1c 61
stepansnigirev 1:6fea6c7dce1c 62 return "";
stepansnigirev 1:6fea6c7dce1c 63 }
stepansnigirev 1:6fea6c7dce1c 64
stepansnigirev 1:6fea6c7dce1c 65 // checks if entered mnemonic is valid
stepansnigirev 1:6fea6c7dce1c 66 static lv_res_t checkMnemonicCallback(lv_obj_t * btn){
stepansnigirev 1:6fea6c7dce1c 67 // TODO:
stepansnigirev 1:6fea6c7dce1c 68 // - check mnemonic
stepansnigirev 1:6fea6c7dce1c 69 // - if ok, init keys and show success message
stepansnigirev 1:6fea6c7dce1c 70 // - otherwise erase the whole mnemonic
stepansnigirev 1:6fea6c7dce1c 71
stepansnigirev 1:6fea6c7dce1c 72 return LV_RES_OK;
stepansnigirev 1:6fea6c7dce1c 73 }
stepansnigirev 1:6fea6c7dce1c 74
stepansnigirev 1:6fea6c7dce1c 75 // generates hd keys from the mnemonic
stepansnigirev 1:6fea6c7dce1c 76 void initKeys(const string mnemonic, const string password){
stepansnigirev 1:6fea6c7dce1c 77 // TODO:
stepansnigirev 1:6fea6c7dce1c 78 // - derive root key from the mnemonic and empty password
stepansnigirev 1:6fea6c7dce1c 79 // - derive account key using m/84'/1'/0'/ derivation path
stepansnigirev 1:6fea6c7dce1c 80 // - get account master public key
stepansnigirev 1:6fea6c7dce1c 81
stepansnigirev 1:6fea6c7dce1c 82 }
stepansnigirev 1:6fea6c7dce1c 83
stepansnigirev 1:6fea6c7dce1c 84 void showAddress(unsigned int child_index, bool change){
stepansnigirev 1:6fea6c7dce1c 85 // TODO:
stepansnigirev 1:6fea6c7dce1c 86 // - derive an address from xpub according to the derivation
stepansnigirev 1:6fea6c7dce1c 87 // - set dataLbl text to the address
stepansnigirev 1:6fea6c7dce1c 88 // - set qr text to "bitcoin:address"
stepansnigirev 1:6fea6c7dce1c 89 // OPTIONAL:
stepansnigirev 1:6fea6c7dce1c 90 // - display both bech32 and nested segwit addresses
stepansnigirev 1:6fea6c7dce1c 91
stepansnigirev 1:6fea6c7dce1c 92 stringstream title;
stepansnigirev 1:6fea6c7dce1c 93 title << "Your ";
stepansnigirev 1:6fea6c7dce1c 94 if(change){
stepansnigirev 1:6fea6c7dce1c 95 title << "change ";
stepansnigirev 1:6fea6c7dce1c 96 }else{
stepansnigirev 1:6fea6c7dce1c 97 title << "receiving ";
stepansnigirev 1:6fea6c7dce1c 98 }
stepansnigirev 1:6fea6c7dce1c 99 title << "address #" << child_index << ":";
stepansnigirev 1:6fea6c7dce1c 100 titleLbl.text(title.str());
stepansnigirev 1:6fea6c7dce1c 101 // generate the address here
stepansnigirev 1:6fea6c7dce1c 102 string address = "to be implemented";
stepansnigirev 1:6fea6c7dce1c 103 dataLbl.text(address);
stepansnigirev 1:6fea6c7dce1c 104 dataLbl.align(ALIGN_CENTER);
stepansnigirev 1:6fea6c7dce1c 105 qr.text(string("bitcoin:") + address);
stepansnigirev 1:6fea6c7dce1c 106 qr.align(ALIGN_CENTER);
stepansnigirev 1:6fea6c7dce1c 107 }
stepansnigirev 1:6fea6c7dce1c 108
stepansnigirev 1:6fea6c7dce1c 109 // this will be called when we press "save master key" button
stepansnigirev 1:6fea6c7dce1c 110 static lv_res_t saveXpubCallback(lv_obj_t * btn){
stepansnigirev 1:6fea6c7dce1c 111 // TODO:
stepansnigirev 1:6fea6c7dce1c 112 // - check if SD card present
stepansnigirev 1:6fea6c7dce1c 113 // - save xpub to the "xpub.txt"
stepansnigirev 1:6fea6c7dce1c 114 // - check if write was sucessful
stepansnigirev 1:6fea6c7dce1c 115 // - show success / fail message
stepansnigirev 1:6fea6c7dce1c 116 // OPTIONAL:
stepansnigirev 1:6fea6c7dce1c 117 // - use [fingerprint/derivation]xpub format
stepansnigirev 1:6fea6c7dce1c 118 // - create bitcoin core descriptor for bitcoin-cli importmulti
stepansnigirev 1:6fea6c7dce1c 119
stepansnigirev 1:6fea6c7dce1c 120 showMessage("Error","To be implemented");
stepansnigirev 1:6fea6c7dce1c 121 return LV_RES_OK;
stepansnigirev 1:6fea6c7dce1c 122 }
stepansnigirev 1:6fea6c7dce1c 123
stepansnigirev 1:6fea6c7dce1c 124 // displays confirmation screen for the transaction signing
stepansnigirev 1:6fea6c7dce1c 125 void showSignRequest(){
stepansnigirev 1:6fea6c7dce1c 126 // TODO:
stepansnigirev 1:6fea6c7dce1c 127 // display information of the transaction:
stepansnigirev 1:6fea6c7dce1c 128 // - go through all outputs
stepansnigirev 1:6fea6c7dce1c 129 // - detect if the address is the change address
stepansnigirev 1:6fea6c7dce1c 130 // - if not, show information in the form "address: amount"
stepansnigirev 1:6fea6c7dce1c 131 // - if it is change, hide or mark as a change
stepansnigirev 1:6fea6c7dce1c 132 // - display the transaction fee
stepansnigirev 1:6fea6c7dce1c 133 // OPTIONAL:
stepansnigirev 1:6fea6c7dce1c 134 // - verify that pubkey is actually used in the script
stepansnigirev 1:6fea6c7dce1c 135 // - do the same for bip49 and check redeem script
stepansnigirev 1:6fea6c7dce1c 136 // - check if derivation path is not weird (indexes are reasonable)
stepansnigirev 1:6fea6c7dce1c 137
stepansnigirev 1:6fea6c7dce1c 138 stringstream ss;
stepansnigirev 1:6fea6c7dce1c 139 ss << "Sending:\n\n";
stepansnigirev 1:6fea6c7dce1c 140 ss << "to be implemented";
stepansnigirev 1:6fea6c7dce1c 141
stepansnigirev 1:6fea6c7dce1c 142 gui.clear();
stepansnigirev 1:6fea6c7dce1c 143 titleLbl = Label("Sign transaction?");
stepansnigirev 1:6fea6c7dce1c 144 titleLbl.size(gui.width(), 20);
stepansnigirev 1:6fea6c7dce1c 145 titleLbl.position(0, 40);
stepansnigirev 1:6fea6c7dce1c 146 titleLbl.alignText(ALIGN_TEXT_CENTER);
stepansnigirev 1:6fea6c7dce1c 147
stepansnigirev 1:6fea6c7dce1c 148 dataLbl = Label(ss.str());
stepansnigirev 1:6fea6c7dce1c 149 dataLbl.size(gui.width()-100, 100);
stepansnigirev 1:6fea6c7dce1c 150 dataLbl.position(50, 300);
stepansnigirev 1:6fea6c7dce1c 151 dataLbl.alignText(ALIGN_TEXT_CENTER);
stepansnigirev 1:6fea6c7dce1c 152
stepansnigirev 1:6fea6c7dce1c 153 Button btn(toMenuCallback, "Cancel");
stepansnigirev 1:6fea6c7dce1c 154 btn.size(gui.width()/2-45, 80);
stepansnigirev 1:6fea6c7dce1c 155 btn.position(30, gui.height()-100);
stepansnigirev 1:6fea6c7dce1c 156
stepansnigirev 1:6fea6c7dce1c 157 Button btn2(signConfirmCallback, "Confirm");
stepansnigirev 1:6fea6c7dce1c 158 btn2.size(gui.width()/2-45, 80);
stepansnigirev 1:6fea6c7dce1c 159 btn2.position(gui.width()/2+30, gui.height()-100);
stepansnigirev 1:6fea6c7dce1c 160 }
stepansnigirev 1:6fea6c7dce1c 161
stepansnigirev 1:6fea6c7dce1c 162 // reads unsigned transaction from SD card
stepansnigirev 1:6fea6c7dce1c 163 static lv_res_t signPSBTCallback(lv_obj_t * btn){
stepansnigirev 1:6fea6c7dce1c 164 // TODO:
stepansnigirev 1:6fea6c7dce1c 165 // - check if SD card is there
stepansnigirev 1:6fea6c7dce1c 166 // - read data from "unsigned.psbt"
stepansnigirev 1:6fea6c7dce1c 167 // - convert it from base64 to raw bytes
stepansnigirev 1:6fea6c7dce1c 168 // - parse psbt transaction
stepansnigirev 1:6fea6c7dce1c 169 // - call showSignRequest()
stepansnigirev 1:6fea6c7dce1c 170 // OPTIONAL
stepansnigirev 1:6fea6c7dce1c 171 // - also show signed transaction as a QR code
stepansnigirev 1:6fea6c7dce1c 172
stepansnigirev 1:6fea6c7dce1c 173 showSignRequest();
stepansnigirev 1:6fea6c7dce1c 174 return LV_RES_OK;
stepansnigirev 1:6fea6c7dce1c 175 }
stepansnigirev 1:6fea6c7dce1c 176
stepansnigirev 1:6fea6c7dce1c 177 // signs transaction
stepansnigirev 1:6fea6c7dce1c 178 static lv_res_t signConfirmCallback(lv_obj_t * btn){
stepansnigirev 1:6fea6c7dce1c 179 // TODO:
stepansnigirev 1:6fea6c7dce1c 180 // - check if SD card is still there
stepansnigirev 1:6fea6c7dce1c 181 // - serialize the psbt to byte array
stepansnigirev 1:6fea6c7dce1c 182 // - convert to base64
stepansnigirev 1:6fea6c7dce1c 183 // - save to "signed.psbt"
stepansnigirev 1:6fea6c7dce1c 184 // - show success message
stepansnigirev 1:6fea6c7dce1c 185
stepansnigirev 1:6fea6c7dce1c 186 showMessage("Error", "To be implemented");
stepansnigirev 1:6fea6c7dce1c 187 return LV_RES_OK;
stepansnigirev 1:6fea6c7dce1c 188 }
stepansnigirev 1:6fea6c7dce1c 189
stepansnigirev 1:6fea6c7dce1c 190 /***************** GUI functions ***************/
stepansnigirev 1:6fea6c7dce1c 191
stepansnigirev 1:6fea6c7dce1c 192 static lv_res_t newMnemonicCallback(lv_obj_t * btn){
stepansnigirev 1:6fea6c7dce1c 193 string mnemonic = generateNewMnemonic();
stepansnigirev 1:6fea6c7dce1c 194 saveMnemonic(mnemonic);
stepansnigirev 1:6fea6c7dce1c 195 showMessage("Write down your recovery phrase:", mnemonic);
stepansnigirev 1:6fea6c7dce1c 196 initKeys(mnemonic);
stepansnigirev 1:6fea6c7dce1c 197 return LV_RES_OK;
stepansnigirev 1:6fea6c7dce1c 198 }
stepansnigirev 1:6fea6c7dce1c 199
stepansnigirev 1:6fea6c7dce1c 200 // show next address
stepansnigirev 1:6fea6c7dce1c 201 static lv_res_t nextCallback(lv_obj_t * btn){
stepansnigirev 1:6fea6c7dce1c 202 child_index++;
stepansnigirev 1:6fea6c7dce1c 203 showAddress(child_index, change);
stepansnigirev 1:6fea6c7dce1c 204 return LV_RES_OK;
stepansnigirev 1:6fea6c7dce1c 205 }
stepansnigirev 1:6fea6c7dce1c 206
stepansnigirev 1:6fea6c7dce1c 207 // show previous address
stepansnigirev 1:6fea6c7dce1c 208 static lv_res_t prevCallback(lv_obj_t * btn){
stepansnigirev 1:6fea6c7dce1c 209 if(child_index > 0){
stepansnigirev 1:6fea6c7dce1c 210 child_index--;
stepansnigirev 1:6fea6c7dce1c 211 showAddress(child_index, change);
stepansnigirev 1:6fea6c7dce1c 212 }
stepansnigirev 1:6fea6c7dce1c 213 return LV_RES_OK;
stepansnigirev 1:6fea6c7dce1c 214 }
stepansnigirev 1:6fea6c7dce1c 215
stepansnigirev 1:6fea6c7dce1c 216 // switch to change addresses
stepansnigirev 1:6fea6c7dce1c 217 static lv_res_t changeCallback(lv_obj_t * btn){
stepansnigirev 1:6fea6c7dce1c 218 change = !change;
stepansnigirev 1:6fea6c7dce1c 219 showAddress(child_index, change);
stepansnigirev 1:6fea6c7dce1c 220 return LV_RES_OK;
stepansnigirev 1:6fea6c7dce1c 221 }
stepansnigirev 1:6fea6c7dce1c 222
stepansnigirev 1:6fea6c7dce1c 223 // show master public key
stepansnigirev 1:6fea6c7dce1c 224 static lv_res_t xpubCallback(lv_obj_t * btn){
stepansnigirev 1:6fea6c7dce1c 225 titleLbl.text("Your master public key");
stepansnigirev 1:6fea6c7dce1c 226 qr.text(xpub.toString());
stepansnigirev 1:6fea6c7dce1c 227 dataLbl.text(xpub.toString());
stepansnigirev 1:6fea6c7dce1c 228 qr.align(ALIGN_CENTER);
stepansnigirev 1:6fea6c7dce1c 229 dataLbl.align(ALIGN_CENTER);
stepansnigirev 1:6fea6c7dce1c 230 return LV_RES_OK;
stepansnigirev 1:6fea6c7dce1c 231 }
stepansnigirev 1:6fea6c7dce1c 232
stepansnigirev 1:6fea6c7dce1c 233 /******************* Main part *****************/
stepansnigirev 1:6fea6c7dce1c 234
stepansnigirev 1:6fea6c7dce1c 235 int main(){
stepansnigirev 1:6fea6c7dce1c 236 init();
stepansnigirev 1:6fea6c7dce1c 237
stepansnigirev 1:6fea6c7dce1c 238 string mnemonic = loadMnemonic();
stepansnigirev 1:6fea6c7dce1c 239 if(mnemonic.length() == 0){
stepansnigirev 1:6fea6c7dce1c 240 showInitScreen();
stepansnigirev 1:6fea6c7dce1c 241 }else{
stepansnigirev 1:6fea6c7dce1c 242 initKeys(mnemonic);
stepansnigirev 1:6fea6c7dce1c 243 showMenu();
stepansnigirev 1:6fea6c7dce1c 244 }
stepansnigirev 1:6fea6c7dce1c 245
stepansnigirev 1:6fea6c7dce1c 246 while(1){
stepansnigirev 1:6fea6c7dce1c 247 gui.update();
stepansnigirev 1:6fea6c7dce1c 248 }
stepansnigirev 1:6fea6c7dce1c 249 }
stepansnigirev 1:6fea6c7dce1c 250
stepansnigirev 1:6fea6c7dce1c 251 /****************** GUI stuff *****************/
stepansnigirev 1:6fea6c7dce1c 252
stepansnigirev 1:6fea6c7dce1c 253 void showInitScreen(){
stepansnigirev 1:6fea6c7dce1c 254 gui.clear();
stepansnigirev 1:6fea6c7dce1c 255 titleLbl = Label("Let's set it up!");
stepansnigirev 1:6fea6c7dce1c 256 titleLbl.size(gui.width(), 20);
stepansnigirev 1:6fea6c7dce1c 257 titleLbl.position(0, 40);
stepansnigirev 1:6fea6c7dce1c 258 titleLbl.alignText(ALIGN_TEXT_CENTER);
stepansnigirev 1:6fea6c7dce1c 259
stepansnigirev 1:6fea6c7dce1c 260 Button btn(newMnemonicCallback, "Generate new mnemonic");
stepansnigirev 1:6fea6c7dce1c 261 btn.size(gui.width()-100, 80);
stepansnigirev 1:6fea6c7dce1c 262 btn.position(0, 200);
stepansnigirev 1:6fea6c7dce1c 263 btn.align(ALIGN_CENTER);
stepansnigirev 1:6fea6c7dce1c 264
stepansnigirev 1:6fea6c7dce1c 265 Button btn2(enterMnemonicCallback, "Enter existing mnemonic");
stepansnigirev 1:6fea6c7dce1c 266 btn2.size(gui.width()-100, 80);
stepansnigirev 1:6fea6c7dce1c 267 btn2.position(0, 300);
stepansnigirev 1:6fea6c7dce1c 268 btn2.align(ALIGN_CENTER);
stepansnigirev 1:6fea6c7dce1c 269 }
stepansnigirev 1:6fea6c7dce1c 270
stepansnigirev 1:6fea6c7dce1c 271 void showMenu(){
stepansnigirev 1:6fea6c7dce1c 272 gui.clear();
stepansnigirev 1:6fea6c7dce1c 273 titleLbl = Label("What do you want to do?");
stepansnigirev 1:6fea6c7dce1c 274 titleLbl.size(gui.width(), 20);
stepansnigirev 1:6fea6c7dce1c 275 titleLbl.position(0, 40);
stepansnigirev 1:6fea6c7dce1c 276 titleLbl.alignText(ALIGN_TEXT_CENTER);
stepansnigirev 1:6fea6c7dce1c 277
stepansnigirev 1:6fea6c7dce1c 278 Button btn(showAddressesCallback, "Show addresses");
stepansnigirev 1:6fea6c7dce1c 279 btn.size(gui.width()-100, 80);
stepansnigirev 1:6fea6c7dce1c 280 btn.position(0, 100);
stepansnigirev 1:6fea6c7dce1c 281 btn.align(ALIGN_CENTER);
stepansnigirev 1:6fea6c7dce1c 282
stepansnigirev 1:6fea6c7dce1c 283 Button btn2(saveXpubCallback, "Export xpub");
stepansnigirev 1:6fea6c7dce1c 284 btn2.size(gui.width()-100, 80);
stepansnigirev 1:6fea6c7dce1c 285 btn2.position(0, 300);
stepansnigirev 1:6fea6c7dce1c 286 btn2.align(ALIGN_CENTER);
stepansnigirev 1:6fea6c7dce1c 287
stepansnigirev 1:6fea6c7dce1c 288 Button btn3(signPSBTCallback, "Sign PSBT transaction");
stepansnigirev 1:6fea6c7dce1c 289 btn3.size(gui.width()-100, 80);
stepansnigirev 1:6fea6c7dce1c 290 btn3.position(0, 400);
stepansnigirev 1:6fea6c7dce1c 291 btn3.align(ALIGN_CENTER);
stepansnigirev 1:6fea6c7dce1c 292
stepansnigirev 1:6fea6c7dce1c 293 Button btn4(wipeCallback, "Wipe device");
stepansnigirev 1:6fea6c7dce1c 294 btn4.size(gui.width()-100, 80);
stepansnigirev 1:6fea6c7dce1c 295 btn4.position(0, 600);
stepansnigirev 1:6fea6c7dce1c 296 btn4.align(ALIGN_CENTER);
stepansnigirev 1:6fea6c7dce1c 297
stepansnigirev 1:6fea6c7dce1c 298 Button btn5(showMnemonicCallback, "Show mnemonic");
stepansnigirev 1:6fea6c7dce1c 299 btn5.size(gui.width()-100, 80);
stepansnigirev 1:6fea6c7dce1c 300 btn5.position(0, 700);
stepansnigirev 1:6fea6c7dce1c 301 btn5.align(ALIGN_CENTER);
stepansnigirev 1:6fea6c7dce1c 302 }
stepansnigirev 1:6fea6c7dce1c 303
stepansnigirev 1:6fea6c7dce1c 304 void showMessage(const string title, const string message){
stepansnigirev 1:6fea6c7dce1c 305 gui.clear();
stepansnigirev 1:6fea6c7dce1c 306 titleLbl = Label(title);
stepansnigirev 1:6fea6c7dce1c 307 titleLbl.size(gui.width(), 20);
stepansnigirev 1:6fea6c7dce1c 308 titleLbl.position(0, 40);
stepansnigirev 1:6fea6c7dce1c 309 titleLbl.alignText(ALIGN_TEXT_CENTER);
stepansnigirev 1:6fea6c7dce1c 310
stepansnigirev 1:6fea6c7dce1c 311 dataLbl = Label(message);
stepansnigirev 1:6fea6c7dce1c 312 dataLbl.size(gui.width()-100, 100);
stepansnigirev 1:6fea6c7dce1c 313 dataLbl.position(50, 300);
stepansnigirev 1:6fea6c7dce1c 314 dataLbl.alignText(ALIGN_TEXT_CENTER);
stepansnigirev 1:6fea6c7dce1c 315
stepansnigirev 1:6fea6c7dce1c 316 Button btn(toMenuCallback, "OK");
stepansnigirev 1:6fea6c7dce1c 317 btn.size(gui.width()-100, 80);
stepansnigirev 1:6fea6c7dce1c 318 btn.position(0, gui.height()-100);
stepansnigirev 1:6fea6c7dce1c 319 btn.align(ALIGN_CENTER);
stepansnigirev 1:6fea6c7dce1c 320 }
stepansnigirev 1:6fea6c7dce1c 321
stepansnigirev 1:6fea6c7dce1c 322 void showAddressScreen(){
stepansnigirev 1:6fea6c7dce1c 323 gui.clear();
stepansnigirev 1:6fea6c7dce1c 324 titleLbl = Label("Your address");
stepansnigirev 1:6fea6c7dce1c 325 titleLbl.size(gui.width(), 20);
stepansnigirev 1:6fea6c7dce1c 326 titleLbl.position(0, 40);
stepansnigirev 1:6fea6c7dce1c 327 titleLbl.alignText(ALIGN_TEXT_CENTER);
stepansnigirev 1:6fea6c7dce1c 328
stepansnigirev 1:6fea6c7dce1c 329 dataLbl = Label(" ");
stepansnigirev 1:6fea6c7dce1c 330 dataLbl.size(gui.width()-100, 100); // full width
stepansnigirev 1:6fea6c7dce1c 331 dataLbl.position(50, gui.height()-300);
stepansnigirev 1:6fea6c7dce1c 332 dataLbl.alignText(ALIGN_TEXT_CENTER);
stepansnigirev 1:6fea6c7dce1c 333
stepansnigirev 1:6fea6c7dce1c 334 qr = QR(" ");
stepansnigirev 1:6fea6c7dce1c 335 qr.size(gui.width()-100);
stepansnigirev 1:6fea6c7dce1c 336 qr.position(0, 100);
stepansnigirev 1:6fea6c7dce1c 337 qr.align(ALIGN_CENTER);
stepansnigirev 1:6fea6c7dce1c 338
stepansnigirev 1:6fea6c7dce1c 339 Button btn(nextCallback, "Next address");
stepansnigirev 1:6fea6c7dce1c 340 btn.size(gui.width()/3-20, 80);
stepansnigirev 1:6fea6c7dce1c 341 btn.position(gui.width()*2/3 + 10, gui.height()-100);
stepansnigirev 1:6fea6c7dce1c 342
stepansnigirev 1:6fea6c7dce1c 343 Button btn2(prevCallback, "Previous address");
stepansnigirev 1:6fea6c7dce1c 344 btn2.size(gui.width()/3-20, 80);
stepansnigirev 1:6fea6c7dce1c 345 btn2.position(10, gui.height()-100);
stepansnigirev 1:6fea6c7dce1c 346
stepansnigirev 1:6fea6c7dce1c 347 Button btn3(changeCallback, "Toggle\nchange");
stepansnigirev 1:6fea6c7dce1c 348 btn3.size(gui.width()/3-20, 80);
stepansnigirev 1:6fea6c7dce1c 349 btn3.position(gui.width()/3 + 10, gui.height()-100);
stepansnigirev 1:6fea6c7dce1c 350
stepansnigirev 1:6fea6c7dce1c 351 Button btn4(xpubCallback, "Show xpub");
stepansnigirev 1:6fea6c7dce1c 352 btn4.size(gui.width()/2-20, 80);
stepansnigirev 1:6fea6c7dce1c 353 btn4.position(gui.width()/2+10, gui.height()-200);
stepansnigirev 1:6fea6c7dce1c 354
stepansnigirev 1:6fea6c7dce1c 355 Button btn5(toMenuCallback, "Menu");
stepansnigirev 1:6fea6c7dce1c 356 btn5.size(gui.width()/2-20, 80);
stepansnigirev 1:6fea6c7dce1c 357 btn5.position(10, gui.height()-200);
stepansnigirev 1:6fea6c7dce1c 358 }
stepansnigirev 1:6fea6c7dce1c 359
stepansnigirev 1:6fea6c7dce1c 360 static lv_res_t toMenuCallback(lv_obj_t * btn){
stepansnigirev 1:6fea6c7dce1c 361 showMenu();
stepansnigirev 1:6fea6c7dce1c 362 return LV_RES_OK;
stepansnigirev 1:6fea6c7dce1c 363 }
stepansnigirev 1:6fea6c7dce1c 364
stepansnigirev 1:6fea6c7dce1c 365 static lv_res_t showAddressesCallback(lv_obj_t * btn){
stepansnigirev 1:6fea6c7dce1c 366 showAddressScreen();
stepansnigirev 1:6fea6c7dce1c 367 showAddress(child_index, change);
stepansnigirev 1:6fea6c7dce1c 368 return LV_RES_OK;
stepansnigirev 1:6fea6c7dce1c 369 }
stepansnigirev 1:6fea6c7dce1c 370
stepansnigirev 1:6fea6c7dce1c 371 static lv_res_t wipeCallback(lv_obj_t * btn){
stepansnigirev 1:6fea6c7dce1c 372 wipe();
stepansnigirev 1:6fea6c7dce1c 373 return LV_RES_OK;
stepansnigirev 1:6fea6c7dce1c 374 }
stepansnigirev 1:6fea6c7dce1c 375
stepansnigirev 1:6fea6c7dce1c 376 /*************** mnemonic stuff ***************/
stepansnigirev 1:6fea6c7dce1c 377
stepansnigirev 1:6fea6c7dce1c 378 static lv_res_t showMnemonicCallback(lv_obj_t * btn){
stepansnigirev 1:6fea6c7dce1c 379 string mnemonic = loadMnemonic();
stepansnigirev 1:6fea6c7dce1c 380 showMessage("Here is your recovery phrase:", mnemonic);
stepansnigirev 1:6fea6c7dce1c 381 return LV_RES_OK;
stepansnigirev 1:6fea6c7dce1c 382 }
stepansnigirev 1:6fea6c7dce1c 383
stepansnigirev 1:6fea6c7dce1c 384 static const char * keys[] = {"q","w","e","r","t","y","u","i","o","p","\n",
stepansnigirev 1:6fea6c7dce1c 385 "a","s","d","f","g","h","j","k","l","\n",
stepansnigirev 1:6fea6c7dce1c 386 " ","z","x","c","v","b","n","m","<",""};
stepansnigirev 1:6fea6c7dce1c 387
stepansnigirev 1:6fea6c7dce1c 388 static lv_res_t typeCallback(lv_obj_t * btn, const char * key){
stepansnigirev 1:6fea6c7dce1c 389 if(key[0] == '<'){
stepansnigirev 1:6fea6c7dce1c 390 if(mnemonic.length() > 0){
stepansnigirev 1:6fea6c7dce1c 391 mnemonic = mnemonic.substr(0,mnemonic.length()-1);
stepansnigirev 1:6fea6c7dce1c 392 }
stepansnigirev 1:6fea6c7dce1c 393 }else{
stepansnigirev 1:6fea6c7dce1c 394 mnemonic += key;
stepansnigirev 1:6fea6c7dce1c 395 }
stepansnigirev 1:6fea6c7dce1c 396 dataLbl.text(mnemonic);
stepansnigirev 1:6fea6c7dce1c 397 return LV_RES_OK;
stepansnigirev 1:6fea6c7dce1c 398 }
stepansnigirev 1:6fea6c7dce1c 399
stepansnigirev 1:6fea6c7dce1c 400 static lv_res_t enterMnemonicCallback(lv_obj_t * btn){
stepansnigirev 1:6fea6c7dce1c 401 gui.clear();
stepansnigirev 1:6fea6c7dce1c 402 mnemonic = "";
stepansnigirev 1:6fea6c7dce1c 403 titleLbl = Label("Enter your mnemonic");
stepansnigirev 1:6fea6c7dce1c 404 titleLbl.size(gui.width(), 20);
stepansnigirev 1:6fea6c7dce1c 405 titleLbl.position(0, 40);
stepansnigirev 1:6fea6c7dce1c 406 titleLbl.alignText(ALIGN_TEXT_CENTER);
stepansnigirev 1:6fea6c7dce1c 407
stepansnigirev 1:6fea6c7dce1c 408 dataLbl = Label(mnemonic);
stepansnigirev 1:6fea6c7dce1c 409 dataLbl.size(gui.width()-100, 50);
stepansnigirev 1:6fea6c7dce1c 410 dataLbl.position(50, 200);
stepansnigirev 1:6fea6c7dce1c 411 dataLbl.alignText(ALIGN_TEXT_CENTER);
stepansnigirev 1:6fea6c7dce1c 412
stepansnigirev 1:6fea6c7dce1c 413 Keyboard kb(typeCallback, keys);
stepansnigirev 1:6fea6c7dce1c 414 kb.size(gui.width(), gui.height()/3);
stepansnigirev 1:6fea6c7dce1c 415 kb.position(0, gui.height()*2/3-150);
stepansnigirev 1:6fea6c7dce1c 416
stepansnigirev 1:6fea6c7dce1c 417 Button btnx(checkMnemonicCallback, "Continue");
stepansnigirev 1:6fea6c7dce1c 418 btnx.size(gui.width()-100, 80);
stepansnigirev 1:6fea6c7dce1c 419 btnx.position(50, gui.height()-100);
stepansnigirev 1:6fea6c7dce1c 420 return LV_RES_OK;
stepansnigirev 1:6fea6c7dce1c 421 }