Compare commits

...

142 Commits

Author SHA1 Message Date
Alex Ant 4ccf2c743c процесс голосования через подпись номера решения 2025-05-12 10:41:37 +05:00
Alex Ant 418d43af58 almost done 2025-05-09 17:31:41 +05:00
Alex Ant 869a75f080 SDK компилируется 2025-05-07 08:23:59 +05:00
Alex Ant c7bc2d1a20 Merge branch 'dev' into document2 2025-05-05 18:56:04 +05:00
Alex Ant 3ea4cd6d73 chore(release): publish 2025-05-05 18:55:34 +05:00
Alex Ant 6a955737e0 update version 2 2025-05-05 18:55:01 +05:00
Alex Ant 51bf49b063 update version 2025-05-05 18:53:25 +05:00
Alex Ant 12468b16c8 Merge branch 'testnet' 2025-05-05 18:50:23 +05:00
Alex Ant 5ebd28d181 откатываем новую таблицу кооперативов 2025-05-05 18:49:08 +05:00
Alex Ant defe482ccd контракты скомпилировались 2025-05-05 18:46:44 +05:00
Alex Ant e99d141f28 before contract migrate 2025-05-05 17:25:56 +05:00
Alex Ant aa0a6731de chore(release): publish 2025-05-05 12:53:42 +05:00
Alex Ant 46f7f10dce coop migration 2025-05-05 12:28:54 +05:00
Alex Ant 552333faf6 chore(release): publish 2025-05-05 11:17:29 +05:00
Alex Ant e23589d4d3 Функционал миграций по версиям с интеграцией блокчейна и двух баз данных 2025-05-04 14:17:27 +05:00
Alex Ant 104b08e1ba chore(release): publish 2025-05-04 12:42:52 +05:00
Alex Ant 1b81cfc0a9 fix workflow #2 2025-05-04 12:42:23 +05:00
Alex Ant 6e51433ae9 update publish workflow 2025-05-04 12:39:52 +05:00
Alex Ant 421f356987 update version 2025-05-04 12:37:53 +05:00
Alex Ant abd9f1931d chore(release): publish 2025-05-04 12:32:16 +05:00
Alex Ant 2b87034abb fix workflows 2025-05-04 12:26:07 +05:00
Alex Ant 8d7c919332 chore(release): publish 2025-05-04 12:08:16 +05:00
Alex Ant 4785ea2886 publish workflow 2025-05-04 12:07:22 +05:00
Alex Ant 4daa06dac1 Обновление структуры signature_info: добавлен идентификатор подписи. Исправлено условие фильтрации истекших решений в ChairmanPlugin. 2025-05-04 11:40:00 +05:00
Alex Ant abc253f47d create document2 format 2025-05-04 11:02:25 +05:00
Alex Ant 5fea2f8f34 chore(release): publish 2025-05-03 16:19:40 +05:00
Alex Ant c29e224f2f Дефолтные конфиги для расширений, фиксы визуалов, микросервис отмены вопроса с повестки 2025-05-03 15:56:08 +05:00
Alex Ant b930543c2b chore(release): publish 2025-05-02 10:40:41 +05:00
Alex Ant 2768d72e90 update 2025-05-01 22:51:07 +05:00
Alex Ant 8ccefe8fac update 2025-05-01 22:46:58 +05:00
Alex Ant c93e59908d update 2025-05-01 22:29:40 +05:00
Alex Ant 22f0fd8a10 update 2025-05-01 22:28:01 +05:00
Alex Ant 8e17d96529 update 2025-05-01 22:23:56 +05:00
Alex Ant 494a164ee8 update 2025-05-01 22:21:00 +05:00
Alex Ant ee28ae1719 update 2025-05-01 22:17:07 +05:00
Alex Ant 3266061359 update 2025-05-01 22:13:38 +05:00
Alex Ant f69d849c4f update lock-file 2025-05-01 21:57:50 +05:00
Alex Ant 2628120e35 update 2025-05-01 21:54:59 +05:00
Alex Ant edf7d9ab62 docs #2 2025-05-01 21:52:49 +05:00
Alex Ant 2095e448e5 docs 2025-05-01 21:50:39 +05:00
Alex Ant beff507f4a Удалены отладочные логи из функций входа и выхода пользователя, а также обновлен способ проверки переменных окружения в функции работы с IndexedDB. 2025-05-01 18:23:56 +05:00
Alex Ant bf4fbfabac update 2025-05-01 16:46:36 +05:00
Alex Ant 2f1d88a74c Добавлены отладочные логи в функции входа и выхода пользователя, а также обновлен способ загрузки переменных окружения в конфигурации Quasar для режима разработки. 2025-05-01 16:00:45 +05:00
Alex Ant b444004f4a Удалены отладочные логи из функции получения переменных окружения и обновлен middleware для инъекции переменных окружения в браузер с использованием ssrMiddleware. 2025-05-01 14:33:41 +05:00
Alex Ant 6862f2881a update 2025-05-01 13:42:00 +05:00
Alex Ant 73afcabee2 Изменен способ определения переменных окружения в конфигурации Quasar: теперь они устанавливаются только для клиентской стороны, если режим не SSR. 2025-05-01 13:27:05 +05:00
Alex Ant b4168a4053 update 2025-05-01 11:34:33 +05:00
Alex Ant 1fe14d5811 update 2025-05-01 11:22:00 +05:00
Alex Ant 89e5c97ef8 update 2025-05-01 11:12:30 +05:00
Alex Ant 258b8304ff update 2025-05-01 11:01:19 +05:00
Alex Ant 69fe9c1348 update 2025-05-01 10:31:01 +05:00
Alex Ant fa4af94fa0 update 2025-05-01 10:29:53 +05:00
Alex Ant 2ac84a6910 update 2025-05-01 10:27:41 +05:00
Alex Ant 3f79cf9a1b update 2025-05-01 10:24:33 +05:00
Alex Ant c155605ca8 update 2025-05-01 09:59:02 +05:00
Alex Ant 80a94f79da update 2025-05-01 09:51:43 +05:00
Alex Ant 89ba6cb356 update 2025-05-01 09:41:37 +05:00
Alex Ant c7bd0326ba Обновление Dockerfile: замена команды установки зависимостей на принудительную, улучшение структуры образа. Изменение конфигурации GitHub Actions для отключения кеширования и упрощения сборки образов. 2025-05-01 09:36:57 +05:00
Alex Ant 2c551a0d9e Оптимизация Dockerfile: добавление этапа сборки для зависимостей, упрощение копирования файлов и улучшение структуры образа. Обновление конфигурации GitHub Actions для сборки и публикации образов с использованием Docker Buildx. 2025-04-30 21:49:16 +05:00
Alex Ant ba103a969e Добавление шагов для отладки в GitHub Actions: вывод последних коммитов, текущей ветки и содержимого компонентов. Обновление комментариев и улучшение сборки образов без кеша. 2025-04-30 21:32:51 +05:00
Alex Ant 0d9177f98f update 2025-04-30 21:29:50 +05:00
Alex Ant 60c32be299 update 2025-04-30 20:54:13 +05:00
Alex Ant 83c107b8b2 Добавление middleware для инъекции переменных окружения в window.__ENV__ и рефакторинг функции получения переменных окружения с учетом различных сред (SSR, SPA). Теперь переменные окружения экспортируются через единую функцию getEnv(). 2025-04-30 20:53:02 +05:00
Alex Ant b6d582fb2c Обновление конфигурации проекта: замена использования переменных окружения на новый модуль env, упрощение Dockerfile, улучшение сборки контейнеров и исправление мелких ошибок в компонентах. 2025-04-30 20:30:42 +05:00
Alex Ant a5818bdc53 update 2025-04-30 18:37:23 +05:00
Alex Ant de0fe5465f update 2025-04-30 18:00:07 +05:00
Alex Ant d43b188a30 update 2025-04-30 17:47:08 +05:00
Alex Ant bfb2be2a72 update 2025-04-30 17:45:28 +05:00
Alex Ant 73c2cd9cb3 update 2025-04-30 17:35:42 +05:00
Alex Ant 61cfc442ef update 2025-04-30 17:33:58 +05:00
Alex Ant 0ed04c2c27 update 2025-04-30 17:29:37 +05:00
Alex Ant 6773509ede update 2025-04-30 17:17:55 +05:00
Alex Ant acd86df785 update 2025-04-30 17:05:31 +05:00
Alex Ant c554b167b3 update 2025-04-30 16:53:55 +05:00
Alex Ant 18cf7b61e3 print env 2025-04-30 16:47:47 +05:00
Alex Ant e42b396a68 VITE_ prefix 2025-04-30 16:39:33 +05:00
Alex Ant c47e61d42a правки SSR проблема рендиринга 2025-04-30 15:55:07 +05:00
Alex Ant 92559370fa modify quasar conf 2025-04-30 12:49:12 +05:00
Alex Ant c3a2ec46b3 update 2025-04-30 11:32:47 +05:00
Alex Ant fe55d23e65 хук на деплой 2025-04-30 10:29:59 +05:00
Alex Ant b0d4f5d542 Добавление сборки и публикации нового Docker-образа для приложения @coopenomics/desktop в workflow. Обновление конфигурации сборки контейнеров. 2025-04-29 23:23:13 +05:00
Alex Ant be48f7a158 Обновление Dockerfile для упрощения сборки с использованием lerna. Добавление новых прокси-файлов для модулей @dicebear/core, @dicebear/collection и email-regex. Обновление зависимостей в package.json и pnpm-lock.yaml. Изменение конфигурации Quasar для оптимизации работы с новыми модулями. 2025-04-29 23:21:10 +05:00
Alex Ant 83bd744100 update workflow 2025-04-29 21:49:48 +05:00
Alex Ant ff1615f7b1 workflow initialization 2025-04-29 21:40:51 +05:00
Alex Ant 696e1a0d2c Merge branch 'main' into dev 2025-04-29 16:32:03 +05:00
Alex Ant 397670473a chore(release): publish 2025-04-29 16:27:09 +05:00
Alex Ant cab8061bc3 Merge branch 'testnet' 2025-04-29 16:21:40 +05:00
Alex Ant 3c2b9bcb4c update script 2025-04-29 16:21:22 +05:00
Alex Ant 7a274b7ab1 update templates 2025-04-29 16:17:58 +05:00
Alex Ant e524244bab Добавление нового поля 'type' в сущность Payment и соответствующие изменения в DTO, схемах и селекторах. Обновление логики обновления статусов платежей с учетом нового поля. Исправление параметров в методах для получения заказов. 2025-04-29 13:36:04 +05:00
Alex Ant 14ecaf259a Добавление нового поля 'coop' в интерфейс Model и обновление схемы валидации для SelectBranchStatement. Обновление логики комбинирования данных в классе Factory для включения данных о кооперативе. Комментарии в стилях инпутов переведены в закомментированный вид. 2025-04-29 12:25:08 +05:00
Alex Ant 749c13dc91 Обновление скриптов публикации и логики миграции. Изменены команды для публикации на продакшн, добавлен новый скрипт publish-prod.sh. Обновлена логика удаления кандидатов в функции миграции и исправлены ссылки на индексы кандидатов в confirmreg.cpp. 2025-04-29 11:05:03 +05:00
Alex Ant ab2ee4cc92 lerna update 2025-04-29 10:16:02 +05:00
Alex Ant 2907352d61 disable meet for temp 2025-04-29 10:11:14 +05:00
Alex Ant 390b995eb6 Добавление новых скриптов для развертывания и обновление интерфейсов для обработки голосования на общем собрании. Обновлены типы данных в интерфейсах и DTO, добавлены новые методы для генерации документов и улучшения функционала. Удалены устаревшие интерфейсы и компоненты, улучшена структура кода для повышения эффективности. 2025-04-28 23:55:55 +05:00
Alex Ant 24b3dd3c60 Удаление устаревших интерфейсов и таблиц, связанных с кошельками. Обновление логики обработки платежей и интерфейсов для работы с новыми типами данных. Улучшение структуры компонентов и интерфейсов для более эффективного взаимодействия с API. Обновление стилей и компонентов пользовательского интерфейса для улучшения визуального восприятия. 2025-04-26 17:14:22 +05:00
Alex Ant 55444a4b72 Обновление интерфейсов и DTO для работы с документами и собраниями. Добавлены новые поля и типы данных, улучшена обработка документов в сервисах. Удалены устаревшие селекторы и обновлены существующие для соответствия новым требованиям. Исправлены типы данных в селекторах и добавлены новые экспорты. 2025-04-25 23:44:32 +05:00
Alex Ant 76854207a7 Сейчас будем переводить сервис документов на агрегатор. Обновление интерфейсов и DTO для обработки документов. Изменены типы полей в интерфейсах DocumentPackageDomainInterface, DocumentRepository и DocumentDomainService для поддержки значений null. Добавлены проверки на наличие данных в DocumentDomainEntity и улучшена обработка документов в DocumentDomainService. Обновлены методы для работы с документами в API и хранилище. 2025-04-23 19:03:18 +05:00
Alex Ant 4fcd700e39 Первичная мобильная верстка страниц стола совета 2025-04-23 12:39:23 +05:00
Alex Ant 05dfcced1b Обновление конфигурации и добавление тестового режима для собраний. Изменен порт для state-history-endpoint, добавлен флаг TEST_MODE в контракте meet, обновлены проверки дат открытия и закрытия собраний. Обновлены интерфейсы и DTO для обработки новых типов данных и улучшения функционала. 2025-04-22 23:23:09 +05:00
Alex Ant 931c366907 Добавление функционала для генерации бюллетеней голосования на общем собрании. Обновлены интерфейсы и DTO для обработки новых типов документов, добавлены методы для генерации бюллетеней и голосования. Исправлены типы данных для идентификаторов вопросов повестки. 2025-04-21 20:29:12 +05:00
Alex Ant 71d35b74d7 Добавление новых методов для подписания решений председателем и секретарем на общем собрании. Удален метод закрытия собрания, обновлены интерфейсы и DTO для обработки новых типов документов и действий. 2025-04-21 16:44:27 +05:00
Alex Ant 21fac5c7df Добавление новых типов и методов для работы с собраниями в модуле общих собраний. Реализованы методы получения данных о собраниях, обновлены интерфейсы и DTO для обработки информации о голосованиях и документах собраний. 2025-04-20 16:41:20 +05:00
Alex Ant 0ba9d55081 Добавление новых входных типов и методов для получения данных о собраниях в модуле общих собраний. Реализованы методы getMeet и getMeets, а также обновлены интерфейсы и DTO для обработки данных. 2025-04-20 12:56:42 +05:00
Alex Ant b5b388e95d Обновление документации и DTO для модуля общих собраний. Добавлены описания для полей в DTO, улучшена структура и добавлены новые типы данных для обработки информации о собраниях и голосованиях. 2025-04-20 11:59:29 +05:00
Alex Ant 9c643395b3 Добавление модуля общих собраний и расширение DTO для документов, включая новые интерфейсы и классы для обработки документов собраний и решений. 2025-04-20 11:39:27 +05:00
Alex Ant b989074170 meet module & extends all documents DTOs 2025-04-18 15:27:35 +05:00
Alex Ant 261f010a49 update release script 2025-04-16 22:03:36 +05:00
Alex Ant af46867939 update releases script 2025-04-16 22:02:08 +05:00
Alex Ant be2355e5c5 generate changelog releases 2025-04-16 21:42:37 +05:00
Alex Ant 8b4a20ed3f make Templates correct 2025-04-16 20:08:50 +05:00
Alex Ant 1ab1e1d3c5 move templates #1 2025-04-16 20:08:24 +05:00
Alex Ant c9aab02aab wtf?! 2025-04-16 20:06:49 +05:00
Alex Ant 0643604778 add meet contract, cooptypes and empty documents templates 2025-04-16 19:58:49 +05:00
Alex Ant fe79f3ff98 desktop bug fixs 2025-04-15 15:57:55 +05:00
Alex Ant f919a14927 remove Env.ts file from desktop and move params to .env 2025-04-15 12:27:29 +05:00
Alex Ant dda389ad75 fix system contract action name 2025-04-15 10:27:53 +05:00
Alex Ant aa42864029 fix contracts build 2025-04-15 10:14:07 +05:00
Alex Ant 41bb17224a coopStore release 2025-04-11 18:29:07 +05:00
Alex Ant fd6f628c43 refactoring desktop 2025-04-10 11:40:14 +05:00
Alex Ant 28ca615d96 claim -> result, result -> assignment 2025-04-06 12:56:55 +05:00
Alex Ant 76203a88d8 before make refactoring 2025-04-06 11:25:29 +05:00
Alex Ant aa891adddf shared actions 2025-04-05 11:36:06 +05:00
Alex Ant ecdac6fff9 loan contract 2025-04-03 18:52:53 +05:00
Alex Ant bcba24ea5e contracts refactoring 2025-04-03 09:36:48 +05:00
Alex Ant 44b1f423cc appStore & medusa component & capital contract (start rework) 2025-03-28 18:42:28 +05:00
Alex Ant 85cc7361d7 refactoring participant widget to page 2025-03-27 19:14:02 +05:00
Alex Ant e5e28ff652 chore(release): publish 2025-03-27 18:13:33 +05:00
Alex Ant 4957182480 update mutation simplification 2025-03-27 17:30:31 +05:00
Alex Ant 84927e943a make participants editable 2025-03-27 14:32:23 +05:00
Alex Ant 0d06114f00 change decision dto and logout on some auth problems 2025-03-26 22:18:12 +05:00
Alex Ant 2654760e16 Merge pull request #201 from coopenomics/kamilocean/sprint-4
Kamilocean/sprint 4
2025-03-26 20:09:37 +03:00
Alex Ant d02e7ba2be README.md for cleos wallet 2025-03-26 18:27:05 +05:00
Alex Ant e18fd94336 make cleos separated component 2025-03-26 18:19:52 +05:00
Alex Ant 03e2410556 make cleos wallet accessable 2025-03-26 13:08:04 +05:00
kamilocean 54a4449e0b Merge branch 'dev' into kamilocean/sprint-4 2025-03-17 16:07:50 +03:00
kamilocean 08c31171a0 WIP: fix EditableActions instead of ActionButton 2025-03-17 16:07:28 +03:00
kamilocean 5253de9279 WIP: add EditableOrganizationCard 2025-03-16 21:04:40 +03:00
Alex Ant 094945e350 make it works 2025-03-14 13:20:41 +05:00
kamilocean eb6b58e6db Merge branch 'dev' into kamilocean/sprint-4 2025-03-13 23:54:25 +03:00
kamilocean 7bcb6e30a7 fix: add Zeus type 2025-03-13 23:54:02 +03:00
kamilocean 44ab386835 WIP: EditableAccountCard 2025-03-13 00:30:00 +03:00
2084 changed files with 67261 additions and 1009638 deletions
Vendored
BIN
View File
Binary file not shown.
+150
View File
@@ -0,0 +1,150 @@
---
description:
globs: components/controller/**
alwaysApply: false
---
# NestJS Controller и Чистая архитектура
## Основные принципы
1. Чистая архитектура - главный архитектурный подход. Пиши код с комментариями.
2. Типы IName, IChecksum256, ITimePointSec - это просто строки.
3. Домен должен быть полностью изолирован от инфраструктурных деталей.
4. Направление зависимостей - внутрь (к ядру, домену).
## Структура проекта
- `domain/` - доменный слой (бизнес-логика, независимая от инфраструктуры)
- `infrastructure/` - инфраструктурный слой (адаптеры к внешним системам)
- `modules/` - слой приложения (DTO, резолверы, сервисы)
## Слои и их взаимодействие
1. **Домен**:
- Содержит чистые доменные интерфейсы и реализованные на них сущности
- НЕ должен зависеть от `cooptypes` (инфраструктурный контракт)
- Использует собственные доменные типы (например, Date вместо строковых timestamp)
- Интерфейсы портов описывают взаимодействие с внешними системами
2. **Инфраструктура**:
- Содержит адаптеры к внешним системам (блокчейн, БД и т.д.)
- Осуществляет преобразование между доменными и инфраструктурными типами
- Общая логика преобразования выносится в утилитарные классы (например, `DomainToBlockchainUtils`)
3. **Модули (приложение)**:
- DTO имплементируют доменные интерфейсы напрямую
- Резолвер вызывает сервис, который принимает DTO
- Сервис передает объекты DTO в интерактор домена
## Поток данных
1. Резолвер принимает входные данные и передает их в сервис
2. Сервис вызывает интерактор домена, передавая ему объекты DTO (имплементирующие доменный интерфейс)
3. Интерактор выполняет бизнес-логику и взаимодействует с портами домена
4. Адаптеры (инфраструктурный слой) преобразуют доменные объекты в формат внешних систем (JSON для хранения мета-данных, ISO для дат и т.д.)
5. Адаптеры возвращают результаты в домен, домен возвращает данные в сервис, который возвращает их в резолвер
## Правила преобразования данных
1. Преобразование DTO → доменный объект: не требуется, если DTO имплементирует доменный интерфейс
2. Преобразование доменный объект → инфраструктурный тип: происходит в адаптерах
3. Преобразование документов, дат и других сложных объектов: используются утилитарные классы уровня инфраструктуры
## Работа с типами данных
1. **Даты**:
- В доменных интерфейсах используется тип `Date`
- В DTO используется тип `Date` с декораторами `@IsDate()` и `@Type(() => Date)`
- В инфраструктурном слое происходит преобразование `Date` → `string` (ISO формат)
```typescript
// Доменный интерфейс
interface MeetDomainInterface {
open_at: Date;
}
// DTO
@Field(() => Date)
@IsDate()
@Type(() => Date)
open_at!: Date;
// Адаптер
const blockchainData = {
open_at: domainToBlockchainUtils.convertDateToBlockchainFormat(data.open_at)
};
```
2. **Документы**:
- В доменных интерфейсах используется собственный тип `SignedDocumentDomainInterface<T>`
- В DTO используется соответствующий DTO-класс (например, `SignedDigitalDocumentInputDTO`)
- В инфраструктурном слое происходит преобразование между форматами (meta-поля в JSON и т.д.)
## Типовые ошибки
1. **Нарушение изоляции домена**: домен должен быть изолирован от инфраструктуры. Не используйте импорты из `cooptypes` в доменных интерфейсах.
```typescript
// Неправильно
import { MeetContract } from 'cooptypes';
export type VoteDomainInterface = MeetContract.Actions.Vote.IInput;
// Правильно
export interface VoteDomainInterface {
coopname: string;
hash: string;
// ... доменные поля
}
```
2. **Преобразование в неправильном слое**: преобразование доменных объектов в инфраструктурные типы должно происходить в адаптерах, а не в доменном слое или сервисе.
```typescript
// Неправильно (в доменном интеракторе)
async vote(data: VoteDomainInterface) {
const blockchainData = { ...data, meta: JSON.stringify(data.meta) };
// ...
}
// Правильно (в адаптере)
async vote(data: VoteDomainInterface) {
const blockchainData = this.convertToBlockchainFormat(data);
// ...
}
```
3. **Дублирование логики преобразования**: общая логика преобразования должна быть вынесена в утилитарные классы.
```typescript
// Неправильно (дублирование в разных адаптерах)
// В MeetAdapter
private convertDoc(doc) { return { ...doc, meta: JSON.stringify(doc.meta) }; }
// В BranchAdapter
private convertDoc(doc) { return { ...doc, meta: JSON.stringify(doc.meta) }; }
// Правильно (общий утилитарный класс)
// DomainToBlockchainUtils
convertSignedDocumentToBlockchainFormat(doc) {
return { ...doc, meta: JSON.stringify(doc.meta) };
}
```
## Примеры
```typescript
// Доменный интерфейс - чистый, без зависимостей от инфраструктуры
export interface VoteOnAnnualGeneralMeetInputDomainInterface {
coopname: string;
hash: string;
member: string;
ballot: VoteItemInputDomainInterface[];
}
// DTO имплементирует доменный интерфейс напрямую
@InputType('VoteOnAnnualGeneralMeetInput')
export class VoteOnAnnualGeneralMeetInputDTO implements VoteOnAnnualGeneralMeetInputDomainInterface {
@Field(() => String)
@IsString()
coopname!: string;
// ... остальные поля
}
// Адаптер преобразует доменный объект в инфраструктурный тип
async vote(data: VoteOnAnnualGeneralMeetInputDomainInterface): Promise<TransactionResult> {
// Преобразуем доменный объект в инфраструктурный тип
const blockchainData: MeetContract.Actions.Vote.IInput = {
coopname: data.coopname,
hash: data.hash,
// ... преобразование других полей
};
// ... отправка данных во внешнюю систему
}
```
@@ -0,0 +1,41 @@
---
description: SDK мутации и запросы для подключения на рабочем столе
globs:
alwaysApply: false
---
Бэкенд реализован здесь components/controller, sdk здесь components/sdk.
Пример создания Query к API через SDK:
``` ts
async function loadBranches(data: IGetBranchesInput): Promise<IBranch[]> {
const { [Queries.Branches.GetBranches.name]: output } = await client.Query(
Queries.Branches.GetBranches.query,
{
variables: {
data
}
}
);
return output;
}
```
Такие запросы обычно хранятся в папке Entities и вызываются из его store.
Пример мутации:
``` ts
async function selectBranch(data: ISelectBranchInput): Promise<boolean>{
const {[Mutations.Branches.SelectBranch.name]: result} = await client.Mutation(Mutations.Branches.SelectBranch.mutation, {variables: {
data
}})
return result
}
```
Мутации обычно храним в папке features.
Как можешь обратить внимание, все мутации и запросы строятся по одному шаблону. Вся необходимая информация уже есть в SDK.
+12
View File
@@ -0,0 +1,12 @@
---
description:
globs:
alwaysApply: true
---
# DESKTOP
- Пишем код фронтенда в архитектуре Feature Sliced Design (FSD).
- Стиль шаблонов PUG на composite API.
- Всегда создаём index.ts файлы для vue компонент.
- Создавай индексные файлы для vue через export {default as NAME} from './where', а на уровне выше, если это необходимо, делай export * from './ui'
+225
View File
@@ -0,0 +1,225 @@
# Архитектура расширений в MonoCoop
## Основные принципы
1. Расширения построены на модулях NestJS с использованием шаблона "Порты и адаптеры"
2. Каждое расширение наследуется от `BaseExtModule` и реализует интерфейс `OnModuleInit`
3. Расширения могут взаимодействовать с блокчейном через соответствующие порты
4. Конфигурации расширений хранятся в БД и описываются с помощью Zod-схем
5. Расширения регистрируются в глобальном реестре `AppRegistry`
## Структура расширения
Минимальная структура расширения включает:
- `XXX-extension.module.ts` - основной модуль расширения
- `package.json` - информация о пакете
- `README.md` - документация
- `INSTALL.md` - инструкции по установке
- `CHANGELOG.md` - история изменений
## Создание нового расширения
1. Создайте директорию для расширения в `components/controller/src/extensions/`
2. Создайте основной класс расширения, наследующийся от `BaseExtModule`
3. Определите Zod-схему для конфигурации
4. Реализуйте метод `initialize()`
5. Зарегистрируйте расширение в `extensions.registry.ts`
6. Добавьте расширение в список дефолтных приложений в `extension-domain.service.ts`
## Пример структуры модуля расширения
```typescript
// XXX-extension.module.ts
export class XXXPlugin extends BaseExtModule {
constructor(...) {
super();
}
name = 'xxx';
plugin!: ExtensionDomainEntity<IConfig>;
public configSchemas = Schema;
async initialize() {
// Инициализация расширения
// Настройка cron-задач
}
}
@Module({
providers: [XXXPlugin],
})
export class XXXPluginModule {
constructor(private readonly xxxPlugin: XXXPlugin) {}
async initialize() {
await this.xxxPlugin.initialize();
}
}
```
## Управление отображением конфигурации
Zod-схемы используются для автоматического отображения формы настроек в интерфейсе пользователя.
Через интерфейс `DeserializedDescriptionOfExtension` из `components/controller/src/types/shared/extension.types.ts`
можно управлять отображением полей формы:
```typescript
export const Schema = z.object({
// Базовое поле с меткой
simpleField: z.string().describe(
describeField({
label: 'Название поля',
note: 'Подсказка под полем'
})
),
// Скрытое поле для служебного использования
hiddenField: z.string().describe(
describeField({
label: 'Скрытое поле',
visible: false
})
),
// Поле с проверкой значения
validatedField: z.number().describe(
describeField({
label: 'Поле с валидацией',
rules: ['val >= 5', 'val <= 100'],
})
),
// Форматированное поле с префиксом и суффиксом
formattedField: z.number().describe(
describeField({
label: 'Форматированное поле',
prepend: '$',
append: 'USD',
})
),
// Многострочное текстовое поле
multilineField: z.string().describe(
describeField({
label: 'Многострочное поле',
maxRows: 5,
minLength: 10,
maxLength: 1000
})
),
});
```
Доступные поля для управления отображением:
- `label` - название поля (обязательное)
- `note` - пояснение или подсказка
- `visible` - видимость поля (по умолчанию true)
- `rules` - правила валидации в виде строковых выражений
- `mask` - маска для ввода
- `fillMask` - автозаполнение маски
- `minLength` / `maxLength` - ограничения длины для текстовых полей
- `maxRows` - количество строк для многострочного ввода
- `append` / `prepend` - текст до/после значения поля
## Взаимодействие с блокчейном
Для взаимодействия с блокчейном:
1. Определите порт в доменном слое (например, `SovietBlockchainPort`)
2. Инжектируйте порт в конструкторе расширения через DI
3. Используйте методы порта для взаимодействия с блокчейном
```typescript
@Inject(SOVIET_BLOCKCHAIN_PORT) private readonly sovietBlockchainPort: SovietBlockchainPort
// ...
const decisions = await this.sovietBlockchainPort.getDecisions(coopname);
```
## Настройка планировщика задач
Расширения могут использовать cron-задачи для периодического выполнения операций:
```typescript
import cron from 'node-cron';
// Регистрация cron-задачи (каждые N минут)
const cronExpression = `*/${this.plugin.config.checkInterval} * * * *`;
cron.schedule(cronExpression, () => {
this.logger.info('Запуск запланированной задачи');
this.runTask();
});
```
## Работа с конфигурацией
1. Определите Zod-схему для конфигурации
2. Используйте `describeField` для добавления UI-метаданных к полям
3. Получайте и обновляйте конфигурацию через репозиторий `extensionRepository`
```typescript
export const Schema = z.object({
checkInterval: z.number().describe(
describeField({
label: 'Интервал проверки (в минутах)',
note: 'Минимум: 5 минут',
rules: ['val >= 5'],
})
),
});
// Обновление конфигурации
this.plugin.config.lastCheckDate = new Date().toISOString();
await this.extensionRepository.update(this.plugin);
```
## Логирование действий
Расширения должны логировать свои действия:
1. Используйте `WinstonLoggerService` для системного логирования
2. Используйте `LogExtensionDomainRepository` для хранения логов в БД
```typescript
// Системное логирование
this.logger.info(`Выполнение операции для ${id}`);
// Сохранение лога в БД
await this.logExtensionRepository.push(this.name, {
type: 'operation',
timestamp: new Date().toISOString(),
data: { ... },
});
```
## Регистрация расширения
После создания расширения, добавьте его в `extensions.registry.ts`:
```typescript
export const AppRegistry: INamedExtension = {
myExtension: {
is_builtin: false,
is_internal: true,
is_available: true,
is_desktop: false,
title: 'Моё расширение',
description: 'Описание функциональности.',
image: 'https://example.com/image.png',
class: MyExtensionPluginModule,
schema: MyExtensionSchema,
tags: ['тег1', 'тег2'],
readme: getReadmeContent('./myExtension'),
instructions: getInstructionsContent('./myExtension'),
},
};
```
## Дефолтные настройки
Добавьте расширение в список дефолтных приложений в `extension-domain.service.ts`:
```typescript
getDefaultApps(): Partial<ExtensionDomainEntity>[] {
return [
// ...
{
name: 'myExtension',
enabled: true,
config: {
// Дефолтные значения конфигурации
parameter1: 'value1',
parameter2: 42,
},
},
// ...
];
}
```
+168
View File
@@ -0,0 +1,168 @@
---
description:
globs: **/controller/src/extensions/**
alwaysApply: false
---
# Архитектура расширений в MonoCoop
## Основные принципы
1. Расширения построены на модулях NestJS с использованием шаблона "Порты и адаптеры"
2. Каждое расширение наследуется от `BaseExtModule` и реализует интерфейс `OnModuleInit`
3. Расширения могут взаимодействовать с блокчейном через соответствующие порты
4. Конфигурации расширений хранятся в БД и описываются с помощью Zod-схем
5. Расширения регистрируются в глобальном реестре `AppRegistry`
## Структура расширения
Минимальная структура расширения включает:
- `XXX-extension.module.ts` - основной модуль расширения
- `package.json` - информация о пакете
- `README.md` - документация
- `INSTALL.md` - инструкции по установке
- `CHANGELOG.md` - история изменений
## Создание нового расширения
1. Создайте директорию для расширения в `components/controller/src/extensions/`
2. Создайте основной класс расширения, наследующийся от `BaseExtModule`
3. Определите Zod-схему для конфигурации
4. Реализуйте метод `initialize()`
5. Зарегистрируйте расширение в `extensions.registry.ts`
6. Добавьте расширение в список дефолтных приложений в `extension-domain.service.ts`
## Пример структуры модуля расширения
```typescript
// XXX-extension.module.ts
export class XXXPlugin extends BaseExtModule {
constructor(...) {
super();
}
name = 'xxx';
plugin!: ExtensionDomainEntity<IConfig>;
public configSchemas = Schema;
async initialize() {
// Инициализация расширения
// Настройка cron-задач
}
// Дополнительные методы расширения
}
@Module({
providers: [XXXPlugin],
})
export class XXXPluginModule {
constructor(private readonly xxxPlugin: XXXPlugin) {}
async initialize() {
await this.xxxPlugin.initialize();
}
}
```
## Взаимодействие с блокчейном
Для взаимодействия с блокчейном:
1. Определите порт в доменном слое (например, `SovietBlockchainPort`)
2. Инжектируйте порт в конструкторе расширения через DI
3. Используйте методы порта для взаимодействия с блокчейном
```typescript
@Inject(SOVIET_BLOCKCHAIN_PORT) private readonly sovietBlockchainPort: SovietBlockchainPort
// ...
const decisions = await this.sovietBlockchainPort.getDecisions(coopname);
```
## Настройка планировщика задач
Расширения могут использовать cron-задачи для периодического выполнения операций:
```typescript
import cron from 'node-cron';
// Регистрация cron-задачи (каждые N минут)
const cronExpression = `*/${this.plugin.config.checkInterval} * * * *`;
cron.schedule(cronExpression, () => {
this.logger.info('Запуск запланированной задачи');
this.runTask();
});
```
## Работа с конфигурацией
1. Определите Zod-схему для конфигурации
2. Используйте `describeField` для добавления UI-метаданных к полям
3. Получайте и обновляйте конфигурацию через репозиторий `extensionRepository`
```typescript
export const Schema = z.object({
checkInterval: z.number().describe(
describeField({
label: 'Интервал проверки (в минутах)',
note: 'Минимум: 5 минут',
rules: ['val >= 5'],
})
),
});
// Обновление конфигурации
this.plugin.config.lastCheckDate = new Date().toISOString();
await this.extensionRepository.update(this.plugin);
```
## Логирование действий
Расширения должны логировать свои действия:
1. Используйте `WinstonLoggerService` для системного логирования
2. Используйте `LogExtensionDomainRepository` для хранения логов в БД
```typescript
// Системное логирование
this.logger.info(`Выполнение операции для ${id}`);
// Сохранение лога в БД
await this.logExtensionRepository.push(this.name, {
type: 'operation',
timestamp: new Date().toISOString(),
data: { ... },
});
```
## Регистрация расширения
После создания расширения, добавьте его в `extensions.registry.ts`:
```typescript
export const AppRegistry: INamedExtension = {
myExtension: {
is_builtin: false,
is_internal: true,
is_available: true,
is_desktop: false,
title: 'Моё расширение',
description: 'Описание функциональности.',
image: 'https://example.com/image.png',
class: MyExtensionPluginModule,
schema: MyExtensionSchema,
tags: ['тег1', 'тег2'],
readme: getReadmeContent('./myExtension'),
instructions: getInstructionsContent('./myExtension'),
},
};
```
## Дефолтные настройки
Добавьте расширение в список дефолтных приложений в `extension-domain.service.ts`:
```typescript
getDefaultApps(): Partial<ExtensionDomainEntity>[] {
return [
// ...
{
name: 'myExtension',
enabled: true,
config: {
// Дефолтные значения конфигурации
parameter1: 'value1',
parameter2: 42,
},
},
// ...
];
}
```
+59
View File
@@ -0,0 +1,59 @@
---
description:
globs: components/sdk/**
alwaysApply: false
---
# Руководство по работе с GraphQL Zeus в SDK
## Основной процесс
1. **Анализ DTO бэкенда**:
- Изучите структуру DTO классов (`@ObjectType`) в бэкенде
- Обратите внимание на имена типов в декораторах `@ObjectType('ИмяТипа')`
- Отметьте поля, связи и вложенные объекты
2. **Создание селекторов**:
- Для каждого DTO создайте соответствующий селектор с именем `raw<ИмяТипа>Selector`
- Селектор - это объект, где ключи соответствуют полям DTO, а значения - `true`
- Для вложенных объектов используйте вложенные селекторы: `field: nestedSelector`
- Для списков используйте один селектор без массива: `items: itemSelector`
3. **Валидация селекторов**:
- Для каждого селектора создайте проверку типа:
```typescript
const _validate: MakeAllFieldsRequired<ValueTypes['ТочноеИмяГрафКьЭлТипа']> = rawSelector
```
- Имя типа должно точно совпадать с именем в декораторе `@ObjectType`
4. **Экспорт селекторов**:
- Создайте финальный селектор с помощью функции `Selector`:
```typescript
export const typeSelector = Selector('ТочноеИмяГрафКьЭлТипа')(rawTypeSelector)
```
- Экспортируйте сырой селектор для переиспользования
- Экспортируйте тип модели: `export type modelType = ModelTypes['ТочноеИмяГрафКьЭлТипа']`
5. **Создание запросов/мутаций**:
- Используйте селекторы в запросах и мутациях:
```typescript
export const query = Selector('Query')({
queryName: [{ data: $('data', 'ТочноеИмяВходногоТипа!') }, exportedSelector]
})
```
- Для параметров используйте оператор `$` с точным именем входного типа
- Создайте интерфейс входных данных:
```typescript
export interface IInput {
data: ModelTypes['ТочноеИмяВходногоТипа']
}
```
## Особенности работы
- **Документы**: всегда сохраняйте структуру `{ hash, signatures, rawDocument }`
- **Сложные DTO**: разбивайте на атомарные селекторы и комбинируйте их
- **Типы в Zeus**: часто отличаются от имен классов в бэкенде, всегда проверяйте в `schema.gql`
- **Массивы**: Zeus автоматически обрабатывает массивы, не используйте `[selector]`
Это руководство поможет правильно структурировать работу с SDK и избежать типичных ошибок при работе с Zeus.
+94
View File
@@ -0,0 +1,94 @@
name: Build Docker Images
on:
push:
branches:
- testnet
tags:
- '*'
jobs:
build:
runs-on: ubuntu-latest
steps:
- name: Checkout repository
uses: actions/checkout@v3
with:
ref: testnet
fetch-depth: 0
- name: Debug info
run: |
echo "Текущая ветка:"
git branch --show-current
echo "Последние коммиты:"
git log -n 3 --oneline
echo "Проверяем файлы в директории components/desktop/src-ssr:"
ls -la components/desktop/src-ssr/ || echo "Директория не найдена!"
echo "Проверяем файлы в middlewares:"
ls -la components/desktop/src-ssr/middlewares/ || echo "Директория middlewares не найдена!"
- name: Set docker tag
run: |
if [[ $GITHUB_REF == refs/tags/* ]]; then
echo "DOCKER_TAG=${GITHUB_REF#refs/tags/}" >> $GITHUB_ENV
else
echo "DOCKER_TAG=latest" >> $GITHUB_ENV
fi
- name: Login to DockerHub
uses: docker/login-action@v2
with:
username: ${{ secrets.DOCKERHUB_USERNAME }}
password: ${{ secrets.DOCKERHUB_TOKEN }}
# Сначала собираем базовый образ с runtime
- name: Build base image
run: |
docker build --target runtime -t dicoop/mono-base:${{ env.DOCKER_TAG }} .
docker push dicoop/mono-base:${{ env.DOCKER_TAG }}
# Создаем сервисные образы на основе базового
- name: Build desktop image
run: |
echo "FROM dicoop/mono-base:${{ env.DOCKER_TAG }}" > Dockerfile.desktop
echo "CMD [\"pnpm\", \"-F\", \"@coopenomics/desktop\", \"run\", \"start\"]" >> Dockerfile.desktop
docker build -t dicoop/desktop:${{ env.DOCKER_TAG }} -f Dockerfile.desktop .
docker push dicoop/desktop:${{ env.DOCKER_TAG }}
- name: Build controller image
run: |
echo "FROM dicoop/mono-base:${{ env.DOCKER_TAG }}" > Dockerfile.coopback
echo "CMD [\"pnpm\", \"-F\", \"@coopenomics/controller\", \"run\", \"start\"]" >> Dockerfile.coopback
docker build -t dicoop/coopback:${{ env.DOCKER_TAG }} -f Dockerfile.coopback .
docker push dicoop/coopback:${{ env.DOCKER_TAG }}
- name: Build parser image
run: |
echo "FROM dicoop/mono-base:${{ env.DOCKER_TAG }}" > Dockerfile.cooparser
echo "CMD [\"pnpm\", \"-F\", \"@coopenomics/parser\", \"run\", \"start\"]" >> Dockerfile.cooparser
docker build -t dicoop/cooparser:${{ env.DOCKER_TAG }} -f Dockerfile.cooparser .
docker push dicoop/cooparser:${{ env.DOCKER_TAG }}
- name: Build notificator image
run: |
echo "FROM dicoop/mono-base:${{ env.DOCKER_TAG }}" > Dockerfile.notificator
echo "CMD [\"pnpm\", \"-F\", \"coop-notificator\", \"run\", \"start\"]" >> Dockerfile.notificator
docker build -t dicoop/notificator:${{ env.DOCKER_TAG }} -f Dockerfile.notificator .
docker push dicoop/notificator:${{ env.DOCKER_TAG }}
# Отправка хука для деплоя
- name: Trigger deployment webhook
if: ${{ success() }}
run: |
if [[ $GITHUB_REF == refs/tags/* ]]; then
# Хук для продакшена
curl -X POST ${{ vars.PRODUCTION_WEBHOOK_URL }} \
-H 'Content-Type: application/json' \
-d '${{ env.DOCKER_TAG }}'
else
# Хук для тестнета
curl -X POST ${{ vars.TESTNET_WEBHOOK_URL }} \
-H 'Content-Type: application/json' \
-d '${{ env.DOCKER_TAG }}'
fi
+93
View File
@@ -0,0 +1,93 @@
name: Publish Docs
on:
push:
branches:
- main
jobs:
build-and-publish-docs:
runs-on: ubuntu-latest
steps:
- name: Checkout repository
uses: actions/checkout@v3
- name: Set up Node.js
uses: actions/setup-node@v3
with:
node-version: 20
- name: Set up Python
uses: actions/setup-python@v4
with:
python-version: '3.10'
- name: Install pnpm
run: npm install -g pnpm
- name: Install Python requirements
run: |
python -m venv venv
source venv/bin/activate
pip install mkdocs-material mkdocs-macros-plugin mkdocs-section-index pymdown-extensions
working-directory: ./components/docs
- name: Install Node.js dependencies
run: pnpm install
working-directory: ./components/docs
- name: Patch spectaql-config.yml for CI
run: |
sed -i.bak "0,/url:.*/s|url:.*|url: 'https://testnet.coopenomics.world/backend/v1/graphql'|" spectaql-config.yml
working-directory: ./components/controller
- name: Show patched spectaql-config.yml
run: cat spectaql-config.yml
working-directory: ./components/controller
- name: Build cooptypes
run: pnpm run build
working-directory: ./components/cooptypes
- name: Generate controller docs
run: pnpm run docs
working-directory: ./components/controller
- name: Copy controller docs
run: |
mkdir -p ./components/docs/docs/graphql
cp -r ./components/controller/docs/* ./components/docs/docs/graphql/
- name: Generate sdk docs
run: pnpm run docs
working-directory: ./components/sdk
- name: Copy sdk docs
run: |
mkdir -p ./components/docs/docs/sdk
cp -r ./components/sdk/docs/* ./components/docs/docs/sdk/
- name: Generate cooptypes docs
run: pnpm run docs
working-directory: ./components/cooptypes
- name: Copy cooptypes docs
run: |
mkdir -p ./components/docs/docs/cooptypes
cp -r ./components/cooptypes/docs/* ./components/docs/docs/cooptypes/
- name: Build docs (mkdocs)
run: |
source venv/bin/activate
mkdocs build
working-directory: ./components/docs
- name: Publish to GitHub Pages
run: npx gh-pages --nojekyll -d site --repo https://x-access-token:${GITHUB_TOKEN}@github.com/coopenomics/mono.git
working-directory: ./components/docs
env:
GIT_AUTHOR_NAME: github-actions
GIT_AUTHOR_EMAIL: github-actions@github.com
GIT_COMMITTER_NAME: github-actions
GIT_COMMITTER_EMAIL: github-actions@github.com
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
+33
View File
@@ -0,0 +1,33 @@
name: Publish Packages
on:
push:
tags:
- '*'
jobs:
build-and-publish:
runs-on: ubuntu-latest
steps:
- name: Checkout repository
uses: actions/checkout@v3
- name: Set up Node.js
uses: actions/setup-node@v3
with:
node-version: 20
registry-url: 'https://registry.npmjs.org'
- name: Install pnpm
run: npm install -g pnpm
- name: Install dependencies
run: pnpm install
- name: Build all packages
run: pnpm lerna run build
- name: Publish to npm
env:
NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }}
run: pnpm lerna publish from-package --yes --no-verify-access
+4 -2
View File
@@ -1,5 +1,7 @@
node_modules/
lerna-debug.log
components/controller/graph.png
wallet-data/
blockchain-data/
blockchain-data/
scripts/changelog-prompt.md
scripts/changelog-release.md
scripts/release-info.md
+5 -3
View File
@@ -4,11 +4,13 @@
"editor.formatOnSave": true,
"editor.tabCompletion": "onlySnippets",
"editor.defaultFormatter": "esbenp.prettier-vscode",
"editor.codeActionsOnSave": ["source.fixAll.eslint"],
"editor.codeActionsOnSave": {
"source.fixAll.eslint":"explicit"
},
"eslint.run": "onType",
"eslint.validate": ["javascript", "typescript", "vue"],
// "typescript.tsdk": "node_modules/typescript/lib",
"i18n-ally.localesPaths": ["src/i18n"],
"typescript.format.enable": true,
"typescript.format.indentSwitchCase": false,
"typescript.validate.enable": true,
"typescript.validate.enable": true
}
+55
View File
@@ -1,8 +1,63 @@
# v2025.5.2
В этом релизе рабочие столы переведены на серверный рендеринг, что улучшает стабильность развертывания и упрощает автоматизацию поставки ПО. Данный релиз является подготовительным к переходу на новый стандарт цифровых документов на платформе.
✨ Новые функции
- [#245](https://github.com/coopenomics/mono/issues/245): Перевод десктопа на серверный рендеринг с поддержкой динамических переменных окружения
🐛 Исправления ошибок
- [#247](https://github.com/coopenomics/mono/issues/247): Исправлен баг с повторной поставкой ПО при обрывах соединения между серверами
🔧 Улучшения
- [#246](https://github.com/coopenomics/mono/issues/246): Перевод CI/CD на сборку и поставку предсобранных докер-контейнеров
#releases
---
# MONO v2025.4.29
В этом релизе реализована новая архитектура рабочих столов с установкой через маркетплейс. Добавлены стол пайщика и стол совета, переработаны разделы документов и подписей, улучшено разделение кошелька и профиля для повышения удобства пользователей.
✨ Новые функции
- [#234](https://github.com/coopenomics/mono/issues/234): Маркетплейс рабочих столов с поддержкой разных ролей и микросервисной архитектурой
- [#238](https://github.com/coopenomics/mono/issues/238): Контроллер общего собрания пайщиков с поддержкой документооборота и подписей
- [#233](https://github.com/coopenomics/mono/issues/233): Минимальный смарт-контракт общих собраний пайщиков
- [#232](https://github.com/coopenomics/mono/issues/232): Бэкенд полного обозревателя блоков
🐛 Исправления ошибок
- [#231](https://github.com/coopenomics/mono/issues/231): Исправления ошибок регистрации, выхода из системы, отображения платежей и редактирования организации
🔧 Улучшения
- [#243](https://github.com/coopenomics/mono/issues/243): Контроль прав доступа на получении документов пайщика
- [#242](https://github.com/coopenomics/mono/issues/242): Бесконечный скролл на документах пайщика и кооператива
- [#241](https://github.com/coopenomics/mono/issues/241): Раздел "Документы" для пайщика
- [#240](https://github.com/coopenomics/mono/issues/240): Множественные подписи на одном документе
- [#239](https://github.com/coopenomics/mono/issues/239): Последовательные методы подписи протокола общего собрания
- [#237](https://github.com/coopenomics/mono/issues/237): Мобильная вёрстка на страницах стола совета
- [#236](https://github.com/coopenomics/mono/issues/236): Пересобран лендинг для MONO
- [#235](https://github.com/coopenomics/mono/issues/235): Настроен флоу гитхаб-релизов с описаниями
- [#226](https://github.com/coopenomics/mono/issues/226): Встроено редактирование пайщиков
- [#224](https://github.com/coopenomics/mono/issues/224): Добавлено ТЗ по контракту капитализации
---
# Change Log
All notable changes to this project will be documented in this file.
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
## [2.2.10](https://github.com/coopenomics/mono/compare/v2.2.9...v2.2.10) (2025-03-27)
### Bug Fixes
* add Zeus type ([7bcb6e3](https://github.com/coopenomics/mono/commit/7bcb6e30a77b0ab89c5293188b58f08f19c8761e))
## [2.2.9](https://github.com/coopenomics/mono/compare/v2.2.8...v2.2.9) (2025-03-12)
**Note:** Version bump only for package monocoop
+34 -1
View File
@@ -1,10 +1,43 @@
FROM node:18-alpine
FROM node:20-alpine AS builder
WORKDIR /app
# Сразу копируем все файлы
COPY . .
# Устанавливаем инструменты
RUN npm install -g pnpm lerna
# Установка зависимостей
# Используем версию pnpm, совместимую с существующим lock-файлом
RUN pnpm install
# Установка системных зависимостей для WeasyPrint
RUN apk add --no-cache \
python3 \
py3-pip \
gcc \
musl-dev \
python3-dev \
pango \
zlib-dev \
jpeg-dev \
openjpeg-dev \
g++ \
libffi-dev \
harfbuzz-subset \
&& python3 -m venv /venv \
&& /venv/bin/pip install WeasyPrint==62.3 \
&& rm -rf /var/cache/*
# Сборка всех компонентов
RUN lerna run build
# Финальный образ
FROM builder AS runtime
# Настройка переменных окружения
ENV PATH="/venv/bin:$PATH"
# Проверка WeasyPrint
RUN weasyprint --version
+46
View File
@@ -80,6 +80,52 @@ pnpm run dev:backend
pnpm run dev:desktop
```
### Кошелёк
Для работы с кошельком блокчейна используется утилита cleos, которая позволяет извлекать таблицы смарт-контрактов и отправлять транзакции в блокчейн если это требуется.
Для работы с командным кошельком `cleos` локально необходимо чтобы инфраструктура была поднята:
```
docker compose up -d
```
Запускаем контейнер с кошельком и входим в него командой:
```
pnpm run cleos
```
В кошельке уже находится дефолтный ключ для работы с локальной средой. Этот ключ зашифрован паролем. Пароль хранится в файле `password` и используется автоматически при разблокировке. Для разблокировки кошелька, находясь в контейнере выполняем:
```
./unlock.sh
```
Для использования кошелька выполняем:
```
./cleos.sh <command>
```
Для получения полного списка команд вызываем кошелек без команд:
```
./cleos.sh
```
Например, для получения информации о текущем состоянии блокчейна:
```
./cleos.sh get info
```
### Возможные проблемы
В случае, если при выполнении ./unlock.sh возникает проблема:
`Unable to connect to keosd, if keosd is running please kill the process and try again`, то выполните команду:
```
./reset.sh
```
Данная команда удалит созданный ранее сокет кошелька, после чего, выполните ./unlock.sh повторно.
## Лицензия
Продукт Потребительского Кооператива "ВОСХОД" распространяется по лицензии BY-NC-SA 4.0.
File diff suppressed because one or more lines are too long
BIN
View File
Binary file not shown.
+1 -1
View File
@@ -2,7 +2,7 @@ EOSIO_PUB_KEY=EOS6MRyAjQq8ud7hVNYcfnVPJqcVpscN5So8BhtHuGYqET5GDW5CV
EOSIO_PRV_KEY=5KQwrPbwdL6PhXujxW37FSSQZ1JiwsST4cqQzDeyXtP79zkvFD3
DATADIR=blockchain-data
BPACCOUNT=eosio
PASSWORD=PASSWORD
PASSWORD=PW5JGe4WsTPGrjnMzkGd4wfVdzoHCEySgbyq2WBWGAxSfevbXqAG4
SERVER_SECRET=SECRET
SERVER_URL=http://127.0.0.1:2998
MONGO_URI=mongodb://127.0.0.1:27017/cooperative-x
+8
View File
@@ -3,6 +3,14 @@
All notable changes to this project will be documented in this file.
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
## [2.2.10](https://github.com/coopenomics/mono/compare/v2.2.9...v2.2.10) (2025-03-27)
**Note:** Version bump only for package @coopenomics/boot
## [2.2.9](https://github.com/coopenomics/mono/compare/v2.2.8...v2.2.9) (2025-03-12)
**Note:** Version bump only for package @coopenomics/boot
+4 -1
View File
@@ -1,7 +1,7 @@
{
"name": "@coopenomics/boot",
"type": "module",
"version": "2.2.9",
"version": "2025.5.5-2",
"private": true,
"packageManager": "pnpm@9.0.6",
"description": "",
@@ -11,6 +11,9 @@
"scripts": {
"enter": "./scripts/enter.sh",
"cli": "esno src/index.ts",
"deploy": "esno src/index.ts deploy",
"cleos": "esno src/index.ts cleos",
"unlock": "esno src/index.ts unlock",
"boot": "esno src/index.ts boot",
"clear": "esno src/index.ts clear",
"start": "./scripts/restart.sh",
+37 -65
View File
@@ -4,6 +4,7 @@ import { JsSignatureProvider } from 'eosjs/dist/eosjs-jssig'
import { Api, JsonRpc, Serialize } from 'eosjs'
import {
DraftContract,
GatewayContract,
RegistratorContract,
SovietContract,
SystemContract,
@@ -513,8 +514,8 @@ export default class Blockchain {
console.log('Новый кооператив пре-иниализирован: ', params)
}
// TODO change registerOrganization to registerCooperative
async registerOrganization(
// TODO change registerCooperative to registerCooperative
async registerCooperative(
params: RegistratorContract.Actions.RegisterCooperative.IRegisterCooperative,
) {
await this.update_pass_instance()
@@ -573,7 +574,7 @@ export default class Blockchain {
)
}
async registerAccount2(
async createAccount(
params: RegistratorContract.Actions.CreateAccount.ICreateAccount,
) {
await this.update_pass_instance()
@@ -586,7 +587,7 @@ export default class Blockchain {
name: RegistratorContract.Actions.CreateAccount.actionName,
authorization: [
{
actor: params.registrator,
actor: params.coopname,
permission: 'active',
},
],
@@ -618,7 +619,7 @@ export default class Blockchain {
name: RegistratorContract.Actions.RegisterUser.actionName,
authorization: [
{
actor: params.registrator,
actor: params.coopname,
permission: 'active',
},
],
@@ -800,36 +801,39 @@ export default class Blockchain {
async exec(params: SovietContract.Actions.Decisions.Exec.IExec) {
await this.update_pass_instance()
await this.api.transact(
{
actions: [
{
account: SovietContract.contractName.production,
name: SovietContract.Actions.Decisions.Exec.actionName,
authorization: [
{
actor: params.executer,
permission: 'active',
try {
await this.api.transact(
{
actions: [
{
account: SovietContract.contractName.production,
name: SovietContract.Actions.Decisions.Exec.actionName,
authorization: [
{
actor: params.executer,
permission: 'active',
},
],
data: {
...params,
},
],
data: {
...params,
},
},
],
},
{
blocksBehind: 3,
expireSeconds: 30,
},
)
],
},
{
blocksBehind: 3,
expireSeconds: 30,
},
)
}
catch (e) {
console.dir(e, { depth: null })
}
console.log('Решение исполнено: ', params)
}
async joinCoop(
params: RegistratorContract.Actions.JoinCooperative.IJoinCooperative,
async ConfirmPayment(
params: GatewayContract.Actions.CompleteIncome.ICompeteIncome,
) {
await this.update_pass_instance()
@@ -837,11 +841,11 @@ export default class Blockchain {
{
actions: [
{
account: RegistratorContract.contractName.production,
name: RegistratorContract.Actions.JoinCooperative.actionName,
account: GatewayContract.contractName.production,
name: GatewayContract.Actions.CompleteIncome.actionName,
authorization: [
{
actor: params.registrator,
actor: params.coopname,
permission: 'active',
},
],
@@ -985,36 +989,4 @@ export default class Blockchain {
console.log('Программа установлена: ', params)
}
async makeCoagreement(
params: SovietContract.Actions.Agreements.MakeCoagreement.IMakeCoagreement,
) {
await this.update_pass_instance()
await this.api.transact(
{
actions: [
{
account: SovietContract.contractName.production,
name: SovietContract.Actions.Agreements.MakeCoagreement.actionName,
authorization: [
{
actor: params.administrator,
permission: 'active',
},
],
data: {
...params,
},
},
],
},
{
blocksBehind: 3,
expireSeconds: 30,
},
)
console.log('Программа установлена: ', params)
}
}
+1 -1
View File
@@ -32,7 +32,7 @@ max-block-net-usage-threshold-bytes = 1024
verbose-http-errors = true
chain-state-history = true
trace-history = true
state-history-endpoint = 0.0.0.0:8080
state-history-endpoint = 0.0.0.0:8070
resource-monitor-space-threshold = 99
resource-monitor-not-shutdown-on-threshold-exceeded = true
wasm-runtime = eos-vm
+15
View File
@@ -75,4 +75,19 @@ export default [
path: path.resolve(process.cwd(), '../contracts/build/contracts/capital'),
target: 'capital',
},
{
name: 'wallet',
path: path.resolve(process.cwd(), '../contracts/build/contracts/wallet'),
target: 'wallet',
},
{
name: 'loan',
path: path.resolve(process.cwd(), '../contracts/build/contracts/loan'),
target: 'loan',
},
{
name: 'meet',
path: path.resolve(process.cwd(), '../contracts/build/contracts/meet'),
target: 'meet',
},
]
+12
View File
@@ -87,6 +87,18 @@ export default {
name: 'capital',
code_permissions_to: ['capital'],
},
{
name: 'loan',
code_permissions_to: ['loan'],
},
{
name: 'meet',
code_permissions_to: ['meet'],
},
{
name: 'wallet',
code_permissions_to: ['wallet'],
},
{
name: 'soviet',
code_permissions_to: ['soviet'],
+13 -9
View File
@@ -3,19 +3,23 @@ import { promisify } from 'node:util'
const execAsync = promisify(exec)
export async function execCommand(command: string[]): Promise<string> {
const fullCmd = ['docker', 'compose', 'exec', '-T', 'node', ...command].join(' ')
export async function execCommand(command: string[]): Promise<void> {
const fullCmd = ['docker', 'compose', 'exec', 'node', ...command].join(' ')
try {
// eslint-disable-next-line node/prefer-global/process
const { stdout, stderr } = await execAsync(fullCmd, { env: process.env })
if (stderr) {
console.error(stderr)
}
return stdout.trim()
if (stdout)
console.log(stdout.trim())
if (stderr)
console.error(stderr.trim())
}
catch (error: any) {
console.error('Command failed:', error.stderr || error)
throw error
catch (err: any) {
if (err.stdout)
console.log(err.stdout.trim())
if (err.stderr)
console.error(err.stderr.trim())
// опционально:
// console.error(`Command failed with code ${err.code}`)
}
}
+8
View File
@@ -6,6 +6,14 @@ export async function clearDB(): Promise<void> {
// eslint-disable-next-line node/prefer-global/process
await mongoose.connect(process.env.MONGO_URI as string)
try {
await mongoose.connection.collection('users').deleteMany({})
console.log('Все документы удалены из коллекции users')
}
catch (e) {
console.error('Ошибка при удалении:', e)
}
try {
await mongoose.connection.collection('sync').deleteMany({})
console.log('Все документы удалены из коллекции sync')
+3 -9
View File
@@ -31,17 +31,11 @@ program.version('0.1.0')
// Команда для запуска команды в контейнере
program
.command('cleos <cmd...>')
.command('cleos [cmd...]')
.description('Execute a cleos command in a Node container')
.allowUnknownOption()
.action(async (cmd: string[]) => {
try {
console.log(cmd)
await execCommand(['cleos', ...cmd])
}
catch (error) {
console.error('Command execution failed:', error)
}
.action(async (cmd: string[] = []) => {
await execCommand(['cleos', ...cmd])
})
// Команда для запуска команды в контейнере
+25 -71
View File
@@ -6,6 +6,7 @@ import type { Account, Contract, Keys } from '../types'
import config, { GOVERN_SYMBOL, SYMBOL } from '../configs'
import Blockchain from '../blockchain'
import { sendPostToCoopbackWithSecret, sleep } from '../utils'
import { generateRandomSHA256 } from '../utils/randomHash'
const test_hash
= '157192b276da23cc84ab078fc8755c051c5f0430bf4802e55718221e6b76c777'
@@ -46,48 +47,6 @@ export class CooperativeClass {
})
}
async createAgreements(coopname: string) {
// console.log('создаём кооперативное соглашение/положение по кошельку')
await this.blockchain.makeCoagreement({
coopname,
administrator: coopname,
type: 'wallet',
draft_id: TCooperative.Registry.WalletAgreement.registry_id,
program_id: 1,
})
await this.blockchain.makeCoagreement({
coopname,
administrator: coopname,
type: 'signature',
draft_id: TCooperative.Registry.RegulationElectronicSignature.registry_id,
program_id: 0,
})
await this.blockchain.makeCoagreement({
coopname,
administrator: coopname,
type: 'user',
draft_id: TCooperative.Registry.UserAgreement.registry_id,
program_id: 0,
})
await this.blockchain.makeCoagreement({
coopname,
administrator: coopname,
type: 'privacy',
draft_id: TCooperative.Registry.PrivacyPolicy.registry_id,
program_id: 0,
})
await this.blockchain.makeCoagreement({
coopname,
administrator: coopname,
type: 'coopenomics',
draft_id: TCooperative.Registry.CoopenomicsAgreement.registry_id,
program_id: 0,
})
}
async createCooperative(username: string, keys?: Keys) {
const account = await this.blockchain.generateKeypair(
username,
@@ -96,8 +55,7 @@ export class CooperativeClass {
)
console.log('Регистрируем аккаунт')
await this.blockchain.registerAccount2({
registrator: config.provider,
await this.blockchain.createAccount({
coopname: config.provider,
referer: '',
username: account.username,
@@ -106,40 +64,22 @@ export class CooperativeClass {
})
console.log('Регистрируем аккаунт как пользователя')
const registration_hash = generateRandomSHA256()
await this.blockchain.registerUser({
registrator: config.provider,
coopname: config.provider,
braname: '',
username: account.username,
type: 'organization',
})
console.log('Переводим аккаунт в организации')
await this.blockchain.registerOrganization({
username: account.username,
coopname: account.username,
params: {
is_cooperative: true,
coop_type: 'conscoop',
announce: 'Тестовый кооператив',
description: 'Тестовое описание',
initial: `100.0000 ${config.token.govern_symbol}`,
minimum: `300.0000 ${config.token.govern_symbol}`,
org_initial: `1000.0000 ${config.token.govern_symbol}`,
org_minimum: `3000.0000 ${config.token.govern_symbol}`,
},
document,
statement: document,
registration_hash,
})
console.log('Отправляем заявление на вступление')
await this.blockchain.joinCoop({
registrator: config.provider_chairman,
await this.blockchain.ConfirmPayment({
coopname: config.provider,
username: account.username,
document,
braname: '',
income_hash: registration_hash,
})
console.log('Голосуем по решению в провайдере')
@@ -182,9 +122,23 @@ export class CooperativeClass {
},
})
console.log('создаём программы и соглашения новому кооперативу')
// await this.createPrograms(username)
await this.createAgreements(username)
console.log('Переводим аккаунт в кооператив')
await this.blockchain.registerCooperative({
username: account.username,
coopname: account.username,
params: {
is_cooperative: true,
coop_type: 'conscoop',
announce: 'Тестовый кооператив',
description: 'Тестовое описание',
initial: `100.0000 ${config.token.govern_symbol}`,
minimum: `300.0000 ${config.token.govern_symbol}`,
org_initial: `1000.0000 ${config.token.govern_symbol}`,
org_minimum: `3000.0000 ${config.token.govern_symbol}`,
},
document,
})
console.log('Переводим инициализационные токены')
await this.blockchain.transfer({ from: 'eosio', to: username, quantity: `100.0000 ${SYMBOL}`, memo: '' })
+3 -4
View File
@@ -157,7 +157,7 @@ export async function startInfra() {
position: 'Председатель',
based_on: 'Решение общего собрания №1',
},
country: 'Russia',
country: 'Российская Федерация',
city: 'Москва',
fact_address: '117593 г. Москва, муниципальный округ Ясенево, проезд Соловьиный, дом 1, помещение 1/1',
full_address:
@@ -202,7 +202,7 @@ export async function startInfra() {
first_name: 'Иван',
last_name: 'Иванов',
middle_name: 'Иванович',
birthdate: '2023-04-01',
birthdate: '1990/04/01',
phone: '+71234567890',
email: 'ivanov@example.com',
full_address: 'Переулок Правды д. 1',
@@ -210,7 +210,7 @@ export async function startInfra() {
series: 7122,
number: 112233,
issued_by: 'отделом УФМС по г. Москва',
issued_at: '22.04.2010',
issued_at: '2010/05/10',
code: '111-232',
},
}
@@ -316,7 +316,6 @@ export async function startInfra() {
const cooperative = new CooperativeClass(blockchain)
await cooperative.createAgreements(config.provider)
await cooperative.createPrograms(config.provider)
console.log(`Арендуем ресурсы провайдеру`)
+3 -4
View File
@@ -28,7 +28,7 @@ export class CooperativeClass {
this.blockchain = blockchain
}
async createParticipant(username: string, keys?: Keys) {
async addUser(username: string, keys?: Keys) {
const account = await this.blockchain.generateKeypair(
username,
keys,
@@ -37,7 +37,6 @@ export class CooperativeClass {
console.log('Регистрируем аккаунт')
const data: RegistratorContract.Actions.AddUser.IAddUser = {
registrator: config.provider,
coopname: config.provider,
referer: '',
username: account.username,
@@ -115,12 +114,12 @@ export class CooperativeClass {
}
}
export async function createParticipant(username: string) {
export async function addUser(username: string) {
// инициализируем инстанс с ключами
const blockchain = new Blockchain(config.network, config.private_keys)
const cooperative = new CooperativeClass(blockchain)
await cooperative.createParticipant(username, {
await cooperative.addUser(username, {
// eslint-disable-next-line node/prefer-global/process
privateKey: process.env.EOSIO_PRV_KEY!,
// eslint-disable-next-line node/prefer-global/process
+63 -39
View File
@@ -4,7 +4,7 @@ import Blockchain from '../blockchain'
import config from '../configs'
import { getTotalRamUsage, globalRamStats } from '../utils/getTotalRamUsage'
import { generateRandomSHA256 } from '../utils/randomHash'
import { createParticipant } from '../init/participant'
import { addUser } from '../init/participant'
import { generateRandomUsername } from '../utils/randomUsername'
import { sleep } from '../utils'
import { processDecision } from './soviet/processDecision'
@@ -55,19 +55,19 @@ beforeAll(async () => {
investor1 = generateRandomUsername()
console.log('investor1: ', investor1)
await createParticipant(investor1)
await addUser(investor1)
tester1 = generateRandomUsername()
console.log('tester1: ', tester1)
await createParticipant(tester1)
await addUser(tester1)
tester2 = generateRandomUsername()
console.log('tester2: ', tester2)
await createParticipant(tester2)
await addUser(tester2)
tester3 = generateRandomUsername()
console.log('tester3: ', tester3)
await createParticipant(tester3)
await addUser(tester3)
// const { stdout } = await execa('esno', [CLI_PATH, 'boot'], { stdio: 'inherit' })
// expect(stdout).toContain('Boot process completed')
@@ -397,6 +397,8 @@ describe('тест контракта CAPITAL', () => {
application: 'voskhod',
project_hash: project1.project_hash,
result_hash: generateRandomSHA256(),
assignee: 'ant',
assignment: 'Задание #1: тут описание',
}
result1 = data
@@ -477,55 +479,56 @@ describe('тест контракта CAPITAL', () => {
const { finalResult, commitHash } = await commitToResult(blockchain, 'voskhod', result1.result_hash, result1.project_hash, tester1, tester1CommitHours)
commits.push(commitHash)
expect(finalResult.creators_amount).toBe('10000.0000 RUB')
expect(finalResult.creators_base).toBe('10000.0000 RUB')
expect(finalResult.creators_bonus).toBe('3820.0000 RUB')
expect(finalResult.authors_bonus).toBe('16180.0000 RUB')
expect(finalResult.generated_amount).toBe('30000.0000 RUB')
expect(finalResult.generated).toBe('30000.0000 RUB')
expect(finalResult.capitalists_bonus).toBe('48540.0000 RUB')
expect(finalResult.total_amount).toBe('78540.0000 RUB')
expect(finalResult.total).toBe('78540.0000 RUB')
})
it('добавить коммит создателя tester2 на 10 часов по 1000 RUB', async () => {
const { finalResult, commitHash } = await commitToResult(blockchain, 'voskhod', result1.result_hash, result1.project_hash, tester2, tester2CommitHours)
commits.push(commitHash)
expect(finalResult.creators_amount).toBe('20000.0000 RUB')
expect(finalResult.creators_base).toBe('20000.0000 RUB')
expect(finalResult.creators_bonus).toBe('7640.0000 RUB')
expect(finalResult.authors_bonus).toBe('32360.0000 RUB')
expect(finalResult.generated_amount).toBe('60000.0000 RUB')
expect(finalResult.generated).toBe('60000.0000 RUB')
expect(finalResult.capitalists_bonus).toBe('97080.0000 RUB')
expect(finalResult.total_amount).toBe('157080.0000 RUB')
expect(finalResult.total).toBe('157080.0000 RUB')
})
it('пишем заявление на возврат в кошелёк от tester1 на 10000 RUB', async () => {
const withdrawAmount = `${(tester1CommitHours * parseFloat(ratePerHour)).toFixed(4)} RUB`
console.log('commits: ', commits)
const { withdrawHash, transactionId } = await withdrawContribution(
blockchain,
'voskhod',
tester1,
result1.result_hash,
result1.project_hash,
[commits[0]],
withdrawAmount,
fakeDocument,
)
})
// TODO: заменить на получение ссуды, а возврат перенести ниже
// it('пишем заявление на возврат в кошелёк от tester1 на 10000 RUB', async () => {
// const withdrawAmount = `${(tester1CommitHours * parseFloat(ratePerHour)).toFixed(4)} RUB`
// console.log('commits: ', commits)
// const { withdrawHash, transactionId } = await withdrawContribution(
// blockchain,
// 'voskhod',
// tester1,
// result1.result_hash,
// result1.project_hash,
// [commits[0]],
// withdrawAmount,
// fakeDocument,
// )
// })
it('пишем заявление на возврат в кошелёк от tester2 на 10000 RUB', async () => {
const withdrawAmount = `${(tester2CommitHours * parseFloat(ratePerHour)).toFixed(4)} RUB`
// it('пишем заявление на возврат в кошелёк от tester2 на 10000 RUB', async () => {
// const withdrawAmount = `${(tester2CommitHours * parseFloat(ratePerHour)).toFixed(4)} RUB`
const { withdrawHash, transactionId } = await withdrawContribution(
blockchain,
'voskhod',
tester2,
result1.result_hash,
result1.project_hash,
[commits[1]],
withdrawAmount,
fakeDocument,
)
})
// const { withdrawHash, transactionId } = await withdrawContribution(
// blockchain,
// 'voskhod',
// tester2,
// result1.result_hash,
// result1.project_hash,
// [commits[1]],
// withdrawAmount,
// fakeDocument,
// )
// })
it('регистрируем расход на 1000 RUB', async () => {
const expenseAmount = '1000.0000 RUB'
@@ -605,15 +608,24 @@ describe('тест контракта CAPITAL', () => {
expect(blockchainResult.result_hash).toBe(result1.result_hash)
expect(blockchainResult.project_hash).toBe(project1.project_hash)
expect(blockchainResult.coopname).toBe('voskhod')
expect(blockchainResult.status).toBe('opened')
expect(blockchainResult.status).toBe('closed')
expect(blockchainResult.creators_amount_remain).toBe(blockchainResult.creators_amount)
expect(blockchainResult.creators_bonus_remain).toBe(blockchainResult.creators_bonus)
expect(blockchainResult.authors_bonus_remain).toBe(blockchainResult.authors_bonus)
expect(blockchainResult.capitalists_bonus_remain).toBe(blockchainResult.capitalists_bonus)
console.log('Результат после старта приёма: ', blockchainResult)
})
it('обновляем капитал первого создателя в результате', async () => {
const claim_hash = generateRandomSHA256()
const data: CapitalContract.Actions.CreateClaim.ICreateClaim = {
coopname: 'voskhod',
application: 'voskhod',
result_hash: result1.result_hash,
username: tester1,
claim_hash,
}
const result = await blockchain.api.transact(
@@ -656,11 +668,14 @@ describe('тест контракта CAPITAL', () => {
})
it('обновляем капитал второго создателя в результате', async () => {
const claim_hash = generateRandomSHA256()
const data: CapitalContract.Actions.CreateClaim.ICreateClaim = {
coopname: 'voskhod',
application: 'voskhod',
result_hash: result1.result_hash,
username: tester2,
claim_hash,
}
const result = await blockchain.api.transact(
@@ -703,11 +718,14 @@ describe('тест контракта CAPITAL', () => {
})
it('повторно обновляем капитал второго создателя в результате и ожидаем ошибку', async () => {
const claim_hash = generateRandomSHA256()
const data: CapitalContract.Actions.CreateClaim.ICreateClaim = {
coopname: 'voskhod',
application: 'voskhod',
result_hash: result1.result_hash,
username: tester2,
claim_hash,
}
try {
@@ -742,11 +760,14 @@ describe('тест контракта CAPITAL', () => {
})
it('обновляем капитал инвестора в результате', async () => {
const claim_hash = generateRandomSHA256()
const data: CapitalContract.Actions.CreateClaim.ICreateClaim = {
coopname: 'voskhod',
application: 'voskhod',
result_hash: result1.result_hash,
username: investor1,
claim_hash,
}
const result = await blockchain.api.transact(
@@ -789,11 +810,14 @@ describe('тест контракта CAPITAL', () => {
})
it('повторно обновляем капитал инвестора в результате и ожидаем ошибку', async () => {
const claim_hash = generateRandomSHA256()
const data: CapitalContract.Actions.CreateClaim.ICreateClaim = {
coopname: 'voskhod',
application: 'voskhod',
result_hash: result1.result_hash,
username: investor1,
claim_hash,
}
try {
@@ -28,7 +28,7 @@ export async function commitToResult(
resultHash,
2,
'sha256',
))[0] || { spend: '0.0000 RUB', commits_count: 0 }
))[0] || { spended: '0.0000 RUB', commits_count: 0 }
const prevProject = (await blockchain.getTableRows(
CapitalContract.contractName.production,
@@ -39,7 +39,7 @@ export async function commitToResult(
projectHash,
3,
'sha256',
))[0] || { spend: '0.0000 RUB' }
))[0] || { spended: '0.0000 RUB' }
const prevContributor = (await blockchain.getTableRows(
CapitalContract.contractName.production,
@@ -62,10 +62,9 @@ export async function commitToResult(
coopname,
application: coopname,
result_hash: resultHash,
creator,
commit_hash: commitHash,
contribution_statement: fakeDocument,
contributed_hours: spendHours,
username: creator,
}
console.log(`\n🚀 Отправка транзакции CreateCommit для результата ${resultHash}`)
@@ -104,16 +103,14 @@ export async function commitToResult(
console.log('🔍 Коммит после создания:', blockchainCommit)
expect(blockchainCommit).toBeDefined()
expect(blockchainCommit.commit_hash).toBe(commitHash)
expect(blockchainCommit.spend).toBe(totalSpended)
expect(blockchainCommit.spended).toBe(totalSpended)
expect(blockchainCommit.status).toBe('created')
// Утверждение коммита
const approveCommitData: CapitalContract.Actions.ApproveCommit.IApproveCommit = {
const approveCommitData: SovietContract.Actions.Approves.ConfirmApprove.IConfirmApprove = {
coopname,
application: coopname,
commit_hash: commitHash,
approver: 'ant',
approved_statement: fakeDocument,
approval_hash: commitHash,
approved_document: fakeDocument,
}
console.log(`\n✅ Подтверждение коммита ${commitHash}`)
@@ -121,8 +118,8 @@ export async function commitToResult(
{
actions: [
{
account: CapitalContract.contractName.production,
name: CapitalContract.Actions.ApproveCommit.actionName,
account: SovietContract.contractName.production,
name: SovietContract.Actions.Approves.ConfirmApprove.actionName,
authorization: [{ actor: coopname, permission: 'active' }],
data: approveCommitData,
},
@@ -149,86 +146,84 @@ export async function commitToResult(
'sha256',
))[0]
console.log('🔍 Коммит после утверждения:', blockchainCommit)
expect(blockchainCommit).toBeDefined()
expect(blockchainCommit.commit_hash).toBe(commitHash)
expect(blockchainCommit.status).toBe('approved')
// Коммит удаляем после утверждения
expect(blockchainCommit).toBeUndefined()
// Получение всех решений и выполнение последнего
const decisions = await blockchain.getTableRows(
SovietContract.contractName.production,
coopname,
'decisions',
1000,
)
const lastDecision = decisions[decisions.length - 1]
// // Получение всех решений и выполнение последнего
// const decisions = await blockchain.getTableRows(
// SovietContract.contractName.production,
// coopname,
// 'decisions',
// 1000,
// )
// const lastDecision = decisions[decisions.length - 1]
console.log(`\n📜 Выполнение последнего решения: ${lastDecision.id}`)
await processDecision(blockchain, lastDecision.id)
// console.log(`\n📜 Выполнение последнего решения: ${lastDecision.id}`)
// await processDecision(blockchain, lastDecision.id)
{
// Утверждение коммита
const act1Data: CapitalContract.Actions.SetAct1.ISetAct1 = {
coopname,
application: coopname,
username: creator,
commit_hash: commitHash,
act: fakeDocument,
}
// {
// // Утверждение коммита
// const act1Data: CapitalContract.Actions.SetAct1.ISetAct1 = {
// coopname,
// application: coopname,
// username: creator,
// commit_hash: commitHash,
// act: fakeDocument,
// }
console.log(`\n✅ Установка акта1 по коммиту ${commitHash}`)
const act1Result = await blockchain.api.transact(
{
actions: [
{
account: CapitalContract.contractName.production,
name: CapitalContract.Actions.SetAct1.actionName,
authorization: [{ actor: coopname, permission: 'active' }],
data: act1Data,
},
],
},
{
blocksBehind: 3,
expireSeconds: 30,
},
)
// console.log(`\n✅ Установка акта1 по коммиту ${commitHash}`)
// const act1Result = await blockchain.api.transact(
// {
// actions: [
// {
// account: CapitalContract.contractName.production,
// name: CapitalContract.Actions.SetAct1.actionName,
// authorization: [{ actor: coopname, permission: 'active' }],
// data: act1Data,
// },
// ],
// },
// {
// blocksBehind: 3,
// expireSeconds: 30,
// },
// )
getTotalRamUsage(act1Result)
expect(act1Result.transaction_id).toBeDefined()
}
// getTotalRamUsage(act1Result)
// expect(act1Result.transaction_id).toBeDefined()
// }
{
// Утверждение коммита
const act2Data: CapitalContract.Actions.SetAct2.ISetAct2 = {
coopname,
application: coopname,
username: creator,
commit_hash: commitHash,
act: fakeDocument,
}
// {
// // Утверждение коммита
// const act2Data: CapitalContract.Actions.SetAct2.ISetAct2 = {
// coopname,
// application: coopname,
// username: creator,
// commit_hash: commitHash,
// act: fakeDocument,
// }
console.log(`\n✅ Установка акта2 по коммиту ${commitHash}`)
const act2Result = await blockchain.api.transact(
{
actions: [
{
account: CapitalContract.contractName.production,
name: CapitalContract.Actions.SetAct2.actionName,
authorization: [{ actor: coopname, permission: 'active' }],
data: act2Data,
},
],
},
{
blocksBehind: 3,
expireSeconds: 30,
},
)
// console.log(`\n✅ Установка акта2 по коммиту ${commitHash}`)
// const act2Result = await blockchain.api.transact(
// {
// actions: [
// {
// account: CapitalContract.contractName.production,
// name: CapitalContract.Actions.SetAct2.actionName,
// authorization: [{ actor: coopname, permission: 'active' }],
// data: act2Data,
// },
// ],
// },
// {
// blocksBehind: 3,
// expireSeconds: 30,
// },
// )
getTotalRamUsage(act2Result)
expect(act2Result.transaction_id).toBeDefined()
}
// getTotalRamUsage(act2Result)
// expect(act2Result.transaction_id).toBeDefined()
// }
// Проверка результата после утверждения коммита
const finalResult = (await blockchain.getTableRows(
@@ -269,8 +264,8 @@ export async function commitToResult(
console.log('▶ Проект:', finalProject)
console.log('▶ Контрибьютор:', finalContributor)
// expect(parseFloat(finalResult.spend)).toBe(parseFloat(prevResult.spend) + parseFloat(totalSpended))
// expect(parseFloat(finalProject.spend)).toBe(parseFloat(prevProject.spend))
// expect(parseFloat(finalResult.spended)).toBe(parseFloat(prevResult.spended) + parseFloat(totalSpended))
// expect(parseFloat(finalProject.spended)).toBe(parseFloat(prevProject.spended))
// Проверка, что у контрибьютора увеличились contributed_hours и available
// expect(parseFloat(finalContributor.contributed_hours)).toBe(parseFloat(prevContributor.contributed_hours) + spendHours)
@@ -174,26 +174,24 @@ export async function registerExpense(
const blockchainWithdraw = (await blockchain.getTableRows(
GatewayContract.contractName.production,
coopname,
GatewayContract.Tables.Withdraws.tableName,
GatewayContract.Tables.Outcomes.tableName,
1,
expenseHash,
expenseHash,
3,
2,
'sha256',
))[0]
console.log('🔍 Вывод средств:', blockchainWithdraw)
expect(blockchainWithdraw).toBeDefined()
expect(blockchainWithdraw.withdraw_hash).toBe(expenseHash)
expect(blockchainWithdraw.outcome_hash).toBe(expenseHash)
expect(blockchainWithdraw.quantity).toBe(expenseAmount)
expect(blockchainWithdraw.status).toBe('authorized')
expect(blockchainWithdraw.status).toBe('pending')
// Завершение вывода
const completeWithdrawData: GatewayContract.Actions.CompleteWithdraw.ICompleteWithdraw = {
const completeWithdrawData: GatewayContract.Actions.CompleteOutcome.ICompleteOutcome = {
coopname,
application: '',
memo: '',
withdraw_hash: expenseHash,
outcome_hash: expenseHash,
}
console.log(`\n✅ Завершение вывода ${expenseHash}`)
@@ -202,7 +200,7 @@ export async function registerExpense(
actions: [
{
account: GatewayContract.contractName.production,
name: GatewayContract.Actions.CompleteWithdraw.actionName,
name: GatewayContract.Actions.CompleteOutcome.actionName,
authorization: [{ actor: coopname, permission: 'active' }],
data: completeWithdrawData,
},
@@ -0,0 +1,57 @@
import { afterAll, beforeAll, describe, expect, it } from 'vitest'
import { GatewayContract, RegistratorContract, SovietContract } from 'cooptypes'
import { sha256 } from 'eosjs/dist/eosjs-key-conversions'
import Blockchain from '../blockchain'
import config from '../configs'
import { getTotalRamUsage, globalRamStats } from '../utils/getTotalRamUsage'
import { addUser } from '../init/participant'
import { generateRandomUsername } from '../utils/randomUsername'
import { generateRandomSHA256 } from '../utils/randomHash'
import { signWalletAgreement } from './wallet/signWalletAgreement'
import { depositToWallet } from './wallet/depositToWallet'
import { processDecision } from './soviet/processDecision'
import { getParticipant } from './registrator/getParticipant'
import { registerUser } from './registrator/registerUser'
const blockchain = new Blockchain(config.network, config.private_keys)
let tester1: string
const walletProgramStates1: any[] = []
const fakeDocument = {
hash: '157192B276DA23CC84AB078FC8755C051C5F0430BF4802E55718221E6B76C777',
public_key: 'PUB_K1_5JhMfxbsNebajHcTEK8yC9uNN9Dit9hEmzE8ri8yMhhzzEtUA4',
signature: 'SIG_K1_KmKWPBC8dZGGDGhbKEoZEzPr3h5crRrR2uLdGRF5DJbeibY1MY1bZ9sPwHsgmPfiGFv9psfoCVsXFh9TekcLuvaeuxRKA8',
meta: '{}',
}
beforeAll(async () => {
await blockchain.update_pass_instance()
}, 500_000)
afterAll(() => {
console.log('\n📊 **RAM USAGE SUMMARY** 📊')
let totalGlobalRam = 0
for (const [key, ramUsed] of Object.entries(globalRamStats)) {
console.log(` ${key} = ${(ramUsed / 1024).toFixed(2)} kb`)
totalGlobalRam += ramUsed
}
console.log(`\n💾 **TOTAL RAM USED IN TESTS**: ${(totalGlobalRam / 1024).toFixed(2)} kb\n`)
})
describe('тест Registrator', () => {
it('регистируем пайщика 1', async () => {
const coopname = 'voskhod'
const tester1 = generateRandomUsername()
await registerUser(blockchain, coopname, tester1)
})
it('регистируем пайщика 2', async () => {
const coopname = 'voskhod'
const tester2 = generateRandomUsername()
await registerUser(blockchain, coopname, tester2)
})
})
@@ -0,0 +1,19 @@
import { SovietContract } from 'cooptypes'
import type Blockchain from '../../blockchain'
export async function getParticipant(
blockchain: Blockchain,
coopname: string,
username: string,
) {
const participant = (await blockchain.getTableRows(
SovietContract.contractName.production,
'voskhod',
'participants',
1,
username,
username,
))[0]
return participant
}
@@ -0,0 +1,123 @@
import { GatewayContract, RegistratorContract, SovietContract } from 'cooptypes'
import { expect } from 'vitest'
import { generateRandomSHA256 } from '../../utils/randomHash'
import { getTotalRamUsage } from '../../utils/getTotalRamUsage'
import { processDecision } from '../soviet/processDecision'
import { getParticipant } from '../registrator/getParticipant'
import { fakeDocument } from '../soviet/fakeDocument'
import { compareTokenAmounts, getCoopWallet } from '../wallet/walletUtils'
export async function registerUser(blockchain: any, coopname: string, username: string) {
const registration_hash = generateRandomSHA256()
const account = await blockchain.generateKeypair(username, undefined, 'Аккаунт кооператива')
// 🔹 Получаем балансы до регистрации
const prevCoopWallet = await getCoopWallet(blockchain, coopname)
const prevAvailable = prevCoopWallet?.circulating_account?.available || '0.0000 RUB'
const prevInitial = prevCoopWallet?.initial_account?.available || '0.0000 RUB'
console.log('📦 CoopWallet BEFORE:', prevCoopWallet)
// 🔹 1. Создание аккаунта
{
const data: RegistratorContract.Actions.CreateAccount.ICreateAccount = {
coopname,
referer: '',
username,
public_key: account.publicKey,
meta: '',
}
const result = await blockchain.api.transact({
actions: [{
account: RegistratorContract.contractName.production,
name: RegistratorContract.Actions.CreateAccount.actionName,
authorization: [{ actor: coopname, permission: 'active' }],
data,
}],
}, { blocksBehind: 3, expireSeconds: 30 })
getTotalRamUsage(result)
console.log('✅ Аккаунт создан')
}
// 🔹 2. Регистрация пайщика
{
const data: RegistratorContract.Actions.RegisterUser.IRegisterUser = {
coopname,
braname: '',
username,
type: 'individual',
statement: fakeDocument,
registration_hash,
}
const result = await blockchain.api.transact({
actions: [{
account: RegistratorContract.contractName.production,
name: RegistratorContract.Actions.RegisterUser.actionName,
authorization: [{ actor: coopname, permission: 'active' }],
data,
}],
}, { blocksBehind: 3, expireSeconds: 30 })
getTotalRamUsage(result)
console.log('✅ Пайщик зарегистрирован')
}
// 🔹 3. Подтверждение прихода
{
const data: GatewayContract.Actions.CompleteIncome.ICompleteIncome = {
coopname,
income_hash: registration_hash,
}
const result = await blockchain.api.transact({
actions: [{
account: GatewayContract.contractName.production,
name: GatewayContract.Actions.CompleteIncome.actionName,
authorization: [{ actor: coopname, permission: 'active' }],
data,
}],
}, { blocksBehind: 3, expireSeconds: 30 })
getTotalRamUsage(result)
console.log('✅ Приход подтвержден')
}
// 🔹 4. Исполнение решения
const decisions = await blockchain.getTableRows(
SovietContract.contractName.production,
coopname,
'decisions',
1000,
)
const lastDecision = decisions.at(-1)
console.log('📜 Последнее решение:', lastDecision)
await processDecision(blockchain, lastDecision.id)
console.log('✅ Решение выполнено')
// 🔹 5. Проверка участника
const participant = await getParticipant(blockchain, coopname, username)
console.log('🙋 Участник:', participant)
expect(participant).toBeDefined()
expect(participant.has_vote).toBe(1)
expect(participant.status).toBe('accepted')
expect(participant.username).toBe(username)
// 🔹 6. Проверка балансов после регистрации
const coopWalletAfter = await getCoopWallet(blockchain, coopname)
const newAvailable = coopWalletAfter?.circulating_account?.available || '0.0000 RUB'
const newInitial = coopWalletAfter?.initial_account?.available || '0.0000 RUB'
console.log('💰 CoopWallet AFTER:', coopWalletAfter)
const minAmount = parseFloat(participant.minimum_amount.split(' ')[0])
const initAmount = parseFloat(participant.initial_amount.split(' ')[0])
compareTokenAmounts(prevAvailable, newAvailable, minAmount)
compareTokenAmounts(prevInitial, newInitial, initAmount)
return participant
}
+2 -2
View File
@@ -2,7 +2,7 @@ import { afterAll, beforeAll, describe, expect, it } from 'vitest'
import Blockchain from '../blockchain'
import config from '../configs'
import { getTotalRamUsage, globalRamStats } from '../utils/getTotalRamUsage'
import { createParticipant } from '../init/participant'
import { addUser } from '../init/participant'
import { generateRandomUsername } from '../utils/randomUsername'
import { signWalletAgreement } from './wallet/signWalletAgreement'
import { depositToWallet } from './wallet/depositToWallet'
@@ -23,7 +23,7 @@ beforeAll(async () => {
tester1 = generateRandomUsername()
console.log('tester1: ', tester1)
await createParticipant(tester1)
await addUser(tester1)
}, 500_000)
afterAll(() => {
@@ -1,17 +1,17 @@
import { randomInt } from 'node:crypto'
import { GatewayContract } from 'cooptypes'
import { GatewayContract, WalletContract } from 'cooptypes'
import { expect } from 'vitest'
import { getTotalRamUsage } from '../../utils/getTotalRamUsage'
import { generateRandomSHA256 } from '../../utils/randomHash'
import { compareTokenAmounts, getCoopProgramWallet, getCoopWallet, getDeposit, getUserProgramWallet } from './walletUtils'
export async function depositToWallet(blockchain: any, coopname: string, username: string, amount: number) {
const depositId = randomInt(100000)
const data: GatewayContract.Actions.CreateDeposit.ICreateDeposit = {
const data: WalletContract.Actions.CreateDeposit.ICreateDeposit = {
coopname,
username,
deposit_id: depositId,
type: 'deposit',
deposit_hash: generateRandomSHA256(),
quantity: `${amount.toFixed(4)} RUB`,
}
@@ -19,9 +19,9 @@ export async function depositToWallet(blockchain: any, coopname: string, usernam
{
actions: [
{
account: GatewayContract.contractName.production,
name: GatewayContract.Actions.CreateDeposit.actionName,
authorization: [{ actor: username, permission: 'active' }],
account: WalletContract.contractName.production,
name: WalletContract.Actions.CreateDeposit.actionName,
authorization: [{ actor: coopname, permission: 'active' }],
data,
},
],
@@ -35,16 +35,15 @@ export async function depositToWallet(blockchain: any, coopname: string, usernam
getTotalRamUsage(result)
expect(result.transaction_id).toBeDefined()
const deposit = await getDeposit(blockchain, coopname, depositId)
const deposit = await getDeposit(blockchain, coopname, data.deposit_hash)
expect(deposit).toEqual(expect.objectContaining({
id: depositId,
expect(deposit).toMatchObject({
deposit_hash: data.deposit_hash,
username,
coopname,
type: 'deposit',
quantity: `${amount.toFixed(4)} RUB`,
status: 'pending',
}))
})
const prevUserWallet = await getUserProgramWallet(blockchain, coopname, username, 1)
const prevUserWalletAvailable = prevUserWallet?.available || '0.0000 RUB'
@@ -52,11 +51,9 @@ export async function depositToWallet(blockchain: any, coopname: string, usernam
const prevCoopWallet = await getCoopWallet(blockchain, coopname)
const prevCoopWalletAvailable = prevCoopWallet?.circulating_account?.available || '0.0000 RUB'
const data2: GatewayContract.Actions.CompleteDeposit.ICompleteDeposit = {
const data2: GatewayContract.Actions.CompleteIncome.ICompleteIncome = {
coopname,
admin: coopname,
deposit_id: depositId,
memo: '',
income_hash: data.deposit_hash,
}
const result2 = await blockchain.api.transact(
@@ -64,7 +61,7 @@ export async function depositToWallet(blockchain: any, coopname: string, usernam
actions: [
{
account: GatewayContract.contractName.production,
name: GatewayContract.Actions.CompleteDeposit.actionName,
name: GatewayContract.Actions.CompleteIncome.actionName,
authorization: [{ actor: coopname, permission: 'active' }],
data: data2,
},
@@ -77,8 +74,9 @@ export async function depositToWallet(blockchain: any, coopname: string, usernam
)
getTotalRamUsage(result2)
const deposit2 = await getDeposit(blockchain, coopname, depositId)
expect(deposit2.status).toBe('completed')
const deposit2 = await getDeposit(blockchain, coopname, data.deposit_hash)
expect(deposit2).toBeUndefined()
const program = await getCoopProgramWallet(blockchain, coopname, 1)
@@ -1,5 +1,6 @@
import { FundContract, GatewayContract, SovietContract } from 'cooptypes'
import { FundContract, SovietContract, WalletContract } from 'cooptypes'
import { expect } from 'vitest'
import type Blockchain from '../../blockchain'
export async function getUserProgramWallet(blockchain: any, coopname: string, username: string, program_id: number) {
const wallets = await blockchain.getTableRows(
@@ -24,7 +25,7 @@ export async function getCoopProgramWallet(blockchain: any, coopname: string, pr
program_id.toString(),
program_id.toString(),
)
console.log('PROGRAMS:', program)
return program[0]
}
@@ -37,14 +38,16 @@ export async function getCoopWallet(blockchain: any, coopname: string) {
))[0]
}
export async function getDeposit(blockchain: any, coopname: string, deposit_id: number) {
export async function getDeposit(blockchain: Blockchain, coopname: string, deposit_hash: string) {
return (await blockchain.getTableRows(
GatewayContract.contractName.production,
WalletContract.contractName.production,
coopname,
'deposits',
WalletContract.Tables.Deposits.tableName,
1,
deposit_id.toString(),
deposit_id.toString(),
deposit_hash,
deposit_hash,
2,
'sha256',
))[0]
}
+2
View File
@@ -0,0 +1,2 @@
eosio-wallet/wallet.lock
eosio-wallet/keosd.sock
+8
View File
@@ -0,0 +1,8 @@
# Change Log
All notable changes to this project will be documented in this file.
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
## [2.2.10](https://github.com/coopenomics/mono/compare/v2.2.9...v2.2.10) (2025-03-27)
**Note:** Version bump only for package @coopenomics/cleos
+54
View File
@@ -0,0 +1,54 @@
# The filename (relative to data-dir) to create a unix socket for HTTP RPC; set blank to disable. (eosio::http_plugin)
# unix-socket-path = keosd.sock
# The local IP and port to listen for incoming http connections; setting to http-category-address to enable http-category-address option. leave blank to disable. (eosio::http_plugin)
# http-server-address =
# Specify the Access-Control-Allow-Origin to be returned on each request (eosio::http_plugin)
# access-control-allow-origin =
# Specify the Access-Control-Allow-Headers to be returned on each request (eosio::http_plugin)
# access-control-allow-headers =
# Specify the Access-Control-Max-Age to be returned on each request. (eosio::http_plugin)
# access-control-max-age =
# Specify if Access-Control-Allow-Credentials: true should be returned on each request. (eosio::http_plugin)
# access-control-allow-credentials = false
# The maximum body size in bytes allowed for incoming RPC requests (eosio::http_plugin)
# max-body-size = 2097152
# Maximum size in megabytes http_plugin should use for processing http requests. -1 for unlimited. 503 error response when exceeded. (eosio::http_plugin)
# http-max-bytes-in-flight-mb = 500
# Maximum number of requests http_plugin should use for processing http requests. 503 error response when exceeded. (eosio::http_plugin)
# http-max-in-flight-requests = -1
# Maximum time on main thread for processing a request, -1 for unlimited (eosio::http_plugin)
# http-max-response-time-ms = 15
# Append the error log to HTTP responses (eosio::http_plugin)
# verbose-http-errors = false
# If set to false, then any incoming "Host" header is considered valid (eosio::http_plugin)
# http-validate-host = true
# Additionally acceptable values for the "Host" header of incoming HTTP requests, can be specified multiple times. Includes http/s_server_address by default. (eosio::http_plugin)
# http-alias =
# Number of worker threads in http thread pool (eosio::http_plugin)
# http-threads = 2
# If set to false, do not keep HTTP connections alive, even if client requests. (eosio::http_plugin)
# http-keep-alive = true
# The path of the wallet files (absolute path or relative to application data dir) (eosio::wallet_plugin)
# wallet-dir = "."
# Timeout for unlocked wallet in seconds (default 900 (15 minutes)). Wallets will automatically lock after specified number of seconds of inactivity. Activity is defined as any wallet command e.g. list-wallets. (eosio::wallet_plugin)
# unlock-timeout = 900
# Plugin(s) to enable, may be specified multiple times
# plugin =
@@ -0,0 +1,3 @@
{
"cipher_keys": "710a43f09ece89ed7baf387cc1ae3127cb90d9fc16cffda660c71c75678d1fe4d8b22e1fd0476e232581a37e3c3beda3e25b873ae0a9d43c274f30b4d9ea394f4c583234a6d0715540163edc28db22de98b0aa7e9431ebfc6f28b1eaf665326d7456b55f1fa776e7eac61d90264871e6a58b3ebbd8dec377e05ef7fec64b348aef02459329f49d1384bf2af32fd02ce1"
}
+1
View File
@@ -0,0 +1 @@
PW5JGe4WsTPGrjnMzkGd4wfVdzoHCEySgbyq2WBWGAxSfevbXqAG4
+12
View File
@@ -0,0 +1,12 @@
{
"name": "@coopenomics/cleos",
"version": "2025.5.5-2",
"private": true,
"description": "",
"scripts": {
"run": "./run.sh"
},
"keywords": [],
"author": "",
"license": "ISC"
}
+7
View File
@@ -0,0 +1,7 @@
docker run --rm -it --name cleos \
--network dicoop \
--volume ./eosio-wallet:/root/eosio-wallet \
--volume ./scripts:/root/scripts \
-w /root/scripts \
dicoop/blockchain_v5.1.1:dev /bin/bash
+5
View File
@@ -0,0 +1,5 @@
ls
exit
ls
./cleos.sh
exit
+3
View File
@@ -0,0 +1,3 @@
#!/bin/bash
cleos -u http://node:8888 "$@"
+2
View File
@@ -0,0 +1,2 @@
#!/bin/bash
rm ../eosio-wallet/keosd.sock
+3
View File
@@ -0,0 +1,3 @@
#!/bin/bash
cleos wallet unlock --name default < ../eosio-wallet/password
+8
View File
@@ -3,6 +3,14 @@
All notable changes to this project will be documented in this file.
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
## [2.2.10](https://github.com/coopenomics/mono/compare/v2.2.9...v2.2.10) (2025-03-27)
**Note:** Version bump only for package @coopenomics/contracts
## [2.2.9](https://github.com/coopenomics/mono/compare/v2.2.8...v2.2.9) (2025-03-12)
**Note:** Version bump only for package @coopenomics/contracts
+3
View File
@@ -30,6 +30,9 @@ macro(add_contract_build name)
endmacro()
# Добавляем все контракты
add_contract_build(meet)
add_contract_build(loan)
add_contract_build(wallet)
add_contract_build(capital)
add_contract_build(branch)
add_contract_build(contributor)
+6 -127
View File
@@ -1,18 +1,15 @@
#include "branch.hpp"
#include "src/addtrusted.cpp"
#include "src/createbranch.cpp"
#include "src/deletebranch.cpp"
#include "src/deltrusted.cpp"
#include "src/editbranch.cpp"
using namespace eosio;
[[eosio::action]] void branch::migrate() {
require_auth(_branch);
branchstat_index stat(_branch, _branch.value);
auto st = stat.find("nzpzufzhcfab"_n.value);
if (st != stat.end()){
stat.modify(st, _branch, [&](auto &s){
s.count = 0;
});
}
}
@@ -21,121 +18,3 @@ using namespace eosio;
require_auth(_system);
};
[[eosio::action]] void branch::addtrusted(eosio::name coopname, eosio::name braname, eosio::name trusted) {
check_auth_or_fail(_branch, coopname, coopname, "addtrusted"_n);
branch_index branches(_branch, coopname.value);
auto branch = branches.find(braname.value);
eosio::check(branch != branches.end(), "Кооперативный участок не найден");
auto trusted_account = get_account_or_fail(trusted);
eosio::check(trusted_account.type == "individual"_n, "Только физическое лицо может быть назначено доверенным кооперативного участка");
branches.modify(branch, coopname, [&](auto &b) {
eosio::check(std::find(b.trusted.begin(), b.trusted.end(), trusted) == b.trusted.end(),
"Доверенный уже добавлен в кооперативный участок");
eosio::check(b.trusted.size() < 3, "Не больше трех доверенных на одном кооперативном участке");
b.trusted.push_back(trusted);
});
}
[[eosio::action]] void branch::deltrusted(eosio::name coopname, eosio::name braname, eosio::name trusted) {
check_auth_or_fail(_branch, coopname, coopname, "deltrusted"_n);
branch_index branches(_branch, coopname.value);
auto branch = branches.find(braname.value);
eosio::check(branch != branches.end(), "Кооперативный участок не найден");
branches.modify(branch, coopname, [&](auto &b) {
auto it = std::find(b.trusted.begin(), b.trusted.end(), trusted);
eosio::check(it != b.trusted.end(), "Доверенный не найден в кооперативном участке");
b.trusted.erase(it);
});
}
[[eosio::action]] void branch::createbranch(eosio::name coopname, eosio::name braname, eosio::name trustee) {
check_auth_or_fail(_branch, coopname, coopname, "createbranch"_n);
branch_index branches(_branch, coopname.value);
auto coop = get_cooperative_or_fail(coopname);
auto authorizer_account = get_account_or_fail(trustee);
eosio::check(authorizer_account.type == "individual"_n, "Только физическое лицо может быть назначено председателем кооперативного участка");
branches.emplace(coopname, [&](auto &row) {
row.braname = braname;
row.trustee = trustee;
});
action(
permission_level{ _branch, "active"_n},
_registrator,
"createbranch"_n,
std::make_tuple(coopname, braname)
).send();
uint64_t branch_count = add_branch_count(coopname);
if (!coop.is_branched && branch_count >= 3) { //регистрируем переход на кооперативные участки
action(
permission_level{ _branch, "active"_n},
_registrator,
"enabranches"_n,
std::make_tuple(coopname)
).send();
}
//TODO create subfunds and subwallets
}
[[eosio::action]] void branch::editbranch(eosio::name coopname, eosio::name braname, eosio::name trustee) {
check_auth_or_fail(_branch, coopname, coopname, "editbranch"_n);
branch_index branches(_branch, coopname.value);
auto branch = branches.find(braname.value);
eosio::check(branch != branches.end(), "Кооперативный участок не найден");
auto authorizer_account = get_account_or_fail(trustee);
eosio::check(authorizer_account.type == "individual"_n, "Только физическое лицо может быть назначено председателем кооперативного участка");
branches.modify(branch, coopname, [&](auto &b) {
b.trustee = trustee;
});
}
[[eosio::action]] void branch::deletebranch(eosio::name coopname, eosio::name braname) {
check_auth_or_fail(_branch, coopname, coopname, "deletebranch"_n);
branch_index branches(_branch, coopname.value);
auto branch = branches.find(braname.value);
auto coop = get_cooperative_or_fail(coopname);
eosio::check(branch != branches.end(), "Кооперативный участок не найден");
branches.erase(branch);
// отключаем участников кооператива от кооперативного участка
action(
permission_level{ _branch, "active"_n},
_soviet,
"deletebranch"_n,
std::make_tuple(coopname, braname)
).send();
uint64_t new_count = sub_branch_count(coopname);
if (coop.is_branched && new_count < 3) { //отключаем систему КУ, если их меньше 3
action(
permission_level{ _branch, "active"_n},
_registrator,
"disbranches"_n,
std::make_tuple(coopname)
).send();
}
};
@@ -0,0 +1,17 @@
[[eosio::action]] void branch::addtrusted(eosio::name coopname, eosio::name braname, eosio::name trusted) {
check_auth_or_fail(_branch, coopname, coopname, "addtrusted"_n);
branch_index branches(_branch, coopname.value);
auto branch = branches.find(braname.value);
eosio::check(branch != branches.end(), "Кооперативный участок не найден");
auto trusted_account = get_account_or_fail(trusted);
eosio::check(trusted_account.type == "individual"_n, "Только физическое лицо может быть назначено доверенным кооперативного участка");
branches.modify(branch, coopname, [&](auto &b) {
eosio::check(std::find(b.trusted.begin(), b.trusted.end(), trusted) == b.trusted.end(),
"Доверенный уже добавлен в кооперативный участок");
eosio::check(b.trusted.size() < 3, "Не больше трех доверенных на одном кооперативном участке");
b.trusted.push_back(trusted);
});
}
@@ -0,0 +1,36 @@
[[eosio::action]] void branch::createbranch(eosio::name coopname, eosio::name braname, eosio::name trustee) {
check_auth_or_fail(_branch, coopname, coopname, "createbranch"_n);
branch_index branches(_branch, coopname.value);
auto coop = get_cooperative_or_fail(coopname);
auto authorizer_account = get_account_or_fail(trustee);
eosio::check(authorizer_account.type == "individual"_n, "Только физическое лицо может быть назначено председателем кооперативного участка");
branches.emplace(coopname, [&](auto &row) {
row.braname = braname;
row.trustee = trustee;
});
action(
permission_level{ _branch, "active"_n},
_registrator,
"createbranch"_n,
std::make_tuple(coopname, braname)
).send();
uint64_t branch_count = add_branch_count(coopname);
if (!coop.is_branched && branch_count >= 3) { //регистрируем переход на кооперативные участки
action(
permission_level{ _branch, "active"_n},
_registrator,
"enabranches"_n,
std::make_tuple(coopname)
).send();
}
//TODO create subfunds and subwallets
}
@@ -0,0 +1,30 @@
[[eosio::action]] void branch::deletebranch(eosio::name coopname, eosio::name braname) {
check_auth_or_fail(_branch, coopname, coopname, "deletebranch"_n);
branch_index branches(_branch, coopname.value);
auto branch = branches.find(braname.value);
auto coop = get_cooperative_or_fail(coopname);
eosio::check(branch != branches.end(), "Кооперативный участок не найден");
branches.erase(branch);
// отключаем участников кооператива от кооперативного участка
action(
permission_level{ _branch, "active"_n},
_soviet,
"deletebranch"_n,
std::make_tuple(coopname, braname)
).send();
uint64_t new_count = sub_branch_count(coopname);
if (coop.is_branched && new_count < 3) { //отключаем систему КУ, если их меньше 3
action(
permission_level{ _branch, "active"_n},
_registrator,
"disbranches"_n,
std::make_tuple(coopname)
).send();
}
};
@@ -0,0 +1,13 @@
[[eosio::action]] void branch::deltrusted(eosio::name coopname, eosio::name braname, eosio::name trusted) {
check_auth_or_fail(_branch, coopname, coopname, "deltrusted"_n);
branch_index branches(_branch, coopname.value);
auto branch = branches.find(braname.value);
eosio::check(branch != branches.end(), "Кооперативный участок не найден");
branches.modify(branch, coopname, [&](auto &b) {
auto it = std::find(b.trusted.begin(), b.trusted.end(), trusted);
eosio::check(it != b.trusted.end(), "Доверенный не найден в кооперативном участке");
b.trusted.erase(it);
});
}
@@ -0,0 +1,16 @@
[[eosio::action]] void branch::editbranch(eosio::name coopname, eosio::name braname, eosio::name trustee) {
check_auth_or_fail(_branch, coopname, coopname, "editbranch"_n);
branch_index branches(_branch, coopname.value);
auto branch = branches.find(braname.value);
eosio::check(branch != branches.end(), "Кооперативный участок не найден");
auto authorizer_account = get_account_or_fail(trustee);
eosio::check(authorizer_account.type == "individual"_n, "Только физическое лицо может быть назначено председателем кооперативного участка");
branches.modify(branch, coopname, [&](auto &b) {
b.trustee = trustee;
});
}
+97 -99
View File
@@ -1,17 +1,33 @@
// capital.cpp
#include "capital.hpp"
#include "src/result/createresult.cpp"
#include "src/result/startdistrbn.cpp"
#include "src/assignment/createassign.cpp"
#include "src/assignment/startdistrbn.cpp"
#include "src/investment/createinvest.cpp"
#include "src/investment/approveinvst.cpp"
#include "src/investment/capauthinvst.cpp"
#include "src/claim/approveclaim.cpp"
#include "src/claim/createclaim.cpp"
#include "src/claim/claimnow.cpp"
#include "src/claim/capauthclaim.cpp"
#include "src/commit/createcmmt.cpp"
#include "src/commit/approvecmmt.cpp"
#include "src/commit/declinecmmt.cpp"
#include "src/commit/delcmmt.cpp"
#include "src/debt/createdebt.cpp"
#include "src/debt/approvedebt.cpp"
#include "src/debt/debtauthcnfr.cpp"
#include "src/debt/debtpaycnfrm.cpp"
#include "src/debt/debtpaydcln.cpp"
#include "src/debt/declinedebt.cpp"
#include "src/debt/settledebt.cpp"
#include "src/result/approverslt.cpp"
#include "src/result/updaterslt.cpp"
#include "src/result/pushrslt.cpp"
#include "src/result/authrslt.cpp"
#include "src/result/setact1.cpp"
#include "src/result/setact2.cpp"
#include "src/registration/capregcontr.cpp"
#include "src/registration/approvereg.cpp"
@@ -22,13 +38,6 @@
#include "src/managment/addauthor.cpp"
#include "src/managment/allocate.cpp"
#include "src/managment/diallocate.cpp"
#include "src/managment/wthdrcallbck.cpp"
#include "src/commit/createcmmt.cpp"
#include "src/commit/approvecmmt.cpp"
#include "src/commit/capauthcmmt.cpp"
#include "src/commit/setact1.cpp"
#include "src/commit/setact2.cpp"
#include "src/withdraw_from_result/createwthd1.cpp"
@@ -48,8 +57,11 @@
#include "src/expense/approveexpns.cpp"
#include "src/expense/capauthexpns.cpp"
// #include "src/expense/capdeclexpns.cpp"
#include "src/expense/createexpnse.cpp"
#include "src/expense/expense_withdraw_callback.cpp"
#include "src/expense/exppaycnfrm.cpp"
#include "src/fundproj/fundproj.cpp"
#include "src/fundproj/refreshproj.cpp"
@@ -59,18 +71,6 @@
#include <optional>
// TODO: внедрить коррекцию долей при выходе пайщика из проекта / программы
// void capital::reduce_shares(name coopname, checksum256 project_hash, name username, asset amount) {
// require_auth(_capital);
// contributor_index contributors(_capital, coopname.value);
// auto idx = contributors.get_index<"byusername"_n>();
// auto itr = idx.find(username.value);
// eosio::check(itr != idx.end(), "Contributor not found");
// }
void capital::validate_project_hierarchy_depth(eosio::name coopname, checksum256 project_hash) {
uint8_t level = 0;
@@ -148,7 +148,7 @@ eosio::asset capital::get_amount_for_withdraw_from_commit(eosio::name coopname,
c.status = "withdrawed"_n;
});
return itr -> spend;
return itr -> spended;
}
@@ -256,21 +256,6 @@ std::optional<progwallet> capital::get_capital_wallet(eosio::name coopname, eosi
}
std::optional<result_author> capital::get_result_author(eosio::name coopname, eosio::name username, const checksum256 &result_hash) {
result_authors_index result_authors(_capital, coopname.value);
auto result_author_index = result_authors.get_index<"byresauthor"_n>();
uint128_t combined_id = combine_checksum_ids(result_hash, username);
auto result_author_itr = result_author_index.find(combined_id);
if (result_author_itr == result_author_index.end()) {
return std::nullopt;
}
return *result_author_itr;
}
std::optional<author> capital::get_author(eosio::name coopname, eosio::name username, const checksum256 &project_hash) {
authors_index authors(_capital, coopname.value);
auto project_author_index = authors.get_index<"byprojauthor"_n>();
@@ -285,36 +270,49 @@ std::optional<author> capital::get_author(eosio::name coopname, eosio::name user
return *author_itr;
}
std::optional<creator> capital::get_creator(eosio::name coopname, eosio::name username, const checksum256 &result_hash) {
std::optional<creator> capital::get_creator(eosio::name coopname, eosio::name username, const checksum256 &assignment_hash) {
creators_index creators(_capital, coopname.value);
auto result_creator_index = creators.get_index<"byresultcrtr"_n>();
auto assignment_creator_index = creators.get_index<"byassigncrtr"_n>();
uint128_t combined_id = combine_checksum_ids(result_hash, username);
auto creator_itr = result_creator_index.find(combined_id);
uint128_t combined_id = combine_checksum_ids(assignment_hash, username);
auto creator_itr = assignment_creator_index.find(combined_id);
if (creator_itr == result_creator_index.end()) {
if (creator_itr == assignment_creator_index.end()) {
return std::nullopt;
}
return *creator_itr;
}
std::optional<result> capital::get_result(eosio::name coopname, const checksum256 &result_hash) {
result_index results(_capital, coopname.value);
auto result_hash_index = results.get_index<"byhash"_n>();
std::optional<assignment> capital::get_assignment(eosio::name coopname, const checksum256 &assignment_hash) {
assignment_index assignments(_capital, coopname.value);
auto assignment_hash_index = assignments.get_index<"byhash"_n>();
auto result_itr = result_hash_index.find(result_hash);
if (result_itr == result_hash_index.end()) {
auto assignment_itr = assignment_hash_index.find(assignment_hash);
if (assignment_itr == assignment_hash_index.end()) {
return std::nullopt;
}
return *result_itr;
return *assignment_itr;
}
result capital::get_result_or_fail(eosio::name coopname, const checksum256 &result_hash, const char* msg) {
auto maybe_result = get_result(coopname, result_hash);
eosio::check(maybe_result.has_value(), msg);
return *maybe_result;
std::optional<debt> capital::get_debt(eosio::name coopname, const checksum256 &debt_hash) {
debts_index debts(_capital, coopname.value);
auto hash_index = debts.get_index<"bydebthash"_n>();
auto itr = hash_index.find(debt_hash);
if (itr == hash_index.end()) {
return std::nullopt;
}
return *itr;
}
assignment capital::get_assignment_or_fail(eosio::name coopname, const checksum256 &assignment_hash, const char* msg) {
auto maybe_assignment = get_assignment(coopname, assignment_hash);
eosio::check(maybe_assignment.has_value(), msg);
return *maybe_assignment;
}
@@ -386,10 +384,21 @@ std::optional<capital_tables::project_withdraw> capital::get_project_withdraw(eo
}
std::optional<claim> capital::get_claim(eosio::name coopname, const checksum256 &result_hash, eosio::name username) {
claim_index claims(_capital, coopname.value);
auto idx = claims.get_index<"byresuser"_n>();
auto rkey = combine_checksum_ids(result_hash, username);
std::optional<result> capital::get_result(eosio::name coopname, const checksum256 &result_hash) {
result_index results(_capital, coopname.value);
auto idx = results.get_index<"byhash"_n>();
auto it = idx.find(result_hash);
if (it == idx.end()) {
return std::nullopt;
}
return *it;
}
std::optional<result> capital::get_result_by_assignment_and_username(eosio::name coopname, const checksum256 &assignment_hash, eosio::name username) {
result_index results(_capital, coopname.value);
auto idx = results.get_index<"byresuser"_n>();
auto rkey = combine_checksum_ids(assignment_hash, username);
auto it = idx.find(rkey);
if (it == idx.end()) {
@@ -412,17 +421,17 @@ std::optional<convert> capital::get_convert(eosio::name coopname, const checksum
}
claim capital::get_claim_or_fail(eosio::name coopname, const checksum256 &result_hash, eosio::name username, const char* msg) {
auto c = get_claim(coopname, result_hash, username);
result capital::get_result_by_assignment_and_username_or_fail(eosio::name coopname, const checksum256 &assignment_hash, eosio::name username, const char* msg) {
auto c = get_result_by_assignment_and_username(coopname, assignment_hash, username);
eosio::check(c.has_value(), msg);
return *c;
}
std::optional<resactor> capital::get_resactor(eosio::name coopname, const checksum256 &result_hash, eosio::name username) {
resactor_index ractors(_capital, coopname.value);
auto idx = ractors.get_index<"byresuser"_n>();
auto rkey = combine_checksum_ids(result_hash, username);
std::optional<creauthor> capital::get_creauthor(eosio::name coopname, const checksum256 &assignment_hash, eosio::name username) {
creauthor_index creathors(_capital, coopname.value);
auto idx = creathors.get_index<"byresuser"_n>();
auto rkey = combine_checksum_ids(assignment_hash, username);
auto it = idx.find(rkey);
if (it == idx.end()) {
@@ -431,10 +440,10 @@ std::optional<resactor> capital::get_resactor(eosio::name coopname, const checks
return *it;
}
resactor capital::get_resactor_or_fail(eosio::name coopname, const checksum256 &result_hash, eosio::name username, const char* msg) {
auto maybe_resactor = get_resactor(coopname, result_hash, username);
eosio::check(maybe_resactor.has_value(), msg);
return *maybe_resactor;
creauthor capital::get_creauthor_or_fail(eosio::name coopname, const checksum256 &assignment_hash, eosio::name username, const char* msg) {
auto maybe_creauthor = get_creauthor(coopname, assignment_hash, username);
eosio::check(maybe_creauthor.has_value(), msg);
return *maybe_creauthor;
}
@@ -466,40 +475,29 @@ global_state capital::get_global_state(name coopname) {
}
void capital::ensure_contributor(name coopname, name username) {
// Получаем глобальное состояние для установки reward_per_share_last
auto gs = get_global_state(coopname);
}
//----------------------------------------------------------------------------
// calculcate_capital_amounts: для расчёта премий по формулам:
// - creators_bonus = spend * 0.382
// - authors_bonus = spend * 1.618
// - generated = spend + creators_bonus + authors_bonus
// - creators_bonus = spended * 0.382
// - authors_bonus = spended * 0.618
// - generated = spended + creators_bonus + authors_bonus
// - capitalists_bonus = generated * 1.618
// - total = generated + capitalists_bonus
//----------------------------------------------------------------------------
bonus_result capital::calculcate_capital_amounts(int64_t spend_amount) {
bonus_result br{};
bonus_result capital::calculcate_capital_amounts(const eosio::asset& spended) {
bonus_result br;
// Преобразуем spend_amount в double для дальнейших расчетов
double spend = double(spend_amount);
// 1) creators_bonus = spend_amount * 0.382
br.creators_bonus = int64_t(spend * 0.382);
// 2) authors_bonus = spend_amount * 1.618
br.authors_bonus = int64_t(spend * 1.618);
// 3) generated = spend + creators_bonus + authors_bonus
br.generated = int64_t(spend + br.creators_bonus + br.authors_bonus);
// 4) capitalists_bonus = generated * 1.618
br.capitalists_bonus = int64_t(double(br.generated) * 1.618);
// 5) total = generated + capitalists_bonus
br.total = int64_t(br.generated + br.capitalists_bonus);
double amount = static_cast<double>(spended.amount);
eosio::symbol sym = spended.symbol;
br.creator_base = spended;
br.author_base = spended;
br.creators_bonus = eosio::asset(int64_t(amount * 0.382), sym);
br.authors_bonus = eosio::asset(int64_t(amount * 0.618), sym);
br.generated = eosio::asset(br.creator_base.amount + br.creators_bonus.amount + br.authors_bonus.amount + br.author_base.amount, sym);
br.capitalists_bonus = eosio::asset( int64_t(static_cast<double>(br.generated.amount) * 1.618), sym);
br.total = eosio::asset(br.generated.amount + br.capitalists_bonus.amount, sym);
return br;
}
+84 -58
View File
@@ -28,38 +28,34 @@ public:
void init(name coopname, name initiator);
[[eosio::action]]
void createresult(name coopname, name application, checksum256 project_hash, checksum256 result_hash);
void createassign(name coopname, name application, checksum256 project_hash, checksum256 assignment_hash, eosio::name assignee, std::string description);
//Возврат из задания
[[eosio::action]]
void createwthd1(eosio::name coopname, eosio::name application, eosio::name username, checksum256 assignment_hash, checksum256 withdraw_hash, asset amount, document2 return_statement);
[[eosio::action]]
void wthdrcallbck(eosio::name coopname, eosio::name callback_type, checksum256 withdraw_hash);
//Возврат из результата
[[eosio::action]]
void createwthd1(eosio::name coopname, eosio::name application, eosio::name username, checksum256 result_hash, checksum256 withdraw_hash, asset amount, document return_statement);
[[eosio::action]]
void capauthwthd1(eosio::name coopname, uint64_t withdraw_id, document authorization);
void capauthwthd1(eosio::name coopname, checksum256 withdraw_hash, document2 authorization);
// Возврат из проекта
[[eosio::action]]
void createwthd2(name coopname, name application, name username, checksum256 project_hash, checksum256 withdraw_hash, asset amount, document return_statement);
void createwthd2(name coopname, name application, name username, checksum256 project_hash, checksum256 withdraw_hash, asset amount, document2 return_statement);
[[eosio::action]]
void capauthwthd2(eosio::name coopname, uint64_t withdraw_id, document authorization);
void capauthwthd2(eosio::name coopname, checksum256 withdraw_hash, document2 authorization);
[[eosio::action]]
void approvewthd2(name coopname, name application, name approver, checksum256 withdraw_hash, document approved_return_statement);
void approvewthd2(name coopname, name application, name approver, checksum256 withdraw_hash, document2 approved_return_statement);
// Возврат из программы
[[eosio::action]]
void createwthd3(name coopname, name application, name username, checksum256 project_hash, checksum256 withdraw_hash, asset amount, document return_statement);
void createwthd3(name coopname, name application, name username, checksum256 project_hash, checksum256 withdraw_hash, asset amount, document2 return_statement);
[[eosio::action]]
void capauthwthd3(eosio::name coopname, uint64_t withdraw_id, document authorization);
void capauthwthd3(eosio::name coopname, checksum256 withdraw_hash, document2 authorization);
[[eosio::action]]
void approvewthd3(name coopname, name application, name approver, checksum256 withdraw_hash, document approved_return_statement);
void approvewthd3(name coopname, name application, name approver, checksum256 withdraw_hash, document2 approved_return_statement);
[[eosio::action]]
void createproj (
@@ -74,93 +70,124 @@ public:
std::string subject
);
// claims
// results
[[eosio::action]]
void createclaim(
void updaterslt(
eosio::name coopname,
eosio::name application,
eosio::name username,
checksum256 assignment_hash,
checksum256 result_hash
);
[[eosio::action]]
void claimnow(name coopname, name application, name username, checksum256 result_hash, document statement);
void pushrslt(name coopname, name application, checksum256 result_hash, document2 statement);
[[eosio::action]]
void capauthclaim(eosio::name coopname, uint64_t claim_id, document decision);
void authrslt(eosio::name coopname, checksum256 result_hash, document2 decision);
[[eosio::action]]
void approveclaim(eosio::name coopname, eosio::name application, eosio::name approver, eosio::name username, checksum256 result_hash, document approved_statement);
void approverslt(eosio::name coopname, eosio::name application, eosio::name approver, checksum256 result_hash, document2 approved_statement);
// конвертация
[[eosio::action]]
void approvecnvrt(eosio::name coopname, eosio::name application, eosio::name approver, checksum256 convert_hash, document approved_statement);
void approvecnvrt(eosio::name coopname, eosio::name application, eosio::name approver, checksum256 convert_hash, document2 approved_statement);
[[eosio::action]]
void createcnvrt(
eosio::name coopname,
eosio::name application,
eosio::name username,
checksum256 result_hash,
checksum256 assignment_hash,
checksum256 convert_hash,
document convert_statement
document2 convert_statement
);
[[eosio::action]]
void startdistrbn(name coopname, name application, checksum256 result_hash);
void startdistrbn(name coopname, name application, checksum256 assignment_hash);
[[eosio::action]]
void addauthor(name coopname, name application, checksum256 project_hash, name author, uint64_t shares);
// Коммиты
[[eosio::action]]
void approvecmmt(eosio::name coopname, eosio::name application, eosio::name approver, checksum256 commit_hash, document approved_statement);
void createcmmt(eosio::name coopname, eosio::name application, eosio::name username, checksum256 assignment_hash, checksum256 commit_hash, uint64_t contributed_hours);
[[eosio::action]]
void createcmmt(eosio::name coopname, eosio::name application, eosio::name creator, checksum256 result_hash, checksum256 commit_hash, uint64_t contributed_hours, document contribution_statement);
void approvecmmt(eosio::name coopname, checksum256 commit_hash, document2 empty_document);
[[eosio::action]]
void setact1(eosio::name coopname, eosio::name application, eosio::name username, checksum256 commit_hash, document act);
void declinecmmt(eosio::name coopname, checksum256 commit_hash, std::string reason);
[[eosio::action]]
void setact2(eosio::name coopname, eosio::name application, eosio::name username, checksum256 commit_hash, document act);
void delcmmt(eosio::name coopname, eosio::name application, eosio::name approver, checksum256 commit_hash);
// Долги
[[eosio::action]]
void capauthcmmt(eosio::name coopname, uint64_t commit_id, document authorization);
void createdebt(name coopname, name username, checksum256 assignment_hash, checksum256 debt_hash, asset amount, time_point_sec repaid_at, document2 statement);
[[eosio::action]]
void approvedebt(eosio::name coopname, checksum256 debt_hash, document2 approved_statement);
[[eosio::action]]
void debtauthcnfr(eosio::name coopname, checksum256 debt_hash, document2 decision);
[[eosio::action]]
void debtpaycnfrm(name coopname, checksum256 debt_hash);
[[eosio::action]]
void debtpaydcln(name coopname, checksum256 debt_hash, std::string reason);
[[eosio::action]]
void declinedebt(name coopname, checksum256 debt_hash, std::string reason);
[[eosio::action]]
void settledebt(name coopname);
[[eosio::action]]
void setact1(eosio::name coopname, eosio::name application, eosio::name username, checksum256 commit_hash, document2 act);
[[eosio::action]]
void setact2(eosio::name coopname, eosio::name application, eosio::name username, checksum256 commit_hash, document2 act);
// Регистрация
[[eosio::action]]
void regcontrib(eosio::name coopname, eosio::name application, eosio::name username, checksum256 project_hash, uint64_t convert_percent, eosio::asset rate_per_hour, time_point_sec created_at, document agreement);
void regcontrib(eosio::name coopname, eosio::name application, eosio::name username, checksum256 project_hash, uint64_t convert_percent, eosio::asset rate_per_hour, time_point_sec created_at, document2 agreement);
[[eosio::action]]
void capregcontr(eosio::name coopname, uint64_t contributor_id, document authorization);
void capregcontr(eosio::name coopname, uint64_t contributor_id, document2 authorization);
[[eosio::action]]
void approvereg(eosio::name coopname, eosio::name application, eosio::name approver, checksum256 project_hash, eosio::name username, document approved_agreement);
void approvereg(eosio::name coopname, eosio::name application, eosio::name approver, checksum256 project_hash, eosio::name username, document2 approved_agreement);
// Инвестиции
[[eosio::action]]
void createinvest(name coopname, name application, name username, checksum256 project_hash, checksum256 invest_hash, asset amount, document statement);
void createinvest(name coopname, name application, name username, checksum256 project_hash, checksum256 invest_hash, asset amount, document2 statement);
[[eosio::action]]
void capauthinvst(eosio::name coopname, uint64_t invest_id, document authorization);
void capauthinvst(eosio::name coopname, checksum256 invest_hash, document2 authorization);
[[eosio::action]]
void approveinvst(name coopname, name application, name approver, checksum256 invest_hash, document approved_statement);
void approveinvst(name coopname, name application, name approver, checksum256 invest_hash, document2 approved_statement);
[[eosio::action]]
void allocate(eosio::name coopname, eosio::name application, checksum256 project_hash, checksum256 result_hash, eosio::asset amount);
void allocate(eosio::name coopname, eosio::name application, checksum256 project_hash, checksum256 assignment_hash, eosio::asset amount);
[[eosio::action]]
void diallocate(eosio::name coopname, eosio::name application, checksum256 project_hash, checksum256 result_hash, eosio::asset amount);
void diallocate(eosio::name coopname, eosio::name application, checksum256 project_hash, checksum256 assignment_hash, eosio::asset amount);
[[eosio::action]]
void approvewthd1(name coopname, name application, name approver, checksum256 withdraw_hash, document approved_return_statement);
void approvewthd1(name coopname, name application, name approver, checksum256 withdraw_hash, document2 approved_return_statement);
// Расходы
[[eosio::action]]
void createexpnse(eosio::name coopname, eosio::name application, checksum256 expense_hash, checksum256 result_hash, name creator, uint64_t fund_id, asset amount, std::string description, document statement);
void createexpnse(eosio::name coopname, eosio::name application, checksum256 expense_hash, checksum256 assignment_hash, name creator, uint64_t fund_id, asset amount, std::string description, document2 statement);
[[eosio::action]]
void approveexpns(name coopname, name application, name approver, checksum256 expense_hash, document approved_statement);
void approveexpns(name coopname, name application, name approver, checksum256 expense_hash, document2 approved_statement);
[[eosio::action]]
void capauthexpns(eosio::name coopname, uint64_t expense_id, document authorization);
void capauthexpns(eosio::name coopname, checksum256 expense_hash, document2 authorization);
[[eosio::action]]
void exppaycnfrm(eosio::name coopname, checksum256 expense_hash);
// Членские взносы
[[eosio::action]] void fundproj(eosio::name coopname, checksum256 project_hash, asset amount, std::string memo);
[[eosio::action]] void refreshproj(name coopname, name application, checksum256 project_hash, name username);
@@ -191,14 +218,14 @@ private:
* @return Текущее глобальное состояние.
*/
global_state get_global_state(name coopname);
void ensure_contributor(name coopname, name username);
static bonus_result calculcate_capital_amounts(int64_t spend_amount);
static bonus_result calculcate_capital_amounts(const eosio::asset& spended);
std::optional<author> get_author(eosio::name coopname, eosio::name username, const checksum256 &project_hash);
std::optional<creator> get_creator(eosio::name coopname, eosio::name username, const checksum256 &result_hash);
std::optional<result> get_result(eosio::name coopname, const checksum256 &result_hash);
std::optional<creator> get_creator(eosio::name coopname, eosio::name username, const checksum256 &assignment_hash);
std::optional<assignment> get_assignment(eosio::name coopname, const checksum256 &assignment_hash);
std::optional<debt> get_debt(eosio::name coopname, const checksum256 &debt_hash);
std::optional<project> get_project(eosio::name coopname, const checksum256 &project_hash);
std::optional<project> get_master_project(eosio::name coopname);
@@ -208,14 +235,17 @@ private:
int64_t get_capital_user_share_balance(eosio::name coopname, eosio::name username);
std::optional<claim> get_claim(eosio::name coopname, const checksum256 &result_hash, eosio::name username);
std::optional<result> get_result_by_assignment_and_username(eosio::name coopname, const checksum256 &assignment_hash, eosio::name username);
std::optional<result> get_result(eosio::name coopname, const checksum256 &result_hash);
std::optional<convert> get_convert(eosio::name coopname, const checksum256 &hash);
std::optional<result_author> get_result_author(eosio::name coopname, eosio::name username, const checksum256 &result_hash);
std::optional<commit> get_commit(eosio::name coopname, const checksum256 &hash);
std::optional<invest> get_invest(eosio::name coopname, const checksum256 &invest_hash);
std::optional<capital_tables::result_withdraw> get_result_withdraw(eosio::name coopname, const checksum256 &hash);
std::optional<capital_tables::project_withdraw> get_project_withdraw(eosio::name coopname, const checksum256 &hash);
std::optional<capital_tables::program_withdraw> get_program_withdraw(eosio::name coopname, const checksum256 &hash);
std::optional<expense> get_expense(eosio::name coopname, const checksum256 &hash);
@@ -231,17 +261,13 @@ private:
int64_t get_capital_program_share_balance(eosio::name coopname);
std::optional<capital_tables::program_withdraw> get_program_withdraw(eosio::name coopname, const checksum256 &hash);
uint64_t count_authors_by_project(eosio::name coopname, const checksum256 &project_hash);
eosio::asset get_amount_for_withdraw_from_commit(eosio::name coopname, eosio::name username, const checksum256 &hash);
void expense_withdraw_callback(name coopname, checksum256 withdraw_hash);
resactor get_resactor_or_fail(eosio::name coopname, const checksum256 &result_hash, eosio::name username, const char* msg);
std::optional<resactor> get_resactor(eosio::name coopname, const checksum256 &result_hash, eosio::name username);
claim get_claim_or_fail(eosio::name coopname, const checksum256 &result_hash, eosio::name username, const char* msg);
result get_result_or_fail(eosio::name coopname, const checksum256 &result_hash, const char* msg);
creauthor get_creauthor_or_fail(eosio::name coopname, const checksum256 &assignment_hash, eosio::name username, const char* msg);
std::optional<creauthor> get_creauthor(eosio::name coopname, const checksum256 &assignment_hash, eosio::name username);
result get_result_by_assignment_and_username_or_fail(eosio::name coopname, const checksum256 &assignment_hash, eosio::name username, const char* msg);
assignment get_assignment_or_fail(eosio::name coopname, const checksum256 &assignment_hash, const char* msg);
};
@@ -6,50 +6,53 @@
using namespace eosio;
struct bonus_result {
int64_t creators_bonus;
int64_t authors_bonus;
int64_t generated;
int64_t capitalists_bonus;
int64_t total;
asset author_base;
asset creator_base;
asset creators_bonus;
asset authors_bonus;
asset generated;
asset capitalists_bonus;
asset total;
};
// resactors.hpp (или в capital.hpp)
struct [[eosio::table, eosio::contract(CAPITAL)]] resactor {
// creauthors.hpp (или в capital.hpp)
struct [[eosio::table, eosio::contract(CAPITAL)]] creauthor {
uint64_t id;
checksum256 project_hash; // С каким результатом связана запись
checksum256 result_hash; // С каким результатом связана запись
eosio::name username; // Чей это учёт
checksum256 assignment_hash; // С каким результатом связана запись
eosio::name username; //
eosio::asset provisional_amount = asset(0, _root_govern_symbol);
eosio::asset debt_amount = asset(0, _root_govern_symbol);
eosio::asset spended = asset(0, _root_govern_symbol);
eosio::asset available = asset(0, _root_govern_symbol);
eosio::asset for_convert = asset(0, _root_govern_symbol);
eosio::asset spend = asset(0, _root_govern_symbol);
// Сколько пользователь имеет «авторских долей» в этом результате
uint64_t authors_shares = 0;
uint64_t author_shares = 0;
// Сколько пользователь имеет «создательских долей» в creators_bonus
uint64_t creators_bonus_shares = 0;
uint64_t creator_bonus_shares = 0;
// Сколько часов вложено в результат
// Сколько часов вложено в задание
uint64_t contributed_hours = 0;
uint64_t primary_key() const { return id; }
checksum256 by_result_hash() const { return result_hash; } ///< Индекс по хэшу результата
checksum256 by_assignment_hash() const { return assignment_hash; } ///< Индекс по хэшу задания
checksum256 by_project_hash() const { return project_hash; } ///< Индекс по хэшу проекта
// Индекс по (result_hash + username)
// Индекс по (assignment_hash + username)
uint128_t by_resuser() const {
return combine_checksum_ids(result_hash, username);
return combine_checksum_ids(assignment_hash, username);
}
};
typedef eosio::multi_index<
"resactors"_n, resactor,
indexed_by<"byproject"_n, const_mem_fun<resactor, checksum256, &resactor::by_project_hash>>,
indexed_by<"byresult"_n, const_mem_fun<resactor, checksum256, &resactor::by_result_hash>>,
indexed_by<"byresuser"_n, const_mem_fun<resactor, uint128_t, &resactor::by_resuser>>
> resactor_index;
"creauthors"_n, creauthor,
indexed_by<"byproject"_n, const_mem_fun<creauthor, checksum256, &creauthor::by_project_hash>>,
indexed_by<"byassignment"_n, const_mem_fun<creauthor, checksum256, &creauthor::by_assignment_hash>>,
indexed_by<"byresuser"_n, const_mem_fun<creauthor, uint128_t, &creauthor::by_resuser>>
> creauthor_index;
@@ -61,22 +64,22 @@ struct [[eosio::table, eosio::contract(CAPITAL)]] expense {
name status = "created"_n; ///< Статус расхода (created | approved | authorized)
checksum256 project_hash; ///< Хэш проекта, связанного с расходом.
checksum256 result_hash; ///< Хэш результата, связанного с расходом.
checksum256 assignment_hash; ///< Хэш задания, связанного с расходом.
checksum256 expense_hash; ///< Хэш расхода.
uint64_t fund_id; ///< Идентификатор фонда списания (expfunds в контакте fund)
eosio::asset amount; ///< Сумма расхода.
std::string description; ///< Публичное описание расхода.
document expense_statement; ///< Служебная записка
document approved_statement; ///< принятая записка председателем или доверенным
document authorization; ///< утвержденная записка советом
document2 expense_statement; ///< Служебная записка
document2 approved_statement; ///< принятая записка председателем или доверенным
document2 authorization; ///< утвержденная записка советом
time_point_sec spend_at = current_time_point(); ///< Дата и время создания расхода.
time_point_sec spended_at = current_time_point(); ///< Дата и время создания расхода.
uint64_t primary_key() const { return id; } ///< Основной ключ.
uint64_t by_username() const { return username.value; } ///< По имени пользователя.
checksum256 by_expense_hash() const { return expense_hash; } ///< Индекс по хэшу задачи.
checksum256 by_result_hash() const { return result_hash; } ///< Индекс по хэшу результата.
checksum256 by_assignment_hash() const { return assignment_hash; } ///< Индекс по хэшу задания.
checksum256 by_project_hash() const { return project_hash; } ///< Индекс по хэшу проекта.
};
@@ -85,7 +88,7 @@ struct [[eosio::table, eosio::contract(CAPITAL)]] expense {
"expenses"_n, expense,
indexed_by<"byusername"_n, const_mem_fun<expense, uint64_t, &expense::by_username>>,
indexed_by<"byhash"_n, const_mem_fun<expense, checksum256, &expense::by_expense_hash>>,
indexed_by<"byresulthash"_n, const_mem_fun<expense, checksum256, &expense::by_result_hash>>,
indexed_by<"byassignment"_n, const_mem_fun<expense, checksum256, &expense::by_assignment_hash>>,
indexed_by<"byprojhash"_n, const_mem_fun<expense, checksum256, &expense::by_project_hash>>
> expense_index;
@@ -101,22 +104,24 @@ struct [[eosio::table, eosio::contract(CAPITAL)]] commit {
name username; ///< Имя пользователя, совершившего действие.
name status; ///< Статус коммита (created | approved | authorized | act1 | act2 )
checksum256 project_hash; ///< Хэш проекта, связанного с действием.
checksum256 result_hash; ///< Хэш результата, связанного с действием.
checksum256 assignment_hash; ///< Хэш задания, связанного с действием.
checksum256 commit_hash; ///< Хэш действия.
uint64_t contributed_hours; ///< Сумма временных затрат, связанная с действием.
eosio::asset spend; ///< Сумма затрат, связанная с действием.
eosio::asset rate_per_hour = asset(0, _root_govern_symbol); ///< Стоимость часа
eosio::asset spended = asset(0, _root_govern_symbol); ///< Сумма затрат, связанная с действием.
eosio::asset generated = asset(0, _root_govern_symbol); ///< Сумма генерации, связанная с действием.
eosio::asset creators_bonus = asset(0, _root_govern_symbol); ///< Сумма затрат, связанная с действием.
eosio::asset authors_bonus = asset(0, _root_govern_symbol);///< Сумма затрат, связанная с действием.
eosio::asset capitalists_bonus = asset(0, _root_govern_symbol); ///< Сумма затрат, связанная с действием.
eosio::asset total = asset(0, _root_govern_symbol); ///< Суммарная стоимость коммита на будущем приёме задания с учетом капитализации и генерации
document contribution_statement; ///< Техническое задание (спецификация) как приложение к договору УХД
document approved_statement; ///< Одобрение председателя или доверенного лица
document authorization; ///< Решение совета
document act1; ///< акт приема-передачи (1)
document act2; ///< акт приема-передачи (2)
std::string decline_comment;
time_point_sec created_at; ///< Дата и время создания действия.
uint64_t primary_key() const { return id; } ///< Основной ключ.
uint64_t by_username() const { return username.value; } ///< По имени пользователя.
checksum256 by_commit_hash() const { return commit_hash; } ///< Индекс по хэшу задачи.
checksum256 by_result_hash() const { return result_hash; } ///< Индекс по хэшу результата.
checksum256 by_assignment_hash() const { return assignment_hash; } ///< Индекс по хэшу задания.
checksum256 by_project_hash() const { return project_hash; } ///< Индекс по хэшу проекта.
};
@@ -124,7 +129,7 @@ typedef eosio::multi_index<
"commits"_n, commit,
indexed_by<"byusername"_n, const_mem_fun<commit, uint64_t, &commit::by_username>>,
indexed_by<"byhash"_n, const_mem_fun<commit, checksum256, &commit::by_commit_hash>>,
indexed_by<"byresulthash"_n, const_mem_fun<commit, checksum256, &commit::by_result_hash>>,
indexed_by<"byassignment"_n, const_mem_fun<commit, checksum256, &commit::by_assignment_hash>>,
indexed_by<"byprojhash"_n, const_mem_fun<commit, checksum256, &commit::by_project_hash>>
> commit_index;
@@ -143,8 +148,8 @@ struct [[eosio::table, eosio::contract(CAPITAL)]] invest {
eosio::asset amount = asset(0, _root_govern_symbol); ///< Сумма инвестиции.
name status; ///< created | signed | authorized | blocked
time_point_sec invested_at; ///< Дата приёма инвестиции.
document invest_statement; ///< Заявление на зачёт из кошелька.
document approved_statement; ///< Подпись председателя на принятом заявлении.
document2 invest_statement; ///< Заявление на зачёт из кошелька.
document2 approved_statement; ///< Подпись председателя на принятом заявлении.
uint64_t primary_key() const { return id; } ///< Основной ключ.
uint64_t by_username() const { return username.value; } ///< Индекс по имени аккаунта.
@@ -172,9 +177,9 @@ struct [[eosio::table, eosio::contract(CAPITAL)]] contributor {
checksum256 project_hash;
name status;
time_point_sec created_at;
document agreement;
document approved_agreement;
document authorization;
document2 agreement;
document2 approved_agreement;
document2 authorization;
eosio::asset invested = asset(0, _root_govern_symbol);
@@ -183,12 +188,13 @@ struct [[eosio::table, eosio::contract(CAPITAL)]] contributor {
eosio::asset rate_per_hour = asset(0, _root_govern_symbol);
eosio::asset spend = asset(0, _root_govern_symbol);
eosio::asset spended = asset(0, _root_govern_symbol);
eosio::asset debt_amount = asset(0, _root_govern_symbol);
eosio::asset withdrawed = asset(0, _root_govern_symbol);
eosio::asset converted = asset(0, _root_govern_symbol);
eosio::asset expensed = asset(0, _root_govern_symbol);
eosio::asset returned = asset(0, _root_govern_symbol);
eosio::asset claimed = asset(0, _root_govern_symbol);
eosio::asset share_balance = asset(0, _root_govern_symbol); ///< Баланс долей пайщика
eosio::asset pending_rewards = asset(0, _root_govern_symbol); ///< Накопленные награды
@@ -227,19 +233,27 @@ struct [[eosio::table, eosio::contract(CAPITAL)]] project {
uint64_t authors_count;
uint64_t authors_shares;
uint64_t commits_count;
std::vector<uint64_t> expense_funds = {4};
eosio::asset target = asset(0, _root_govern_symbol);
eosio::asset invested = asset(0, _root_govern_symbol);
eosio::asset available = asset(0, _root_govern_symbol);
eosio::asset allocated = asset(0, _root_govern_symbol);
eosio::asset creators_base = asset(0, _root_govern_symbol);
eosio::asset creators_bonus = asset(0, _root_govern_symbol);
eosio::asset authors_bonus = asset(0, _root_govern_symbol);
eosio::asset capitalists_bonus = asset(0, _root_govern_symbol);
eosio::asset total = asset(0, _root_govern_symbol); // стоимость проекта с учетом генерации и капитализации
eosio::asset expensed = asset(0, _root_govern_symbol);
eosio::asset spend = asset(0, _root_govern_symbol);
eosio::asset spended = asset(0, _root_govern_symbol);
eosio::asset generated = asset(0, _root_govern_symbol);
eosio::asset converted = asset(0, _root_govern_symbol);
eosio::asset claimed = asset(0, _root_govern_symbol);
eosio::asset withdrawed = asset(0, _root_govern_symbol);
double parent_distribution_ratio = 1;
int64_t membership_cumulative_reward_per_share = 0;
@@ -261,59 +275,62 @@ typedef eosio::multi_index<"projects"_n, project,
> project_index;
struct [[eosio::table, eosio::contract(CAPITAL)]] result {
struct [[eosio::table, eosio::contract(CAPITAL)]] assignment {
uint64_t id;
checksum256 result_hash;
checksum256 assignment_hash;
checksum256 project_hash;
eosio::name status = "created"_n; ///< created
eosio::name status = "opened"_n; ///< opened | closed
eosio::name coopname;
eosio::name assignee;
std::string description;
uint64_t authors_shares;
uint64_t total_creators_bonus_shares;
uint64_t authors_count;
uint64_t commits_count;
time_point_sec created_at = current_time_point();
time_point_sec expired_at = eosio::time_point_sec(eosio::current_time_point().sec_since_epoch() + 365 * 86400);
uint64_t authors_shares;
uint64_t total_creators_bonus_shares;
uint64_t authors_count;
uint64_t commits_count;
eosio::asset allocated = asset(0, _root_govern_symbol); ///< аллоцированные на создание задания средства
eosio::asset available = asset(0, _root_govern_symbol); ///< зарезерированные на создание задания средства
eosio::asset spended = asset(0, _root_govern_symbol); ///< фактически потраченные ресурсы на создание задание в виде времени (паевые взносы-возвраты)
eosio::asset generated = asset(0, _root_govern_symbol); ///< стоимость РИД с учётом премий авторов и создателей
eosio::asset expensed = asset(0, _root_govern_symbol); ///< фактически потраченные на создание задания средства в виде расходов (подписки, прочее)
eosio::asset withdrawed = asset(0, _root_govern_symbol); ///< фактически возвращенные средства из задания
eosio::asset allocated = asset(0, _root_govern_symbol); ///< аллоцированные на создание результата средства
eosio::asset available = asset(0, _root_govern_symbol); ///< зарезерированные на создание результата средства
eosio::asset spend = asset(0, _root_govern_symbol); ///< фактически потраченные ресурсы на создание результат в виде времени (паевые взносы-возвраты)
eosio::asset expensed = asset(0, _root_govern_symbol); ///< фактически потраченные на создание результата средства в виде расходов (подписки, прочее)
eosio::asset withdrawed = asset(0, _root_govern_symbol); ///< фактически возвращенные средства из результата
eosio::asset creators_base = asset(0, _root_govern_symbol); ///< себестоимость РИД
eosio::asset creators_amount = asset(0, _root_govern_symbol); ///< себестоимость РИД
eosio::asset generated_amount = asset(0, _root_govern_symbol); ///< стоимость РИД с учётом премий авторов и создателей
eosio::asset creators_bonus = asset(0, _root_govern_symbol); ///< премии создателей - 0.382 от себестоимости (creators_amount)
eosio::asset authors_bonus = asset(0, _root_govern_symbol); ///< премии авторов - 1.618 от себестоимости (creators_amount)
eosio::asset creators_bonus = asset(0, _root_govern_symbol); ///< премии создателей - 0.382 от себестоимости (creators_base)
eosio::asset authors_bonus = asset(0, _root_govern_symbol); ///< премии авторов - 1.618 от себестоимости (creators_base)
eosio::asset capitalists_bonus = asset(0, _root_govern_symbol); ///< премии пайщиков кооператива - 1.618 от generated_amount
eosio::asset total_amount = asset(0, _root_govern_symbol); ///< Капитализация РИД (стоимость РИД в generated_amount + capitalists_bonus)
eosio::asset total = asset(0, _root_govern_symbol); ///< Стоимость РИД с учетом генерации и капитализации (стоимость РИД в spended + authors_bonus + creators_bonus + capitalists_bonus)
eosio::asset authors_bonus_remain = asset(0, _root_govern_symbol); ///< сумма остатка для выплаты авторам
eosio::asset creators_amount_remain = asset(0, _root_govern_symbol); ///< сумма остатка для выплаты авторам
eosio::asset creators_base_remain = asset(0, _root_govern_symbol); ///< сумма остатка для выплаты авторам
eosio::asset creators_bonus_remain = asset(0, _root_govern_symbol); ///< сумма остатка для выплаты авторам
eosio::asset capitalists_bonus_remain = asset(0, _root_govern_symbol); ///< сумма остатка для выплаты пайщикам
uint64_t primary_key() const { return id; } ///< Основной ключ.
checksum256 by_hash() const { return result_hash; } ///< Индекс по хэшу результата.
checksum256 by_hash() const { return assignment_hash; } ///< Индекс по хэшу задания.
checksum256 by_project_hash() const { return project_hash; } ///< Индекс по хэшу идеи
};
typedef eosio::multi_index<"results"_n, result,
indexed_by<"byhash"_n, const_mem_fun<result, checksum256, &result::by_hash>>,
indexed_by<"byprojecthash"_n, const_mem_fun<result, checksum256, &result::by_project_hash>>
> result_index;
typedef eosio::multi_index<"assignments"_n, assignment,
indexed_by<"byhash"_n, const_mem_fun<assignment, checksum256, &assignment::by_hash>>,
indexed_by<"byprojecthash"_n, const_mem_fun<assignment, checksum256, &assignment::by_project_hash>>
> assignment_index;
struct [[eosio::table, eosio::contract(CAPITAL)]] claim {
struct [[eosio::table, eosio::contract(CAPITAL)]] result {
uint64_t id;
checksum256 project_hash;
checksum256 assignment_hash;
checksum256 result_hash;
eosio::name coopname;
@@ -323,39 +340,50 @@ struct [[eosio::table, eosio::contract(CAPITAL)]] claim {
eosio::name status = "created"_n; ///< created | statement | decision | act1 | act2 | completed
time_point_sec created_at = current_time_point();
eosio::asset author_amount = asset(0, _root_govern_symbol);
eosio::asset creator_amount = asset(0, _root_govern_symbol);
eosio::asset capitalist_amount = asset(0, _root_govern_symbol);
eosio::asset creator_base_amount = asset(0, _root_govern_symbol);
eosio::asset debt_amount = asset(0, _root_govern_symbol);
eosio::asset creator_bonus_amount = asset(0, _root_govern_symbol);
eosio::asset author_bonus_amount = asset(0, _root_govern_symbol);
eosio::asset generation_amount = asset(0, _root_govern_symbol);
eosio::asset capitalist_bonus_amount = asset(0, _root_govern_symbol);
eosio::asset total_amount = asset(0, _root_govern_symbol);
eosio::asset available_for_return = asset(0, _root_govern_symbol);
eosio::asset available_for_convert = asset(0, _root_govern_symbol);
document claim_statement; ///< Заявление
document approved_statement; ///< Принятое заявление
document authorization; ///< Решение
document2 result_statement; ///< Заявление
document2 approved_statement; ///< Принятое заявление
document2 authorization; ///< Решение совета
document2 act1; ///< Акт1
document2 act2; ///< Акт2
uint64_t primary_key() const { return id; } ///< Основной ключ.
uint64_t by_username() const { return username.value; } ///< Индекс по владельцу
checksum256 by_result_hash() const { return result_hash; } ///< Индекс по хэшу
checksum256 by_hash() const { return result_hash; } ///< Индекс по хэшу проекта
checksum256 by_assignment_hash() const { return assignment_hash; } ///< Индекс по хэшу
checksum256 by_project_hash() const { return project_hash; } ///< Индекс по хэшу проекта
uint128_t by_result_user() const {
return combine_checksum_ids(result_hash, username);
uint128_t by_assignment_user() const {
return combine_checksum_ids(assignment_hash, username);
}
};
typedef eosio::multi_index<"claims"_n, claim,
indexed_by<"byusername"_n, const_mem_fun<claim, uint64_t, &claim::by_username>>,
indexed_by<"byresult"_n, const_mem_fun<claim, checksum256, &claim::by_result_hash>>,
indexed_by<"byprojecthash"_n, const_mem_fun<claim, checksum256, &claim::by_project_hash>>,
indexed_by<"byresuser"_n, const_mem_fun<claim, uint128_t, &claim::by_result_user>>
> claim_index;
typedef eosio::multi_index<"results"_n, result,
indexed_by<"byusername"_n, const_mem_fun<result, uint64_t, &result::by_username>>,
indexed_by<"byhash"_n, const_mem_fun<result, checksum256, &result::by_hash>>,
indexed_by<"byassignment"_n, const_mem_fun<result, checksum256, &result::by_assignment_hash>>,
indexed_by<"byprojecthash"_n, const_mem_fun<result, checksum256, &result::by_project_hash>>,
indexed_by<"byresuser"_n, const_mem_fun<result, uint128_t, &result::by_assignment_user>>
> result_index;
struct [[eosio::table, eosio::contract(CAPITAL)]] convert {
uint64_t id;
checksum256 project_hash;
checksum256 result_hash;
checksum256 assignment_hash;
checksum256 convert_hash;
eosio::name coopname;
@@ -365,25 +393,25 @@ struct [[eosio::table, eosio::contract(CAPITAL)]] convert {
eosio::asset convert_amount = asset(0, _root_govern_symbol);
document convert_statement; ///< Заявление
document2 convert_statement; ///< Заявление
time_point_sec created_at = current_time_point();
uint64_t primary_key() const { return id; } ///< Основной ключ.
uint64_t by_username() const { return username.value; } ///< Индекс по владельцу
checksum256 by_convert_hash() const { return convert_hash; } ///< Индекс по хэшу
checksum256 by_result_hash() const { return result_hash; } ///< Индекс по хэшу
checksum256 by_assignment_hash() const { return assignment_hash; } ///< Индекс по хэшу
checksum256 by_project_hash() const { return project_hash; } ///< Индекс по хэшу проекта
uint128_t by_result_user() const {
return combine_checksum_ids(result_hash, username);
uint128_t by_assignment_user() const {
return combine_checksum_ids(assignment_hash, username);
}
};
typedef eosio::multi_index<"converts"_n, convert,
indexed_by<"byusername"_n, const_mem_fun<convert, uint64_t, &convert::by_username>>,
indexed_by<"byhash"_n, const_mem_fun<convert, checksum256, &convert::by_convert_hash>>,
indexed_by<"byresult"_n, const_mem_fun<convert, checksum256, &convert::by_result_hash>>,
indexed_by<"byassignment"_n, const_mem_fun<convert, checksum256, &convert::by_assignment_hash>>,
indexed_by<"byprojecthash"_n, const_mem_fun<convert, checksum256, &convert::by_project_hash>>
> convert_index;
@@ -410,60 +438,32 @@ struct [[eosio::table, eosio::contract(CAPITAL)]] author {
> authors_index;
/**
* @brief Таблица для учёта авторства на результатах
* Принимает в себя копии объектов авторов из проекта. И используется для распределения премий по конкретному результату.
*/
struct [[eosio::table, eosio::contract(CAPITAL)]] result_author {
uint64_t id;
checksum256 project_hash;
checksum256 result_hash;
eosio::name username;
uint64_t shares;
uint64_t primary_key() const { return id; } ///< Основной ключ
uint64_t by_username() const { return username.value; } ///< Индекс по имени пользователя
checksum256 by_project_hash() const { return project_hash; } ///< Индекс по хэшу идеи
uint128_t by_result_author() const {
return combine_checksum_ids(project_hash, username);
}
};
typedef eosio::multi_index<"resauthors"_n, result_author,
indexed_by<"byusername"_n, const_mem_fun<result_author, uint64_t, &result_author::by_username>>,
indexed_by<"byprojecthash"_n, const_mem_fun<result_author, checksum256, &result_author::by_project_hash>>,
indexed_by<"byresauthor"_n, const_mem_fun<result_author, uint128_t, &result_author::by_result_author>>
> result_authors_index;
struct [[eosio::table, eosio::contract(CAPITAL)]] creator {
uint64_t id; ///< id и primary_key
checksum256 project_hash; ///< Хэш идеи
checksum256 result_hash; ///< Хэш результата интеллектуальной деятельности
checksum256 assignment_hash; ///< Хэш задания интеллектуальной деятельности
eosio::name username; ///< Имя пользователя
eosio::asset spend = asset(0, _root_govern_symbol); ///< Стоимость использованных ресурсов
eosio::asset spended = asset(0, _root_govern_symbol); ///< Стоимость использованных ресурсов
uint64_t primary_key() const { return id; }
checksum256 by_result_hash() const { return result_hash; }
checksum256 by_assignment_hash() const { return assignment_hash; }
checksum256 by_project_hash() const { return project_hash; }
uint128_t by_result_creator() const {
return combine_checksum_ids(result_hash, username);
uint128_t by_assignment_creator() const {
return combine_checksum_ids(assignment_hash, username);
}
uint64_t by_username() const { return username.value; }
};
typedef eosio::multi_index<"creators"_n, creator,
indexed_by<"byresulthash"_n, const_mem_fun<creator, checksum256, &creator::by_result_hash>>,
indexed_by<"byassignment"_n, const_mem_fun<creator, checksum256, &creator::by_assignment_hash>>,
indexed_by<"byprojecthash"_n, const_mem_fun<creator, checksum256, &creator::by_project_hash>>,
indexed_by<"byusername"_n, const_mem_fun<creator, uint64_t, &creator::by_username>>,
indexed_by<"byresultcrtr"_n, const_mem_fun<creator, uint128_t, &creator::by_result_creator>>
indexed_by<"byassigncrtr"_n, const_mem_fun<creator, uint128_t, &creator::by_assignment_creator>>
> creators_index;
/**
@@ -513,19 +513,19 @@ namespace capital_tables {
uint64_t id; ///< Уникальный ID запроса на возврат.
name coopname; ///< Имя аккаунта кооператива
checksum256 project_hash; ///< Хэш проекта
checksum256 result_hash; ///< Хэш результата
checksum256 assignment_hash; ///< Хэш задания
checksum256 withdraw_hash; ///< Уникальный внешний ключ
name username; ///< Имя аккаунта участника, запрашивающего возврат.
name status = "created"_n; ///< Статус взноса-возврата (created | approved | )
asset amount = asset(0, _root_govern_symbol); ///< Запрошенная сумма для возврата.
document contribution_statement; ///< Заявление на паевой взнос авторскими правами
document return_statement; ///< Заявление на возврат паевого взноса деньгами
document2 contribution_statement; ///< Заявление на паевой взнос авторскими правами
document2 return_statement; ///< Заявление на возврат паевого взноса деньгами
document approved_contribution_statement; ///< Принятое председателем заявление на взнос
document approved_return_statement; ///< Принятое председателем заявление на возврат взноса деньгами
document2 approved_contribution_statement; ///< Принятое председателем заявление на взнос
document2 approved_return_statement; ///< Принятое председателем заявление на возврат взноса деньгами
document authorized_contribution_statement; ///< Решение совета на приём взноса
document authorized_return_statement; ///< Решение совета на возврат взноса
document2 authorized_contribution_statement; ///< Решение совета на приём взноса
document2 authorized_return_statement; ///< Решение совета на возврат взноса
time_point_sec created_at = current_time_point(); ///< Дата и время создания действия. ///< Время создания запроса.
@@ -539,7 +539,7 @@ namespace capital_tables {
indexed_by<"byhash"_n, const_mem_fun<result_withdraw, checksum256, &result_withdraw::by_hash>>,
indexed_by<"byusername"_n, const_mem_fun<result_withdraw, uint64_t, &result_withdraw::by_account>>,
indexed_by<"bycreated"_n, const_mem_fun<result_withdraw, uint64_t, &result_withdraw::by_created>>
> result_withdraws_index; ///< Таблица для хранения запросов на возврат из результата.
> result_withdraws_index; ///< Таблица для хранения запросов на возврат из задания.
struct [[eosio::table, eosio::contract(CAPITAL)]] project_withdraw {
@@ -550,9 +550,9 @@ namespace capital_tables {
name username; ///< Имя аккаунта участника, запрашивающего возврат.
name status = "created"_n; ///< Статус взноса-возврата (created | approved | )
asset amount = asset(0, _root_govern_symbol); ///< Запрошенная сумма для возврата.
document return_statement; ///< Заявление на возврат паевого взноса деньгами
document2 return_statement; ///< Заявление на возврат паевого взноса деньгами
document approved_return_statement; ///< Принятое председателем заявление на возврат взноса деньгами
document2 approved_return_statement; ///< Принятое председателем заявление на возврат взноса деньгами
time_point_sec created_at = current_time_point(); ///< Дата и время создания действия. ///< Время создания запроса.
@@ -578,9 +578,9 @@ namespace capital_tables {
name username; ///< Имя аккаунта участника, запрашивающего возврат.
name status = "created"_n; ///< Статус взноса-возврата (created | approved | )
asset amount = asset(0, _root_govern_symbol); ///< Запрошенная сумма для возврата.
document return_statement; ///< Заявление на возврат паевого взноса деньгами
document2 return_statement; ///< Заявление на возврат паевого взноса деньгами
document approved_return_statement; ///< Принятое председателем заявление на возврат взноса деньгами
document2 approved_return_statement; ///< Принятое председателем заявление на возврат взноса деньгами
time_point_sec created_at = current_time_point(); ///< Дата и время создания действия. ///< Время создания запроса.
@@ -0,0 +1,50 @@
void capital::createassign(name coopname, name application, checksum256 project_hash, checksum256 assignment_hash, eosio::name assignee, std::string description) {
require_auth(coopname);
auto project = get_project(coopname, project_hash);
eosio::check(project.has_value(), "проект не найден");
// Проверяем, существует ли уже assignment
assignment_index assignments(_capital, coopname.value);
auto assignment = get_assignment(coopname, assignment_hash);
eosio::check(!assignment.has_value(), "Объект задания уже существует");
get_participant_or_fail(coopname, assignee);
// Создаём assignment
assignments.emplace(coopname, [&](auto &n) {
n.id = get_global_id_in_scope(_capital, coopname, "assignments"_n);
n.coopname = coopname;
n.assignee = assignee;
n.description = description;
n.project_hash = project_hash;
n.assignment_hash = assignment_hash;
n.authors_shares = project -> authors_shares;
n.authors_count = project -> authors_count;
});
authors_index authors(_capital, coopname.value);
auto authors_hash_index = authors.get_index<"byprojecthash"_n>();
// Перебираем всех авторов с данным project_hash
auto author_itr = authors_hash_index.lower_bound(project_hash);
uint64_t authors_count = 0;
creauthor_index creathors(_capital, coopname.value);
// Копируем запись автора идеи в assignment_authors
while(author_itr != authors_hash_index.end() && author_itr->project_hash == project_hash) {
creathors.emplace(coopname, [&](auto &ra){
ra.id = creathors.available_primary_key();
ra.assignment_hash = assignment_hash;
ra.project_hash = project_hash;
ra.username = author_itr->username;
ra.author_shares = author_itr -> shares;
});
authors_count++;
author_itr++;
}
eosio::check(authors_count > 0, "Нельзя создать задание без установленных авторов в проекте");
}
@@ -0,0 +1,22 @@
void capital::startdistrbn(name coopname, name application, checksum256 assignment_hash) {
check_auth_or_fail(_capital, coopname, application, "start"_n);
auto assignment = get_assignment(coopname, assignment_hash);
eosio::check(assignment.has_value(), "Задание не найдено");
eosio::check(assignment -> status == "opened"_n, "Только задание в статусе opened может быть запущен в распределение");
auto project = get_project(coopname, assignment -> project_hash);
eosio::check(project.has_value(), "проект не найден");
assignment_index assignments(_capital, coopname.value);
auto assignment_for_modify = assignments.find(assignment -> id);
//заносим доступные средства к распределению
assignments.modify(assignment_for_modify, coopname, [&](auto& row) {
row.status = "closed"_n;
row.authors_bonus_remain = row.authors_bonus;
row.creators_base_remain = row.creators_base;
row.creators_bonus_remain = row.creators_bonus;
row.capitalists_bonus_remain = row.capitalists_bonus;
});
};
@@ -1,25 +0,0 @@
void capital::approveclaim(eosio::name coopname, eosio::name application, eosio::name approver, eosio::name username, checksum256 result_hash, document approved_statement){
check_auth_or_fail(_capital, coopname, application, "approveclaim"_n);
verify_document_or_fail(approved_statement);
auto exist_claim = get_claim(coopname, result_hash, username);
eosio::check(exist_claim.has_value(), "Клайм пользователя для результата не существует");
auto result = get_result(coopname, result_hash);
eosio::check(result.has_value(), "Результат не найден");
claim_index claims(_capital, coopname.value);
auto claim = claims.find(exist_claim -> id);
claims.modify(claim, coopname, [&](auto &a) {
a.status = "approved"_n;
a.approved_statement = approved_statement;
});
//отправляем в совет
action(permission_level{ _capital, "active"_n}, _soviet, "createagenda"_n,
std::make_tuple(coopname, claim -> username, _capital, _capital_claim_authorize_action, claim -> id, claim -> claim_statement, std::string("")))
.send();
};
@@ -1,39 +0,0 @@
void capital::capauthclaim(eosio::name coopname, uint64_t claim_id, document decision) {
require_auth(_soviet);
claim_index claims(_capital, coopname.value);
auto claim = claims.find(claim_id);
eosio::check(claim != claims.end(), "Объект запроса доли не найден");
// Проверяем статус
eosio::check(claim -> status == "statement"_n, "Неверный статус");
auto exist = get_project(coopname, claim -> project_hash);
eosio::check(exist.has_value(),"Проект не найден");
project_index projects(_capital, coopname.value);
auto project = projects.find(exist -> id);
auto contributor = get_active_contributor_or_fail(coopname, claim -> project_hash, claim -> username);
contributor_index contributors(_capital, coopname.value);
auto contributor_for_modify = contributors.find(contributor -> id);
contributors.modify(contributor_for_modify, coopname, [&](auto &c){
c.claimed += claim -> total_amount;
c.share_balance += claim -> total_amount;
});
projects.modify(project, coopname, [&](auto &p) {
p.claimed += claim -> total_amount;
p.total_share_balance += claim -> total_amount;
});
std::string memo = "Зачёт части целевого паевого взноса по договору УХД с ID: " + std::to_string(contributor -> id) + " в качестве паевого взноса по программе 'Цифровой Кошелёк' с ID: " + std::to_string(claim_id);
//Увеличиваем баланс средств в капитализации
Wallet::add_blocked_funds(_capital, coopname, claim -> username, claim -> total_amount, _capital_program, memo);
//Удаляем объект claim за ненадобностью
claims.erase(claim);
};
@@ -1,22 +0,0 @@
void capital::claimnow(name coopname, name application, name username, checksum256 result_hash, document statement) {
check_auth_or_fail(_capital, coopname, application, "claimnow"_n);
// проверяем заявление
verify_document_or_fail(statement);
// извлекаем клайм
auto claim = get_claim(coopname, result_hash, username);
eosio::check(claim.has_value(), "Объект запроса доли не найден");
eosio::check(claim->status == "pending"_n, "Нельзя изменить статус клайма");
eosio::check(claim -> username == username, "Неверно указано имя пользователя владельца результата");
// обновляем клайм, добавляя заявление
claim_index claims(_capital, coopname.value);
auto claim_for_modify = claims.find(claim->id);
claims.modify(claim_for_modify, coopname, [&](auto &c){
c.status = "statement"_n;
c.claim_statement = statement;
});
}
@@ -1,131 +0,0 @@
void capital::createclaim(
eosio::name coopname,
eosio::name application,
eosio::name username,
checksum256 result_hash
) {
// Авторизация
check_auth_or_fail(_capital, coopname, application, "createclaim"_n);
// Получаем результат (или кидаем ошибку)
auto exist_result = get_result_or_fail(coopname, result_hash, "Результат не найден");
eosio::check(exist_result.status == "opened"_n, "Распределение стоимости результата еще не начато или уже завершено");
// Проверяем, нет ли уже такого клайма
auto existing_claim = get_claim(coopname, result_hash, username);
eosio::check(!existing_claim.has_value(), "Клайм уже существует");
// Находим запись в таблице results
result_index results(_capital, coopname.value);
auto result = results.find(exist_result.id);
// Получаем контрибьютора
auto exist_contributor = get_active_contributor_or_fail(coopname, exist_result.project_hash, username);
contributor_index contributors(_capital, coopname.value);
auto contributor = contributors.find(exist_contributor->id);
// Попробуем найти resactor
auto optional_resactor = get_resactor(coopname, result_hash, username);
//=== (A) Авторская часть ===
uint64_t author_amount = 0;
{
// Если resactor есть, считаем долю.
if (optional_resactor.has_value()) {
auto resactor = *optional_resactor;
// Исходная сумма (просто authors_bonus.amount)
uint64_t authors_total = result -> authors_bonus.amount;
// Доля пользователя
uint64_t user_auth_shares = resactor.authors_shares;
// Всего долей авторов
uint64_t total_auth_shares = result -> authors_shares;
if (authors_total > 0 && total_auth_shares > 0 && user_auth_shares > 0) {
uint128_t tmp = (uint128_t)authors_total * (uint128_t)user_auth_shares;
author_amount = (uint64_t)(tmp / (uint128_t)total_auth_shares);
print(result->authors_bonus_remain.amount, ", ", author_amount);
eosio::check(result->authors_bonus_remain.amount >= author_amount,
"Недостаточно средств для авторов");
}
}
}
//=== (B) Создательская часть бонусов ===
uint64_t creator_amount = 0;
{
if (optional_resactor.has_value()) {
auto resactor = *optional_resactor;
uint64_t creators_bonus_total = result->creators_bonus.amount; // вся сумма создателей
uint64_t user_creator_bonus_shares = resactor.creators_bonus_shares;
uint64_t total_creators_bonus_shares= result->total_creators_bonus_shares;
if (creators_bonus_total > 0 && total_creators_bonus_shares > 0 && user_creator_bonus_shares > 0) {
uint128_t tmp = (uint128_t)creators_bonus_total * (uint128_t)user_creator_bonus_shares;
creator_amount = (uint64_t)(tmp / (uint128_t)total_creators_bonus_shares);
eosio::check(result->creators_bonus_remain.amount >= creator_amount, "Недостаточно средств для создателей");
}
}
}
//=== (C) Капиталисты ===
// здесь resactor НЕ обязателен, доли берём из глобальных методов
uint64_t capitalist_amount = 0;
{
// Полная сумма для капиталистов
uint64_t capitals_total = result->capitalists_bonus.amount;
// Пользовательские доли берем из кошелька программы
uint64_t user_cap_shares = get_capital_user_share_balance(coopname, username);
// Общее число долей капиталистов во всей программе
uint64_t total_cap_shares = get_capital_program_share_balance(coopname);
if (capitals_total > 0 && total_cap_shares > 0 && user_cap_shares > 0) {
uint128_t tmp = (uint128_t)capitals_total * (uint128_t)user_cap_shares;
capitalist_amount = (uint64_t)(tmp / (uint128_t)total_cap_shares);
eosio::check(result->capitalists_bonus_remain.amount >= capitalist_amount,
"Недостаточно средств для пайщиков");
}
}
//=== Складываем всё ===
uint64_t total_claim_amount = author_amount + creator_amount + capitalist_amount;
eosio::asset total_amount(total_claim_amount, _root_govern_symbol);
//=== Создаём запись в claims ===
claim_index claims(_capital, coopname.value);
uint64_t claim_id = get_global_id_in_scope(_capital, coopname, "claims"_n);
claims.emplace(coopname, [&](auto &n) {
n.id = claim_id;
n.username = username;
n.result_hash = result_hash;
n.coopname = coopname;
n.status = "created"_n;
n.author_amount = asset(author_amount, _root_govern_symbol);
n.creator_amount = asset(creator_amount, _root_govern_symbol);
n.capitalist_amount = asset(capitalist_amount, _root_govern_symbol);
n.total_amount = total_amount;
});
//=== Уменьшаем остаток bonus_remain ===
results.modify(result, coopname, [&](auto &r){
// авторы
if (author_amount > 0) {
r.authors_bonus_remain -= eosio::asset(author_amount, _root_govern_symbol);
}
// создатели
if (creator_amount > 0) {
r.creators_bonus_remain -= eosio::asset(creator_amount, _root_govern_symbol);
}
// капиталисты
if (capitalist_amount > 0) {
r.capitalists_bonus_remain -= eosio::asset(capitalist_amount, _root_govern_symbol);
}
});
}
@@ -1,27 +1,85 @@
void capital::approvecmmt(eosio::name coopname, eosio::name application, eosio::name approver, checksum256 commit_hash, document approved_statement){
check_auth_or_fail(_capital, coopname, application, "approvecmmt"_n);
verify_document_or_fail(approved_statement);
void capital::approvecmmt(eosio::name coopname, checksum256 commit_hash, document2 empty_document) {
require_auth(_soviet);
auto exist_commit = get_commit(coopname, commit_hash);
eosio::check(exist_commit.has_value(), "Действие с указанным хэшем не существует");
auto result = get_result(coopname, exist_commit -> result_hash);
eosio::check(result.has_value(), "Результат не найден");
eosio::check(result -> status == "created"_n, "Нельзя добавить действие в уже закрытый результат");
eosio::check(exist_commit.has_value(), "Коммит не найден");
commit_index commits(_capital, coopname.value);
auto commit = commits.find(exist_commit -> id);
commits.modify(commit, coopname, [&](auto &a) {
a.status = "approved"_n;
a.approved_statement = approved_statement;
auto exist_assignment = get_assignment(coopname, commit -> assignment_hash);
eosio::check(exist_assignment.has_value(), "Задание не найдено");
eosio::check(exist_assignment -> status == "opened"_n, "Нельзя добавить коммит в уже закрытое задание");
// Обновляем assignment
assignment_index assignments(_capital, coopname.value);
auto assignment = assignments.find(exist_assignment -> id);
assignments.modify(assignment, _capital, [&](auto &row) {
row.spended += commit -> spended;
row.creators_base += commit -> spended;
row.generated += commit -> generated;
row.creators_bonus += commit -> creators_bonus;
row.authors_bonus += commit -> authors_bonus;
row.capitalists_bonus += commit -> capitalists_bonus;
row.total += commit -> total;
row.total_creators_bonus_shares += commit-> spended.amount;
row.commits_count++;
});
// Обновляем проект
auto exist_project = get_project(coopname, commit -> project_hash);
eosio::check(exist_project.has_value(),"Проект не найден");
project_index projects(_capital, coopname.value);
auto project = projects.find(exist_project -> id);
//отправляем в совет
action(permission_level{ _capital, "active"_n}, _soviet, "createagenda"_n,
std::make_tuple(coopname, commit -> username, _capital, _capital_commit_authorize_action, commit -> id, commit -> contribution_statement, std::string("")))
.send();
projects.modify(project, _capital, [&](auto &p) {
p.spended += commit -> spended;
p.generated += commit -> generated;
p.creators_base += commit -> spended;
p.creators_bonus += commit -> creators_bonus;
p.authors_bonus += commit -> authors_bonus;
p.capitalists_bonus += commit -> capitalists_bonus;
p.total += commit -> total;
p.commits_count++;
});
// Обновляем актора и проект
auto exist_contributor = get_active_contributor_or_fail(coopname, commit -> project_hash, commit -> username);
contributor_index contributors(_capital, coopname.value);
auto contributor = contributors.find(exist_contributor -> id);
contributors.modify(contributor, coopname, [&](auto &c){
c.spended += commit->spended;
c.contributed_hours += commit->contributed_hours;
});
// Обновляем запись в creauthors (создательские доли)
auto exist_creauthor = get_creauthor(coopname, commit->assignment_hash, commit->username);
creauthor_index creathors(_capital, coopname.value);
if (!exist_creauthor.has_value()) {
creathors.emplace(_capital, [&](auto &ra){
ra.id = creathors.available_primary_key();
ra.project_hash = commit->project_hash;
ra.assignment_hash = commit->assignment_hash;
ra.username = commit->username;
ra.spended = commit->spended;
ra.contributed_hours = commit->contributed_hours;
// сумма, которая доступна для получения ссуды и используется в качества залога
ra.provisional_amount = commit->spended;
ra.creator_bonus_shares = commit->spended.amount;
});
} else {
auto creauthor = creathors.find(exist_creauthor->id);
creathors.modify(creauthor, _capital, [&](auto &ra) {
ra.spended += commit->spended;
ra.contributed_hours += commit->contributed_hours;
ra.provisional_amount += commit->spended;
ra.creator_bonus_shares += commit->spended.amount;
});
}
commits.erase(commit);
};
@@ -1,16 +0,0 @@
void capital::capauthcmmt(eosio::name coopname, uint64_t commit_id, document authorization) {
require_auth(_soviet);
commit_index commits(_capital, coopname.value);
auto commit = commits.find(commit_id);
eosio::check(commit != commits.end(), "Коммит не найден");
auto contributor = get_active_contributor_or_fail(coopname, commit->project_hash, commit->username);
//TODO: change to coopname
commits.modify(commit, _soviet, [&](auto &n) {
n.status = "authorized"_n;
n.authorization = authorization;
});
};
@@ -1,35 +1,63 @@
void capital::createcmmt(eosio::name coopname, eosio::name application, eosio::name creator, checksum256 result_hash, checksum256 commit_hash, uint64_t contributed_hours, document contribution_statement){
check_auth_or_fail(_capital, coopname, application, "createcmmt"_n);
void capital::createcmmt(eosio::name coopname, eosio::name application, eosio::name username, checksum256 assignment_hash, checksum256 commit_hash, uint64_t contributed_hours){
require_auth(coopname);
verify_document_or_fail(contribution_statement);
auto assignment = get_assignment(coopname, assignment_hash);
eosio::check(assignment.has_value(), "Задание не найдено");
auto result = get_result(coopname, result_hash);
eosio::check(result.has_value(), "Результат не найден");
auto contributor = get_active_contributor_or_fail(coopname, result -> project_hash, creator);
auto contributor = get_active_contributor_or_fail(coopname, assignment -> project_hash, username);
auto exist_commit = get_commit(coopname, commit_hash);
eosio::check(!exist_commit.has_value(), "Действие с указанным хэшем уже существует");
eosio::check(contributed_hours > 0, "Только положительная сумма");
eosio::check(contributed_hours > 0, "Только положительная сумма часов");
eosio::asset spend = contributor -> rate_per_hour * contributed_hours;
// считаем сумму фактических затрат создателя на основе ставки в час и потраченного времени
eosio::asset spended = contributor -> rate_per_hour * contributed_hours;
// Вычисляем премии на основе суммы фактических затрат
auto amounts = capital::calculcate_capital_amounts(spended);
commit_index commits(_capital, coopname.value);
auto commit_id = get_global_id_in_scope(_capital, coopname, "commits"_n);
//TODO: надо смотреть надо ли здесь добавлять creator_base и author_base
commits.emplace(coopname, [&](auto &a) {
a.id = get_global_id_in_scope(_capital, coopname, "commits"_n);
a.id = commit_id;
a.status = "created"_n;
a.coopname = coopname;
a.application = application;
a.username = creator;
a.project_hash = result -> project_hash;
a.result_hash = result_hash;
a.username = username;
a.project_hash = assignment -> project_hash;
a.assignment_hash = assignment_hash;
a.commit_hash = commit_hash;
a.contributed_hours = contributed_hours;
a.spend = spend;
a.rate_per_hour = contributor -> rate_per_hour;
a.spended = spended;
a.generated = amounts.generated;
a.creators_bonus = amounts.creators_bonus;
a.authors_bonus = amounts.authors_bonus;
a.capitalists_bonus = amounts.capitalists_bonus;
a.total = amounts.total;
a.created_at = current_time_point();
a.contribution_statement = contribution_statement;
});
auto empty_doc = document2{};
//отправить на approve председателю
Action::send<createapprv_interface>(
_soviet,
"createapprv"_n,
_capital,
coopname,
username,
empty_doc,
commit_hash,
_capital,
"approvecmmt"_n,
"declinecmmt"_n,
std::string("")
);
}
@@ -0,0 +1,14 @@
void capital::declinecmmt(eosio::name coopname, checksum256 commit_hash, std::string reason) {
require_auth(_soviet);
auto exist_commit = get_commit(coopname, commit_hash);
eosio::check(exist_commit.has_value(), "Коммит не найден");
commit_index commits(_capital, coopname.value);
auto commit = commits.find(exist_commit -> id);
commits.modify(commit, coopname, [&](auto &c) {
c.status = "declined"_n;
c.decline_comment = reason;
});
}
@@ -0,0 +1,14 @@
void capital::delcmmt(eosio::name coopname, eosio::name application, eosio::name approver, checksum256 commit_hash) {
require_auth(coopname);
auto exist_commit = get_commit(coopname, commit_hash);
eosio::check(exist_commit.has_value(), "Коммит с указанным хэшем не существует");
commit_index commits(_capital, coopname.value);
auto commit = commits.find(exist_commit->id);
eosio::check(commit != commits.end(), "Коммит не найден");
eosio::check(commit->status == "declined"_n, "Удалять можно только отклонённые коммиты");
commits.erase(commit);
}
@@ -1,124 +0,0 @@
/**
* @brief Принятие второго акта (act2). Убираем любой CRPS, просто плюсуем бонусы.
*/
void capital::setact2(
eosio::name coopname,
eosio::name application,
eosio::name username,
checksum256 commit_hash,
document act
) {
check_auth_or_fail(_capital, coopname, application, "setact2"_n);
verify_document_or_fail(act);
// Ищем коммит
auto exist_commit = get_commit(coopname, commit_hash);
eosio::check(exist_commit.has_value(), "Коммит не найден");
eosio::check(exist_commit -> username == username, "Неверно указано имя пользователя владельца результата");
eosio::check(exist_commit -> status == "act1"_n, "Неверный статус для поставки акта");
// Обновляем коммит
commit_index commits(_capital, coopname.value);
auto commit = commits.find(exist_commit->id);
commits.modify(commit, coopname, [&](auto &c) {
c.status = "act2"_n;
c.act2 = act;
});
// Ищем результат и проект
auto exist_result = get_result_or_fail(coopname, commit->result_hash, "Результат не найден");
auto exist_project = get_project(coopname, exist_result.project_hash);
eosio::check(exist_project.has_value(), "Проект не найден");
// Ищем вкладчика
auto exist_contributor = get_active_contributor_or_fail(coopname, exist_result.project_hash, commit->username);
contributor_index contributors(_capital, coopname.value);
auto contributor = contributors.find(exist_contributor->id);
// Распределяем spend на available / for_convert
// convert_percent — целое число от 0 до HUNDR_PERCENTS
int64_t for_convert_amount = (commit->spend.amount * contributor->convert_percent) / HUNDR_PERCENTS;
eosio::asset for_convert(for_convert_amount, commit->spend.symbol);
eosio::asset available = commit->spend - for_convert;
// Вычисляем bonus
auto br = capital::calculcate_capital_amounts(commit->spend.amount);
eosio::asset creators_bonus (br.creators_bonus, commit->spend.symbol);
eosio::asset authors_bonus (br.authors_bonus, commit->spend.symbol);
eosio::asset generated (br.generated, commit->spend.symbol);
eosio::asset capitalists_bonus (br.capitalists_bonus, commit->spend.symbol);
eosio::asset total (br.total, commit->spend.symbol);
// Обновляем result
result_index results(_capital, coopname.value);
auto result = results.find(exist_result.id);
eosio::check(result->available >= commit->spend, "Недостаточно средств в результате для приёма коммита");
results.modify(result, coopname, [&](auto &row) {
row.available -= commit->spend;
row.spend += commit->spend;
row.creators_amount += commit->spend;
row.total_creators_bonus_shares += commit->spend.amount;
row.creators_bonus += creators_bonus;
row.authors_bonus += authors_bonus;
row.generated_amount += generated;
row.capitalists_bonus += capitalists_bonus;
row.total_amount += total;
row.commits_count++;
});
// Обновляем проект
project_index projects(_capital, coopname.value);
auto project = projects.find(exist_project->id);
// Обновляем актора и проект
contributors.modify(contributor, coopname, [&](auto &c){
c.spend += commit->spend;
c.share_balance += commit->spend;
c.contributed_hours += commit->contributed_hours;
});
projects.modify(project, coopname, [&](auto &p) {
p.generated += generated;
p.spend += commit->spend;
p.available += commit->spend;
p.total_share_balance += commit->spend;
});
// Обновляем запись в resactors (создательские доли)
auto exist_resactor = get_resactor(coopname, commit->result_hash, commit->username);
resactor_index ractors(_capital, coopname.value);
if (!exist_resactor.has_value()) {
ractors.emplace(coopname, [&](auto &ra){
ra.id = ractors.available_primary_key();
ra.project_hash = commit->project_hash;
ra.result_hash = commit->result_hash;
ra.username = commit->username;
ra.creators_bonus_shares = commit->spend.amount;
ra.spend = commit->spend;
ra.for_convert = for_convert;
ra.available = available;
ra.contributed_hours = commit->contributed_hours;
});
} else {
auto resactor = ractors.find(exist_resactor->id);
ractors.modify(resactor, coopname, [&](auto &ra) {
ra.creators_bonus_shares += commit -> spend.amount;
ra.for_convert += for_convert;
ra.available += available;
ra.spend += commit->spend;
ra.contributed_hours += commit->contributed_hours;
});
}
// 10) Добавляем заблокированные средства на договор УХД
std::string memo = "Приём паевого взноса по договору УХД с contributor_id: " + std::to_string(contributor->id);
Wallet::add_blocked_funds(_capital, coopname, contributor->username, commit->spend, _source_program, memo);
}
@@ -1,16 +1,16 @@
void capital::approvecnvrt(eosio::name coopname, eosio::name application, eosio::name approver, checksum256 convert_hash, document approved_statement){
void capital::approvecnvrt(eosio::name coopname, eosio::name application, eosio::name approver, checksum256 convert_hash, document2 approved_statement){
check_auth_or_fail(_capital, coopname, application, "approvecnvrt"_n);
verify_document_or_fail(approved_statement);
auto exist_convert = get_convert(coopname, convert_hash);
eosio::check(exist_convert.has_value(), "Конвертация пользователя для результата не найдена");
eosio::check(exist_convert.has_value(), "Конвертация пользователя для задананиеа не найдена");
convert_index converts(_capital, coopname.value);
auto convert = converts.find(exist_convert -> id);
auto result = get_result(coopname, convert -> result_hash);
eosio::check(result.has_value(), "Результат не найден");
auto assignment = get_assignment(coopname, convert -> assignment_hash);
eosio::check(assignment.has_value(), "Задание не найдено");
// добавляем доли актору и отмечаем статистику сконвертированных сумм
auto contributor = get_active_contributor_or_fail(coopname, convert -> project_hash, convert -> username);
@@ -36,7 +36,7 @@ void capital::approvecnvrt(eosio::name coopname, eosio::name application, eosio:
std::string memo = "Зачёт части целевого паевого взноса по договору УХД с ID: " + std::to_string(contributor -> id) + " в качестве паевого взноса по программе 'Капитализация' с ID: " + std::to_string(convert -> id);
//Списываем баланс средств с УХД только при наличии convert_amount в claim
//Списываем баланс средств с УХД только при наличии convert_amount в result
Wallet::sub_blocked_funds(_capital, coopname, convert -> username, convert -> convert_amount, _source_program, memo);
//Увеличиваем баланс средств в капитализации
@@ -1,36 +1,40 @@
/**
* @brief
*
*/
void capital::createcnvrt(
eosio::name coopname,
eosio::name application,
eosio::name username,
checksum256 result_hash,
checksum256 assignment_hash,
checksum256 convert_hash,
document convert_statement
document2 convert_statement
) {
// Авторизация
check_auth_or_fail(_capital, coopname, application, "createcnvrt"_n);
require_auth(coopname);
// Получаем результат (или кидаем ошибку)
auto exist_result = get_result_or_fail(coopname, result_hash, "Результат не найден");
eosio::check(exist_result.status == "opened"_n || exist_result.status == "created"_n, "Распределение стоимости результата еще не начато или уже завершено");
// Получаем задание (или кидаем ошибку)
auto exist_assignment = get_assignment_or_fail(coopname, assignment_hash, "Задание не найдено");
eosio::check(exist_assignment.status == "closed"_n, "Распределение стоимости задания еще не начато");
// Проверяем, нет ли уже такой конвертации
auto existing_convert = get_convert(coopname, convert_hash);
eosio::check(!existing_convert.has_value(), "Объект конвертации с указанным хэшем уже существует");
// Находим запись в таблице results
result_index results(_capital, coopname.value);
auto result = results.find(exist_result.id);
// Находим запись в таблице assignments
assignment_index assignments(_capital, coopname.value);
auto assignment = assignments.find(exist_assignment.id);
// Получаем контрибьютора
auto exist_contributor = get_active_contributor_or_fail(coopname, exist_result.project_hash, username);
auto exist_contributor = get_active_contributor_or_fail(coopname, exist_assignment.project_hash, username);
contributor_index contributors(_capital, coopname.value);
auto contributor = contributors.find(exist_contributor->id);
// Попробуем найти resactor
auto exist_resactor = get_resactor_or_fail(coopname, result_hash, username, "Объект актора в результате не найден");
// Находим creauthor
auto exist_creauthor = get_creauthor_or_fail(coopname, assignment_hash, username, "Объект актора в результате не найден");
//=== Сумма к конвертации ===
asset convert_amount = exist_resactor.available + exist_resactor.for_convert;
asset convert_amount = exist_creauthor.available + exist_creauthor.for_convert;
eosio::check(convert_amount.amount > 0, "Нет доступных средств для конвертации");
//=== Создаём запись в converts ===
@@ -40,8 +44,8 @@ void capital::createcnvrt(
converts.emplace(coopname, [&](auto &n) {
n.id = convert_id;
n.username = username;
n.project_hash = exist_result.project_hash;
n.result_hash = result_hash;
n.project_hash = exist_assignment.project_hash;
n.assignment_hash = assignment_hash;
n.convert_hash = convert_hash;
n.coopname = coopname;
n.status = "created"_n;
@@ -49,18 +53,18 @@ void capital::createcnvrt(
n.convert_statement = convert_statement;
});
eosio::check(result -> creators_amount_remain >= convert_amount, "Недостаточно средств в result.creators_amount_remain для конвертации");
eosio::check(assignment -> creators_base_remain >= convert_amount, "Недостаточно средств в assignment.creators_base_remain для конвертации");
results.modify(result, coopname, [&](auto &r) {
r.creators_amount_remain -= convert_amount;
assignments.modify(assignment, coopname, [&](auto &r) {
r.creators_base_remain -= convert_amount;
});
resactor_index ractors(_capital, coopname.value);
creauthor_index creathors(_capital, coopname.value);
auto resactor = ractors.find(exist_resactor.id);
auto creauthor = creathors.find(exist_creauthor.id);
//обнуляем доступные средства к выводу или конвертации
ractors.modify(resactor, coopname, [&](auto &ra) {
creathors.modify(creauthor, coopname, [&](auto &ra) {
ra.for_convert = asset(0, _root_govern_symbol);
ra.available = asset(0, _root_govern_symbol);
});
@@ -0,0 +1,32 @@
void capital::approvedebt(eosio::name coopname, checksum256 debt_hash, document2 approved_statement)
{
require_auth(_soviet);
debts_index debts(_capital, coopname.value);
auto exist_debt = get_debt(coopname, debt_hash);
eosio::check(exist_debt.has_value(), "Долг не найден");
auto debt = debts.find(exist_debt -> id);
debts.modify(debt, coopname, [&](auto& d) {
d.status = "approved"_n;
d.approved_statement = approved_statement;
});
//отправляем в совет
Action::send<createagenda_interface>(
_soviet,
"createagenda"_n,
_capital,
coopname,
debt -> username,
get_valid_soviet_action("createdebt"_n),
debt_hash,
_capital,
"debtauthcnfr"_n,
"declinedebt"_n,
debt -> statement,
std::string("")
);
}
@@ -0,0 +1,75 @@
void capital::createdebt(name coopname, name username, checksum256 assignment_hash, checksum256 debt_hash, asset amount, time_point_sec repaid_at, document2 statement) {
require_auth(coopname);
verify_document_or_fail(statement);
Wallet::validate_asset(amount);
auto exist_assignment = get_assignment(coopname, assignment_hash);
eosio::check(exist_assignment.has_value(), "Задание не найдено");
assignment_index assignments(_capital, coopname.value);
auto assignment = assignments.find(exist_assignment -> id);
eosio::check(assignment -> status == "opened"_n, "Только результаты в статусе opened могут быть основанием для выдачи ссуды");
auto exist_contributor = get_active_contributor_or_fail(coopname, assignment -> project_hash, username);
eosio::check(exist_contributor.has_value(), "Договор УХД с пайщиком не найден");
contributor_index contributors(_capital, coopname.value);
auto contributor = contributors.find(exist_contributor -> id);
contributors.modify(contributor, coopname, [&](auto &c){
c.debt_amount += amount;
});
auto exist_creauthor = get_creauthor(coopname, assignment_hash, username);
eosio::check(exist_creauthor.has_value(), "Резактор не найден");
creauthor_index creauthors(_capital, coopname.value);
auto creauthor = creauthors.find(exist_creauthor->id);
eosio::check(creauthor -> provisional_amount >= amount, "Недостаточно доступных средств для получения ссуды");
creauthors.modify(creauthor, coopname, [&](auto &ra) {
ra.debt_amount += amount;
ra.provisional_amount -= amount;
});
auto exist_debt = get_debt(coopname, debt_hash);
eosio::check(!exist_debt.has_value(), "Ссуда с указанным hash уже существует");
debts_index debts(_capital, coopname.value);
auto debt_id = get_global_id_in_scope(_soviet, coopname, "debts"_n);
debts.emplace(coopname, [&](auto &d){
d.id = debt_id;
d.coopname = coopname;
d.username = username;
d.debt_hash = debt_hash;
d.assignment_hash = assignment_hash;
d.project_hash = assignment -> project_hash;
d.amount = amount;
d.statement = statement;
d.repaid_at = repaid_at;
});
// Отправляем в совет approve-запрос
action(
permission_level{_capital, "active"_n}, // кто вызывает
_soviet,
"createapprv"_n,
std::make_tuple(
coopname,
username,
statement,
debt_hash, // внешний ID
_capital, // callback_contract (текущий контракт)
"approvedebt"_n, // callback_action_approve
"declinedebt"_n, // callback_action_decline
std::string("")
)
).send();
}
@@ -0,0 +1,43 @@
//действие вызывается советом как коллбэк при положительном решении по вопросу выдачи ссуд
//вызывает контракт шлюза для регистрации исходящего платежа
void capital::debtauthcnfr(eosio::name coopname, checksum256 debt_hash, document2 decision) {
require_auth(_soviet);
auto exist_debt = get_debt(coopname, debt_hash);
eosio::check(exist_debt.has_value(), "Долг не найден");
debts_index debts(_capital, coopname.value);
auto debt = debts.find(exist_debt -> id);
debts.modify(debt, _capital, [&](auto &d){
d.status = "authorized"_n;
d.authorization = decision;
});
//Создаём объект долга в контракте loan
Action::send<createdebt_interface>(
_loan,
"createdebt"_n,
_capital,
coopname,
debt -> username,
debt -> debt_hash,
debt -> repaid_at,
debt -> amount
);
// создаём объект исходящего платежа в gateway с коллбэком после обработки
Action::send<createoutpay_interface>(
_gateway,
"createoutpay"_n,
_capital,
coopname,
debt -> username,
debt -> debt_hash,
debt -> amount,
_capital,
"debtpaycnfrm"_n,
"dclnauthdebt"_n
);
};
@@ -0,0 +1,11 @@
void capital::debtpaycnfrm(name coopname, checksum256 debt_hash) {
require_auth(_gateway);
auto exist_debt = get_debt(coopname, debt_hash);
eosio::check(exist_debt.has_value(), "Долг не найден");
debts_index debts(_capital, coopname.value);
auto debt = debts.find(exist_debt -> id);
debts.erase(debt);
};
@@ -0,0 +1,22 @@
void capital::debtpaydcln(name coopname, checksum256 debt_hash, std::string reason) {
require_auth(_gateway);
auto exist_debt = get_debt(coopname, debt_hash);
eosio::check(exist_debt.has_value(), "Долг не найден");
debts_index debts(_capital, coopname.value);
auto debt = debts.find(exist_debt -> id);
//Удаляем объект долга в контракте loan
Action::send<settledebt_interface>(
_loan,
"settledebt"_n,
_capital,
coopname,
debt -> username,
debt -> debt_hash,
debt -> amount
);
debts.erase(debt);
};
@@ -0,0 +1,38 @@
void capital::declinedebt(name coopname, checksum256 debt_hash, std::string reason) {
//вызывается при отклонении советом или председателем из контракта совета
require_auth(_gateway);
auto exist_debt = get_debt(coopname, debt_hash);
eosio::check(exist_debt.has_value(), "Долг не найден");
debts_index debts(_capital, coopname.value);
auto debt = debts.find(exist_debt -> id);
auto exist_contributor = get_active_contributor_or_fail(coopname, debt -> project_hash, debt -> username);
eosio::check(exist_contributor.has_value(), "Договор УХД с пайщиком не найден");
contributor_index contributors(_capital, coopname.value);
auto contributor = contributors.find(exist_contributor -> id);
eosio::check(contributor -> debt_amount >= debt -> amount, "Возникла какая-то чудовищная ошибка: у пайщика недостаточно средств в долговом кошельке для того, чтобы принять возврат долга. Такого вообще не должно было быть, но если произошло, пожалуйста, срочно обратитесь в поддержку.");
contributors.modify(contributor, coopname, [&](auto &c) {
c.debt_amount -= debt -> amount;
});
auto exist_creauthor = get_creauthor(coopname, debt -> assignment_hash, debt -> username);
eosio::check(exist_creauthor.has_value(), "Резактор не найден");
creauthor_index creauthors(_capital, coopname.value);
auto creauthor = creauthors.find(exist_creauthor->id);
eosio::check(creauthor -> provisional_amount >= debt -> amount, "Недостаточно доступных средств для получения ссуды");
eosio::check(creauthor -> debt_amount >= debt -> amount, "Возникла какая-то чудовищная ошибка: у пайщика недостаточно средств в долговом кошельке для того, чтобы принять возврат долга. Такого вообще не должно было быть, но если произошло, пожалуйста, срочно обратитесь в поддержку.");
creauthors.modify(creauthor, coopname, [&](auto &ra) {
ra.debt_amount -= debt -> amount;
ra.provisional_amount += debt -> amount;
});
debts.erase(debt);
}
@@ -0,0 +1,3 @@
void capital::settledebt(name coopname){
}
@@ -1,4 +1,4 @@
void capital::approveexpns(name coopname, name application, name approver, checksum256 expense_hash, document approved_statement) {
void capital::approveexpns(name coopname, name application, name approver, checksum256 expense_hash, document2 approved_statement) {
check_auth_or_fail(_capital, coopname, application, "approveinvst"_n);
verify_document_or_fail(approved_statement);
@@ -16,20 +16,30 @@ void capital::approveexpns(name coopname, name application, name approver, check
auto contributor = get_active_contributor_or_fail(coopname, expense -> project_hash, expense -> username);
auto exist_result = get_result(coopname, expense -> result_hash);
eosio::check(exist_result.has_value(),"Результат не найден");
eosio::check(exist_result -> available >= expense -> amount, "Недостаточно средств в результате для списания расходов");
auto exist_assignment = get_assignment(coopname, expense -> assignment_hash);
eosio::check(exist_assignment.has_value(),"Задание не найдено");
eosio::check(exist_assignment -> available >= expense -> amount, "Недостаточно средств в результате для списания расходов");
result_index results(_capital, coopname.value);
auto result = results.find(exist_result -> id);
assignment_index assignments(_capital, coopname.value);
auto assignment = assignments.find(exist_assignment -> id);
results.modify(result, coopname, [&](auto &r){
assignments.modify(assignment, coopname, [&](auto &r){
r.available -= expense -> amount;
});
//отправляем в совет
action(permission_level{ _capital, "active"_n}, _soviet, "createagenda"_n,
std::make_tuple(coopname, expense -> username, _capital, _capital_expense_authorize_action, expense -> id, expense -> expense_statement, std::string("")))
.send();
std::make_tuple(
coopname,
expense -> username,
get_valid_soviet_action("capresexpns"_n),
expense_hash,
_capital,
"capauthexpns"_n,
"capdeclexpns"_n,
expense -> expense_statement,
std::string("")
)
).send();
}
@@ -1,10 +1,11 @@
void capital::capauthexpns(eosio::name coopname, uint64_t expense_id, document authorization) {
void capital::capauthexpns(eosio::name coopname, checksum256 expense_hash, document2 authorization) {
require_auth(_soviet);
expense_index expenses(_capital, coopname.value);
auto expense = expenses.find(expense_id);
auto exist_expense = get_expense(coopname, expense_hash);
eosio::check(exist_expense.has_value(), "Расход не найден");
eosio::check(expense != expenses.end(), "Расход не найден");
expense_index expenses(_capital, coopname.value);
auto expense = expenses.find(exist_expense -> id);
auto contributor = get_active_contributor_or_fail(coopname, expense -> project_hash, expense -> username);
eosio::check(contributor.has_value(), "Договор УХД с пайщиком по проекту не найден");
@@ -16,8 +17,16 @@ void capital::capauthexpns(eosio::name coopname, uint64_t expense_id, document a
});
// создаём объект исходящего платежа в gateway с коллбэком после обработки
action(permission_level{ _capital, "active"_n}, _gateway, _gateway_create_expense_withdraw_action,
std::make_tuple(coopname, ""_n, expense -> username, expense -> expense_hash, expense -> amount, expense -> expense_statement, _capital, _gateway_to_capital_expense_callback_type, std::string("")))
.send();
action(permission_level{ _capital, "active"_n}, _gateway, "createoutpay"_n,
std::make_tuple(
coopname,
expense -> username,
expense -> expense_hash,
expense -> amount,
_capital,
"exppaycnfrm"_n,
"capdeclexpns"_n
)
).send();
}
@@ -0,0 +1,3 @@
void capital::capdeclexpns(name coopname) {
}
@@ -1,4 +1,4 @@
void capital::createexpnse(eosio::name coopname, eosio::name application, checksum256 expense_hash, checksum256 result_hash, name creator, uint64_t fund_id, asset amount, std::string description, document statement){
void capital::createexpnse(eosio::name coopname, eosio::name application, checksum256 expense_hash, checksum256 assignment_hash, name creator, uint64_t fund_id, asset amount, std::string description, document2 statement){
check_auth_or_fail(_capital, coopname, application, "createexpns"_n);
verify_document_or_fail(statement);
@@ -7,11 +7,11 @@ void capital::createexpnse(eosio::name coopname, eosio::name application, checks
check(amount.is_valid(), "Invalid asset");
check(amount.amount > 0, "Amount must be positive");
result_index results(_capital, coopname.value);
auto result = get_result(coopname, result_hash);
eosio::check(result.has_value(), "Объект результата не существует");
assignment_index assignments(_capital, coopname.value);
auto assignment = get_assignment(coopname, assignment_hash);
eosio::check(assignment.has_value(), "Объект задананиеа не существует");
auto contributor = get_active_contributor_or_fail(coopname, result -> project_hash, creator);
auto contributor = get_active_contributor_or_fail(coopname, assignment -> project_hash, creator);
auto exist_expense = get_expense(coopname, expense_hash);
eosio::check(!exist_expense.has_value(), "Расход с указанным хэшем уже существует");
@@ -25,12 +25,12 @@ void capital::createexpnse(eosio::name coopname, eosio::name application, checks
i.coopname = coopname;
i.application = application;
i.username = creator;
i.project_hash = result -> project_hash;
i.result_hash = result_hash;
i.project_hash = assignment -> project_hash;
i.assignment_hash = assignment_hash;
i.expense_hash = expense_hash;
i.fund_id = fund_id;
i.status = "created"_n;
i.spend_at = current_time_point();
i.spended_at = current_time_point();
i.expense_statement = statement;
i.amount = amount;
i.description = description;
@@ -1,6 +1,6 @@
void capital::expense_withdraw_callback(name coopname, checksum256 expense_hash){
auto payer = check_auth_and_get_payer_or_fail({_gateway});
void capital::exppaycnfrm(eosio::name coopname, checksum256 expense_hash) {
auto payer = check_auth_and_get_payer_or_fail({ _gateway });
auto expense = get_expense(coopname, expense_hash);
eosio::check(expense.has_value(), "Объект расходов не найден");
@@ -8,17 +8,18 @@ void capital::expense_withdraw_callback(name coopname, checksum256 expense_hash)
contributor_index contributors(_capital, coopname.value);
auto contributor_for_modify = contributors.find(contributor -> id);
contributors.modify(contributor_for_modify, coopname, [&](auto &c){
contributors.modify(contributor_for_modify, payer, [&](auto &c){
c.expensed += expense -> amount;
});
auto exist_result = get_result(coopname, expense -> result_hash);
eosio::check(exist_result.has_value(),"Результат не найден");
auto exist_assignment = get_assignment(coopname, expense -> assignment_hash);
eosio::check(exist_assignment.has_value(),"Задание не найдено");
result_index results(_capital, coopname.value);
auto result = results.find(exist_result -> id);
assignment_index assignments(_capital, coopname.value);
auto assignment = assignments.find(exist_assignment -> id);
results.modify(result, coopname, [&](auto &r){
//TODO: make coopname payer
assignments.modify(assignment, payer, [&](auto &r){
r.expensed += expense -> amount;
});
@@ -37,4 +38,4 @@ void capital::expense_withdraw_callback(name coopname, checksum256 expense_hash)
expenses.erase(expense_for_delete);
//TODO: здесь должна быть проводка по фонду
}
}
@@ -1,4 +1,4 @@
void capital::approveinvst(name coopname, name application, name approver, checksum256 invest_hash, document approved_statement) {
void capital::approveinvst(name coopname, name application, name approver, checksum256 invest_hash, document2 approved_statement) {
check_auth_or_fail(_capital, coopname, application, "approveinvst"_n);
verify_document_or_fail(approved_statement);
@@ -15,7 +15,18 @@ void capital::approveinvst(name coopname, name application, name approver, check
});
//отправляем в совет
action(permission_level{ _capital, "active"_n}, _soviet, _capital_invest_authorize_action,
std::make_tuple(coopname, invest -> username, invest -> id, invest -> invest_statement, std::string("")))
.send();
action(permission_level{ _capital, "active"_n}, _soviet, "createagenda"_n,
std::make_tuple(
coopname,
invest -> username,
get_valid_soviet_action("capitalinvst"_n),
invest -> invest_hash,
_capital,
"capauthinvst"_n,
"capdeclinvst"_n,
invest -> invest_statement,
std::string("")
)
).send();
};
@@ -2,14 +2,15 @@
* @brief Принимаем решение совета и вносим средства на кошелек пайщика при УХД
*
*/
void capital::capauthinvst(eosio::name coopname, uint64_t invest_id, document authorization) {
void capital::capauthinvst(eosio::name coopname, checksum256 invest_hash, document2 authorization) {
require_auth(_soviet);
auto exist_invest = get_invest(coopname, invest_hash);
eosio::check(exist_invest.has_value(), "Инвестиция не найдена");
invest_index invests(_capital, coopname.value);
auto invest = invests.find(invest_id);
eosio::check(invest != invests.end(), "Инвестиция не найдена");
auto invest = invests.find(exist_invest -> id);
auto contributor = get_active_contributor_or_fail(coopname, invest -> project_hash, invest -> username);
eosio::check(contributor.has_value(), "Договор УХД с пайщиком по проекту не найден");
@@ -0,0 +1,3 @@
void capital::capdeclinvst(){
//TODO:
}
@@ -1,4 +1,4 @@
void capital::createinvest(name coopname, name application, name username, checksum256 project_hash, checksum256 invest_hash, asset amount, document statement) {
void capital::createinvest(name coopname, name application, name username, checksum256 project_hash, checksum256 invest_hash, asset amount, document2 statement) {
check_auth_or_fail(_capital, coopname, application, "createinvest"_n);
verify_document_or_fail(statement);
@@ -15,10 +15,10 @@ void capital::addauthor(name coopname, name application, checksum256 project_has
auto author_itr = project_author_index.find(combined_id);
authors.emplace(coopname, [&](auto& row) {
row.id = get_global_id_in_scope(_capital, coopname, "authors"_n);
row.project_hash = project_hash;
row.username = author;
row.shares = shares;
row.id = get_global_id_in_scope(_capital, coopname, "authors"_n);
row.project_hash = project_hash;
row.username = author;
row.shares = shares;
});
project_index projects(_capital, coopname.value);
@@ -1,4 +1,4 @@
void capital::allocate(eosio::name coopname, eosio::name application, checksum256 project_hash, checksum256 result_hash, eosio::asset amount) {
void capital::allocate(eosio::name coopname, eosio::name application, checksum256 project_hash, checksum256 assignment_hash, eosio::asset amount) {
check_auth_or_fail(_capital, coopname, application, "allocate"_n);
Wallet::validate_asset(amount);
@@ -6,9 +6,9 @@ void capital::allocate(eosio::name coopname, eosio::name application, checksum25
auto project = get_project(coopname, project_hash);
eosio::check(project.has_value(), "Проект с указанным хэшем не найден");
auto result = get_result(coopname, result_hash);
eosio::check(result.has_value(), "Объект результата не найден");
eosio::check(project -> available >= amount, "Недостаточно средств в проекте для аллокации в результат");
auto assignment = get_assignment(coopname, assignment_hash);
eosio::check(assignment.has_value(), "Объект задананиеа не найден");
eosio::check(project -> available >= amount, "Недостаточно средств в проекте для аллокации в задание");
project_index projects(_capital, coopname.value);
auto project_for_modify = projects.find(project -> id);
@@ -18,10 +18,10 @@ void capital::allocate(eosio::name coopname, eosio::name application, checksum25
row.allocated += amount;
});
result_index results(_capital, coopname.value);
auto result_for_modify = results.find(result -> id);
assignment_index assignments(_capital, coopname.value);
auto assignment_for_modify = assignments.find(assignment -> id);
results.modify(result_for_modify, coopname, [&](auto& row) {
assignments.modify(assignment_for_modify, coopname, [&](auto& row) {
row.allocated += amount;
row.available += amount;
});
@@ -1,4 +1,4 @@
void capital::diallocate(eosio::name coopname, eosio::name application, checksum256 project_hash, checksum256 result_hash, eosio::asset amount) {
void capital::diallocate(eosio::name coopname, eosio::name application, checksum256 project_hash, checksum256 assignment_hash, eosio::asset amount) {
check_auth_or_fail(_capital, coopname, application, "diallocate"_n);
Wallet::validate_asset(amount);
@@ -6,14 +6,14 @@ void capital::diallocate(eosio::name coopname, eosio::name application, checksum
auto project = get_project(coopname, project_hash);
eosio::check(project.has_value(), "Проект с указанным хэшем не найден");
auto result = get_result(coopname, result_hash);
eosio::check(result.has_value(), "Объект результата не найден");
eosio::check(result -> available >= amount, "Недостаточно средств в результате для возврата в проект");
auto assignment = get_assignment(coopname, assignment_hash);
eosio::check(assignment.has_value(), "Объект задананиеа не найден");
eosio::check(assignment -> available >= amount, "Недостаточно средств в задананиее для возврата в проект");
result_index results(_capital, coopname.value);
auto result_for_modify = results.find(result -> id);
assignment_index assignments(_capital, coopname.value);
auto assignment_for_modify = assignments.find(assignment -> id);
results.modify(result_for_modify, coopname, [&](auto& row) {
assignments.modify(assignment_for_modify, coopname, [&](auto& row) {
row.available -= amount;
row.allocated -= amount;
});
@@ -1,17 +0,0 @@
void capital::wthdrcallbck(eosio::name coopname, eosio::name callback_type, checksum256 withdraw_hash) {
auto payer = check_auth_and_get_payer_or_fail({ _gateway });
// Обработка на основе типа callback_type
switch(callback_type.value) {
case "expense"_n.value: {
// Логика для типа "expense"
capital::expense_withdraw_callback(coopname, withdraw_hash);
break;
}
default: {
// Обработка для неизвестных типов
eosio::check(false, "Неизвестный тип коллбэка при обработке платежа");
break;
}
}
}
@@ -6,7 +6,7 @@
* @param username
* @param approved_agreement
*/
void capital::approvereg(eosio::name coopname, eosio::name application, eosio::name approver, checksum256 project_hash, eosio::name username, document approved_agreement) {
void capital::approvereg(eosio::name coopname, eosio::name application, eosio::name approver, checksum256 project_hash, eosio::name username, document2 approved_agreement) {
check_auth_or_fail(_capital, coopname, application, "approvereg"_n);
verify_document_or_fail(approved_agreement);
@@ -5,7 +5,7 @@
* @param application
* @param contributor_id
*/
void capital::capregcontr(eosio::name coopname, uint64_t contributor_id, document authorization) {
void capital::capregcontr(eosio::name coopname, uint64_t contributor_id, document2 authorization) {
require_auth(_soviet);
contributor_index contributors(_capital, coopname.value);
@@ -1,7 +1,7 @@
/**
* @brief Регистрация пайщика в контракте и получение договора УХД от него.
*/
void capital::regcontrib(eosio::name coopname, eosio::name application, eosio::name username, checksum256 project_hash, uint64_t convert_percent, eosio::asset rate_per_hour, time_point_sec created_at, document agreement) {
void capital::regcontrib(eosio::name coopname, eosio::name application, eosio::name username, checksum256 project_hash, uint64_t convert_percent, eosio::asset rate_per_hour, time_point_sec created_at, document2 agreement) {
check_auth_or_fail(_capital, coopname, application, "regcontrib"_n);
verify_document_or_fail(agreement);
@@ -1,6 +0,0 @@
1. Создаём результат createresult
2. Добавляем создателя addcreator
3.

Some files were not shown because too many files have changed in this diff Show More