Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Examples use-cases - get transaction #83

Merged
merged 20 commits into from
Aug 20, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -82,13 +82,14 @@ private FlowTransactionResult waitForSeal(FlowId txID) {

private FlowAddress getAccountCreatedAddress(FlowTransactionResult txResult) {
FlowEvent event = txResult.getEvents().stream()
.filter(it -> "flow.AccountCreated".equals(it.getType()))
.filter(it -> "flow.AccountCreated".equals(it.getType()))
.findFirst()
.orElseThrow(() -> new RuntimeException("account created event not found"));

EventField field = (EventField) event.getPayload().getJsonCadence();
String address = (String) field.getValue().getRequiredField("address").getValue();

assert address != null;
return new FlowAddress(address);
}

Expand All @@ -103,18 +104,10 @@ private byte[] loadScript(String name) {
}
}

public FlowAddress createAccount(FlowAddress payerAddress, PublicKey publicKey) {

FlowAccountKey payerAccountKey = getAccountKey(payerAddress, 0);

FlowScript script = new FlowScript(loadScript("cadence/create_account.cdc"));

FlowTransaction tx = new FlowTransaction(
private FlowTransaction createTransaction(FlowAddress payerAddress, FlowAccountKey payerAccountKey, FlowScript script, List<FlowArgument> arguments) {
return new FlowTransaction(
script,
List.of(
new FlowArgument(new StringField(publicKey.getHex())),
new FlowArgument(new UInt8NumberField(Integer.toString(publicKey.getAlgo().getIndex())))
),
arguments,
getLatestBlockID(),
100L,
new FlowTransactionProposalKey(
Expand All @@ -127,50 +120,51 @@ public FlowAddress createAccount(FlowAddress payerAddress, PublicKey publicKey)
Collections.emptyList(),
Collections.emptyList()
);
}

private FlowId signAndSendTransaction(FlowTransaction tx, FlowAddress payerAddress, FlowAccountKey payerAccountKey) {
Signer signer = Crypto.getSigner(privateKey, payerAccountKey.getHashAlgo());
tx = tx.addEnvelopeSignature(payerAddress, payerAccountKey.getId(), signer);
return sendTransaction(tx);
}

FlowId txID = sendTransaction(tx);

public FlowAddress createAccount(FlowAddress payerAddress, PublicKey publicKey) {
FlowAccountKey payerAccountKey = getAccountKey(payerAddress, 0);
FlowScript script = new FlowScript(loadScript("cadence/create_account.cdc"));
List<FlowArgument> arguments = List.of(
new FlowArgument(new StringField(publicKey.getHex())),
new FlowArgument(new UInt8NumberField(Integer.toString(publicKey.getAlgo().getIndex())))
);
FlowTransaction tx = createTransaction(payerAddress, payerAccountKey, script, arguments);
FlowId txID = signAndSendTransaction(tx, payerAddress, payerAccountKey);
FlowTransactionResult txResult = waitForSeal(txID);
return getAccountCreatedAddress(txResult);
}

public FlowId sendSampleTransaction(FlowAddress payerAddress, PublicKey publicKey) {
FlowAccountKey payerAccountKey = getAccountKey(payerAddress, 0);
FlowScript script = new FlowScript(loadScript("cadence/create_account.cdc"));
List<FlowArgument> arguments = List.of(
new FlowArgument(new StringField(publicKey.getHex())),
new FlowArgument(new UInt8NumberField(Integer.toString(publicKey.getAlgo().getIndex())))
);
FlowTransaction tx = createTransaction(payerAddress, payerAccountKey, script, arguments);
return signAndSendTransaction(tx, payerAddress, payerAccountKey);
}

public void transferTokens(FlowAddress senderAddress, FlowAddress recipientAddress, BigDecimal amount) {
if (amount.scale() != 8) {
throw new RuntimeException("FLOW amount must have exactly 8 decimal places of precision (e.g. 10.00000000)");
}

FlowAccountKey senderAccountKey = getAccountKey(senderAddress, 0);

FlowScript script = new FlowScript(loadScript("cadence/transfer_flow.cdc"));

List<FlowArgument> arguments = List.of(
new FlowArgument(new UFix64NumberField(amount.toPlainString())),
new FlowArgument(new AddressField(recipientAddress.getBase16Value()))
);

FlowTransaction tx = new FlowTransaction(
script,
arguments,
getLatestBlockID(),
100L,
new FlowTransactionProposalKey(
senderAddress,
senderAccountKey.getId(),
senderAccountKey.getSequenceNumber()
),
senderAddress,
Collections.singletonList(senderAddress),
Collections.emptyList(),
Collections.emptyList()
);

Signer signer = Crypto.getSigner(privateKey, senderAccountKey.getHashAlgo());
tx = tx.addEnvelopeSignature(senderAddress, senderAccountKey.getId(), signer);

FlowId txID = sendTransaction(tx);
FlowTransaction tx = createTransaction(senderAddress, senderAccountKey, script, arguments);
FlowId txID = signAndSendTransaction(tx, senderAddress, senderAccountKey);
waitForSeal(txID);
}

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
package org.onflow.examples.java.getEvent;

import kotlin.ranges.LongRange;
import org.onflow.flow.sdk.*;
import java.util.HashSet;
import java.util.List;
import java.util.Set;

public class GetEventAccessAPIConnector {
private final FlowAccessApi accessAPI;

public GetEventAccessAPIConnector(FlowAccessApi accessAPI) {
this.accessAPI = accessAPI;
}

public List<FlowEventResult> getEventsForHeightRange(String eventType, long startHeight, long endHeight) {
LongRange range = new LongRange(startHeight, endHeight);
FlowAccessApi.AccessApiCallResponse<List<FlowEventResult>> response = accessAPI.getEventsForHeightRange(eventType, range);
if (response instanceof FlowAccessApi.AccessApiCallResponse.Success) {
return ((FlowAccessApi.AccessApiCallResponse.Success<List<FlowEventResult>>) response).getData();
} else if (response instanceof FlowAccessApi.AccessApiCallResponse.Error) {
FlowAccessApi.AccessApiCallResponse.Error errorResponse = (FlowAccessApi.AccessApiCallResponse.Error) response;
throw new RuntimeException(errorResponse.getMessage(), errorResponse.getThrowable());
} else {
throw new RuntimeException("Unknown response type");
}
}

public List<FlowEventResult> getEventsForBlockIds(String eventType, List<FlowId> blockIds) {
Set<FlowId> blockIdSet = new HashSet<>(blockIds);
FlowAccessApi.AccessApiCallResponse<List<FlowEventResult>> response = accessAPI.getEventsForBlockIds(eventType, blockIdSet);
if (response instanceof FlowAccessApi.AccessApiCallResponse.Success) {
return ((FlowAccessApi.AccessApiCallResponse.Success<List<FlowEventResult>>) response).getData();
} else if (response instanceof FlowAccessApi.AccessApiCallResponse.Error errorResponse) {
throw new RuntimeException(errorResponse.getMessage(), errorResponse.getThrowable());
} else {
throw new RuntimeException("Unknown response type");
}
}

public FlowTransactionResult getTransactionResult(FlowId txID) {
FlowAccessApi.AccessApiCallResponse<FlowTransactionResult> response = accessAPI.getTransactionResultById(txID);
if (response instanceof FlowAccessApi.AccessApiCallResponse.Success) {
return ((FlowAccessApi.AccessApiCallResponse.Success<FlowTransactionResult>) response).getData();
} else if (response instanceof FlowAccessApi.AccessApiCallResponse.Error errorResponse) {
throw new RuntimeException(errorResponse.getMessage(), errorResponse.getThrowable());
} else {
throw new RuntimeException("Unknown response type");
}
}

public List<FlowEventResult> getAccountCreatedEvents(long startHeight, long endHeight) {
return getEventsForHeightRange("flow.AccountCreated", startHeight, endHeight);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
package org.onflow.examples.java.getNetworkParams;

import org.onflow.flow.sdk.FlowAccessApi;
import org.onflow.flow.sdk.FlowChainId;

public class GetNetworkParametersAccessAPIConnector {

private final FlowAccessApi accessAPI;

public GetNetworkParametersAccessAPIConnector(FlowAccessApi accessAPI) {
this.accessAPI = accessAPI;
}

public FlowChainId getNetworkParameters() {
FlowAccessApi.AccessApiCallResponse<FlowChainId> response = accessAPI.getNetworkParameters();
if (response instanceof FlowAccessApi.AccessApiCallResponse.Success) {
return ((FlowAccessApi.AccessApiCallResponse.Success<FlowChainId>) response).getData();
} else {
FlowAccessApi.AccessApiCallResponse.Error errorResponse = (FlowAccessApi.AccessApiCallResponse.Error) response;
throw new RuntimeException(errorResponse.getMessage(), errorResponse.getThrowable());
}
}
}

Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
package org.onflow.examples.java.getTransaction;

import org.onflow.flow.sdk.FlowAccessApi;
import org.onflow.flow.sdk.FlowId;
import org.onflow.flow.sdk.FlowTransaction;
import org.onflow.flow.sdk.FlowTransactionResult;

public class GetTransactionAccessAPIConnector {

private final FlowAccessApi accessAPI;

public GetTransactionAccessAPIConnector(FlowAccessApi accessAPI) {
this.accessAPI = accessAPI;
}

public FlowTransaction getTransaction(FlowId txID) {
FlowAccessApi.AccessApiCallResponse<FlowTransaction> response = accessAPI.getTransactionById(txID);
if (response instanceof FlowAccessApi.AccessApiCallResponse.Success) {
return ((FlowAccessApi.AccessApiCallResponse.Success<FlowTransaction>) response).getData();
} else {
FlowAccessApi.AccessApiCallResponse.Error errorResponse = (FlowAccessApi.AccessApiCallResponse.Error) response;
throw new RuntimeException(errorResponse.getMessage(), errorResponse.getThrowable());
}
}

public FlowTransactionResult getTransactionResult(FlowId txID) {
FlowAccessApi.AccessApiCallResponse<FlowTransactionResult> response = accessAPI.getTransactionResultById(txID);
if (response instanceof FlowAccessApi.AccessApiCallResponse.Success) {
return ((FlowAccessApi.AccessApiCallResponse.Success<FlowTransactionResult>) response).getData();
} else {
FlowAccessApi.AccessApiCallResponse.Error errorResponse = (FlowAccessApi.AccessApiCallResponse.Error) response;
throw new RuntimeException(errorResponse.getMessage(), errorResponse.getThrowable());
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,101 @@
package org.onflow.examples.java.getEvent;

import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.onflow.examples.java.AccessAPIConnector;
import org.onflow.flow.common.test.*;
import org.onflow.flow.sdk.*;
import org.onflow.flow.sdk.crypto.Crypto;
import org.onflow.flow.sdk.crypto.PublicKey;

import java.util.List;
import java.util.Set;

import static org.junit.jupiter.api.Assertions.*;

@FlowEmulatorProjectTest(flowJsonLocation = "../flow/flow.json")
public class GetEventAccessAPIConnectorTest {
@FlowServiceAccountCredentials
private TestAccount serviceAccount;

@FlowTestAccount
private TestAccount testAccount;

@FlowTestClient
private FlowAccessApi accessAPI;

private GetEventAccessAPIConnector connector;

private FlowId txID;

@BeforeEach
void setup() {
AccessAPIConnector accessAPIConnector = new AccessAPIConnector(serviceAccount.getPrivateKey(), accessAPI);
connector = new GetEventAccessAPIConnector(accessAPI);

// Send a sample transaction to create an account and capture the transaction ID
PublicKey publicKey = Crypto.generateKeyPair(SignatureAlgorithm.ECDSA_P256).getPublic();
txID = accessAPIConnector.sendSampleTransaction(
serviceAccount.getFlowAddress(),
publicKey
);
}

@Test
void testGetEventsForHeightRange() {
List<FlowEventResult> events = connector.getEventsForHeightRange("flow.AccountCreated", 0, 30);
assertNotNull(events, "Events should not be null");
assertFalse(events.isEmpty(), "Expected account created events but found none.");
assertEquals(3, events.size(), "Expected 3 account created events.");
}

@Test
void testGetEventsForBlockIds() {
FlowBlockHeader latestBlock;

// Get the latest block header from the access API
FlowAccessApi.AccessApiCallResponse<FlowBlockHeader> latestBlockResponse = accessAPI.getLatestBlockHeader(true);

// Handle the response
if (latestBlockResponse instanceof FlowAccessApi.AccessApiCallResponse.Success) {
latestBlock = ((FlowAccessApi.AccessApiCallResponse.Success<FlowBlockHeader>) latestBlockResponse).getData();
} else if (latestBlockResponse instanceof FlowAccessApi.AccessApiCallResponse.Error errorResponse) {
throw new RuntimeException(errorResponse.getMessage(), errorResponse.getThrowable());
} else {
throw new RuntimeException("Unknown response type");
}

List<FlowId> blockIds = List.of(latestBlock.getId());
List<FlowEventResult> events = connector.getEventsForBlockIds("flow.AccountCreated", blockIds);

assertNotNull(events, "Events should not be null");
assertFalse(events.isEmpty(), "Expected events for the provided block IDs but found none.");
assertEquals(1, events.size(), "Expected 1 account created event.");
}

@Test
void testAccountCreatedEvents() {
List<FlowEventResult> events = connector.getAccountCreatedEvents(0, 30);
assertNotNull(events, "Events should not be null");
assertFalse(events.isEmpty(), "Expected account created events but found none.");
for (FlowEventResult block : events) {
for (FlowEvent event : block.getEvents()) {
assertEquals("flow.AccountCreated", event.getType());
}
}
}

@Test
void testTransactionResultEvents() {
FlowTransactionResult txResult = connector.getTransactionResult(txID);
assertNotNull(txResult, "Transaction result should not be null");
assertFalse(txResult.getEvents().isEmpty(), "Expected events in transaction result but found none.");

Set<String> expectedEventTypes = Set.of("Withdrawn", "TokensDeposited", "Deposited", "AccountCreated", "AccountKeyAdded", "TokensWithdrawn", "StorageCapabilityControllerIssued", "CapabilityPublished");

for (FlowEvent event : txResult.getEvents()) {
String eventType = event.getType().split("\\.")[event.getType().split("\\.").length - 1];
assertTrue(expectedEventTypes.contains(eventType), "Unexpected event type: " + eventType);
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
package org.onflow.examples.java.getNetworkParams;

import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.onflow.flow.common.test.FlowEmulatorProjectTest;
import org.onflow.flow.common.test.FlowTestClient;
import org.onflow.flow.sdk.FlowAccessApi;
import org.onflow.flow.sdk.FlowChainId;

import static org.junit.jupiter.api.Assertions.*;

@FlowEmulatorProjectTest(flowJsonLocation = "../flow/flow.json")
public class GetNetworkParametersAccessAPIConnectorTest {

@FlowTestClient
private FlowAccessApi accessAPI;

private GetNetworkParametersAccessAPIConnector networkParametersConnector;

@BeforeEach
public void setup() {
networkParametersConnector = new GetNetworkParametersAccessAPIConnector(accessAPI);
}

@Test
public void canFetchNetworkParameters() {
FlowChainId networkParams = networkParametersConnector.getNetworkParameters();
assertNotNull(networkParams, "Network parameters should not be null");
assertFalse(networkParams.getId().isEmpty(), "Network parameters should have a valid ID");
assertEquals(FlowChainId.EMULATOR, networkParams, "Network parameters should match EMULATOR");
assertEquals("flow-emulator", networkParams.getId(), "Network ID should be 'flow-emulator'");
}
}
Loading
Loading