使用Web3j管理Java中的ERC20令牌

在本文中,我们将学习如何使用Web3j库管理Java中的ERC20(Fungible)令牌。

ERC20是一个以符合标准的方式实现令牌的以太坊智能合约标准,因此可以轻松地与任何应用程序(dapps,钱包,交易所等)进行交互和集成令牌。

有关ERC20的更多详细信息,请参阅ERC-20令牌标准一文

先决条件

要学习本教程,您需要在计算机上安装以下软件:

  • Java编程语言(> 8)
  • 包和依赖关系管理器,例如MavenGradle
  • IDE(集成开发环境),对于本教程,我们使用Eclipse
  • Truffle:开发,测试和部署以太坊智能合约的开发框架
  • Ganache-cli:您用于以太坊开发的本地个人区块链。

通过运行命令启动ganache:

ganache-cli

合约部署

在开始之前,我们需要在以太坊区块链上部署ERC20令牌合约(在我们的案例中为Ganache)。有很多方法可以做到这一点(阅读开发你的ERC-20令牌解释OpenZeppelin第3部分:令牌标准)。为了本教程的目的,我们使用最简单的解决方案,使用OpenZeppelin可重用合约,Truffle和Ganache。

1.首先为我们的ERC20创建一个名为JVM的项目文件夹,并初始化一个Truffle项目

$mkdir JVM
$cd JVM
$truffle init

2.然后我们安装Open-Zeppelin Solidity库,其中包含大量高质量,经过全面测试和审核的可重用智能合约

使用npm包导入OpenZeppelin智能合约。

$npm init -y
$npm install openzeppelin-solidity --save-exact

3.创建合约文件 ./contracts/JavaToken.sol

智能合约继承了可重用的OpenZeppelin合约中的所有功能和规则ERC20Mintable。我们只需要配置以下常量变量,如下所示:

// JavaToken.sol
pragma solidity ^0.5.8;

import "openzeppelin-solidity/contracts/token/ERC20/ERC20Mintable.sol";

contract JavaToken is ERC20Mintable {
 string public constant name = "Java代币";
 string public constant symbol = "JVM";
 uint8 public constant decimals = 18;
}

4.在我们当地的Ganache网络上部署智能合约

我们需要先完成迁移脚本。创建一个名为的文件./migrations/2_deploy_contract.js,并将以下代码添加到该文件中:

// 2_deploy_contract.js
const JavaToken = artifacts.require("./JavaToken.sol");

module.exports = function(deployer, network, accounts) {
 // Deploy the smart contract
 deployer.deploy(JavaToken, {from: accounts[0]}).then(function(instance) {
 // Mint 100 tokens
 return instance.mint(accounts[0], web3.utils.toBN("100"), {from: accounts[0]});
 });
};

迁移脚本部署合约,mints并将100个JVM令牌分发到部署者帐户(Ganache第一个帐户)。

下一步是配置与Ganache网络的连接以部署智能合约。将文件更改./truffle-config.js为以下代码:

// truffle-config.js
module.exports = {
  networks: {
    development: {
      host: "localhost",
      port: 8545,
      network_id: "*"
    }
  }
};

要在Ganache网络上部署智能合约,请运行以下命令(不要忘记事先启动ganache-cli):

$truffle migrate --network development

Compiling your contracts...
===========================
> Compiling ./contracts/JavaToken.sol
> Compiling ./contracts/Migrations.sol
> Compiling openzeppelin-solidity/contracts/access/Roles.sol
> Compiling openzeppelin-solidity/contracts/access/roles/MinterRole.sol
> Compiling openzeppelin-solidity/contracts/math/SafeMath.sol
> Compiling openzeppelin-solidity/contracts/token/ERC20/ERC20.sol
> Compiling openzeppelin-solidity/contracts/token/ERC20/ERC20Mintable.sol
> Compiling openzeppelin-solidity/contracts/token/ERC20/IERC20.sol
> Artifacts written to /home/gjeanmart/workspace/tutorials/kauri-content/java-erc20/JVM/build/contracts
> Compiled successfully using:
 - solc: 0.5.8+commit.23d335f2.Emscripten.clang


Starting migrations...
======================
> Network name: 'development'
> Network id: 1565778588423
> Block gas limit: 0x6691b7


1_initial_migration.js
======================

 Deploying 'Migrations'
 ----------------------
 > transaction hash: 0x6161e15461a5c748a532b2191600986b8798be4842e78791238e9e77af5e1310
 > Blocks: 0 Seconds: 0
 > contract address: 0xC59fC6035859Dd35871c5d9211a0713ed608d59D
 > block number: 6
 > block timestamp: 1565778631
 > account: 0xB0C24796Fc9212AB371c8Caf1ea3F33cC1d4c8a0
 > balance: 99.95438236
 > gas used: 261393
 > gas price: 20 gwei
 > value sent: 0 ETH
 > total cost: 0.00522786 ETH


 > Saving migration to chain.
 > Saving artifacts
 -------------------------------------
 > Total cost: 0.00522786 ETH


2_deploy_contract.js
====================

 Deploying 'JavaToken'
 ---------------------
 > transaction hash: 0xfc5b214cbd56ecd4d24795aacefe1fdaf27b1b223ebff78299fd47f302cb374c
 > Blocks: 0 Seconds: 0
 > contract address: 0x9339a071cB9C1E3BbBA50E5E298f234c5095f012
 > block number: 8
 > block timestamp: 1565778631
 > account: 0xB0C24796Fc9212AB371c8Caf1ea3F33cC1d4c8a0
 > balance: 99.92109908
 > gas used: 1622141
 > gas price: 20 gwei
 > value sent: 0 ETH
 > total cost: 0.03244282 ETH


 > Saving migration to chain.
 > Saving artifacts
 -------------------------------------
 > Total cost: 0.03244282 ETH


