moecat

moecat

摸鱼大师

web3j学习(1)

本文源代码见 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

image

<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();
        }));
    }
}

运行代码

image

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

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


获取地址以太坊余额

以太坊链上就很简单


  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;
    }

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

加载中...
此文章数据所有权由区块链加密技术和智能合约保障仅归创作者所有。