如何開發(fā)一款以太坊(安卓)錢包系列1 - 通過助記詞創(chuàng)建賬號

最新內(nèi)容會(huì)更新在主站深入淺出區(qū)塊鏈社區(qū)
原文鏈接:以太坊(安卓)錢包系列1 - 通過助記詞創(chuàng)建賬號

上周我開源了一款錢包墩剖,反映很好,一周時(shí)間不到已經(jīng)快到100 Star痒筒。接下來我會(huì)幾篇系列文章把開發(fā)以太坊錢包的核心要點(diǎn)寫出來驱还,也算是對代碼的一個(gè)解讀凸克。

寫在前面

錢包是使用Android安卓平臺(tái)編寫闷沥,使用的是原生代碼Java 語言編寫, 是基于Java 1.8 版本舆逃,也使用了Java 1.8 中一些較新的語言特性蚂维,如 Lambda表達(dá)式等;另外還較多使用了ReactiveX/RxAndroid響應(yīng)式編程用法路狮。

在本系列文章中虫啥,重點(diǎn)是介紹以太坊錢包賬號、交易等邏輯奄妨,有時(shí)可能會(huì)假定讀者已經(jīng)了解Android開發(fā)等相關(guān)知識(shí)涂籽,因?yàn)檫@些內(nèi)容不是文章的重點(diǎn),因此不會(huì)過多介紹砸抛,請海涵评雌。

錢包包含的功能

通常一個(gè)錢包會(huì)包含以下功能:

  • [x] 支持通過生成助記詞、Keystore文件直焙、私鑰 創(chuàng)建錢包賬號景东。
  • [x] 支持導(dǎo)出錢包賬號助記詞、私鑰奔誓、Keystore文件斤吐。
  • [x] 支持多個(gè)錢包賬號管理
  • [x] 賬戶余額查詢及轉(zhuǎn)賬功能(二維碼掃描支持)。
  • [x] 支持ERC20 代幣(余額顯示厨喂、轉(zhuǎn)賬和措、代幣幣價(jià)顯示)
  • [x] 支持用法幣(美元和人民幣)實(shí)時(shí)顯示幣價(jià)。
  • [x] 歷史交易列表顯示

創(chuàng)建賬號預(yù)備知識(shí)

我們先來介紹第一個(gè)功能:通過生成助記詞杯聚、Keystore文件臼婆、私鑰創(chuàng)建錢包賬號。
本系列中幌绍,錢包都是指分層確定性錢包颁褂,(HD錢包 Hierarchical Deterministic Wallets)故响, 之前博客有一篇文章分層錢包進(jìn)行了詳細(xì)的介紹,還不熟悉的可以讀一下颁独。
為了保持本文的完整彩届,這里做一個(gè)總結(jié)性回顧:以太坊及比特幣的地址是由隨機(jī)生成的私鑰經(jīng)過橢圓曲線等算法單向推倒而來 ,BIP32及BIP44是為方便管理私鑰提出的分層推倒方案誓酒,BIP39 定義助記詞讓分層種子的備份更方便樟蠕。
而KeyStore文件是用來解密以太坊保存私鑰的一種方式,大家可以閱讀下這篇文章: 賬號Keystore文件導(dǎo)入導(dǎo)出了解更多靠柑。

實(shí)現(xiàn)完成的寨辩,界面如下圖:

image

這是一張導(dǎo)入錢包賬號的截圖(導(dǎo)入和創(chuàng)建,其實(shí)原理一樣)歼冰,界面仿照ImToken靡狞,不過本文將不會(huì)介紹UI部分的編寫。

Web3j & bitcoinj

為了完成創(chuàng)建賬號功能隔嫡,我們需要使用到兩個(gè)庫:Web3jbitcoinj

Web3是一套和以太坊通信的封裝庫腮恩,Web3j是Java版本的實(shí)現(xiàn),例如發(fā)起交易和智能合約進(jìn)行交互武契,下圖很好的表達(dá)了其作用荡含。


image

不過本文中的功能内颗,主要是使用了web3j中橢圓曲線加密及KeyStore文件的生成與解密。

bitcoinj 的功能和web3類似恨溜,它是比特幣協(xié)議的Java實(shí)現(xiàn)糟袁,他實(shí)現(xiàn)了 BIP32躺盛、BIP44及BIP39 相關(guān)協(xié)議。

Android使用Gradle來構(gòu)建周叮,直接在app/build.gradle文件中加入:

implementation 'org.web3j:core:4.1.0-android'
implementation 'org.bitcoinj:bitcoinj-core:0.14.7'

