web3j学习(1)

本文源代码见 https://github.com/pigeon2049/planet-universal

作为一个写 java 的全栈开发，sodility 语言似乎让人很难下手，所以先从熟悉的领域入手

web3j

起手一个传统 springboot maven 项目，引用 web3j 依赖

Copy
<dependency>
<groupId>org.web3j</groupId>
<artifactId>core</artifactId>
<version>${web3j.version}</version>
</dependency>
<dependency>
<groupId>org.web3j</groupId>
<artifactId>contracts</artifactId>
<version>${web3j.version}</version>
</dependency>

为了快速开发学习，本机需要安装 docker

Copy
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-docker-compose</artifactId>
<scope>runtime</scope>
<optional>true</optional>
</dependency>

新版本 springboot 支持集成 docker, 所以没有安装环境的过程，直接启，会得到一个 ipfs kubo 客户端以及 influxdb 时序数据库

开始学习:
web3j 需要一个以太坊客户端节点，可以自己用 geth 搭一个，也可以偷懒使用 cloudflare 提供的公共端口，使用公共端口注意尽量不要使用自己的地址和密钥与合约交互，容易产生安全问题

application.properties 添加 cloudflare eth gateway

Copy
web3j.node.address=https://cloudflare-eth.com/

定义一个配置文件，生成 web3j 的 bean

Copy

@Configuration
public class Web3jConfig {

@Value("${web3j.node.address}")
private String ethNode;

@Bean
public Web3j web3j() throws ExecutionException, InterruptedException {
Web3j build = Web3j.build(new HttpService(ethNode));
Web3ClientVersion web3ClientVersion = build.web3ClientVersion().sendAsync().get();
System.out.println(web3ClientVersion.getWeb3ClientVersion());
return build;
}
}

这样我们就得到了一个可用的 web3j client

接下来简单写个获取以太坊链上实时 Gas 费的方法

Copy
@Service
public class GasPrice {

private final Web3j web3j;

public GasPrice(Web3j web3j) {
this.web3j = web3j;
}

public BigInteger gasGasPrice() throws IOException {

return web3j.ethGasPrice().send().getGasPrice();
}

}

是不是很简单？

但是你就会发现这个单位好像不对，平时看到的是 Gwei
, 换算一下

Copy
BigInteger gas = gasPrice.gasGasPrice();
BigDecimal value= BigDecimal.valueOf(gas .longValue() * 0.000000001).setScale(2, RoundingMode.HALF_UP);

保留两位小数，得到的就是 Gwei 了

简单写个定时，每秒获取一次 Gas 数据存数据库

Copy
@Service
public class UpdateGasPrice implements CommandLineRunner {

@Value("${influx.url}")
String url;

@Value("${influx.token}")
String token;

@Value("${influx.org}")
String org ;

@Value("${influx.bucket}")
String bucket ;

private final GasPrice gasPrice;

public UpdateGasPrice(GasPrice gasPrice) {
this.gasPrice = gasPrice;
}

@Override
public void run(String... args) throws Exception {
InfluxDBClient client = InfluxDBClientFactory.create(url, token.toCharArray(), org, bucket)
.setLogLevel(LogLevel.BASIC);
WriteApi writeApi = client.makeWriteApi(WriteOptions.builder().flushInterval(2_000).build());

Timer timer = new Timer();
timer.schedule(new TimerTask() {
@Override
public void run() {

try {
BigInteger gas = gasPrice.gasGasPrice();
if (gas!=null){
BigDecimal value= BigDecimal.valueOf(gas.longValue() * 0.000000001).setScale(2, RoundingMode.HALF_UP);
Point point = Point
.measurement("eth")
.addField("gas", gas.longValue())
.addField("gasGwei", value)
.time(Instant.now(), WritePrecision.S);

System.out.println("Produced DataPoint: " + point.toLineProtocol());

writeApi.writePoint(point);
}

} catch (IOException ignored) {}

}
}, 0, 1000);

Runtime.getRuntime().addShutdownHook(new Thread(() -> {
System.out.println("Close Client and Producer");
timer.cancel();
client.close();
}));
}
}

运行代码

打开http://localhost:8086
进入 influxdb 的管理网页，密码写在 env 里

可以看到已经开始写入 gas 数据了

获取地址以太坊余额

以太坊链上就很简单

Copy

public BigDecimal getBalance(String address) throws IOException {
BigInteger balance = web3j.ethGetBalance(address, DefaultBlockParameterName.LATEST).send().getBalance();
BigDecimal ether = Convert.fromWei(String.valueOf(balance), Convert.Unit.ETHER);
System.out.println(address+" balance:"+ether.toString());
return ether;
}

获取 Erc20 代币余额

Copy

public BigDecimal getErc20Balance(String address,String tokenContractAddress) throws Exception {

// Use ReadOnlyTransactionManager for read-only operations
ReadonlyTransactionManager txManager = new ReadonlyTransactionManager(web3j, null);
DefaultGasProvider gasPriceProvider = new DefaultGasProvider();
// ERC20 is your generated ERC20 contract wrapper class
ERC20 contract = ERC20.load(tokenContractAddress, web3j, txManager, gasPriceProvider);

// Call the balanceOf function on the ERC-20 contract
BigInteger balance = contract.balanceOf(address).send();
BigDecimal ether = Convert.fromWei(String.valueOf(balance), Convert.Unit.ETHER);
System.out.println("Balance of " + address + ": " + ether);

return ether;
}

本次学习了简易的链上操作，只是简易读取
后续加深学习合约交互