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
- Pool Creation: Each pool is unique per (superToken, admin, poolId) combination
- Units: Determine proportional share (e.g., 100 units out of 1000 total = 10% share)
- Distribution: Instantly distributes to all members based on their unit share
- Gas Efficiency: More efficient than sending individual transfers
Next Steps
- Learn to connect to GDA pools as a member
- Explore batch operations
- Check the GDA API reference