本文源代码见 https://github.com/pigeon2049/planet-universal
作为一个写 java 的全栈开发,sodility 语言似乎让人很难下手,所以先从熟悉的领域入手
web3j
起手一个传统 springboot maven 项目,引用 web3j 依赖
<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
<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
web3j.node.address=https://cloudflare-eth.com/
定义一个配置文件,生成 web3j 的 bean
@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 费的方法
@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
, 换算一下
BigInteger gas = gasPrice.gasGasPrice();
BigDecimal value= BigDecimal.valueOf(gas .longValue() * 0.000000001).setScale(2, RoundingMode.HALF_UP);
保留两位小数,得到的就是 Gwei 了
简单写个定时,每秒获取一次 Gas 数据存数据库
@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 数据了
获取地址以太坊余额
以太坊链上就很简单
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 代币余额
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;
}
本次学习了简易的链上操作,只是简易读取
后续加深学习合约交互