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
Copy 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
:
Copy // 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:
ReentrancyGuard
: Prevent reentrancy
AggregatorV3Interface
: Chainlink price feeds
Key Data Structures
Enums
Copy enum PoolStatus { Open, Closed, Resolved }
enum OracleType { Chainlink, Social, Manual }
enum Vote { Yes, No }
Pool Struct
Copy 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
Copy uint256 public constant PLATFORM_FEE = 50;
uint256 public constant BASIS_POINTS = 10000;
Key Functions
Create Pool
Copy function createPool(string memory question, uint256 deadline, OracleType oracleType,
address chainlinkFeed, uint256 targetPrice, bool isGreaterThan) external payable
Cast Vote
Copy function castVote(uint256 poolId, Vote vote) external payable nonReentrant
Close Pool
Copy function closePool(uint256 poolId) external
Resolve Pool (Manual)
Copy function resolvePoolManually(uint256 poolId, bool outcome) external
Claim Winnings
Copy function claimWinnings(uint256 poolId) external nonReentrant
Events
Copy 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
Copy 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
Copy 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.