@sfpro/sdk

How to create a GDA pool and distribute

Set up one-to-many token distributions with GDA pools

The General Distribution Agreement (GDA) enables efficient one-to-many token distributions through pools. Pool members receive tokens proportionally based on their allocated units.

Create a Pool

First, create a new GDA pool:

import { useWriteGdaForwarder } from "@sfpro/sdk/hook"
import { useAccount } from "wagmi"

const superToken = "0x..." // USDCx address

function CreatePool() {
  const { address } = useAccount()
  const { writeContract: createPool } = useWriteGdaForwarder({ 
    functionName: "createPool", 
    args: [superToken, address!, "0x"] 
  }) 
  
  return (
    <button onClick={() => createPool?.()}>
      Create Distribution Pool
    </button>
  )
}
import { gdaForwarderAbi, gdaForwarderAddress } from "@sfpro/sdk/abi"
import { createWalletClient, http } from "viem"
import { mainnet } from "viem/chains"
import { privateKeyToAccount } from "viem/accounts"

const account = privateKeyToAccount(process.env.PRIVATE_KEY as `0x${string}`)
const walletClient = createWalletClient({
  account,
  chain: mainnet,
  transport: http()
})

const superToken = "0x..." // USDCx address
const poolAdmin = account.address // Pool admin address

async function createPool() {
  const hash = await walletClient.writeContract({ 
    address: gdaForwarderAddress[mainnet.id], 
    abi: gdaForwarderAbi, 
    functionName: "createPool", 
    args: [superToken, poolAdmin, "0x"] 
  }) 
  
  return hash
}
import { writeGdaForwarder } from "@sfpro/sdk/action"
import { createConfig } from "@wagmi/core"
import { createWalletClient, http } from "viem"
import { mainnet } from "viem/chains"
import { privateKeyToAccount } from "viem/accounts"

const account = privateKeyToAccount(process.env.PRIVATE_KEY as `0x${string}`)
const wagmiConfig = createConfig({
  chains: [mainnet],
  client({ chain }) {
    return createWalletClient({
      account,
      chain,
      transport: http(),
    })
  },
})

const superToken = "0x..." // USDCx address
const poolAdmin = account.address // Pool admin address

async function createPool() {
  const hash = await writeGdaForwarder(wagmiConfig, { 
    chainId: mainnet.id, 
    functionName: "createPool", 
    args: [superToken, poolAdmin, "0x"] 
  }) 
  
  return hash
}

Get Pool Address

After creating a pool, you need to get its address:

import { useReadGdaForwarder } from "@sfpro/sdk/hook"
import { keccak256, toHex } from "viem"

const superToken = "0x..." // USDCx address
const poolAdmin = "0x..." // Pool admin address
const poolId = keccak256(toHex("mypool"))

function PoolAddress() {
  const { data: poolAddress } = useReadGdaForwarder({ 
    functionName: "getPool", 
    args: [superToken, poolAdmin, poolId] 
  }) 
  
  return (
    <div>
      Pool Address: {poolAddress}
    </div>
  )
}
import { gdaForwarderAbi, gdaForwarderAddress } from "@sfpro/sdk/abi"
import { createPublicClient, http, keccak256, toHex } from "viem"
import { mainnet } from "viem/chains"

const client = createPublicClient({
  chain: mainnet,
  transport: http()
})

const superToken = "0x..." // USDCx address
const poolAdmin = "0x..." // Pool admin address
const poolId = keccak256(toHex("mypool")) // Or use index like toHex(0)

async function getPoolAddress() {
  const poolAddress = await client.readContract({ 
    address: gdaForwarderAddress[mainnet.id], 
    abi: gdaForwarderAbi, 
    functionName: "getPool", 
    args: [superToken, poolAdmin, poolId] 
  }) 
  
  return poolAddress
}
import { readGdaForwarder } from "@sfpro/sdk/action"
import { createConfig } from "@wagmi/core"
import { http, keccak256, toHex } from "viem"
import { mainnet } from "viem/chains"

