Project template for hardware wallet workshop

Dependencies:   mbed QSPI_DISCO_F469NI BSP_DISCO_F469NI

Committer:
stepansnigirev
Date:
Wed Jul 31 12:22:15 2019 +0000
Revision:
2:8b42ea8491ae
Parent:
1:6fea6c7dce1c
Child:
3:f9462bf83c56
button actions

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 2:8b42ea8491ae 194 if(mnemonic.length() > 0){
stepansnigirev 2:8b42ea8491ae 195 saveMnemonic(mnemonic);
stepansnigirev 2:8b42ea8491ae 196 showMessage("Write down your recovery phrase:", mnemonic);
stepansnigirev 2:8b42ea8491ae 197 initKeys(mnemonic);
stepansnigirev 2:8b42ea8491ae 198 }
stepansnigirev 1:6fea6c7dce1c 199 return LV_RES_OK;
stepansnigirev 1:6fea6c7dce1c 200 }
stepansnigirev 1:6fea6c7dce1c 201
stepansnigirev 1:6fea6c7dce1c 202 // show next address
stepansnigirev 1:6fea6c7dce1c 203 static lv_res_t nextCallback(lv_obj_t * btn){
stepansnigirev 1:6fea6c7dce1c 204 child_index++;
stepansnigirev 1:6fea6c7dce1c 205 showAddress(child_index, change);
stepansnigirev 1:6fea6c7dce1c 206 return LV_RES_OK;
stepansnigirev 1:6fea6c7dce1c 207 }
stepansnigirev 1:6fea6c7dce1c 208
stepansnigirev 1:6fea6c7dce1c 209 // show previous address
stepansnigirev 1:6fea6c7dce1c 210 static lv_res_t prevCallback(lv_obj_t * btn){
stepansnigirev 1:6fea6c7dce1c 211 if(child_index > 0){
stepansnigirev 1:6fea6c7dce1c 212 child_index--;
stepansnigirev 1:6fea6c7dce1c 213 showAddress(child_index, change);
stepansnigirev 1:6fea6c7dce1c 214 }
stepansnigirev 1:6fea6c7dce1c 215 return LV_RES_OK;
stepansnigirev 1:6fea6c7dce1c 216 }
stepansnigirev 1:6fea6c7dce1c 217
stepansnigirev 1:6fea6c7dce1c 218 // switch to change addresses
stepansnigirev 1:6fea6c7dce1c 219 static lv_res_t changeCallback(lv_obj_t * btn){
stepansnigirev 1:6fea6c7dce1c 220 change = !change;
stepansnigirev 1:6fea6c7dce1c 221 showAddress(child_index, change);
stepansnigirev 1:6fea6c7dce1c 222 return LV_RES_OK;
stepansnigirev 1:6fea6c7dce1c 223 }
stepansnigirev 1:6fea6c7dce1c 224
stepansnigirev 1:6fea6c7dce1c 225 // show master public key
stepansnigirev 1:6fea6c7dce1c 226 static lv_res_t xpubCallback(lv_obj_t * btn){
stepansnigirev 1:6fea6c7dce1c 227 titleLbl.text("Your master public key");
stepansnigirev 1:6fea6c7dce1c 228 qr.text(xpub.toString());
stepansnigirev 1:6fea6c7dce1c 229 dataLbl.text(xpub.toString());
stepansnigirev 1:6fea6c7dce1c 230 qr.align(ALIGN_CENTER);
stepansnigirev 1:6fea6c7dce1c 231 dataLbl.align(ALIGN_CENTER);
stepansnigirev 1:6fea6c7dce1c 232 return LV_RES_OK;
stepansnigirev 1:6fea6c7dce1c 233 }
stepansnigirev 1:6fea6c7dce1c 234
stepansnigirev 1:6fea6c7dce1c 235 /******************* Main part *****************/
stepansnigirev 1:6fea6c7dce1c 236
stepansnigirev 1:6fea6c7dce1c 237 int main(){
stepansnigirev 1:6fea6c7dce1c 238 init();
stepansnigirev 1:6fea6c7dce1c 239
stepansnigirev 1:6fea6c7dce1c 240 string mnemonic = loadMnemonic();
stepansnigirev 1:6fea6c7dce1c 241 if(mnemonic.length() == 0){
stepansnigirev 1:6fea6c7dce1c 242 showInitScreen();
stepansnigirev 1:6fea6c7dce1c 243 }else{
stepansnigirev 1:6fea6c7dce1c 244 initKeys(mnemonic);
stepansnigirev 1:6fea6c7dce1c 245 showMenu();
stepansnigirev 1:6fea6c7dce1c 246 }
stepansnigirev 1:6fea6c7dce1c 247
stepansnigirev 1:6fea6c7dce1c 248 while(1){
stepansnigirev 1:6fea6c7dce1c 249 gui.update();
stepansnigirev 1:6fea6c7dce1c 250 }
stepansnigirev 1:6fea6c7dce1c 251 }
stepansnigirev 1:6fea6c7dce1c 252
stepansnigirev 1:6fea6c7dce1c 253 /****************** GUI stuff *****************/
stepansnigirev 1:6fea6c7dce1c 254
stepansnigirev 1:6fea6c7dce1c 255 void showInitScreen(){
stepansnigirev 1:6fea6c7dce1c 256 gui.clear();
stepansnigirev 1:6fea6c7dce1c 257 titleLbl = Label("Let's set it up!");
stepansnigirev 1:6fea6c7dce1c 258 titleLbl.size(gui.width(), 20);
stepansnigirev 1:6fea6c7dce1c 259 titleLbl.position(0, 40);
stepansnigirev 1:6fea6c7dce1c 260 titleLbl.alignText(ALIGN_TEXT_CENTER);
stepansnigirev 1:6fea6c7dce1c 261
stepansnigirev 1:6fea6c7dce1c 262 Button btn(newMnemonicCallback, "Generate new mnemonic");
stepansnigirev 1:6fea6c7dce1c 263 btn.size(gui.width()-100, 80);
stepansnigirev 1:6fea6c7dce1c 264 btn.position(0, 200);
stepansnigirev 1:6fea6c7dce1c 265 btn.align(ALIGN_CENTER);
stepansnigirev 1:6fea6c7dce1c 266
stepansnigirev 1:6fea6c7dce1c 267 Button btn2(enterMnemonicCallback, "Enter existing mnemonic");
stepansnigirev 1:6fea6c7dce1c 268 btn2.size(gui.width()-100, 80);
stepansnigirev 1:6fea6c7dce1c 269 btn2.position(0, 300);
stepansnigirev 1:6fea6c7dce1c 270 btn2.align(ALIGN_CENTER);
stepansnigirev 1:6fea6c7dce1c 271 }
stepansnigirev 1:6fea6c7dce1c 272
stepansnigirev 1:6fea6c7dce1c 273 void showMenu(){
stepansnigirev 1:6fea6c7dce1c 274 gui.clear();
stepansnigirev 1:6fea6c7dce1c 275 titleLbl = Label("What do you want to do?");
stepansnigirev 1:6fea6c7dce1c 276 titleLbl.size(gui.width(), 20);
stepansnigirev 1:6fea6c7dce1c 277 titleLbl.position(0, 40);
stepansnigirev 1:6fea6c7dce1c 278 titleLbl.alignText(ALIGN_TEXT_CENTER);
stepansnigirev 1:6fea6c7dce1c 279
stepansnigirev 1:6fea6c7dce1c 280 Button btn(showAddressesCallback, "Show addresses");
stepansnigirev 1:6fea6c7dce1c 281 btn.size(gui.width()-100, 80);
stepansnigirev 1:6fea6c7dce1c 282 btn.position(0, 100);
stepansnigirev 1:6fea6c7dce1c 283 btn.align(ALIGN_CENTER);
stepansnigirev 1:6fea6c7dce1c 284
stepansnigirev 1:6fea6c7dce1c 285 Button btn2(saveXpubCallback, "Export xpub");
stepansnigirev 1:6fea6c7dce1c 286 btn2.size(gui.width()-100, 80);
stepansnigirev 1:6fea6c7dce1c 287 btn2.position(0, 300);
stepansnigirev 1:6fea6c7dce1c 288 btn2.align(ALIGN_CENTER);
stepansnigirev 1:6fea6c7dce1c 289
stepansnigirev 1:6fea6c7dce1c 290 Button btn3(signPSBTCallback, "Sign PSBT transaction");
stepansnigirev 1:6fea6c7dce1c 291 btn3.size(gui.width()-100, 80);
stepansnigirev 1:6fea6c7dce1c 292 btn3.position(0, 400);
stepansnigirev 1:6fea6c7dce1c 293 btn3.align(ALIGN_CENTER);
stepansnigirev 1:6fea6c7dce1c 294
stepansnigirev 1:6fea6c7dce1c 295 Button btn4(wipeCallback, "Wipe device");
stepansnigirev 1:6fea6c7dce1c 296 btn4.size(gui.width()-100, 80);
stepansnigirev 1:6fea6c7dce1c 297 btn4.position(0, 600);
stepansnigirev 1:6fea6c7dce1c 298 btn4.align(ALIGN_CENTER);
stepansnigirev 1:6fea6c7dce1c 299
stepansnigirev 1:6fea6c7dce1c 300 Button btn5(showMnemonicCallback, "Show mnemonic");
stepansnigirev 1:6fea6c7dce1c 301 btn5.size(gui.width()-100, 80);
stepansnigirev 1:6fea6c7dce1c 302 btn5.position(0, 700);
stepansnigirev 1:6fea6c7dce1c 303 btn5.align(ALIGN_CENTER);
stepansnigirev 1:6fea6c7dce1c 304 }
stepansnigirev 1:6fea6c7dce1c 305
stepansnigirev 1:6fea6c7dce1c 306 void showMessage(const string title, const string message){
stepansnigirev 1:6fea6c7dce1c 307 gui.clear();
stepansnigirev 1:6fea6c7dce1c 308 titleLbl = Label(title);
stepansnigirev 1:6fea6c7dce1c 309 titleLbl.size(gui.width(), 20);
stepansnigirev 1:6fea6c7dce1c 310 titleLbl.position(0, 40);
stepansnigirev 1:6fea6c7dce1c 311 titleLbl.alignText(ALIGN_TEXT_CENTER);
stepansnigirev 1:6fea6c7dce1c 312
stepansnigirev 1:6fea6c7dce1c 313 dataLbl = Label(message);
stepansnigirev 1:6fea6c7dce1c 314 dataLbl.size(gui.width()-100, 100);
stepansnigirev 1:6fea6c7dce1c 315 dataLbl.position(50, 300);
stepansnigirev 1:6fea6c7dce1c 316 dataLbl.alignText(ALIGN_TEXT_CENTER);
stepansnigirev 1:6fea6c7dce1c 317
stepansnigirev 1:6fea6c7dce1c 318 Button btn(toMenuCallback, "OK");
stepansnigirev 1:6fea6c7dce1c 319 btn.size(gui.width()-100, 80);
stepansnigirev 1:6fea6c7dce1c 320 btn.position(0, gui.height()-100);
stepansnigirev 1:6fea6c7dce1c 321 btn.align(ALIGN_CENTER);
stepansnigirev 1:6fea6c7dce1c 322 }
stepansnigirev 1:6fea6c7dce1c 323
stepansnigirev 1:6fea6c7dce1c 324 void showAddressScreen(){
stepansnigirev 1:6fea6c7dce1c 325 gui.clear();
stepansnigirev 1:6fea6c7dce1c 326 titleLbl = Label("Your address");
stepansnigirev 1:6fea6c7dce1c 327 titleLbl.size(gui.width(), 20);
stepansnigirev 1:6fea6c7dce1c 328 titleLbl.position(0, 40);
stepansnigirev 1:6fea6c7dce1c 329 titleLbl.alignText(ALIGN_TEXT_CENTER);
stepansnigirev 1:6fea6c7dce1c 330
stepansnigirev 1:6fea6c7dce1c 331 dataLbl = Label(" ");
stepansnigirev 1:6fea6c7dce1c 332 dataLbl.size(gui.width()-100, 100); // full width
stepansnigirev 1:6fea6c7dce1c 333 dataLbl.position(50, gui.height()-300);
stepansnigirev 1:6fea6c7dce1c 334 dataLbl.alignText(ALIGN_TEXT_CENTER);
stepansnigirev 1:6fea6c7dce1c 335
stepansnigirev 1:6fea6c7dce1c 336 qr = QR(" ");
stepansnigirev 1:6fea6c7dce1c 337 qr.size(gui.width()-100);
stepansnigirev 1:6fea6c7dce1c 338 qr.position(0, 100);
stepansnigirev 1:6fea6c7dce1c 339 qr.align(ALIGN_CENTER);
stepansnigirev 1:6fea6c7dce1c 340
stepansnigirev 1:6fea6c7dce1c 341 Button btn(nextCallback, "Next address");
stepansnigirev 1:6fea6c7dce1c 342 btn.size(gui.width()/3-20, 80);
stepansnigirev 1:6fea6c7dce1c 343 btn.position(gui.width()*2/3 + 10, gui.height()-100);
stepansnigirev 1:6fea6c7dce1c 344
stepansnigirev 1:6fea6c7dce1c 345 Button btn2(prevCallback, "Previous address");
stepansnigirev 1:6fea6c7dce1c 346 btn2.size(gui.width()/3-20, 80);
stepansnigirev 1:6fea6c7dce1c 347 btn2.position(10, gui.height()-100);
stepansnigirev 1:6fea6c7dce1c 348
stepansnigirev 1:6fea6c7dce1c 349 Button btn3(changeCallback, "Toggle\nchange");
stepansnigirev 1:6fea6c7dce1c 350 btn3.size(gui.width()/3-20, 80);
stepansnigirev 1:6fea6c7dce1c 351 btn3.position(gui.width()/3 + 10, gui.height()-100);
stepansnigirev 1:6fea6c7dce1c 352
stepansnigirev 1:6fea6c7dce1c 353 Button btn4(xpubCallback, "Show xpub");
stepansnigirev 1:6fea6c7dce1c 354 btn4.size(gui.width()/2-20, 80);
stepansnigirev 1:6fea6c7dce1c 355 btn4.position(gui.width()/2+10, gui.height()-200);
stepansnigirev 1:6fea6c7dce1c 356
stepansnigirev 1:6fea6c7dce1c 357 Button btn5(toMenuCallback, "Menu");
stepansnigirev 1:6fea6c7dce1c 358 btn5.size(gui.width()/2-20, 80);
stepansnigirev 1:6fea6c7dce1c 359 btn5.position(10, gui.height()-200);
stepansnigirev 1:6fea6c7dce1c 360 }
stepansnigirev 1:6fea6c7dce1c 361
stepansnigirev 1:6fea6c7dce1c 362 static lv_res_t toMenuCallback(lv_obj_t * btn){
stepansnigirev 1:6fea6c7dce1c 363 showMenu();
stepansnigirev 1:6fea6c7dce1c 364 return LV_RES_OK;
stepansnigirev 1:6fea6c7dce1c 365 }
stepansnigirev 1:6fea6c7dce1c 366
stepansnigirev 1:6fea6c7dce1c 367 static lv_res_t showAddressesCallback(lv_obj_t * btn){
stepansnigirev 1:6fea6c7dce1c 368 showAddressScreen();
stepansnigirev 1:6fea6c7dce1c 369 showAddress(child_index, change);
stepansnigirev 1:6fea6c7dce1c 370 return LV_RES_OK;
stepansnigirev 1:6fea6c7dce1c 371 }
stepansnigirev 1:6fea6c7dce1c 372
stepansnigirev 1:6fea6c7dce1c 373 static lv_res_t wipeCallback(lv_obj_t * btn){
stepansnigirev 1:6fea6c7dce1c 374 wipe();
stepansnigirev 1:6fea6c7dce1c 375 return LV_RES_OK;
stepansnigirev 1:6fea6c7dce1c 376 }
stepansnigirev 1:6fea6c7dce1c 377
stepansnigirev 1:6fea6c7dce1c 378 /*************** mnemonic stuff ***************/
stepansnigirev 1:6fea6c7dce1c 379
stepansnigirev 1:6fea6c7dce1c 380 static lv_res_t showMnemonicCallback(lv_obj_t * btn){
stepansnigirev 1:6fea6c7dce1c 381 string mnemonic = loadMnemonic();
stepansnigirev 1:6fea6c7dce1c 382 showMessage("Here is your recovery phrase:", mnemonic);
stepansnigirev 1:6fea6c7dce1c 383 return LV_RES_OK;
stepansnigirev 1:6fea6c7dce1c 384 }
stepansnigirev 1:6fea6c7dce1c 385
stepansnigirev 1:6fea6c7dce1c 386 static const char * keys[] = {"q","w","e","r","t","y","u","i","o","p","\n",
stepansnigirev 1:6fea6c7dce1c 387 "a","s","d","f","g","h","j","k","l","\n",
stepansnigirev 1:6fea6c7dce1c 388 " ","z","x","c","v","b","n","m","<",""};
stepansnigirev 1:6fea6c7dce1c 389
stepansnigirev 1:6fea6c7dce1c 390 static lv_res_t typeCallback(lv_obj_t * btn, const char * key){
stepansnigirev 1:6fea6c7dce1c 391 if(key[0] == '<'){
stepansnigirev 1:6fea6c7dce1c 392 if(mnemonic.length() > 0){
stepansnigirev 1:6fea6c7dce1c 393 mnemonic = mnemonic.substr(0,mnemonic.length()-1);
stepansnigirev 1:6fea6c7dce1c 394 }
stepansnigirev 1:6fea6c7dce1c 395 }else{
stepansnigirev 1:6fea6c7dce1c 396 mnemonic += key;
stepansnigirev 1:6fea6c7dce1c 397 }
stepansnigirev 1:6fea6c7dce1c 398 dataLbl.text(mnemonic);
stepansnigirev 1:6fea6c7dce1c 399 return LV_RES_OK;
stepansnigirev 1:6fea6c7dce1c 400 }
stepansnigirev 1:6fea6c7dce1c 401
stepansnigirev 2:8b42ea8491ae 402 static lv_res_t showInitScreenCallback(lv_obj_t * btn){
stepansnigirev 2:8b42ea8491ae 403 showInitScreen();
stepansnigirev 2:8b42ea8491ae 404 return LV_RES_OK;
stepansnigirev 2:8b42ea8491ae 405 }
stepansnigirev 2:8b42ea8491ae 406
stepansnigirev 1:6fea6c7dce1c 407 static lv_res_t enterMnemonicCallback(lv_obj_t * btn){
stepansnigirev 1:6fea6c7dce1c 408 gui.clear();
stepansnigirev 1:6fea6c7dce1c 409 mnemonic = "";
stepansnigirev 1:6fea6c7dce1c 410 titleLbl = Label("Enter your mnemonic");
stepansnigirev 1:6fea6c7dce1c 411 titleLbl.size(gui.width(), 20);
stepansnigirev 1:6fea6c7dce1c 412 titleLbl.position(0, 40);
stepansnigirev 1:6fea6c7dce1c 413 titleLbl.alignText(ALIGN_TEXT_CENTER);
stepansnigirev 1:6fea6c7dce1c 414
stepansnigirev 1:6fea6c7dce1c 415 dataLbl = Label(mnemonic);
stepansnigirev 1:6fea6c7dce1c 416 dataLbl.size(gui.width()-100, 50);
stepansnigirev 1:6fea6c7dce1c 417 dataLbl.position(50, 200);
stepansnigirev 1:6fea6c7dce1c 418 dataLbl.alignText(ALIGN_TEXT_CENTER);
stepansnigirev 1:6fea6c7dce1c 419
stepansnigirev 1:6fea6c7dce1c 420 Keyboard kb(typeCallback, keys);
stepansnigirev 1:6fea6c7dce1c 421 kb.size(gui.width(), gui.height()/3);
stepansnigirev 1:6fea6c7dce1c 422 kb.position(0, gui.height()*2/3-150);
stepansnigirev 1:6fea6c7dce1c 423
stepansnigirev 1:6fea6c7dce1c 424 Button btnx(checkMnemonicCallback, "Continue");
stepansnigirev 2:8b42ea8491ae 425 btnx.size(gui.width()/2-45, 80);
stepansnigirev 2:8b42ea8491ae 426 btnx.position(30+gui.width()/2, gui.height()-100);
stepansnigirev 2:8b42ea8491ae 427
stepansnigirev 2:8b42ea8491ae 428 Button btny(showInitScreenCallback, "Back");
stepansnigirev 2:8b42ea8491ae 429 btny.size(gui.width()/2-45, 80);
stepansnigirev 2:8b42ea8491ae 430 btny.position(30, gui.height()-100);
stepansnigirev 1:6fea6c7dce1c 431 return LV_RES_OK;
stepansnigirev 1:6fea6c7dce1c 432 }