Skip to content
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
4 changes: 4 additions & 0 deletions e2e-tests/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
.logs/
pycardano/.venv/
__pycache__/
node_modules/
29 changes: 28 additions & 1 deletion e2e-tests/README.md
Original file line number Diff line number Diff line change
@@ -1,10 +1,37 @@
# End-to-End Tests

This folder contains various types of end-to-end tests. Currently, these tests need to be run manually, but automation of the test execution will be implemented in the future.
This folder contains end-to-end tests for Yaci DevKit. The SDK compatibility tests build, sign and submit
transactions through Yaci Store's Blockfrost-compatible API using each SDK.

## Test Categories

1. **api-tests**: This folder contains HTTP API tests, primarily for admin endpoints and essential endpoints from Yaci Store.
2. **lucid-evo**: Compatibility tests for Lucid Evolution.
3. **meshjs**: Compatibility tests for MeshJs
4. **evolution-sdk**: Compatibility tests for Evolution SDK
5. **pycardano**: Compatibility tests for PyCardano
6. **cardano-client-lib**: Compatibility tests for cardano-client-lib (JBang scripts)

## Run all SDK tests

Requires `bun`, `python3`, `jbang`, Java 21 and `timeout` (GNU coreutils), plus a built CLI jar
(`cd applications/cli && ./gradlew clean build -x test`).

```shell
# Against a running DevKit (Yaci Store on 8080, admin API on 10000)
./run-sdk-tests.sh

# Update every SDK to its latest version, recreate the devnet and run
./run-sdk-tests.sh --update --restart

# Test a Yaci Store build (runs Store in java mode from this jar; recreates the devnet)
./run-sdk-tests.sh --store-jar /path/to/yaci-store-<version>.jar

# A subset, or a specific cardano-client-lib version
./run-sdk-tests.sh --only pycardano,cardano-client-lib --ccl-version 0.8.0-pre5
```

`--restart` and `--store-jar` stop the running DevKit and recreate the devnet (`create-node -o`), which wipes
its data. They match processes by command line, so they also stop any other `cardano-node` or
`cardano-submit-api` on the machine (e.g. a preprod or mainnet node); without those flags nothing is stopped.
Per-test logs are written to `.logs/`.
32 changes: 32 additions & 0 deletions e2e-tests/cardano-client-lib/Devnet.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
import com.bloxbean.cardano.client.account.Account;
import com.bloxbean.cardano.client.api.model.Result;
import com.bloxbean.cardano.client.backend.api.BackendService;
import com.bloxbean.cardano.client.backend.blockfrost.service.BFBackendService;
import com.bloxbean.cardano.client.common.model.Networks;

// Shared settings for the cardano-client-lib e2e tests
public class Devnet {
public static final String YACI_STORE_URL = System.getenv().getOrDefault("YACI_STORE_URL", "http://localhost:8080/api/v1");

// Default Yaci DevKit account 0 (pre-funded on devnet creation)
public static final String MNEMONIC = "test test test test test test test test test test test test test test test test test test test test test test test sauce";

public static final String RECEIVER = "addr_test1qqm87edtdxc7vu2u34dpf9jzzny4qhk3wqezv6ejpx3vgrwt46dz4zq7vqll88fkaxrm4nac0m5cq50jytzlu0hax5xqwlraql";

public static BackendService backendService() {
String url = YACI_STORE_URL.endsWith("/") ? YACI_STORE_URL : YACI_STORE_URL + "/";
return new BFBackendService(url, "Dummy Key");
}

public static Account account() {
return Account.createFromMnemonic(Networks.testnet(), MNEMONIC);
}

public static void check(String step, Result<String> result) {
if (!result.isSuccessful()) {
System.out.println("FAIL " + step + ": " + result.getResponse());
System.exit(1);
}
System.out.println("OK " + step + ": " + result.getValue());
}
}
43 changes: 43 additions & 0 deletions e2e-tests/cardano-client-lib/MintToken.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
///usr/bin/env jbang "$0" "$@" ; exit $?
//JAVA 21
//DEPS com.bloxbean.cardano:cardano-client-lib:${ccl.version:0.8.0-preview1}
//DEPS com.bloxbean.cardano:cardano-client-backend-blockfrost:${ccl.version:0.8.0-preview1}
//DEPS org.slf4j:slf4j-nop:2.0.13
//SOURCES Devnet.java

