Skip to content
LogoLogo

Client

The @mure/sdk client wraps the lower-level @mure/api-v2 client and a blockchain adapter into one interface. It handles transaction creation, API communication, and on-chain submission in one call.

Installation

Creating a Client

Use createClient to instantiate the client. You must provide an Adapter — the SDK ships with a viem adapter out of the box.

import { createClient, viem } 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 });

API configuration

Pass API options under the api key. Both fields are optional, so createClient({ adapter }) stays valid.

const client = createClient({
  adapter,
  api: {
    url: "https://api.mure.app/v2", // optional, defaults to this URL
    apiKey: process.env.MURE_API_KEY, // optional
  },
});

createClient throws ClientConfigError synchronously when api.apiKey is a blank string. An absent key is allowed. See Authentication for credential semantics.

Transfer

The transfer method creates a transfer intent via the API and immediately submits the resulting transaction through the adapter.

import { eth } from "@mure/sdk/accounts/evm";
 
const hash = await client.transfer({
  to: eth("0x8f664a25158021EFb4470f9036431664ce9f7895"), // recipient address
  asset: "USDC",
  amount: 10_000_000n, // 10 USDC (6 decimals)
});

transfer resolves to the transaction hash as a bare hex string. It does not return an outcome array.

Parameters

FieldTypeRequiredDescription
fromAddressNoSource address and chain. Defaults to the adapter's connected account.
toAddressYesDestination address and chain (same chain as from).
assetstring | { in: Address; out: Address }YesToken symbol, CAIP-10 asset, or swap pair. See Swaps.
amountbigintYesAmount to transfer as a bigint.
deadlinestringNoLatest execution time (ISO 8601). Defaults to +1 hour.
callDatastringNoHex-encoded calldata forwarded to recipient.

Explicit from

When from is omitted, the client uses the adapter's connected account. You can also provide it explicitly:

import { sepolia } from "@mure/sdk/accounts/evm";
 
const hash = await client.transfer({
  from: sepolia("0x3165fd5B9D37Ac9619aC5895CA33F308aB02a053"), // sender address
  to: sepolia("0x8f664a25158021EFb4470f9036431664ce9f7895"), // recipient address
  asset: "USDC",
  amount: 10_000_000n, // 10 USDC (6 decimals)
});

Swaps

To swap one asset for another on the same chain, pass an { in, out } object instead of a single asset string. Both fields accept the same address formats as from and to.

import { base, eth } from "@mure/sdk/accounts/evm";
 
const USDC = eth("0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48");
const NATIVE_ETH = eth("0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE");
 
const hash = await client.transfer({
  to: eth("0x8f664a25158021EFb4470f9036431664ce9f7895"),
  asset: { in: USDC, out: NATIVE_ETH },
  amount: 10_000_000n,
});

Cross-chain bridges

To move assets across chains, set to to an address on a different chain than from. The SDK submits a single transfer call and Mure selects a bridge route automatically.

import { base, eth } from "@mure/sdk/accounts/evm";
 
const USDC = eth("0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48");
 
const hash = await client.transfer({
  from: eth("0x3165fd5B9D37Ac9619aC5895CA33F308aB02a053"),
  to: base("0x8f664a25158021EFb4470f9036431664ce9f7895"),
  asset: { in: USDC, out: USDC },
  amount: 10_000_000n,
});

Submission and confirmation

transfer is two operations in one call:

  1. POST a transfer intent to the API.
  2. Hand the returned transaction to the adapter.

The SDK adds no confirmation step of its own. Whether the user sees a prompt depends on the adapter's account. The examples on this page use privateKeyToAccount, so submission is silent. A browser-wallet transport prompts through the wallet.

The public transfer API has no preview option. To inspect the intent before you submit it, create the intent with ApiClient.createTransfer, then send the transaction with client.send.

import { Account } from "@mure/chains/caip";
import { ApiClient } from "@mure/api-v2/client";
import { Effect } from "effect";
import { ClientService } from "@mure/sdk";
 
const program = Effect.gen(function* () {
  const api = yield* ApiClient;
  const client = yield* ClientService;
 
  // 1. Create the intent and inspect it.
  const intent = yield* api.createTransfer({
    payload: {
      from: Account.expand(
        "eip155:1:0x3165fd5B9D37Ac9619aC5895CA33F308aB02a053",
      ),
      to: Account.expand("eip155:1:0x8f664a25158021EFb4470f9036431664ce9f7895"),
      asset: Account.expandAssetReference("USDC"),
      amount: 10_000_000n,
    },
  });
 
  console.log("Submitting to", intent.tx.to, "value", intent.tx.value);
 
  // 2. Submit only after you decide.
  const [outcome] = yield* client.send(intent.tx);
  return outcome;
});

Provide the ClientService and ApiClient layers to run it.

const runnable = program.pipe(
  Effect.provide(ClientService.layer),
  Effect.provide(adapter),
  Effect.provide(
    ApiClient.layer({
      baseUrl: "https://api.mure.app/v2",
      apiKey: process.env.MURE_API_KEY,
    }),
  ),
);
 
Effect.runPromise(runnable).then(console.log).catch(console.error);

Send

For transactions you have already constructed, use client.send to broadcast them through the configured adapter. Pass one transaction or an array.

