Splits

Splits

Begin by importing SplitsClient into your app.

import { SplitsClient } from '@0xsplits/splits-sdk'
 
const splitsClient = new SplitsClient({
  chainId,
  publicClient, // viem public client (optional, required if using any of the contract functions)
  walletClient, // viem wallet client (optional, required if using any contract write functions. must have an account already attached)
  includeEnsNames, // boolean, defaults to false. If true, will return ens names for any split recipient or controller (only for mainnet)
  // If you want to return ens names on chains other than mainnet, you can pass in a mainnet public client
  // here. Be aware though that the ens name may not necessarily resolve to the proper address on the
  // other chain for non EOAs (e.g. Gnosis Safe's)
  ensPublicClient, // viem public client (optional)
})

Now you're ready to use any of the functions. All Arguments and Responses for these functions are objects. This will make it easier for us to release updates to the SDK without breaking existing implementations.

The SDK comprises 3 different types of functions: Subgraph Reads, SplitMain Writes, and SplitMain Reads.

Subgraph Reads

These functions make it easier to query the subgraph.

getSplitMetadata

Returns all metadata for a given splitAddress.

Usage

const args = {
  splitAddress: '0xF8843981e7846945960f53243cA2Fd42a579f719',
}
 
const response = await splitsClient.getSplitMetadata(args)

Arguments

{
  splitAddress: string
}

Response

{
  type: 'Split'
  address: string
  controller: {
    address: string
    ensName?: string
  } | null
  newPotentialController: {
    address: string
    ensName?: string
  } | null
  distributorFeePercent: number
  recipients: {
    percentAllocation: number
    recipient: {
      address: string
      ensName?: string
    }
  }[]
  createdBlock: number
}

getRelatedSplits

Returns all Splits related to a given address.

Usage

const args = {
  address: '0xEc8Bfc8637247cEe680444BA1E25fA5e151Ba342',
}
 
const response = await splitsClient.getRelatedSplits(args)

Arguments

{
  address: string
}

Response

{
  receivingFrom: { # Splits in which the address is a Recipient
    address: string
    controller: {
      address: string
      ensName?: string
    } | null
    newPotentialController: {
      address: string
      ensName?: string
    } | null
    distributorFeePercent: number
    recipients: {
      percentAllocation: number
      recipient: {
        address: string
        ensName?: string
      }
    }[]
    createdBlock: number
  }[]
  controlling: { # Splits of which the address is the Controller
    address: string
    controller: {
      address: string
      ensName?: string
    } | null
    newPotentialController: {
      address: string
      ensName?: string
    } | null
    distributorFeePercent: number
    recipients: {
      percentAllocation: number
      recipient: {
        address: string
        ensName?: string
      }
    }[]
    createdBlock: number
  }[]
  pendingControl: { # Splits of which the address has been given but not yet accepted Control
    address: string
    controller: {
      address: string
      ensName?: string
    } | null
    newPotentialController: {
      address: string
      ensName?: string
    } | null
    distributorFeePercent: number
    recipients: {
      percentAllocation: number
      recipient: {
        address: string
        ensName?: string
      }
    }[]
    createdBlock: number
  }[]
}

getSplitEarnings

Returns token balances for a given splitAddress.

NOTE: Fetching active balances optionally takes an erc20TokenList argument. If the rpc url is not Alchemy or Infura, that token list is required. If the token list is passed in, balances will only be fetched for tokens in that list (as well as the native token and any previously distributed tokens). Otherwise, all erc20 transfers to the split address will be reviewed with a getLogs request, but only Alchemy and Infura support a large enough getLogs request. You can disable fetching active balances by passing in includeActiveBalances: false.

Usage

const args = {
  splitAddress: '0xF8843981e7846945960f53243cA2Fd42a579f719',
}
 
const response = await splitsClient.getSplitEarnings(args)

Arguments

{
  splitAddress: string
  includeActiveBalances?: boolean # defaults to true
  erc20TokenList?: string[]
}

Response

