Android以太坊钱包全部功能-基于web3j实现
文章目录
- 需要用到的工具
- Ganache
- Metamask
- 钱包功能的具体实现
- 引入依赖
- 创建钱包
- 第一种创建方式
- 第二种创建方式
- keystore导入钱包
- 助记词导入钱包
- 私钥导入钱包
- Ganache环境
- 链接infura第三方私链
- 以太坊钱包转账
- 监听交易
- 查询余额
- 查看交易详情
- 智能合约
- 查询交易记录
这段时间学习了利用web3j来实现Android以太坊钱包的功能。所以这里做一些相关记录,方便以后查看。
需要用到的工具
用工具的目的就是为了测试方便,可以切换到自己的私链或者第三方的测试链,因为不能把所有的操作都放在以太坊公网去实现,毕竟那是实打实的以太坊币。
Ganache
它的安装比较简单,一直下一步就行
安装好之后如图:
它会提供10个账户 每个有100个以太币,而且可以在里面轻松的看到一些交易的纪录和交易详情。
Metamask
Metamask是一个基于Chorme的插件,它最方便的是可以切换不同的测试链还可以添加自定义的私链,如图:
Main Ethereum :表示以太坊公网,也就是正式环境
Ropsten、Kovan和Rinkeby都是Infura提供的测试链,Infura的使用也很简单,注册登录创建项目之后就可以看到如图:
创建好之后就需要往里面充以太币目前我只用到了Ropsten和Kovan。
Ropsten可以在Metamask中完成充值,具体步骤如下:
至此可以开心的在Ropsten测试环境进行转账和交易查询等操作了。
Kovan的充值有两种方式:
具体参考
:Kovan充值以太币
大概就是在这个网址https://gitter.im/kovan-testnet/faucet发送一个你需要充值的账户地址,然后就是等……
上面这几种工具基本就可以满足现目前的以太坊钱包开发的基本功能了,下面开始具体的钱包功能开发。
钱包功能的具体实现
引入依赖
需要用到的依赖不多,就一个web3j和一个用于生成助记词的库,之所以引入第二个库是因为web3j提供的生成助记词的MnemonicUtils.generateMnemonic()一直报错,目前还没找到解决的办法。
implementation 'org.web3j:core:3.3.1-android'implementation 'io.github.novacrypto:BIP39:0.1.9'//用于生成助记词
按我现在的理解,各个环境创建的钱包都可以互相导入,只是里面的以太币不通用,所以在创建钱包和导入钱包的环节都还是使用以太坊主网。
创建钱包
创建钱包目前找到两种实现方式
第一种创建方式
可以获取到钱包的私钥、keystore、address等信息,但是没找到获取助记词的方法,实现方式如下:
//钱包密码pwd = mEdPasswd.getText().toString().trim();try {File fileDir = new File(Environment.getExternalStorageDirectory().getPath() + "/MyWallet");if (!fileDir.exists()) {fileDir.mkdirs();}ECKeyPair ecKeyPair = Keys.createEcKeyPair();//keystore文件名String filename = WalletUtils.generateWalletFile(pwd, ecKeyPair, fileDir, false);//获取keystore内容File KeyStore = new File(Environment.getExternalStorageDirectory().getPath() + "/MyWallet/" + filename);Log.e("+++","keystore:"+getDatafromFile(KeyStore.getAbsolutePath()));String msg = "fileName:\n" + filename+ "\nprivateKey:\n" + Numeric.encodeQuantity(ecKeyPair.getPrivateKey())+ "\nPublicKey:\n" + Numeric.encodeQuantity(ecKeyPair.getPublicKey());Log.e("+++", "create:" + msg);} catch (Exception e) {e.printStackTrace();}
创建成功后打印信息:
create:fileName:UTC--2018-09-18T22-06-27.233--01e2a527948f35514b1bd2ddbb6023c7757c3254.jsonprivateKey:0x44fd9b00d0e17ccd0c414f0fe3d72c8a6c1b89a3e50d9ef0a267673d150ca1bbPublicKey:0xf91431f4deda321070ddb0b3836a8ed92caec4ec735bd4f71916f8de416b0b1361b95584a6042a121bad8bed8cab6e19e176fddbf763cf9c99e4ea4382513f54
第二种创建方式
这种创建方式可以获取到钱包的全部信息,代码如下:
File fileDir = new File(Environment.getExternalStorageDirectory().getPath() + "/MyWallet");if (!fileDir.exists()) {fileDir.mkdirs();}StringBuilder sb = new StringBuilder();byte[] entropy = new byte[Words.TWELVE.byteLength()];new SecureRandom().nextBytes(entropy);new MnemonicGenerator(English.INSTANCE).createMnemonic(entropy, sb::append);String mnemonics = sb.toString();android.util.Log.e("+++","生成的助记词:"+mnemonics);//password为输入的钱包密码byte[] seed = MnemonicUtils.generateSeed(mnemonics, password);ECKeyPair privateKey = ECKeyPair.create(sha256(seed));String walletFile = null;try {walletFile = generateWalletFile(password, privateKey, fileDir, false);} catch (CipherException e) {e.printStackTrace();} catch (IOException e) {e.printStackTrace();}Bip39Wallet bip39Wallet = new Bip39Wallet(walletFile, mnemonics);Log.e("+++",bip39Wallet.getFilename());keystore = getDatafromFile(new File(Environment.getExternalStorageDirectory().getPath() + "/MyWallet/"+bip39Wallet.getFilename()).getAbsolutePath());Log.e("+++","keystore:"+keystore);//导入助记词获取钱包地址Credentials credentials = WalletUtils.loadBip39Credentials(password,bip39Wallet.getMnemonic());Log.e("+++","导入助记词获取钱包地址:"+credentials.getAddress());String msg = "\n助记词:\n" + bip39Wallet.getMnemonic()+"\naddress:\n" + credentials.getAddress()+ "\nprivateKey:\n" + Numeric.encodeQuantity(credentials.getEcKeyPair().getPrivateKey())+ "\nPublicKey:\n" + Numeric.encodeQuantity(credentials.getEcKeyPair().getPublicKey());mTvMsg.setText(msg);Log.e("+++",msg);
打印信息 :
09-18 22:37:14.030 8963-8963/com.my.eth_demo E/+++: 助记词:shine creek tragic unable admit disease oil result various gun kingdom shopaddress:0xc5bbd2ea03eaa5e94a3af8bb4d8bfc178f837de3privateKey:0xa4756509c9c58cb5165f74797c50c4a2eddc160eade08989b1403755cfdf6e60PublicKey:0x8c7891f319582bf9bc653e3032be4406666e86938e4b860e28bc08b272f080306fcdbbbad5754b88a7dd90ad054b3ac4c9c40facda15c27b60180b27376f2ba9
注意上面两种都需要开启文件权限。
总结一下钱包提到的几个关键词语,钱包密码、助记词、私钥、地址、公钥,借助网上的一段描述:
若以银行账户为类比,这 5 个词分别对应内容如下:
地址=银行卡号
密码=银行卡密码
私钥=银行卡号+银行卡密码
助记词=银行卡号+银行卡密码
Keystore+密码=银行卡号+银行卡密码
Keystore ≠ 银行卡号
到这里两种钱包的创建方式都已经实现了,但还是有两点疑问
1、第一种方式创建的钱包为什么获取不到助记词?
2、第二种方式中的助记词生成方式是否能行?
keystore导入钱包
keystore导入钱包需要keystore和密码,代码如下:
String password = mEdPasswd.getText().toString().trim();String keystore = mEdKeyStore.getText().toString().trim();ObjectMapper objectMapper = new ObjectMapper();objectMapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);WalletFile walletFile = null;try {walletFile = objectMapper.readValue(keystore, WalletFile.class);} catch (IOException e) {e.printStackTrace();}try {ECKeyPair keyPair = Wallet.decrypt(password, walletFile);WalletFile generateWalletFile = Wallet.createLight(password, keyPair);Log.e("+++","keyStoreImportAddress:"+generateWalletFile.getAddress());mTvMsg.setText("Address:"+generateWalletFile.getAddress());MyApplication.wallets.add(generateWalletFile.getAddress());} catch (CipherException e) {e.printStackTrace();}
打印信息:
09-18 22:47:19.046 18531-18531/com.my.eth_demo E/+++: keyStoreImportAddress:d62a21fb6771858f6bf0bd1a83b583ec3bbe08faprivatekey:77352659602195464805734571732795606172527138956341173026077776154531522435270
助记词导入钱包
助记词导入钱包需要助记词,这里提供的密码相当于重置钱包密码
String menmory = mEdMemory.getText().toString().trim();String passwd = mEdPasswd.getText().toString().trim();List mnemonicList = Arrays.asList(menmory.split(" "));byte[] seed = new SeedCalculator().withWordsFromWordList(English.INSTANCE).calculateSeed(mnemonicList, passwd);ECKeyPair ecKeyPair = ECKeyPair.create(Sha256.sha256(seed));String privateKey = ecKeyPair.getPrivateKey().toString(16);String publicKey = ecKeyPair.getPublicKey().toString(16);String address = "0x" + Keys.getAddress(publicKey);//创建钱包地址与密钥String fileName = null;try {fileName = WalletUtils.generateWalletFile(passwd, ecKeyPair, new File(Environment.getExternalStorageDirectory().getPath() + "/MyWallet"), false);} catch (Exception e) {e.printStackTrace();}Log.e("+++","privateKey:"+privateKey);Log.e("+++","address:"+address);
打印信息:
09-19 21:09:34.218 24695-24695/com.my.eth_demo E/+++: privateKey:2604bcf5fed76ce9bfd2056829594a5b77b702862f7effb1651f6b0218b6daebaddress:0x92f1d2317c1353ad112dfb4c36ccabbd5fbb523a
私钥导入钱包
私钥导入只需要钱包私钥
Credentials credentials = Credentials.create(privateKey);ECKeyPair ecKeyPair = credentials.getEcKeyPair();KeyStoreUtils.genKeyStore2Files(ecKeyPair);String msg = "address:\n" + credentials.getAddress()+ "\nprivateKey:\n" + Numeric.encodeQuantity(ecKeyPair.getPrivateKey())+ "\nPublicKey:\n" + Numeric.encodeQuantity(ecKeyPair.getPublicKey());Log.e("+++", "daoru:" + msg);
打印信息:
09-18 22:51:56.669 20830-20830/com.my.eth_demo E/+++: daoru:address:0x20bd719345dcc624dc43b30e893eac21099a2ab0privateKey:0xec8559f8e38ed088f56c328f71753b296d43958b4d64a0b906147b5bffca0279PublicKey:0x7591a2d625bc9d08ab9b161834f5055368082e7d40a894bf968ab7b07e7ace6ed418388fa608fe6d1c057b9fcac3a03467145edbcac5cae0b7249a4a05666901
Ganache环境
Ganache的安装很简单,安装完成后上面会有一个RPC SERVER,默认HTTP://127.0.0.1:7545,如果需要链接到这个环境只需要在web3j做如下配置:
//本机ip
Web3j web3j = Web3jFactory.build(new HttpService("http://xxx.xxx.xx.xxx:7545"))
链接infura第三方私链
Infura提供了多种测试链这里以Ropsten为例,在这个测试链上做一个0.01以太币的转账,然后在Etherscan上查看转账情况。
//切换到Ropsten环境Web3j web3j = Web3jFactory.build(new HttpService("https://ropsten.infura.io/v3/b1a395a114ba485586c43d0fa227d443"));//目标账户String toAddress = "0x2B3e66B96924a170c4367e564C6638F28a620110";//转出账户Credentials credentials1 = Credentials.create("D3F293CC53D86F1B93A16E873FEAD44BA14F0E50987719307318A21A0A7C21D1");//通过提供的Transfer进行转账TransactionReceipt transactionReceipt = null;try {transactionReceipt = Transfer.sendFunds(web3j, credentials1, toAddress,BigDecimal.valueOf(0.01), Convert.Unit.ETHER).send();} catch (Exception e) {e.printStackTrace();}Log.e("+++","第三方私链转账Hash:"+transactionReceipt.getTransactionHash());
打印信息:
09-19 21:23:02.997 28951-30330/com.my.eth_demo E/+++: 第三方私链转账Hash:0xd5ddeaf77dad663493c90bd1f9f7f98813cdfae32d65e447d23ab8e89f12df08
然后在Etherscan上查看交易记录:
至此已经链接到Ropsten测试链上,并且进行了一笔以太币转账交易。
以太坊钱包转账
上面就已经成功链接到Ropsten测试链上并且进行了一笔交易,再记录一下另一种以太币转账方法,暂时无法区分二者的区别,先转3个以太币:
EthGetTransactionCount ethGetTransactionCount = null;try {ethGetTransactionCount = web3j.ethGetTransactionCount(fromAddress, DefaultBlockParameterName.LATEST).sendAsync().get();} catch (InterruptedException e) {e.printStackTrace();} catch (ExecutionException e) {e.printStackTrace();}BigInteger nonce = ethGetTransactionCount.getTransactionCount();RawTransaction rawTransaction = RawTransaction.createEtherTransaction(nonce, Convert.toWei("18", Convert.Unit.GWEI).toBigInteger(),Convert.toWei("45000", Convert.Unit.WEI).toBigInteger(), toAddress, new BigInteger("3000000000000000000"));byte[] signedMessage = TransactionEncoder.signMessage(rawTransaction, credentials);String hexValue = Numeric.toHexString(signedMessage);EthSendTransaction ethSendTransaction = null;try {ethSendTransaction = web3j.ethSendRawTransaction(hexValue).sendAsync().get();} catch (InterruptedException e) {e.printStackTrace();} catch (ExecutionException e) {e.printStackTrace();}if (ethSendTransaction.hasError()) {Log.e("+++transfer error:", ethSendTransaction.getError().getMessage());} else {String transactionHash = ethSendTransaction.getTransactionHash();Log.e("+++transactionHash:", ""+ transactionHash);}
一样到Etherscan上查看转账记录:
监听交易
当有交易发生时会触发,可以查看交易信息。
//监听交易web3j.transactionObservable().subscribe(new Subscriber<Transaction>() {@Overridepublic void onCompleted() {}@Overridepublic void onError(Throwable e) {}@Overridepublic void onNext(Transaction transaction) {Log.e("+++",""+transaction);}});
查询余额
//查询余额DefaultBlockParameter defaultBlockParameter = new DefaultBlockParameterNumber(13);EthGetBalance ethGetBalance = null;try {ethGetBalance = web3j.ethGetBalance("0x38B4D9fe0aC062AC09Cc7a6FB45Ba9319c6B688e", DefaultBlockParameterName.LATEST).send();Log.e("+++","balance:"+Convert.fromWei(ethGetBalance.getBalance().toString(), Convert.Unit.ETHER));} catch (IOException e) {e.printStackTrace();}
查看交易详情
//获取交易详情try {org.web3j.protocol.core.methods.response.Transaction transactionResult = web3j.ethGetTransactionByHash(transactionReceipt.getTransactionHash()).send().getResult();Log.e("+++","交易详情:"+transactionResult.getFrom());} catch (IOException e) {e.printStackTrace();}
详情可以获取到的信息如图:
智能合约
可以通过web3j去写智能合约,也可以通过solidity写智能合约,然后通过web3j转换成java文件来实现,具体步骤如下:
1、下载web3j命令行
2、安装solc
npm install -g solc
3、编写智能合约
pragma solidity ^0.4.0;contract SimpleStorage {uint storedData;function set(uint x) public {storedData = x;}function get() public view returns (uint) {return storedData;}
}
4、生成bin和abi文件
solcjs myContract.sol --optimize --bin --abi --output-dir C:\Users\wangc\Desktop\
5、切换到web3j命令行工具的bin目录下,生成java文件:
web3j solidity generate C:\Users\wangc\Desktop\myContract_sol_myContract.bin C:\Users\wangc\Desktop\myContract_sol_myContract.abi -o C:\Users\wangc\Desktop\ -p com.my.contract
6、将java文件放入项目中使用
//智能合约调用try {MyContract_sol_myContract contract = MyContract_sol_myContract.deploy(web3j, credentials1, GAS_PRICE, GAS_LIMIT).send();Log.e("+++","智能合约地址:"+contract.getContractAddress());Object o2 = contract.set(new BigInteger("1")).send();Log.e("+++","智能合约获取:"+contract.get());} catch (Exception e) {e.printStackTrace();}
打印信息:
09-19 22:26:05.802 18270-19185/com.dajiabao.eth_demo E/+++: 智能合约地址:0xe36f4dd87295aa33364c268029d64330422bb5e6
09-19 22:27:40.441 18270-19185/com.dajiabao.eth_demo E/+++: 智能合约获取:org.web3j.protocol.core.RemoteCall@69ceb67
一个简单的智能合约调用也完成了。其实主要的还是solidity编写智能合约部分,后面的就是流程式的调用
查询交易记录
暂时还没做
Android以太坊钱包的大概功能就了解这么多,目前还需要了解的有如何进行代币的转账,以及前面提到的几个疑问。
主要还是要多花点事件研究solidity编写智能合约。
Android以太坊钱包全部功能-基于web3j实现相关推荐
- 使用web3j构建以太坊钱包
创建一个以太坊钱包有多种方式,一般情况下可以通过geth.EtherumWallet等客户端.对于前端,可以使用插件MetaMask进行创建.这几种方式技术实现虽然不同,但底层原理是一致的.本文主要介 ...
- 登链钱包(一款功能强大的以太坊钱包)完全开源
你是否和我前段时间一样,苦苦的寻找一款好用的开源以太坊钱包,你会发现可用都很少,因为很多钱包说开源,仅仅是开源部分代码,现在不需要再找了, 登链钱包完全开源,登链钱包完全开源,登链钱包完全开源,重要的 ...
- Python如何从私钥创建以太坊钱包地址!
从私钥创建比特币钱包地址有点复杂.在这里,我们会使过程更加简单化.我们需要应用一个哈希函数来获取公钥,另一个哈希函数来获取地址.让我们开始吧. 公钥 我们需要做的第一件事是将ECDSA或椭圆曲线数字签 ...
- 以太坊钱包1-Android-创建钱包
以太坊钱包1-Android-创建钱包 2018年09月19日 18:24:13 勤奋的懒惰 阅读数 1557 版权声明:本文为博主原创文章,未经博主允许不得转载. https://blog.csdn ...
- 初识以太坊 ——钱包、测试网络和简单交易
以太币单位 • 以太坊的货币单位称为以太,也称为ETH或符号Ξ • ether被细分为更小的单位,直到可能的最小单位,称为wei:1 ether =10^18wei • 以太的值总是在以太坊内部表示为 ...
- 基于以太坊实现代币|基于以太坊实现你自己的加密货币
文章内容主要来自于 https://www.ethereum.org/token. 笔者没有过英语4级,翻译的不好请见谅 _ 代币 我们将创建一个数字令牌(digital token).以太坊生态系统 ...
- 以太坊钱包2-Android-转账(ETH)
文章目录 参考 前提准备 获取`ropsten`上的以太币 ETH查询余额 ETH转账 参考 Demo 参考代码 参考 以太坊钱包1-Android-创建钱包 以太坊钱包2-Android-转账(ET ...
- 以太坊钱包_最大的以太坊钱包币数量还在增加
持币最多的以太坊钱包地址,现在又开始继续增加持币量. ETH从累积中看到涨的迹象 以太坊价格在232.07美元,没有跌破200美元的支撑位.现在市场更多的信号在表明,大型钱包地址币的数量在累积,也间接 ...
- 安装构建以太坊钱包Parity
2019独角兽企业重金招聘Python工程师标准>>> Parity内置易用的以太坊钱包和Ðapp环境,并可通过Web浏览器访问.Parity被认为是与以太坊区块链交互的最快速,最安 ...
最新文章
- 批量提取出apk文件中的classes.dex文件
- 架空输电线路运行规程_[精品课程]金具的种类架空输电线路设计
- Kibana——数据图形化制作
- 小程序 按需_小程序后台操作,新手需知道的几个要点
- 【实施工程师】ubuntu创建文件
- Exchange Server 2013系统要求
- 解决eclipse中git中cannot open git-upload-pack(无法打开Git上传包)问题
- shell编程之正则表达式与文本工具
- Cocos2d JS 之消灭星星(十) 关卡配置
- arduino 上传项目出错_活动回顾 | 续报率80%的Arduino试听课,确定不来看看吗?
- 数据增强_炼丹笔记三:数据增强
- 计算机打代码的技巧,工作超实用的电脑技巧
- 郑明秋什么版本的MySQL_mysql数据库实用教程教学课件作者郑明秋代码数据库脚本代码9787568250825.docx...
- python压缩文件夹为zip_python压缩文件夹内所有文件为zip文件的方法
- ios 渐变透明背景_利用PS绘制唯美梦幻多边形背景图
- 家庭网络理解(家庭版光猫、路由器、交换机)
- 查词app android教程,英语查单词app哪个好_查单词app推荐_专门查单词的app
- C语言函数:toupper
- 网络安全特训之——网络信息安全攻防学习平台(基础关)
- assert在c语言中有什么作用,C语言中assert的作用是什么?
热门文章
- zblog php换域名,zblog 怎么更换域名
- 企业能源管控平台在工业能效提升行动中的作用
- C/C++编程:写了placement new也要写placement delete
- ashx获取input file 文件_手机浏览器input type=file标签调用手机拍照+分片上传
- 生产追溯系统方案——Namisoft
- Excel 固定显示表头 / 列头
- excel计算数据时固定某一列或一行或某一值
- 沃顿商学院自我管理课——埃里克.格雷腾斯
- 数据告诉你杜蕾斯是怎么风靡全球的?
- matlab标定工具箱 使用,关于 matlab 标定工具箱的使用 | 学步园