Builder Integration

The Builder Code system allows trading interfaces (builders) to earn fees on orders placed through their platforms. When users place orders through a builder’s interface, the builder can receive a portion of the trade value as fees.

Note

For more details on the Builder Integration system, see the official Nado documentation.

Overview

How It Works

  1. Builder Registration: Contact the Nado team to get registered as a builder

  2. Order Placement: Users place orders through your interface with your builder ID and fee rate in the order appendix

  3. Fee Collection: When orders are matched, builder fees are automatically collected

  4. Fee Claiming: Claim accumulated fees to your subaccount, then withdraw normally

Key Concepts

Term

Description

Builder ID

Unique 16-bit identifier for the builder (1-65535)

Builder Fee Rate

Fee rate in units of 0.1bps (0.001%)

Fee Rate Units

Builder fee rates are specified in 0.1bps units (0.001% per unit):

  • 1 unit = 0.001% = 0.00001

  • 10 units = 0.01% = 1bps

  • 50 units = 0.05% = 5bps

  • 100 units = 0.1% = 10bps

Placing Orders with Builder Info

To route orders through your builder and collect fees, include your builder information in the order appendix using the build_appendix function.

Basic Example

from nado_protocol.utils.order import build_appendix
from nado_protocol.utils.expiration import OrderType

# Create appendix with builder info
# builder_id: Your registered builder ID
# builder_fee_rate: Fee rate in 0.1bps units (e.g., 50 = 5bps = 0.05%)
appendix = build_appendix(
    order_type=OrderType.DEFAULT,
    builder_id=2,
    builder_fee_rate=50  # 5bps = 0.05%
)

Complete Order Placement Example

from eth_account import Account
from nado_protocol.engine_client import EngineClient, EngineClientOpts
from nado_protocol.engine_client.types.execute import PlaceOrderParams, OrderParams
from nado_protocol.utils.order import build_appendix
from nado_protocol.utils.expiration import OrderType, get_expiration_timestamp
from nado_protocol.utils.math import to_pow_10, to_x18
from nado_protocol.utils.nonce import gen_order_nonce
from nado_protocol.utils.subaccount import SubaccountParams

# Initialize client
signer = Account.from_key("YOUR_PRIVATE_KEY")
engine_client = EngineClient(
    opts=EngineClientOpts(url="https://gateway.prod.nado.xyz/v1", signer=signer)
)

# Get contracts info
contracts = engine_client.get_contracts()
engine_client.endpoint_addr = contracts.endpoint_addr
engine_client.chain_id = contracts.chain_id

# Build appendix with builder info
builder_appendix = build_appendix(
    order_type=OrderType.DEFAULT,
    builder_id=2,           # Your builder ID
    builder_fee_rate=50     # 5bps fee rate
)

# Create order
order = OrderParams(
    sender=SubaccountParams(
        subaccount_owner=signer.address,
        subaccount_name="default"
    ),
    priceX18=to_x18(100000),         # Price in x18 format
    amount=to_pow_10(1, 16),          # 0.01 BTC
    expiration=get_expiration_timestamp(60),  # 60 seconds from now
    nonce=gen_order_nonce(),
    appendix=builder_appendix
)

# Place order
product_id = 2  # BTC-PERP
result = engine_client.place_order(
    PlaceOrderParams(product_id=product_id, order=order)
)
print(f"Order placed: {result}")

Combining Builder with Other Appendix Options

Builder info can be combined with other order options like IOC, reduce-only, or isolated positions:

from nado_protocol.utils.order import build_appendix
from nado_protocol.utils.expiration import OrderType
from nado_protocol.utils.math import to_x6

# IOC order with builder fee
ioc_builder_appendix = build_appendix(
    order_type=OrderType.IOC,
    builder_id=2,
    builder_fee_rate=30  # 3bps
)

# Reduce-only order with builder fee
reduce_only_builder_appendix = build_appendix(
    order_type=OrderType.DEFAULT,
    reduce_only=True,
    builder_id=2,
    builder_fee_rate=25  # 2.5bps
)

# Isolated position with builder fee
isolated_builder_appendix = build_appendix(
    order_type=OrderType.DEFAULT,
    isolated=True,
    isolated_margin=to_x6(1000),  # 1000 USDC margin
    builder_id=2,
    builder_fee_rate=50  # 5bps
)

Extracting Builder Info from Appendix

You can extract builder information from an existing appendix:

