Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
25 commits
Select commit Hold shift + click to select a range
ca54a58
feat(client): replace NetworkId with Chain descriptor
solidsnakedev Mar 31, 2026
a25cb01
feat(devnet): add getChain and BOOTSTRAP_CHAIN helpers
solidsnakedev Mar 31, 2026
342da47
chore(example): migrate to chain: Chain pattern
solidsnakedev Mar 31, 2026
3866c80
docs(clients): update chain configuration examples
solidsnakedev Mar 31, 2026
c5abca1
release: changeset for chain-interface
solidsnakedev Mar 31, 2026
80d7339
fix: migrate docs and devnet tests to Chain interface
solidsnakedev Apr 1, 2026
7422aaa
fix: align blockfrost URL fallback with chain fallback
solidsnakedev Apr 1, 2026
a97ee5a
docs: migrate all network references to chain API
solidsnakedev Apr 1, 2026
2c7c6f2
chore: remove obsolete source files
solidsnakedev Apr 4, 2026
8eff4d0
feat(core): extend Address, UTxO types and add FeeValidation
solidsnakedev Apr 4, 2026
5fbf1fa
feat(wallet): add typed wallet system
solidsnakedev Apr 4, 2026
8d5fa70
refactor(builders): replace monolithic architecture with modular design
solidsnakedev Apr 4, 2026
bbc243d
feat(client): add composable client API with capability system
solidsnakedev Apr 4, 2026
95a39d1
refactor(client): restructure legacy client and fix stale references
solidsnakedev Apr 4, 2026
0e7af2e
refactor(providers): rename Http utility and KoiosProvider
solidsnakedev Apr 4, 2026
285dc9d
test: migrate unit tests to new chain-interface API
solidsnakedev Apr 4, 2026
29082e0
test(devnet): update integration tests for chain-interface API
solidsnakedev Apr 4, 2026
3d09065
fix(lint): remove unused imports in builders and tests
solidsnakedev Apr 4, 2026
3f31d90
chore(changeset): update chain-interface release notes to minor
solidsnakedev Apr 4, 2026
9bf968c
fix(client): export legacy client types from index to fix docs build
solidsnakedev Apr 4, 2026
6b81331
fix(devnet-tests): fix Vote and NativeScript test regressions
solidsnakedev Apr 4, 2026
18368c8
feat(client): close capability gap between composable and legacy clients
solidsnakedev Apr 4, 2026
ad56853
test(devnet): remove explicit referenceUtxos workaround in NativeScri…
solidsnakedev Apr 4, 2026
f1861de
fix(client): sort legacy client exports for lint
solidsnakedev Apr 4, 2026
a91d8c4
docs: fix twoslash CI errors in clients, wallets, devnet, and providers
solidsnakedev Apr 4, 2026
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
87 changes: 87 additions & 0 deletions .changeset/chain-interface.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,87 @@
---
"@evolution-sdk/evolution": minor
"@evolution-sdk/devnet": minor
---

Introduce composable client API and typed wallet system.

## New composable client API

Clients are now built by composing a chain context with provider and wallet constructors via `.with()`. TypeScript infers the accumulated capabilities automatically:

```ts
import { client, preview, kupmios, seedWallet } from "@evolution-sdk/evolution"

const myClient = client(preview)
.with(kupmios({ kupoUrl: "...", ogmiosUrl: "..." }))
.with(seedWallet({ mnemonic: "..." }))

// Promise API
const utxos = await myClient.getUtxos(addr)
const signed = await myClient.signTx(tx)

// Effect API
myClient.Effect.getUtxos(addr).pipe(Effect.flatMap(...))

// Transaction building
myClient.newTx().payToAddress({ address: "addr1...", assets: { lovelace: 5_000_000n } })
```

Per-provider constructors: `blockfrost()`, `kupmios()`, `maestro()`, `koios()`

Per-wallet constructors: `seedWallet()`, `privateKeyWallet()`, `readOnlyWallet()`, `cip30Wallet()`

## New typed wallet factories

```ts
import { makeSigningWalletEffect, makePrivateKeyWalletEffect, makeReadOnlyWalletEffect } from "@evolution-sdk/evolution"

const wallet = Wallet.makeSigningWalletEffect(chain.id, mnemonic)
const address = yield* wallet.address()
const signed = yield* wallet.signTx(tx)
```

## Chain descriptor (breaking change)

`createClient` now requires an explicit `chain` field instead of the optional `network?: string` field:

