Motiv
Build on X Layer

Integrate Builder Codes#

Add ERC-8021 attribution to your app on X Layer using Wagmi or Viem to attribute onchain activity on X Layer.

Prerequisites#

Requires viem 2.45.0 or higher. Define the X Layer chain(s) you need and reuse them across your config:

Ts
// Mainnet
import { defineChain } from "viem";

export const xlayer = defineChain({
  id: 196,
  name: "X Layer",
  nativeCurrency: { name: "OKB", symbol: "OKB", decimals: 18 },
  rpcUrls: {
    default: { http: ["https://rpc.xlayer.tech"] },
  },
  blockExplorers: {
    default: { name: "OKLink", url: "https://www.oklink.com/xlayer" },
  },
});

// Testnet
export const xlayerTestnet = defineChain({
  id: 1952,
  name: "X Layer Testnet",
  nativeCurrency: { name: "OKB", symbol: "OKB", decimals: 18 },
  rpcUrls: {
    default: { http: ["https://testrpc.xlayer.tech"] },
  },
  blockExplorers: {
    default: { name: "OKLink", url: "https://www.oklink.com/x-layer-testnet" },
  },
});

Get your Builder Code

Client-Level Setup#

Configure dataSuffix once at the client level. All transactions sent through this client automatically include your Builder Code.

Wagmi#

  1. Install dependencies:
Bash
npm i ox wagmi viem
  1. Add dataSuffix to your Wagmi config:
Ts
// config.ts
import { createConfig, http } from "wagmi";
import { Attribution } from "ox/erc8021";
import { xlayer } from "./chain";

const DATA_SUFFIX = Attribution.toDataSuffix({
  codes: ["YOUR-BUILDER-CODE"],
});

export const config = createConfig({
  chains: [xlayer],
  transports: {
    [xlayer.id]: http(),
  },
  dataSuffix: DATA_SUFFIX,
});
  1. Transactions via useSendTransaction automatically include your Builder Code:
Tsx
// App.tsx
import { useSendTransaction } from "wagmi";
import { parseEther } from "viem";

function SendButton() {
  const { sendTransaction } = useSendTransaction();

  return (
    <button
      onClick={() =>
        sendTransaction({
          to: "0x8d7c41aa990234b2d7e064df150a4228ed984648",
          value: parseEther("0.01"),
        })
      }
    >
      Send OKB
    </button>
  );
}

For batch transactions, use useSendCalls and pass the suffix via capabilities:

Tsx
import { useSendCalls } from "wagmi";
import { parseEther } from "viem";

function SendCallsButton() {
  const { sendCalls } = useSendCalls();

  return (
    <button
      onClick={() =>
        sendCalls({
          calls: [
            {
              to: "0x8d7c41aa990234b2d7e064df150a4228ed984648",
              value: parseEther("0.01"),
            },
          ],
          capabilities: {
            dataSuffix: {
              value: DATA_SUFFIX,
              optional: true,
            },
          },
        })
      }
    >
      Send calls
    </button>
  );
}

Note: useSendCalls requires the connected wallet to support the dataSuffix capability.

Viem#

  1. Install dependencies:
Bash
npm i ox viem
  1. Add dataSuffix when creating your wallet client:
Ts
// client.ts
import { createWalletClient, http } from "viem";
import { Attribution } from "ox/erc8021";
import { xlayer } from "./chain";

const DATA_SUFFIX = Attribution.toDataSuffix({
  codes: ["YOUR-BUILDER-CODE"],
});

export const walletClient = createWalletClient({
  chain: xlayer,
  transport: http(),
  dataSuffix: DATA_SUFFIX,
});
  1. All transactions sent through this client include your Builder Code:
Ts
import { parseEther } from "viem";
import { walletClient } from "./client";

const hash = await walletClient.sendTransaction({
  to: "0x8d7c41aa990234b2d7e064df150a4228ed984648",
  value: parseEther("0.01"),
});

Per-Transaction Configuration#

If you need granular control, pass dataSuffix directly on individual transactions instead of at the client level.

useSendTransaction#

Tsx
import { useSendTransaction } from "wagmi";
import { parseEther } from "viem";
import { Attribution } from "ox/erc8021";

const DATA_SUFFIX = Attribution.toDataSuffix({
  codes: ["YOUR-BUILDER-CODE"],
});

function App() {
  const { sendTransaction } = useSendTransaction();

  return (
    <button
      onClick={() =>
        sendTransaction({
          to: "0x8d7c41aa990234b2d7e064df150a4228ed984648",
          value: parseEther("0.01"),
          dataSuffix: DATA_SUFFIX,
        })
      }
    >
      Send OKB
    </button>
  );
}

useSendCalls#

Pass the suffix via the capabilities object.

Note: useSendCalls requires the connected wallet to support the dataSuffix capability.

Tsx
import { useSendCalls } from "wagmi";
import { parseEther } from "viem";
import { Attribution } from "ox/erc8021";

const DATA_SUFFIX = Attribution.toDataSuffix({
  codes: ["YOUR-BUILDER-CODE"],
});

function App() {
  const { sendCalls } = useSendCalls();

  return (
    <button
      onClick={() =>
        sendCalls({
          calls: [
            {
              to: "0x8d7c41aa990234b2d7e064df150a4228ed984648",
              value: parseEther("1"),
            },
          ],
          capabilities: {
            dataSuffix: {
              value: DATA_SUFFIX,
              optional: true,
            },
          },
        })
      }
    >
      Send calls
    </button>
  );
}

Verify Attribution#

See Verify Attribution for steps to confirm your transaction was properly attributed.

Builder Code Analytics#

Track your Builder Code performance in the OKX Developer Portal:

  • Onchain activity — monitor attributed transactions and call volume
  • User acquisition — measure new users driven by your app
  • Conversion metrics — analyze funnel performance from impression to onchain action

Use these insights to optimize your integration and grow your audience on X Layer.