Summary
=======
> Total deployments: 2
> Final cost: 0.03767068 ETH

命令完成后请注意合约地址。

如果您想了解有关此步骤的更多信息,我建议您阅读以下有关Truffle和Ganache的文章,以便部署智能合约:Truffle:智能合约编制和部署以及Truffle 101 – 智能合约开发工具

使用Web3j加载合约

现在我们在Ganache本地区块链上部署了一个ERC20智能合约,我们可以使用Web3j ERC20实用程序类开始在Java中与它进行交互。

1.创建一个新项目并导入Web3j依赖项

在您喜欢的IDE中创建一个新的Maven项目并导入Web3j依赖项(core以及contractsEIP支持):

"http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
  4.0.0
  io.kauri.tutorials.java-ethereum
  java-erc20
  0.0.1-SNAPSHOT

  
    1.8
    1.8
    4.2.0
  

  
    
      org.web3j
      core
      ${web3j.version}
    
    
      org.web3j
      contracts
      ${web3j.version}
    
  


2.创建一个新类以加载ERC20智能合约盘点器

ERC20是标准,因此无需手动生成智能合约盘点器,Web3j默认包含它。

但是,您需要将Web3j连接到以太坊区块链并配置钱包以签署交易。

在本文中,我们连接到本地Ganache区块链(默认情况下公开http://localhost:8545)并使用第一个Ganache测试帐户(读取Ganache启动日志以查找此信息),在部署期间收到100个JVM令牌。

// Connect Web3j to the区块链
String rpcEndpoint = "http://localhost:8545";
Web3j web3j = Web3j.build(new HttpService(rpcEndpoint));

// Prepare a wallet
String pk = "0x5bbbef76458bf30511c9ee6ed56783644eb339258d02656755c68098c4809130";
// Account address: 0x1583c05d6304b6651a7d9d723a5c32830f53a12f
Credentials credentials = Credentials.create(pk);

// Load the contract
String contractAddress = "0xe4F275cE131eF87Cb8bF425E02D9215055e9F875";
ERC20 javaToken = ERC20.load(contractAddress, web3j, credentials, new DefaultGasProvider());

对于更复杂的方案,您可以使用特定的TransactionManagerGas参数加载合约ERC20.load(contractAddress, web3j, transactionManager, gasPrice, gasLimit)

3.获取令牌信息

一旦我们加载了ERC20令牌合约,我们就可以开始请求存储在此合约上的信息,例如JVM令牌中的小数或余额。

以下代码检索我们之前在合约中配置的信息。

String symbol = javaToken.symbol().send();
String name = javaToken.name().send();
BigInteger decimal = javaToken.decimals().send();

System.out.println("symbol: " + symbol);
System.out.println("name: " + name);
System.out.println("decimal: " + decimal.intValueExact());

更重要的是,我们可以检索帐户的令牌余额。

BigInteger balance1 = javaToken.balanceOf("0x1583c05d6304b6651a7d9d723a5c32830f53a12f").send();
System.out.println("balance (0x1583c05d6304b6651a7d9d723a5c32830f53a12f)="+balance1.toString());

BigInteger balance2 = javaToken.balanceOf("0x0db6b797e64666d4b36b13e5dc6fcd4661893ac8").send();
System.out.println("balance (0x0db6b797e64666d4b36b13e5dc6fcd4661893ac8)="+balance2.toString());

该帐户0x1583c05d6304b6651a7d9d723a5c32830f53a12f是Ganache的第一个帐户,即部署合约并在部署期间收到100个令牌的帐户。虽然0x0db6b797e64666d4b36b13e5dc6fcd4661893ac8代表Ganache的第二个帐户没有收到任何令牌。

转移代币

要与令牌交互,该ERC20班提供所需的像所有功能transfertransferFrom以及approve

例如,我们可以0x0db6b797e64666d4b36b13e5dc6fcd4661893ac8通过从配置为Credentials(0x1583c05d6304b6651a7d9d723a5c32830f53a12f)的帐户签名并发送一个事务来传输25个JVM令牌。

TransactionReceipt receipt = javaToken.transfer("0x0db6b797e64666d4b36b13e5dc6fcd4661893ac8", new BigInteger("25")).send();
System.out.println("Transaction hash: "+receipt.getTransactionHash());

BigInteger balance1 = javaToken.balanceOf("0x1583c05d6304b6651a7d9d723a5c32830f53a12f").send();
System.out.println("balance (0x1583c05d6304b6651a7d9d723a5c32830f53a12f)="+balance1.toString());

BigInteger balance2 = javaToken.balanceOf("0x0db6b797e64666d4b36b13e5dc6fcd4661893ac8").send();
System.out.println("balance (0x0db6b797e64666d4b36b13e5dc6fcd4661893ac8)="+balance2.toString());

收到转移事件的通知

最后,我们将介绍如何订阅ERC20合约生成的特定事件,以便我们可以对其中的任何活动做出反应。

您可以通过以下方法检索给定事务的特定事件getTransferEvents

List events = javaToken.getTransferEvents(receipt);
events.forEach(event
 -> System.out.println("from: " + event._from + ", to: " + event._to + ", value: " + event._value));

我们还可以添加RxJava作为依赖项,以便通过连续订阅任何新事件transferEventFlowable

javaToken.transferEventFlowable(DefaultBlockParameterName.EARLIEST, DefaultBlockParameterName.LATEST)
 .subscribe(event
 -> System.out.println("from: " + event._from + ", to: " + event._to + ", value: " + event._value));

提示:投资有风险,入市需谨慎,本资讯不作为投资理财建议。请理性投资,切实提高风险防范意识;如有发现的违法犯罪线索,可积极向有关部门举报反映。
你可能还喜欢