Integrate Builder Codes#
Add ERC-8021 attribution to your app on X Layer using Viem or Wagmi 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:
// chain.ts
import { defineChain } from "viem";
// Mainnet
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
- Mainnet: Go to the OKX developer portal, verify your address, then create your Builder Code on the Builder Code page.
- Testnet: Connect your wallet and call
registerAutoon the Builder Code registry contract. Need testnet OKB? Use the faucet.
Client-Level Setup#
Configure dataSuffix once on the client that actually sends the transaction. For browser wallet integrations, Viem is the recommended default because the configured wallet client is also the client used to send the transaction.
Viem (Recommended)#
- Install dependencies:
npm i ox viem
- Create and reuse one wallet client with
dataSuffix:
// client.ts
import { createWalletClient, custom } from "viem";
import { Attribution } from "ox/erc8021";
import { xlayer } from "./chain";
const DATA_SUFFIX = Attribution.toDataSuffix({
codes: ["YOUR-BUILDER-CODE"],
});
if (!window.ethereum) {
throw new Error("No injected wallet found");
}
export const walletClient = createWalletClient({
chain: xlayer,
transport: custom(window.ethereum),
dataSuffix: DATA_SUFFIX,
});
- Send transactions with the same client:
import { walletClient } from "./client";
const [account] = await walletClient.requestAddresses();
const hash = await walletClient.sendTransaction({
account,
to: "0x8d7c41aa990234b2d7e064df150a4228ed984648",
});
Every transaction sent through walletClient includes your Builder Code automatically.
Wagmi#
For connector wallets, use a custom connector client so dataSuffix is applied to the wallet-backed client used by useSendTransaction.
- Install dependencies:
npm i ox wagmi viem
- Add a custom injected connector that returns a client with
dataSuffix:
// config.ts
import { Attribution } from "ox/erc8021";
import { createClient, custom } from "viem";
import { createConfig, createConnector, http } from "wagmi";
import { injected } from "wagmi/connectors";
import { xlayer } from "./chain";
const DATA_SUFFIX = Attribution.toDataSuffix({
codes: ["YOUR-BUILDER-CODE"],
});
function injectedWithDataSuffix() {
const baseInjected = injected();
return createConnector((config) => {
const connector = baseInjected(config);
return {
...connector,
async getClient({ chainId } = {}) {
const id = chainId ?? (await connector.getChainId());
const chain = config.chains.find((item) => item.id === id);
const provider = await connector.getProvider({ chainId: id });
const [account] = await connector.getAccounts();
if (!chain) throw new Error(`Chain ${id} is not configured.`);
if (!provider) throw new Error("Injected provider not found.");
if (!account) throw new Error("No connected account found.");
return createClient({
account,
chain,
dataSuffix: DATA_SUFFIX,
transport: (options) =>
custom(provider)({
...options,
retryCount: 0,
}),
});
},
};
});
}
export const config = createConfig({
chains: [xlayer],
connectors: [injectedWithDataSuffix()],
transports: {
[xlayer.id]: http(),
},
});
- Transactions via
useSendTransactioninherit your Builder Code from the custom connector client:
// App.tsx
import { useSendTransaction } from "wagmi";
function SendButton() {
const { sendTransaction } = useSendTransaction();
return (
<button
onClick={() =>
sendTransaction({
to: "0x8d7c41aa990234b2d7e064df150a4228ed984648",
})
}
>
Send OKB
</button>
);
}
Per-Transaction Configuration#
If you need granular control, pass dataSuffix directly on individual transactions instead of at the client level.
useSendTransaction#
import { useSendTransaction } from "wagmi";
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",
dataSuffix: DATA_SUFFIX,
})
}
>
Send OKB
</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.