Technical Details
Technical information for developers
This document provides comprehensive technical information about FrensPool's architecture, smart contracts, and integration points for developers who want to build on or interact with the platform.
Architecture Overview
FrensPool uses a modern web3 architecture consisting of:
Smart Contracts: Solidity contracts deployed on Monad Testnet
Frontend Application: Next.js web application with React
Backend Services: Supabase for data indexing and user management
Blockchain Interactions: Ethers.js v6 for contract interactions
State Management: React context and hooks for frontend state
Styling: Tailwind CSS with shadcn/ui components
title FrensPool Architecture
graph TD
A[Frontend (Next.js)] --> B[Smart Contracts (Solidity)]
A --> C[Supabase Backend]
B --> D[Monad Blockchain]
B --> E[Chainlink Oracles]
C --> F[Database]
C --> G[Authentication]
A --> H[Ethers.js]
H --> B
Smart Contract Details
Contract Address
Monad Testnet: 0x2535fe5De9A5BfAF6cf27316f141a5f67239E65A
Contract Architecture
The FrensPool contract inherits from OpenZeppelin's Ownable
and ReentrancyGuard
:
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.28;
import "@openzeppelin/contracts/access/Ownable.sol";
import "@openzeppelin/contracts/security/ReentrancyGuard.sol";
import "@chainlink/contracts/src/v0.8/interfaces/AggregatorV3Interface.sol";
contract FrensPool is Ownable, ReentrancyGuard {
// Contract implementation
}
Uses:
Ownable
: Access controlReentrancyGuard
: Prevent reentrancyAggregatorV3Interface
: Chainlink price feeds
Key Data Structures
Enums
enum PoolStatus { Open, Closed, Resolved }
enum OracleType { Chainlink, Social, Manual }
enum Vote { Yes, No }
Pool Struct
struct Pool {
uint256 id;
address creator;
string question;
uint256 buyIn;
uint256 deadline;
OracleType oracleType;
PoolStatus status;
uint256 totalYesVotes;
uint256 totalNoVotes;
uint256 totalAmount;
bool outcome;
address chainlinkFeed;
uint256 targetPrice;
bool isGreaterThan;
mapping(address => Vote) votes;
mapping(address => bool) hasVoted;
mapping(address => bool) hasClaimed;
}
Constants
uint256 public constant PLATFORM_FEE = 50;
uint256 public constant BASIS_POINTS = 10000;
Key Functions
Create Pool
function createPool(string memory question, uint256 deadline, OracleType oracleType,
address chainlinkFeed, uint256 targetPrice, bool isGreaterThan) external payable
Cast Vote
function castVote(uint256 poolId, Vote vote) external payable nonReentrant
Close Pool
function closePool(uint256 poolId) external
Resolve Pool (Manual)
function resolvePoolManually(uint256 poolId, bool outcome) external
Claim Winnings
function claimWinnings(uint256 poolId) external nonReentrant
Events
event PoolCreated(uint256 indexed poolId, address indexed creator, string question, uint256 buyIn, uint256 deadline);
event VoteCast(uint256 indexed poolId, address indexed voter, Vote vote, uint256 amount);
event PoolResolved(uint256 indexed poolId, bool outcome);
event WinningsClaimed(uint256 indexed poolId, address indexed user, uint256 amount);
Frontend Integration
Contract ABI
Refer to the FRENS_POOL_ABI
for simplified interaction.
Connecting with Ethers.js
Setup
import { ethers } from "ethers";
import { FRENS_POOL_ABI } from "./abi";
const CONTRACT_ADDRESS = process.env.NEXT_PUBLIC_CONTRACT_ADDRESS;
const RPC_URL = process.env.NEXT_PUBLIC_RPC_URL;
export function getReadOnlyProvider() {
return new ethers.JsonRpcProvider(RPC_URL);
}
export function getContractInstance(provider: any) {
return new ethers.Contract(CONTRACT_ADDRESS, FRENS_POOL_ABI, provider);
}
export async function getSigner(provider: any) {
return await provider.getSigner();
}
Create Pool Example
export async function createPoolOnChain(
provider: any,
question: string,
deadline: string,
buyInAmount: string,
oracleType = 2,
chainlinkFeed = ethers.ZeroAddress,
targetPrice = "0",
isGreaterThan = false,
): Promise<{ success: boolean; txHash: string }> {
const deadlineTimestamp = Math.floor(new Date(deadline).getTime() / 1000);
const buyInWei = ethers.parseEther(buyInAmount);
const signer = await getSigner(provider);
const contract = getContractInstance(signer);
const tx = await contract.createPool(
question,
deadlineTimestamp,
oracleType,
chainlinkFeed,
targetPrice,
isGreaterThan,
{ value: buyInWei }
);
await tx.wait();
return { success: true, txHash: tx.hash };
}
This documentation will continue to evolve as FrensPool adds features, optimizations, and mainnet support. For full ABI, helper functions, and additional integrations (e.g., Farcaster mini-app context), refer to the frenspool-dev-kit
repo.
Last updated