Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions pages/_meta.json
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@
},
"core": "Core contracts",
"templates": "Templates",
"networks": "Networks",
"app_support": {
"type": "page",
"title": "App Support",
Expand Down
2 changes: 1 addition & 1 deletion pages/index.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ just want to understand how you can use the protocol today, we recommend you che
- Free: No protocol fees – runs exactly at gas cost
- Unstoppable: Non-upgradable contracts run as long as the underlying network
exists
- Multichain: Deployed on Ethereum, Optimism, Base, Zora, Polygon, Arbitrum + more
- Multichain: Deployed on Ethereum, Optimism, Base, Zora, Polygon, Arbitrum, Arc, Robinhood Chain + more
- Open source: All contracts are
[verified](https://etherscan.io/address/0x2ed6c4b5da6378c7897ac67ba9e43102feb694ee#code),
[audited](https://github.com/0xSplits/splits-contracts/blob/main/audit/0xSplits_A-1.pdf),
Expand Down
16 changes: 16 additions & 0 deletions pages/networks.mdx
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
---
description: "Network-specific notes for the Splits protocol, starting with Arc, where USDC is the native gas token."
---

# Networks

Most of the protocol behaves the same on every network. This section covers
networks where something about the chain changes how you use Splits.

| Network | Summary |
| :------ | :------ |
| [Arc](/networks/arc) | Splits V2.2 and the Warehouse on Arc, where USDC is the native gas token: what is deployed, SDK requirements, and how the two USDC token ids behave. |

Contract addresses for every network are listed in the address tables on each
contract page, such as [Warehouse](/core/warehouse) and
[SplitV2](/core/split-v2).
3 changes: 3 additions & 0 deletions pages/networks/_meta.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
{
"arc": "Arc"
}
154 changes: 154 additions & 0 deletions pages/networks/arc.mdx
Original file line number Diff line number Diff line change
@@ -0,0 +1,154 @@
---
description: "How Splits V2.2 and the Warehouse work on Arc, where USDC is the native gas token: what is deployed, SDK requirements, and how USDC token ids behave."
---

import { Callout } from 'nextra-theme-docs'

# Arc

Splits V2.2 (Push and Pull splits) and the Warehouse are deployed on Arc
mainnet (chain id 5042) and Arc testnet (chain id 5042002).

Arc-owned facts, such as how USDC works as the native token, fees, and RPC
behavior, live in [Arc's docs](https://docs.arc.io/arc/references/evm-differences).
This page only covers how Splits behaves there.

## What is deployed

Only the Warehouse and SplitV2 (Push and Pull splits) are deployed on Arc. Split
V1, V2.0 and V2.1 splits, Waterfall, Swapper, Oracle, Pass-Through, Vesting,
Liquid, Recoup and Diversifier are not.

Addresses are listed in the "Arc – 5042" sections of the
[Warehouse](/core/warehouse) and [SplitV2](/core/split-v2) pages. They are the
same on testnet, listed under "Arc Testnet – 5042002".

## SDK

Arc requires `@0xsplits/splits-sdk` 6.7.0 or later, and
`@0xsplits/splits-sdk-react` 4.6.0 or later if you use the React hooks.

On Arc the SDK supports only the [SplitV2 client](/sdk/splits-v2) and the
[Warehouse client](/sdk/warehouse). The data client, and the subgraph behind it,
do not cover Arc, so you do not need an API key for Arc. When `distribute` needs
a split's recipients and you have not passed them, the SDK recovers them from
onchain logs through your provider.

## USDC on Arc: two token ids

On Arc, USDC is the native token. Arc exposes it two ways, and both views read
the same balance (see [Arc's docs](https://docs.arc.io/arc/references/evm-differences)):

- **Native**, with 18 decimals.
- **ERC-20**, at `0x3600000000000000000000000000000000000000`, with 6 decimals.

Splits treats these as two different token ids, as the
[Warehouse](/core/warehouse) does for any two tokens:

- The native id is `0xeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee`, the same id the
Warehouse uses for ETH on other networks.
- The ERC-20 id is the `uint256` form of `0x3600000000000000000000000000000000000000`.

What follows from that:

- **The funding route does not matter.** After you fund a split with USDC by
either route (an ERC-20 transfer or a native value send), the split's balance
is visible under both ids: 100 USDC reads as `100000000` under the ERC-20 id
and `100000000000000000000` under the native id. Never add the two together.
- **`distribute` credits under the id you pass.** Recipients are credited under
that id, whichever route funded the split. `withdraw` is also per id, so a
recipient credited under both ids makes two withdrawals, and withdrawing under
an id with no credit reverts.
- **The Warehouse labels both ids the same**: the name is "Splits Wrapped USDC"
and the symbol is "splitsUSDC". Only the decimals differ.

How a distribution behaves depends on the id and on whether the split is Push or
Pull:

| Route | Token id | Decimals | Push behavior | Pull behavior | Failure modes |
| :---- | :------- | :------- | :------------ | :------------ | :------------ |
| ERC-20 | `0x3600…0000` | 6 | `distribute` pays recipients directly. A blocklisted recipient makes the whole call revert and nobody is paid; so does a blocklisted distributor when the distributor fee is above 0. Contract recipients that revert on receive are fine. | `distribute` credits the Warehouse and succeeds. Only a blocklisted recipient's own `withdraw` reverts. A contract that reverts on receive can still withdraw. | On an immutable Push split, a blocklisted recipient blocks distribution permanently. |
| Native | `0xeeee…eeee` | 18 | A recipient that cannot take native value (a blocklisted address, or a contract that reverts on receive) does not block the others. Its share is credited in the Warehouse under the native id. | `distribute` credits the Warehouse and succeeds. Only the affected recipient's own `withdraw` reverts. | A share credited to a recipient that cannot receive stays stuck until that recipient can receive again. A distributor that reverts on receiving a reward above 0 reverts the whole Push call. A recipient contract can also block a Push distribution by re-entering `distribute`; see the notes on the [SplitV2](/core/split-v2) page. |

Real transactions on Arc mainnet confirmed that funding by either route is
visible under both ids, that `distribute` credits only the id you pass, and that
`withdraw` pays out per id. They used four splits of 0.1 USDC each (Pull and
Push, funded by ERC-20 transfer and by native send). The failure modes in the
table come from read-only simulations (`eth_call` with state overrides, nothing
broadcast), using an address that is blocked on Arc testnet. The ERC-20 id is
served by an upgradeable contract controlled by Circle and Arc, so this behavior
can change.

### Recommendation

This is guidance derived from the behavior above, not a protocol rule.

- Default to the ERC-20 id. It matches Arc's guidance of using the 6-decimal
interface for transfers and accounting, and it works for any contract
recipient.
- On the ERC-20 id, use a Pull split when recipients are many, untrusted, or
could be blocklisted. Use Push only for a few known recipients and an owner who
can remove one. Never use an immutable Push split if a recipient could be
blocklisted.
- Pick one id per split and stay with it. When you work on a split you did not
create, check both ids.
- Use the native id only if you specifically need Push distribution to keep
working when one recipient cannot receive, and you accept the stuck credit
described above.

<Callout type="warning" emoji="⚠️">
**The zero address is not USDC in the SDK.** `distribute` and
`WarehouseClient.withdraw` treat a zero `tokenAddress` as the native id, but
`getSplitBalance` does not: it passes the address through as given. Pass the
ERC-20 address explicitly in all three.
</Callout>

## Distributing and withdrawing

`distribute` needs the split's full configuration, and a mismatch reverts with
`InvalidSplit()`. The configuration is emitted in the `SplitUpdated` event, at
creation and on every update. The split's `updateBlockNumber()` returns the
block of the latest one, so you can read that single block instead of scanning
history. In the SDK, you can skip recovery by passing `splitFields` (the
`recipients` and `distributorFeePercent`) to `distribute`.

The distribution incentive goes to the distributor address passed to
`distribute`, which the SDK defaults to the connected wallet. On a Pull split it
is credited to that address's Warehouse balance, so it needs a `withdraw` too.

`distribute` does not pay out everything. It keeps 1 unit in the split, a Pull
split also keeps 1 unit in its own Warehouse balance, and rounding remainders
stay behind. The Warehouse's `withdraw(owner, token)` pays the balance minus 1:
it pays 0 at a balance of 1 and reverts at a balance of 0. The unit that stays in
a recipient's Warehouse balance is included in their next withdrawal. One unit
is 0.000001 USDC under the ERC-20 id, so smaller amounts can only move through
the native id, and 1 wei under the native id.

For example, a Pull split with three recipients (50/30/20), funded with 0.1 USDC
and distributed under the ERC-20 id, credited 49,999, 29,999 and 19,999 units.
After their withdrawals the recipients had received 49,998, 29,998 and 19,998
units, and 6 units of the 100,000 were left behind: 1 in the split, 2 in the
split's Warehouse balance, and 1 in each recipient's Warehouse balance.

## Network notes

| Network | RPC |
| :------ | :-- |
| Arc – 5042 | `https://rpc.mainnet.arc.io` |
| Arc Testnet – 5042002 | `https://rpc.testnet.arc.io` |

- **`eth_getLogs` range.** On the public RPCs for both networks, a range of
10,000 blocks works and 10,001 fails with error `-32012` ("requested range too
large"). The public RPCs also rate-limit requests (error `-32005`). Use
`updateBlockNumber()` to avoid wide log scans.
- **Fees and logs.** Arc sets a minimum fee per gas. A USDC move through the
ERC-20 interface emits two `Transfer` logs, and a native move emits one. Both
are defined by Arc, not Splits. See
[Arc's docs](https://docs.arc.io/arc/references/evm-differences) for the
current fee requirements, and
[USDC system events](https://docs.arc.io/arc/references/usdc-system-events)
before you count `Transfer` logs.
- **Testing.** A local fork does not reproduce the behavior of the upgradeable
ERC-20 contract at `0x3600…0000`, so test with `eth_call` against the Arc RPC.

Verified against @0xsplits/splits-sdk 6.7.0 and Splits V2.2 on 2026-10-23.
5 changes: 5 additions & 0 deletions public/llms.txt
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,11 @@ The protocol makes it easy to split onchain payments among multiple recipients.
- [Liquid Split](https://splits.org/protocol/docs/templates/liquid.md): Mutable split governed by NFT ownership
- [Diversifier](https://splits.org/protocol/docs/templates/diversifier.md): Automatically swap and diversify incoming tokens

## Networks

- [Networks](https://splits.org/protocol/docs/networks.md): Network-specific notes for the protocol
- [Arc](https://splits.org/protocol/docs/networks/arc.md): Splits V2.2 and the Warehouse on Arc, where USDC is the native gas token: deployed contracts, SDK requirements, and USDC token id behavior

## Optional

- [GitHub](https://github.com/0xSplits): Source code for all contracts and SDKs
Expand Down
Loading