Реалізація DAO-порталу (голосування, пропозиції) на сайті

Наша компанія займається розробкою, підтримкою та обслуговуванням сайтів будь-якої складності. Від простих односторінкових сайтів до масштабних кластерних систем, побудованих на мікро сервісах. Досвід розробників підтверджено сертифікатами від вендорів.

Розробка та обслуговування будь-яких видів сайтів:

Інформаційні сайти або веб-програми
Сайти візитки, landing page, корпоративні сайти, онлайн каталоги, квіз, промо-сайти, блоги, ресурси новин, інформаційні портали, форуми, агрегатори
Сайти або веб-програми електронної комерції
Інтернет-магазини, B2B-портали, маркетплейси, онлайн-обмінники, кешбек-сайти, біржі, дропшиппінг-платформи, парсери товарів
Веб-програми для управління бізнес-процесами
CRM-системи, ERP-системи, корпоративні портали, системи управління виробництвом, парсери інформації
Сайти або веб-програми електронних послуг
Дошки оголошень, онлайн-школи, онлайн-кінотеатри, конструктори сайтів, портали надання електронних послуг, відеохостинги, тематичні портали

Це лише деякі з технічних типів сайтів, з якими ми працюємо, і кожен із них може мати свої специфічні особливості та функціональність, а також бути адаптованим під конкретні потреби та цілі клієнта.

Пропоновані послуги
Показано 1 з 1 послугУсі 2065 послуг
Реалізація DAO-порталу (голосування, пропозиції) на сайті
Складна
~2-4 тижні
Часті питання

Наші компетенції:

Етапи розробки

Останні роботи

  • image_website-b2b-advance_0.png
    Розробка сайту компанії B2B ADVANCE
    1262
  • image_web-applications_feedme_466_0.webp
    Розробка веб-додатків для компанії FEEDME
    1171
  • image_websites_belfingroup_462_0.webp
    Розробка веб-сайту для компанії БЕЛФІНГРУП
    874
  • image_ecommerce_furnoro_435_0.webp
    Розробка інтернет магазину для компанії FURNORO
    1094
  • image_crm_enviok_479_0.webp
    Розробка веб-додатків для компанії Enviok
    831
  • image_bitrix-bitrix-24-1c_fixper_448_0.png
    Розробка веб-сайту для компанії ФІКСПЕР
    851

Реалізація DAO-портала (голосування, пропозиції) на сайті

DAO-портал — веб-інтерфейс для управління децентралізованою організацією: створення пропозицій, голосування токенами, делегування голосів, виконання прийнятих рішень через смарт-контракти.

Архітектура DAO

Governance Token (ERC-20 + EIP-2612 для делегації)
         |
Governor Contract (OpenZeppelin Governor)
    ├── Propose (створити пропозицію)
    ├── CastVote (проголосувати)
    ├── Queue (поставити в чергу Timelock)
    └── Execute (виконати через Timelock)
         |
Timelock Controller
    └── Target Contracts (Treasury, Protocol)

Governor Contract

// SPDX-License-Identifier: MIT
pragma solidity ^0.8.20;

import "@openzeppelin/contracts/governance/Governor.sol";
import "@openzeppelin/contracts/governance/extensions/GovernorSettings.sol";
import "@openzeppelin/contracts/governance/extensions/GovernorCountingSimple.sol";
import "@openzeppelin/contracts/governance/extensions/GovernorVotes.sol";
import "@openzeppelin/contracts/governance/extensions/GovernorTimelockControl.sol";

contract DAOGovernor is
    Governor, GovernorSettings, GovernorCountingSimple,
    GovernorVotes, GovernorTimelockControl
{
    constructor(
        IVotes _token,
        TimelockController _timelock
    )
        Governor("DAO Governor")
        GovernorSettings(
            1 days,   // voting delay (1 день до старту голосування)
            7 days,   // voting period (7 днів голосування)
            100_000e18  // proposal threshold (потрібно 100k токенів)
        )
        GovernorVotes(_token)
        GovernorTimelockControl(_timelock)
    {}

    // 4% токенів потрібно для прохідного (quorum)
    function quorum(uint256 blockNumber) public view override returns (uint256) {
        return token.getPastTotalSupply(blockNumber) * 4 / 100;
    }
}