const wagmiConfig = createConfig({
  chains: [mainnet],
  transports: {
    [mainnet.id]: http()
  }
})

const superToken = "0x..." // USDCx address
const poolAdmin = "0x..." // Pool admin address
const poolId = keccak256(toHex("mypool"))

async function getPoolAddress() {
  const poolAddress = await readGdaForwarder(wagmiConfig, { 
    chainId: mainnet.id, 
    functionName: "getPool", 
    args: [superToken, poolAdmin, poolId] 
  }) 
  
  return poolAddress
}

Give Units to Pool Members

Allocate units to members to determine their share of distributions:

import { useWriteGdaPool } from "@sfpro/sdk/hook"

const poolAddress = "0x..." // Your pool address
const member = "0x..." // Member address
const units = 100n // Number of units

function GiveUnits() {
  const { writeContract: updateUnits } = useWriteGdaPool({ 
    address: poolAddress, 
    functionName: "updateMemberUnits", 
    args: [member, units, "0x"] 
  }) 
  
  return (
    <button onClick={() => updateUnits?.()}>
      Give 100 units to member
    </button>
  )
}
import { gdaPoolAbi } from "@sfpro/sdk/abi"
import { createWalletClient, http } from "viem"
import { mainnet } from "viem/chains"
import { privateKeyToAccount } from "viem/accounts"

const account = privateKeyToAccount(process.env.PRIVATE_KEY as `0x${string}`)
const walletClient = createWalletClient({
  account,
  chain: mainnet,
  transport: http()
})

const poolAddress = "0x..." // Your pool address
const member = "0x..." // Member address
const units = 100n // Number of units

async function giveUnits() {
  const hash = await walletClient.writeContract({ 
    address: poolAddress, 
    abi: gdaPoolAbi, 
    functionName: "updateMemberUnits", 
    args: [member, units, "0x"] 
  }) 
  
  return hash
}
import { writeGdaPool } from "@sfpro/sdk/action"
import { createConfig } from "@wagmi/core"
import { createWalletClient, http } from "viem"
import { mainnet } from "viem/chains"
import { privateKeyToAccount } from "viem/accounts"

const account = privateKeyToAccount(process.env.PRIVATE_KEY as `0x${string}`)
const wagmiConfig = createConfig({
  chains: [mainnet],
  client({ chain }) {
    return createWalletClient({
      account,
      chain,
      transport: http(),
    })
  },
})

const poolAddress = "0x..." // Your pool address
const member = "0x..." // Member address
const units = 100n // Number of units

async function giveUnits() {
  const hash = await writeGdaPool(wagmiConfig, { 
    chainId: mainnet.id, 
    address: poolAddress, 
    functionName: "updateMemberUnits", 
    args: [member, units, "0x"] 
  }) 
  
  return hash
}

Distribute Tokens

Once members have units, distribute tokens to all members proportionally:

import { useWriteGdaForwarder } from "@sfpro/sdk/hook"
import { useAccount } from "wagmi"
import { parseEther } from "viem"

const superToken = "0x..." // USDCx address
const poolAddress = "0x..." // Your pool address
const amount = parseEther("1000") // 1000 tokens

function DistributeTokens() {
  const { address } = useAccount()
  const { writeContract: distribute } = useWriteGdaForwarder({ 
    functionName: "distribute", 
    args: [superToken, address!, poolAddress, amount, "0x"] 
  }) 
  
  return (
    <button onClick={() => distribute?.()}>
      Distribute 1000 tokens to pool
    </button>
  )
}
import { gdaForwarderAbi, gdaForwarderAddress } from "@sfpro/sdk/abi"
import { createWalletClient, http, parseEther } from "viem"
import { mainnet } from "viem/chains"
import { privateKeyToAccount } from "viem/accounts"

const account = privateKeyToAccount(process.env.PRIVATE_KEY as `0x${string}`)
const walletClient = createWalletClient({
  account,
  chain: mainnet,
  transport: http()
})