提示: 實(shí)踐中遇到的一個(gè)問題,由于bitcoinj 中引入了 com.lambdaworks:scrypt加密庫合冀, 它包含的lib/x86_64/darwin/libscrypt.dylib文件项贺,會(huì)導(dǎo)致在進(jìn)行Android App Bundle 編譯時(shí)會(huì)出現(xiàn)錯(cuò)誤(好像也會(huì)導(dǎo)致某些機(jī)型沒法安裝),解決辦法是在 build.gradle 加入一下語句棕叫,把這個(gè)文件在打包時(shí)排除掉奕删。
packagingOptions {
exclude 'lib/x86_64/darwin/libscrypt.dylib'
}

創(chuàng)建賬號實(shí)現(xiàn)

通過助記詞常見錢包賬號

這是目前錢包客戶端急侥,最常見的一種為用戶常見賬號的方式坏怪,這里會(huì)包含一下幾個(gè)核心步驟:

  1. 生成一個(gè)隨機(jī)數(shù)種子绊茧;
  2. 通過隨機(jī)數(shù)種子得到助記詞;
  3. 通過 種子 + 路徑 派生生成私鑰鹏秋;
  4. 使用KeyStore保存私鑰亡笑;
  5. 私鑰推倒出賬號地址。

大家可以在再次閱讀分層錢包百拓,理解為何這么做的原因。

理解了上面幾點(diǎn)衙传,那么代碼就容易明白了厕九,代碼在代碼庫中的app/src/pro/upchain/wallet/utils/ETHWalletUtils.java中,關(guān)鍵代碼邏輯如下:

    // 創(chuàng)建錢包對象入口函數(shù)
    public static ETHWallet generateMnemonic(String walletName, String pwd) {
        String[] pathArray = "m/44'/60'/0'/0/0".split("/");

        long creationTimeSeconds = System.currentTimeMillis() / 1000;

        SecureRandom secureRandom = SecureRandomUtils.secureRandom();
        DeterministicSeed ds = new DeterministicSeed(secureRandom, 128, "", creationTimeSeconds);

        return generateWalletByMnemonic(walletName, ds, pathArray, pwd);
    }

    /**
     * @param walletName 錢包名稱
     * @param ds         助記詞加密種子
     * @param pathArray  助記詞標(biāo)準(zhǔn)
     * @param pwd        密碼
     * @return
     */
    @Nullable
    public static ETHWallet generateWalletByMnemonic(String walletName, DeterministicSeed ds,
                                                     String[] pathArray, String pwd) {
        //種子
        byte[] seedBytes = ds.getSeedBytes();
        //助記詞
        List<String> mnemonic = ds.getMnemonicCode();

        if (seedBytes == null)
            return null;

        //  衍生推倒key
        DeterministicKey dkKey = HDKeyDerivation.createMasterPrivateKey(seedBytes);
        for (int i = 1; i < pathArray.length; i++) {
            ChildNumber childNumber;
            if (pathArray[i].endsWith("'")) {
                int number = Integer.parseInt(pathArray[i].substring(0,
                        pathArray[i].length() - 1));
                childNumber = new ChildNumber(number, true);
            } else {
                int number = Integer.parseInt(pathArray[i]);
                childNumber = new ChildNumber(number, false);
            }
            dkKey = HDKeyDerivation.deriveChildKey(dkKey, childNumber);
        }

        ECKeyPair keyPair = ECKeyPair.create(dkKey.getPrivKeyBytes());
        ETHWallet ethWallet = generateWallet(walletName, pwd, keyPair);
        if (ethWallet != null) {
            ethWallet.setMnemonic(convertMnemonicList(mnemonic));
        }
        return ethWallet;
    }

        @Nullable
    private static ETHWallet generateWallet(String walletName, String pwd, ECKeyPair ecKeyPair) {
        WalletFile keyStoreFile;
        try {
            keyStoreFile = Wallet.create(pwd, ecKeyPair, 1024, 1); // WalletUtils. .generateNewWalletFile();
        } catch (Exception e) {
            e.printStackTrace();
            return null;
        }

        BigInteger publicKey = ecKeyPair.getPublicKey();
        String s = publicKey.toString();

        String wallet_dir = AppFilePath.Wallet_DIR;

        String keystorePath = "keystore_" + walletName + ".json";
        File destination = new File(wallet_dir, "keystore_" + walletName + ".json");

        //目錄不存在則創(chuàng)建目錄,創(chuàng)建不了則報(bào)錯(cuò)
        if (!createParentDir(destination)) {
            return null;
        }
        try {
            objectMapper.writeValue(destination, keyStoreFile);
        } catch (IOException e) {
            e.printStackTrace();
            return null;
        }

        ETHWallet ethWallet = new ETHWallet();
        ethWallet.setName(walletName);
        ethWallet.setAddress(Keys.toChecksumAddress(keyStoreFile.getAddress()));
        ethWallet.setKeystorePath(destination.getAbsolutePath());
        ethWallet.setPassword(Md5Utils.md5(pwd));
        return ethWallet;
    }

