A Hono-based API for managing onchain Seeds (artwork proposals) and NFT-based blessings for the Abraham AI art curation ecosystem.
This API provides:
- Seed Creation - Onchain artwork proposals with authorized creator control
- Round-Based Winner Selection - Daily competition with anti-whale mechanics
- Blessings System - NFT-gated voting with quadratic scoring
- ERC1155 Editions - Winning seeds become collectible NFTs
The system uses:
- AbrahamSeeds Contract (Base L2) - ERC1155-based seed and blessing management
- MerkleGating Module (Base L2) - Cross-chain NFT verification via Merkle proofs
- FirstWorks NFT (Ethereum L1) - NFT ownership for blessing eligibility
- Privy - Authentication
- Viem - Blockchain interactions
- Hono - Lightweight web framework
L1 (Ethereum Mainnet) L2 (Base)
┌──────────────────┐ ┌───────────────────┐
│ FirstWorks NFT │───snapshot───▶│ MerkleGating │
│ (ERC721) │ │ (Proof Verify) │
└──────────────────┘ └─────────┬─────────┘
│
┌─────────▼─────────┐
│ AbrahamSeeds │
│ (ERC1155) │
│ ├─ Seeds │
│ ├─ Blessings │
│ ├─ Creations │
│ └─ Editions │
└───────────────────┘
- Onchain Storage: All seeds stored on AbrahamSeeds contract (Base L2)
- Authorized Creators: Only wallets with CREATOR_ROLE can create seeds
- Two Creation Modes:
- Backend-Signed (Gasless): API creates seed on behalf of creator
- Client-Signed: Creator signs transaction with their wallet
- Access Control: Role-based permissions (ADMIN, CREATOR, OPERATOR)
- NFT-Gated: Only FirstWorks NFT holders can bless
- Cross-Chain Verification: L1 ownership verified via Merkle proofs on L2
- Daily Limits: N blessings per day where N = NFTs owned (configurable)
- Quadratic Scoring: Score = √(blessings) prevents whale dominance
- Delegation Support: Users can approve backend for gasless blessings
- Round-Based: Each 24-hour period is an independent competition
- Anti-Whale: Square root scoring prevents large holders from dominating
- Daily Winners: Highest scoring seed wins each round
- ERC1155 Minting: Winners receive edition NFTs (creator, curator, public)
- Creator Editions: Minted directly to seed creator
- Curator Editions: Distributed to top blessers (priests)
- Public Editions: Available for purchase (50/50 split: creator/treasury)
| Network | Contract | Address |
|---|---|---|
| Base Sepolia | AbrahamSeeds | 0x0b95d25463b7a937b3df28368456f2c40e95c730 |
| Base Sepolia | MerkleGating | 0x46657b69308d90a4756369094c5d78781f3f5979 |
| Ethereum Mainnet | FirstWorks NFT | 0x9734c959A5FEC7BaD8b0b560AD94F9740B90Efd8 |
npm installcp .env.example .env.local
# Edit .env.local with your configurationRequired variables:
# Privy Authentication
PRIVY_APP_ID=your_privy_app_id
PRIVY_APP_SECRET=your_privy_app_secret
# AbrahamSeeds Contract (L2)
L2_SEEDS_CONTRACT=0x0b95d25463b7a937b3df28368456f2c40e95c730
L2_GATING_CONTRACT=0x46657b69308d90a4756369094c5d78781f3f5979
L2_SEEDS_DEPLOYMENT_BLOCK=36452477
NETWORK=baseSepolia
# RPC URLs
L2_RPC_URL=https://base-sepolia.g.alchemy.com/v2/YOUR_KEY
MAINNET_RPC_URL=https://eth-mainnet.g.alchemy.com/v2/YOUR_KEY
# FirstWorks NFT (L1)
FIRSTWORKS_CONTRACT_ADDRESS=0x9734c959A5FEC7BaD8b0b560AD94F9740B90Efd8
FIRSTWORKS_RPC_URL=https://eth-mainnet.g.alchemy.com/v2/YOUR_KEY
# Backend Wallet (for gasless operations)
RELAYER_PRIVATE_KEY=0x...
# Admin Keys
ADMIN_KEY=your_admin_key
CRON_SECRET=your_cron_secret# Generate FirstWorks NFT ownership snapshot
npm run snapshot:generate
# Generate Merkle tree from snapshot
npm run merkle:generatenpm run devThe API will be running at http://localhost:3000
| Endpoint | Method | Description |
|---|---|---|
/api/seeds |
GET | Get all seeds (paginated) |
/api/seeds/count |
GET | Get total seed count |
/api/seeds/stats |
GET | Get seed statistics |
/api/seeds/config |
GET | Get contract configuration |
/api/seeds/:seedId |
GET | Get seed by ID |
/api/seeds |
POST | Create seed (backend-signed) |
/api/seeds/prepare |
POST | Prepare seed creation transaction |
| Endpoint | Method | Description |
|---|---|---|
/api/blessings |
POST | Submit blessing (gasless) |
/api/blessings/prepare |
POST | Prepare blessing transaction |
/api/blessings/eligibility |
GET | Check user eligibility |
/api/blessings/stats |
GET | Get user blessing stats |
/api/blessings/delegation-status |
GET | Check delegation status |
/api/blessings/prepare-delegate |
POST | Prepare delegation transaction |
/api/blessings/seed/:seedId |
GET | Get blessings for seed |
/api/blessings/user/:address |
GET | Get blessings by user |
| Endpoint | Method | Description |
|---|---|---|
/api/admin/update-snapshot |
POST | Update NFT snapshot + Merkle tree |
/api/admin/snapshot-status |
GET | Get snapshot status |
/api/cron/select-winner |
POST | Select daily winner |
The system uses NFT ownership snapshots to verify blessing eligibility. Update periodically:
# Full update: snapshot + merkle + contract
npm run update-snapshot
# Skip contract update
SKIP_CONTRACT_UPDATE=true npm run update-snapshotcurl -X POST http://localhost:3000/api/admin/update-snapshot \
-H "X-Admin-Key: your-admin-key"// vercel.json
{
"crons": [
{
"path": "/api/cron/update-snapshot",
"schedule": "0 1 * * *"
},
{
"path": "/api/cron/select-winner",
"schedule": "0 0 * * *"
}
]
}AbrahamSeeds uses OpenZeppelin's AccessControl:
| Role | Powers |
|---|---|
DEFAULT_ADMIN_ROLE |
Grant/revoke roles, update config, pause contract |
CREATOR_ROLE |
Submit seeds |
OPERATOR_ROLE |
Select winners, distribute curator editions, relayer operations |
# Grant CREATOR_ROLE
npm run grant-creator:base-sepolia -- --address 0xNewCreator
# Or via Hardhat console
npx hardhat console --network baseSepolia
> const contract = await ethers.getContractAt("AbrahamSeeds", "0x0b95d25463b7a937b3df28368456f2c40e95c730")
> await contract.addCreator("0xNewCreator")Prevents whale dominance:
Score = √(user_blessings)
Examples:
- 1 blessing = score 1
- 4 blessings = score 2
- 100 blessings = score 10
- 10000 blessings = score 100
Total Score = Σ √(blessings_from_user_i) for all users
Example:
- User A: 100 blessings → √100 = 10
- User B: 25 blessings → √25 = 5
- User C: 4 blessings → √4 = 2
- Total Score: 10 + 5 + 2 = 17
import { usePrivy } from "@privy-io/react-auth";
const { getAccessToken } = usePrivy();
// Check eligibility
async function checkEligibility() {
const token = await getAccessToken();
const response = await fetch("/api/blessings/eligibility", {
headers: { Authorization: `Bearer ${token}` }
});
return response.json();
}
// Submit blessing (gasless)
async function blessSeed(seedId: number) {
const token = await getAccessToken();
const response = await fetch("/api/blessings", {
method: "POST",
headers: {
"Content-Type": "application/json",
Authorization: `Bearer ${token}`
},
body: JSON.stringify({ seedId })
});
return response.json();
}For gasless blessings, users must approve the backend as delegate:
// 1. Check delegation status
const status = await fetch("/api/blessings/delegation-status", {
headers: { Authorization: `Bearer ${token}` }
}).then(r => r.json());
// 2. If not approved, get delegation transaction
if (!status.data.isDelegateApproved) {
const delegateTx = await fetch("/api/blessings/prepare-delegate", {
method: "POST",
headers: {
"Content-Type": "application/json",
Authorization: `Bearer ${token}`
},
body: JSON.stringify({ approved: true })
}).then(r => r.json());
// 3. User signs delegation transaction
await walletClient.sendTransaction({
to: delegateTx.data.transaction.to,
data: delegateTx.data.transaction.data
});
}
// 4. Now gasless blessings work
await blessSeed(seedId);npm run deploy:abraham-seeds:base-sepolianpm run deploy:abraham-seeds:baseThe deployment script:
- Deploys MerkleGating module
- Deploys AbrahamSeeds contract
- Grants CREATOR_ROLE and OPERATOR_ROLE to relayer
- Updates MerkleGating with Merkle root
- Creates a test seed
- Saves ABIs and deployment info
abraham-api/
├── contracts/
│ └── src/
│ ├── agents/abraham/
│ │ └── AbrahamSeeds.sol # Main contract
│ ├── core/
│ │ └── EdenAgent.sol # Base contract
│ ├── modules/gating/
│ │ └── MerkleGating.sol # NFT verification
│ └── interfaces/
│ └── IGatingModule.sol # Gating interface
├── deploy/
│ └── deploy_abraham_seeds.ts # Deployment script
├── lib/
│ ├── abi/ # Contract ABIs
│ └── snapshots/ # NFT snapshots & Merkle trees
├── src/
│ ├── middleware/
│ │ └── auth.ts # Privy auth
│ ├── routes/
│ │ ├── blessings.ts # Blessing endpoints
│ │ ├── seeds.ts # Seed endpoints
│ │ └── commandments.ts # Commandment endpoints
│ ├── services/
│ │ ├── contractService.ts # Contract interactions
│ │ └── blessingService.ts # Blessing logic
│ └── server.ts # Main entry
├── docs/
│ ├── API_REFERENCE.md # API documentation
│ ├── DEPLOYMENT_GUIDE.md # Deployment guide
│ └── SEEDS_CONTRACT_REFERENCE.md # Contract reference
├── .env.example # Environment template
├── hardhat.config.ts
├── package.json
├── QUICKSTART.md # Quick start guide
├── SETUP.md # Detailed setup guide
└── SMART_CONTRACT_SUMMARY.md # Contract architecture
| Script | Description |
|---|---|
npm run dev |
Start development server |
npm start |
Start production server |
npm run compile |
Compile Solidity contracts |
npm run snapshot:generate |
Generate NFT ownership snapshot |
npm run merkle:generate |
Generate Merkle tree |
npm run update-snapshot |
Full snapshot + merkle + contract update |
npm run deploy:abraham-seeds:base-sepolia |
Deploy to testnet |
npm run deploy:abraham-seeds:base |
Deploy to mainnet |
npm run grant-creator:base-sepolia |
Grant CREATOR_ROLE |
npm run select-winner |
Manually select winner |
npm run test:contracts |
Run contract tests |
- QUICKSTART.md - Quick start guide
- SETUP.md - Detailed setup instructions
- SMART_CONTRACT_SUMMARY.md - Contract architecture
- docs/DEPLOYMENT_GUIDE.md - Deployment guide
- docs/API_REFERENCE.md - API endpoints reference
- docs/SEEDS_CONTRACT_REFERENCE.md - Contract functions
npm run snapshot:generate
npm run merkle:generatenpm run merkle:generate
npm run update-rootUser needs to approve delegation:
POST /api/blessings/prepare-delegate
# User signs the returned transactionnpm run grant-creator:base-sepolia -- --address 0xRelayerAddressnpm run verify:seeds:base-sepolia- Private keys stored in environment variables only
.env.localin.gitignore- Relayer wallet separate from deployer
- Admin key required for sensitive endpoints
- Role-based access control on contract
MIT
For issues or questions, please open an issue in the repository.