Skip to content

How to Pay Circle Bridge Kit Fees on the Source Chain (2026)

Receive-exact USDC with Circle Bridge Kit: estimate → opaque quote → bridge, totalDebit vs amountReceived, and when source-paid fees beat destination deduction.

Table of Contents

Default Circle Bridge Kit forwarding takes Fast Transfer and Forwarding Service fees out of the destination mint. That is fine for treasury rebalances. It breaks checkout and payroll flows where the recipient must land the exact USDC amount you promised.

This Stablecoin Insider how-to covers Circle Bridge Kit fees paid on the source chain: config.feePayment: 'source' with useForwarder: true, the opaque Fee Service quote, estimate → bridge, TokenMessengerWithFees, and the SLOW-only constraint on Avalanche, Polygon PoS, Sei, and XDC. It is a follow-on to Stablecoin Insider's How to Transfer USDC with Circle Bridge Kit (kit.bridge basics). No Fee Service credentials were available for a live quote, so live fee numbers from Arc's tutorial sample stay labeled as docs examples.

Key Takeaways

  • feePayment:'source' + useForwarder:true delivers receive-exact USDC on destination.
  • Call kit.estimate, pass the opaque quote into kit.bridge before it expires.
  • Source wallet pays totalDebit (amount + feeTotal); amountReceived equals amount.
  • On Avalanche, Polygon PoS, Sei, and XDC sources, set transferSpeed:'SLOW'.
  • No customFee with source fees; live Fee Service quotes need route credentials.
🧭
What this guide is: a package and docs audit of @circle-fin/bridge-kit 1.15.2 receive-exact / source-paid fees (npm latest as of 11 October 2026), checked against the published README, index.d.mts types, Arc App Kit pay-fees-on-source and use-forwarding-service tutorials, plus a TypeScript dry-run that confirmed kit.estimate narrows to ReceiveExactEstimateResult when feePayment is 'source'. No mainnet funds moved. Live Fee Service quotes: unavailable (no Circle Fee Service / adapter credentials in this environment).

What source-paid Circle Bridge Kit fees change

By default, CCTP Fast Transfer and Forwarding Service fees are taken from the amount minted on the destination chain. Arc's pay fees on the source chain tutorial states the alternative: pay those fees upfront on the source chain so the recipient receives the exact bridge amount.

The published Bridge Kit 1.15.2 README calls this receive-exact forwarding. Bridge Kit obtains a short-lived signed Fee Service quote, approves amount + feeTotal in source-chain USDC, and burns exactly amount through TokenMessengerWithFees. The destination mint is not reduced.

That is a different product promise than destination-deducted forwarding. Destination-paid mode is simpler for one wallet that owns both legs. Source-paid mode is for merchants, payroll, and custodial payouts that advertise "you receive N USDC" and cannot silently shave basis points at mint.

How to Transfer USDC with Circle Bridge Kit (2026)
Sibling how-to for kit.bridge basics, FAST vs SLOW, and useForwarder without source-paid fees.

npm and API facts Stablecoin Insider checked on 11 October 2026

Stablecoin Insider pulled registry metadata, the downloads API, and the 1.15.2 tarball the same afternoon this post was drafted. Numbers below are point-in-time, not projections.

FactValueSource
Package / version@circle-fin/bridge-kit 1.15.2npm registry (published 30 Sep 2026)
Weekly downloads (4–10 Oct 2026)17,447npm downloads API point range
Monthly downloads (10 Sep–9 Oct 2026)78,438npm downloads API last-month
Node engines>= 20.0.0package.json engines
Fee dependency@circle-fin/provider-fee-v1 ^0.3.2package.json dependencies
Receive-exact since1.14.0 (types @since)index.d.mts

Source: Bridge Kit README on jsDelivr, npm downloads API for 4–10 October 2026 (17,447 downloads), and last-month downloads (78,438 for 10 September–9 October 2026).

Naming note for engineers reading both surfaces: Arc App Kit tutorials call the pre-flight method kit.estimateBridge. The published npm class BridgeKit exposes kit.estimate (and kit.bridge). Stablecoin Insider's Node dry-run on 1.15.2 confirmed typeof BridgeKit.prototype.estimateBridge === 'undefined' while estimate, bridge, findSourceFeeProvider, and getSupportedChains are present. Code samples below use the npm method names.

The receive-exact API shape: feePayment, useForwarder, quote