{
  activeBalances?: { # tokens that are waiting to be distributed
    [token: string]: bigint
  }
  distributed: { # tokens that have already been distributed
    [token: string]: bigint
  }
}

getFormattedSplitEarnings

Returns the same data as getSplitEarnings, but includes token data as well as a formatted amount.

Usage

const args = {
  splitAddress: '0xF8843981e7846945960f53243cA2Fd42a579f719',
}
 
const response = await splitsClient.getFormattedSplitEarnings(args)

Arguments

{
  splitAddress: string
  includeActiveBalances?: boolean # defaults to true
  erc20TokenList?: string[]
}

Response

{
  activeBalances?: { # tokens that are waiting to be distributed
    [token: string]: {
      symbol: string
      decimals: number
      rawAmount: bigint
      formattedAmount: string
    }
  }
  distributed: { # tokens that have already been distributed
    [token: string]: {
      symbol: string
      decimals: number
      rawAmount: bigint
      formattedAmount: string
    }
  }
}

getUserEarnings

Returns token balances for a given userAddress.

Usage

const args = {
  userAddress: '0xEc8Bfc8637247cEe680444BA1E25fA5e151Ba342',
}
 
const response = await splitsClient.getUserEarnings(args)

Arguments

{
  userAddress: string
}

Response

{
  withdrawn: { # tokens the user has already withdrawn from the protocol
    [token: string]: bigint
  }
  activeBalances: { # tokens that have been distributed but not yet withdrawn
    [token: string]: bigint
  }
}

getFormattedUserEarnings

Returns the same data as getUserEarnings, but includes token data as well as a formatted amount.

Usage

const args = {
  userAddress: '0xEc8Bfc8637247cEe680444BA1E25fA5e151Ba342',
}
 
const response = await splitsClient.getFormattedUserEarnings(args)

Arguments

{
  userAddress: string
}

Response

{
  withdrawn: { # tokens the user has already withdrawn from the protocol
    [token: string]: {
      symbol: string
      decimals: number
      rawAmount: bigint
      formattedAmount: string
    }
  }
  activeBalances: { # tokens that have been distributed but not yet withdrawn
    [token: string]: {
      symbol: string
      decimals: number
      rawAmount: bigint
      formattedAmount: string
    }
  }
}

getUserEarningsByContract

Returns token balances for a given userAddress, separated out by each 0xSplits contract the user has received from. Can optionally pass in a list of contractAddresses to filter results to just a set of contracts.

Usage

const args = {
  userAddress: '0xEc8Bfc8637247cEe680444BA1E25fA5e151Ba342',
}
 
const response = await splitsClient.getUserEarningsByContract(args)

Arguments

{
  userAddress: string
  contractAddresses?: string[]
}

Response

{
  withdrawn: { # tokens the user has already withdrawn from the protocol
    [token: string]: bigint
  }
  activeBalances: { # tokens that have been distributed but not yet withdrawn
    [token: string]: bigint
  }
  earningsByContract: { # Earnings broken out by each 0xSplits contract the user has received from
    [contractAddress: string]: {
      withdrawn: {
        [token: string]: bigint
      }
      activeBalances: {
        [token: string]: bigint
      }
    }
  }
}

getFormattedUserEarningsByContract

Returns the same data as getUserEarningsByContract, but includes token data as well as a formatted amount.

Usage

const args = {
  userAddress: '0xEc8Bfc8637247cEe680444BA1E25fA5e151Ba342',
}
 
const response = await splitsClient.getFormattedUserEarningsByContract(args)

Arguments

{
  userAddress: string
  contractAddresses?: string[]
}

Response

