Skip to Content

Allocator

The Allocator comes with functions to allocate tokens to a collection of recipients. We use arrays for the public function to simplify token transfers to multiple recipients.

  • Allocate - tokens going from sender to a recipient
  • Distribute - tokens going from strategy contract to a recipient
event Allocate(address indexed from, address indexed to, uint256 amount, address token, bytes data); function allocate(address[] calldata recipients, uint256[] calldata amounts, address token, bytes[] calldata data) public virtual {} function _allocate(address to, uint256 amount, address token, bytes memory data) internal virtual internal virtual nonReentrant {} function distribute(address[] calldata recipients, uint256[] calldata amounts, address token, bytes[] calldata data) public virtual {} function _distribute(address to, uint256 amount, address token, bytes memory data) internal virtual internal virtual nonReentrant {}

The reason the allocate function contains an array of recipients and amounts is because we want to be able to send to many in one transaction without using Multicall.

Never approve Multicall3 to spend your tokens. https://github.com/mds1/multicall?tab=readme-ov-file#security

Examples
// Only Vote token is allowed and projects must be approved contract VoteStrategy is Allocator { function _allocate(address recipient, uint256 amount, address token, bytes memory) internal override { require(token == voteToken, "Must be vote token"); require(projects[recipient][0].status == IRegistry.Status.approved, "Project must be approved"); super._allocate(recipient, amount, token, ""); } } // Fund Strategy with tokens contract MatchingFundsStrategy is Allocator, Ownable { function fund(uint256 amount, address token) public { require(token == matchingToken, "Must be vote token or matching token"); super._allocate(address(this), amount, token, ""); } // Calculate distributions off-chain and call this to distributes function distributeMatching(address[] calldata recipients, uint256[] calldata amounts, address token, bytes[] calldata data) public onlyOwner { require(token == matchingToken, "Must be vote token or matching token"); super.distribute(recipients, amounts, token, data); } }

Indexer GraphQL Query

{ allocations(where: { strategy_in_: ["0xYourContract"] }) { items { to from amount amountInUSD # Indexer fetches token price token # { token: address, symbol: "ETH", decimals: 18 } } } }

Hooks

const donations = useAllocations({ where: { strategy_in: ["0xYourContract"], from_not_in: ["0xYourContract"], // Exclude matching distributions }, }); const matchingDistributions = useAllocations({ where: { strategy_in: ["0xYourContract"], from_in: ["0xYourContract"], }, });

Components

AllocationForm

The AllocationForm component can be used to transfer tokens to projects added to a Cart

import { AllocationForm } from "~/components/allocation/allocation-form"; export default function CheckoutPage() { const { YourStrategy } = useContracts(); const erc20address = "0xTokenAddress"; return ( <AllocationForm defaultValues={{}} strategyAddress={YourStrategy?.address} tokenAddress={erc20address} /> ); }

AllocationsTable

The AllocationsTable component renders a table of token tranfers.

import { AllocationForm } from "~/components/allocation/allocation-form"; export default function ProjectDetailsPage() { const { YourStrategy } = useContracts(); return ( <AllocationsTable query={{ where: { strategy_in: [YourContract?.address], to: "0xProjectAddress", }, }} /> ); }
Last updated on