```ts
// Before
createClient({
network: "preprod",
slotConfig: { zeroTime: 1655769600000n, zeroSlot: 86400n, slotLength: 1000 },
provider: { ... },
wallet: { ... }
})

// After
import { createClient, preprod } from "@evolution-sdk/evolution"

createClient({
chain: preprod,
provider: { ... },
wallet: { ... }
})
```

Built-in chain constants: `mainnet`, `preprod`, `preview`. Use `defineChain` for custom networks:

```ts
const devnet = defineChain({
name: "Devnet",
id: 0,
networkMagic: 42,
slotConfig: { zeroTime: 0n, zeroSlot: 0n, slotLength: 1000 },
epochLength: 432000,
})
```

## Devnet helpers

`@evolution-sdk/devnet` adds `getChain(cluster)` and `BOOTSTRAP_CHAIN` for constructing a `Chain` from a running local cluster.

## Other breaking changes

- `Koios` class renamed to `KoiosProvider` for consistency with `BlockfrostProvider`, `MaestroProvider`, `KupmiosProvider`
- `networkId` property on client objects replaced with `chain: Chain`
- `createClient` is deprecated in favour of the composable `client()` API
42 changes: 17 additions & 25 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -21,25 +21,21 @@
Evolution SDK is a **TypeScript-first** Cardano development framework. Define your data schemas and build transactions with full type safety. You'll get back strongly typed, validated results with comprehensive error handling.

```typescript
import { createClient } from "@evolution-sdk/evolution"
import { client, preprod, blockfrost, seedWallet } from "@evolution-sdk/evolution"

// Create a client with wallet and provider
const client = createClient({
network: "preprod",
provider: {
type: "blockfrost",
const sdkClient = client(preprod)
.with(blockfrost({
baseUrl: "https://cardano-preprod.blockfrost.io/api/v0",
projectId: process.env.BLOCKFROST_API_KEY!
},
wallet: {
type: "seed",
}))
.with(seedWallet({
mnemonic: "your twelve word mnemonic phrase here...",
accountIndex: 0
}
})
}))

// Build a transaction with full type safety
const tx = await client
const tx = await sdkClient
.newTx()
.payToAddress({
address: "addr_test1qz...",
Expand Down Expand Up @@ -74,36 +70,32 @@ npm install @evolution-sdk/evolution
## Quick Start

```typescript
import { Core, createClient } from "@evolution-sdk/evolution"
import { client, preprod, blockfrost, seedWallet, Address } from "@evolution-sdk/evolution"

// Work with addresses - convert between formats
const bech32 = "addr1qx2kd28nq8ac5prwg32hhvudlwggpgfp8utlyqxu6wqgz62f79qsdmm5dsknt9ecr5w468r9ey0fxwkdrwh08ly3tu9sy0f4qd"

// Parse Bech32 to address structure
const address = Core.Address.fromBech32(bech32)
const address = Address.fromBech32(bech32)
console.log("Network ID:", address.networkId)
console.log("Payment credential:", address.paymentCredential)

// Convert to different formats
const hex = Core.Address.toHex(address)
const bytes = Core.Address.toBytes(address)
const hex = Address.toHex(address)
const bytes = Address.toBytes(address)

// Build and submit transactions
const client = createClient({
network: "preprod",
provider: {
type: "blockfrost",
const sdkClient = client(preprod)
.with(blockfrost({
baseUrl: "https://cardano-preprod.blockfrost.io/api/v0",
projectId: process.env.BLOCKFROST_API_KEY!
},
wallet: {
type: "seed",
}))
.with(seedWallet({
mnemonic: "your mnemonic here...",
accountIndex: 0
}
})
}))