Stablecoin Insider unpacked the 1.15.2 tarball and read package/index.d.mts. BridgeConfig.feePayment is optional 'source' | 'destination'. When feePayment is 'source', TypeScript overloads kit.estimate to return ReceiveExactEstimateResult (amountReceived, feeTotal, feeItems, totalDebit, quoteExpiry, quote). Arc's tutorial describes the same two-step flow: estimate with feePayment source, then bridge with the same params plus the quote.

import { BridgeKit } from '@circle-fin/bridge-kit'
import { createViemAdapterFromPrivateKey } from '@circle-fin/adapter-viem-v2'

const kit = new BridgeKit()
const adapter = createViemAdapterFromPrivateKey({
  privateKey: process.env.PRIVATE_KEY as `0x${string}`,
})

const params = {
  from: { adapter, chain: 'Ethereum' },
  to: {
    chain: 'Base',
    recipientAddress: '0x742d35Cc6634C0532925a3b844Bc454e4438f44e',
    useForwarder: true, // required with feePayment: 'source'
  },
  amount: '100',
  config: {
    transferSpeed: 'FAST',
    feePayment: 'source',
  },
} as const

const estimate = await kit.estimate(params)
// ReceiveExactEstimateResult: amountReceived, feeTotal, totalDebit, quoteExpiry, quote
const result = await kit.bridge({
  ...params,
  quote: estimate.quote, // opaque 0x-prefixed hex; do not decode or log
})

That pattern matches both the README receive-exact section and Arc's pay-fees-on-source tutorial (which names the estimate method estimateBridge). useForwarder: true is mandatory. Arc's docs say omitting it (or setting false) throws a validation error. The Forwarding Service tutorial explains why: the forwarder fetches the attestation and submits the destination mint, so the recipient does not need a destination signer.

What EstimateResult fields mean (and the Arc sample numbers)

When feePayment is source, the estimate is a ReceiveExactEstimateResult. Fields Stablecoin Insider verified in types:

  • amountReceived: exact USDC the destination recipient receives (equals amount)
  • feeTotal: total source-chain USDC fee (sum of feeItems)
  • totalDebit: amountReceived + feeTotal (what the source wallet must hold and approve)
  • fees: familiar breakdown (forwarder / provider)
  • feeItems: signed Fee Service line items (FORWARD, PRE_FINALITY) with args / argsHash
  • quoteExpiry: TIMESTAMP (expiresAt unix seconds) or BLOCK_NUMBER (expiresAtBlock + optional blockEstimatedAt)
  • quote: opaque signed hex; pass through unchanged

Arc's tutorial shows a worked Sepolia → Arc Testnet sample for 1.00 USDC. In that docs example, amountReceived is "1.0", feeTotal is "0.076527", totalDebit is "1.076527", with feeItems FORWARD "0.076397" and PRE_FINALITY "0.00013", and quoteExpiry mode BLOCK_NUMBER at expiresAtBlock 45947392. Those figures are documentation examples from Arc, not a live quote Stablecoin Insider fetched. Live Fee Service quotes were unavailable in this environment (no adapter private key / Fee Service credentials), so production UIs must call kit.estimate on the real route and render the returned totalDebit.

⚠️
Quote opacity and expiry: treat quote as sensitive raw bytes. Bridge Kit validates a supplied quote before and after approval and fails closed if it is invalid, mismatched, expired, or too close to expiry. It never silently replaces a caller-supplied quote. On failure, call estimate again and retry. Omitting quote lets the SDK fetch and refresh for you.

How to pay Circle Bridge Kit fees on the source chain (step by step)

Step 1: Install Bridge Kit 1.15.2+ and an EVM adapter

Receive-exact types are marked @since 1.14.0. Stablecoin Insider tested against 1.15.2. Node.js >= 20 is required.

npm install @circle-fin/bridge-kit@1.15.2 @circle-fin/adapter-viem-v2 viem
# engines: node >= 20.0.0

Step 2: Confirm the source chain supports source fees

A chain qualifies when it configures a TokenMessengerWithFees wrapper. List them:

const sourceFeeChains = kit.getSupportedChains({ sourceFeeSupported: true })
console.log(sourceFeeChains.map((c) => c.chain))
// Arc tutorial form: kit.getSupportedChains("bridge", { sourceFeeSupported: true })