import com.bloxbean.cardano.client.account.Account;
import com.bloxbean.cardano.client.api.util.PolicyUtil;
import com.bloxbean.cardano.client.function.helper.SignerProviders;
import com.bloxbean.cardano.client.quicktx.QuickTxBuilder;
import com.bloxbean.cardano.client.quicktx.Tx;
import com.bloxbean.cardano.client.transaction.spec.Asset;

import java.math.BigInteger;

// Mint a native token with a native-script policy, then query the holder's UTxOs for it
public class MintToken {
public static void main(String[] args) throws Exception {
Account minter = Devnet.account();
var policy = PolicyUtil.createMultiSigScriptAllPolicy("e2e-policy", 1);
var asset = new Asset("E2EToken", BigInteger.valueOf(1000));

Tx tx = new Tx()
.mintAssets(policy.getPolicyScript(), asset, minter.baseAddress())
.from(minter.baseAddress());

var result = new QuickTxBuilder(Devnet.backendService())
.compose(tx)
.withSigner(SignerProviders.signerFrom(minter))
.withSigner(SignerProviders.signerFrom(policy))
.completeAndWait(System.out::println);
Devnet.check("mint", result);

String unit = policy.getPolicyId() + asset.getNameAsHex().substring(2);
var utxos = Devnet.backendService().getUtxoService().getUtxos(minter.baseAddress(), unit, 10, 1);
if (!utxos.isSuccessful() || utxos.getValue().isEmpty()) {
System.out.println("FAIL query minted asset " + unit + ": " + utxos.getResponse());
System.exit(1);
}
System.out.println("OK query minted asset: " + unit);
}
}
31 changes: 31 additions & 0 deletions e2e-tests/cardano-client-lib/Payment.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
///usr/bin/env jbang "$0" "$@" ; exit $?
//JAVA 21
//DEPS com.bloxbean.cardano:cardano-client-lib:${ccl.version:0.8.0-preview1}
//DEPS com.bloxbean.cardano:cardano-client-backend-blockfrost:${ccl.version:0.8.0-preview1}
//DEPS org.slf4j:slf4j-nop:2.0.13
//SOURCES Devnet.java

import com.bloxbean.cardano.client.account.Account;
import com.bloxbean.cardano.client.api.model.Amount;
import com.bloxbean.cardano.client.function.helper.SignerProviders;
import com.bloxbean.cardano.client.quicktx.QuickTxBuilder;
import com.bloxbean.cardano.client.quicktx.Tx;

// Simple ADA payment using Yaci Store as the Blockfrost backend
public class Payment {
public static void main(String[] args) {
Account sender = Devnet.account();
System.out.println("Sender: " + sender.baseAddress());

Tx tx = new Tx()
.payToAddress(Devnet.RECEIVER, Amount.ada(5))
.from(sender.baseAddress());

var result = new QuickTxBuilder(Devnet.backendService())
.compose(tx)
.withSigner(SignerProviders.signerFrom(sender))
.completeAndWait(System.out::println);

Devnet.check("payment", result);
}
}
67 changes: 67 additions & 0 deletions e2e-tests/cardano-client-lib/PlutusV3.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
///usr/bin/env jbang "$0" "$@" ; exit $?
//JAVA 21
//DEPS com.bloxbean.cardano:cardano-client-lib:${ccl.version:0.8.0-preview1}
//DEPS com.bloxbean.cardano:cardano-client-backend-blockfrost:${ccl.version:0.8.0-preview1}
//DEPS org.slf4j:slf4j-nop:2.0.13
//SOURCES Devnet.java

import com.bloxbean.cardano.client.account.Account;
import com.bloxbean.cardano.client.address.AddressProvider;
import com.bloxbean.cardano.client.api.model.Amount;
import com.bloxbean.cardano.client.api.model.Utxo;
import com.bloxbean.cardano.client.common.model.Networks;
import com.bloxbean.cardano.client.function.helper.SignerProviders;
import com.bloxbean.cardano.client.plutus.blueprint.PlutusBlueprintUtil;
import com.bloxbean.cardano.client.plutus.blueprint.model.PlutusVersion;
import com.bloxbean.cardano.client.plutus.spec.BytesPlutusData;
import com.bloxbean.cardano.client.plutus.spec.ConstrPlutusData;
import com.bloxbean.cardano.client.plutus.spec.PlutusScript;
import com.bloxbean.cardano.client.quicktx.QuickTxBuilder;
import com.bloxbean.cardano.client.quicktx.ScriptTx;
import com.bloxbean.cardano.client.quicktx.Tx;

