Integrate Sendr in an afternoon.
Every Sendr launch is a plain ERC-20 living in a standard Uniswap V3 1% pool. Anything that already speaks V3 works. Below is what you need to index, quote, and trade against sendr tokens.
Contract addresses
Chain id 4663 · Explorer Blockscout · Public RPC rpc.mainnet.chain.robinhood.com. Beware: a PancakeSwap fork also lives on this chain — the addresses above are the canonical Uniswap V3 deployment (factory 0x1f7d…2EfA).
Events to index
Point your indexer at SendrFactory from block 9539458 and watch three events:
event TokenDeployed( address indexed token, address indexed creator, address indexed feeRecipient, string name, string symbol, string metadataURI, uint256 positionId, int24 startingTick, bool tokenIsToken0, uint256 timestamp ); event InitialBuy( address indexed token, address indexed buyer, uint256 ethIn, uint256 tokensOut ); event TreasuryUpdated(address indexed oldTreasury, address indexed newTreasury);
Every launched token emits its own standard ERC-20 Transfer/Approval events; the pool at UniswapV3Factory.getPool(token, WETH, 10000) emits Swap/Mint/Burn. No custom hook contracts, so any generic V3 indexer works.
Reading the registry (viem)
The factory keeps every launched token in an on-chain array so a frontend can render the whole registry without scanning logs:
import { createPublicClient, http } from 'viem';
import { sendrFactoryAbi } from '@/lib/abis';
const client = createPublicClient({
transport: http('https://rpc.mainnet.chain.robinhood.com'),
});
// Whole registry in ONE call.
const tokens = await client.readContract({
address: '0x8aB2f02f6debA2542c5ef26A8e89929Cf49E1aE4',
abi: sendrFactoryAbi,
functionName: 'getTokens',
args: [0n, 500n], // offset, limit — clamped to array length
});
Deploying a token programmatically
Deploys are one payable call. Pin the metadata JSON (with image pointing to another IPFS pin) yourself, then:
import { walletClient } from './wallet';
import { sendrFactoryAbi } from '@/lib/abis';
import { parseEther, zeroAddress } from 'viem';
const hash = await walletClient.writeContract({
address: '0x8aB2f02f6debA2542c5ef26A8e89929Cf49E1aE4',
abi: sendrFactoryAbi,
functionName: 'deployToken',
args: [
'My Token',
'MTKN',
'ipfs://bafy…metadata',
zeroAddress, // fee recipient defaults to msg.sender
],
value: parseEther('0.05'), // optional atomic initial buy
});
Pass any positive value to atomically buy in the same tx. Overshoot the 5% supply cap and the whole tx reverts with InitialBuyExceedsCap — use QuoterV2 to quote before submitting.
Collecting LP fees
Fees split 95% / 5% (creator / treasury) on every collect. The call is permissionless — anyone can trigger a payout and the recipients are whoever the locker has on record:
import { sendrLPLockerAbi } from '@/lib/abis';
const hash = await walletClient.writeContract({
address: '0x3E959E7f7dA000540e11f91B63cA9DE65199d950',
abi: sendrLPLockerAbi,
functionName: 'collectFees',
args: [tokenAddress],
});
The creator slot is redirect-able by the current holder via updateCreator(token, newAddr).
Downloading the ABIs
ABIs are extracted from the compiled Foundry output and live in apps/web-robinhood/lib/abis/ in the GitHub repo. Each file exports a <name>Abi const the way viem/wagmi expect. To regenerate:
# From repo root, with Foundry installed
cd contracts
forge build
# Then re-emit each ABI file
DEST=../apps/web-robinhood/lib/abis
for c in SendrFactory SendrLPLocker SendrToken; do
{ echo "export const ${c,,}Abi = "; \
forge inspect $c abi --json; \
echo " as const;"; } > "$DEST/$c.ts"
done