from nado_protocol.utils.order import (
    build_appendix,
    order_builder_id,
    order_builder_fee_rate,
    order_builder_info
)
from nado_protocol.utils.expiration import OrderType

# Create appendix
appendix = build_appendix(
    order_type=OrderType.DEFAULT,
    builder_id=2,
    builder_fee_rate=50
)

# Extract individual fields
builder_id = order_builder_id(appendix)
fee_rate = order_builder_fee_rate(appendix)

# Or get both as a tuple
builder_info = order_builder_info(appendix)  # Returns (builder_id, fee_rate) or None

print(f"Builder ID: {builder_id}")
print(f"Fee Rate: {fee_rate} (0.1bps units)")
print(f"Builder Info: {builder_info}")

Querying Orders with Builder Fees

When querying historical orders or matches, the builder fee is included in the response:

Querying Historical Orders

from nado_protocol.indexer_client import IndexerClient
from nado_protocol.utils.order import order_builder_id, order_builder_fee_rate

indexer = IndexerClient(opts={"url": "https://archive.prod.nado.xyz/v1"})

# Query order by digest
orders = indexer.get_historical_orders_by_digest(["0x...order_digest..."])

if orders.orders:
    order = orders.orders[0]
    print(f"Digest: {order.digest}")
    print(f"Total Fee: {order.fee}")
    print(f"Builder Fee: {order.builder_fee}")

    # Extract builder info from appendix
    if order.appendix:
        appendix_int = int(order.appendix)
        print(f"Builder ID: {order_builder_id(appendix_int)}")
        print(f"Builder Fee Rate: {order_builder_fee_rate(appendix_int)}")

Querying Match Events

from nado_protocol.indexer_client import IndexerClient
from nado_protocol.indexer_client.types.query import IndexerMatchesParams

indexer = IndexerClient(opts={"url": "https://archive.prod.nado.xyz/v1"})

# Query matches for a subaccount
sender_hex = "0x..."  # Your subaccount hex
matches = indexer.get_matches(
    IndexerMatchesParams(
        subaccounts=[sender_hex],
        product_ids=[2],  # BTC-PERP
        limit=10
    )
)

for match in matches.matches:
    print(f"Digest: {match.digest}")
    print(f"Base Filled: {match.base_filled}")
    print(f"Total Fee: {match.fee}")
    print(f"Sequencer Fee: {match.sequencer_fee}")
    print(f"Builder Fee: {match.builder_fee}")

Querying Claimable Fees

Before claiming, check how much you’ve accumulated using get_claimable_builder_fee:

from nado_protocol.contracts import NadoContracts, NadoContractsContext
from nado_protocol.contracts.loader import load_deployment

deployment = load_deployment("mainnet")  # or "testnet"
nado_contracts = NadoContracts(
    node_url=deployment.node_url,
    contracts_context=NadoContractsContext(**deployment.dict()),
)

builder_id = 2  # Your builder ID
claimable = nado_contracts.get_claimable_builder_fee(builder_id)
print(f"Claimable: {claimable / 1e18} USDC")

This calls the getClaimableBuilderFee(quoteId, builderId) view function on the OffchainExchange contract. The return value is in x18 format (divide by 10^18 to get USDC), e.g. 5000000000000000000 = 5 USDC.

Claiming Builder Fees

Builders can claim their accumulated fees using the claim_builder_fee method on NadoContracts.

Note

Claiming builder fees requires a 1 USDT slow mode fee. Make sure to approve the fee before claiming.

Complete Claiming Example

from eth_account import Account
from nado_protocol.contracts import (
    NadoContracts,
    NadoContractsContext,
    ClaimBuilderFeeParams
)
from nado_protocol.contracts.loader import load_deployment
from nado_protocol.utils.math import to_pow_10

# Load deployment config
deployment = load_deployment("mainnet")  # or "testnet"

# Initialize contracts
nado_contracts = NadoContracts(
    node_url=deployment.node_url,
    contracts_context=NadoContractsContext(**deployment.dict()),
)

signer = Account.from_key("YOUR_PRIVATE_KEY")

# Approve 1 USDT for slow mode fee
usdt_token = nado_contracts.get_token_contract_for_product(0)
slow_mode_fee = to_pow_10(1, 6)  # 1 USDT
approve_tx = nado_contracts.approve_allowance(usdt_token, slow_mode_fee, signer)
print(f"Approval tx: {approve_tx}")

# Wait for approval to be mined
import time
time.sleep(5)