// Lock ADA at an always-succeeds PlutusV3 script and spend it back. Script evaluation goes
// through Yaci Store's Blockfrost-compatible /utils/txs/evaluate endpoint.
public class PlutusV3 {
// Same always-succeeds validator as lucid-evo/plutus_v3.ts (CBOR-wrapped compiled code)
static final String COMPILED_CODE = "5857010000323232323225333002323232323253330073370e900118041baa00113232324a26018601a004601600260126ea800458c024c028008c020004c020008c018004c010dd50008a4c26cacae6955ceaab9e5742ae89";

public static void main(String[] args) throws Exception {
Account owner = Devnet.account();
var backend = Devnet.backendService();
PlutusScript script = PlutusBlueprintUtil.getPlutusScriptFromCompiledCode(COMPILED_CODE, PlutusVersion.v3);
String scriptAddress = AddressProvider.getEntAddress(script, Networks.testnet()).toBech32();
System.out.println("Script address: " + scriptAddress);

var datum = ConstrPlutusData.of(0, BytesPlutusData.of(owner.getBaseAddress().getPaymentCredentialHash().get()));

// Lock
Tx lockTx = new Tx()
.payToContract(scriptAddress, Amount.ada(10), datum)
.from(owner.baseAddress());
var lockResult = new QuickTxBuilder(backend)
.compose(lockTx)
.withSigner(SignerProviders.signerFrom(owner))
.completeAndWait(System.out::println);
Devnet.check("lock", lockResult);

// Spend the UTxO created by the lock tx
Utxo scriptUtxo = backend.getUtxoService().getUtxos(scriptAddress, 100, 1).getValue().stream()
.filter(u -> u.getTxHash().equals(lockResult.getValue()))
.findFirst()
.orElseThrow(() -> new IllegalStateException("Locked UTxO not found at " + scriptAddress));

var redeemer = ConstrPlutusData.of(0, BytesPlutusData.of("Hello, World!"));
ScriptTx spendTx = new ScriptTx()
.collectFrom(scriptUtxo, redeemer)
.payToAddress(owner.baseAddress(), Amount.ada(5))
.attachSpendingValidator(script);
var spendResult = new QuickTxBuilder(backend)
.compose(spendTx)
.feePayer(owner.baseAddress())
.collateralPayer(owner.baseAddress())
.withSigner(SignerProviders.signerFrom(owner))
.completeAndWait(System.out::println);
Devnet.check("spend", spendResult);
}
}
11 changes: 11 additions & 0 deletions e2e-tests/cardano-client-lib/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
# cardano-client-lib Compatibility Tests

