# Magician-Blockchain
# Magician-Scanning
Magician-Scanning是一个用Java开发的扫描区块链的工具包,当我们在程序中需要一些功能时,它可以派上用场,比如说。
当一个地址收到ETH时,程序中的一个方法会被自动触发,这个交易会被传入该方法。
当一个合约的某个功能被调用时(比如ERC20转账),它会自动触发程序中的一个方法,并将这个交易传递给这个方法。它甚至可以只在代币被转移到指定地址时被触发。
当程序需要保留一个区块高度开始以来的所有交易记录时,也可以使用这个工具包。
它计划支持三种链,ETH(BSC,POLYGON等),SOL和TRON
# 导入依赖
<dependency>
<groupId>com.github.yuyenews</groupId>
<artifactId>Magician-Scanning</artifactId>
<version>1.0.12</version>
</dependency>
<!-- 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 -->
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-jdk14</artifactId>
<version>1.7.12</version>
</dependency>
# ETH(BSC, POLYGAN, ARB 等)链
# 创建监听器
监听器 可以创建多个,根据你的需求 分别设置监听条件
/**
* 创建一个类,实现 EthMonitorEvent接口 即可
*/
public class EventDemo implements EthMonitorEvent {
/**
* 筛选条件,如果遇到了符合条件的交易,会自动触发 call方法
* 这些条件都是 并且的关系,必须要同时满足才行
* 如果不想根据某个条件筛选,直接不给那个条件设置值就好了
* 这个方法如果不实现,或者返回null, 那么就代表监听任意交易
*/
@Override
public EthMonitorFilter ethMonitorFilter() {
return EthMonitorFilter.builder()
.setFromAddress("0x131231249813d334C58f2757037F68E2963C4crc") // 筛选 fromAddress 发送的交易
.setToAddress("0x552115849813d334C58f2757037F68E2963C4c5e") // 筛选 toAddress 或 合约地址 收到的交易
.setMinValue(BigInteger.valueOf(1)) // 筛选发送的主链币数量 >= minValue 的交易
.setMaxValue(BigInteger.valueOf(10)) // 筛选发送的主链币数量 <= maxValue 的交易
.setInputDataFilter( // 根据inputData筛选
InputDataFilter.builder()
.setFunctionCode(ERC20.TRANSFER.getFunctionCode()) // 函数签名(被调用的合约内的某方法), 支持任意函数,这里的枚举只是一部分标准的合约函数
.setTypeReferences( // 此方法的参数列表(仅类型)
new TypeReference<Address>(){},
new TypeReference<Uint256>(){}
)
.setValue("0x552115849813d334C58f2757037F68E2963C4c5e", null)// 筛选第几个参数 = 什么值
);
}
/**
* 如果遇到了符合上面条件的交易,就会触发这个方法
* transactionModel.getEthTransactionModel() 是一个交易对象,内部包含hash,value,from,to 等 所有的数据
*/
@Override
public void call(TransactionModel transactionModel) {
// 符合条件的交易记录
EthBlock.TransactionObject transactionObject = transactionModel.getEthTransactionModel().getTransactionObject();
// 本条交易记录所在的块信息
EthBlock ethBlock = transactionModel.getEthTransactionModel().getEthBlock();
}
}
# InputDataFilter 详解
如果你想监控某合约内的某函数, 被调用的交易
public EthMonitorFilter ethMonitorFilter() {
return EthMonitorFilter.builder()
.setToAddress("0x552115849813d334C58f2757037F68E2963C4c5e") // 合约地址
.setInputDataFilter( // 根据inputData筛选
InputDataFilter.builder()
.setFunctionCode("0xadasasdf") // 被调用的函数编码(inputData前十位)
);
}
如果 有一个合约[0x552115849813d334C58f2757037F68E2963C4c5e], 里面有一个函数是 transferFrom(address from, address to, uint256 amount)
你想 实现一个监控:如果有人用这个合约里的这个函数,将代币转给[0x552115849813d334C58f2757037F68E2963C4c5e]时,就触发 Monitor事件,那么你可以这样写
public EthMonitorFilter ethMonitorFilter() {
return EthMonitorFilter.builder()
.setToAddress("0x552115849813d334C58f2757037F68E2963C4c5e") // 合约地址
.setInputDataFilter( // 根据inputData筛选
InputDataFilter.builder()
.setFunctionCode(ERC20.TRANSFER_FROM.getFunctionCode()) // 被调用的函数编码(inputData前十位)
.setTypeReferences( // 此方法的参数列表(仅类型)
new TypeReference<Address>(){}, // 第一个参数的类型
new TypeReference<Address>(){}, // 第二个参数的类型
new TypeReference<Uint256>(){} // 第三个参数的类型
)
.setValue(null, "0x552115849813d334C58f2757037F68E2963C4c5e", null)// 筛选第二个参数(to) = 0x552115849813d334C58f2757037F68E2963C4c5e
);
}
# 开启一个扫块任务
// 初始化线程池,核心线程数必须 >= 全局的扫块的任务数量 + 全局的重试策略的数量
// 这是一个全局配置,不管你开了几个任务,不管你需要扫描几条链,几种链,都只需要写一次这句代码
EventThreadPool.init(1);
// 开启一个扫块任务,如果你想扫描多个链,那么直接拷贝这段代码,并修改配置即可
MagicianBlockchainScan.create()
.setRpcUrl(
EthRpcInit.create()
.addRpcUrl("https://data-seed-prebsc-1-s1.binance.org:8545")
) // 节点的RPC地址
.setScanPeriod(5000) // 间隔多久,扫描下一个区块
.setBeginBlockNumber(BigInteger.valueOf(24318610)) // 从哪个块高开始扫描
.setEndBlockNumber(BigInteger.valueOf(24318680)) // 扫描到哪个块高就停止这个任务(不设置,或者设置为0,代表不限制)
.addEthMonitorEvent(new EventOne()) // 添加 监听事件
.addEthMonitorEvent(new EventTwo()) // 添加 监听事件
.addEthMonitorEvent(new EventThree()) // 添加 监听事件
.start();
# 使用代理访问RPC地址
// 使用 addRpcUrl 方法的另一个重载,传入代理设置即可
EthRpcInit.create()
.addRpcUrl("https://data-seed-prebsc-1-s1.binance.org:8545/",
new Proxy(Proxy.Type.HTTP, new InetSocketAddress("127.0.0.1", 4780)))
// ---------- 除了上面那种以外,addRpcUrl 方法一共有这么几种重载,根据你的需求挑选合适的方法 ----------
// 直接传入 wei3j的HttpService
// 这种方法 可定制化最高,基本上就是web3j本来的使用方式
EthRpcInit.create()
.addRpcUrl(new HttpService(""))
// 传入okHttpClient
// 这种方法 可定制化程度也非常高,基本上就是使用okHttp访问 区块链节点了
OkHttpClient okHttpClient = xxxxxx;
EthRpcInit.create()
.addRpcUrl(okHttpClient)
// 有些代理服务器 需要鉴权,可以使用这种方式来设置用户名和密码
EthRpcInit.create()
.addRpcUrl("https://data-seed-prebsc-1-s1.binance.org:8545/",
new Proxy(Proxy.Type.HTTP, new InetSocketAddress("127.0.0.1", 4780)),
(Route route, Response response) -> {
//设置代理服务器账号密码
String credential = Credentials.basic("用户名", "密码");
return response.request().newBuilder()
.header("Proxy-Authorization", credential)
.build();
}
)
# TRON链
# 创建监听器
条件过滤器还在开发中,可以关注后续更新,call方法会接收到所有扫描到的交易信息,需要您自己判断筛选
/**
* 创建一个类,实现TronMonitorEvent接口即可
*/
public class TronEventOne implements TronMonitorEvent {
/**
* transactionModel 对象里包含此条交易的所有信息
*/
@Override
public void call(TransactionModel transactionModel) {
System.out.println("TRON 成功了!!!");
System.out.println("TRON, txID: " + transactionModel.getTronTransactionModel().getTxID());
}
}
# 开启一个扫块任务
下面标出了跟ETH扫块任务的两个区别,除此之外,再无其他区别
// 初始化线程池,核心线程数必须 >= 全局的扫块的任务数量 + 全局的重试策略的数量
// 这是一个全局配置,不管你开了几个任务,不管你需要扫描几条链,几种链,都只需要写一次这句代码
EventThreadPool.init(1);
MagicianBlockchainScan.create()
.setRpcUrl(
// 跟ETH的区别一,这里需要用TronRpcInit
TronRpcInit.create()
.addRpcUrl("https://api.shasta.trongrid.io/wallet")
)
.addTronMonitorEvent(new TronEventOne()) // 跟ETH的区别二,添加监听器需要用 addTronMonitorEvent
.start();
# 使用代理访问RPC地址
开发中......
# SOLANA链
开发中......
# 停止某一个扫块任务
三条链都是一样的写法
// 将对象拿到
MagicianBlockchainScan blockChainScan = MagicianBlockchainScan.create()
.setRpcUrl(
EthRpcInit.create()
.addRpcUrl("https://data-seed-prebsc-1-s1.binance.org:8545")
) // 节点的RPC地址
.setScanPeriod(5000) // 间隔多久,扫描下一个区块
.setBeginBlockNumber(BigInteger.valueOf(24318610)) // 从哪个块高开始扫描
.addEthMonitorEvent(new EventOne()) // 添加 监听事件
// 因为start方法没有返回值,为了能获取blockChainScan对象,所以上面的链式不可以调用start,需要改成用返回的对象来调用
blockChainScan.start();
// 调用这个方法可以停止这一个扫块任务
blockChainScan.shutdown();
# 停止所有扫块任务
MagicianBlockchainScan.shutdownAll();
# 获取当前任务扫描到的最大块高
// 将对象拿到
MagicianBlockchainScan blockChainScan = MagicianBlockchainScan.create()
.setRpcUrl(
EthRpcInit.create()
.addRpcUrl("https://data-seed-prebsc-1-s1.binance.org:8545")
) // 节点的RPC地址
.setScanPeriod(5000) // 间隔多久,扫描下一个区块
.setBeginBlockNumber(BigInteger.valueOf(24318610)) // 从哪个块高开始扫描
.addEthMonitorEvent(new EventOne()) // 添加 监听事件
// 因为start方法没有返回值,为了能获取blockChainScan对象,所以上面的链式不可以调用start,需要改成用返回的对象来调用
blockChainScan.start();
// 调用这个方法可以获取当前任务已经扫描到的最大块高
// 有一定的误差,因为在你获取的这一瞬间,扫描任务可能又扫描到好几个新块高了
blockChainScan.getCurrentBlockHeight();
# 配置多个RPC URL 实现负载均衡
三条链都是一样的,只是EthRpcInit 需要改成对应的链的类
调用addRpcUrl方法多次,传入多个RPC URL,即可实现负载均衡(轮询)
MagicianBlockchainScan.create()
.setRpcUrl(
EthRpcInit.create()
.addRpcUrl("https://data-seed-prebsc-1-s1.binance.org:8545")
.addRpcUrl("https://data-seed-prebsc-2-s1.binance.org:8545")
.addRpcUrl("https://data-seed-prebsc-1-s2.binance.org:8545")
) // 节点的RPC地址
# 重试策略(三条链都是一样的写法)
在符合以下两个条件时,会发生重试,两个条件必须全都符合 才会触发重试
- 当前正在扫描的块高 是空的(块不存在 或者 块里面没交易)
- 当前正在扫描的块高 < 链上的最新块高
当上面两个条件同时符合的时候,扫描任务会跳过这个块,然后继续扫描下一个块,同时 重试策略会收到被跳过的块高, 你可以在重试策略里 自己处理
# 创建一个重试策略
public class EthRetry implements RetryStrategy {
@Override
public void retry(BigInteger blockNumber) {
}
}
# 将重试策略添加到扫描任务中
MagicianBlockchainScan.create()
.setRetryStrategy(new EthRetry())// 调用这个方法添加
.start();
# 需要注意线程数量的配置
如果你此时开了一个扫块任务 + 一个 重试策略,那么需要占用两个线程,所以参数必须传2
// 初始化线程池,核心线程数必须 >= 全局的扫块的任务数量 + 全局的重试策略的数量
// 这是一个全局配置,不管你开了几个任务,不管你需要扫描几条链,几种链,都只需要写一次这句代码
EventThreadPool.init(2);
# InputData 编解码
# ETH(BSC, POYGAN 等)链
// 编码
String inputData = EthAbiCodec.getInputData(
"transfer", // 方法名
new Address(toAddress), // 参数1
new Uint256(new BigInteger("1000000000000000000")) // 参数2,如果还有其他参数,可以继续传入下一个
);
// 解码
List<Type> result = EthAbiCodec.decoderInputData(
"0x" + inputData.substring(10), // 去除方法签名的inputData
new TypeReference<Address>() {}, // 被编码的方法的参数1 类型
new TypeReference<Uint256>() {} // 被编码的方法的参数2 类型, 如果还有其他参数,可以继续传入下一个
);
for(Type type : result){
System.out.println(type.getValue());
}
// 获取方法签名,其实就是inputData的前十位
String functionCode = EthAbiCodec.getFunAbiCode(
"transfer", // 方法名
new Address(toAddress), // 参数1,值随意传,反正我们要的方法签名,不是完整的inputData
new Uint256(new BigInteger("1000000000000000000")) // 参数2,值随意传,反正我们要的方法签名,不是完整的inputData,如果还有其他参数,可以继续传入下一个
);
# TRON
开发中......
# SOLANA
开发中......
# 项目内置了几个functionCode(ETH专用)
如果你刚好要监听这几个函数,那么可以直接用,前提是你的合约里的函数必须跟 Openzeppelin 的规范一样,连参数列表的顺序都必须一样
# ERC20
ERC20.TRANSFER.getFunctionCode();
ERC20.APPROVE.getFunctionCode();
ERC20.TRANSFER_FROM.getFunctionCode();
# ERC721
ERC721.SAFE_TRANSFER_FROM.getFunctionCode();
ERC721.SAFE_TRANSFER_FROM_TWO.getFunctionCode(); // 没有data的那个
ERC721.TRANSFER_FROM.getFunctionCode();
ERC721.APPROVE.getFunctionCode();
ERC721.SET_APPROVAL_FOR_ALL.getFunctionCode();
# ERC1155
ERC1155.SET_APPROVAL_FOR_ALL.getFunctionCode();
ERC1155.SAFE_TRANSFER_FROM.getFunctionCode();
ERC1155.SAFE_BATCH_TRANSFER_FROM.getFunctionCode();
# Magician-ContractsTools
Magician-ContractsTools是一个用于调用智能合约的工具包,你可以非常容易地在Java程序中调用智能合约进行查询和写入操作。
有三个内置的标准合约模板,分别是ERC20、ERC721和ERC1155,如果你需要调用这三个合约中的标准函数,可以帮助你非常快速地完成工作。除了内置的合同模板外,如果你需要调用自定义的合同函数也是很容易的,以后我们还会继续增加标准模板。
此外,还有InputData解码和ETH查询和转移的工具
计划支持三种链,ETH(BSC、POLYGON等)、SOL和TRON
# 导入依赖
<dependency>
<groupId>com.github.yuyenews</groupId>
<artifactId>Magician-ContractsTools</artifactId>
<version>1.0.4</version>
</dependency>
<!-- 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 -->
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-jdk14</artifactId>
<version>1.7.12</version>
</dependency>
# 合约查询 以及 写入
初始化合约工具对象
String privateKey = ""; // 私钥
Web3j web3j = Web3j.build(new HttpService("https://data-seed-prebsc-1-s1.binance.org:8545/")); // 链的RPC地址
String contractAddress = "";
EthContractUtil ethContractUtil = EthContractUtil.builder(web3j);
查询合约
List<Type> result = ethContractUtil.select(
contractAddress, // 合约地址
EthAbiCodecTool.getInputData(
"balanceOf", // 要调用的方法名称
new Address(toAddress) // 方法的参数,如果有多个,可以继续传入下一个参数
), // 要调用的方法的inputData
new TypeReference<Uint256>() {} // 方法的返回类型,如果有多个返回值,可以继续传入下一个参数
);
写入合约
// 往合约里写入数据
SendResultModel sendResultModel = ethContractUtil.sendRawTransaction(
SendModel.builder()
.setSenderAddress("0xb4e32492E9725c3215F1662Cf28Db1862ed1EE84") // 调用者的地址
.setPrivateKey("")// senderAddress的私钥
.setToAddress(contractAddress) // 合约地址
.setValue(new BigInteger("1000000000")) // 主链币数量,如果想用默认值 可以直接传null,或者不传这个参数
.setGasPrice(new BigInteger("1000")) // gasPrice,如果想用默认值 可以直接传null,或者不传这个参数
.setGasLimit(new BigInteger("800000")) // gasLimit,如果想用默认值 可以直接传null,或者不传这个参数
.setNonce(new BigInteger("100")), // 自定义nonce,如果想要默认值 可以直接传null,或者不传这个参数
.setChainId(97) // 设置链ID
EthAbiCodecTool.getInputData(
"transfer", // 要调用的方法名称
new Address(toAddress), // 方法的参数,如果有多个,可以继续传入下一个参数
new Uint256(new BigInteger("1000000000000000000")) // 方法的参数,如果有多个,可以继续传入下一个参数
) // 要调用的方法的inputData
);
sendResultModel.getEthSendTransaction(); // 发送交易后的结果
sendResultModel.getEthGetTransactionReceipt(); // 交易成功上链后的结果
# 合约模板
目前只有三种模板,后面会继续增加
# 调用ERC20合约
初始化合约模板
Web3j web3j = Web3j.build(new HttpService("https://data-seed-prebsc-2-s1.binance.org:8545"));
String contractAddress = "";
ERC20Contract erc20Contract = ERC20Contract.builder(web3j, contractAddress);
查询
// 调用合约的 totalSupply 函数
BigInteger total = erc20Contract.totalSupply();
// 调用合约的 balanceOf 函数
BigInteger amount = erc20Contract.balanceOf("0xb4e32492E9725c3215F1662Cf28Db1862ed1EE84");
// 调用合约的 allowance 函数
BigInteger amount = erc20Contract.allowance("0xb4e32492E9725c3215F1662Cf28Db1862ed1EE84", "0x552115849813d334C58f2757037F68E2963C4c5e");
写入
// 调用合约的 transfer 函数
SendResultModel sendResultModel = erc20Contract.transfer(
"0x552115849813d334C58f2757037F68E2963C4c5e", // 转账接收人
new BigInteger("1000000000000000000"), // 转账金额
SendModel.builder()
.setSenderAddress("0xb4e32492E9725c3215F1662Cf28Db1862ed1EE84") // 调用者的地址
.setPrivateKey("")// senderAddress的私钥
.setValue(new BigInteger("1000000000")) // 主链币数量,如果想用默认值 可以直接传null,或者不传这个参数
.setGasPrice(new BigInteger("1000")) // gasPrice,如果想用默认值 可以直接传null,或者不传这个参数
.setGasLimit(new BigInteger("800000")) // gasLimit,如果想用默认值 可以直接传null,或者不传这个参数
);
sendResultModel.getEthSendTransaction(); // 发送交易后的结果
sendResultModel.getEthGetTransactionReceipt(); // 交易成功上链后的结果
// 调用合约的 transferFrom 函数
SendResultModel sendResultModel = erc20Contract.transferFrom(
"0xb4e32492E9725c3215F1662Cf28Db1862ed1EE84", // 转账付款人
"0x552115849813d334C58f2757037F68E2963C4c5e", // 转账接收人
new BigInteger("1000000000000000000"), // 转账金额
SendModel.builder()
.setSenderAddress("0xb4e32492E9725c3215F1662Cf28Db1862ed1EE84") // 调用者的地址
.setPrivateKey("")// senderAddress的私钥
.setValue(new BigInteger("1000000000")) // 主链币数量,如果想用默认值 可以直接传null,或者不传这个参数
.setGasPrice(new BigInteger("1000")) // gasPrice,如果想用默认值 可以直接传null,或者不传这个参数
.setGasLimit(new BigInteger("800000")) // gasLimit,如果想用默认值 可以直接传null,或者不传这个参数
);
sendResultModel.getEthSendTransaction(); // 发送交易后的结果
sendResultModel.getEthGetTransactionReceipt(); // 交易成功上链后的结果
// 调用合约的 approve 函数
SendResultModel sendResultModel = erc20Contract.approve(
"0x552115849813d334C58f2757037F68E2963C4c5e", // 被授权人
new BigInteger("1000000000000000000"), // 授权金额
SendModel.builder()
.setSenderAddress("0xb4e32492E9725c3215F1662Cf28Db1862ed1EE84") // 调用者的地址
.setPrivateKey("")// senderAddress的私钥
.setValue(new BigInteger("1000000000")) // 主链币数量,如果想用默认值 可以直接传null,或者不传这个参数
.setGasPrice(new BigInteger("1000")) // gasPrice,如果想用默认值 可以直接传null,或者不传这个参数
.setGasLimit(new BigInteger("800000")) // gasLimit,如果想用默认值 可以直接传null,或者不传这个参数
);
sendResultModel.getEthSendTransaction(); // 发送交易后的结果
sendResultModel.getEthGetTransactionReceipt(); // 交易成功上链后的结果
# 调用ERC721合约
初始化合约模板
Web3j web3j = Web3j.build(new HttpService("https://data-seed-prebsc-2-s1.binance.org:8545"));
String contractAddress = "";
ERC721Contract erc721Contract = ERC721Contract.builder(web3j, contractAddress);
查询
// 调用合约的 balanceOf 函数
BigInteger amount = erc20Contract.balanceOf("0xb4e32492E9725c3215F1662Cf28Db1862ed1EE84");
// 调用合约的 ownerOf 函数
String ownerAddress = erc721Contract.ownerOf(new BigInteger("1002"));
// 调用 isApprovedForAll 函数
Boolean result = erc1155Contract.isApprovedForAll("0xb4e32492E9725c3215F1662Cf28Db1862ed1EE84", "0x552115849813d334C58f2757037F68E2963C4c5e");
// 调用 getApproved 函数
String approvedAddress = erc721Contract.getApproved(new BigInteger("1002"));
写入
// 调用 approve 函数
SendResultModel sendResultModel = erc721Contract.approve(
"0x552115849813d334C58f2757037F68E2963C4c5e", // 被授权人
new BigInteger("1002"), // 授权的tokenId
SendModel.builder()
.setSenderAddress("0xb4e32492E9725c3215F1662Cf28Db1862ed1EE84") // 调用者的地址
.setPrivateKey("")// senderAddress的私钥
.setValue(new BigInteger("1000000000")) // 主链币数量,如果想用默认值 可以直接传null,或者不传这个参数
.setGasPrice(new BigInteger("1000")) // gasPrice,如果想用默认值 可以直接传null,或者不传这个参数
.setGasLimit(new BigInteger("800000")) // gasLimit,如果想用默认值 可以直接传null,或者不传这个参数
);
sendResultModel.getEthSendTransaction(); // 发送交易后的结果
sendResultModel.getEthGetTransactionReceipt(); // 交易成功上链后的结果
// 调用合约的 transferFrom 函数
SendResultModel sendResultModel = erc20Contract.transferFrom(
"0xb4e32492E9725c3215F1662Cf28Db1862ed1EE84", // 转账付款人
"0x552115849813d334C58f2757037F68E2963C4c5e", // 转账接收人
new BigInteger("1002"), // tokenId
SendModel.builder()
.setSenderAddress("0xb4e32492E9725c3215F1662Cf28Db1862ed1EE84") // 调用者的地址
.setPrivateKey("")// senderAddress的私钥
.setValue(new BigInteger("1000000000")) // 主链币数量,如果想用默认值 可以直接传null,或者不传这个参数
.setGasPrice(new BigInteger("1000")) // gasPrice,如果想用默认值 可以直接传null,或者不传这个参数
.setGasLimit(new BigInteger("800000")) // gasLimit,如果想用默认值 可以直接传null,或者不传这个参数
);
sendResultModel.getEthSendTransaction(); // 发送交易后的结果
sendResultModel.getEthGetTransactionReceipt(); // 交易成功上链后的结果
// 调用合约的 safeTransferFrom 函数(没有data参数的那个)
SendResultModel sendResultModel = erc20Contract.safeTransferFrom(
"0xb4e32492E9725c3215F1662Cf28Db1862ed1EE84", // 转账付款人
"0x552115849813d334C58f2757037F68E2963C4c5e", // 转账接收人
new BigInteger("1002"), // tokenId
SendModel.builder()
.setSenderAddress("0xb4e32492E9725c3215F1662Cf28Db1862ed1EE84") // 调用者的地址
.setPrivateKey("")// senderAddress的私钥
.setValue(new BigInteger("1000000000")) // 主链币数量,如果想用默认值 可以直接传null,或者不传这个参数
.setGasPrice(new BigInteger("1000")) // gasPrice,如果想用默认值 可以直接传null,或者不传这个参数
.setGasLimit(new BigInteger("800000")) // gasLimit,如果想用默认值 可以直接传null,或者不传这个参数
);
sendResultModel.getEthSendTransaction(); // 发送交易后的结果
sendResultModel.getEthGetTransactionReceipt(); // 交易成功上链后的结果
// 调用合约的 safeTransferFrom 函数(有data参数的那个)
SendResultModel sendResultModel = erc20Contract.safeTransferFrom(
"0xb4e32492E9725c3215F1662Cf28Db1862ed1EE84", // 转账付款人
"0x552115849813d334C58f2757037F68E2963C4c5e", // 转账接收人
new BigInteger("1002"), // tokenId
new byte[0], // data
SendModel.builder()
.setSenderAddress("0xb4e32492E9725c3215F1662Cf28Db1862ed1EE84") // 调用者的地址
.setPrivateKey("")// senderAddress的私钥
.setValue(new BigInteger("1000000000")) // 主链币数量,如果想用默认值 可以直接传null,或者不传这个参数
.setGasPrice(new BigInteger("1000")) // gasPrice,如果想用默认值 可以直接传null,或者不传这个参数
.setGasLimit(new BigInteger("800000")) // gasLimit,如果想用默认值 可以直接传null,或者不传这个参数
);
sendResultModel.getEthSendTransaction(); // 发送交易后的结果
sendResultModel.getEthGetTransactionReceipt(); // 交易成功上链后的结果
// 调用 setApprovalForAll 函数
SendResultModel sendResultModel = erc1155Contract.setApprovalForAll(
"0x552115849813d334C58f2757037F68E2963C4c5e", // 被授权人
true, // 是否授权全部
SendModel.builder()
.setSenderAddress("0xb4e32492E9725c3215F1662Cf28Db1862ed1EE84") // 调用者的地址
.setPrivateKey("")// senderAddress的私钥
.setValue(new BigInteger("1000000000")) // 主链币数量,如果想用默认值 可以直接传null,或者不传这个参数
.setGasPrice(new BigInteger("1000")) // gasPrice,如果想用默认值 可以直接传null,或者不传这个参数
.setGasLimit(new BigInteger("800000")) // gasLimit,如果想用默认值 可以直接传null,或者不传这个参数
);
sendResultModel.getEthSendTransaction(); // 发送交易后的结果
sendResultModel.getEthGetTransactionReceipt(); // 交易成功上链后的结果
# 调用ERC1155合约
初始化合约模板
Web3j web3j = Web3j.build(new HttpService("https://data-seed-prebsc-2-s1.binance.org:8545"));
String contractAddress = "";
ERC1155Contract erc1155Contract = ERC1155Contract.builder(web3j, contractAddress);
查询
// 调用 balanceOf 函数
BigInteger amount = erc1155Contract.balanceOf("0x552115849813d334C58f2757037F68E2963C4c5e", new BigInteger("0"));
// 调用 balanceOfBatch 函数
List<String> address = new ArrayList<>();
address.add("0xb4e32492E9725c3215F1662Cf28Db1862ed1EE84");
address.add("0x552115849813d334C58f2757037F68E2963C4c5e");
List<BigInteger> tokenId = new ArrayList<>();
tokenId.add(new BigInteger("0"));
tokenId.add(new BigInteger("0"));
List<BigInteger> amounts = erc1155Contract.balanceOfBatch(address, tokenId);
// 调用 isApprovedForAll 函数
Boolean result = erc1155Contract.isApprovedForAll("0xb4e32492E9725c3215F1662Cf28Db1862ed1EE84", "0x552115849813d334C58f2757037F68E2963C4c5e");
写入
// 调用 setApprovalForAll 函数
SendResultModel sendResultModel = erc1155Contract.setApprovalForAll(
"0x552115849813d334C58f2757037F68E2963C4c5e", // 被授权人
true, // 是否授权全部
SendModel.builder()
.setSenderAddress("0xb4e32492E9725c3215F1662Cf28Db1862ed1EE84") // 调用者的地址
.setPrivateKey("")// senderAddress的私钥
.setValue(new BigInteger("1000000000")) // 主链币数量,如果想用默认值 可以直接传null,或者不传这个参数
.setGasPrice(new BigInteger("1000")) // gasPrice,如果想用默认值 可以直接传null,或者不传这个参数
.setGasLimit(new BigInteger("800000")) // gasLimit,如果想用默认值 可以直接传null,或者不传这个参数
);
sendResultModel.getEthSendTransaction(); // 发送交易后的结果
sendResultModel.getEthGetTransactionReceipt(); // 交易成功上链后的结果
// 调用 safeTransferFrom 函数
SendResultModel sendResultModel = erc1155Contract.safeTransferFrom(
"0xb4e32492E9725c3215F1662Cf28Db1862ed1EE84", // 转账付款人
"0x552115849813d334C58f2757037F68E2963C4c5e", // 转账接收人
new BigInteger("1002"), // tokenId
new BigInteger("1"), // 数量
new byte[0], // data
SendModel.builder()
.setSenderAddress("0xb4e32492E9725c3215F1662Cf28Db1862ed1EE84") // 调用者的地址
.setPrivateKey("")// senderAddress的私钥
.setValue(new BigInteger("1000000000")) // 主链币数量,如果想用默认值 可以直接传null,或者不传这个参数
.setGasPrice(new BigInteger("1000")) // gasPrice,如果想用默认值 可以直接传null,或者不传这个参数
.setGasLimit(new BigInteger("800000")) // gasLimit,如果想用默认值 可以直接传null,或者不传这个参数
);
sendResultModel.getEthSendTransaction(); // 发送交易后的结果
sendResultModel.getEthGetTransactionReceipt(); // 交易成功上链后的结果
// 调用 safeBatchTransferFrom 函数
List<BigInteger> tokenIds = new ArrayList<>();
tokenIds.add(new BigInteger("1002"));
tokenIds.add(new BigInteger("1003"));
List<BigInteger> amounts = new ArrayList<>();
amounts.add(new BigInteger("1"));
amounts.add(new BigInteger("10"));
SendResultModel sendResultModel = erc1155Contract.safeBatchTransferFrom(
"0xb4e32492E9725c3215F1662Cf28Db1862ed1EE84", // 转账付款人
"0x552115849813d334C58f2757037F68E2963C4c5e", // 转账接收人
tokenIds, // tokenId 集合
amounts, // 数量 集合
new byte[0], // data
SendModel.builder()
.setSenderAddress("0xb4e32492E9725c3215F1662Cf28Db1862ed1EE84") // 调用者的地址
.setPrivateKey("")// senderAddress的私钥
.setValue(new BigInteger("1000000000")) // 主链币数量,如果想用默认值 可以直接传null,或者不传这个参数
.setGasPrice(new BigInteger("1000")) // gasPrice,如果想用默认值 可以直接传null,或者不传这个参数
.setGasLimit(new BigInteger("800000")) // gasLimit,如果想用默认值 可以直接传null,或者不传这个参数
);
sendResultModel.getEthSendTransaction(); // 发送交易后的结果
sendResultModel.getEthGetTransactionReceipt(); // 交易成功上链后的结果
# InputData 编解码
// 编码
String inputData = EthAbiCodecTool.getInputData(
"transfer", // 方法名
new Address(toAddress), // 参数1
new Uint256(new BigInteger("1000000000000000000")) // 参数2,如果还有其他参数,可以继续传入下一个
);
// 解码
List<Type> result = EthAbiCodecTool.decoderInputData(
"0x" + inputData.substring(10), // 去除方法签名的inputData
new TypeReference<Address>() {}, // 被编码的方法的参数1 类型
new TypeReference<Uint256>() {} // 被编码的方法的参数2 类型, 如果还有其他参数,可以继续传入下一个
);
for(Type type : result){
System.out.println(type.getValue());
}
// 获取方法签名,其实就是inputData的前十位
String functionCode = EthAbiCodecTool.getFunAbiCode(
"transfer", // 方法名
new Address(toAddress), // 参数1,值随意传,反正我们要的方法签名,不是完整的inputData
new Uint256(new BigInteger("1000000000000000000")) // 参数2,值随意传,反正我们要的方法签名,不是完整的inputData,如果还有其他参数,可以继续传入下一个
);
# 主链币查询以及转账
String privateKey = ""; // 私钥
Web3j web3j = Web3j.build(new HttpService("https://data-seed-prebsc-1-s1.binance.org:8545/")); // 链的RPC地址
EthHelper ethHelper = EthHelper.builder(web3j);
// 余额查询
BigInteger balance = ethHelper.balanceOf(fromAddress);
// 转账
TransactionReceipt transactionReceipt = ethHelper.transfer(
toAddress,
privateKey,
BigDecimal.valueOf(1),
Convert.Unit.ETHER
);