BridgeKit also exposes findSourceFeeProvider on the prototype (confirmed in Stablecoin Insider's dry-run). Use it when you need the provider that can honor feePayment source for a given route.

Step 3: Estimate with feePayment source and useForwarder true

Build the same params object you will later pass to bridge. Set config.feePayment to 'source' and to.useForwarder to true. Call kit.estimate. Narrow on 'amountReceived' in estimate (or rely on the TypeScript overload) before you show totalDebit to the user.

Step 4: Bridge with the opaque quote (or omit it for SDK refresh)

Pass quote: estimate.quote into kit.bridge with identical from / to / amount / config. If the quote is near expiry, re-estimate. Prefer omitting quote only when you accept SDK-managed fetch and refresh; for checkout UIs, Stablecoin Insider prefers an explicit estimate → user confirm → bridge with that quote so the on-screen totalDebit matches the burn.

Step 5: Use SLOW on Standard Transfer-only sources

transferSpeed defaults to FAST. Arc's requirements section states that some source chains support only CCTP Standard Transfer, naming Avalanche, Polygon PoS, Sei, XDC, and their testnets. On those chains, keep feePayment source and set transferSpeed: 'SLOW'. Using FAST (or omitting transferSpeed) can fail with a Quote API error such as PRE_FINALITY_UNAVAILABLE (often HTTP 422).

await kit.bridge({
  from: { adapter, chain: 'Avalanche' },
  to: {
    recipientAddress: '0xRecipient',
    chain: 'Base',
    useForwarder: true,
  },
  amount: '1.00',
  config: {
    feePayment: 'source',
    transferSpeed: 'SLOW', // required on Standard-only sources
  },
})

For product trade-offs between Fast and Standard outside the source-fee path, see Stablecoin Insider's CCTP Fast vs Standard guide.

TokenMessengerWithFees vs manual depositForBurn

Under the hood, source-paid burns do not call plain TokenMessengerV2.depositForBurn with maxFee and minFinalityThreshold. Types document adapter action cctp.v2.depositForBurnWithFees on TokenMessengerWithFees: the wrapper collects fees via FeeManager against a signed QuoteClaim, then delegates to unmodified TokenMessengerV2. When hookData is present (GenericExecutor FORWARD path), the contract method is depositForBurnWithHookAndFees.

Unlike depositForBurn, TokenMessengerWithFees methods do not take maxFee or minFinalityThreshold. Fee and finality behavior are derived from the signed quote. That is why quote expiry races matter: once the quote is stale, the on-chain call is designed to reject rather than invent a new fee.

AttributeSource-paid Bridge KitManual CCTP depositForBurn + self-mint
Recipient amountExact amount (amountReceived == amount)You choose; mint is burn minus whatever you allow
Fee collectionUpfront USDC on source via Fee Service quoteUsually maxFee ceiling; destination or your relayer pays gas
Burn contractTokenMessengerWithFees (+ Fees methods)TokenMessengerV2.depositForBurn
maxFee / minFinalityThresholdOmitted; bound in signed quoteYou set both on the burn
Destination mintForwarding Service required (useForwarder)Your bot submits receiveMessage
Custom developer feeNot supported with feePayment sourceYour own skim if you wrap the burn
Attestation ownershipOrbit / Forwarding ServiceYou poll Iris and mint

Source: Bridge Kit 1.15.2 index.d.mts (depositForBurnWithFees remarks), README, Arc pay-fees-on-source, and Circle's CCTP overview / CCTP fees.

When source-paid fees beat destination-deducted forwarding

Stablecoin Insider's take is operational, not a fee forecast. Source-paid fees win when:

  • The recipient contract or user is owed an exact USDC amount (invoices, payroll, OTC settlement).
  • The destination wallet cannot hold spare USDC to cover a shaved mint.
  • Your UI already shows a locked receive amount and cannot re-quote after the user confirms.
  • You are bridging into Arc or another app where gas is USDC-denominated and the receiver must spend the full credited amount immediately.

Destination-deducted forwarding still wins for same-owner rebalances, when the source EOA is USDC-rich but gas-poor and you would rather shave the mint than acquire source gas plus feeTotal, and when you need config.customFee (Arc and the README both say custom fees are incompatible with feePayment source; the SDK throws by design).

Who this fails for (named downsides)

  • EOA gas on source. Source-paid mode spends source-chain native gas for approve + burn and also locks feeTotal in USDC. A recipient-funded gas model does not erase the source gas bill.
  • Quote expiry races. Quotes are short-lived (TIMESTAMP or BLOCK_NUMBER). Slow user confirmation UIs that cache quote across a long wait will fail closed. Re-estimate; do not patch the hex.
  • SLOW-only chains. Avalanche, Polygon PoS, Sei, and XDC (and testnets) need transferSpeed SLOW with source fees. FAST yields PRE_FINALITY_UNAVAILABLE-class Quote API errors.
  • No customFee. Integrators who skim 90/10 developer fees must stay on the destination fee path.
  • EVM-first receive-exact. README states the initial release supports EVM sources, EVM destinations, and source-chain USDC fee payment. Do not assume Solana source fees without re-reading the version you pin.
  • 429 / 503 Fee Service responses. README: on 429, caller-managed exponential backoff; 503 SERVICE_NOT_ENABLED means the source route is disabled and should not be retried.
  • Partial forwarder errors. Arc notes that if the burn confirms but the Forwarding Service returns no destination tx hash, the SDK can return an error-state BridgeResult that still includes the burn step (retryable). Inspect result.state and result.steps before re-burning.
💡
Stablecoin Insider's take: pay Circle Bridge Kit fees on the source chain when the product promise is receive-exact USDC. Treat the Fee Service quote like a signed FX ticket: opaque, short-lived, and fatal if edited. Keep destination-deducted forwarding for owner-operated rebalances, and keep manual CCTP when you need a custom burn wrapper or your own attestation worker. Estimate first, confirm totalDebit, pass the quote, and force SLOW on Avalanche / Polygon / Sei / XDC sources.

Where this sits next to aggregators and plain bridges

Source-paid Bridge Kit is still CCTP burn-and-mint, not a liquidity bridge and not a multi-bridge quote engine. For wrapped-asset routes and multi-bridge comparisons, use Stablecoin Insider's best crypto cross-chain bridges in 2026 and best cross-chain aggregators for 2026. When the asset or route leaves Circle's CCTP set, compare LI.FI. For a Solana-specific USDC walkthrough outside Bridge Kit fees, see how to bridge USDC from Ethereum to Solana.


If you still need the basic kit.bridge path without source fees, start with the sibling guide, then return here when the recipient must receive the exact amount.

Need the Bridge Kit one-liner before you add feePayment source? Read the sibling transfer guide.

How to Transfer USDC with Circle Bridge Kit
How to Choose CCTP Fast vs Standard Transfer
Decision guide for transferSpeed FAST vs SLOW before you lock source-paid fees.

FAQ

What does feePayment source do in Circle Bridge Kit?

It pays Fast Transfer and Forwarding Service fees upfront in source-chain USDC so the destination recipient receives the exact bridge amount. You must also set useForwarder: true.

Is the method called estimate or estimateBridge?

On npm @circle-fin/bridge-kit 1.15.2 the method is kit.estimate (BridgeKit.prototype.estimateBridge is undefined). Arc App Kit tutorials document kit.estimateBridge for the same two-step estimate-then-bridge flow.

What is TokenMessengerWithFees?

It is the CCTP wrapper that collects a signed Fee Service quote on the source chain, then delegates the burn to TokenMessengerV2. Bridge Kit uses depositForBurnWithFees / depositForBurnWithHookAndFees instead of plain depositForBurn with maxFee.

Why do Avalanche and Polygon need transferSpeed SLOW?

Arc's pay-fees-on-source docs list Avalanche, Polygon PoS, Sei, XDC, and their testnets as Standard Transfer-only sources. FAST (the default) can return PRE_FINALITY_UNAVAILABLE from the Quote API.

Can I combine customFee with source-paid fees?

No. Arc and the Bridge Kit README state custom fees are not supported with feePayment source; the SDK throws. Collect integrator fees only on the destination fee path.

What happens if the Fee Service quote expires?

Bridge Kit fails closed. It does not silently replace a caller-supplied quote. Call estimate again and pass the new quote. quoteExpiry is either a unix TIMESTAMP or a source-chain BLOCK_NUMBER.

Did Stablecoin Insider run a live Fee Service quote?

No. Live quotes were unavailable without Fee Service / adapter credentials. Arc's published sample (1.00 USDC with feeTotal 0.076527) is cited as a documentation example only.

When should I still use manual CCTP instead?

When you need a custom burn wrapper, your own attestation worker, unsupported routes, or gas accounting inside a larger contract flow. Circle still positions Bridge Kit for app integrations and raw CCTP for full backend control.


This content is provided for informational and educational purposes only and does not constitute financial, investment, legal, or tax advice; no material herein should be interpreted as a recommendation, endorsement, or solicitation to buy or sell.

Latest