const superToken = "0x..." // USDCx address
const poolAddress = "0x..." // Your pool address
const amount = parseEther("1000") // 1000 tokens to distribute

async function distributeToPool() {
  const hash = await walletClient.writeContract({ 
    address: gdaForwarderAddress[mainnet.id], 
    abi: gdaForwarderAbi, 
    functionName: "distribute", 
    args: [superToken, account.address, poolAddress, amount, "0x"] 
  }) 
  
  return hash
}
import { writeGdaForwarder } from "@sfpro/sdk/action"
import { createConfig } from "@wagmi/core"
import { createWalletClient, http, parseEther } from "viem"
import { mainnet } from "viem/chains"
import { privateKeyToAccount } from "viem/accounts"

const account = privateKeyToAccount(process.env.PRIVATE_KEY as `0x${string}`)
const wagmiConfig = createConfig({
  chains: [mainnet],
  client({ chain }) {
    return createWalletClient({
      account,
      chain,
      transport: http(),
    })
  },
})

const superToken = "0x..." // USDCx address
const poolAddress = "0x..." // Your pool address
const amount = parseEther("1000") // 1000 tokens

async function distributeToPool() {
  const hash = await writeGdaForwarder(wagmiConfig, { 
    chainId: mainnet.id, 
    functionName: "distribute", 
    args: [superToken, account.address, poolAddress, amount, "0x"] 
  }) 
  
  return hash
}

Complete Example

Here's a complete workflow for creating and using a GDA pool:

import { 
  gdaForwarderAbi, 
  gdaForwarderAddress,
  gdaPoolAbi,
  superTokenAbi
} from "@sfpro/sdk/abi"
import { createWalletClient, createPublicClient, http, parseEther, toHex } from "viem"
import { mainnet } from "viem/chains"
import { privateKeyToAccount } from "viem/accounts"

const account = privateKeyToAccount(process.env.PRIVATE_KEY as `0x${string}`)
const walletClient = createWalletClient({
  account,
  chain: mainnet,
  transport: http()
})
const publicClient = createPublicClient({
  chain: mainnet,
  transport: http()
})

async function setupDistributionPool() {
  const superToken = "0x..." // USDCx address
  const poolId = toHex(1) // Simple pool ID
  
  // 1. Create pool
  await walletClient.writeContract({
    address: gdaForwarderAddress[mainnet.id],
    abi: gdaForwarderAbi,
    functionName: "createPool",
    args: [superToken, account.address, poolId]
  })
  
  // 2. Get pool address
  const poolAddress = await publicClient.readContract({
    address: gdaForwarderAddress[mainnet.id],
    abi: gdaForwarderAbi,
    functionName: "getPool",
    args: [superToken, account.address, poolId]
  })
  
  // 3. Add members with units
  const members = [
    { address: "0x...", units: 50n },  // 50% share
    { address: "0x...", units: 30n },  // 30% share
    { address: "0x...", units: 20n },  // 20% share
  ]
  
  for (const member of members) {
    await walletClient.writeContract({
      address: poolAddress,
      abi: gdaPoolAbi,
      functionName: "updateMemberUnits",
      args: [member.address, member.units, "0x"]
    })
  }
  
  // 4. Distribute tokens
  const distributionAmount = parseEther("1000")
  await walletClient.writeContract({
    address: gdaForwarderAddress[mainnet.id],
    abi: gdaForwarderAbi,
    functionName: "distribute",
    args: [superToken, account.address, poolAddress, distributionAmount, "0x"]
  })
  
  return poolAddress
}

Key Concepts

  1. Pool Creation: Each pool is unique per (superToken, admin, poolId) combination
  2. Units: Determine proportional share (e.g., 100 units out of 1000 total = 10% share)
  3. Distribution: Instantly distributes to all members based on their unit share
  4. Gas Efficiency: More efficient than sending individual transfers

Next Steps