{"content":{"title":"大家好，我开发了一个扫块的工具包，可以用来方便的监听交易动态","body":"Magician-web3是一个区块链[开发工具](https://learnblockchain.cn/article/3434)包。它由两个功能组成。一个是扫描区块链，根据开发者的需要监控交易。另一个是对web3j的一些二次打包，可以减少开发者在一些常见场景下的工作量。它计划支持三种链，ETH（BSC、POLYGAN等）、SOL和TRON。\r\n\r\n开发语言是 java ，底层依赖了 Web3J ， 废话不多说，直接上示例\r\n\r\n## 引入依赖\r\n\r\n```xml\r\n<dependency>\r\n    <groupId>com.github.yuyenews</groupId>\r\n    <artifactId>Magician-web3</artifactId>\r\n    <version>1.0.0</version>\r\n</dependency>\r\n\r\n<!-- This is the logging package, you must have it or the console will not see anything, any logging package that can bridge with slf4j is supported -->\r\n<dependency>\r\n    <groupId>org.slf4j</groupId>\r\n    <artifactId>slf4j-jdk14</artifactId>\r\n    <version>1.7.12</version>\r\n</dependency>\r\n```\r\n\r\n## 创建监听器\r\n\r\n监听器 可以创建多个，根据你的需求 分别设置监听条件\r\n\r\n```java\r\n/**\r\n * 创建一个类，实现 EthMonitorEvent 接口 即可\r\n */\r\npublic class EventDemo implements EthMonitorEvent {\r\n\r\n    /**\r\n     * 筛选条件，如果遇到了符合条件的交易，会自动触发 call 方法\r\n     * 这些条件都是 并且的关系，必须要同时满足才行\r\n     * 如果不想根据某个条件筛选，直接不给那个条件设置值就好了\r\n     * 这个方法如果不实现，或者返回 null ， 那么就代表监听任意交易\r\n     */\r\n    @Override\r\n    public EthMonitorFilter ethMonitorFilter() {\r\n        return EthMonitorFilter.builder()\r\n                .setFromAddress(\"0x131231249813d334C58f2757037F68E2963C4crc\") // 筛选 fromAddress 发送的交易\r\n                .setToAddress(\"0x552115849813d334C58f2757037F68E2963C4c5e\") // 筛选 toAddress 或 合约地址 收到的交易\r\n                .setMinValue(BigInteger.valueOf(1)) // 筛选发送的主链币数量 >= minValue 的交易\r\n                .setMaxValue(BigInteger.valueOf(10)) // 筛选发送的主链币数量 <= maxValue 的交易\r\n                .setFunctionCode(\"0xasdas123\"); // 筛选调用合约内 某方法 的交易\r\n    }\r\n\r\n    /**\r\n     * 如果遇到了符合上面条件的交易，就会触发这个方法\r\n     * transactionModel.getEthTransactionModel() 是一个交易对象，内部包含 hash ，value ，from ，to 等 所有的数据\r\n     */\r\n    @Override\r\n    public void call(TransactionModel transactionModel) {\r\n        String template = \"EventOne 扫描到了, hash:{0}, from:{1}, to: {2}, input: {3}\";\r\n        template = template.replace(\"{0}\", transactionModel.getEthTransactionModel().getBlockHash());\r\n        template = template.replace(\"{1}\", transactionModel.getEthTransactionModel().getFrom());\r\n        template = template.replace(\"{2}\", transactionModel.getEthTransactionModel().getTo());\r\n        template = template.replace(\"{3}\", transactionModel.getEthTransactionModel().getInput());\r\n\r\n        System.out.println(template);\r\n    }\r\n}\r\n\r\n```\r\n\r\n## 开启一个扫块任务\r\n\r\n```java\r\n\r\n// 初始化线程池，核心线程数必须 >= 扫块的任务数量，建议等于扫块的任务数量\r\nEventThreadPool.init(1);\r\n\r\n// 开启一个扫块任务，如果你想扫描多个链，那么直接拷贝这段代码，并修改配置即可\r\nMagicianBlockchainScan.create()\r\n        .setRpcUrl(\"https://data-seed-prebsc-1-s1.binance.org:8545/\") // 节点的 RPC 地址\r\n        .setChainType(ChainType.ETH) // 要扫描的链（如果设置成 ETH ，那么可以扫描 BSC, POLYGAN 等其他任意 以太坊标准的链）\r\n        .setScanPeriod(5000) // 每轮扫描的间隔\r\n        .setScanSize(1000) // 每轮扫描的块数\r\n        .setBeginBlockNumber(BigInteger.valueOf(24318610)) // 从哪个块高开始扫描\r\n        .addEthMonitorEvent(new EventOne()) // 添加 监听事件\r\n        .addEthMonitorEvent(new EventTwo()) // 添加 监听事件\r\n        .addEthMonitorEvent(new EventThree()) // 添加 监听事件\r\n        .start();\r\n\r\n// TODO 暂时不支持 SOL 和 TRON ， 正在开发中......\r\n\r\n```\r\n\r\n## Web3J 扩展\r\n\r\n在 Web3j 的基础上进行了二次封装，扩展了几个基础的方法，可以在一定程度上减轻开发者的工作量\r\n\r\n### 主链币查询以及转账\r\n\r\n```java\r\nString privateKey = \"\"; // 私钥\r\nWeb3j web3j = Web3j.build(new HttpService(\"https://data-seed-prebsc-1-s1.binance.org:8545/\")); // 链的 RPC 地址\r\n\r\nEthHelper ethHelper =  MagicianWeb3.getEthBuilder().getEth(web3j, privateKey);\r\n\r\n// 余额查询\r\nBigInteger balance = ethHelper.balanceOf(fromAddress);\r\n\r\n// 转账\r\nTransactionReceipt transactionReceipt = ethHelper.transfer(\r\n            toAddress,\r\n            BigDecimal.valueOf(1),\r\n            Convert.Unit.ETHER\r\n);\r\n``` \r\n### InputData 编解码\r\n\r\n```java\r\nEthAbiCodec ethAbiCodec = MagicianWeb3.getEthBuilder().getEthAbiCodec();\r\n\r\n// 编码\r\nString inputData = ethAbiCodec.getInputData(\r\n            \"transfer\", // 方法名\r\n            new Address(toAddress), // 参数 1\r\n            new Uint256(new BigInteger(\"1000000000000000000\")) // 参数 2 ，如果还有其他参数，可以继续传入下一个\r\n    );\r\n\r\n// 解码\r\nList<Type> result = ethAbiCodec.decoderInputData(\r\n            \"0x\" + inputData.substring(10), // 去除方法签名的 inputData\r\n            new TypeReference<Address>() {}, // 被编码的方法的参数 1 类型\r\n            new TypeReference<Uint256>() {} // 被编码的方法的参数 2 类型， 如果还有其他参数，可以继续传入下一个\r\n    );\r\n\r\nfor(Type type : result){\r\n    System.out.println(type.getValue());\r\n}\r\n\r\n// 获取方法签名，其实就是 inputData 的前十位\r\nString functionCode = ethAbiCodec.getFunAbiCode(\r\n            \"transfer\", // 方法名\r\n            new Address(toAddress), // 参数 1 ，值随意传，反正我们要的方法签名，不是完整的 inputData\r\n            new Uint256(new BigInteger(\"1000000000000000000\")) // 参数 2 ，值随意传，反正我们要的方法签名，不是完整的 inputData ，如果还有其他参数，可以继续传入下一个\r\n    );\r\n   \r\n```\r\n\r\n#### 合约查询 以及 写入\r\n\r\n```java\r\nString privateKey = \"\"; // 私钥\r\nWeb3j web3j = Web3j.build(new HttpService(\"https://data-seed-prebsc-1-s1.binance.org:8545/\")); // 链的 RPC 地址\r\n\r\nEthContract ethContract = MagicianWeb3.getEthBuilder().getEthContract(web3j, fromAddressPrivateKey);\r\nEthAbiCodec ethAbiCodec = MagicianWeb3.getEthBuilder().getEthAbiCodec();\r\n\r\n// 查询\r\nList<Type> result = ethContract.select(\r\n            contractAddress, // 合约地址\r\n            ethAbiCodec.getInputData(\r\n                    \"balanceOf\", // 要调用的方法名称\r\n                    new Address(toAddress) // 方法的参数，如果有多个，可以继续传入下一个参数\r\n            ),  // 要调用的方法的 inputData\r\n            new TypeReference<Uint256>() {} // 方法的返回类型，如果有多个返回值，可以继续传入下一个参数\r\n        );\r\n\r\n// 往合约里写入数据\r\n// gasPrice ，gasLimit 两个参数，如果想用默认值可以不传，或者传 null\r\n// 如果不传的话，两个参数都必须不传，要传就一起传， 如果设置为 null 的话，可以一个为 null ，一个有值\r\nSendResultModel sendResultModel = ethContract.sendRawTransaction(\r\n                    fromAddress, // 调用者的地址\r\n                    contractAddress, // 合约地址\r\n                    new BigInteger(\"1200000\"), // gasPrice ，如果想用默认值 可以直接传 null ，或者不传这个参数\r\n                    new BigInteger(\"800000\"), // gasLimit ，如果想用默认值 可以直接传 null ，或者不传这个参数\r\n                    ethAbiCodec.getInputData(\r\n                            \"transfer\", // 要调用的方法名称\r\n                            new Address(toAddress), // 方法的参数，如果有多个，可以继续传入下一个参数\r\n                            new Uint256(new BigInteger(\"1000000000000000000\")) // 方法的参数，如果有多个，可以继续传入下一个参数\r\n                    ) // 要调用的方法的 inputData\r\n            );\r\n\r\nsendResultModel.getEthSendTransaction(); // 发送交易后的结果\r\nsendResultModel.getEthGetTransactionReceipt(); // 交易成功上链后的结果\r\n```\r\n\r\ngithub 地址：[https://github.com/Magician-blockchain/Magician-web3]( https://github.com/Magician-blockchain/Magician-web3)"},"author":{"user":"https://learnblockchain.cn/people/12517","address":null},"history":null,"timestamp":1667892561,"version":1}