{
  withdrawn: { # tokens the user has already withdrawn from the protocol
    [token: string]: {
      symbol: string
      decimals: number
      rawAmount: bigint
      formattedAmount: string
    }
  }
  activeBalances: { # tokens that have been distributed but not yet withdrawn
    [token: string]: {
      symbol: string
      decimals: number
      rawAmount: bigint
      formattedAmount: string
    }
  }
  earningsByContract: { # Earnings broken out by each 0xSplits contract the user has received from
    [contractAddress: string]: {
      withdrawn: {
        [token: string]: {
          symbol: string
          decimals: number
          rawAmount: bigint
          formattedAmount: string
        }
      }
      activeBalances: {
        [token: string]: {
          symbol: string
          decimals: number
          rawAmount: bigint
          formattedAmount: string
        }
      }
    }
  }
}

SplitMain Writes

createSplit

Creates a new Split contract.

Usage

const args = {
  recipients: [
    {
      address: "0x442C01498ED8205bFD9aaB6B8cc5C810Ed070C8f",
      percentAllocation: 50.0000
    },
    {
      address: "0xc3313847E2c4A506893999f9d53d07cDa961a675",
      percentAllocation: 50.0000
    }
  ],
  distributorFeePercent: 1.0000,
  controller: "0xEc8Bfc8637247cEe680444BA1E25fA5e151Ba342"
}
 
const response = await splitsClient.createSplit(args)

Arguments

{
  recipients: {
    address: string
    percentAllocation: number # >0 and <100 and up to 4 decimals
  }[]
  distributorFeePercent: number # <10 and up to 4 decimals
  controller?: string # defaults to AddressZero for an immutable split
}

Response

{
  splitAddress: string
  event: Log # CreateSplit emitted on SplitMain
}

updateSplit

Updates an existing mutable Split contract. Only callable by the controller of splitAddress.

Usage

const args = {
  splitAddress: "0x047ED5b8E8a7eDBd92FAF61f3117cAFE8c529ABb",
  recipients: [
    {
      address: "0x442C01498ED8205bFD9aaB6B8cc5C810Ed070C8f",
      percentAllocation: 50.0000
    },
    {
      address: "0xc3313847E2c4A506893999f9d53d07cDa961a675",
      percentAllocation: 50.0000
    },
  ],
  distributorFeePercent: 1.0000
}
 
const response = await splitsClient.updateSplit(args)

Arguments

{
  splitAddress: string
  recipients: {
    address: string
    percentAllocation: number
  }[]
  distributorFeePercent: number
}

Response

{
  event: Log # UpdateSplit emitted on SplitMain
}

distributeToken

Distributes the balance of token for splitAddress, and sends the distributor fee to distributorAddress.

Usage

const args = {
  splitAddress: "0xd9137B84f56D61Bb961082DD9Eb21bE3D7B14cB9",
  token: "0x64d91f12ece7362f91a6f8e7940cd55f05060b92",
  distributorAddress: "0x2fa128274cfcf47afd4dc03cd3f2a59af09b6a72"
}
 
const response = await splitsClient.distributeToken(args)

Arguments

{
  splitAddress: string
  token: string
  distributorAddress?: string # defaults to signer
}

Response

{
  event: Log # DistributeETH or DistributeERC20 emitted on SplitMain
}

updateSplitAndDistributeToken

This combines updateSplit and distributeToken into one transaction. Only callable by the controller of splitAddress.

Usage

const args = {
  splitAddress: "0xd9137B84f56D61Bb961082DD9Eb21bE3D7B14cB9",
  token: "0x64d91f12ece7362f91a6f8e7940cd55f05060b92",
  recipients: [
    {
      address: "0x442C01498ED8205bFD9aaB6B8cc5C810Ed070C8f",
      percentAllocation: 50.0000
    },
    {
      address: "0xc3313847E2c4A506893999f9d53d07cDa961a675",
      percentAllocation: 50.0000
    },
  ],
  distributorFeePercent: 1.0000,
  distributorAddress: "0x2fa128274cfcf47afd4dc03cd3f2a59af09b6a72"
}
 
const response = await splitsClient.updateSplitAndDistributeToken(args)

Arguments

{
  splitAddress: string
  token: string
  recipients: {
    address: string
    percentAllocation: number
  }[]
  distributorFeePercent: number
  distributorAddress?: string # defaults to signer
}

