> ## Documentation Index
> Fetch the complete documentation index at: https://www.dynamic.xyz/docs/llms.txt
> Use this file to discover all available pages before exploring further.

# Mavryk

> Derive Mavryk addresses and sign transactions using Dynamic embedded wallets

## Overview

Mavryk (a fork of Tezos) uses the Ed25519 elliptic curve. Addresses are derived with Blake2b-160 hashing and encoded using `b58cencode` from `@mavrykdynamics/webmavryk-utils`. Transactions are built and submitted using `MavrykToolkit` from `@mavrykdynamics/webmavryk`.

This guide covers **Ed25519 (`mv1`) addresses only**. Mavryk also supports Secp256k1 (`mv2`), P-256 (`mv3`), and BLS12-381 (`mv4`); Dynamic’s embedded wallet flow here assumes Ed25519 keys.

| Property       | Value                                        |
| -------------- | -------------------------------------------- |
| Curve          | Ed25519                                      |
| Address Format | base58check (`mv1...`)                       |
| Hashing        | Blake2b-160 (address), Blake2b-256 (signing) |
| Serialization  | Micheline / node-forged binary               |
| Smallest Unit  | Mumav (1 MAV = 10^6 mumav)                   |

## Dependencies

<CodeGroup>
  ```bash npm theme={"system"}
  npm install @mavrykdynamics/webmavryk @mavrykdynamics/webmavryk-utils @stablelib/blake2b bs58 @noble/curves
  ```

  ```bash yarn theme={"system"}
  yarn add @mavrykdynamics/webmavryk @mavrykdynamics/webmavryk-utils @stablelib/blake2b bs58 @noble/curves
  ```

  ```bash pnpm theme={"system"}
  pnpm add @mavrykdynamics/webmavryk @mavrykdynamics/webmavryk-utils @stablelib/blake2b bs58 @noble/curves
  ```

  ```bash bun theme={"system"}
  bun add @mavrykdynamics/webmavryk @mavrykdynamics/webmavryk-utils @stablelib/blake2b bs58 @noble/curves
  ```
</CodeGroup>

## Derive Address

Hash the Ed25519 public key with Blake2b-160 and encode with `b58cencode` using the `MV1` prefix:

```typescript theme={"system"}
import { hash } from "@stablelib/blake2b";
import { b58cencode, prefix, Prefix } from "@mavrykdynamics/webmavryk-utils";
import bs58 from "bs58";

function deriveMavrykAddress(walletAddress: string): string {
  const pubkey = bs58.decode(walletAddress);
  const h = hash(pubkey, 20);
  return b58cencode(h, prefix[Prefix.MV1]);
}
```

## Sign a Message

Mavryk uses a `0x05` watermark for arbitrary data signing, followed by Blake2b-256 — the same scheme as the React Native example below:

```typescript theme={"system"}
import { signMessage } from "@dynamic-labs-sdk/client";
import type { WalletAccount } from "@dynamic-labs-sdk/client";
import { mergebuf, buf2hex } from "@mavrykdynamics/webmavryk-utils";
import { hash } from "@stablelib/blake2b";

async function signMavrykMessage(
  message: string,
  wallet: WalletAccount,
): Promise<string> {
  const messageBytes = new TextEncoder().encode(message);
  const watermarked = mergebuf(new Uint8Array([0x05]), messageBytes);
  const digest = hash(watermarked, 32);
  const result = await signMessage({
    walletAccount: wallet,
    message: buf2hex(digest),
  });
  return result.signature;
}
```

## Verify a Signature

Verify the Ed25519 signature against the same Blake2b-256 digest produced when signing (watermark `0x05` + message):

```typescript theme={"system"}
import { ed25519 } from "@noble/curves/ed25519";
import { mergebuf } from "@mavrykdynamics/webmavryk-utils";
import { hash } from "@stablelib/blake2b";
import bs58 from "bs58";

function verifyMavrykSignature(
  message: string,
  signature: string,
  walletAddress: string,
): boolean {
  const pubkey = bs58.decode(walletAddress);
  const messageBytes = new TextEncoder().encode(message);
  const watermarked = mergebuf(new Uint8Array([0x05]), messageBytes);
  const digest = hash(watermarked, 32);
  const sigBytes = bs58.decode(signature);
  return ed25519.verify(sigBytes, digest, pubkey);
}
```

## Check Balance

Query the MAV balance via the Mavryk node RPC:

```typescript theme={"system"}
async function getMavrykBalance(address: string): Promise<string> {
  const res = await fetch(
    `https://rpc.mavryk.network/chains/main/blocks/head/context/contracts/${address}/balance`,
  );

  if (!res.ok) return "0";

  const mumavStr = await res.json();
  const mumav = BigInt(mumavStr);
  const divisor = BigInt(1_000_000);
  const whole = mumav / divisor;
  const frac = mumav % divisor;
  const fracStr = frac.toString().padStart(6, "0").replace(/0+$/, "");
  return fracStr.length === 0 ? whole.toString() : `${whole}.${fracStr}`;
}
```

## Send a Transfer

Use `MavrykToolkit` with a custom signer that routes signing through Dynamic’s `signMessage`. The toolkit handles forging, watermarking, and injection automatically.

```typescript theme={"system"}
import { signMessage } from "@dynamic-labs-sdk/client";
import type { WalletAccount } from "@dynamic-labs-sdk/client";
import { hash } from "@stablelib/blake2b";
import {
  hex2buf, buf2hex, mergebuf,
  b58cencode, prefix, Prefix,
} from "@mavrykdynamics/webmavryk-utils";
import { MavrykToolkit } from "@mavrykdynamics/webmavryk";
import bs58 from "bs58";

const MAVRYK_RPC = "https://rpc.mavryk.network";

class DynamicMavrykSigner {
  constructor(
    private pubkeyBytes: Uint8Array,
    private wallet: WalletAccount,
  ) {}

  async publicKey() {
    return b58cencode(this.pubkeyBytes, prefix[Prefix.EDPK]);
  }

  async publicKeyHash() {
    return b58cencode(hash(this.pubkeyBytes, 20), prefix[Prefix.MV1]);
  }

  async secretKey(): Promise<string | undefined> {
    return undefined;
  }

  async sign(bytes: string, watermark?: Uint8Array) {
    let buf = hex2buf(bytes);
    if (watermark) buf = mergebuf(watermark, buf);

    // Mavryk requires Blake2b-256 pre-hash before signing
    const digest = hash(buf, 32);

    const { signature } = await signMessage({
      walletAccount: this.wallet,
      message: buf2hex(digest),
    });
    // Dynamic returns the signature as base58; decode before encoding
    const sigBytes = bs58.decode(signature);

    return {
      bytes,
      sig: b58cencode(sigBytes, prefix[Prefix.SIG]),
      prefixSig: b58cencode(sigBytes, prefix[Prefix.EDSIG]),
      sbytes: bytes + buf2hex(sigBytes),
    };
  }
}

async function sendMavrykTransfer(
  to: string,
  amount: number,
  wallet: WalletAccount,
): Promise<string> {
  const pubkeyBytes = bs58.decode(wallet.address);

  const signer = new DynamicMavrykSigner(pubkeyBytes, wallet);
  const toolkit = new MavrykToolkit(MAVRYK_RPC);
  toolkit.setSignerProvider(signer);

  const op = await toolkit.contract.transfer({ to, amount });
  await op.confirmation(1);
  return op.hash;
}
```

<Note>
  `MavrykToolkit` handles operation forging, watermarking (`0x03`), and injection. The custom signer applies Blake2b-256 pre-hashing before passing the digest to Dynamic’s `signMessage`.
</Note>
