Adapters
The @mure/sdk uses an adapter pattern to stay wallet-agnostic. An adapter implements the AdapterServiceApi contract, which tells the SDK how to send transactions, read the current account, and read the current chain.
The only adapter shipped today is built on viem, but you can write your own by satisfying the same interface.
AdapterService
AdapterService is an Effect Context.Service. It defines the boundary between the SDK and the blockchain.
Interface
| Method | Signature | Description |
|---|---|---|
sendTransaction | (tx: Transaction) => Effect<Hex, AdapterServiceError> | Send a single transaction and return its hash. |
sendTransactions | (txs: Transaction[]) => Effect<AdapterSendOutcome[], AdapterServiceError> | Send a batch and return one outcome per input, in input order. |
account | Effect<CAIPAccountCompact> | The active account address in CAIP-10 compact format. |
chain | Effect<CAIPChainCompact> | The active chain identifier in CAIP-2 format. |
Outcome states
sendTransactions reports one AdapterSendOutcome per input.
| Status | Payload | Meaning |
|---|---|---|
success | hash | The transaction was included in a block. |
reverted | hash | The transaction was included but reverted on-chain. |
failed | cause | The adapter rejected the transaction before inclusion. |
unknown | hash? | The adapter could not confirm the result within the poll bound. |
AdapterServiceError
All adapter failures are surfaced as AdapterServiceError, a typed Effect error that carries the original cause.
import { AdapterServiceError } from "@mure/sdk/adapters";
// Error shape:
// {
// _tag: "AdapterServiceError",
// cause: Error // the original viem or provider error
// }ViemAdapter
ViemAdapter is the production adapter for any EVM chain. It wraps a viem WalletClient and implements the full AdapterServiceApi.
Factory: viem()
The viem() helper is the easiest way to create an adapter. It accepts either a ready-made WalletClient or a configuration object.
import { http } from "viem";
import { sepolia } from "viem/chains";
import { privateKeyToAccount } from "viem/accounts";
import { createWalletClient } from "viem";
import { viem } from "@mure/sdk/adapters";
const walletClient = createWalletClient({
chain: sepolia,
transport: http(),
account: privateKeyToAccount("0x..."), // replace with your private key
});
const adapter = viem(walletClient);import { http } from "viem";
import { sepolia } from "viem/chains";
import { privateKeyToAccount } from "viem/accounts";
import { viem } from "@mure/sdk/adapters";
const adapter = viem({
chain: sepolia,
transport: http(),
account: privateKeyToAccount("0x..."), // replace with your private key
});Batch transactions with sendTransactions
ViemAdapter supports EIP-5792 batch calls through sendTransactions. It calls viem's sendCalls, polls the call status with a fixed 1 second interval and a 120 attempt cap, and returns one outcome per input in input order.
An empty batch resolves to [] and does not call sendCalls.
When the wallet does not support batching, the adapter falls back to sequential sends. Each send is classified by its receipt. A rejected send becomes failed with the real cause. An input whose receipt does not arrive within the poll bound becomes unknown.
import { Effect } from "effect";
import { AdapterService } from "@mure/sdk/adapters";
const program = Effect.gen(function* () {
const adapter = yield* AdapterService;
const outcomes = yield* adapter.sendTransactions([
{ to: "0x...", data: "0x...", value: 0n },
{ to: "0x...", data: "0x...", value: 0n },
]);
return outcomes;
});Adapter contract
An adapter must satisfy these obligations:
sendTransactionresolves to a well-formed transaction hash.sendTransactionsresolves to exactly one outcome per input, in input order.- An empty batch resolves to
[]without calling the batch action. - A batch reports mixed outcomes. It does not fail as a whole because one input failed.
- A rejected input is
failedwith the original cause. - An unresolved input is
unknown. accountandchainare consistent CAIP compact values.accountstarts withchain:.- An attempt-level failure fails with
AdapterServiceErrorcarrying the original cause.
The SDK ships a conformance suite that checks these obligations against the viem adapter and a synthetic adapter. The suite stays internal and is not part of the package export map.
Low-level: ViemAdapter
If you already have a WalletClient and want to skip the viem() factory, use ViemAdapter directly.
import { ViemAdapter } from "@mure/sdk/adapters";
const adapter = ViemAdapter(walletClient);Usage
An adapter is required to create a Client. Pass it to createClient along with the API URL.
import { viem } from "@mure/sdk/adapters";
import { createClient } from "@mure/sdk";
import { http } from "viem";
import { sepolia } from "viem/chains";
import { privateKeyToAccount } from "viem/accounts";
const adapter = viem({
chain: sepolia,
transport: http(),
account: privateKeyToAccount("0x..."), // replace with your private key
});
const client = createClient({ adapter });For advanced Effect patterns, you can provide the adapter Layer to any program that requires AdapterService.
import { Effect } from "effect";
import { AdapterService } from "@mure/sdk/adapters";
const program = Effect.gen(function* () {
const adapter = yield* AdapterService;
const account = yield* adapter.account;
console.log("Connected:", account);
});
const runnable = program.pipe(Effect.provide(adapter));