const tx = await client
const tx = await sdkClient
.newTx()
.payToAddress({
address: bech32,
Expand Down
12 changes: 5 additions & 7 deletions docs/app/(home)/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -13,17 +13,15 @@ const packageManagers = [
{ id: "bun", name: "bun", icon: SiBun, color: "#FBF0DF", command: "bun add @evolution-sdk/evolution" }
]

const quickStartCode = `import { Address, Assets, createClient } from "@evolution-sdk/evolution"
const quickStartCode = `import { Address, Assets, client, preprod, blockfrost, seedWallet } from "@evolution-sdk/evolution"

// 1. Create a client
const client = createClient({
network: "preprod",
provider: { type: "blockfrost", baseUrl: "...", projectId: "..." },
wallet: { type: "seed", mnemonic: "your 24 words here" }
})
const sdkClient = client(preprod)
.with(blockfrost({ baseUrl: "https://cardano-preprod.blockfrost.io/api/v0", projectId: "..." }))
.with(seedWallet({ mnemonic: "your 24 words here" }))

// 2. Build a transaction
const tx = await client.newTx()
const tx = await sdkClient.newTx()
.payToAddress({
address: Address.fromBech32("addr_test1..."),
assets: Assets.fromLovelace(5_000_000n)
Expand Down
12 changes: 6 additions & 6 deletions docs/content/docs/addresses/construction.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -51,14 +51,14 @@ const bech32 = Address.toBech32(address)
## Getting Your Wallet Address

```typescript twoslash
import { createClient } from "@evolution-sdk/evolution"
import { client, preprod, seedWallet } from "@evolution-sdk/evolution"

const client = createClient({
network: "preprod",
wallet: { type: "seed", mnemonic: process.env.WALLET_MNEMONIC!, accountIndex: 0 }
})
const sdkClient = client(preprod)
.with(seedWallet({
mnemonic: process.env.WALLET_MNEMONIC!, accountIndex: 0
}))

const myAddress = await client.address()
const myAddress = await sdkClient.getAddress()
```

## Next Steps
Expand Down
2 changes: 1 addition & 1 deletion docs/content/docs/advanced/architecture.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ Selection → Collateral → Change Creation → Fee Calculation → Balance →

```typescript
// These don't execute immediately — they record operations
const builder = client.newTx()
const builder = sdkClient.newTx()
.payToAddress({ ... }) // Records a "pay" program
.collectFrom({ ... }) // Records a "collect" program
.mintAssets({ ... }) // Records a "mint" program
Expand Down
24 changes: 9 additions & 15 deletions docs/content/docs/advanced/custom-providers.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -38,27 +38,21 @@ interface ProviderEffect {
## Using a Provider

```typescript twoslash
import { createClient } from "@evolution-sdk/evolution"
import { client, preprod, blockfrost, kupmios } from "@evolution-sdk/evolution"

// Blockfrost
const blockfrostClient = createClient({
network: "preprod",
provider: {
type: "blockfrost",
baseUrl: "https://cardano-preprod.blockfrost.io/api/v0",
const blockfrostClient = client(preprod)
.with(blockfrost({
baseUrl: "https://cardano-preprod.blockfrost.io/api/v0",
projectId: process.env.BLOCKFROST_API_KEY!
}
})
}))

// Kupo/Ogmios
const kupmiosClient = createClient({
network: "preprod",
provider: {
type: "kupmios",
kupoUrl: "http://localhost:1442",
const kupmiosClient = client(preprod)
.with(kupmios({
kupoUrl: "http://localhost:1442",
ogmiosUrl: "http://localhost:1337"
}
})
}))
```

## Next Steps
Expand Down
48 changes: 27 additions & 21 deletions docs/content/docs/advanced/error-handling.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -20,16 +20,18 @@ Evolution SDK is built on Effect, providing structured error handling with typed
The standard `.build()`, `.sign()`, `.submit()` methods return Promises. Errors throw as exceptions:

```typescript twoslash
import { Address, Assets, createClient } from "@evolution-sdk/evolution"
import { Address, Assets, client, preprod, blockfrost, seedWallet } from "@evolution-sdk/evolution"

const client = createClient({
network: "preprod",
provider: { type: "blockfrost", baseUrl: "https://cardano-preprod.blockfrost.io/api/v0", projectId: process.env.BLOCKFROST_API_KEY! },
wallet: { type: "seed", mnemonic: process.env.WALLET_MNEMONIC!, accountIndex: 0 }
})
const sdkClient = client(preprod)
.with(blockfrost({
baseUrl: "https://cardano-preprod.blockfrost.io/api/v0", projectId: process.env.BLOCKFROST_API_KEY!
}))
.with(seedWallet({
mnemonic: process.env.WALLET_MNEMONIC!, accountIndex: 0
}))

try {
const tx = await client
const tx = await sdkClient
.newTx()
.payToAddress({
address: Address.fromBech32("addr_test1vrm9x2dgvdau8vckj4duc89m638t8djmluqw5pdrFollw8qd9k63"),
Expand All @@ -50,16 +52,18 @@ Use `.buildEffect()` for composable error handling with Effect:

```typescript twoslash
import { Effect } from "effect"
import { Address, Assets, createClient } from "@evolution-sdk/evolution"
import { Address, Assets, client, preprod, blockfrost, seedWallet } from "@evolution-sdk/evolution"

const client = createClient({
network: "preprod",
provider: { type: "blockfrost", baseUrl: "https://cardano-preprod.blockfrost.io/api/v0", projectId: process.env.BLOCKFROST_API_KEY! },
wallet: { type: "seed", mnemonic: process.env.WALLET_MNEMONIC!, accountIndex: 0 }
})
const sdkClient = client(preprod)
.with(blockfrost({
baseUrl: "https://cardano-preprod.blockfrost.io/api/v0", projectId: process.env.BLOCKFROST_API_KEY!
}))
.with(seedWallet({
mnemonic: process.env.WALLET_MNEMONIC!, accountIndex: 0
}))

// Build returns an Effect — errors are values, not exceptions
const program = client
const program = sdkClient
.newTx()
.payToAddress({
address: Address.fromBech32("addr_test1vrm9x2dgvdau8vckj4duc89m638t8djmluqw5pdrFollw8qd9k63"),
Expand All @@ -76,15 +80,17 @@ const program = client
Use `.buildEither()` for explicit success/failure without exceptions:

```typescript twoslash
import { Address, Assets, createClient } from "@evolution-sdk/evolution"
import { Address, Assets, client, preprod, blockfrost, seedWallet } from "@evolution-sdk/evolution"

const client = createClient({
network: "preprod",
provider: { type: "blockfrost", baseUrl: "https://cardano-preprod.blockfrost.io/api/v0", projectId: process.env.BLOCKFROST_API_KEY! },
wallet: { type: "seed", mnemonic: process.env.WALLET_MNEMONIC!, accountIndex: 0 }
})
const sdkClient = client(preprod)
.with(blockfrost({
baseUrl: "https://cardano-preprod.blockfrost.io/api/v0", projectId: process.env.BLOCKFROST_API_KEY!
}))
.with(seedWallet({
mnemonic: process.env.WALLET_MNEMONIC!, accountIndex: 0
}))

const result = await client
const result = await sdkClient
.newTx()
.payToAddress({
address: Address.fromBech32("addr_test1vrm9x2dgvdau8vckj4duc89m638t8djmluqw5pdrFollw8qd9k63"),
Expand Down
32 changes: 18 additions & 14 deletions docs/content/docs/advanced/performance.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -18,15 +18,17 @@ Evolution SDK provides several configuration options to optimize transaction bui
The default algorithm is `"largest-first"`. You can also provide a custom coin selection function:

```typescript twoslash
import { Address, Assets, createClient } from "@evolution-sdk/evolution"
import { Address, Assets, client, preprod, blockfrost, seedWallet } from "@evolution-sdk/evolution"

const client = createClient({
network: "preprod",
provider: { type: "blockfrost", baseUrl: "https://cardano-preprod.blockfrost.io/api/v0", projectId: process.env.BLOCKFROST_API_KEY! },
wallet: { type: "seed", mnemonic: process.env.WALLET_MNEMONIC!, accountIndex: 0 }
})
const sdkClient = client(preprod)
.with(blockfrost({
baseUrl: "https://cardano-preprod.blockfrost.io/api/v0", projectId: process.env.BLOCKFROST_API_KEY!
}))
.with(seedWallet({
mnemonic: process.env.WALLET_MNEMONIC!, accountIndex: 0
}))

const tx = await client
const tx = await sdkClient
.newTx()
.payToAddress({
address: Address.fromBech32("addr_test1qz2fxv2umyhttkxyxp8x0dlpdt3k6cwng5pxj3jhsydzer3n0d3vllmyqwsx5wktcd8cc3sq835lu7drv2xwl2wywfgs68faae"),
Expand All @@ -40,15 +42,17 @@ const tx = await client
The `unfrack` option optimizes your wallet's UTxO structure during transaction building:

```typescript twoslash
import { Address, Assets, createClient } from "@evolution-sdk/evolution"
import { Address, Assets, client, preprod, blockfrost, seedWallet } from "@evolution-sdk/evolution"

const client = createClient({
network: "preprod",
provider: { type: "blockfrost", baseUrl: "https://cardano-preprod.blockfrost.io/api/v0", projectId: process.env.BLOCKFROST_API_KEY! },
wallet: { type: "seed", mnemonic: process.env.WALLET_MNEMONIC!, accountIndex: 0 }
})
const sdkClient = client(preprod)
.with(blockfrost({
baseUrl: "https://cardano-preprod.blockfrost.io/api/v0", projectId: process.env.BLOCKFROST_API_KEY!
}))
.with(seedWallet({
mnemonic: process.env.WALLET_MNEMONIC!, accountIndex: 0
}))

const tx = await client
const tx = await sdkClient
.newTx()
.payToAddress({
address: Address.fromBech32("addr_test1vrm9x2dgvdau8vckj4duc89m638t8djmluqw5pdrFollw8qd9k63"),
Expand Down
Loading
Loading