const outcomes = await client.send([
  { to: "0x...", data: "0x...", value: 0n },
  { to: "0x...", data: "0x...", value: 0n },
]);

send returns one outcome per input, in input order.

StatusPayloadMeaning
successhashThe transaction was included in a block.
revertedhashThe transaction was included but reverted on-chain.
failedcauseThe adapter rejected the transaction before inclusion.
unknownhash?The adapter could not confirm the result within the poll bound.

A single transaction resolves to a one-element outcome array.

const [outcome] = await client.send({ to: "0x...", data: "0x...", value: 0n });

The adapter owns batching. When the wallet supports EIP-5792, send submits the batch with one call and polls the call status. When the wallet does not support batching, the adapter sends the transactions sequentially and reports each result. A batch does not fail as a whole because one transaction failed.

send is useful when you want to combine Mure-generated transactions with your own calls, or when you are using a wallet model such as account abstraction or EIP-7702 that is covered by Mure's Unified Entrypoint.

Reading transfers and tokens

List transfers

const transfers = await client.listTransfers(); // all transfers
const swaps = await client.listTransfers({ type: "swap" }); // filtered

The args parameter is optional. Omit it to list every transfer.

FieldTypeRequiredDescription
type"transfer" | "swap" | "bridge"NoFilter by transfer type.

Returns { items: TransferSummary[] }.

FieldTypeDescription
idstringTransfer id.
type"transfer" | "swap" | "bridge"Transfer type.
status"draft" | "pending" | "confirmed" | "failed" | "expired" | "finalized"Transfer status.
createdAtDateCreation time.
updatedAtDateLast update time.
orderId`0x${string}` (optional)Order id when the transfer has one.
metadata{ chainId: "eip155:<ref>"; hash?: "0x<hex>" }Chain id and transaction hash.

Get one transfer

const transfer = await client.getTransfer({ id: "int_transfer_01..." });

The args parameter is required and must contain id.

FieldTypeRequiredDescription
idstringYesTransfer id.

Returns a single TransferSummary with the fields listed above.

List tokens

const tokens = await client.listTokens(); // all tokens
const mainnet = await client.listTokens({ chainId: "eip155:1" }); // filtered

The args parameter is optional. Omit it to list every token.

FieldTypeRequiredDescription
chainId`eip155:${number}`NoFilter by chain.

Returns { items: TokenDefinition[] }.

FieldTypeDescription
symbolstringToken symbol.
chainIdstringChain id.
addressstringCAIP-10 account for the symbol and chain pair.
decimalsnumberToken decimals.
metadatastring | nullExtra token metadata.

EVM account helpers

The SDK ships with small helpers that build CAIP-10 identifiers for common EVM chains. They are available from @mure/sdk/accounts/evm.

import {
  eth,
  sepolia,
  base,
  baseSepolia,
  hyperliquid,
  hyperliquidTestnet,
} from "@mure/sdk/accounts/evm";
 
const mainnetAccount = eth("0x8f664a25158021EFb4470f9036431664ce9f7895");
// => "eip155:1:0x8f664a25158021EFb4470f9036431664ce9f7895"

Use these helpers to keep addresses chain-scoped and avoid hand-written CAIP-10 strings in examples.

Imports

The SDK exposes one root entry and four documented subpaths.

Import pathExports
@mure/sdkcreateClient, ClientService, ClientServiceError, ClientConfigError, viem, ViemAdapter, AdapterService, AdapterServiceError, and the public types.
@mure/sdk/adaptersAdapterService, AdapterServiceError, ViemAdapter, viem.
@mure/sdk/accounts/evmeth, sepolia, base, baseSepolia, hyperliquid, hyperliquidTestnet.
@mure/sdk/chainstoCAIP.
@mure/sdk/chains/evmtoCAIP.

Error Handling

All SDK errors are surfaced as ClientServiceError. Wrap calls in try/catch to handle failures.

import { ClientServiceError } from "@mure/sdk";
import { eth } from "@mure/sdk/accounts/evm";
 
try {
  const hash = await client.transfer({
    to: eth("0x..."), // recipient address
    asset: "USDC",
    amount: 10_000_000n, // 10 USDC (6 decimals)
  });
} catch (error) {
  if (error instanceof ClientServiceError) {
    console.error("Transfer failed:", error.message);
  }
}

Effect-TS Integration

For advanced use cases, you can access the client inside an Effect program.

import { Effect } from "effect";
import { ClientService } from "@mure/sdk";
import { eth } from "@mure/sdk/accounts/evm";
 
const program = Effect.gen(function* () {
  const client = yield* ClientService;
  const hash = yield* client.transfer({
    to: eth("0x..."), // recipient address
    asset: "USDC",
    amount: 10_000_000n, // 10 USDC (6 decimals)
  });
  return hash;
});

The ClientService is a Context.Service. Provide it via ClientService.layer combined with an Adapter and ApiClient.layer.

import { ClientService } from "@mure/sdk";
import { ApiClient } from "@mure/api-v2/client";
import { Effect } from "effect";
 
const runnable = program.pipe(
  Effect.provide(ClientService.layer),
  Effect.provide(adapter),
  Effect.provide(
    ApiClient.layer({
      baseUrl: "https://api.mure.app/v2",
      apiKey: process.env.MURE_API_KEY,
    }),
  ),
);
 
Effect.runPromise(runnable).then(console.log).catch(console.error);