Frontend: створення пропозиції

import { useWriteContract, useAccount } from 'wagmi';
import { encodeFunctionData } from 'viem';

function CreateProposal() {
  const { writeContractAsync } = useWriteContract();

  const handleSubmit = async (formData: ProposalFormData) => {
    // Кодуємо виклик цільового контракту
    const calldata = encodeFunctionData({
      abi: treasuryAbi,
      functionName: 'transfer',
      args: [formData.recipient, formData.amount]
    });

    await writeContractAsync({
      address: GOVERNOR_ADDRESS,
      abi: governorAbi,
      functionName: 'propose',
      args: [
        [TREASURY_ADDRESS],     // targets
        [0n],                   // values (ETH)
        [calldata],             // calldatas
        formData.description    // description (Markdown)
      ]
    });
  };

  return <ProposalForm onSubmit={handleSubmit} />;
}

Frontend: голосування

function VoteOnProposal({ proposalId }) {
  const { writeContractAsync } = useWriteContract();
  const { address } = useAccount();

  // Отримати вагу голосу на момент снепшота
  const { data: votingPower } = useReadContract({
    address: GOVERNOR_ADDRESS,
    abi: governorAbi,
    functionName: 'getVotes',
    args: [address!, proposalSnapshotBlock]
  });

  const castVote = async (support: 0 | 1 | 2) => {
    // 0 = Against, 1 = For, 2 = Abstain
    await writeContractAsync({
      address: GOVERNOR_ADDRESS,
      abi: governorAbi,
      functionName: 'castVoteWithReason',
      args: [proposalId, support, reason]
    });
  };

  return (
    <div>
      <p>Ваш вес голосу: {formatTokens(votingPower)} токенів</p>
      <button onClick={() => castVote(1)}>За</button>
      <button onClick={() => castVote(0)}>Проти</button>
      <button onClick={() => castVote(2)}>Утриматися</button>
    </div>
  );
}

Індексування через The Graph

// Отримання списку пропозицій
const PROPOSALS_QUERY = gql`
  query GetProposals($state: String, $first: Int, $skip: Int) {
    proposals(
      where: { state: $state }
      orderBy: createdAt
      orderDirection: desc
      first: $first
      skip: $skip
    ) {
      id
      proposalId
      proposer { id }
      description
      state
      forVotes
      againstVotes
      abstainVotes
      quorum
      startBlock
      endBlock
      createdAt
    }
  }
`;

// Делегування голосів
async function delegateVotes(delegatee: string) {
  await writeContractAsync({
    address: GOVERNANCE_TOKEN,
    abi: erc20VotesAbi,
    functionName: 'delegate',
    args: [delegatee]
  });
}

Інтеграція Snapshot (off-chain голосування)

Для сигнальних голосувань без gas-затрат — Snapshot Protocol:

import snapshot from '@snapshot-labs/snapshot.js';

const client = new snapshot.Client712('https://hub.snapshot.org');

// Створити голосування (підписується кошельком, без транзакції)
await client.proposal(web3, address, {
  space: 'your-dao.eth',
  type: 'single-choice',
  title: 'Прийняти нову стратегію токенів?',
  body: '## Описання\n\nПовне описання пропозиції...',
  choices: ['За', 'Проти', 'Утриматися'],
  start: Math.floor(Date.now() / 1000),
  end: Math.floor(Date.now() / 1000) + 7 * 24 * 3600,
  snapshot: await web3.eth.getBlockNumber(),
  plugins: JSON.stringify({}),
  app: 'your-dao-app'
});

Терміни реалізації

  • Governor + Timelock + Governance Token контракти — 2–3 тижні
  • Frontend (список пропозицій, голосування, делегування) — 2–3 тижні
  • Індексер + повний портал — 1–2 місяці