Response

{
  event: Log # DistributeETH or DistributeERC20 emitted on SplitMain
}

withdrawFunds

Withdraws tokens for a given address.

Usage

const args = {
  address: "0x357138F2690B82f29dF32bf2a3d0e6d4CC4D63C1",
  tokens: [
    "0x64d91f12ece7362f91a6f8e7940cd55f05060b92",
    "0x0000000000000000000000000000000000000000"
  ]
}
 
const response = await splitsClient.withdrawFunds(args)

Arguments

{
  address: string
  tokens: string[]
}

Response

{
  event: Log # Withdrawal emitted on SplitMain
}

initiateControlTransfer

Transfers control of splitAddress to newController. Only callable by the controller of splitAddress.

Usage

const args = {
  splitAddress: "0xd9137B84f56D61Bb961082DD9Eb21bE3D7B14cB9",
  newController: "0x2fa128274cfcf47afd4dc03cd3f2a59af09b6a72"
}
 
const response = await splitsClient.initiateControlTransfer(args)

Arguments

{
  splitAddress: string
  newController: string
}

Response

{
  event: Log # InitiateControlTransfer emitted on SplitMain
}

acceptControlTransfer

Accepts control of splitAddress. Only callable by the new controller of splitAddress.

Usage

const args = {
  splitAddress: '0xd9137B84f56D61Bb961082DD9Eb21bE3D7B14cB9',
}
 
const response = await splitsClient.acceptControlTransfer(args)

Arguments

{
  splitAddress: string
}

Response

{
  event: Log # ControlTransfer emitted on SplitMain
}

cancelControlTransfer

Cancels the transfer of splitAddress. Only callable by the controller of splitAddress.

Usage

const args = {
  splitAddress: '0xd9137B84f56D61Bb961082DD9Eb21bE3D7B14cB9',
}
 
const response = await splitsClient.cancelControlTransfer(args)

Arguments

{
  splitAddress: string
}

Response

{
  event: Log # CancelControlTransfer emitted on SplitMain
}

makeSplitImmutable

Makes splitAddress immutable. Only callable by the controller of splitAddress.

Usage

const args = {
  splitAddress: '0xd9137B84f56D61Bb961082DD9Eb21bE3D7B14cB9',
}
 
const response = await splitsClient.makeSplitImmutable(args)

Arguments

{
  splitAddress: string
}

Response

{
  event: Log # ControlTransfer emitted on SplitMain
}

batchDistributeAndWithdraw

Performs a multicall transaction, will distribute multiple tokens on a split and withdraw for any given addresses.

Usage

const args = {
  splitAddress: '0xd9137B84f56D61Bb961082DD9Eb21bE3D7B14cB9',
  tokens: [
    '0x0000000000000000000000000000000000000000',
    '0xc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2',
  ],
  recipientAddresses: [
    '0x39883c6e81e273f381bffe5a8c26c3a866ff57ca',
    '0xeb78334dfde3afbc2b904f06153f59cc80ee07fa',
    '0x6b48ad78a26604b9e158a07ec4abb2981842e168',
    '0xc3313847E2c4A506893999f9d53d07cDa961a675',
  ],
  distributorAddress: '0x2fa128274cfcf47afd4dc03cd3f2a59af09b6a72',
}
 
const response = await splitsClient.batchDistributeAndWithdraw(args)

Arguments

{
  splitAddress: string
  tokens: string[]
  recipientAddresses: string[]
  distributorAddress?: string # defaults to signer
}

Response

{
  events: Log[]
}

batchDistributeAndWithdrawForAll

Performs a multicall transaction, will distribute multiple tokens on a split and withdraw for all recipients.

Usage

const args = {
  splitAddress: '0xd9137B84f56D61Bb961082DD9Eb21bE3D7B14cB9',
  tokens: [
    '0x0000000000000000000000000000000000000000',
    '0xc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2',
  ],
  distributorAddress: '0x2fa128274cfcf47afd4dc03cd3f2a59af09b6a72',
}
 