[JBang](https://www.jbang.dev) scripts using `BFBackendService` pointed at Yaci Store. The cardano-client-lib
version defaults to the one in the `//DEPS` lines and can be overridden with `-Dccl.version`.

```shell
jbang Payment.java # simple ADA payment
jbang MintToken.java # mint a native token and query it by asset
jbang PlutusV3.java # lock at an always-succeeds PlutusV3 script and spend it back
jbang -Dccl.version=0.8.0-preview1 Payment.java # another cardano-client-lib version
```
1 change: 1 addition & 0 deletions e2e-tests/evolution-sdk/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
node_modules/
52 changes: 52 additions & 0 deletions e2e-tests/evolution-sdk/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
# Evolution SDK Compatibility Tests

Tests [Evolution SDK](https://github.com/IntersectMBO/evolution-sdk) (`@evolution-sdk/evolution@0.5.14`)
against a running Yaci DevKit, using Yaci Store as the Blockfrost provider.

## Prerequisites

- Yaci DevKit running with Yaci Store enabled (Store on port 8080, CLI admin API on port 10000)
- [Bun](https://bun.sh): `curl -fsSL https://bun.sh/install | bash`

Override the endpoints if needed:

```shell
export YACI_STORE_URL=http://localhost:8080/api/v1
export YACI_ADMIN_URL=http://localhost:10000/local-cluster/api
```

## Run Tests

```shell
bun install
```

1. Protocol parameters (reproduces [yaci-store#1187](https://github.com/bloxbean/yaci-store/issues/1187))

```shell
bun protocol_params.ts
```

Checks that `drep_deposit` and `gov_action_deposit` in `/epochs/latest/parameters` are strings, as in the
Blockfrost OpenAPI spec, and that Evolution's Blockfrost provider can parse the response. With Yaci Store 2.0.x
it fails with `ParseError ... ["drep_deposit"] Expected string, actual 500000000`.

2. Payment

```shell
bun payment.ts
```

Sends 5 ADA from DevKit's default account and waits for confirmation. It also fails while #1187 is present,
because transaction building fetches protocol parameters first.

3. PlutusV3 payment splitter

```shell
bun plutus_v3.ts
```

Same parameterized validator and flow as `meshjs/payment_splitter_plutusV3.ts`: applies the payees' key hashes
to the script, locks 20 ADA with the owner's key hash as inline datum, then unlocks it (redeemer, owner as
required signer) and splits it equally between the five payees. Script evaluation goes through Yaci Store's
`/utils/txs/evaluate`.
32 changes: 32 additions & 0 deletions e2e-tests/evolution-sdk/bun.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

30 changes: 30 additions & 0 deletions e2e-tests/evolution-sdk/devnet.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
import type { Chain } from "@evolution-sdk/evolution";

export const YACI_STORE_URL = process.env.YACI_STORE_URL ?? "http://localhost:8080/api/v1";
export const YACI_ADMIN_URL = process.env.YACI_ADMIN_URL ?? "http://localhost:10000/local-cluster/api";

// Default Yaci DevKit account 0 (pre-funded on devnet creation)
export const SEED_PHRASE =
"test test test test test test test test test test test test test test test test test test test test test test test sauce";

export const RECEIVER =
"addr_test1qqm87edtdxc7vu2u34dpf9jzzny4qhk3wqezv6ejpx3vgrwt46dz4zq7vqll88fkaxrm4nac0m5cq50jytzlu0hax5xqwlraql";

// Build an Evolution Chain from the running devnet's genesis info
export async function devnetChain(): Promise<Chain> {
const res = await fetch(`${YACI_ADMIN_URL}/admin/devnet`);
if (!res.ok) throw new Error(`Failed to fetch devnet info: HTTP ${res.status}`);
const info = await res.json();

return {
id: 0,
name: "Yaci DevKit",
networkMagic: info.protocolMagic,
epochLength: Math.round(info.epochLength * info.slotLength),
slotConfig: {
zeroTime: BigInt(info.startTime) * 1000n,
zeroSlot: 0n,
slotLength: Math.round(info.slotLength * 1000),
},
};
}
15 changes: 15 additions & 0 deletions e2e-tests/evolution-sdk/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
{
"name": "evolution-sdk-e2e",
"version": "1.0.0",
"private": true,
"type": "module",
"description": "Evolution SDK compatibility tests against Yaci DevKit",
"scripts": {
"test:params": "bun protocol_params.ts",
"test:payment": "bun payment.ts"
},
"license": "ISC",
"dependencies": {
"@evolution-sdk/evolution": "0.5.15"
}
}
23 changes: 23 additions & 0 deletions e2e-tests/evolution-sdk/payment.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
// Simple ADA payment with Evolution SDK using Yaci Store as the Blockfrost provider.
// Transaction building needs protocol parameters, so this also fails while
// https://github.com/bloxbean/yaci-store/issues/1187 is present.
import { Address, Assets, Client, TransactionHash } from "@evolution-sdk/evolution";
import { RECEIVER, SEED_PHRASE, YACI_STORE_URL, devnetChain } from "./devnet";

const client = Client.make(await devnetChain())
.withBlockfrost({ baseUrl: YACI_STORE_URL, projectId: "Dummy Key" })
.withSeed({ mnemonic: SEED_PHRASE, accountIndex: 0 });

console.log("Sender:", Address.toBech32(await client.address()));

const signBuilder = await client
.newTx()
.payToAddress({ address: Address.fromBech32(RECEIVER), assets: Assets.fromLovelace(5_000_000n) })
.build();

const txHash = TransactionHash.toHex(await signBuilder.signAndSubmit());
console.log("Submitted:", txHash);

const confirmed = await client.awaitTx(TransactionHash.fromHex(txHash), 1000, 60_000);
console.log("Confirmed:", confirmed);
process.exit(confirmed ? 0 : 1);
Loading
Loading