# Claim builder fees
tx_hash = nado_contracts.claim_builder_fee(
    ClaimBuilderFeeParams(
        subaccount_owner=signer.address,
        subaccount_name="default",
        builder_id=2  # Your builder ID
    ),
    signer
)
print(f"Claim tx: {tx_hash}")

Encoding ClaimBuilderFee Transaction Manually

If you need to encode the transaction manually:

from nado_protocol.utils.slow_mode import (
    SlowModeTxType,
    encode_claim_builder_fee_tx
)
from nado_protocol.utils.bytes32 import subaccount_to_bytes32

# Encode the transaction
sender_bytes = subaccount_to_bytes32("0xYourAddress", "default")
builder_id = 2

claim_tx = encode_claim_builder_fee_tx(sender_bytes, builder_id)

# Verify tx type (should be 31)
assert claim_tx[0] == SlowModeTxType.CLAIM_BUILDER_FEE

print(f"Encoded tx: {claim_tx.hex()}")

Querying Builder Info

You can query a builder’s configuration:

from nado_protocol.contracts import NadoContracts, NadoContractsContext
from nado_protocol.contracts.loader import load_deployment

deployment = load_deployment("mainnet")
nado_contracts = NadoContracts(
    node_url=deployment.node_url,
    contracts_context=NadoContractsContext(**deployment.dict()),
)

# Query builder info
builder_id = 2
builder_info = nado_contracts.get_builder_info(builder_id)

print(f"Owner: {builder_info.owner}")
print(f"Default Fee Tier: {builder_info.default_fee_tier}")
print(f"Lowest Fee Rate: {builder_info.lowest_fee_rate}")
print(f"Highest Fee Rate: {builder_info.highest_fee_rate}")

Querying Claim Events

Query claim_builder_fee events from the indexer:

from nado_protocol.indexer_client import IndexerClient
from nado_protocol.indexer_client.types.models import IndexerEventType
from nado_protocol.indexer_client.types.query import (
    IndexerEventsParams,
    IndexerEventsRawLimit
)

indexer = IndexerClient(opts={"url": "https://archive.prod.nado.xyz/v1"})

# Query claim events for your subaccount
sender_hex = "0x..."  # Your subaccount hex
events_data = indexer.get_events(
    IndexerEventsParams(
        subaccounts=[sender_hex],
        event_types=[IndexerEventType.CLAIM_BUILDER_FEE],
        limit=IndexerEventsRawLimit(raw=10)
    )
)

for event in events_data.events:
    # Find corresponding tx for timestamp
    tx = next(
        (t for t in events_data.txs if t.submission_idx == event.submission_idx),
        None
    )
    if tx:
        print(f"Claim event at timestamp: {tx.timestamp}")
        print(f"Pre-balance: {event.pre_balance}")
        print(f"Post-balance: {event.post_balance}")

Fee Calculation

Builder fees are calculated based on the trade’s notional value:

builder_fee = maker_price × |base_filled| × builder_fee_rate / 10^18

Example: Buying 0.1 BTC at $100,000 with a 5bps (50 units) builder fee:

  • Notional = $100,000 × 0.1 = $10,000

  • Fee rate in x18 = 50 × 10^13 = 5 × 10^14

  • Builder fee = $10,000 × 5 × 10^14 / 10^18 = $5

Validation Rules

Orders with builder information must satisfy:

  1. Builder Must Exist: The builder ID must be registered

  2. Fee Rate Within Bounds: Fee rate must be within your configured bounds (lowest_fee_rate to highest_fee_rate)

  3. No Fee Without Builder: If builder_id == 0, then builder_fee_rate must also be 0

Error Codes

Error Code

Error Value

Description

2118

InvalidBuilder

Builder ID is invalid, not registered, or fee rate is outside allowed bounds

Getting Started

  1. Contact Nado Team: Reach out to get registered as a builder

  2. Activate Subaccount: Make a minimum $5 deposit to activate your subaccount

  3. Integrate: Update your order placement to include builder info in the appendix

  4. Claim & Withdraw: Periodically claim fees and withdraw to your wallet

API Reference

Order Appendix Functions

  • nado_protocol.utils.order.build_appendix() - Build an appendix with builder info

  • nado_protocol.utils.order.order_builder_id() - Extract builder ID from appendix

  • nado_protocol.utils.order.order_builder_fee_rate() - Extract fee rate from appendix

  • nado_protocol.utils.order.order_builder_info() - Extract (builder_id, fee_rate) tuple

Slow Mode Functions

Contract Methods

See Also