上述代碼中亭引,generateMnemonic()是入口函數(shù),最終返回的是一個(gè)ETHWallet 自定義的錢包實(shí)體類焙蚓,一個(gè)實(shí)例就對應(yīng)一個(gè)錢包,ETHWallet保存了錢包相關(guān)的屬性萌京,后面會(huì)詳細(xì)介紹宏浩,如果對它序列化保存錢包賬號及多個(gè)錢包賬號管理。

幾個(gè)注意事項(xiàng)

關(guān)于助記詞及私鑰的保存求妹,有幾點(diǎn)要特別注意制恍,否則有可能和其他錢包無法兼容或?qū)е滤借€泄漏神凑。

這部分作為訂閱者福利,發(fā)表在我的小專欄鹃唯,趁還未漲價(jià)瓣喊,趕緊訂閱吧,超值的八匠!

參考文檔

加入知識(shí)星球趴酣,和一群優(yōu)秀的區(qū)塊鏈從業(yè)者一起學(xué)習(xí)。
深入淺出區(qū)塊鏈 - 系統(tǒng)學(xué)習(xí)區(qū)塊鏈抡四,打造最好的區(qū)塊鏈技術(shù)博客。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末淑履,一起剝皮案震驚了整個(gè)濱河市秘噪,隨后出現(xiàn)的幾起案子勉耀,更是在濱河造成了極大的恐慌,老刑警劉巖至壤,帶你破解...
    沈念sama閱讀 222,378評論 6 516
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件像街,死亡現(xiàn)場離奇詭異晋渺,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī)畴栖,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 94,970評論 3 399
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來挪挤,“玉大人,你說我怎么就攤上這事鸠信⌒橇ⅲ” “怎么了?”我有些...
    開封第一講書人閱讀 168,983評論 0 362
  • 文/不壞的土叔 我叫張陵绰垂,是天一觀的道長劲装。 經(jīng)常有香客問我占业,道長,這世上最難降的妖魔是什么谦疾? 我笑而不...
    開封第一講書人閱讀 59,938評論 1 299
  • 正文 為了忘掉前任念恍,我火速辦了婚禮,結(jié)果婚禮上仗考,老公的妹妹穿的比我還像新娘秃嗜。我一直安慰自己,他們只是感情好锅锨,可當(dāng)我...
    茶點(diǎn)故事閱讀 68,955評論 6 398
  • 文/花漫 我一把揭開白布必搞。 她就那樣靜靜地躺著囊咏,像睡著了一般。 火紅的嫁衣襯著肌膚如雪霜第。 梳的紋絲不亂的頭發(fā)上泌类,一...
    開封第一講書人閱讀 52,549評論 1 312
  • 那天底燎,我揣著相機(jī)與錄音,去河邊找鬼双仍。 笑死,一個(gè)胖子當(dāng)著我的面吹牛晴玖,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播让簿,決...
    沈念sama閱讀 41,063評論 3 422
  • 文/蒼蘭香墨 我猛地睜開眼尔当,長吁一口氣:“原來是場噩夢啊……” “哼蹂安!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起畜号,我...
    開封第一講書人閱讀 39,991評論 0 277
  • 序言:老撾萬榮一對情侶失蹤简软,失蹤者是張志新(化名)和其女友劉穎述暂,沒想到半個(gè)月后畦韭,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 46,522評論 1 319
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡察郁,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 38,604評論 3 342
  • 正文 我和宋清朗相戀三年皮钠,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了鳞芙。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片期虾。...
    茶點(diǎn)故事閱讀 40,742評論 1 353
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡镶苞,死狀恐怖陈惰,靈堂內(nèi)的尸體忽然破棺而出聋涨,到底是詐尸還是另有隱情,我是刑警寧澤脊凰,帶...
    沈念sama閱讀 36,413評論 5 351
  • 正文 年R本政府宣布狸涌,位于F島的核電站,受9級特大地震影響帕胆,放射性物質(zhì)發(fā)生泄漏懒豹。R本人自食惡果不足惜诊杆,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 42,094評論 3 335
  • 文/蒙蒙 一晨汹、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧剥扣,春花似錦铝穷、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,572評論 0 25
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽稳衬。三九已至,卻和暖如春薄疚,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背砰碴。 一陣腳步聲響...
    開封第一講書人閱讀 33,671評論 1 274
  • 我被黑心中介騙來泰國打工衣式, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留碴卧,地道東北人乃正。 一個(gè)月前我還...
    沈念sama閱讀 49,159評論 3 378
  • 正文 我出身青樓瓮具,卻偏偏與公主長得像荧飞,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個(gè)殘疾皇子名党,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,747評論 2 361

推薦閱讀更多精彩內(nèi)容