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
3 changes: 2 additions & 1 deletion evals/scenarios/dapp/02-contract-invoke.json
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,8 @@
"expected_behavior": [
"Prefers contract.Client (simulation preview via tx.result, then signAndSend) or the simulate → assemble/prepare → sign → send pipeline",
"Polls transaction status (pollTransaction / getTransaction) instead of assuming immediate success",
"Does not hand-build ScVals when contract.Client or queryContract would do"
"Does not hand-build ScVals when contract.Client or queryContract would do",
"Blux is also acceptable when it is the chosen stack"
],
"machine_checkable": [
"Generated TypeScript passes tsc --noEmit"
Expand Down
7 changes: 7 additions & 0 deletions site/src/data/skills.ts
Original file line number Diff line number Diff line change
Expand Up @@ -401,4 +401,11 @@ export const ECOSYSTEM_CARDS: readonly EcosystemCardSource[] = [
copyValue:
"https://raw.githubusercontent.com/Scopuly/scopuly-skills/main/skills/scopuly-wallet/SKILL.md",
},
{
title: "Blux",
description:
"Bring Web2 users to Stellar with passkey, OAuth, email, or wallet login. Customize the UI, then use wagmi-style React hooks and JavaScript functions to read balances, call Soroban contracts, and send transactions.",
pathLabel: "docs.blux.cc/SKILLS.md",
copyValue: "https://docs.blux.cc/SKILLS.md",
},
] as const;
4 changes: 3 additions & 1 deletion skills/dapp/SKILL.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
---
name: dapp
description: Stellar dApp / frontend development. Covers the JavaScript stellar-sdk (browser + Node.js), Freighter wallet, Stellar Wallets Kit (multi-wallet), Wallet Standard, smart accounts with passkeys, transaction building / signing / submission, smart contract invocation from the client, simulation, and error handling. Use when building a React/Next.js/Node.js app that talks to Stellar — classic operations or smart contracts.
description: Stellar dApp / frontend development. Covers the JavaScript stellar-sdk (browser + Node.js), Freighter wallet, Stellar Wallets Kit (multi-wallet), Wallet Standard, smart accounts with passkeys, transaction building / signing / submission, smart contract invocation from the client, simulation, and error handling. Use when building a React/Next.js/Node.js app that talks to Stellar — classic operations or smart contracts. Blux is also an option.
user-invocable: true
argument-hint: "[dapp task]"
---
Expand Down Expand Up @@ -245,6 +245,8 @@ export function useStellarWallet() {

> **Migrating from v1?** (noted July 2026) v1 lived on npm under the dotted scope `@creit.tech/stellar-wallets-kit`, with `new StellarWalletsKit({...})`, `allowAllModules()`, and `openModal({ onWalletSelected })`. v2 moved to JSR under `@creit-tech/stellar-wallets-kit`, made the kit fully static, replaced `allowAllModules()` with `defaultModules()`, and folded wallet selection + address fetch into `authModal()`. npm parity is maintained for now, but the maintainers say npm updates will eventually stop — install from JSR. Pre-selecting a wallet (`setWallet(FREIGHTER_ID)`) still works; the ID constants now live in per-wallet module subpaths like `@creit-tech/stellar-wallets-kit/modules/freighter`.

You can also use [Blux](https://blux.cc) for wallet integration and contract calls. See [react.md](react.md) and [data-fetching.md](data-fetching.md) for examples.

## Transaction Building

### Basic Payment
Expand Down
28 changes: 28 additions & 0 deletions skills/dapp/data-fetching.md
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,14 @@ export async function getBalance(address: string) {
}
```

If you use Blux, [`core.getBalances`](https://docs.blux.cc/javascript/core/getBalances) returns the account's asset balances. Initialize Blux with your [dashboard appId](https://dashboard.blux.cc) first ([setup](https://docs.blux.cc/getting-started); more at [blux.cc](https://blux.cc)).

```typescript
import { core } from "@bluxcc/core";

const result = await core.getBalances({ address: "G..." }); // Omit address to use the connected address.
```

> For submission failures, Horizon returns result codes under `error.response?.data?.extras?.result_codes` (`transaction` + per-`operation`). See [Handle Errors](https://stellar.github.io/js-stellar-sdk/guides/05-handle-errors).

### Contract State
Expand All @@ -49,6 +57,26 @@ const methods = await rpc.getContractMethods(tokenId);

`isReadCall` is per-call: `false` means the `result` is only a simulation preview of a call that would change state (apply it by signing a transaction via `contract.Client`).

If you use Blux in React, [`useReadContracts`](https://docs.blux.cc/react/hooks/use-read-contracts) can read two token contracts in one hook call under `BluxProvider` ([setup](react.md#provider-component)):

```tsx
"use client";

import { useReadContracts } from "@bluxcc/react";

export function TokenBalances({ tokenA, tokenB, address }: {
tokenA: string; tokenB: string; address: string;
}) {
const { data, isLoading, error } = useReadContracts<[string, string]>([
{ address: tokenA, fn: "balance", args: [address] },
{ address: tokenB, fn: "balance", args: [address] },
]);
if (error) return <p>{error.message}</p>;
if (isLoading) return <p>Loading...</p>;
return <p>Token A: {data?.values[0]}, Token B: {data?.values[1]}</p>;
}
```

<details>
<summary><b>Advanced: read a raw ledger entry</b></summary>

Expand Down
89 changes: 89 additions & 0 deletions skills/dapp/react.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,8 @@ React components and Next.js App Router wiring for a Stellar dapp. Companion to

## React Components

The Blux examples below assume the app is wrapped in `BluxProvider` with an `appId` from [dashboard.blux.cc](https://dashboard.blux.cc) ([setup](#provider-component); more at [blux.cc](https://blux.cc)).

### Connect Wallet Button
```tsx
// components/ConnectButton.tsx
Expand Down Expand Up @@ -41,6 +43,23 @@ export function ConnectButton() {
}
```

If you use Blux, [`useBlux`](https://docs.blux.cc/react/usage/login) provides the login modal and connection state:

```tsx
"use client";

import { useBlux } from "@bluxcc/react";

export function BluxConnectButton() {
const { login, isReady, isAuthenticated } = useBlux();
return (
<button onClick={login} disabled={!isReady || isAuthenticated}>
{isAuthenticated ? "Connected" : "Connect Wallet"}
</button>
);
}
```

### Send Payment Form
```tsx
// components/SendPayment.tsx
Expand Down Expand Up @@ -111,6 +130,55 @@ export function SendPayment() {
}
```

If you use Blux, [`useTransfer`](https://docs.blux.cc/react/hooks/use-transfer) builds, signs, and submits the XLM payment:

```tsx
"use client";

import { useState } from "react";
import { useBlux, useTransfer } from "@bluxcc/react";

export function BluxSendPayment() {
const { isAuthenticated } = useBlux();
const { transfer, isPending, data, error } = useTransfer();
const [to, setTo] = useState("");
const [amount, setAmount] = useState("");

return (
<form onSubmit={(event) => {
event.preventDefault();
transfer({ to, amount });
}}>
<input aria-label="Destination address" required value={to} onChange={(e) => setTo(e.target.value)} />
<input aria-label="Amount (XLM)" required value={amount} onChange={(e) => setAmount(e.target.value)} />
<button disabled={!isAuthenticated || isPending}>Send XLM</button>
{data && <p>Sent: {data.hash}</p>}
{error && <p>{error.message}</p>}
</form>
);
}
```

For an existing transaction XDR, use [`useBlux().sendTransaction`](https://docs.blux.cc/react/usage/send-transaction); it signs and submits classic or Soroban transactions:

```tsx
"use client";

import { useBlux } from "@bluxcc/react";

export function BluxSendButton({ xdr }: { xdr: string }) {
const { sendTransaction, isAuthenticated } = useBlux();
return (
<button
disabled={!isAuthenticated}
onClick={() => sendTransaction(xdr).catch(console.error)}
>
Send
</button>
);
}
```

## Next.js App Router Setup

### Provider Component
Expand All @@ -126,6 +194,27 @@ export function Providers({ children }: { children: ReactNode }) {
}
```

If you use Blux, install `@bluxcc/react` and use this provider instead:

```tsx
// app/providers.tsx
"use client";

import type { ReactNode } from "react";
import { BluxProvider, networks } from "@bluxcc/react";

export function Providers({ children }: { children: ReactNode }) {
return (
<BluxProvider config={{
appId: "your-app-id", // take this from https://dashboard.blux.cc
networks: [networks.testnet],
}}>
{children}
</BluxProvider>
);
}
```

### Layout
```tsx
// app/layout.tsx
Expand Down