diff --git a/src/main/java/conflux/web3j/contract/ContractCall.java b/src/main/java/conflux/web3j/contract/ContractCall.java index 2a192ce..af6253a 100644 --- a/src/main/java/conflux/web3j/contract/ContractCall.java +++ b/src/main/java/conflux/web3j/contract/ContractCall.java @@ -3,9 +3,15 @@ import java.math.BigInteger; import java.util.Arrays; import java.util.Collections; +import java.util.List; +import conflux.web3j.request.LogFilter; +import conflux.web3j.response.Log; import org.web3j.abi.FunctionEncoder; +import org.web3j.abi.TypeReference; +import org.web3j.abi.datatypes.DynamicArray; import org.web3j.abi.datatypes.Function; +import org.web3j.abi.datatypes.StaticArray; import org.web3j.abi.datatypes.Type; import conflux.web3j.Cfx; @@ -90,4 +96,17 @@ public > D callAndGet(Class returnType, String method, T return DecodeUtil.decode(rawData, returnType); } + public > List callAndGet(TypeReference> returnType, String method, Type... args) { + String rawData = this.call(method, args).sendAndGet(); + return DecodeUtil.decode(rawData, returnType); + } + + public > List callAndGet(TypeReference.StaticArrayTypeReference> returnType, String method, Type... args) { + String rawData = this.call(method, args).sendAndGet(); + return DecodeUtil.decode(rawData, returnType); + } + + public List getLogs(LogFilter filter) { + return this.cfx.getLogs(filter).sendAndGet(); + } } diff --git a/src/main/java/conflux/web3j/contract/internals/CrossSpaceCall.java b/src/main/java/conflux/web3j/contract/internals/CrossSpaceCall.java index f7c9122..6a208c8 100644 --- a/src/main/java/conflux/web3j/contract/internals/CrossSpaceCall.java +++ b/src/main/java/conflux/web3j/contract/internals/CrossSpaceCall.java @@ -4,12 +4,24 @@ import conflux.web3j.Cfx; import conflux.web3j.RpcException; import conflux.web3j.contract.ContractCall; +import conflux.web3j.request.Epoch; +import conflux.web3j.request.LogFilter; +import conflux.web3j.response.Log; +import conflux.web3j.response.Receipt; +import conflux.web3j.response.events.LogNotification; import conflux.web3j.types.CfxAddress; import java.math.BigInteger; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; -import org.web3j.abi.datatypes.Address; -import org.web3j.abi.datatypes.DynamicBytes; +import io.reactivex.Flowable; +import io.reactivex.functions.Function; +import org.web3j.abi.DefaultFunctionReturnDecoder; +import org.web3j.abi.FunctionReturnDecoder; +import org.web3j.abi.TypeReference; +import org.web3j.abi.datatypes.*; import org.web3j.abi.datatypes.generated.Uint256; import org.web3j.utils.Numeric; import org.web3j.abi.datatypes.generated.Bytes20; @@ -18,7 +30,38 @@ public class CrossSpaceCall extends ContractCall{ private final static String contract = "0x0888000000000000000000000000000000000006"; private Account account; // if account not set, can only use read method private CfxAddress contractAddress; - + + public static final Event Call_EVENT = new Event("Call", + Arrays.>asList( + new TypeReference(true) {}, + new TypeReference(true) {}, + new TypeReference(false) {}, + new TypeReference(false) {}, + new TypeReference(false) {} + )); + + public static final Event Create_EVENT = new Event("Create", + Arrays.>asList( + new TypeReference(true) {}, + new TypeReference(true) {}, + new TypeReference(false) {}, + new TypeReference(false) {}, + new TypeReference(false) {} + )); + + public static final Event Withdraw_EVENT = new Event("Withdraw", + Arrays.>asList( + new TypeReference(true) {}, + new TypeReference
(true) {}, + new TypeReference(false) {}, + new TypeReference(false) {} + )); + + public static final Event Outcome_EVENT = new Event("Outcome", + Arrays.>asList( + new TypeReference(false) {} + )); + public CrossSpaceCall(Account account) { super(account.getCfx(), new CfxAddress(CrossSpaceCall.contract, account.getCfx().getIntNetworkId())); this.contractAddress = new CfxAddress(CrossSpaceCall.contract, account.getCfx().getIntNetworkId()); @@ -71,11 +114,322 @@ public String withdrawFromMapped(Account.Option option, BigInteger value)throws } public BigInteger mappedBalance(Address addr)throws RpcException{ - return this.callAndGet(Uint256.class, "mappedBalance", addr); + return this.callAndGet(Uint256.class, "mappedBalance", addr); } public BigInteger mappedNonce(Address addr)throws RpcException{ return this.callAndGet(Uint256.class, "mappedNonce", addr); } + public List getCallEvents(Receipt transactionReceipt) { + LogFilter filter = LogFilter.generateLogFilter( + Call_EVENT, + this.contractAddress + ); + filter.setBlockHashes(Arrays.asList(transactionReceipt.getBlockHash())); + + List logs = this.getLogs(filter); + ArrayList responses = new ArrayList(); + + for (Log log : logs) { + String senderTopic = log.getTopics().get(1); + String receiverTopic = log.getTopics().get(2); + Bytes20 sender = (Bytes20) DefaultFunctionReturnDecoder.decodeIndexedValue(senderTopic, TypeReference.create(Bytes20.class)); + Bytes20 receiver = (Bytes20) DefaultFunctionReturnDecoder.decodeIndexedValue(receiverTopic, TypeReference.create(Bytes20.class)); + + CallEventResponse typedResponse = new CallEventResponse(); + String rawData = log.getData(); + List outputParameters = new ArrayList>(); + outputParameters.add(new TypeReference() {}); + outputParameters.add(new TypeReference() {}); + outputParameters.add(new TypeReference() {}); + + List list = FunctionReturnDecoder.decode(rawData, outputParameters); + + typedResponse.sender = sender.getValue(); + typedResponse.receiver = receiver.getValue(); + typedResponse.value = (BigInteger) list.get(0).getValue(); + typedResponse.nonce = (BigInteger) list.get(1).getValue(); + typedResponse.data = (byte[]) list.get(2).getValue(); + + responses.add(typedResponse); + } + + return responses; + } + + public List getCreateEvents(Receipt transactionReceipt) { + LogFilter filter = LogFilter.generateLogFilter( + Call_EVENT, + this.contractAddress + ); + filter.setBlockHashes(Arrays.asList(transactionReceipt.getBlockHash())); + + List logs = this.getLogs(filter); + ArrayList responses = new ArrayList(); + + for (Log log : logs) { + String senderTopic = log.getTopics().get(1); + String contractTopic = log.getTopics().get(2); + Bytes20 sender = (Bytes20) DefaultFunctionReturnDecoder.decodeIndexedValue(senderTopic, TypeReference.create(Bytes20.class)); + Bytes20 contract_address = (Bytes20) DefaultFunctionReturnDecoder.decodeIndexedValue(contractTopic, TypeReference.create(Bytes20.class)); + + CreateEventResponse typedResponse = new CreateEventResponse(); + String rawData = log.getData(); + List outputParameters = new ArrayList>(); + outputParameters.add(new TypeReference() {}); + outputParameters.add(new TypeReference() {}); + outputParameters.add(new TypeReference() {}); + + List list = FunctionReturnDecoder.decode(rawData, outputParameters); + + typedResponse.sender = sender.getValue(); + typedResponse.contract_address = contract_address.getValue(); + typedResponse.value = (BigInteger) list.get(0).getValue(); + typedResponse.nonce = (BigInteger) list.get(1).getValue(); + typedResponse.init = (byte[]) list.get(2).getValue(); + + responses.add(typedResponse); + } + + return responses; + } + + public List getWithdrawEvents(Receipt transactionReceipt) { + LogFilter filter = LogFilter.generateLogFilter( + Call_EVENT, + this.contractAddress + ); + filter.setBlockHashes(Arrays.asList(transactionReceipt.getBlockHash())); + + List logs = this.getLogs(filter); + ArrayList responses = new ArrayList(); + + for (Log log : logs) { + System.out.println(log.getTopics().size()); + String senderTopic = log.getTopics().get(1); + String receiverTopic = log.getTopics().get(2); + Bytes20 sender = (Bytes20) DefaultFunctionReturnDecoder.decodeIndexedValue(senderTopic, TypeReference.create(Bytes20.class)); + Address receiver = (Address) DefaultFunctionReturnDecoder.decodeIndexedValue(receiverTopic, TypeReference.create(Address.class)); + + WithdrawEventResponse typedResponse = new WithdrawEventResponse(); + String rawData = log.getData(); + List outputParameters = new ArrayList>(); + outputParameters.add(new TypeReference() {}); + outputParameters.add(new TypeReference() {}); + + List list = FunctionReturnDecoder.decode(rawData, outputParameters); + + typedResponse.sender = sender.getValue(); + typedResponse.receiver = receiver.getValue(); + typedResponse.value = (BigInteger) list.get(0).getValue(); + typedResponse.nonce = (BigInteger) list.get(1).getValue(); + + responses.add(typedResponse); + } + + return responses; + } + + public List getOutcomeEvents(Receipt transactionReceipt) { + LogFilter filter = LogFilter.generateLogFilter( + Call_EVENT, + this.contractAddress + ); + filter.setBlockHashes(Arrays.asList(transactionReceipt.getBlockHash())); + + List logs = this.getLogs(filter); + ArrayList responses = new ArrayList(); + + for (Log log : logs) { + OutcomeEventResponse typedResponse = new OutcomeEventResponse(); + String rawData = log.getData(); + List outputParameters = new ArrayList>(); + outputParameters.add(new TypeReference() {}); + + List list = FunctionReturnDecoder.decode(rawData, outputParameters); + + typedResponse.success = (Boolean) list.get(0).getValue(); + + responses.add(typedResponse); + } + + return responses; + } + + public Flowable CallEventFlowable(Cfx cfxPubsub, Epoch startEpoch, Epoch endEpoch) throws Exception{ + return CallEventFlowable( + cfxPubsub, + LogFilter.generateLogFilter( + Epoch.earliest(), + Epoch.latestState(), + Call_EVENT, + this.contractAddress + ) + ); + } + + public Flowable CreateEventFlowable(Cfx cfxPubsub, Epoch startEpoch, Epoch endEpoch) throws Exception{ + return CreateEventFlowable( + cfxPubsub, + LogFilter.generateLogFilter( + Epoch.earliest(), + Epoch.latestState(), + Create_EVENT, + this.contractAddress + ) + ); + } + + public Flowable WithdrawEventFlowable(Cfx cfxPubsub, Epoch startEpoch, Epoch endEpoch) throws Exception{ + return WithdrawEventFlowable(cfxPubsub, + LogFilter.generateLogFilter( + Epoch.earliest(), + Epoch.latestState(), + Withdraw_EVENT, + this.contractAddress + ) + ); + } + + public Flowable OutcomeEventFlowable(Cfx cfxPubsub, Epoch startEpoch, Epoch endEpoch) throws Exception{ + return OutcomeEventFlowable(cfxPubsub, + LogFilter.generateLogFilter( + Epoch.earliest(), + Epoch.latestState(), + Outcome_EVENT, + this.contractAddress + ) + ); + } + + public Flowable CallEventFlowable(Cfx cfxPubsub, LogFilter filter)throws Exception { + return cfxPubsub.subscribeLogs(filter).map(new Function(){ + @Override + public CallEventResponse apply(LogNotification log) { + String senderTopic = log.getParams().getResult().getTopics().get(1); + String receiverTopic = log.getParams().getResult().getTopics().get(2); + Bytes20 sender = (Bytes20) DefaultFunctionReturnDecoder.decodeIndexedValue(senderTopic, TypeReference.create(Bytes20.class)); + Bytes20 receiver = (Bytes20) DefaultFunctionReturnDecoder.decodeIndexedValue(receiverTopic, TypeReference.create(Bytes20.class)); + + CallEventResponse typedResponse = new CallEventResponse(); + String rawData = log.getParams().getResult().getData(); + List outputParameters = new ArrayList>(); + outputParameters.add(new TypeReference() {}); + outputParameters.add(new TypeReference() {}); + outputParameters.add(new TypeReference() {}); + + List list = FunctionReturnDecoder.decode(rawData, outputParameters); + + typedResponse.sender = sender.getValue(); + typedResponse.receiver = receiver.getValue(); + typedResponse.value = (BigInteger) list.get(0).getValue(); + typedResponse.nonce = (BigInteger) list.get(1).getValue(); + typedResponse.data = (byte[]) list.get(2).getValue(); + + return typedResponse; + } + }); + } + + public Flowable CreateEventFlowable(Cfx cfxPubsub, LogFilter filter)throws Exception { + return cfxPubsub.subscribeLogs(filter).map(new Function(){ + @Override + public CreateEventResponse apply(LogNotification log) { + String senderTopic = log.getParams().getResult().getTopics().get(1); + String receiverTopic = log.getParams().getResult().getTopics().get(2); + Bytes20 sender = (Bytes20) DefaultFunctionReturnDecoder.decodeIndexedValue(senderTopic, TypeReference.create(Bytes20.class)); + Bytes20 contract_address = (Bytes20) DefaultFunctionReturnDecoder.decodeIndexedValue(receiverTopic, TypeReference.create(Bytes20.class)); + + CreateEventResponse typedResponse = new CreateEventResponse(); + String rawData = log.getParams().getResult().getData(); + List outputParameters = new ArrayList>(); + outputParameters.add(new TypeReference() {}); + outputParameters.add(new TypeReference() {}); + outputParameters.add(new TypeReference() {}); + + List list = FunctionReturnDecoder.decode(rawData, outputParameters); + + typedResponse.sender = sender.getValue(); + typedResponse.contract_address = contract_address.getValue(); + typedResponse.value = (BigInteger) list.get(0).getValue(); + typedResponse.nonce = (BigInteger) list.get(1).getValue(); + typedResponse.init = (byte[]) list.get(2).getValue(); + + return typedResponse; + } + }); + } + + public Flowable WithdrawEventFlowable(Cfx cfxPubsub, LogFilter filter)throws Exception { + return cfxPubsub.subscribeLogs(filter).map(new Function(){ + @Override + public WithdrawEventResponse apply(LogNotification log) { + String senderTopic = log.getParams().getResult().getTopics().get(1); + String receiverTopic = log.getParams().getResult().getTopics().get(2); + Bytes20 sender = (Bytes20) DefaultFunctionReturnDecoder.decodeIndexedValue(senderTopic, TypeReference.create(Bytes20.class)); + Address receiver = (Address) DefaultFunctionReturnDecoder.decodeIndexedValue(receiverTopic, TypeReference.create(Address.class)); + + WithdrawEventResponse typedResponse = new WithdrawEventResponse(); + String rawData = log.getParams().getResult().getData(); + List outputParameters = new ArrayList>(); + outputParameters.add(new TypeReference() {}); + outputParameters.add(new TypeReference() {}); + + List list = FunctionReturnDecoder.decode(rawData, outputParameters); + + typedResponse.sender = sender.getValue(); + typedResponse.receiver = receiver.getValue(); + typedResponse.value = (BigInteger) list.get(0).getValue(); + typedResponse.nonce = (BigInteger) list.get(1).getValue(); + + return typedResponse; + } + }); + } + + public Flowable OutcomeEventFlowable(Cfx cfxPubsub, LogFilter filter)throws Exception { + return cfxPubsub.subscribeLogs(filter).map(new Function(){ + @Override + public OutcomeEventResponse apply(LogNotification log) { + OutcomeEventResponse typedResponse = new OutcomeEventResponse(); + String rawData = log.getParams().getResult().getData(); + List outputParameters = new ArrayList>(); + outputParameters.add(new TypeReference() {}); + + List list = FunctionReturnDecoder.decode(rawData, outputParameters); + + typedResponse.success = (Boolean) list.get(0).getValue(); + + return typedResponse; + } + }); + } + + public static class CallEventResponse extends LogNotification { + public byte[] sender; + public byte[] receiver; + public BigInteger value; + public BigInteger nonce; + public byte[] data; + } + + public static class CreateEventResponse extends LogNotification { + public byte[] sender; + public byte[] contract_address; + public BigInteger value; + public BigInteger nonce; + public byte[] init; + } + + public static class WithdrawEventResponse extends LogNotification { + public byte[] sender; + public String receiver; + public BigInteger value; + public BigInteger nonce; + } + + public static class OutcomeEventResponse extends LogNotification { + public Boolean success; + } } diff --git a/src/main/java/conflux/web3j/contract/internals/PoSRegister.java b/src/main/java/conflux/web3j/contract/internals/PoSRegister.java index c59421a..c5c5b5c 100644 --- a/src/main/java/conflux/web3j/contract/internals/PoSRegister.java +++ b/src/main/java/conflux/web3j/contract/internals/PoSRegister.java @@ -4,22 +4,52 @@ import conflux.web3j.Cfx; import conflux.web3j.RpcException; import conflux.web3j.contract.ContractCall; +import conflux.web3j.request.Epoch; +import conflux.web3j.request.LogFilter; +import conflux.web3j.response.Log; +import conflux.web3j.response.Receipt; +import conflux.web3j.response.events.LogNotification; import conflux.web3j.types.CfxAddress; import conflux.web3j.contract.abi.TupleDecoder; import java.math.BigInteger; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; -import org.web3j.abi.datatypes.Address; +import io.reactivex.Flowable; +import io.reactivex.functions.Function; + +import org.web3j.abi.DefaultFunctionReturnDecoder; +import org.web3j.abi.FunctionReturnDecoder; +import org.web3j.abi.TypeReference; +import org.web3j.abi.datatypes.*; import org.web3j.abi.datatypes.generated.Uint64; import org.web3j.abi.datatypes.generated.Bytes32; import org.web3j.utils.Numeric; - - public class PoSRegister extends ContractCall{ private final static String contract = "0x0888000000000000000000000000000000000005"; private Account account; // if account not set, can only use read method private CfxAddress contractAddress; + public static final Event REGISTER_EVENT = new Event("Register", + Arrays.>asList( + new TypeReference(true) {}, + new TypeReference(false) {}, + new TypeReference(false) {} + )); + + public static final Event INCREASE_STAKE_EVENT = new Event("IncreaseStake", + Arrays.>asList( + new TypeReference(true) {}, + new TypeReference(false) {} + )); + + public static final Event RETIRE_EVENT = new Event("Retire", + Arrays.>asList( + new TypeReference(true) {}, + new TypeReference(false) {} + )); public PoSRegister(Account account) { super(account.getCfx(), new CfxAddress(PoSRegister.contract, account.getCfx().getIntNetworkId())); @@ -90,4 +120,216 @@ public Bytes32 addressToIdentifier(Address addr)throws RpcException{ byte[] bytes = this.callAndGet(Bytes32.class, "addressToIdentifier", addr); return new Bytes32(bytes); } + + public List getRegisterEvents(Receipt transactionReceipt) { + LogFilter filter = LogFilter.generateLogFilter( + REGISTER_EVENT, + this.contractAddress + ); + filter.setBlockHashes(Arrays.asList(transactionReceipt.getBlockHash())); + + List logs = this.getLogs(filter); + + ArrayList responses = new ArrayList(); + + for (Log log : logs) { + String identifierTopic = log.getTopics().get(1); + Bytes32 identifier = (Bytes32) DefaultFunctionReturnDecoder.decodeIndexedValue(identifierTopic, TypeReference.create(Bytes32.class)); + + RegisterEventResponse typedResponse = new RegisterEventResponse(); + String rawData = log.getData(); + List outputParameters = new ArrayList>(); + outputParameters.add(new TypeReference() {}); + outputParameters.add(new TypeReference() {}); + + List list = FunctionReturnDecoder.decode(rawData, outputParameters); + + typedResponse.identifier = identifier.getValue(); + typedResponse.blsPubKey = (byte[]) list.get(0).getValue(); + typedResponse.vrfPubKey = (byte[]) list.get(1).getValue(); + + responses.add(typedResponse); + } + + return responses; + } + + public List getIncreaseStakeEvents(Receipt transactionReceipt) { + LogFilter filter = LogFilter.generateLogFilter( + INCREASE_STAKE_EVENT, + this.contractAddress + ); + filter.setBlockHashes(Arrays.asList(transactionReceipt.getBlockHash())); + + List logs = this.getLogs(filter); + ArrayList responses = new ArrayList(); + + for (Log log : logs) { + String identifierTopic = log.getTopics().get(1); + Bytes32 identifier = (Bytes32) DefaultFunctionReturnDecoder.decodeIndexedValue(identifierTopic, TypeReference.create(Bytes32.class)); + + IncreaseStakeEventResponse typedResponse = new IncreaseStakeEventResponse(); + String rawData = log.getData(); + List outputParameters = new ArrayList>(); + outputParameters.add(new TypeReference() {}); + + List list = FunctionReturnDecoder.decode(rawData, outputParameters); + + typedResponse.identifier = identifier.getValue(); + typedResponse.votePower = (BigInteger) list.get(0).getValue(); + + responses.add(typedResponse); + } + + return responses; + } + + public List getRetireEvents(Receipt transactionReceipt) { + LogFilter filter = LogFilter.generateLogFilter( + RETIRE_EVENT, + this.contractAddress + ); + filter.setBlockHashes(Arrays.asList(transactionReceipt.getBlockHash())); + + List logs = this.getLogs(filter); + ArrayList responses = new ArrayList(); + + for (Log log : logs) { + String identifierTopic = log.getTopics().get(1); + Bytes32 identifier = (Bytes32) DefaultFunctionReturnDecoder.decodeIndexedValue(identifierTopic, TypeReference.create(Bytes32.class)); + + RetireEventResponse typedResponse = new RetireEventResponse(); + String rawData = log.getData(); + List outputParameters = new ArrayList>(); + outputParameters.add(new TypeReference() {}); + + List list = FunctionReturnDecoder.decode(rawData, outputParameters); + + typedResponse.identifier = identifier.getValue(); + typedResponse.votePower = (BigInteger) list.get(0).getValue(); + + responses.add(typedResponse); + } + + return responses; + } + + public Flowable RegisterEventFlowable(Cfx cfxPubsub, LogFilter filter)throws Exception { + return cfxPubsub.subscribeLogs(filter).map(new Function(){ + @Override + public RegisterEventResponse apply(LogNotification log) { + String identifierTopic = log.getParams().getResult().getTopics().get(1); + Bytes32 identifier = (Bytes32) DefaultFunctionReturnDecoder.decodeIndexedValue(identifierTopic, TypeReference.create(Bytes32.class)); + + RegisterEventResponse typedResponse = new RegisterEventResponse(); + String rawData = log.getParams().getResult().getData(); + + List outputParameters = new ArrayList>(); + outputParameters.add(new TypeReference() {}); + outputParameters.add(new TypeReference() {}); + List list = FunctionReturnDecoder.decode(rawData, outputParameters); + typedResponse.identifier = identifier.getValue(); + typedResponse.blsPubKey = (byte[]) list.get(0).getValue(); + typedResponse.vrfPubKey = (byte[]) list.get(1).getValue(); + + return typedResponse; + } + }); + } + + public Flowable RegisterEventFlowable(Cfx cfxPubsub, Epoch startEpoch, Epoch endEpoch) throws Exception{ + return RegisterEventFlowable( + cfxPubsub, + LogFilter.generateLogFilter( + Epoch.earliest(), + Epoch.latestState(), + REGISTER_EVENT, + this.contractAddress + ) + ); + } + + public Flowable IncreaseStakeEventFlowable(Cfx cfxPubsub, LogFilter filter)throws Exception { + return cfxPubsub.subscribeLogs(filter).map(new Function(){ + @Override + public IncreaseStakeEventResponse apply(LogNotification log) { + String identifierTopic = log.getParams().getResult().getTopics().get(1); + Bytes32 identifier = (Bytes32) DefaultFunctionReturnDecoder.decodeIndexedValue(identifierTopic, TypeReference.create(Bytes32.class)); + + IncreaseStakeEventResponse typedResponse = new IncreaseStakeEventResponse(); + String rawData = log.getParams().getResult().getData(); + List outputParameters = new ArrayList>(); + outputParameters.add(new TypeReference() {}); + + List list = FunctionReturnDecoder.decode(rawData, outputParameters); + + typedResponse.identifier = identifier.getValue(); + typedResponse.votePower = (BigInteger) list.get(0).getValue(); + + return typedResponse; + } + }); + } + + public Flowable IncreaseStakeEventFlowable(Cfx cfxPubsub, Epoch startEpoch, Epoch endEpoch) throws Exception{ + return RegisterEventFlowable( + cfxPubsub, + LogFilter.generateLogFilter( + Epoch.earliest(), + Epoch.latestState(), + INCREASE_STAKE_EVENT, + this.contractAddress + ) + ); + } + + public Flowable RetireEventFlowable(Cfx cfxPubsub, LogFilter filter)throws Exception { + return cfxPubsub.subscribeLogs(filter).map(new Function(){ + @Override + public RetireEventResponse apply(LogNotification log) { + String identifierTopic = log.getParams().getResult().getTopics().get(1); + Bytes32 identifier = (Bytes32) DefaultFunctionReturnDecoder.decodeIndexedValue(identifierTopic, TypeReference.create(Bytes32.class)); + + RetireEventResponse typedResponse = new RetireEventResponse(); + String rawData = log.getParams().getResult().getData(); + List outputParameters = new ArrayList>(); + outputParameters.add(new TypeReference() {}); + + List list = FunctionReturnDecoder.decode(rawData, outputParameters); + + typedResponse.identifier = identifier.getValue(); + typedResponse.votePower = (BigInteger) list.get(0).getValue(); + + return typedResponse; + } + }); + } + + public Flowable RetireEventFlowable(Cfx cfxPubsub, Epoch startEpoch, Epoch endEpoch) throws Exception{ + return RegisterEventFlowable( + cfxPubsub, + LogFilter.generateLogFilter( + Epoch.earliest(), + Epoch.latestState(), + RETIRE_EVENT, + this.contractAddress + ) + ); + } + + public static class RegisterEventResponse extends LogNotification { + public byte[] identifier; + public byte[] blsPubKey; + public byte[] vrfPubKey; + } + + public static class IncreaseStakeEventResponse extends LogNotification { + public byte[] identifier; + public BigInteger votePower; + } + + public static class RetireEventResponse extends LogNotification { + public byte[] identifier; + public BigInteger votePower; + } } diff --git a/src/main/java/conflux/web3j/request/LogFilter.java b/src/main/java/conflux/web3j/request/LogFilter.java index 64735b6..4eac847 100644 --- a/src/main/java/conflux/web3j/request/LogFilter.java +++ b/src/main/java/conflux/web3j/request/LogFilter.java @@ -1,8 +1,13 @@ package conflux.web3j.request; import java.math.BigInteger; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collections; import java.util.List; +import org.web3j.abi.EventEncoder; +import org.web3j.abi.datatypes.Event; import org.web3j.utils.Numeric; import conflux.web3j.types.Address; @@ -79,4 +84,34 @@ public String getOffset() { public void setOffset(Long offset) { this.offset = offset; } + + public static LogFilter generateLogFilter(Epoch startEpoch, Epoch endEpoch, Event event, Address contract){ + LogFilter filter = new LogFilter(); + List addresses = Arrays.asList(contract); + filter.setAddress(addresses); + filter.setFromEpoch(startEpoch); + filter.setToEpoch(endEpoch); + + List> topics = new ArrayList>(); + List topic = Arrays.asList(EventEncoder.encode(event)); + topics.add(topic); + + filter.setTopics(topics); + + return filter; + } + + public static LogFilter generateLogFilter(Event event, Address contract){ + LogFilter filter = new LogFilter(); + List addresses = Arrays.asList(contract); + filter.setAddress(addresses); + List> topics = new ArrayList>(); + List topic = Arrays.asList(EventEncoder.encode(event)); + + topics.add(topic); + + filter.setTopics(topics); + + return filter; + } }