אנו יוצרים אפליקציות מובייל ל-DAO שהופכות קריאת הצעות והצבעה לתהליך פשוט ואינטואיטיבי. מחזיקי טוקנים רוצים ללמוד במהירות על החלטות שמתקבלות, להצביע בכמה קליקים, ולא לפספס מועדים. המומחיות שלנו—5+ שנים של פיתוח Web3 למובייל, כולל אינטגרציה עם Governor ו-Snapshot, האצלת טוקנים, ואנליטיקה—מקצרת את זמן הפיתוח ב-40% ומונעת מלכודות נפוצות במפגש בין בלוקצ'יין לפלטפורמות מובייל.
האתגר הטכני המרכזי הוא תמיכה בשני תקני הצבעה שונים מהותית: on-chain (OpenZeppelin Governor) ו-off-chain (Snapshot). כל אחד דורש ארכיטקטורה משלו לבקשות, חתימת עסקאות, וניהול מצב. אנו משלבים אותם כך שהמשתמש מקבל ממשק אחיד ללא שלבים מיותרים.
כיצד פועלים תקני ההצבעה: Governor מול Snapshot
On-chain (Governor): כל העסקאות נמצאות על הבלוקצ'יין. OpenZeppelin Governor הוא התקן דה-פקטו המשמש את Compound, Uniswap, Aave. ההצבעה עולה גז, אך התוצאות ניתנות לאימות קריפטוגרפי. תומך בהאצלה דרך ERC20Votes.
Off-chain (Snapshot): חתימות EIP-712 ללא גז. נתוני ההצבעה נשמרים ברשת Snapshot, אך הפעולות לא מבוצעות אוטומטית—נדרש multisig או executor. חיסכון בגז עד 100%.
רוב ה-DAO משלבים: Snapshot להצבעה מקדימה (ללא גז), Governor לביצוע. האפליקציה חייבת לעבוד עם שניהם דרך ממשק אחד.
כיצד ליישם הצבעה On-chain ו-Off-chain?
תהליך שלב-אחר-שלב לשילוב שני התקנים:
- קבע את סוג ההצבעה לפי קריטיות ותקציב: on-chain להחלטות חשובות, Snapshot לסקרים מהירים.
- עבור on-chain, השתמש ב-
governor.castVote(proposalId, support)עם פרמטרים 0 (נגד), 1 (בעד), 2 (נמנע). העסקה דורשת גז. - עבור off-chain, חתום על הודעת EIP-712 ושלח אותה דרך Snapshot API. חינם—יתרון מרכזי. דוגמת יישום:
struct SnapshotVotePayload: Codable {
let version: String // "0.1.3"
let timestamp: Int
let space: String // ID пространства DAO
let type: String // "single-choice", "approval", "quadratic"
let payload: VotePayload
struct VotePayload: Codable {
let proposal: String // IPFS hash предложения
let choice: Int // 1 = For, 2 = Against
let metadata: String // "{}"
}
}חתום דרך WalletConnect או ארנק מובנה.
רשימת הצעות: נתונים ומצבים
הצעה עוברת מספר מצבים (ראה טבלה). הנתונים מתקבלים דרך The Graph (OpenZeppelin Governor subgraph) או Tally API—קריאה ישירה ל-struct SnapshotVotePayload: Codable { let version: String // "0.1.3" let timestamp: Int let space: String // ID пространства DAO let type: String // "single-choice", "approval", "quadratic" let payload: VotePayload struct VotePayload: Codable { let proposal: String // IPFS hash предложения let choice: Int // 1 = For, 2 = Against let metadata: String // "{}" } } אינה יעילה לרשימה.
| מצב | Governor | תיאור |
|---|---|---|
| ממתין | 0 | ההצבעה טרם החלה |
| פעיל | 1 | ההצבעה פתוחה |
| בוטל | 2 | בוטל על ידי המחבר |
| נכשל | 3 | לא הגיע לקוורום או לרוב |
| הצליח | 4 | עבר, ממתין לתור |
| בתור | 5 | ב-TimeLock, ממתין לביצוע |
| פג תוקף | 6 | מועד הביצוע חלף |
| בוצע | 7 | בוצע |
כדי לבקש רשימה, השתמש בשאילתות GraphQL ל-Tally API:
struct TallyProposalsQuery: Codable {
static let query = """
query Proposals($governorId: ID!, $first: Int!) {
proposals(governorId: $governorId, pagination: { first: $first }, sort: { sortBy: id, isDescending: true }) {
id
title
description
status
voteStats {
support
votes
percent
}
start {
... on Block {
timestamp
}
}
end {
... on Block {
timestamp
}
}
}
}
"""
}Tally, Boardroom, Messari—אגרגטורים מוכנים. עבור DAO מותאם אישית, אנו פורסים The Graph subgraph.
מדוע מסך ההצעה הוא נקודת הכניסה המרכזית?
רוב המשתתפים רק מצביעים, לא יוצרים הצעות. המסך צריך להראות סטטוס, טיימר, תוצאות בזמן אמת, וכפתור הצבעה (רק ב-Active). מבנה לדוגמה:
- כותרת ותיאור (עיבוד Markdown)
- סטטוס ומסגרת זמן
- תוצאות: בעד / נגד / נמנע עם פסי התקדמות
- קוורום: X מתוך Y קולות הושגו
- כפתורי הצבעה (רק ב-Active)
- היסטוריית אירועים: מי הצביע ומתי
data class ProposalVoteStats(
val forVotes: BigDecimal,
val againstVotes: BigDecimal,
val abstainVotes: BigDecimal
) {
val totalVotes get() = forVotes + againstVotes + abstainVotes
val forPercent get() = if (totalVotes > BigDecimal.ZERO) (forVotes / totalVotes * BigDecimal(100)).toInt() else 0
val quorumReached get() = totalVotes >= quorumThreshold
} האצלת טוקנים: מה ומה לבדוק
טוקנים מסוג IGovernor.state() מאפשרים להאציל כוח הצבעה ללא העברת טוקנים. קריאה ל-struct TallyProposalsQuery: Codable { static let query = """ query Proposals($governorId: ID!, $first: Int!) { proposals(governorId: $governorId, pagination: { first: $first }, sort: { sortBy: id, isDescending: true }) { id title description status voteStats { support votes percent } start { ... on Block { timestamp } } end { ... on Block { timestamp } } } } """ } היא עסקה אחת. אם לא קוראים לה, הטוקנים לא משתתפים בהצבעת Governor גם אם הם ביתרה.
UX: בכניסה ראשונה, בדוק האצלה דרך data class ProposalVoteStats( val forVotes: BigDecimal, val againstVotes: BigDecimal, val abstainVotes: BigDecimal ) { val totalVotes get() = forVotes + againstVotes + abstainVotes val forPercent get() = if (totalVotes > BigDecimal.ZERO) (forVotes / totalVotes * BigDecimal(100)).toInt() else 0 val quorumReached get() = totalVotes >= quorumThreshold } . אם אין האצלה, הצג באנר "הפעל את זכות ההצבעה שלך". דוגמת קוד:
func getDelegatee(for address: EthereumAddress) async throws -> EthereumAddress {
return try await governanceToken.delegates(account: address)
} התראות Push למשתתפים פעילים
הירשם לאירועים דרך APNs/FCM: הצעה חדשה, סגירת הצבעה קרובה (אזהרה 24 שעות), קוורום הושג, הצעה בוצעה. המשתמש מגדיר מסננים—אנחנו לא שולחים ספאם.
יצירת הצעה: מתי צריך
יצירת הצעה דרך Governor דורשת ציון ERC20Votes, token.delegate(delegateeAddress), token.delegates(account), ו-func getDelegatee(for address: EthereumAddress) async throws -> EthereumAddress { return try await governanceToken.delegates(account: address) } . אנו מפשטים את הממשק עם תבניות או בונה קריאות למשתמשים טכניים. בדוק את סף הטוקנים המינימלי (targets) לפני השליחה.
טעויות אינטגרציה נפוצות
- לא בודקים האצלה—קולות לא נספרים.
- שליחת חתימת Snapshot ללא דומיין EIP-712 נכון.
- התעלמות מקוורום: ללא זה, ההצעה לא תבוצע.
- ספאם של התראות—משתמשים מכבים אותן.
מה כלול בעבודה
- תיעוד טכני לאינטגרציית Governor ו-Snapshot
- קוד מקור למודולי הצבעה והאצלה
- הגדרת התראות Push ואנליטיקה
- גישה לריפוזיטורי ו-CI/CD
- הדרכת צוות לשינויים ותמיכה לשבועיים
לוחות זמנים
| רכיב | משך |
|---|---|
| רשימת הצעות + סטטוסים | שבוע 1 |
| מסך הצעה עם הצבעות בזמן אמת | שבוע 1 |
| הצבעה On-chain (Governor) | 3 ימים |
| הצבעת Snapshot | 3 ימים |
| האצלת טוקנים | יומיים |
| התראות Push | 3 ימים |
| יצירת הצעות | שבוע 1 |
MVP (רשימה + הצבעה + האצלה): 3–4 שבועות. אפליקציה מלאה עם יצירת הצעות, היסטוריה, אנליטיקה: 8–12 שבועות.
צור קשר לדיון מפורט על אפליקציית ה-DAO שלך. קבל ייעוץ ממהנדסים עם ניסיון של 5+ שנים בפיתוח מובייל ו-30+ פרויקטי Web3 מיושמים. אנו מבטיחים עמידה בהנחיות App Store Review ואחסון מאובטח של מפתחות פרטיים. הזמן פיתוח וקצר את זמן היציאה לשוק ב-40%.







