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

# Bridging

> Bridge USDC across chains using Circle's CCTP protocol, directly from Product Accounts.

export const GithubCodeBlock = ({typescript, python}) => {
  const [typescriptCode, setTypescriptCode] = useState("");
  const [pythonCode, setPythonCode] = useState("");
  function removeWhitespace(strings, x) {
    return strings.map(str => {
      let count = 0;
      let i = 0;
      while (i < str.length && count < x && str[i] === " ") {
        count++;
        i++;
      }
      return str.slice(i);
    });
  }
  function cropToSnippet({text, from, to}) {
    const lines = text.split("\n");
    let result = [];
    let isCollecting = false;
    for (const line of lines) {
      if (line.trim() === from) {
        isCollecting = true;
        continue;
      }
      if (line.trim() === to) {
        break;
      }
      if (isCollecting) {
        result.push(line);
      }
    }
    const whitespaceToDelete = result[0].length - result[0].trimStart().length;
    result = removeWhitespace(result, whitespaceToDelete);
    return result.join("\n");
  }
  function removeSnippetComments(code) {
    return code.replace(/(\/\/|#) SNIPPET (START|END) \d+(\n|$)/g, "");
  }
  useEffect(() => {
    if (!typescript) return;
    fetch(typescript.url).then(response => response.text()).then(text => {
      let code = text;
      if (typescript.snippetNumber) {
        code = cropToSnippet({
          text,
          from: `// SNIPPET START ${typescript.snippetNumber}`,
          to: `// SNIPPET END ${typescript.snippetNumber}`
        });
      } else {
        code = removeSnippetComments(code);
      }
      setTypescriptCode(code);
    }).catch(error => {
      console.error("Error loading file:", error);
    });
  }, [typescript]);
  useEffect(() => {
    if (!python) return;
    fetch(python.url).then(response => response.text()).then(text => {
      let code = text;
      if (python.snippetNumber) {
        code = cropToSnippet({
          text,
          from: `# SNIPPET START ${python.snippetNumber}`,
          to: `# SNIPPET END ${python.snippetNumber}`
        });
      } else {
        code = removeSnippetComments(code);
      }
      setPythonCode(code);
    }).catch(error => {
      console.error("Error loading file:", error);
    });
  }, [python]);
  if (!python && !typescript) return null;
  if (!python) {
    return <CodeBlock language="typescript" filename={typescript.name} expandable={typescript?.numOfLinesExpandable ? "true" : null} lines="true" icon="https://upload.wikimedia.org/wikipedia/commons/f/f5/Typescript.svg" code={typescriptCode} children={typescriptCode || !typescript?.numOfLinesExpandable || <div style={{
      whiteSpace: "pre-wrap"
    }}>
        {Array(typescript?.numOfLinesExpandable).fill("-").map(x => x).join("\n")}
      </div>} />;
  }
  if (!typescript) {
    return <CodeBlock language="python" filename={python.name} expandable={python?.numOfLinesExpandable ? "true" : null} lines="true" icon="https://upload.wikimedia.org/wikipedia/commons/c/c3/Python-logo-notext.svg" code={pythonCode} children={pythonCode || !python?.numOfLinesExpandable || <div style={{
      whiteSpace: "pre-wrap"
    }}>
        {Array(python?.numOfLinesExpandable).fill("-").map(x => x).join("\n")}
      </div>} />;
  }
  return <CodeGroup>
  <CodeBlock language="typescript" filename={typescript.name} expandable={typescript?.numOfLinesExpandable ? "true" : null} lines="true" icon="https://upload.wikimedia.org/wikipedia/commons/f/f5/Typescript.svg" code={typescriptCode} children={typescriptCode || !typescript?.numOfLinesExpandable || <div style={{
    whiteSpace: "pre-wrap"
  }}>
          {Array(typescript?.numOfLinesExpandable).fill("-").map(x => x).join("\n")}
        </div>} />
  <CodeBlock language="python" filename={python.name} expandable={python?.numOfLinesExpandable ? "true" : null} lines="true" icon="https://upload.wikimedia.org/wikipedia/commons/c/c3/Python-logo-notext.svg" code={pythonCode} children={pythonCode || !python?.numOfLinesExpandable || <div style={{
    whiteSpace: "pre-wrap"
  }}>
          {Array(python?.numOfLinesExpandable).fill("-").map(x => x).join("\n")}
        </div>} />
</CodeGroup>;
};

## What It Does

Move USDC between chains without leaving your Product Account. Compass integrates Circle's Cross-Chain Transfer Protocol (CCTP) V2, enabling secure, native USDC transfers between Ethereum, Arbitrum, and Base.

Unlike wrapped token bridges, CCTP burns USDC on the source chain and mints native USDC on the destination. No liquidity pools, no slippage, no wrapped tokens.

## Supported Chains

| Chain    | CCTP Domain |
| -------- | ----------- |
| Ethereum | 0           |
| Arbitrum | 3           |
| Base     | 6           |

## Transfer Modes

CCTP V2 offers two transfer speeds:

| Mode     | Speed        | Fee     |
| -------- | ------------ | ------- |
| Standard | \~15-19 min  | Free    |
| Fast     | \~30 seconds | \~0.01% |

Fast mode uses confirmed finality for near-instant transfers. The fee is automatically calculated based on Circle's current rates.

## How It Works

Bridging happens in two steps: burn on the source chain, then mint on the destination chain.

### Step 1: Burn USDC

Call the [burn endpoint](https://docs.compasslabs.ai/v2/api-reference/bridge/initiate-usdc-bridging) to get a transaction that burns USDC from the Product Account on the source chain.

```bash theme={"system"}
POST /v2/cctp/burn
{
  "owner": "0x...",
  "chain": "ethereum",
  "amount": 1000,
  "destination_chain": "base",
  "destination_owner": "0x...",
  "transfer_mode": "fast"
}
```

The response includes:

* A `transaction` to sign and broadcast (or `eip_712` typed data if using gas sponsorship)
* A `bridge_id` to track the transfer

### Step 2: Mint USDC

After the burn transaction confirms, Circle's attestation service validates the transfer. Call the [mint endpoint](https://docs.compasslabs.ai/v2/api-reference/bridge/complete-usdc-bridging) with the `bridge_id` and `burn_tx_hash` to get the mint transaction.

```bash theme={"system"}
POST /v2/cctp/mint
{
  "bridge_id": "...",
  "burn_tx_hash": "0x...",
  "gas_sponsorship": false
}
```

**Response codes:**

* **200 OK**: Attestation ready, mint transaction included
* **202 Accepted**: Attestation pending, poll again shortly
* **404 Not Found**: Bridge ID not found

For standard transfers, attestation takes \~15-19 minutes. For fast transfers, it's typically under 30 seconds.

## Implementation Example

This example demonstrates bridging 1 USDC from Base to Arbitrum without gas sponsorship.

> **Note**
>
> * Full source code is available in our public GitHub repository: [CompassLabs/api\_usecases – cctp\_bridging](https://github.com/CompassLabs/api_usecases/tree/main/v2/cctp_bridging)

### Prerequisites

<Steps>
  <Step title="Install Dependencies">
    Install the required packages.

    <GithubCodeBlock
      typescript={{
    name: "package.json",
    url: "https://raw.githubusercontent.com/CompassLabs/api_usecases/main/v2/cctp_bridging/typescript/package.json",
  }}
      python={{
    name: "pyproject.toml",
    url: "https://raw.githubusercontent.com/CompassLabs/api_usecases/main/v2/cctp_bridging/python/pyproject.toml",
  }}
    />
  </Step>

  <Step title="Set Environment Variables">
    Create a `.env` file:

    <GithubCodeBlock
      typescript={{
    name: ".env.example",
    url: "https://raw.githubusercontent.com/CompassLabs/api_usecases/main/v2/cctp_bridging/typescript/.env.example",
  }}
      python={{
    name: ".env.example",
    url: "https://raw.githubusercontent.com/CompassLabs/api_usecases/main/v2/cctp_bridging/python/.env.example",
  }}
    />
  </Step>
</Steps>

### Implementation

<Steps>
  <Step title="Import Libraries & Initialize SDK">
    <GithubCodeBlock
      typescript={{
    name: "index.ts",
    url: "https://raw.githubusercontent.com/CompassLabs/api_usecases/main/v2/cctp_bridging/typescript/src/index.ts",
    snippetNumber: 1,
  }}
      python={{
    name: "main.py",
    url: "https://raw.githubusercontent.com/CompassLabs/api_usecases/main/v2/cctp_bridging/python/main.py",
    snippetNumber: 1,
  }}
    />

    <GithubCodeBlock
      typescript={{
    name: "index.ts",
    url: "https://raw.githubusercontent.com/CompassLabs/api_usecases/main/v2/cctp_bridging/typescript/src/index.ts",
    snippetNumber: 2,
  }}
      python={{
    name: "main.py",
    url: "https://raw.githubusercontent.com/CompassLabs/api_usecases/main/v2/cctp_bridging/python/main.py",
    snippetNumber: 2,
  }}
    />
  </Step>

  <Step title="Burn USDC on Source Chain">
    Request and broadcast the burn transaction on Base.

    <GithubCodeBlock
      typescript={{
    name: "index.ts",
    url: "https://raw.githubusercontent.com/CompassLabs/api_usecases/main/v2/cctp_bridging/typescript/src/index.ts",
    snippetNumber: 3,
  }}
      python={{
    name: "main.py",
    url: "https://raw.githubusercontent.com/CompassLabs/api_usecases/main/v2/cctp_bridging/python/main.py",
    snippetNumber: 3,
  }}
    />

    <GithubCodeBlock
      typescript={{
    name: "index.ts",
    url: "https://raw.githubusercontent.com/CompassLabs/api_usecases/main/v2/cctp_bridging/typescript/src/index.ts",
    snippetNumber: 4,
  }}
      python={{
    name: "main.py",
    url: "https://raw.githubusercontent.com/CompassLabs/api_usecases/main/v2/cctp_bridging/python/main.py",
    snippetNumber: 4,
  }}
    />
  </Step>

  <Step title="Wait for Circle Attestation">
    Poll the mint endpoint until Circle's attestation is ready.

    <GithubCodeBlock
      typescript={{
    name: "index.ts",
    url: "https://raw.githubusercontent.com/CompassLabs/api_usecases/main/v2/cctp_bridging/typescript/src/index.ts",
    snippetNumber: 5,
  }}
      python={{
    name: "main.py",
    url: "https://raw.githubusercontent.com/CompassLabs/api_usecases/main/v2/cctp_bridging/python/main.py",
    snippetNumber: 5,
  }}
    />
  </Step>

  <Step title="Mint USDC on Destination Chain">
    Execute the mint transaction on Arbitrum.

    <GithubCodeBlock
      typescript={{
    name: "index.ts",
    url: "https://raw.githubusercontent.com/CompassLabs/api_usecases/main/v2/cctp_bridging/typescript/src/index.ts",
    snippetNumber: 6,
  }}
      python={{
    name: "main.py",
    url: "https://raw.githubusercontent.com/CompassLabs/api_usecases/main/v2/cctp_bridging/python/main.py",
    snippetNumber: 6,
  }}
    />
  </Step>
</Steps>

## Gas Sponsorship

Both burn and mint transactions support gas sponsorship. Set `gas_sponsorship=true` to receive EIP-712 typed data instead of an unsigned transaction.

The owner signs the typed data off-chain, then you submit the signature to [/gas\_sponsorship/prepare](https://docs.compasslabs.ai/v2/api-reference/gas-sponsorship/prepare-gas-sponsored-transaction) to get a transaction that the sender broadcasts.

## Prerequisites

Before bridging:

1. The owner must have a [Product Account](/v2/Products/Accounts) on both chains
2. USDC must be in the Product Account on the source chain (use [/earn/transfer](https://docs.compasslabs.ai/v2/api-reference/earn/transfer-tokens-tofrom-account) to deposit)

## Use Cases

**Cross-chain yield optimization:** Move USDC to the chain with the best yield opportunities, then deposit into vaults or Aave markets.

**Multi-chain treasury management:** Consolidate funds across chains or distribute to different chains based on operational needs.

**User onboarding:** Let users bridge funds from any supported chain to where your application operates.

## Next Steps

<CardGroup cols={3}>
  <Card title="Product Accounts" icon="wallet" href="/v2/Products/Accounts">
    Create Product Accounts required for bridging on both chains.
  </Card>

  <Card title="Earn" icon="chart-line" href="/v2/Products/Earn">
    Deploy bridged USDC into variable yield opportunities.
  </Card>

  <Card title="Gas Sponsorship" icon="gas-pump" href="/v2/Products/gas-sponsorship">
    Sponsor gas for bridge transactions to improve user experience.
  </Card>
</CardGroup>