const response = await splitsClient.batchDistributeAndWithdrawForAll(args)

Arguments

{
  splitAddress: string
  tokens: string[]
  distributorAddress?: string # defaults to signer
}

Response

{
  events: Log[]
}

Gas Estimation

The client has a gas estimation feature that can be used with any of the above write functions. Just call the function off of the estimateGas property. Estimating the gas for the create split function would look like:

const args = {
  recipients: [
    {
      address: "0x442C01498ED8205bFD9aaB6B8cc5C810Ed070C8f",
      percentAllocation: 50.0000
    },
    {
      address: "0xc3313847E2c4A506893999f9d53d07cDa961a675",
      percentAllocation: 50.0000
    }
  ],
  distributorFeePercent: 1.0000,
  controller: "0xEc8Bfc8637247cEe680444BA1E25fA5e151Ba342"
}
 
const gasEstimate = await splitsClient.estimateGas.createSplit(args)

CallData

The client has a call data feature that can be used with any of the above write functions. Just call the function off of the callData property. Generating call data for the create split function would look like:

const args = {
  recipients: [
    {
      address: "0x442C01498ED8205bFD9aaB6B8cc5C810Ed070C8f",
      percentAllocation: 50.0000
    },
    {
      address: "0xc3313847E2c4A506893999f9d53d07cDa961a675",
      percentAllocation: 50.0000
    }
  ],
  distributorFeePercent: 1.0000,
  controller: "0xEc8Bfc8637247cEe680444BA1E25fA5e151Ba342"
}
 
const callData = await splitsClient.callData.createSplit(args)

SplitMain Reads

getSplitBalance

Returns the balance for a given splitAddress and token. If no token is provided, returns the ETH balance.

Usage

const args = {
  splitAddress: '0x2ed6c4B5dA6378c7897AC67Ba9e43102Feb694EE',
  token: '0x64d91f12ece7362f91a6f8e7940cd55f05060b92',
}
 
const response = await splitsClient.getSplitBalance(args)

Arguments

{
  splitAddress: string
  token?: string # defaults to AddressZero
}

Response

{
  balance: bigint
}

predictImmutableSplitAddress

Returns the determinisic address (using CREATE2 (opens in a new tab)) at which an immutable Split will be deployed for given recipients and distributorFeePercent. Also returns whether or not this split has already been created.

Usage

const args = {
  recipients: [
    {
      address: "0x442C01498ED8205bFD9aaB6B8cc5C810Ed070C8f",
      percentAllocation: 50.0000
    },
    {
      address: "0xc3313847E2c4A506893999f9d53d07cDa961a675",
      percentAllocation: 50.0000
    },
  ],
  distributorFeePercent: 1.0000
}
 
const response = await splitsClient.predictImmutableSplitAddress(args)

Arguments

{
  recipients: {
    address: string
    percentAllocation: number
  }[]
  distributorFeePercent: number
}

Response

{
  splitAddress: string
  splitExists: boolean
}

getController

Returns the controller for a given splitAddress.

Usage

const args = {
  splitAddress: '0xd9137B84f56D61Bb961082DD9Eb21bE3D7B14cB9',
}
 
const response = await splitsClient.getController(args)

Arguments

{
  splitAddress: string
}

Response

{
  controller: string
}

getNewPotentialController

Returns the new potential controller (i.e., the account that needs to accept control) for a given splitAddress.

Usage

const args = {
  splitAddress: '0xd9137B84f56D61Bb961082DD9Eb21bE3D7B14cB9',
}
 
const response = await splitsClient.getNewPotentialController(args)

Arguments

{
  splitAddress: string
}

Response

{
  newPotentialController: string
}

getHash

Returns the current hash for a given splitAddress.

Usage

const args = {
  splitAddress: '0xd9137B84f56D61Bb961082DD9Eb21bE3D7B14cB9',
}
 
const response = await splitsClient.getHash(args)

Arguments

{
  splitAddress: string
}

Response

{
  hash: string
}