Minimum Viable Ethereum Mobile Wallet – Part 3: Account & Private Key

This is part 3 of the step-by-step tutorial to walk the reader through the development of a Minimum Viable Ethereum Mobile Wallet in React Native. I call it the Minimum Viable Wallet or MVW in short.

MVW’s source codes can be found here.

In this part, I will explain the codes that lets me create a new Ethereum Wallet account and how I secure my private key in the mobile device.

Tutorial Structure

This tutorial is a work in progress. When done, it will come in 4 parts.

  • Part 1: For folks who just want to test MVW, I wrote about how MVW works here.
  • Part 2: For folks who want to build an MVW from codes, I will explain how it is done and the libraries that I used. 
  • Part 3: In this part, I will explain the codes behind wallet account creation and private key storage. Keep reading.
  • Part 4: I will walk through the codes for reading from and running a smart contract within the app. 

I will keep adding new parts as I write them. So check back often.

Creating a New Account

Account creation is done by pressing the [Create Account] button on the home screen. This is how it looks.

Here’s the score codes for the home screen.

The user presses [Create Account] and the following codes are executed:

  _handleSubmit = async (values, bag) => {
    var x = global.web3.eth.accounts.create(web3.utils.randomHex(32));
    await Expo.SecureStore.setItemAsync('key', x.privateKey.substring(2));
    await Expo.SecureStore.setItemAsync('wallet', x.address);
    this.setState({address: x.address});
    this.setState({key: x.privateKey.substring(2)});
    console.log("myaddress:" + x.address);
    console.log("mykey:" + x.privateKey.substring(2));
  };

The function web3.utils.randomHex(32) generates a pseudo-random HEX string of 32 byte.

The function web3.eth.accounts.create() generates an account object using this HEX string. The account object contains 2 properties, the account’s address and its private key. In Ethereum, your account’s address lets others on the Ethereum blockchain network know who you are. Your account’s private key lets you unlock your account so that you can use it to sign transactions on the Ethereum blockchain network. 

At this stage, nothing has happened on the Ethereum blockchain network – no one on the Ethereum network knows that this wallet address exist, not until you fund it with ETH or use it to sign a transaction.

But wait a moment, if this step doesn’t check the Ethereum blockchain for duplicity, what happens if someone else runs this function and end up with the same wallet address? The answer is that the chance of a coincidence (or collision) is extremely low The reason goes back to how web3.utils.randomHex generates pseudo-random HEX strings. In MVW, this pseudo-random HEX string is generated with the JavaScript Math.random() function in random.bytes.js. There’s a good article describing how Math.random() works here. Some will argue that Math.random() isn’t truly random. Randomness depends largely on how a seed value is chosen. I have written about the challenge of Pseudo Random Number Generator (PRNG) in an article about developing a lottery system as a smart contract here. So let’s assume that this all works out and we successfully generate a unique Wallet address and a corresponding private key. 

Next, we need to store the private key in a secure storage area in our mobile device because anyone who possesses your private key can sign transactions and send ETH with your account. In MVW, I keep the private key and address with Expo.SecureStore, which is Expo.io‘s encrypted storage system that keeps data securely stored in a separate storage system that no other apps in your mobile device has access to. 

Expo.SecureStore.setItemAsync('key', x.privateKey.substring(2)) stores the private key as ‘key’ and Expo.SecureStore.setItemAsync('wallet', x.address) stores the wallet address as ‘wallet’.

Finally this.setState({address: x.address}) updates the address state with this address and this.setState({key: x.privateKey.substring(2)}) updates the privateKey state with the private key.

<Text>Wallet: {this.state.address}</Text>
<Text>Key: {this.state.key}</Text>

In MVW, I also display both the wallet address and its private key on the screen. You probably don’t want to do this in an actual implementation since it exposes the private key for everyone to see.

Changing Wallet Properties

In MVW, I also developed a Properties screen that lets you change your wallet address, its private key and the address of the default Smart Contract that MVW executes.

Here’s the score code.

  _fetchData = async () => {

    const keystore = await Expo.SecureStore.getItemAsync('key');
    if (keystore !== null) {
      this.setState({key: keystore});
      console.log(keystore);
    }

    const walletstore = await Expo.SecureStore.getItemAsync('wallet');
    if (walletstore !== null) {
      this.setState({wallet: walletstore});
      console.log(walletstore);
    }

    console.log(this.state.key);
    console.log(this.state.wallet);
  };

_fetchData attempts to retrieve ‘key’ and ‘wallet’ from Expo.SecureStore and if it does so successfully, it saves the value in this screen’s ‘key’ and ‘wallet’ state. This work is done by Expo.SecureStore.getItemAsync('key') and Expo.SecureStore.getItemAsync('wallet') which retrieves ‘key’ and ‘wallet’ from secure storage.

  _handleSubmit = async (values, bag) => {
    try {
      try {
        await Expo.SecureStore.setItemAsync('address', values.address);
        await Expo.SecureStore.setItemAsync('key', values.key);
        await Expo.SecureStore.setItemAsync('wallet', values.walletaddress);
        Alert.alert('Saved!');
      } catch (error) {
        // Error saving data
        console.log(error);
      }
    } catch (error) {
      bag.setSubmitting(false);
      bag.setErrors(error);
    }
  };

_handleSubmit is trigger when the user presses the [Save] button. It writes the new values of values.walletaddress, values.address and values.key from the text fields in the form to each corresponding Expo.SecureStore storage.

This work is done by Expo.SecureStore.setItemAsync('address', values.address), Expo.SecureStore.setItemAsync('key', values.key) and Expo.SecureStore.setItemAsync('wallet', values.walletaddress)

What’s Next?

In the next part, I will walk through the codes to read from and write to a Smart contract using this wallet address.

Photo by NeONBRAND on Unsplash