Compare commits

...

238 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
Alex Ant 0f1f34f621 make unnesassary result 2025-03-26 11:42:05 +05:00
Alex Ant c08473618f some updates on contracts and tests 2025-03-22 13:58:51 +05:00
Alex Ant 3b4fb195bb update 2025-03-21 17:58:33 +05:00
Alex Ant 827eb10cc2 Merge branch 'dev' into TSK-900 2025-03-19 10:58:53 +05:00
Alex Ant 6e7c60de6e Создание кошелька при регистрации участника 2025-03-19 10:58:20 +05:00
Alex Ant 8033e3fc8e update 2025-03-18 21:04:12 +05:00
Alex Ant abb0b629f3 TSK-900 capital contract - fund by membership contributions and distribution it 2025-03-18 11:50:07 +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
Ilia Smirnov a6011f5d46 Merged readme fixes 2025-03-17 12:52:02 +03:00
Ilia Smirnov a1300e2b3c Merge branch 'dev' of github.com:coopenomics/mono into TSK-878 2025-03-17 12:49:40 +03:00
Alex Ant 8f58672403 Merge pull request #217 from coopenomics/dacom-dark-sun/sprint-4
Спринт-4 | dacom-dark-sun
2025-03-17 09:57:34 +03:00
Alex Ant b8d048bf3c README.md 2025-03-17 11:55:18 +05:00
Ilia Smirnov bb7b650ebc docs(install): updated installation instructions 2025-03-17 09:44:10 +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
Alex Ant 7ed4024555 run container on boot 2025-03-13 22:58:46 +05:00
Alex Ant 6fa45c5958 bug fix 2025-03-13 22:39:41 +05:00
Alex Ant a883f140d4 clear database on reboot 2025-03-13 21:04:21 +05:00
Alex Ant 1bec52efcb bug fix #2 2025-03-13 20:50:42 +05:00
Alex Ant 674e58ec3f fix bug 2025-03-13 20:46:53 +05:00
Alex Ant 373d705387 update nodemon for notificator 2025-03-13 20:33:56 +05:00
Alex Ant 46fb693020 add clear method 2025-03-13 20:10:47 +05:00
Alex Ant f1fe7d1545 make boot better 2025-03-13 19:57:35 +05:00
kamilocean 44ab386835 WIP: EditableAccountCard 2025-03-13 00:30:00 +03:00
Alex Ant 51d736eba4 chore(release): publish 2025-03-12 11:33:00 +05:00
Alex Ant dcc4f6bd03 fix packages 2025-03-12 10:31:41 +05:00
Alex Ant eef2482423 README.md and some setup fixs 2025-03-12 10:24:48 +05:00
Alex Ant f46a1fb9b5 ascii text fix 2025-03-12 09:51:52 +05:00
Alex Ant bae45af414 contracts path change 2025-03-12 09:33:47 +05:00
Alex Ant aff3835f50 fix data paths 2025-03-12 09:26:43 +05:00
Alex Ant 5f249f6032 add lossed lib dir 2025-03-12 09:03:45 +05:00
Alex Ant a185d7e9e8 fix build 2025-03-11 23:34:27 +05:00
Alex Ant 3449caf0e2 fix build 2025-03-11 23:15:03 +05:00
Alex Ant cc458cc916 fix some files 2025-03-11 22:59:52 +05:00
Alex Ant 2b6b56ace9 move contracts inside and make common setup script 2025-03-11 22:57:08 +05:00
Alex Ant 4d72c920c6 capital cooptypes 2025-03-11 19:57:49 +05:00
Alex Ant b0186a1baa add Env-testnet.ts 2025-03-06 13:53:31 +05:00
Alex Ant bc3836b316 docker-compose for infra 2025-03-06 11:34:04 +05:00
Alex Ant 0a444efe55 sosediAgreement and docker-compose-infra.yaml 2025-03-06 11:22:43 +05:00
Alex Ant fba3988834 env controller 2025-03-05 21:55:40 +05:00
Alex Ant b99e1abb03 update package 2025-03-05 21:54:10 +05:00
Alex Ant ab44237bb9 update cooptypes 2025-03-05 17:33:48 +05:00
Alex Ant 6d98dc073f add capital contract 2025-03-04 20:23:36 +05:00
Alex Ant 9709ef4333 investment templates 2025-02-25 20:35:03 +05:00
Alex Ant cb60f6f735 update test structure 2025-02-22 15:43:00 +05:00
Alex Ant 5d0ab2e2db fix 2025-02-13 10:14:32 +05:00
Alex Ant 4e3b0b52c8 branch bug fix 2025-02-13 10:08:46 +05:00
Alex Ant 973590281c chore(release): publish 2025-02-10 14:58:11 +05:00
Alex Ant 4f7defb85c update 2025-02-10 14:56:44 +05:00
Alex Ant 59f4d8dc26 delete onewallet structure 2025-02-10 14:44:03 +05:00
Alex Ant be736e105a wallet fast fix 2025-02-10 13:39:31 +05:00
Alex Ant 3be56ba462 chore(release): publish 2025-02-07 19:35:06 +05:00
Alex Ant f7adf8457b Dockerfile fix 2025-02-07 19:25:01 +05:00
Alex Ant 80b8856f15 fix 2025-02-07 18:48:44 +05:00
Alex Ant 0860f47d88 capital sdk mutations 2025-02-07 18:39:39 +05:00
Alex Ant 382b75fccf cooplace 2025-01-30 19:25:35 +05:00
Alex Ant d3dacbd32d add production cooperative to the list 2025-01-28 23:08:02 +05:00
Alex Ant 6c51e4b596 fix selectBranch bug and add IP for entrepreneur user 2025-01-28 16:27:22 +05:00
Alex Ant d0bd4428be chore(release): publish 2025-01-27 11:08:26 +05:00
Alex Ant 43ffcb7362 update 2025-01-27 10:54:50 +05:00
Alex Ant ca5dfca290 update table style on documents 2025-01-27 10:29:08 +05:00
Alex Ant 8a495eff37 add new templates for documents and fix QR-pay interface 2025-01-27 10:07:52 +05:00
Alex Ant bee6af12fb get COOPBACK const from system.info everywhere 2025-01-23 18:52:33 +05:00
Alex Ant 4a3dfc3eb7 update 2025-01-22 17:49:33 +05:00
Alex Ant 4e87a4adc4 fix init process 2025-01-22 16:08:24 +05:00
Alex Ant d9bb9d5884 update system info 2025-01-22 12:23:34 +05:00
Alex Ant 562be0cb89 update 2025-01-21 17:51:03 +05:00
Alex Ant 2fdc86af97 chore(release): publish 2025-01-19 18:52:27 +05:00
Alex Ant 220d1225b2 update 2025-01-19 17:04:34 +05:00
Alex Ant e047a6e449 remove username input on getAccounts & remove deleteAccount mutation on SDK 2025-01-19 16:34:54 +05:00
Alex Ant 97b21a9d69 chore(release): publish 2025-01-18 16:15:43 +05:00
Alex Ant 9be9570dea document and blockchain classes on SDK, move sign documents on signup to use SDK 2025-01-18 16:11:32 +05:00
Alex Ant cbfe37dbba chore(release): publish 2025-01-17 13:52:58 +05:00
Alex Ant bf176a2c05 fix connection button only for voskhod coops 2025-01-17 13:50:36 +05:00
Alex Ant 173c51eb26 connection button for coops on desktop 2025-01-17 13:46:47 +05:00
Alex Ant 71dbb090fb memberButton for access to coop settings 2025-01-17 13:02:40 +05:00
Alex Ant 832133e6cc Canvas SDK class 2025-01-17 12:57:46 +05:00
Alex Ant 2730a92b01 update 2025-01-16 19:54:20 +05:00
Alex Ant 40fb5c80eb update 2025-01-16 19:45:35 +05:00
Alex Ant 6c65095961 add account class 2025-01-16 17:46:08 +05:00
Alex Ant d02f7ae7bc rollback 2025-01-16 12:40:17 +05:00
Alex Ant 9f0b4b24ba update SDK 2025-01-16 12:34:04 +05:00
Alex Ant 237357c1d5 canvas class and update types on dto 2025-01-16 12:30:57 +05:00
Alex Ant aefb1caf57 update 2025-01-16 12:17:00 +05:00
Alex Ant a3328e7ef0 move to sdk login 2025-01-16 12:09:04 +05:00
Alex Ant db24588273 fix paymentMethods orders 2025-01-15 13:47:58 +05:00
Alex Ant 2cabeeb6bd temp fix order id bug 2025-01-15 10:52:02 +05:00
Alex Ant 88352202b0 update 2025-01-14 21:50:45 +05:00
Alex Ant e02d8a949b update 2025-01-14 20:40:26 +05:00
Alex Ant e7e5457cf2 uppdate 2025-01-14 20:39:39 +05:00
Alex Ant 29b98b0f7d add login method to SDK 2025-01-14 20:32:49 +05:00
Alex Ant ae7378f474 update 2025-01-14 18:07:31 +05:00
Alex Ant b05c17bee4 chore(release): publish 2025-01-14 17:50:44 +05:00
Alex Ant a2d3dac226 chore(release): publish 2025-01-14 17:41:40 +05:00
Alex Ant a8ec41e255 fix 2025-01-14 13:48:53 +05:00
Alex Ant 1d16062961 renaming and sdk 2025-01-14 13:45:45 +05:00
Alex Ant 2a614e8656 move to sdk #1 2025-01-14 12:32:58 +05:00
Alex Ant baaaaf01bf sdk-client docs 2025-01-10 10:35:54 +05:00
Alex Ant 20f1fc51b1 hard payment migration 2025-01-01 21:07:59 +05:00
Alex Ant d749ebf981 add a lot of queries and mutations 2025-01-01 12:06:41 +05:00
3494 changed files with 189000 additions and 68006 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
+5 -1
View File
@@ -1,3 +1,7 @@
node_modules/
lerna-debug.log
components/coopback/graph.png
components/controller/graph.png
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
}
+127
View File
@@ -1,8 +1,135 @@
# 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
## [2.2.8](https://github.com/coopenomics/monocoop/compare/v2.2.7...v2.2.8) (2025-02-10)
**Note:** Version bump only for package monocoop
## [2.2.7](https://github.com/coopenomics/monocoop/compare/v2.2.6...v2.2.7) (2025-02-07)
**Note:** Version bump only for package monocoop
## [2.2.6](https://github.com/coopenomics/monocoop/compare/v2.2.6-alpha.0...v2.2.6) (2025-01-27)
**Note:** Version bump only for package monocoop
## [2.2.5](https://github.com/coopenomics/monocoop/compare/v2.2.4...v2.2.5) (2025-01-18)
**Note:** Version bump only for package monocoop
## [2.2.4](https://github.com/coopenomics/monocoop/compare/v2.2.0...v2.2.4) (2025-01-17)
**Note:** Version bump only for package monocoop
## [2.2.3](https://github.com/coopenomics/monocoop/compare/v2.2.0...v2.2.3) (2025-01-16)
**Note:** Version bump only for package monocoop
## [2.2.1](https://github.com/coopenomics/monocoop/compare/v2.2.0...v2.2.1) (2025-01-14)
**Note:** Version bump only for package monocoop
## [2.1.9](https://github.com/coopenomics/monocoop/compare/v2.1.8...v2.1.9) (2025-01-14)
**Note:** Version bump only for package monocoop
## [2.1.8](https://github.com/coopenomics/monocoop/compare/v2.1.6...v2.1.8) (2024-12-24)
**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
+127 -10
View File
@@ -1,18 +1,135 @@
# MONOCOOP
# MONO
Моно-репозиторий компонент клиента системы электронного документооборота для потребительских и производственных кооперативов.
Система управления взаимоотношениями в кооперативе. Включает в себя полный комплект программного обеспечения для подключения к платформе "Кооперативная Экономика" и управления взаимоотношениями с пайщиками в кооперативе и самим кооперативом на основе смарт-контрактов и простой электронной подписи.
## Инициализация
## Ветки
- Для разработки используется ветка `dev`.
- Для стейджа используется ветка `testnet`.
- Для продакшена используется ветка `main`.
## Установка
```sh
pnpm install
```
curl -X POST http://127.0.0.1:2998/v1/system/init \
-H "Content-Type: application/json" \
-H "server-secret: SECRET" \
-d @init-cooperative1.json
Также для работы потребуется установленная фабрика документов `weasyprint` для вашей операционной системы: <https://doc.courtbouillon.org/weasyprint/stable/first_steps.html#installation>
## Конфигурация
Для конфигурации потребуетcя установленный `docker` и `docker-compose`. Выполните команду и следуйте инструкциям:
```sh
pnpm run setup
```
## Запуск
### Инфраструктура
Для работы системы необходимы базы `mongo`, `postgres` и `redis`.
Команда запуска баз данных в контейнерах для работы в фоновом режиме:
```sh
docker compose up -d
```
### Блокчейн и контракты
```sh
pnpm boot
```
Команда запустит блокчейн и установит все смарт-контракты, подготовив систему к локальной разработке или применению.
### Бэкенд
```sh
pnpm run dev:backend
```
Команда запустит набор сервисов бэкенда и точку доступа GraphQL-API на 2998 порту.
### Фронтенд
Команда запустит рабочий стол кооператива на 3005 порту:
```sh
pnpm run dev:desktop
```
### Очистка базы
Команда очистит базу mongodb и начнет производство блоков с начала:
```sh
pnpm run clear
```
Правильная последовательность команд при переустановке проекта "с нуля":
```sh
git pull
pnpm install
pnpm run setup
pnpm run clear
pnpm run boot
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.
Продукт Потребительского Кооператива "ВОСХОД" распространяется по лицензии BY-NC-SA 4.0.
Разрешено делиться, копировать и распространять материал на любом носителе и форме, адаптировать, делать ремиксы, видоизменять и создавать новое, опираясь на этот материал. При использовании, Вы должны обеспечить указание авторства, предоставить ссылку, и обозначить изменения, если таковые были сделаны. Если вы перерабатываете, преобразовываете материал или берёте его за основу для производного произведения, вы должны распространять переделанные вами части материала на условиях той же лицензии , в соответствии с которой распространяется оригинал. Запрещено коммерческое использование материала. Использование в коммерческих целях – это использование, в первую очередь направленное на получение коммерческого преимущества или денежного вознаграждения.
Юридический текст лицензии: https://creativecommons.org/licenses/by-nc-sa/4.0/legalcode.ru
Юридический текст лицензии: <https://creativecommons.org/licenses/by-nc-sa/4.0/legalcode.ru>
File diff suppressed because one or more lines are too long
BIN
View File
Binary file not shown.
+10
View File
@@ -0,0 +1,10 @@
EOSIO_PUB_KEY=EOS6MRyAjQq8ud7hVNYcfnVPJqcVpscN5So8BhtHuGYqET5GDW5CV
EOSIO_PRV_KEY=5KQwrPbwdL6PhXujxW37FSSQZ1JiwsST4cqQzDeyXtP79zkvFD3
DATADIR=blockchain-data
BPACCOUNT=eosio
PASSWORD=PW5JGe4WsTPGrjnMzkGd4wfVdzoHCEySgbyq2WBWGAxSfevbXqAG4
SERVER_SECRET=SECRET
SERVER_URL=http://127.0.0.1:2998
MONGO_URI=mongodb://127.0.0.1:27017/cooperative-x
SIMPLE_EXPLORER_API=http://localhost:4000
SKIP_BLOCK_FETCH=TRUE
+14
View File
@@ -0,0 +1,14 @@
.cache
.DS_Store
.idea
*.log
*.tgz
coverage
dist
lib-cov
logs
node_modules
temp
.env
blockchain-data/*
wallet-data/*
+80
View File
@@ -0,0 +1,80 @@
# 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/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
## [0.1.8](https://github.com/coopenomics/contracts/compare/boot@0.1.7...boot@0.1.8) (2024-12-24)
**Note:** Version bump only for package boot
## [0.1.7](https://github.com/coopenomics/contracts/compare/boot@0.1.7-alpha.0...boot@0.1.7) (2024-10-16)
**Note:** Version bump only for package boot
## [0.1.6](https://github.com/coopenomics/contracts/compare/boot@0.1.5...boot@0.1.6) (2024-10-13)
**Note:** Version bump only for package boot
## [0.1.5](https://github.com/coopenomics/contracts/compare/boot@0.1.5-alpha.0...boot@0.1.5) (2024-09-26)
**Note:** Version bump only for package boot
## [0.1.4](https://github.com/coopenomics/contracts/compare/boot@0.1.4-alpha.0...boot@0.1.4) (2024-08-13)
**Note:** Version bump only for package boot
## [0.1.3](https://github.com/coopenomics/contracts/compare/boot@0.1.3-alpha.0...boot@0.1.3) (2024-08-13)
**Note:** Version bump only for package boot
## [0.1.2](https://github.com/coopenomics/contracts/compare/boot@0.1.2-alpha.0...boot@0.1.2) (2024-08-10)
**Note:** Version bump only for package boot
## [0.1.1](https://github.com/coopenomics/contracts/compare/boot@0.1.1-alpha.1...boot@0.1.1) (2024-08-09)
**Note:** Version bump only for package boot
+1
View File
@@ -0,0 +1 @@
# Загрузчик.
+19
View File
@@ -0,0 +1,19 @@
// @ts-check
import antfu from '@antfu/eslint-config'
export default antfu(
{
ignores: [
// eslint ignore globs here
],
},
{
rules: {
'no-unused-vars': 'warn',
'unused-imports/no-unused-vars': 'off',
'no-console': 'off',
'unicorn/prefer-number-properties': 'off',
// overrides
},
},
)
+54
View File
@@ -0,0 +1,54 @@
{
"name": "@coopenomics/boot",
"type": "module",
"version": "2025.5.5-2",
"private": true,
"packageManager": "pnpm@9.0.6",
"description": "",
"author": "Alex Ant <dacom.dark.sun@gmail.com>",
"license": "",
"keywords": [],
"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",
"stop": "./scripts/stop.sh"
},
"dependencies": {
"@coopenomics/factory": "workspace:*",
"axios": "^1.6.8",
"chai": "^5.1.2",
"commander": "^12.1.0",
"cooptypes": "workspace:*",
"dockerode": "^4.0.2",
"dotenv": "^16.4.5",
"eosjs": "^22.1.0",
"eosjs-api": "^7.0.4",
"eosjs-ecc": "^4.0.7",
"execa": "^9.5.2",
"mocha": "^10.7.3",
"mongoose": "^8.10.0"
},
"devDependencies": {
"@antfu/eslint-config": "^2.18.0",
"@antfu/ni": "^0.21.12",
"@antfu/utils": "^0.7.8",
"@types/dockerode": "^3.3.31",
"@types/node": "^20.12.12",
"bumpp": "^9.4.1",
"eslint": "^9.2.0",
"esno": "^4.7.0",
"pnpm": "^9.1.1",
"rimraf": "^5.0.7",
"simple-git-hooks": "^2.11.1",
"typescript": "^5.4.5",
"unbuild": "^2.0.0",
"vite": "^5.2.11",
"vitest": "^1.6.0"
}
}
+80
View File
@@ -0,0 +1,80 @@
#!/bin/zsh
# Определение ассоциативных массивов
typeset -A contract_params_test contract_params_prod
contract_params_test=(
[ano]="ano"
[gateway]="gateway"
[draft]="draft"
[marketplace]="marketplace"
[soviet]="soviet"
[registrator]="registrator"
[system]="eosio"
[fund]="fund"
)
contract_params_prod=(
[ano]="ano"
[gateway]="gateway"
[draft]="draft"
[marketplace]="marketplace"
[soviet]="soviet"
[registrator]="registrator"
[system]="eosio"
[fund]="fund"
[template]="template"
)
# Выбор массива параметров в зависимости от входящего аргумента
if [ "$2" = "prod" ]; then
contract_params=("${(@kv)contract_params_prod}")
elif [ "$2" = "test" ]; then
contract_params=("${(@kv)contract_params_test}")
else
contract_params=("${(@kv)contract_params_test}")
fi
# Форматирование строки для переменной окружения
contract_params_str=""
for key value in "${(@kv)contract_params}"; do
contract_params_str+="${key}=${value},"
done
# Проверяем, задан ли аргумент для контрактов
if [ -n "$1" ]; then
contracts=$1
else
contracts="*"
fi
# Запуск контейнера Docker
docker run --rm --name cdt_v4.1.0 \
--volume $(pwd):/project \
-w /project \
--env CONTRACT_PARAMS="$contract_params_str" \
dicoop/cdt_v4.1.0 /bin/bash -c "
cd ../cpp
# Перебираем все папки в директории
for folder in $contracts ; do
# Убираем слэш из названия папки, чтобы получить имя контракта
contract=\${folder%/}
contract=\${contract##*/}
echo \"Сборка контракта \$contract в \$folder...\"
# Переходим в директорию контракта
cd \$folder
# Извлекаем параметр для -contract из переменной окружения
contract_param=\$(echo \$CONTRACT_PARAMS | grep -o \"\$contract=[^,]*\" | cut -d'=' -f2)
# Компилируем с использованием параметра -contract
cdt-cpp -abigen -I include -R include -contract \$contract_param -o \$contract.wasm \$contract.cpp
# Возвращаемся назад
cd ..
echo \"Сборка контракта \$contract завершена!\"
done
"
+1
View File
@@ -0,0 +1 @@
cd ../system/build && cmake -DCMAKE_BUILD_TYPE=Release -DBUILD_TESTS=ON -Dcdt_DIR="/cdt/build/lib/cmake/cdt" -Dleap_DIR="/blockchain/build/lib/cmake/leap" .. && make -j 2
+5
View File
@@ -0,0 +1,5 @@
#!/bin/bash
# Передача аргументов cleos
docker exec -it node /usr/local/bin/cleos "$@"
+108
View File
@@ -0,0 +1,108 @@
#!/bin/bash
# Импорт параметров сетей
source ./networks.sh
# Устанавливаем значения по умолчанию
network_param=$local
account_name_param=""
network=""
# Получаем первый аргумент, который должен быть именем контракта
contract_name=$1
rm /Users/darksun/testnet/wallet/keosd.sock
./kill.sh
# Проверяем наличие параметра -n и устанавливаем соответствующую сеть
while [[ $# -gt 0 ]]; do
case $1 in
-n)
network=$2
shift
shift
;;
-t)
account_name_param=$2
shift
shift
;;
*)
shift
;;
esac
done
# Устанавливаем значение сети из networks.sh
case $network in
prod)
network_param=$prod
;;
test)
network_param=$test
;;
local)
network_param=$local
;;
esac
# Разблокировка кошелька
./unlock.sh
# Функция для установки контракта
deploy_contract() {
local contract=$1
local dir=$2
local account_name=$3
echo "Устанавливаем контракт $contract на аккаунт $account_name..."
if [ -z "$account_name_param" ]; then
echo ./cleos.sh $network_param set contract $account_name $dir -p $account_name
./cleos.sh $network_param set contract $account_name $dir -p $account_name
else
echo ./cleos.sh $network_param set contract $account_name_param $dir -p $account_name_param
./cleos.sh $network_param set contract $account_name_param $dir -p $account_name_param
fi
}
# Если контракт указан, деплоим только его
if [ ! -z "$contract_name" ]; then
ls ./
echo "Проверка наличия папки для контракта $contract_name..."
if [ -d "./$contract_name" ]; then
echo "Папка контракта найдена. Содержимое папки:"
deploy_contract $contract_name "/contracts/cpp/$contract_name" $contract_name
elif [[ "$contract_name" == "eosio.msig" || "$contract_name" == "eosio.token" || "$contract_name" == "eosio.wrap" ]]; then
echo "Папка системного контракта найдена. Содержимое папки:"
ls "/contracts/cpp/system/build/contracts/$contract_name"
deploy_contract $contract_name "/contracts/cpp/system/build/contracts/$contract_name" $contract_name
elif [ "$contract_name" == "eosio.system" ]; then
echo "Папка системного контракта найдена. Содержимое папки:"
ls "/contracts/cpp/system/build/contracts/$contract_name"
deploy_contract $contract_name "/contracts/cpp/system/build/contracts/$contract_name" "eosio"
elif [ "$contract_name" == "eosio.boot" ]; then
echo "Папка системного контракта найдена. Содержимое папки:"
ls "/contracts/cpp/system/build/contracts/$contract_name"
deploy_contract $contract_name "/contracts/cpp/system/build/contracts/$contract_name" "eosio"
else
echo "Контракт $contract_name не найден"
fi
exit 0
fi
# Перебираем все папки с контрактами на верхнем уровне, исключая 'system'
for dir in $(find /contracts/cpp/* -maxdepth 0 -type d ! -name 'system'); do
contract=$(basename $dir)
echo "Найдена папка $dir для контракта $contract. Содержимое папки:"
ls $dir
deploy_contract $contract $dir $contract
done
# Исключение для контрактов в папке system
special_system_contracts=("eosio.msig" "eosio.token" "eosio.wrap")
for contract in "${special_system_contracts[@]}"; do
echo "Найдена папка системного контракта для $contract. Содержимое папки:"
ls "/contracts/cpp/system/build/contracts/$contract"
deploy_contract $contract "/contracts/cpp/system/build/contracts/$contract" $contract
done
deploy_contract "eosio.system" "/contracts/cpp/system/build/contracts/eosio.system" "eosio"
+4
View File
@@ -0,0 +1,4 @@
docker run --rm -it --name cdt \
--volume $(pwd)/:/project \
-w /project \
dicoop/blockchain_v5.1.1:dev /bin/bash
+3
View File
@@ -0,0 +1,3 @@
cd ../
doxygen
cp -r ../docs/html/* ../../doctrine/site/contracts
+4
View File
@@ -0,0 +1,4 @@
#!/bin/bash
# убиваем keosd на всякий случай
docker exec -it node pkill keosd
+35
View File
@@ -0,0 +1,35 @@
#!/bin/bash
# Получаем текущую директорию
dir="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
# Проверяем, существуют ли директории
if [ ! -d ~/testnet ]; then
echo "Директория ~/testnet не найдена. Создание..."
mkdir -p ~/testnet
fi
if [ ! -d ~/testnet/config ]; then
echo "Директория ~/testnet/config не найдена. Создание..."
mkdir -p ~/testnet/config
fi
# Проверяем, существует ли файл
if [ ! -f ~/testnet/config/config.ini ]; then
echo "Файл config.ini не найден. Копирование..."
cp $dir/configs/master/config.ini ~/testnet/config/config.ini
fi
# Запускаем контейнер Docker с нужными параметрами
docker run --name node -d -p 8888:8888 -p 9876:9876 -p 8080:8080 \
-v ~/testnet/data:/mnt/dev/data \
-v ~/testnet/config:/mnt/dev/config \
-v ~/testnet/wallet:/root/eosio-wallet \
-v $dir/../../contracts:/contracts \
dicoop/blockchain:v5.1.0-dev \
/bin/bash -c '/usr/local/bin/nodeos -d /mnt/dev/data -p eosio --config-dir /mnt/dev/config --genesis-json /mnt/dev/config/genesis.json'
docker network connect hyperion node
echo "Контейнер node установлен - блокчейн запущен."
sleep 10
+5
View File
@@ -0,0 +1,5 @@
#!/bin/bash
local="-u http://localhost:8888"
test="-u https://testnet.coopenomics.world/api"
prod="-u https://voskhod.coopenomics.world/api"
+22
View File
@@ -0,0 +1,22 @@
{
"net": {
"assumed_stake_weight": 10000000,
"current_weight_ratio": 500000000000000,
"decay_secs": 86400,
"exponent": 1,
"max_price": "1000.0000 AXON",
"min_price": "1000.0000 AXON",
"target_weight_ratio": 500000000000000
},
"cpu": {
"assumed_stake_weight": 10000000,
"current_weight_ratio": 500000000000000,
"decay_secs": 86400,
"exponent": 1,
"max_price": "1000.0000 AXON",
"min_price": "1000.0000 AXON",
"target_weight_ratio": 500000000000000
},
"min_powerup_fee": "0.0001 AXON",
"powerup_days": 1
}
+1
View File
@@ -0,0 +1 @@
cleos push action eosio cfgpowerup "[`cat ./powerup.json`]" -p eosio
+39
View File
@@ -0,0 +1,39 @@
#!/bin/bash
# Run unlock script before activating features
./unlock.sh
# Activate PREACTIVATE_FEATURE before installing eosio.boot
#./cleos.sh push action eosio activate '["0ec7e080177b2c02b278d5088611686b49d739925a92d9bfcacd7fc6b74053bd"]' -p eosio@active
curl --noproxy -X POST "http://localhost:8888/v1/producer/schedule_protocol_feature_activations" -d '{"protocol_features_to_activate": ["0ec7e080177b2c02b278d5088611686b49d739925a92d9bfcacd7fc6b74053bd"]}'
# Install eosio.boot which supports the native actions and activate
# action that allows activating desired protocol features prior to
# deploying a system contract with more features such as eosio.bios
# or eosio.system
./deploy.sh eosio.boot
# Activate remaining features
./cleos.sh push action eosio activate '["c3a6138c5061cf291310887c0b5c71fcaffeab90d5deb50d3b9e687cead45071"]' -p eosio@active
./cleos.sh push action eosio activate '["d528b9f6e9693f45ed277af93474fd473ce7d831dae2180cca35d907bd10cb40"]' -p eosio@active
./cleos.sh push action eosio activate '["5443fcf88330c586bc0e5f3dee10e7f63c76c00249c87fe4fbf7f38c082006b4"]' -p eosio@active
./cleos.sh push action eosio activate '["f0af56d2c5a48d60a4a5b5c903edfb7db3a736a94ed589d0b797df33ff9d3e1d"]' -p eosio@active
./cleos.sh push action eosio activate '["2652f5f96006294109b3dd0bbde63693f55324af452b799ee137a81a905eed25"]' -p eosio@active
./cleos.sh push action eosio activate '["8ba52fe7a3956c5cd3a656a3174b931d3bb2abb45578befc59f283ecd816a405"]' -p eosio@active
./cleos.sh push action eosio activate '["ad9e3d8f650687709fd68f4b90b41f7d825a365b02c23a636cef88ac2ac00c43"]' -p eosio@active
./cleos.sh push action eosio activate '["68dcaa34c0517d19666e6b33add67351d8c5f69e999ca1e37931bc410a297428"]' -p eosio@active
./cleos.sh push action eosio activate '["e0fb64b1085cc5538970158d05a009c24e276fb94e1a0bf6a528b48fbc4ff526"]' -p eosio@active
./cleos.sh push action eosio activate '["ef43112c6543b88db2283a2e077278c315ae2c84719a8b25f25cc88565fbea99"]' -p eosio@active
./cleos.sh push action eosio activate '["4a90c00d55454dc5b059055ca213579c6ea856967712a56017487886a4d4cc0f"]' -p eosio@active
./cleos.sh push action eosio activate '["1a99a59d87e06e09ec5b028a9cbb7749b4a5ad8819004365d02dc4379a8b7241"]' -p eosio@active
./cleos.sh push action eosio activate '["4e7bf348da00a945489b2a681749eb56f5de00b900014e137ddae39f48f69d67"]' -p eosio@active
./cleos.sh push action eosio activate '["4fca8bd82bbd181e714e283f83e1b45d95ca5af40fb89ad3977b653c448f78c2"]' -p eosio@active
./cleos.sh push action eosio activate '["299dcb6af692324b899b39f16d5a530a33062804e41f09dc97e9f156b4476707"]' -p eosio@active
./cleos.sh push action eosio activate '["bcd2a26394b36614fd4894241d3c451ab0f6fd110958c3423073621a70826e99"]' -p eosio@active
./cleos.sh push action eosio activate '["35c2186cc36f7bb4aeaf4487b36e57039ccf45a9136aa856a5d569ecca55ef2b"]' -p eosio@active
./cleos.sh push action eosio activate '["6bcb40a24e49c26d0a60513b6aeb8551d264e4717f306b81a37a5afb3b47cedc"]' -p eosio@active
# Install the eosio.system contract
./deploy.sh eosio.system
+10
View File
@@ -0,0 +1,10 @@
#!/bin/bash
# Останавливаем и удаляем контейнер, если он существует
docker stop node > /dev/null 2>&1 && docker rm node > /dev/null 2>&1
# Очищаем папку с данными блокчейна
rm -rf ~/testnet/data/*
echo "Очистка завершена."
+1
View File
@@ -0,0 +1 @@
cd ../cpp/system/build/tests && ctest -j $(nproc) --rerun-failed --output-on-failure
+46
View File
@@ -0,0 +1,46 @@
#!/bin/sh
if [ ! -d $DATADIR ]; then
mkdir -p $DATADIR;
fi
ARCH=`uname -m`
NODEOS='/usr/local/bin/nodeos'
if [ "${ARCH}" = "x86_64" ]; then
EOSVM=eos-vm-jit
else
EOSVM=eos-vm
fi
$NODEOS \
--signature-provider $EOSIO_PUB_KEY=KEY:$EOSIO_PRV_KEY \
--plugin eosio::net_plugin \
--plugin eosio::net_api_plugin \
--plugin eosio::producer_plugin \
--plugin eosio::producer_api_plugin \
--plugin eosio::chain_plugin \
--plugin eosio::chain_api_plugin \
--plugin eosio::http_plugin \
--data-dir $DATADIR"/data" \
--blocks-dir $DATADIR"/blocks" \
--config-dir $DATADIR"/config" \
--producer-name $BPACCOUNT \
--http-server-address 0.0.0.0:8888 \
--p2p-listen-endpoint 0.0.0.0:9010 \
--access-control-allow-origin=* \
--contracts-console \
--http-validate-host=false \
--verbose-http-errors \
--enable-stale-production \
--trace-history \
--chain-state-history \
--max-transaction-time=2000 \
--abi-serializer-max-time-ms=60000 \
--http-max-response-time-ms=8000 \
--chain-state-db-size-mb 8192 \
--chain-state-db-guard-size-mb 1024 \
--wasm-runtime=$EOSVM \
>> $DATADIR"/coopos.log" 2>&1 & \
echo $! > $DATADIR"/coopos.pid"
+9
View File
@@ -0,0 +1,9 @@
#!/bin/bash
VERBOSE=""
if [[ $1 == "--verbose" ]]; then
VERBOSE="--verbose"
fi
cd ../cpp/system/build/tests && ctest -j $(nproc) --output-on-failure $VERBOSE
+15
View File
@@ -0,0 +1,15 @@
source .env
if [ -f $DATADIR"/eosd.pid" ]; then
pid=`cat $DATADIR"/eosd.pid"`
echo $pid
kill $pid
rm -r $DATADIR"/eosd.pid"
echo -ne "Stoping Node"
while true; do
[ ! -d "/proc/$pid/fd" ] && break
echo -ne "."
sleep 1
done
echo -ne "\rNode Stopped. \n"
fi
+33
View File
@@ -0,0 +1,33 @@
#!/bin/bash
# Переходим в директорию скрипта
cd "$(dirname "$0")"
# Проверяем наличие папки для хранения данных о кошельке
if [ ! -d "$HOME/testnet/wallet" ]; then
mkdir -p $HOME/testnet/wallet
fi
# Проверяем наличие файла с паролем
if [ ! -f "$HOME/testnet/wallet/password" ]; then
echo "Создание нового кошелька..."
# Создаем новый кошелек и сохраняем пароль в файл внутри контейнера
docker exec -it node /usr/local/bin/cleos wallet create --file password.txt
if [ $? -eq 0 ]; then
# Копируем пароль из файла контейнера в локальный файл
docker cp node:/workdir/password.txt $HOME/testnet/wallet/password
# Удаляем временный файл из контейнера
docker exec -it node rm /workdir/password.txt
echo "Пароль от кошелька сохранён в файле $HOME/testnet/wallet/password"
# Импортируем ключ в кошелек
docker exec -it node /usr/local/bin/cleos wallet import --private-key 5KQwrPbwdL6PhXujxW37FSSQZ1JiwsST4cqQzDeyXtP79zkvFD3
else
echo "Не удалось создать кошелек"
exit 1
fi
else
echo "Использование существующего кошелька..."
# Разблокировка кошелька
docker exec -it node /usr/local/bin/cleos wallet unlock --password $(cat $HOME/testnet/wallet/password) > /dev/null 2>&1
fi
+992
View File
@@ -0,0 +1,992 @@
import { TextDecoder, TextEncoder } from 'node:util' // Add missing import
import fs from 'node:fs'
import { JsSignatureProvider } from 'eosjs/dist/eosjs-jssig'
import { Api, JsonRpc, Serialize } from 'eosjs'
import {
DraftContract,
GatewayContract,
RegistratorContract,
SovietContract,
SystemContract,
TokenContract,
} from 'cooptypes'
// @ts-expect-error заменить на antelope
import EosApi from 'eosjs-api'
// @ts-expect-error заменить на antelope
import ecc from 'eosjs-ecc'
import config from '../configs'
import type { Contract, Feature, Keys, Network } from '../types'
export default class Blockchain {
public signatureProvider: any
public privateKeys: any[] = []
public api: any
public network: Network
public new_accounts: any[] = []
constructor(network: Network, privateKeys: string[] = []) {
this.network = network
this.privateKeys = privateKeys
}
async update_pass_instance() {
const protocol = this.network.protocol
const endpoint = this.network.host
const port = this.network.port
const res = `${protocol}://${endpoint}${port}`
const rpc = new JsonRpc(res, { fetch })
const signatureProvider = new JsSignatureProvider(this.privateKeys)
this.api = new Api({
rpc,
signatureProvider,
textDecoder: new TextDecoder(),
textEncoder: new TextEncoder(),
})
this.api.read = await EosApi({ httpEndpoint: res })
}
generateRandomUsername(): string {
const characters = 'abcdefghijklmnopqrstuvwxyz'
let username = ''
for (let i = 0; i < 12; i++) {
const randomIndex = Math.floor(Math.random() * characters.length)
username += characters[randomIndex]
}
return username
}
async getInfo() {
const result = await this.api.read.getInfo({})
return result
}
async getTableRows(
code: string,
scope: string,
table: string,
limit = 10,
lower_bound?: string,
upper_bound?: string,
index_position?: number,
key_type: 'i64' | 'i128' | 'i256' | 'float64' | 'float128' | 'sha256' | 'ripemd160' = 'i64',
): Promise<any> {
try {
const result = await this.api.read.getTableRows({
json: true,
code,
scope,
table,
limit,
lower_bound,
upper_bound,
index_position,
key_type,
})
return result.rows
}
catch (error) {
console.error('Error fetching table rows:', error)
throw error
}
}
async generateKeypair(username?: string, keys?: Keys, memo?: string) {
let privateKey = ''
let publicKey = ''
if (!username)
username = this.generateRandomUsername()
if (keys) {
privateKey = keys.privateKey
publicKey = keys.publicKey
}
else {
privateKey = await ecc.randomKey()
publicKey = await ecc.privateToPublic(privateKey)
}
this.privateKeys = [...this.privateKeys, privateKey]
this.new_accounts.push({ username, privateKey, publicKey, memo })
await this.update_pass_instance()
console.log('\tusername: ', username)
console.log('\tprivateKey: ', privateKey)
console.log('\tpublicKey: ', publicKey)
console.log('\tmemo: ', memo)
return { username, privateKey, publicKey, memo }
}
async createStandartAccount(
creator: string,
accountName: string,
ownerPublicKey: string,
activePublicKey: string,
) {
try {
await this.update_pass_instance()
const result = await this.api.transact(
{
actions: [
{
account: 'eosio',
name: 'newaccount',
authorization: [
{
actor: creator,
permission: 'active',
},
],
data: {
creator,
name: accountName,
owner: {
threshold: 1,
keys: [
{
key: ownerPublicKey,
weight: 1,
},
],
accounts: [],
waits: [],
},
active: {
threshold: 1,
keys: [
{
key: activePublicKey,
weight: 1,
},
],
accounts: [],
waits: [],
},
},
},
],
},
{
blocksBehind: 3,
expireSeconds: 30,
},
)
console.log(`Created account: ${accountName}`)
return result
}
catch (e) {
console.error(e)
}
}
async setContract(contract: Contract) {
try {
console.log('on set: ', contract)
const wasm_path = `${contract.path}/${contract.name}.wasm`
const abi_path = `${contract.path}/${contract.name}.abi`
console.log('wasm_path', wasm_path)
console.log('abi_path', abi_path)
const wasm = fs.readFileSync(wasm_path)
const abi = fs.readFileSync(abi_path)
const buffer = new Serialize.SerialBuffer({
textEncoder: this.api.textEncoder,
textDecoder: this.api.textDecoder,
})
const abiDefinitions = this.api.abiTypes.get('abi_def')
let abiJSON = JSON.parse(abi.toString()) // Convert the abi buffer to a string before parsing it as JSON
abiJSON = abiDefinitions.fields.reduce(
(acc: { [x: string]: any }, { name: fieldName }: any) =>
Object.assign(acc, { [fieldName]: acc[fieldName] || [] }),
abiJSON,
)
abiDefinitions.serialize(buffer, abiJSON)
// eslint-disable-next-line node/prefer-global/buffer
const serializedAbiHexString = Buffer.from(
buffer.asUint8Array(),
).toString('hex')
const data = {
account: contract.target,
vmtype: 0,
vmversion: 0,
code: wasm,
}
// console.log(data)
// console.log("abi: ", serializedAbiHexString)
this.api.transact(
{
actions: [
{
account: 'eosio',
name: 'setcode',
authorization: [
{
actor: contract.target,
permission: 'active',
},
],
data,
},
{
account: 'eosio',
name: 'setabi',
authorization: [
{
actor: contract.target,
permission: 'active',
},
],
data: {
account: contract.target,
abi: serializedAbiHexString,
},
},
],
},
{
blocksBehind: 3,
expireSeconds: 30,
},
)
console.log('contract setted: ', contract.target)
}
catch (e) {
console.log(e)
}
}
async activateFeature(feature: Feature) {
await this.update_pass_instance()
await this.api.transact(
{
actions: [
{
account: 'eosio',
name: 'activate',
authorization: [
{
actor: 'eosio',
permission: 'active',
},
],
data: {
feature_digest: feature.hash,
},
},
],
},
{
blocksBehind: 3,
expireSeconds: 30,
},
)
console.log('Фича активирована: ', feature.name)
}
async createToken(params: TokenContract.Interfaces.ICreate) {
await this.update_pass_instance()
await this.api.transact(
{
actions: [
{
account: 'eosio.token',
name: TokenContract.Actions.Create.actionName,
authorization: [
{
actor: 'eosio.token',
permission: 'active',
},
],
data: {
...params,
},
},
],
},
{
blocksBehind: 3,
expireSeconds: 30,
},
)
console.log('Токен создан: ', params)
}
async issueToken(params: TokenContract.Interfaces.IIssue) {
await this.update_pass_instance()
await this.api.transact(
{
actions: [
{
account: 'eosio.token',
name: TokenContract.Actions.Issue.actionName,
authorization: [
{
actor: 'eosio',
permission: 'active',
},
],
data: {
...params,
},
},
],
},
{
blocksBehind: 3,
expireSeconds: 30,
},
)
console.log('Токен выпущен: ', params)
}
async initSystem(params: SystemContract.Actions.Init.IInit) {
await this.update_pass_instance()
await this.api.transact(
{
actions: [
{
account: SystemContract.contractName.production,
name: SystemContract.Actions.Init.actionName,
authorization: [
{
actor: 'eosio',
permission: 'active',
},
],
data: {
...params,
},
},
],
},
{
blocksBehind: 3,
expireSeconds: 30,
},
)
console.log('Системный контракт инициализирован', params)
}
async initEmission(
params: SystemContract.Actions.InitEmission.IInitEmission,
) {
await this.update_pass_instance()
await this.api.transact(
{
actions: [
{
account: SystemContract.contractName.production,
name: SystemContract.Actions.InitEmission.actionName,
authorization: [
{
actor: 'eosio',
permission: 'active',
},
],
data: {
...params,
},
},
],
},
{
blocksBehind: 3,
expireSeconds: 30,
},
)
console.log('Эмиссия инициализирована', params)
}
async initPowerup(params: SystemContract.Actions.InitPowerup.IInitPowerup) {
await this.update_pass_instance()
await this.api.transact(
{
actions: [
{
account: SystemContract.contractName.production,
name: SystemContract.Actions.InitPowerup.actionName,
authorization: [
{
actor: 'eosio',
permission: 'active',
},
],
data: {
...params,
},
},
],
},
{
blocksBehind: 3,
expireSeconds: 30,
},
)
console.log('Система аренды инициализирована', params)
}
async powerup(params: SystemContract.Actions.Powerup.IPowerup) {
await this.update_pass_instance()
await this.api.transact(
{
actions: [
{
account: SystemContract.contractName.production,
name: SystemContract.Actions.Powerup.actionName,
authorization: [
{
actor: params.payer,
permission: 'active',
},
],
data: {
...params,
},
},
],
},
{
blocksBehind: 3,
expireSeconds: 30,
},
)
console.log('Аренда ресурсов: ', params)
}
async preInit(
params: RegistratorContract.Actions.SetCoopStatus.ISetCoopStatus,
) {
await this.update_pass_instance()
console.log(params)
await this.api.transact(
{
actions: [
{
account: RegistratorContract.contractName.production,
name: RegistratorContract.Actions.SetCoopStatus.actionName,
authorization: [
{
actor: config.provider,
permission: 'active',
},
],
data: {
...params,
},
},
],
},
{
blocksBehind: 3,
expireSeconds: 30,
},
)
console.log('Новый кооператив пре-иниализирован: ', params)
}
// TODO change registerCooperative to registerCooperative
async registerCooperative(
params: RegistratorContract.Actions.RegisterCooperative.IRegisterCooperative,
) {
await this.update_pass_instance()
console.log(params)
await this.api.transact(
{
actions: [
{
account: RegistratorContract.contractName.production,
name: RegistratorContract.Actions.RegisterCooperative.actionName,
authorization: [
{
actor: params.coopname,
permission: 'active',
},
],
data: {
...params,
},
},
],
},
{
blocksBehind: 3,
expireSeconds: 30,
},
)
console.log('Новая организация: ', params)
}
async sendAgreement(
data: SovietContract.Actions.Agreements.SendAgreement.ISendAgreement,
) {
console.log('data', data)
await this.api.transact(
{
actions: [
{
account: SovietContract.contractName.production,
name: SovietContract.Actions.Agreements.SendAgreement.actionName,
authorization: [
{
actor: data.administrator,
permission: 'active',
},
],
data,
},
],
},
{
blocksBehind: 3,
expireSeconds: 30,
},
)
}
async createAccount(
params: RegistratorContract.Actions.CreateAccount.ICreateAccount,
) {
await this.update_pass_instance()
await this.api.transact(
{
actions: [
{
account: RegistratorContract.contractName.production,
name: RegistratorContract.Actions.CreateAccount.actionName,
authorization: [
{
actor: params.coopname,
permission: 'active',
},
],
data: {
...params,
},
},
],
},
{
blocksBehind: 3,
expireSeconds: 30,
},
)
console.log('Новый аккаунт 2: ', params)
}
async registerUser(
params: RegistratorContract.Actions.RegisterUser.IRegistrerUser,
) {
await this.update_pass_instance()
await this.api.transact(
{
actions: [
{
account: RegistratorContract.contractName.production,
name: RegistratorContract.Actions.RegisterUser.actionName,
authorization: [
{
actor: params.coopname,
permission: 'active',
},
],
data: {
...params,
},
},
],
},
{
blocksBehind: 3,
expireSeconds: 30,
},
)
console.log('Новый пользователь: ', params)
}
async transfer(params: TokenContract.Actions.Transfer.ITransfer) {
await this.update_pass_instance()
const result = await this.api.transact(
{
actions: [
{
account: TokenContract.contractName.production,
name: TokenContract.Actions.Transfer.actionName,
authorization: [
{
actor: params.from,
permission: 'active',
},
],
data: {
...params,
},
},
],
},
{
blocksBehind: 3,
expireSeconds: 30,
},
)
console.log('Перевод токенов: ', params)
return result
}
async updateAccountPermissionsToCode(
account_for_change: string,
account_for_set_code: string,
) {
try {
await this.update_pass_instance()
const result = await this.api.transact(
{
actions: [
{
account: 'eosio',
name: 'updateauth',
authorization: [
{
actor: account_for_change,
permission: 'active',
},
],
data: {
account: account_for_change,
permission: 'active',
parent: 'owner',
auth: {
threshold: 1,
keys: [
{
key:
this.new_accounts.find(
(account: any) =>
account.username === account_for_change,
)?.publicKey || config.default_public_key,
weight: 1,
},
],
accounts: [
{
permission: {
actor: account_for_set_code,
permission: 'eosio.code',
},
weight: 1,
},
],
waits: [],
},
},
},
],
},
{
blocksBehind: 3,
expireSeconds: 30,
},
)
console.log(
`Updated account permissions: ${account_for_change} -> ${account_for_set_code}`,
)
return result
}
catch (e) {
console.error(e)
}
}
async votefor(
params: SovietContract.Actions.Decisions.VoteFor.IVoteForDecision,
) {
await this.update_pass_instance()
await this.api.transact(
{
actions: [
{
account: SovietContract.contractName.production,
name: SovietContract.Actions.Decisions.VoteFor.actionName,
authorization: [
{
actor: params.member,
permission: 'active',
},
],
data: {
...params,
},
},
],
},
{
blocksBehind: 3,
expireSeconds: 30,
},
)
console.log('Голос за решение: ', params)
}
async authorize(
params: SovietContract.Actions.Decisions.Authorize.IAuthorize,
) {
await this.update_pass_instance()
await this.api.transact(
{
actions: [
{
account: SovietContract.contractName.production,
name: SovietContract.Actions.Decisions.Authorize.actionName,
authorization: [
{
actor: params.chairman,
permission: 'active',
},
],
data: {
...params,
},
},
],
},
{
blocksBehind: 3,
expireSeconds: 30,
},
)
console.log('Решение утверждено: ', params)
}
async exec(params: SovietContract.Actions.Decisions.Exec.IExec) {
await this.update_pass_instance()
try {
await this.api.transact(
{
actions: [
{
account: SovietContract.contractName.production,
name: SovietContract.Actions.Decisions.Exec.actionName,
authorization: [
{
actor: params.executer,
permission: 'active',
},
],
data: {
...params,
},
},
],
},
{
blocksBehind: 3,
expireSeconds: 30,
},
)
}
catch (e) {
console.dir(e, { depth: null })
}
console.log('Решение исполнено: ', params)
}
async ConfirmPayment(
params: GatewayContract.Actions.CompleteIncome.ICompeteIncome,
) {
await this.update_pass_instance()
await this.api.transact(
{
actions: [
{
account: GatewayContract.contractName.production,
name: GatewayContract.Actions.CompleteIncome.actionName,
authorization: [
{
actor: params.coopname,
permission: 'active',
},
],
data: {
...params,
},
},
],
},
{
blocksBehind: 3,
expireSeconds: 30,
},
)
console.log('Заявление на вступление отправлено в совет: ', params)
}
async createBoard(
params: SovietContract.Actions.Boards.CreateBoard.ICreateboard,
) {
await this.update_pass_instance()
await this.api.transact(
{
actions: [
{
account: SovietContract.contractName.production,
name: SovietContract.Actions.Boards.CreateBoard.actionName,
authorization: [
{
actor: params.username,
permission: 'active',
},
],
data: {
...params,
},
},
],
},
{
blocksBehind: 3,
expireSeconds: 30,
},
)
console.log('Совет создан: ', params)
}
async createDraft(params: DraftContract.Actions.CreateDraft.ICreateDraft) {
await this.update_pass_instance()
await this.api.transact(
{
actions: [
{
account: DraftContract.contractName.production,
name: DraftContract.Actions.CreateDraft.actionName,
authorization: [
{
actor: params.username,
permission: 'active',
},
],
data: {
...params,
},
},
],
},
{
blocksBehind: 3,
expireSeconds: 30,
},
)
console.log('Шаблон создан: ', params)
}
async createTranslation(
params: DraftContract.Actions.CreateTranslation.ICreateTranslation,
) {
await this.update_pass_instance()
await this.api.transact(
{
actions: [
{
account: DraftContract.contractName.production,
name: DraftContract.Actions.CreateTranslation.actionName,
authorization: [
{
actor: 'eosio',
permission: 'active',
},
],
data: {
...params,
},
},
],
},
{
blocksBehind: 3,
expireSeconds: 30,
},
)
console.log('Перевод создан: ', params)
}
async createProgram(
params: SovietContract.Actions.Programs.CreateProgram.ICreateProgram,
) {
await this.update_pass_instance()
console.log('params', params)
await this.api.transact(
{
actions: [
{
account: SovietContract.contractName.production,
name: SovietContract.Actions.Programs.CreateProgram.actionName,
authorization: [
{
actor: params.username,
permission: 'active',
},
],
data: {
...params,
},
},
],
},
{
blocksBehind: 3,
expireSeconds: 30,
},
)
console.log('Программа установлена: ', params)
}
}
+532
View File
@@ -0,0 +1,532 @@
plugin = eosio::chain_plugin
plugin = eosio::producer_plugin
plugin = eosio::chain_api_plugin
plugin = eosio::http_plugin
plugin = eosio::state_history_plugin
plugin = eosio::producer_api_plugin
plugin = eosio::resource_monitor_plugin
enable-stale-production = true
read-only-read-window-time-us = 120000
net-threads = 2
max-transaction-time=2000
http-server-address = 0.0.0.0:8888
p2p-listen-endpoint = 0.0.0.0:9876
access-control-allow-origin = *
access-control-allow-credentials = false
http-validate-host = false
producer-name=eosio
producer-name=core
signature-provider = EOS6MRyAjQq8ud7hVNYcfnVPJqcVpscN5So8BhtHuGYqET5GDW5CV=KEY:5KQwrPbwdL6PhXujxW37FSSQZ1JiwsST4cqQzDeyXtP79zkvFD3
http-max-response-time-ms = 30000
max-body-size = 10485760
abi-serializer-max-time-ms = 200000
contracts-console = true
max-block-cpu-usage-threshold-us = 5000
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:8070
resource-monitor-space-threshold = 99
resource-monitor-not-shutdown-on-threshold-exceeded = true
wasm-runtime = eos-vm
# Percentage of cpu block production time used to produce block. Whole number percentages, e.g. 80 for 80% (eosio::producer_plugin)
# cpu-effort-percent = 80
# Percentage of cpu block production time used to produce last block. Whole number percentages, e.g. 80 for 80% (eosio::producer_plugin)
# last-block-cpu-effort-percent = 80
# the location of the blocks directory (absolute path or relative to application data dir) (eosio::chain_plugin)
# blocks-dir = "blocks"
# split the block log file when the head block number is the multiple of the stride
# When the stride is reached, the current block log and index will be renamed '<blocks-retained-dir>/blocks-<start num>-<end num>.log/index'
# and a new current block log and index will be created with the most recent block. All files following
# this format will be used to construct an extended block log. (eosio::chain_plugin)
# blocks-log-stride =
# the maximum number of blocks files to retain so that the blocks in those files can be queried.
# When the number is reached, the oldest block file would be moved to archive dir or deleted if the archive dir is empty.
# The retained block log files should not be manipulated by users. (eosio::chain_plugin)
# max-retained-block-files =
# the location of the blocks retained directory (absolute path or relative to blocks dir).
# If the value is empty, it is set to the value of blocks dir. (eosio::chain_plugin)
# blocks-retained-dir =
# the location of the blocks archive directory (absolute path or relative to blocks dir).
# If the value is empty, blocks files beyond the retained limit will be deleted.
# All files in the archive directory are completely under user's control, i.e. they won't be accessed by nodeos anymore. (eosio::chain_plugin)
# blocks-archive-dir =
# the location of the state directory (absolute path or relative to application data dir) (eosio::chain_plugin)
# state-dir = "state"
# the location of the protocol_features directory (absolute path or relative to application config dir) (eosio::chain_plugin)
# protocol-features-dir = "protocol_features"
# Pairs of [BLOCK_NUM,BLOCK_ID] that should be enforced as checkpoints. (eosio::chain_plugin)
# checkpoint =
# Override default WASM runtime ( "eos-vm-jit", "eos-vm")
# "eos-vm-jit" : A WebAssembly runtime that compiles WebAssembly code to native x86 code prior to execution.
# "eos-vm" : A WebAssembly interpreter.
# (eosio::chain_plugin)
# wasm-runtime = eos-vm-jit
# The name of an account whose code will be profiled (eosio::chain_plugin)
# profile-account =
# Override default maximum ABI serialization time allowed in ms (eosio::chain_plugin)
# abi-serializer-max-time-ms = 15
# Maximum size (in MiB) of the chain state database (eosio::chain_plugin)
# chain-state-db-size-mb = 1024
# Safely shut down node when free space remaining in the chain state database drops below this size (in MiB). (eosio::chain_plugin)
# chain-state-db-guard-size-mb = 128
# Percentage of actual signature recovery cpu to bill. Whole number percentages, e.g. 50 for 50% (eosio::chain_plugin)
# signature-cpu-billable-pct = 50
# Number of worker threads in controller thread pool (eosio::chain_plugin)
# chain-threads = 2
# print contract's output to console (eosio::chain_plugin)
# contracts-console = false
# print deeper information about chain operations (eosio::chain_plugin)
deep-mind = false
# Account added to actor whitelist (may specify multiple times) (eosio::chain_plugin)
# actor-whitelist =
# Account added to actor blacklist (may specify multiple times) (eosio::chain_plugin)
# actor-blacklist =
# Contract account added to contract whitelist (may specify multiple times) (eosio::chain_plugin)
# contract-whitelist =
# Contract account added to contract blacklist (may specify multiple times) (eosio::chain_plugin)
# contract-blacklist =
# Action (in the form code::action) added to action blacklist (may specify multiple times) (eosio::chain_plugin)
# action-blacklist =
# Public key added to blacklist of keys that should not be included in authorities (may specify multiple times) (eosio::chain_plugin)
# key-blacklist =
# Deferred transactions sent by accounts in this list do not have any of the subjective whitelist/blacklist checks applied to them (may specify multiple times) (eosio::chain_plugin)
# sender-bypass-whiteblacklist =
# Database read mode ("head", "irreversible", "speculative").
# In "head" mode: database contains state changes up to the head block; transactions received by the node are relayed if valid.
# In "irreversible" mode: database contains state changes up to the last irreversible block; transactions received via the P2P network are not relayed and transactions cannot be pushed via the chain API.
# In "speculative" mode: database contains state changes by transactions in the blockchain up to the head block as well as some transactions not yet included in the blockchain; transactions received by the node are relayed if valid.
# (eosio::chain_plugin)
# read-mode = head
# Allow API transactions to be evaluated and relayed if valid. (eosio::chain_plugin)
api-accept-transactions = true
# Chain validation mode ("full" or "light").
# In "full" mode all incoming blocks will be fully validated.
# In "light" mode all incoming blocks headers will be fully validated; transactions in those validated blocks will be trusted
# (eosio::chain_plugin)
# validation-mode = full
# Disable the check which subjectively fails a transaction if a contract bills more RAM to another account within the context of a notification handler (i.e. when the receiver is not the code of the action). (eosio::chain_plugin)
# disable-ram-billing-notify-checks = false
# Subjectively limit the maximum length of variable components in a variable legnth signature to this size in bytes (eosio::chain_plugin)
# maximum-variable-signature-length = 16384
# Indicate a producer whose blocks headers signed by it will be fully validated, but transactions in those validated blocks will be trusted. (eosio::chain_plugin)
# trusted-producer =
# Database map mode ("mapped", "heap", or "locked").
# In "mapped" mode database is memory mapped as a file.
# In "heap" mode database is preloaded in to swappable memory and will use huge pages if available.
# In "locked" mode database is preloaded, locked in to memory, and will use huge pages if available.
# (eosio::chain_plugin)
# database-map-mode = mapped
# Maximum size (in MiB) of the EOS VM OC code cache (eosio::chain_plugin)
# eos-vm-oc-cache-size-mb = 1024
# Number of threads to use for EOS VM OC tier-up (eosio::chain_plugin)
# eos-vm-oc-compile-threads = 1
# Enable EOS VM OC tier-up runtime (eosio::chain_plugin)
# eos-vm-oc-enable = false
# enable queries to find accounts by various metadata. (eosio::chain_plugin)
# enable-account-queries = false
# maximum allowed size (in bytes) of an inline action for a nonprivileged account (eosio::chain_plugin)
# max-nonprivileged-inline-action-size = 4096
# Maximum size (in GiB) allowed to be allocated for the Transaction Retry feature. Setting above 0 enables this feature. (eosio::chain_plugin)
# transaction-retry-max-storage-size-gb =
# How often, in seconds, to resend an incoming transaction to network if not seen in a block.
# Needs to be at least twice as large as p2p-dedup-cache-expire-time-sec. (eosio::chain_plugin)
# transaction-retry-interval-sec = 20
# Maximum allowed transaction expiration for retry transactions, will retry transactions up to this value.
# Should be larger than transaction-retry-interval-sec. (eosio::chain_plugin)
# transaction-retry-max-expiration-sec = 120
# Maximum size (in GiB) allowed to be allocated for the Transaction Finality Status feature. Setting above 0 enables this feature. (eosio::chain_plugin)
# transaction-finality-status-max-storage-size-gb =
# Duration (in seconds) a successful transaction's Finality Status will remain available from being first identified. (eosio::chain_plugin)
# transaction-finality-status-success-duration-sec = 180
# Duration (in seconds) a failed transaction's Finality Status will remain available from being first identified. (eosio::chain_plugin)
# transaction-finality-status-failure-duration-sec = 180
# Log the state integrity hash on startup (eosio::chain_plugin)
# integrity-hash-on-start = false
# Log the state integrity hash on shutdown (eosio::chain_plugin)
# integrity-hash-on-stop = false
# If set to greater than 0, periodically prune the block log to store only configured number of most recent blocks.
# If set to 0, no blocks are be written to the block log; block log file is removed after startup. (eosio::chain_plugin)
# block-log-retain-blocks =
# The filename (relative to data-dir) to create a unix socket for HTTP RPC; set blank to disable. (eosio::http_plugin)
# unix-socket-path =
# The local IP and port to listen for incoming http connections; set blank to disable. (eosio::http_plugin)
# http-server-address = 127.0.0.1:8888
# 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. 429 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. 429 error response when exceeded. (eosio::http_plugin)
# http-max-in-flight-requests = -1
# Maximum time for processing a request, -1 for unlimited (eosio::http_plugin)
# http-max-response-time-ms = 30
# 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
# Additionaly 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 actual host:port used to listen for incoming p2p connections. (eosio::net_plugin)
# p2p-listen-endpoint = 0.0.0.0:9876
# An externally accessible host:port for identifying this node. Defaults to p2p-listen-endpoint. (eosio::net_plugin)
# p2p-server-address =
# The public endpoint of a peer node to connect to. Use multiple p2p-peer-address options as needed to compose a network.
# Syntax: host:port[:<trx>|<blk>]
# The optional 'trx' and 'blk' indicates to node that only transactions 'trx' or blocks 'blk' should be sent. Examples:
# p2p.eos.io:9876
# p2p.trx.eos.io:9876:trx
# p2p.blk.eos.io:9876:blk
# (eosio::net_plugin)
# p2p-peer-address =
# Maximum number of client nodes from any single IP address (eosio::net_plugin)
# p2p-max-nodes-per-host = 1
# Allow transactions received over p2p network to be evaluated and relayed if valid. (eosio::net_plugin)
# p2p-accept-transactions = true
# The account and public p2p endpoint of a block producer node to automatically connect to when the it is in producer schedule proximity
# . Syntax: account,host:port
# Example,
# eosproducer1,p2p.eos.io:9876
# eosproducer2,p2p.trx.eos.io:9876:trx
# eosproducer3,p2p.blk.eos.io:9876:blk
# (eosio::net_plugin)
# p2p-auto-bp-peer =
# The name supplied to identify this node amongst the peers. (eosio::net_plugin)
# agent-name = EOS Test Agent
# Can be 'any' or 'producers' or 'specified' or 'none'. If 'specified', peer-key must be specified at least once. If only 'producers', peer-key is not required. 'producers' and 'specified' may be combined. (eosio::net_plugin)
# allowed-connection = any
# Optional public key of peer allowed to connect. May be used multiple times. (eosio::net_plugin)
# peer-key =
# Tuple of [PublicKey, WIF private key] (may specify multiple times) (eosio::net_plugin)
# peer-private-key =
# Maximum number of clients from which connections are accepted, use 0 for no limit (eosio::net_plugin)
# max-clients = 25
# number of seconds to wait before cleaning up dead connections (eosio::net_plugin)
# connection-cleanup-period = 30
# max connection cleanup time per cleanup call in milliseconds (eosio::net_plugin)
# max-cleanup-time-msec = 10
# Maximum time to track transaction for duplicate optimization (eosio::net_plugin)
# p2p-dedup-cache-expire-time-sec = 10
# Number of worker threads in net_plugin thread pool (eosio::net_plugin)
# net-threads = 4
# number of blocks to retrieve in a chunk from any individual peer during synchronization (eosio::net_plugin)
# sync-fetch-span = 100
# Enable experimental socket read watermark optimization (eosio::net_plugin)
# use-socket-read-watermark = false
# The string used to format peers when logging messages about them. Variables are escaped with ${<variable name>}.
# Available Variables:
# _name self-reported name
#
# _cid assigned connection id
#
# _id self-reported ID (64 hex characters)
#
# _sid first 8 characters of _peer.id
#
# _ip remote IP address of peer
#
# _port remote port number of peer
#
# _lip local IP address connected to peer
#
# _lport local port number connected to peer
#
# (eosio::net_plugin)
# peer-log-format = ["${_name}" - ${_cid} ${_ip}:${_port}]
# peer heartbeat keepalive message interval in milliseconds (eosio::net_plugin)
# p2p-keepalive-interval-ms = 10000
# Enable block production, even if the chain is stale. (eosio::producer_plugin)
# enable-stale-production = false
# Start this node in a state where production is paused (eosio::producer_plugin)
# pause-on-startup = false
# Limits the maximum time (in milliseconds) that is allowed a pushed transaction's code to execute before being considered invalid (eosio::producer_plugin)
# max-transaction-time = 30
# Limits the maximum age (in seconds) of the DPOS Irreversible Block for a chain this node will produce blocks on (use negative value to indicate unlimited) (eosio::producer_plugin)
# max-irreversible-block-age = -1
# ID of producer controlled by this node (e.g. inita; may specify multiple times) (eosio::producer_plugin)
# producer-name =
# Key=Value pairs in the form <public-key>=<provider-spec>
# Where:
# <public-key> is a string form of a vaild EOSIO public key
#
# <provider-spec> is a string in the form <provider-type>:<data>
#
# <provider-type> is KEY, KEOSD, or SE
#
# KEY:<data> is a string form of a valid EOSIO private key which maps to the provided public key
#
# KEOSD:<data> is the URL where keosd is available and the approptiate wallet(s) are unlocked
#
# (eosio::producer_plugin)
# signature-provider = EOS6MRyAjQq8ud7hVNYcfnVPJqcVpscN5So8BhtHuGYqET5GDW5CV=KEY:5KQwrPbwdL6PhXujxW37FSSQZ1JiwsST4cqQzDeyXtP79zkvFD3
# account that can not access to extended CPU/NET virtual resources (eosio::producer_plugin)
# greylist-account =
# Limit (between 1 and 1000) on the multiple that CPU/NET virtual resources can extend during low usage (only enforced subjectively; use 1000 to not enforce any limit) (eosio::producer_plugin)
# greylist-limit = 1000
# Offset of non last block producing time in microseconds. Valid range 0 .. -block_time_interval. (eosio::producer_plugin)
# produce-time-offset-us = 0
# Offset of last block producing time in microseconds. Valid range 0 .. -block_time_interval. (eosio::producer_plugin)
# last-block-time-offset-us = -200000
# Percentage of cpu block production time used to produce block. Whole number percentages, e.g. 80 for 80% (eosio::producer_plugin)
# cpu-effort-percent = 10
# Percentage of cpu block production time used to produce last block. Whole number percentages, e.g. 80 for 80% (eosio::producer_plugin)
# last-block-cpu-effort-percent = 10
# Threshold of CPU block production to consider block full; when within threshold of max-block-cpu-usage block can be produced immediately (eosio::producer_plugin)
# max-block-cpu-usage-threshold-us = 5000
# Threshold of NET block production to consider block full; when within threshold of max-block-net-usage block can be produced immediately (eosio::producer_plugin)
# max-block-net-usage-threshold-bytes = 1024
# Maximum wall-clock time, in milliseconds, spent retiring scheduled transactions (and incoming transactions according to incoming-defer-ratio) in any block before returning to normal transaction processing. (eosio::producer_plugin)
# max-scheduled-transaction-time-per-block-ms = 100
# Time in microseconds allowed for a transaction that starts with insufficient CPU quota to complete and cover its CPU usage. (eosio::producer_plugin)
# subjective-cpu-leeway-us = 31000
# Sets the maximum amount of failures that are allowed for a given account per window size. (eosio::producer_plugin)
# subjective-account-max-failures = 3
# Sets the window size in number of blocks for subjective-account-max-failures. (eosio::producer_plugin)
# subjective-account-max-failures-window-size = 1
# Sets the time to return full subjective cpu for accounts (eosio::producer_plugin)
# subjective-account-decay-time-minutes = 1440
# ratio between incoming transactions and deferred transactions when both are queued for execution (eosio::producer_plugin)
# incoming-defer-ratio = 1
# Maximum size (in MiB) of the incoming transaction queue. Exceeding this value will subjectively drop transaction with resource exhaustion. (eosio::producer_plugin)
# incoming-transaction-queue-size-mb = 1024
# Disable subjective CPU billing for API/P2P transactions (eosio::producer_plugin)
# disable-subjective-billing = true
# Account which is excluded from subjective CPU billing (eosio::producer_plugin)
# disable-subjective-account-billing =
# Disable subjective CPU billing for P2P transactions (eosio::producer_plugin)
# disable-subjective-p2p-billing = true
# Disable subjective CPU billing for API transactions (eosio::producer_plugin)
# disable-subjective-api-billing = true
# Number of worker threads in producer thread pool (eosio::producer_plugin)
# producer-threads = 1
# the location of the snapshots directory (absolute path or relative to application data dir) (eosio::producer_plugin)
# snapshots-dir = "snapshots"
# Number of worker threads in read-only execution thread pool. Max 8. (eosio::producer_plugin)
# read-only-threads =
# Time in microseconds the write window lasts. (eosio::producer_plugin)
# read-only-write-window-time-us = 200000
# Time in microseconds the read window lasts. (eosio::producer_plugin)
# read-only-read-window-time-us = 60000
# The local IP and port to listen for incoming prometheus metrics http request. (eosio::prometheus_plugin)
# prometheus-exporter-address = 127.0.0.1:9101
# Time in seconds between two consecutive checks of resource usage. Should be between 1 and 300 (eosio::resource_monitor_plugin)
# resource-monitor-interval-seconds = 2
# Threshold in terms of percentage of used space vs total space. If used space is above (threshold - 5%), a warning is generated. Unless resource-monitor-not-shutdown-on-threshold-exceeded is enabled, a graceful shutdown is initiated if used space is above the threshold. The value should be between 6 and 99 (eosio::resource_monitor_plugin)
# resource-monitor-space-threshold = 90
# Absolute threshold in gibibytes of remaining space; applied to each monitored directory. If remaining space is less than value for any monitored directories then threshold is considered exceeded.Overrides resource-monitor-space-threshold value. (eosio::resource_monitor_plugin)
# resource-monitor-space-absolute-gb =
# Used to indicate nodeos will not shutdown when threshold is exceeded. (eosio::resource_monitor_plugin)
# resource-monitor-not-shutdown-on-threshold-exceeded =
# Number of resource monitor intervals between two consecutive warnings when the threshold is hit. Should be between 1 and 450 (eosio::resource_monitor_plugin)
# resource-monitor-warning-interval = 30
# Limits the maximum time (in milliseconds) that is allowed for sending requests to a keosd provider for signing (eosio::signature_provider_plugin)
# keosd-provider-timeout = 5
# the location of the state-history directory (absolute path or relative to application data dir) (eosio::state_history_plugin)
# state-history-dir = "state-history"
# the location of the state history retained directory (absolute path or relative to state-history dir). (eosio::state_history_plugin)
# state-history-retained-dir =
# the location of the state history archive directory (absolute path or relative to state-history dir).
# If the value is empty string, blocks files beyond the retained limit will be deleted.
# All files in the archive directory are completely under user's control, i.e. they won't be accessed by nodeos anymore. (eosio::state_history_plugin)
# state-history-archive-dir =
# split the state history log files when the block number is the multiple of the stride
# When the stride is reached, the current history log and index will be renamed '*-history-<start num>-<end num>.log/index'
# and a new current history log and index will be created with the most recent blocks. All files following
# this format will be used to construct an extended history log. (eosio::state_history_plugin)
# state-history-stride =
# the maximum number of history file groups to retain so that the blocks in those files can be queried.
# When the number is reached, the oldest history file would be moved to archive dir or deleted if the archive dir is empty.
# The retained history log files should not be manipulated by users. (eosio::state_history_plugin)
# max-retained-history-files =
# enable trace history (eosio::state_history_plugin)
# trace-history = false
# enable chain state history (eosio::state_history_plugin)
# chain-state-history = false
# the endpoint upon which to listen for incoming connections. Caution: only expose this port to your internal network. (eosio::state_history_plugin)
# state-history-endpoint = 127.0.0.1:8080
# the path (relative to data-dir) to create a unix socket upon which to listen for incoming connections. (eosio::state_history_plugin)
# state-history-unix-socket-path =
# enable debug mode for trace history (eosio::state_history_plugin)
# trace-history-debug-mode = false
# if set, periodically prune the state history files to store only configured number of most recent blocks (eosio::state_history_plugin)
# state-history-log-retain-blocks =
# the location of the trace directory (absolute path or relative to application data dir) (eosio::trace_api_plugin)
# trace-dir = "traces"
# the number of blocks each "slice" of trace data will contain on the filesystem (eosio::trace_api_plugin)
# trace-slice-stride = 10000
# Number of blocks to ensure are kept past LIB for retrieval before "slice" files can be automatically removed.
# A value of -1 indicates that automatic removal of "slice" files will be turned off. (eosio::trace_api_plugin)
# trace-minimum-irreversible-history-blocks = -1
# Number of blocks to ensure are uncompressed past LIB. Compressed "slice" files are still accessible but may carry a performance loss on retrieval
# A value of -1 indicates that automatic compression of "slice" files will be turned off. (eosio::trace_api_plugin)
# trace-minimum-uncompressed-irreversible-history-blocks = -1
# ABIs used when decoding trace RPC responses.
# There must be at least one ABI specified OR the flag trace-no-abis must be used.
# ABIs are specified as "Key=Value" pairs in the form <account-name>=<abi-def>
# Where <abi-def> can be:
# an absolute path to a file containing a valid JSON-encoded ABI
# a relative path from `data-dir` to a file containing a valid JSON-encoded ABI
# (eosio::trace_api_plugin)
# trace-rpc-abi =
# Use to indicate that the RPC responses will not use ABIs.
# Failure to specify this option when there are no trace-rpc-abi configuations will result in an Error.
# This option is mutually exclusive with trace-rpc-api (eosio::trace_api_plugin)
# trace-no-abis =
# Plugin(s) to enable, may be specified multiple times
# plugin =
+93
View File
@@ -0,0 +1,93 @@
/* eslint-disable node/prefer-global/process */
import path from 'node:path'
import { config } from 'dotenv'
config()
export default [
{
name: 'eosio.boot',
path: path.resolve(process.cwd(), '../contracts/build/contracts/system/contracts/eosio.boot'),
target: 'eosio',
},
{
name: 'eosio.system',
path: path.resolve(process.cwd(), '../contracts/build/contracts/system/contracts/eosio.system'),
target: 'eosio',
},
{
name: 'eosio.token',
path: path.resolve(process.cwd(), '../contracts/build/contracts/system/contracts/eosio.token'),
target: 'eosio.token',
},
{
name: 'eosio.msig',
path: path.resolve(process.cwd(), '../contracts/build/contracts/system/contracts/eosio.msig'),
target: 'eosio.msig',
},
{
name: 'eosio.wrap',
path: path.resolve(process.cwd(), '../contracts/build/contracts/system/contracts/eosio.wrap'),
target: 'eosio.wrap',
},
{
name: 'registrator',
path: path.resolve(process.cwd(), '../contracts/build/contracts/registrator'),
target: 'registrator',
},
{
name: 'soviet',
path: path.resolve(process.cwd(), '../contracts/build/contracts/soviet'),
target: 'soviet',
},
{
name: 'marketplace',
path: path.resolve(process.cwd(), '../contracts/build/contracts/marketplace'),
target: 'marketplace',
},
{
name: 'draft',
path: path.resolve(process.cwd(), '../contracts/build/contracts/draft'),
target: 'draft',
},
{
name: 'branch',
path: path.resolve(process.cwd(), '../contracts/build/contracts/branch'),
target: 'branch',
},
{
name: 'gateway',
path: path.resolve(process.cwd(), '../contracts/build/contracts/gateway'),
target: 'gateway',
},
{
name: 'fund',
path: path.resolve(process.cwd(), '../contracts/build/contracts/fund'),
target: 'fund',
},
{
name: 'contributor',
path: path.resolve(process.cwd(), '../contracts/build/contracts/contributor'),
target: 'contributor',
},
{
name: 'capital',
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',
},
]
+24
View File
@@ -0,0 +1,24 @@
{
"initial_timestamp": "2024-06-19T06:00:00.000",
"initial_key": "EOS6MRyAjQq8ud7hVNYcfnVPJqcVpscN5So8BhtHuGYqET5GDW5CV",
"initial_configuration": {
"max_block_net_usage": 1048576,
"target_block_net_usage_pct": 1000,
"max_transaction_net_usage": 1048575,
"base_per_transaction_net_usage": 12,
"net_usage_leeway": 500,
"context_free_discount_net_usage_num": 20,
"context_free_discount_net_usage_den": 100,
"max_block_cpu_usage": 300000,
"target_block_cpu_usage_pct": 500,
"max_transaction_cpu_usage": 290000,
"min_transaction_cpu_usage": 100,
"max_transaction_lifetime": 3600,
"deferred_trx_expiration_window": 600,
"max_transaction_delay": 3888000,
"max_inline_action_size": 4096,
"max_inline_action_depth": 10,
"max_authority_depth": 6
},
"initial_chain_id": "0000000000000000000000000000000000000000000000000000000000000000"
}
+213
View File
@@ -0,0 +1,213 @@
/* eslint-disable node/prefer-global/process */
import path from 'node:path'
import { config } from 'dotenv'
import contracts from './contracts'
config()
const network = {
name: 'local',
protocol: 'http',
host: 'localhost',
port: ':8888',
}
// const network = {
// name: 'local',
// protocol: 'https',
// host: 'test.coopenomics.world:443/api',
// port: '',
// }
export const SYMBOL = 'AXON'
export const GOVERN_SYMBOL = 'RUB'
export const provider = 'voskhod'
export const provider_chairman = 'ant'
export const public_key = process.env.EOSIO_PUB_KEY as string
export const private_key = process.env.EOSIO_PRV_KEY as string
export default {
network,
default_public_key: public_key,
system: 'eosio',
provider,
provider_chairman,
private_keys: [private_key],
emission: {
left_border: `1000.0000 ${SYMBOL}`,
tact_duration: 86400,
emission_factor: 0.618,
},
token: {
symbol: SYMBOL,
govern_symbol: GOVERN_SYMBOL,
precision: 4,
max_supply: `1000000000.0000 ${SYMBOL}`,
},
powerup: {
days: 1,
min_powerup: `0.0001 ${SYMBOL}`,
},
allocations: [
{
to: 'eosio',
quantity: `10000.0000 ${SYMBOL}`,
},
],
accounts: [
{
name: 'eosio.token',
},
{
name: 'eosio.bpay',
},
{
name: 'eosio.vpay',
},
{
name: 'eosio.msig',
},
{
name: 'eosio.wrap',
},
{
name: 'eosio.power',
},
{
name: 'eosio.saving',
code_permissions_to: ['eosio.saving'],
},
{
name: 'registrator',
code_permissions_to: ['registrator'],
},
{
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'],
},
{
name: 'branch',
code_permissions_to: ['branch'],
},
{
name: 'marketplace',
code_permissions_to: ['marketplace'],
},
{
name: 'draft',
code_permissions_to: ['draft'],
},
{
name: 'gateway',
code_permissions_to: ['gateway'],
},
{
name: 'fund',
code_permissions_to: ['fund'],
},
{
name: 'contributor',
code_permissions_to: ['contributor'],
},
{
name: provider_chairman,
},
{
name: provider,
code_permissions_to: ['registrator'],
},
],
contracts,
features: [
{
name: 'ACTION_RETURN_VALUE',
hash: 'c3a6138c5061cf291310887c0b5c71fcaffeab90d5deb50d3b9e687cead45071',
},
{
name: 'CONFIGURABLE_WASM_LIMITS2',
hash: 'd528b9f6e9693f45ed277af93474fd473ce7d831dae2180cca35d907bd10cb40',
},
{
name: 'BLOCKCHAIN_PARAMETERS',
hash: '5443fcf88330c586bc0e5f3dee10e7f63c76c00249c87fe4fbf7f38c082006b4',
},
{
name: 'GET_SENDER',
hash: 'f0af56d2c5a48d60a4a5b5c903edfb7db3a736a94ed589d0b797df33ff9d3e1d',
},
{
name: 'FORWARD_SETCODE',
hash: '2652f5f96006294109b3dd0bbde63693f55324af452b799ee137a81a905eed25',
},
{
name: 'ONLY_BILL_FIRST_AUTHORIZER',
hash: '8ba52fe7a3956c5cd3a656a3174b931d3bb2abb45578befc59f283ecd816a405',
},
{
name: 'RESTRICT_ACTION_TO_SELF',
hash: 'ad9e3d8f650687709fd68f4b90b41f7d825a365b02c23a636cef88ac2ac00c43',
},
{
name: 'DISALLOW_EMPTY_PRODUCER_SCHEDULE',
hash: '68dcaa34c0517d19666e6b33add67351d8c5f69e999ca1e37931bc410a297428',
},
{
name: 'FIX_LINKAUTH_RESTRICTION',
hash: 'e0fb64b1085cc5538970158d05a009c24e276fb94e1a0bf6a528b48fbc4ff526',
},
{
name: 'REPLACE_DEFERRED',
hash: 'ef43112c6543b88db2283a2e077278c315ae2c84719a8b25f25cc88565fbea99',
},
{
name: 'NO_DUPLICATE_DEFERRED_ID',
hash: '4a90c00d55454dc5b059055ca213579c6ea856967712a56017487886a4d4cc0f',
},
{
name: 'ONLY_LINK_TO_EXISTING_PERMISSION',
hash: '1a99a59d87e06e09ec5b028a9cbb7749b4a5ad8819004365d02dc4379a8b7241',
},
{
name: 'RAM_RESTRICTIONS',
hash: '4e7bf348da00a945489b2a681749eb56f5de00b900014e137ddae39f48f69d67',
},
{
name: 'WEBAUTHN_KEY',
hash: '4fca8bd82bbd181e714e283f83e1b45d95ca5af40fb89ad3977b653c448f78c2',
},
{
name: 'WTMSIG_BLOCK_SIGNATURES',
hash: '299dcb6af692324b899b39f16d5a530a33062804e41f09dc97e9f156b4476707',
},
{
name: 'GET_CODE_HASH',
hash: 'bcd2a26394b36614fd4894241d3c451ab0f6fd110958c3423073621a70826e99',
},
{
name: 'GET_BLOCK_NUM',
hash: '35c2186cc36f7bb4aeaf4487b36e57039ccf45a9136aa856a5d569ecca55ef2b',
},
{
name: 'CRYPTO_PRIMITIVES',
hash: '6bcb40a24e49c26d0a60513b6aeb8551d264e4717f306b81a37a5afb3b47cedc',
},
],
}
+10
View File
@@ -0,0 +1,10 @@
import type { Network } from '../types'
export const networks: Network[] = [
{
name: 'local',
protocol: 'http',
host: '127.0.0.1',
port: ':8888',
},
]
@@ -0,0 +1,11 @@
{
"protocol_feature_type": "builtin",
"dependencies": [],
"description_digest": "69b064c5178e2738e144ed6caa9349a3995370d78db29e494b3126ebd9111966",
"subjective_restrictions": {
"earliest_allowed_activation_time": "1970-01-01T00:00:00.000",
"preactivation_required": true,
"enabled": true
},
"builtin_feature_codename": "ACTION_RETURN_VALUE"
}
@@ -0,0 +1,11 @@
{
"protocol_feature_type": "builtin",
"dependencies": [],
"description_digest": "70787548dcea1a2c52c913a37f74ce99e6caae79110d7ca7b859936a0075b314",
"subjective_restrictions": {
"earliest_allowed_activation_time": "1970-01-01T00:00:00.000",
"preactivation_required": true,
"enabled": true
},
"builtin_feature_codename": "BLOCKCHAIN_PARAMETERS"
}
@@ -0,0 +1,11 @@
{
"protocol_feature_type": "builtin",
"dependencies": [],
"description_digest": "c0cce5bcd8ea19a28d9e12eafda65ebe6d0e0177e280d4f20c7ad66dcd9e011b",
"subjective_restrictions": {
"earliest_allowed_activation_time": "1970-01-01T00:00:00.000",
"preactivation_required": true,
"enabled": true
},
"builtin_feature_codename": "BLS_PRIMITIVES2"
}
@@ -0,0 +1,11 @@
{
"protocol_feature_type": "builtin",
"dependencies": [],
"description_digest": "8139e99247b87f18ef7eae99f07f00ea3adf39ed53f4d2da3f44e6aa0bfd7c62",
"subjective_restrictions": {
"earliest_allowed_activation_time": "1970-01-01T00:00:00.000",
"preactivation_required": true,
"enabled": true
},
"builtin_feature_codename": "CONFIGURABLE_WASM_LIMITS2"
}
@@ -0,0 +1,11 @@
{
"protocol_feature_type": "builtin",
"dependencies": [],
"description_digest": "68d6405cb8df3de95bd834ebb408196578500a9f818ff62ccc68f60b932f7d82",
"subjective_restrictions": {
"earliest_allowed_activation_time": "1970-01-01T00:00:00.000",
"preactivation_required": true,
"enabled": true
},
"builtin_feature_codename": "CRYPTO_PRIMITIVES"
}
@@ -0,0 +1,11 @@
{
"protocol_feature_type": "builtin",
"dependencies": [],
"description_digest": "440c3efaaab212c387ce967c574dc813851cf8332d041beb418dfaf55facd5a9",
"subjective_restrictions": {
"earliest_allowed_activation_time": "1970-01-01T00:00:00.000",
"preactivation_required": true,
"enabled": true
},
"builtin_feature_codename": "DISABLE_DEFERRED_TRXS_STAGE_1"
}
@@ -0,0 +1,13 @@
{
"protocol_feature_type": "builtin",
"dependencies": [
"fce57d2331667353a0eac6b4209b67b843a7262a848af0a49a6e2fa9f6584eb4"
],
"description_digest": "a857eeb932774c511a40efb30346ec01bfb7796916b54c3c69fe7e5fb70d5cba",
"subjective_restrictions": {
"earliest_allowed_activation_time": "1970-01-01T00:00:00.000",
"preactivation_required": true,
"enabled": true
},
"builtin_feature_codename": "DISABLE_DEFERRED_TRXS_STAGE_2"
}
@@ -0,0 +1,11 @@
{
"protocol_feature_type": "builtin",
"dependencies": [],
"description_digest": "2853617cec3eabd41881eb48882e6fc5e81a0db917d375057864b3befbe29acd",
"subjective_restrictions": {
"earliest_allowed_activation_time": "1970-01-01T00:00:00.000",
"preactivation_required": true,
"enabled": true
},
"builtin_feature_codename": "DISALLOW_EMPTY_PRODUCER_SCHEDULE"
}
@@ -0,0 +1,11 @@
{
"protocol_feature_type": "builtin",
"dependencies": [],
"description_digest": "a98241c83511dc86c857221b9372b4aa7cea3aaebc567a48604e1d3db3557050",
"subjective_restrictions": {
"earliest_allowed_activation_time": "1970-01-01T00:00:00.000",
"preactivation_required": true,
"enabled": true
},
"builtin_feature_codename": "FIX_LINKAUTH_RESTRICTION"
}
@@ -0,0 +1,11 @@
{
"protocol_feature_type": "builtin",
"dependencies": [],
"description_digest": "898082c59f921d0042e581f00a59d5ceb8be6f1d9c7a45b6f07c0e26eaee0222",
"subjective_restrictions": {
"earliest_allowed_activation_time": "1970-01-01T00:00:00.000",
"preactivation_required": true,
"enabled": true
},
"builtin_feature_codename": "FORWARD_SETCODE"
}
@@ -0,0 +1,11 @@
{
"protocol_feature_type": "builtin",
"dependencies": [],
"description_digest": "e5d7992006e628a38c5e6c28dd55ff5e57ea682079bf41fef9b3cced0f46b491",
"subjective_restrictions": {
"earliest_allowed_activation_time": "1970-01-01T00:00:00.000",
"preactivation_required": true,
"enabled": true
},
"builtin_feature_codename": "GET_BLOCK_NUM"
}
@@ -0,0 +1,11 @@
{
"protocol_feature_type": "builtin",
"dependencies": [],
"description_digest": "d2596697fed14a0840013647b99045022ae6a885089f35a7e78da7a43ad76ed4",
"subjective_restrictions": {
"earliest_allowed_activation_time": "1970-01-01T00:00:00.000",
"preactivation_required": true,
"enabled": true
},
"builtin_feature_codename": "GET_CODE_HASH"
}
@@ -0,0 +1,11 @@
{
"protocol_feature_type": "builtin",
"dependencies": [],
"description_digest": "1eab748b95a2e6f4d7cb42065bdee5566af8efddf01a55a0a8d831b823f8828a",
"subjective_restrictions": {
"earliest_allowed_activation_time": "1970-01-01T00:00:00.000",
"preactivation_required": true,
"enabled": true
},
"builtin_feature_codename": "GET_SENDER"
}
@@ -0,0 +1,13 @@
{
"protocol_feature_type": "builtin",
"dependencies": [
"ef43112c6543b88db2283a2e077278c315ae2c84719a8b25f25cc88565fbea99"
],
"description_digest": "45967387ee92da70171efd9fefd1ca8061b5efe6f124d269cd2468b47f1575a0",
"subjective_restrictions": {
"earliest_allowed_activation_time": "1970-01-01T00:00:00.000",
"preactivation_required": true,
"enabled": true
},
"builtin_feature_codename": "NO_DUPLICATE_DEFERRED_ID"
}
@@ -0,0 +1,11 @@
{
"protocol_feature_type": "builtin",
"dependencies": [],
"description_digest": "2f1f13e291c79da5a2bbad259ed7c1f2d34f697ea460b14b565ac33b063b73e2",
"subjective_restrictions": {
"earliest_allowed_activation_time": "1970-01-01T00:00:00.000",
"preactivation_required": true,
"enabled": true
},
"builtin_feature_codename": "ONLY_BILL_FIRST_AUTHORIZER"
}
@@ -0,0 +1,11 @@
{
"protocol_feature_type": "builtin",
"dependencies": [],
"description_digest": "f3c3d91c4603cde2397268bfed4e662465293aab10cd9416db0d442b8cec2949",
"subjective_restrictions": {
"earliest_allowed_activation_time": "1970-01-01T00:00:00.000",
"preactivation_required": true,
"enabled": true
},
"builtin_feature_codename": "ONLY_LINK_TO_EXISTING_PERMISSION"
}
@@ -0,0 +1,11 @@
{
"protocol_feature_type": "builtin",
"dependencies": [],
"description_digest": "64fe7df32e9b86be2b296b3f81dfd527f84e82b98e363bc97e40bc7a83733310",
"subjective_restrictions": {
"earliest_allowed_activation_time": "1970-01-01T00:00:00.000",
"preactivation_required": false,
"enabled": true
},
"builtin_feature_codename": "PREACTIVATE_FEATURE"
}
@@ -0,0 +1,11 @@
{
"protocol_feature_type": "builtin",
"dependencies": [],
"description_digest": "1812fdb5096fd854a4958eb9d53b43219d114de0e858ce00255bd46569ad2c68",
"subjective_restrictions": {
"earliest_allowed_activation_time": "1970-01-01T00:00:00.000",
"preactivation_required": true,
"enabled": true
},
"builtin_feature_codename": "RAM_RESTRICTIONS"
}
@@ -0,0 +1,11 @@
{
"protocol_feature_type": "builtin",
"dependencies": [],
"description_digest": "9908b3f8413c8474ab2a6be149d3f4f6d0421d37886033f27d4759c47a26d944",
"subjective_restrictions": {
"earliest_allowed_activation_time": "1970-01-01T00:00:00.000",
"preactivation_required": true,
"enabled": true
},
"builtin_feature_codename": "REPLACE_DEFERRED"
}
@@ -0,0 +1,11 @@
{
"protocol_feature_type": "builtin",
"dependencies": [],
"description_digest": "e71b6712188391994c78d8c722c1d42c477cf091e5601b5cf1befd05721a57f3",
"subjective_restrictions": {
"earliest_allowed_activation_time": "1970-01-01T00:00:00.000",
"preactivation_required": true,
"enabled": true
},
"builtin_feature_codename": "RESTRICT_ACTION_TO_SELF"
}
@@ -0,0 +1,11 @@
{
"protocol_feature_type": "builtin",
"dependencies": [],
"description_digest": "927fdf78c51e77a899f2db938249fb1f8bb38f4e43d9c1f75b190492080cbc34",
"subjective_restrictions": {
"earliest_allowed_activation_time": "1970-01-01T00:00:00.000",
"preactivation_required": true,
"enabled": true
},
"builtin_feature_codename": "WEBAUTHN_KEY"
}
@@ -0,0 +1,11 @@
{
"protocol_feature_type": "builtin",
"dependencies": [],
"description_digest": "ab76031cad7a457f4fd5f5fca97a3f03b8a635278e0416f77dcc91eb99a48e10",
"subjective_restrictions": {
"earliest_allowed_activation_time": "1970-01-01T00:00:00.000",
"preactivation_required": true,
"enabled": true
},
"builtin_feature_codename": "WTMSIG_BLOCK_SIGNATURES"
}
+3
View File
@@ -0,0 +1,3 @@
import { runContainer } from './run'
export const container = await runContainer()
+34
View File
@@ -0,0 +1,34 @@
/* eslint-disable node/prefer-global/process */
import Blockchain from '../blockchain'
import contracts from '../configs/contracts'
import type { INetwork } from '../configs/networks'
import { networks } from '../configs/networks'
import type { Contract } from '../types'
import { execCommand } from './exec'
export async function deployCommand(name: string, pre_target: string, pre_network: string): Promise<void> {
const network: INetwork | undefined = networks.find(el => el.name === pre_network)
if (!network)
throw new Error('Сеть не найдена')
const contract = contracts.find(el => el.name === name)
if (!contract)
throw new Error('Контракт не найден')
let target = contract.target
if (pre_target)
target = pre_target
const contract_for_deploy: Contract = {
path: contract.path,
name,
target,
}
const blockchain = new Blockchain(network, [process.env.EOSIO_PRV_KEY as string])
await blockchain.update_pass_instance()
await blockchain.setContract(contract_for_deploy)
}
+25
View File
@@ -0,0 +1,25 @@
import { exec } from 'node:child_process'
import { promisify } from 'node:util'
const execAsync = promisify(exec)
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 (stdout)
console.log(stdout.trim())
if (stderr)
console.error(stderr.trim())
}
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}`)
}
}
+14
View File
@@ -0,0 +1,14 @@
import Docker from 'dockerode'
const docker = new Docker()
export async function findContainerByName(name: string) {
const containers = await docker.listContainers({ all: true })
const containerInfo = containers.find(c => c.Names.includes(`/${name}`))
if (containerInfo) {
return docker.getContainer(containerInfo.Id)
}
return null
}
+28
View File
@@ -0,0 +1,28 @@
import axios from 'axios'
async function sleep(ms: number): Promise<void> {
return new Promise(resolve => setTimeout(resolve, ms))
}
export async function checkHealth() {
const check = async (): Promise<void> => {
try {
const response = await axios.post('http://127.0.0.1:8888/v1/chain/get_info')
const result = response.data
await sleep(1000)
console.log('Node is healthy. Continue.', result)
}
catch (error: any) {
console.error(error)
console.log('Блокчейн не доступен с ошибкой. Он поднят? docker compose up -d')
await sleep(1000)
return check() // Повторный вызов функции
}
}
return check()
}
+70
View File
@@ -0,0 +1,70 @@
import { promises as fs } from 'node:fs'
import * as path from 'node:path'
import mongoose from 'mongoose'
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')
}
catch (e) {
console.error('Ошибка при удалении:', e)
}
try {
await mongoose.connection.collection('actions').deleteMany({})
console.log('Все документы удалены из коллекции actions')
}
catch (e) {
console.error('Ошибка при удалении:', e)
}
try {
await mongoose.connection.collection('deltas').deleteMany({})
console.log('Все документы удалены из коллекции deltas')
}
catch (e) {
console.error('Ошибка при удалении:', e)
}
}
export async function clearDirectory(dirPath: string): Promise<void> {
try {
const files = await fs.readdir(dirPath)
for (const file of files) {
const filePath = path.join(dirPath, file)
const stats = await fs.stat(filePath)
if (stats.isDirectory()) {
await clearDirectory(filePath)
await fs.rmdir(filePath)
}
else {
await fs.unlink(filePath)
}
}
}
catch (err) {
console.error(`Error clearing directory ${dirPath}:`, err)
}
}
export async function deleteFile(filePath: string): Promise<void> {
try {
await fs.unlink(filePath)
}
catch (err) {
// console.error(`Error deleting file ${filePath}:`, err)
}
}
+17
View File
@@ -0,0 +1,17 @@
import { exec } from 'node:child_process'
import { config } from 'dotenv'
config()
export async function runContainer(): Promise<void> {
return new Promise((resolve, reject) => {
exec('docker compose up -d node', (error, stdout, stderr) => {
if (error) {
console.error(`Ошибка при запуске контейнера: ${error.message}`)
reject(error)
return
}
resolve()
})
})
}
+11
View File
@@ -0,0 +1,11 @@
import Docker from 'dockerode'
import { findContainerByName } from './find'
export async function stopContainerByName(name: string) {
const container = await findContainerByName(name)
if (container) {
await container.stop()
console.log(`Container stopped.`)
}
}
+194
View File
@@ -0,0 +1,194 @@
/* eslint-disable node/prefer-global/process */
import path from 'node:path'
import fs from 'node:fs'
import { Command } from 'commander'
import { config } from 'dotenv'
import { execCommand } from './docker/exec'
import { stopContainerByName } from './docker/stop'
import { runContainer } from './docker/run'
import { boot } from './init/booter'
import { sleep } from './utils'
import { checkHealth } from './docker/health'
import { clearDB, clearDirectory, deleteFile } from './docker/purge'
import { deployCommand } from './docker/deploy'
config()
const basePath = path.resolve(process.cwd(), './blockchain-data')
const keosdPath = path.resolve(process.cwd(), './wallet-data/keosd.sock')
if (!fs.existsSync(basePath)) {
fs.mkdirSync(basePath, { recursive: true })
}
if (!fs.existsSync(keosdPath)) {
fs.mkdirSync(keosdPath, { recursive: true })
}
const program = new Command()
program.version('0.1.0')
// Команда для запуска команды в контейнере
program
.command('cleos [cmd...]')
.description('Execute a cleos command in a Node container')
.allowUnknownOption()
.action(async (cmd: string[] = []) => {
await execCommand(['cleos', ...cmd])
})
// Команда для запуска команды в контейнере
program
.command('deploy <contract_name>')
.description('Execute a deploy command in a Node container')
.option('-t, --target <target>', 'Specify the target')
.option('-n, --network <network>', 'Specify the network', 'local')
.allowUnknownOption()
.action(async (cmd: string, options: any) => {
try {
const { target, network } = options
await deleteFile(keosdPath)
await deployCommand(cmd, target, network)
}
catch (error) {
console.error('Command execution failed:', error)
}
})
// Команда для получения списка контейнеров
program
.command('stop')
.description('Stop blockchain node as is')
.action(async () => {
try {
await stopContainerByName('node')
console.log('Container is stopped')
}
catch (error) {
console.error('Failed to list containers:', error)
}
})
// Команда для запуска команды в контейнере
program
.command('unlock')
.description('Unlock a cleos wallet with a .env password')
.allowUnknownOption()
.action(async () => {
try {
await execCommand([
'cleos',
'wallet',
'unlock',
'--password',
process.env.PASSWORD!,
])
}
catch (error) {
console.error('Command execution failed:', error)
}
})
// Команда для получения списка контейнеров
program
.command('start')
.description('Start blockchain node as is')
.action(async () => {
try {
await deleteFile(keosdPath)
await runContainer()
console.log('Container is started')
}
catch (error) {
console.error('Failed to list containers:', error)
}
})
// Команда для получения списка контейнеров
program
.command('boot')
.description('Purge blockchain data and boot a Protocol')
.action(async () => {
try {
await stopContainerByName('node')
}
catch (e) {
console.log('Нет контейнера для остановки. Стартуем новый..')
}
try {
await clearDirectory(basePath)
await clearDB()
await runContainer()
await sleep(5000)
await checkHealth()
await boot()
console.log(`
Boot is
.d8888b. .d88888b. 888b d888 8888888b. 888 8888888888 88888888888 8888888888
d88P Y88b d88P" "Y88b 8888b d8888 888 Y88b 888 888 888 888
888 888 888 888 88888b.d88888 888 888 888 888 888 888
888 888 888 888Y88888P888 888 d88P 888 8888888 888 8888888
888 888 888 888 Y888P 888 8888888P" 888 888 888 888
888 888 888 888 888 Y8P 888 888 888 888 888 888
Y88b d88P Y88b. .d88P 888 " 888 888 888 888 888 888
"Y8888P" "Y88888P" 888 888 888 88888888 8888888888 888 8888888888
`)
process.exit(0)
}
catch (error) {
console.error('Failed to boot:', error)
process.exit(1)
}
})
// Команда для получения списка контейнеров
program
.command('clear')
.description('Purge blockchain data and boot a Protocol')
.action(async () => {
try {
await stopContainerByName('node')
await deleteFile(keosdPath)
await clearDirectory(basePath)
await sleep(5000)
await clearDB()
await runContainer()
console.log('Блокчейн очищен и перезапущен. Запустите загрузку: pnpm run boot')
process.exit(0)
}
catch (error) {
console.error('Failed to boot:', error)
process.exit(1)
}
})
// Команда для получения списка контейнеров
program
.command('only-boot')
.description('Boot a Protocol')
.action(async () => {
try {
await boot()
}
catch (error) {
console.error('Failed to boot:', error)
}
})
program.parse(process.argv) // Пуск парсинга аргументов
async function gracefulShutdown() {
// console.log('Stopping container...')
// await stopContainerByName('node')
process.exit(0)
}
process.on('SIGINT', gracefulShutdown)
process.on('SIGTERM', gracefulShutdown)
+7
View File
@@ -0,0 +1,7 @@
import { startInfra } from "./infra"
import { startCoop } from "./cooperative"
export async function boot() {
await startInfra()
await startCoop()
}
+177
View File
@@ -0,0 +1,177 @@
import axios from 'axios'
import { describe, expect, it } from 'vitest'
import { Registry } from '@coopenomics/factory'
import { Cooperative as TCooperative } from 'cooptypes'
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'
const test_sign
= 'SIG_K1_KmKWPBC8dZGGDGhbKEoZEzPr3h5crRrR2uLdGRF5DJbeibY1MY1bZ9sPwHsgmPfiGFv9psfoCVsXFh9TekcLuvaeuxRKA8'
const test_pkey = 'EOS5JhMfxbsNebajHcTEK8yC9uNN9Dit9hEmzE8ri8yMhhzxrLg3J'
const test_meta = JSON.stringify({})
const document = {
hash: test_hash,
signature: test_sign,
public_key: test_pkey,
meta: test_meta,
}
export class CooperativeClass {
public blockchain: Blockchain
constructor(blockchain: Blockchain) {
this.blockchain = blockchain
}
async createPrograms(coopname: string) {
await this.blockchain.createProgram({
coopname,
username: coopname,
type: 'cooplace',
title: 'КООПЛЕЙС',
announce: '',
description: '',
preview: '',
images: '',
calculation_type: 'relative',
fixed_membership_contribution: `${Number(0).toFixed(4)} ${GOVERN_SYMBOL}`,
membership_percent_fee: 10000, // 10%
meta: '',
is_can_coop_spend_share_contributions: false,
})
}
async createCooperative(username: string, keys?: Keys) {
const account = await this.blockchain.generateKeypair(
username,
keys,
'Аккаунт кооператива',
)
console.log('Регистрируем аккаунт')
await this.blockchain.createAccount({
coopname: config.provider,
referer: '',
username: account.username,
public_key: account.publicKey,
meta: '',
})
console.log('Регистрируем аккаунт как пользователя')
const registration_hash = generateRandomSHA256()
await this.blockchain.registerUser({
coopname: config.provider,
braname: '',
username: account.username,
type: 'organization',
statement: document,
registration_hash,
})
console.log('Отправляем заявление на вступление')
await this.blockchain.ConfirmPayment({
coopname: config.provider,
income_hash: registration_hash,
})
console.log('Голосуем по решению в провайдере')
await this.blockchain.votefor({
coopname: config.provider,
member: config.provider_chairman,
decision_id: 1,
})
console.log('Утверждаем решение в провайдере')
await this.blockchain.authorize({
coopname: config.provider,
chairman: config.provider_chairman,
decision_id: 1,
document,
})
console.log('Исполняем решение в провайдере')
await this.blockchain.exec({
executer: config.provider_chairman,
coopname: config.provider,
decision_id: 1,
})
console.log('Отправляем подписанное положение о ЦПП Кошелька оператору')
await this.blockchain.sendAgreement({
coopname: config.provider,
administrator: config.provider,
username: username!,
agreement_type: 'wallet',
document: { // отправляем произвольный документ с валидной подписью
hash: '157192B276DA23CC84AB078FC8755C051C5F0430BF4802E55718221E6B76C777',
public_key: 'PUB_K1_5JhMfxbsNebajHcTEK8yC9uNN9Dit9hEmzE8ri8yMhhzzEtUA4',
signature: 'SIG_K1_KmKWPBC8dZGGDGhbKEoZEzPr3h5crRrR2uLdGRF5DJbeibY1MY1bZ9sPwHsgmPfiGFv9psfoCVsXFh9TekcLuvaeuxRKA8',
meta: '{}',
},
})
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: '' })
console.log(`Арендуем ресурсы кооперативу`)
await this.blockchain.powerup({
payer: 'eosio',
receiver: username,
days: config.powerup.days,
payment: `100.0000 ${config.token.symbol}`,
transfer: true,
})
}
}
export async function startCoop() {
// инициализируем инстанс с ключами
const blockchain = new Blockchain(config.network, config.private_keys)
const cooperative = new CooperativeClass(blockchain)
await cooperative.createCooperative('cooperative1', {
// eslint-disable-next-line node/prefer-global/process
privateKey: process.env.EOSIO_PRV_KEY!,
// eslint-disable-next-line node/prefer-global/process
publicKey: process.env.EOSIO_PUB_KEY!,
})
await blockchain.preInit({
coopname: 'cooperative1',
username: config.provider,
status: 'active',
})
console.log('Кооператив предварительно подготовлен к установке совета.')
}
+338
View File
@@ -0,0 +1,338 @@
import { randomUUID } from 'node:crypto'
import axios from 'axios'
import { Generator, Registry } from '@coopenomics/factory'
import type { Cooperative } from 'cooptypes'
import { DraftContract } from 'cooptypes'
import mongoose from 'mongoose'
import type { Account, Contract } from '../types'
import config from '../configs'
import Blockchain from '../blockchain'
import { sleep } from '../utils'
import { CooperativeClass } from './cooperative'
export async function startInfra() {
// инициализируем инстанс с ключами
const blockchain = new Blockchain(config.network, config.private_keys)
await blockchain.update_pass_instance()
// регистрируем базовые аккаунты
for (const account of config.accounts) {
const { name, ownerPublicKey, activePublicKey } = account as Account
await blockchain.createStandartAccount(
'eosio',
name,
ownerPublicKey || config.default_public_key,
activePublicKey || config.default_public_key,
)
}
// пре-активируем фичу для запуска
const url = `${config.network.protocol}://${config.network.host}${config.network.port}`
try {
const response = await axios.post(
`${url}/v1/producer/schedule_protocol_feature_activations`,
{
protocol_features_to_activate: [
'0ec7e080177b2c02b278d5088611686b49d739925a92d9bfcacd7fc6b74053bd',
],
},
)
console.log('ok -> init activation: ', response.data)
}
catch (e) {
console.log('error -> init activation: ', e)
}
// чуть ждём
await sleep(1000)
// устанавливаем биос
const bios = config.contracts.find(el => el.name === 'eosio.boot')
await blockchain.setContract(bios as Contract)
// чуть ждём
await sleep(2000)
// активируем все оставшиеся фичи
for (const feature of config.features)
await blockchain.activateFeature(feature)
// чуть ждём
await sleep(2000)
// устанавливаем все оставшиеся контракты
const filtered_contracts = config.contracts.filter(
el => el.name !== 'eosio.boot',
)
for (const contract of filtered_contracts)
await blockchain.setContract(contract)
await sleep(2000)
console.log('создаём токен')
await blockchain.createToken({
issuer: 'eosio',
maximum_supply: config.token.max_supply,
})
await sleep(2000)
console.log('выпускаем токены')
for (const allocation of config.allocations) {
await blockchain.issueToken({
to: allocation.to,
quantity: allocation.quantity,
memo: '',
})
}
await sleep(2000)
// выдаём кодовые разрешения всем указанным аккаунтам
for (const account of config.accounts.filter(
el => !!el.code_permissions_to,
)) {
for (const permission_to of account.code_permissions_to ?? []) {
await blockchain.updateAccountPermissionsToCode(
account.name,
permission_to,
)
}
}
await sleep(1000)
// инициализируем системный контракт
await blockchain.initSystem({
version: 0,
core: `${config.token.precision},${config.token.symbol}`,
})
await sleep(1000)
// инициализируем эмиссию
await blockchain.initEmission({
init_supply: config.emission.left_border,
tact_duration: config.emission.tact_duration,
emission_factor: config.emission.emission_factor,
})
await sleep(2000)
await blockchain.initPowerup({
args: {
powerup_days: config.powerup.days,
min_powerup_fee: config.powerup.min_powerup,
},
})
await sleep(2000)
for (const id in Registry) {
const template = Registry[(id as unknown) as keyof typeof Registry]
await blockchain.createDraft({
scope: DraftContract.contractName.production,
username: 'eosio',
registry_id: id,
lang: 'ru',
title: template.Template.title,
description: template.Template.description,
context: template.Template.context,
model: JSON.stringify(template.Template.model),
translation_data: JSON.stringify(template.Template.translations.ru),
})
}
const organizationData: Cooperative.Users.IOrganizationData = {
username: 'voskhod',
type: 'coop',
short_name: '"ПК Восход"',
full_name: 'Потребительский Кооператив "ВОСХОД"',
represented_by: {
first_name: 'Иван',
last_name: 'Иванов',
middle_name: 'Иванович',
position: 'Председатель',
based_on: 'Решение общего собрания №1',
},
country: 'Российская Федерация',
city: 'Москва',
fact_address: '117593 г. Москва, муниципальный округ Ясенево, проезд Соловьиный, дом 1, помещение 1/1',
full_address:
'117593 г. Москва, муниципальный округ Ясенево, проезд Соловьиный, дом 1, помещение 1/1',
email: 'copenomics@yandex.ru',
phone: '+71234567890',
details: {
inn: '9728130611',
ogrn: '1247700283346',
kpp: '772801001',
},
}
const generator = new Generator()
// eslint-disable-next-line node/prefer-global/process
await generator.connect(process.env.MONGO_URI as string)
await generator.save('organization', organizationData)
console.log('Провайдер добавлен: ', organizationData)
await generator.save('paymentMethod', {
is_default: true,
method_id: randomUUID(),
method_type: 'bank_transfer',
username: 'voskhod',
data: {
account_number: '40703810038000110117',
currency: 'RUB',
card_number: '',
bank_name: 'ПАО Сбербанк',
details: {
bik: '044525225',
corr: '30101810400000000225',
kpp: '773643001',
},
},
})
const userData: Cooperative.Users.IIndividualData = {
username: 'ant',
first_name: 'Иван',
last_name: 'Иванов',
middle_name: 'Иванович',
birthdate: '1990/04/01',
phone: '+71234567890',
email: 'ivanov@example.com',
full_address: 'Переулок Правды д. 1',
passport: {
series: 7122,
number: 112233,
issued_by: 'отделом УФМС по г. Москва',
issued_at: '2010/05/10',
code: '111-232',
},
}
await generator.save('individual', userData)
// добавляем переменные кооператива
const vars: Cooperative.Model.IVars = {
coopname: 'voskhod',
full_abbr: 'потребительский кооператив',
full_abbr_genitive: 'потребительского кооператива',
full_abbr_dative: 'потребительскому кооперативу',
short_abbr: 'ПК',
website: 'цифровой-кооператив.рф',
name: 'Восход',
confidential_link: 'coopenomics.world/privacy',
confidential_email: 'privacy@coopenomics.world',
contact_email: 'contact@coopenomics.world',
passport_request: 'no',
wallet_agreement: {
protocol_number: '10-04-2024',
protocol_day_month_year: '10 апреля 2024 г.',
},
signature_agreement: {
protocol_number: '10-04-2024',
protocol_day_month_year: '10 апреля 2024 г.',
},
privacy_agreement: {
protocol_number: '10-04-2024',
protocol_day_month_year: '10 апреля 2024 г.',
},
user_agreement: {
protocol_number: '10-04-2024',
protocol_day_month_year: '10 апреля 2024 г.',
},
participant_application: {
protocol_number: '10-04-2024',
protocol_day_month_year: '10 апреля 2024 г.',
},
}
await generator.save('vars', vars)
// eslint-disable-next-line node/prefer-global/process
await mongoose.connect(process.env.MONGO_URI as string)
try {
await mongoose.connection.collection('sync').deleteMany({})
console.log('Все документы удалены из коллекции sync')
}
catch (e) {
console.error('Ошибка при удалении:', e)
}
try {
await mongoose.connection.collection('actions').deleteMany({})
console.log('Все документы удалены из коллекции actions')
}
catch (e) {
console.error('Ошибка при удалении:', e)
}
try {
await mongoose.connection.collection('deltas').deleteMany({})
console.log('Все документы удалены из коллекции deltas')
}
catch (e) {
console.error('Ошибка при удалении:', e)
}
// добавляем пользователя для подключений
try {
await mongoose.connection.collection('users').insertOne({
email: 'ivanov@example.com',
username: 'ant',
type: 'individual',
role: 'chairman',
is_registered: true,
})
}
catch (e) { console.log('user is exist') }
// имитируем установку
try {
await mongoose.connection.collection('monos').insertOne({
coopname: 'voskhod',
status: 'active',
})
}
catch (e) {
console.log('system is exist')
}
// сохраняем зашированный ключ в vault
try {
await mongoose.connection.collection('vaults').insertOne({
username: 'voskhod',
permission: 'active',
wif: '9d6479a9d77ead53fb0e5e54b3608a95:2046ee3c1577d48aecbee49e8f25c4c2df37ab02f15d73d0d1b6352f53a4b774cb9e71b6028fd7caf64568e195c7878dfbb5d2bf10a3766d90ba9e92ea724428',
})
}
catch (e) { console.log('vault is exist') }
console.log('Создаём программы и соглашения')
const cooperative = new CooperativeClass(blockchain)
await cooperative.createPrograms(config.provider)
console.log(`Арендуем ресурсы провайдеру`)
await blockchain.powerup({
payer: 'eosio',
receiver: config.provider,
days: config.powerup.days,
payment: `100.0000 ${config.token.symbol}`,
transfer: true,
})
await blockchain.transfer({
from: 'eosio',
to: config.provider,
quantity: `100.0000 ${config.token.symbol}`,
memo: '',
})
console.log('Базовая установка завершена')
}
+128
View File
@@ -0,0 +1,128 @@
import axios from 'axios'
import { describe, expect, it } from 'vitest'
import { Registry } from '@coopenomics/factory'
import { RegistratorContract, Cooperative as TCooperative } from 'cooptypes'
import type { Account, Contract, Keys } from '../types'
import config, { GOVERN_SYMBOL, SYMBOL } from '../configs'
import Blockchain from '../blockchain'
import { sendPostToCoopbackWithSecret, sleep } from '../utils'
// const test_hash
// = '157192b276da23cc84ab078fc8755c051c5f0430bf4802e55718221e6b76c777'
// const test_sign
// = 'SIG_K1_KmKWPBC8dZGGDGhbKEoZEzPr3h5crRrR2uLdGRF5DJbeibY1MY1bZ9sPwHsgmPfiGFv9psfoCVsXFh9TekcLuvaeuxRKA8'
// const test_pkey = 'EOS5JhMfxbsNebajHcTEK8yC9uNN9Dit9hEmzE8ri8yMhhzxrLg3J'
// const test_meta = JSON.stringify({})
// const document = {
// hash: test_hash,
// signature: test_sign,
// public_key: test_pkey,
// meta: test_meta,
// }
export class CooperativeClass {
public blockchain: Blockchain
constructor(blockchain: Blockchain) {
this.blockchain = blockchain
}
async addUser(username: string, keys?: Keys) {
const account = await this.blockchain.generateKeypair(
username,
keys,
'Аккаунт участника',
)
console.log('Регистрируем аккаунт')
const data: RegistratorContract.Actions.AddUser.IAddUser = {
coopname: config.provider,
referer: '',
username: account.username,
type: 'individual',
created_at: '2025-02-05T09:34:27',
initial: '100.0000 RUB',
minimum: '100.0000 RUB',
spread_initial: false,
meta: '',
}
await this.blockchain.api.transact({
actions: [
{
account: RegistratorContract.contractName.production,
name: RegistratorContract.Actions.AddUser.actionName,
authorization: [{ actor: config.provider, permission: 'active' }],
data,
},
],
}, {
blocksBehind: 3,
expireSeconds: 30,
})
console.log('Регистрируем аккаунт как пользователя')
const changeKey: RegistratorContract.Actions.ChangeKey.IChangeKey = {
coopname: config.provider,
changer: config.provider,
username: account.username,
public_key: account.publicKey,
}
await this.blockchain.api.transact({
actions: [
{
account: RegistratorContract.contractName.production,
name: RegistratorContract.Actions.ChangeKey.actionName,
authorization: [{ actor: config.provider, permission: 'active' }],
data: changeKey,
},
],
}, {
blocksBehind: 3,
expireSeconds: 30,
})
console.log('Отправляем подписанное положение о ЦПП Кошелька оператору')
await this.blockchain.sendAgreement({
coopname: config.provider,
administrator: config.provider,
username: username!,
agreement_type: 'wallet',
document: { // отправляем произвольный документ с валидной подписью
hash: '157192B276DA23CC84AB078FC8755C051C5F0430BF4802E55718221E6B76C777',
public_key: 'PUB_K1_5JhMfxbsNebajHcTEK8yC9uNN9Dit9hEmzE8ri8yMhhzzEtUA4',
signature: 'SIG_K1_KmKWPBC8dZGGDGhbKEoZEzPr3h5crRrR2uLdGRF5DJbeibY1MY1bZ9sPwHsgmPfiGFv9psfoCVsXFh9TekcLuvaeuxRKA8',
meta: '{}',
},
})
console.log('создаём кошелёк')
// console.log(`Арендуем ресурсы кооперативу`)
// await this.blockchain.powerup({
// payer: 'eosio',
// receiver: username,
// days: config.powerup.days,
// payment: `100.0000 ${config.token.symbol}`,
// transfer: true,
// })
}
}
export async function addUser(username: string) {
// инициализируем инстанс с ключами
const blockchain = new Blockchain(config.network, config.private_keys)
const cooperative = new CooperativeClass(blockchain)
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
publicKey: process.env.EOSIO_PUB_KEY!,
})
}
+853
View File
@@ -0,0 +1,853 @@
import { afterAll, beforeAll, describe, expect, it } from 'vitest'
import { CapitalContract, GatewayContract, SovietContract, TokenContract } from 'cooptypes'
import Blockchain from '../blockchain'
import config from '../configs'
import { getTotalRamUsage, globalRamStats } from '../utils/getTotalRamUsage'
import { generateRandomSHA256 } from '../utils/randomHash'
import { addUser } from '../init/participant'
import { generateRandomUsername } from '../utils/randomUsername'
import { sleep } from '../utils'
import { processDecision } from './soviet/processDecision'
import { registerAndApproveUHDContract } from './capital/registerAndApproveUHDContract'
import { depositToWallet } from './wallet/depositToWallet'
import { signWalletAgreement } from './wallet/signWalletAgreement'
import { signAgreement } from './soviet/signAgreement'
import { signCapitalAgreement } from './capital/signCapitalAgreement'
import { getCoopProgramWallet, getUserProgramWallet } from './wallet/walletUtils'
import { investInProject } from './capital/investInProject'
import { allocateFundsToResult } from './capital/allocateFundsToResult'
import { commitToResult } from './capital/commitToResult'
import { capitalProgramId, ratePerHour, sourceProgramId, walletProgramId } from './capital/consts'
import { withdrawContribution } from './capital/withdrawContribution'
import { registerExpense } from './capital/registerExpense'
// const CLI_PATH = 'src/index.ts'
const blockchain = new Blockchain(config.network, config.private_keys)
let project1: CapitalContract.Actions.CreateProject.ICreateProject
let _project2: CapitalContract.Actions.CreateProject.ICreateProject
let _project3: CapitalContract.Actions.CreateProject.ICreateProject
let tester1: string
let tester2: string
let tester3: string
let investor1: string
let result1: CapitalContract.Actions.CreateResult.ICreateResult
let _result2: CapitalContract.Actions.CreateResult.ICreateResult
let _result3: CapitalContract.Actions.CreateResult.ICreateResult
const commits: string[] = []
const tester1CommitHours = 10
const tester2CommitHours = 10
const investAmount = '100000.0000 RUB'
const fakeDocument = {
hash: '157192B276DA23CC84AB078FC8755C051C5F0430BF4802E55718221E6B76C777',
public_key: 'PUB_K1_5JhMfxbsNebajHcTEK8yC9uNN9Dit9hEmzE8ri8yMhhzzEtUA4',
signature: 'SIG_K1_KmKWPBC8dZGGDGhbKEoZEzPr3h5crRrR2uLdGRF5DJbeibY1MY1bZ9sPwHsgmPfiGFv9psfoCVsXFh9TekcLuvaeuxRKA8',
meta: '{}',
}
beforeAll(async () => {
await blockchain.update_pass_instance()
investor1 = generateRandomUsername()
console.log('investor1: ', investor1)
await addUser(investor1)
tester1 = generateRandomUsername()
console.log('tester1: ', tester1)
await addUser(tester1)
tester2 = generateRandomUsername()
console.log('tester2: ', tester2)
await addUser(tester2)
tester3 = generateRandomUsername()
console.log('tester3: ', tester3)
await addUser(tester3)
// const { stdout } = await execa('esno', [CLI_PATH, 'boot'], { stdio: 'inherit' })
// expect(stdout).toContain('Boot process completed')
}, 500_000)
afterAll(() => {
console.log('\n📊 **RAM USAGE SUMMARY** 📊')
let totalGlobalRam = 0
for (const [key, ramUsed] of Object.entries(globalRamStats)) {
const ramKb = (ramUsed / 1024).toFixed(2)
console.log(` ${key} = ${ramKb} kb`)
totalGlobalRam += ramUsed
}
console.log(`\n💾 **TOTAL RAM USED IN TESTS**: ${(totalGlobalRam / 1024).toFixed(2)} kb\n`)
})
describe('тест контракта CAPITAL', () => {
it('создаём программу генерации', async () => {
const program = await getCoopProgramWallet(blockchain, 'voskhod', sourceProgramId)
if (!program) {
const data: SovietContract.Actions.Programs.CreateProgram.ICreateProgram = {
coopname: 'voskhod',
is_can_coop_spend_share_contributions: true,
username: 'ant',
title: 'Договор УХД',
announce: '',
description: '',
preview: '',
images: '',
calculation_type: 'free',
fixed_membership_contribution: '0.0000 RUB',
membership_percent_fee: '0',
meta: '',
type: 'source',
}
const result = await blockchain.api.transact(
{
actions: [
{
account: SovietContract.contractName.production,
name: SovietContract.Actions.Programs.CreateProgram.actionName,
authorization: [
{
actor: 'ant',
permission: 'active',
},
],
data,
},
],
},
{
blocksBehind: 3,
expireSeconds: 30,
},
)
getTotalRamUsage(result)
expect(result.transaction_id).toBeDefined()
}
})
it('создаём программу капитализации', async () => {
const program = await getCoopProgramWallet(blockchain, 'voskhod', capitalProgramId)
if (!program) {
const data: SovietContract.Actions.Programs.CreateProgram.ICreateProgram = {
coopname: 'voskhod',
is_can_coop_spend_share_contributions: false,
username: 'ant',
title: 'Капитализация',
announce: '',
description: '',
preview: '',
images: '',
calculation_type: 'free',
fixed_membership_contribution: '0.0000 RUB',
membership_percent_fee: '0',
meta: '',
type: 'capital',
}
const result = await blockchain.api.transact(
{
actions: [
{
account: SovietContract.contractName.production,
name: SovietContract.Actions.Programs.CreateProgram.actionName,
authorization: [
{
actor: 'ant',
permission: 'active',
},
],
data,
},
],
},
{
blocksBehind: 3,
expireSeconds: 30,
},
)
getTotalRamUsage(result)
expect(result.transaction_id).toBeDefined()
}
})
it('инициализируем контракт CAPITAL', async () => {
const data: CapitalContract.Actions.Init.IInit = {
coopname: 'voskhod',
initiator: 'voskhod',
}
const state = (await blockchain.getTableRows(
CapitalContract.contractName.production,
CapitalContract.contractName.production,
'state',
1,
'voskhod',
'voskhod',
))[0]
if (state) {
expect(state.coopname).toBe('voskhod')
}
else {
const result = await blockchain.api.transact(
{
actions: [
{
account: CapitalContract.contractName.production,
name: CapitalContract.Actions.Init.actionName,
authorization: [
{
actor: 'voskhod',
permission: 'active',
},
],
data,
},
],
},
{
blocksBehind: 3,
expireSeconds: 30,
},
)
getTotalRamUsage(result)
expect(result.transaction_id).toBeDefined()
}
})
it('создаём проект', async () => {
const hash = generateRandomSHA256()
const parentHash = '0000000000000000000000000000000000000000000000000000000000000000'
const data: CapitalContract.Actions.CreateProject.ICreateProject = {
coopname: 'voskhod',
application: 'voskhod',
title: `Идея ${hash.slice(0, 10)}`,
description: `Описание ${hash.slice(0, 10)}`,
project_hash: hash,
parent_project_hash: parentHash,
parent_distribution_ratio: 0,
terms: '',
subject: '',
}
project1 = data
const result = await blockchain.api.transact(
{
actions: [
{
account: CapitalContract.contractName.production,
name: CapitalContract.Actions.CreateProject.actionName,
authorization: [
{
actor: 'voskhod',
permission: 'active',
},
],
data,
},
],
},
{
blocksBehind: 3,
expireSeconds: 30,
},
)
expect(result.transaction_id).toBeDefined()
const project = (await blockchain.getTableRows(
CapitalContract.contractName.production,
'voskhod',
'projects',
1,
project1.project_hash,
project1.project_hash,
3,
'sha256',
))[0]
expect(project).toBeDefined()
expect(project.status).toBe('created')
expect(project.target).toBe('0.0000 RUB')
expect(project.invested).toBe('0.0000 RUB')
expect(project.authors_count).toBe(0)
expect(project.authors_shares).toBe(0)
expect(project.project_hash).toBe(data.project_hash)
expect(project.title).toBe(data.title)
expect(project.description).toBe(data.description)
getTotalRamUsage(result)
})
it('заключаем договор УХД с автором по проекту', async () => {
const testerNames = [tester1, tester2, investor1] // Можно передавать любое количество пользователей
for (const tester of testerNames) {
await registerAndApproveUHDContract(blockchain, tester, project1.project_hash)
// Получаем все решения и утверждаем последнее
const decisions = await blockchain.getTableRows(
SovietContract.contractName.production,
'voskhod',
'decisions',
1000,
)
const lastDecision = decisions[decisions.length - 1]
console.log(`Последнее решение: `, lastDecision)
await processDecision(blockchain, lastDecision.id)
// Проверка финального статуса контрибьютора
const contributor = (await blockchain.getTableRows(
CapitalContract.contractName.production,
'voskhod',
'contributors',
1,
tester,
tester,
2,
'i64',
))[0]
console.log(`Контрибьютор ${tester} после авторизации: `, contributor)
expect(contributor).toBeDefined()
expect(contributor.status).toBe('authorized')
}
})
it('добавляем автора к идее', async () => {
const data: CapitalContract.Actions.AddAuthor.IAddAuthor = {
coopname: 'voskhod',
application: 'voskhod',
project_hash: project1.project_hash,
author: tester1,
shares: '100',
}
const result = await blockchain.api.transact(
{
actions: [
{
account: CapitalContract.contractName.production,
name: CapitalContract.Actions.AddAuthor.actionName,
authorization: [
{
actor: 'voskhod',
permission: 'active',
},
],
data,
},
],
},
{
blocksBehind: 3,
expireSeconds: 30,
},
)
getTotalRamUsage(result)
expect(result.transaction_id).toBeDefined()
const author = (await blockchain.getTableRows(
CapitalContract.contractName.production,
'voskhod',
'authors',
1,
project1.project_hash,
project1.project_hash,
3,
'sha256',
))[0]
console.log('author: ', author)
expect(author).toBeDefined()
expect(author.username).toBe(tester1)
expect(author.shares).toBe(100)
expect(author.project_hash).toBe(project1.project_hash)
const project = (await blockchain.getTableRows(
CapitalContract.contractName.production,
'voskhod',
'projects',
1,
project1.project_hash,
project1.project_hash,
3,
'sha256',
))[0]
expect(project).toBeDefined()
expect(project.authors_count).toBe(1)
expect(project.authors_shares).toBe(100)
})
it('создать результат', async () => {
const data: CapitalContract.Actions.CreateResult.ICreateResult = {
coopname: 'voskhod',
application: 'voskhod',
project_hash: project1.project_hash,
result_hash: generateRandomSHA256(),
assignee: 'ant',
assignment: 'Задание #1: тут описание',
}
result1 = data
const result = await blockchain.api.transact(
{
actions: [
{
account: CapitalContract.contractName.production,
name: CapitalContract.Actions.CreateResult.actionName,
authorization: [
{
actor: 'voskhod',
permission: 'active',
},
],
data,
},
],
},
{
blocksBehind: 3,
expireSeconds: 30,
},
)
getTotalRamUsage(result)
expect(result.transaction_id).toBeDefined()
const blockchainResult = (await blockchain.getTableRows(
CapitalContract.contractName.production,
'voskhod',
'results',
1,
result1.result_hash,
result1.result_hash,
2,
'sha256',
))[0]
expect(blockchainResult).toBeDefined()
expect(blockchainResult.result_hash).toBe(result1.result_hash)
expect(blockchainResult.project_hash).toBe(project1.project_hash)
expect(blockchainResult.coopname).toBe('voskhod')
})
it(`подписать соглашение о ЦПП "Цифровой Кошелек" и пополнить баланс кошелька investor1`, async () => {
{
const { wallet, program } = await signWalletAgreement(blockchain, 'voskhod', investor1, fakeDocument)
console.log('wallet investor1: ', wallet)
}
{
const { depositId, program, userWallet } = await depositToWallet(blockchain, 'voskhod', investor1, 100000)
}
})
it('подписать соглашение о ЦПП "Капитализация"', async () => {
const testerNames = [tester1, tester2, investor1] // Можно передавать любое количество пользователей
for (const tester of testerNames) {
await signCapitalAgreement(blockchain, 'voskhod', tester, fakeDocument)
}
})
it('инвестировать в проект аккаунтом investor1', async () => {
await investInProject(blockchain, 'voskhod', investor1, project1.project_hash, investAmount, fakeDocument)
})
it('финансировать результат проекта на 10000 RUB', async () => {
await allocateFundsToResult(blockchain, 'voskhod', project1.project_hash, result1.result_hash, '10000.0000 RUB')
})
it('финансировать результат проекта на 20000 RUB', async () => {
await allocateFundsToResult(blockchain, 'voskhod', project1.project_hash, result1.result_hash, '20000.0000 RUB')
})
it('добавить коммит создателя tester1 на 10 часов по 1000 RUB', async () => {
const { finalResult, commitHash } = await commitToResult(blockchain, 'voskhod', result1.result_hash, result1.project_hash, tester1, tester1CommitHours)
commits.push(commitHash)
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).toBe('30000.0000 RUB')
expect(finalResult.capitalists_bonus).toBe('48540.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_base).toBe('20000.0000 RUB')
expect(finalResult.creators_bonus).toBe('7640.0000 RUB')
expect(finalResult.authors_bonus).toBe('32360.0000 RUB')
expect(finalResult.generated).toBe('60000.0000 RUB')
expect(finalResult.capitalists_bonus).toBe('97080.0000 RUB')
expect(finalResult.total).toBe('157080.0000 RUB')
})
// 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`
// 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'
const { expenseHash } = await registerExpense(
blockchain,
'voskhod', // coopname
result1.result_hash, // resultHash
project1.project_hash, // projectHash
tester1, // creator
4, // fund_id (фонд хозяйственных расходов)
expenseAmount,
fakeDocument, // fakeDocument
)
})
it('регистрируем расход на 5000 RUB', async () => {
const expenseAmount = '5000.0000 RUB'
const { expenseHash } = await registerExpense(
blockchain,
'voskhod', // coopname
result1.result_hash, // resultHash
project1.project_hash, // projectHash
tester1, // creator
4, // fund_id (фонд хозяйственных расходов)
expenseAmount,
fakeDocument, // fakeDocument
)
})
/// ____________
it('завершаем цикл и стартуем распределение', async () => {
const data: CapitalContract.Actions.StartDistribution.IStart = {
coopname: 'voskhod',
application: 'voskhod',
result_hash: result1.result_hash,
}
const result = await blockchain.api.transact(
{
actions: [
{
account: CapitalContract.contractName.production,
name: CapitalContract.Actions.StartDistribution.actionName,
authorization: [
{
actor: 'voskhod',
permission: 'active',
},
],
data,
},
],
},
{
blocksBehind: 3,
expireSeconds: 30,
},
)
getTotalRamUsage(result)
expect(result.transaction_id).toBeDefined()
const blockchainResult = (await blockchain.getTableRows(
CapitalContract.contractName.production,
'voskhod',
'results',
1,
result1.result_hash,
result1.result_hash,
2,
'sha256',
))[0]
expect(blockchainResult).toBeDefined()
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('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(
{
actions: [
{
account: CapitalContract.contractName.production,
name: CapitalContract.Actions.CreateClaim.actionName,
authorization: [
{
actor: 'voskhod',
permission: 'active',
},
],
data,
},
],
},
{
blocksBehind: 3,
expireSeconds: 30,
},
)
getTotalRamUsage(result)
expect(result.transaction_id).toBeDefined()
const blockchainResult = (await blockchain.getTableRows(
CapitalContract.contractName.production,
'voskhod',
'results',
1,
result1.result_hash,
result1.result_hash,
2,
'sha256',
))[0]
expect(blockchainResult).toBeDefined()
console.log('blockchainResult: ', blockchainResult)
})
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(
{
actions: [
{
account: CapitalContract.contractName.production,
name: CapitalContract.Actions.CreateClaim.actionName,
authorization: [
{
actor: 'voskhod',
permission: 'active',
},
],
data,
},
],
},
{
blocksBehind: 3,
expireSeconds: 30,
},
)
getTotalRamUsage(result)
expect(result.transaction_id).toBeDefined()
const blockchainResult = (await blockchain.getTableRows(
CapitalContract.contractName.production,
'voskhod',
'results',
1,
result1.result_hash,
result1.result_hash,
2,
'sha256',
))[0]
expect(blockchainResult).toBeDefined()
console.log('blockchainResult: ', blockchainResult)
})
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 {
await sleep(1000)
await blockchain.api.transact(
{
actions: [
{
account: CapitalContract.contractName.production,
name: CapitalContract.Actions.CreateClaim.actionName,
authorization: [
{
actor: 'voskhod',
permission: 'active',
},
],
data,
},
],
},
{
blocksBehind: 3,
expireSeconds: 30,
},
)
throw new Error('Ожидалась ошибка, но транзакция прошла успешно')
}
catch (error: any) {
const message = error.json?.error?.details?.[0]?.message
expect(message).toMatch(/Клайм уже существует/i)
}
})
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(
{
actions: [
{
account: CapitalContract.contractName.production,
name: CapitalContract.Actions.CreateClaim.actionName,
authorization: [
{
actor: 'voskhod',
permission: 'active',
},
],
data,
},
],
},
{
blocksBehind: 3,
expireSeconds: 30,
},
)
getTotalRamUsage(result)
expect(result.transaction_id).toBeDefined()
const blockchainResult = (await blockchain.getTableRows(
CapitalContract.contractName.production,
'voskhod',
'results',
1,
result1.result_hash,
result1.result_hash,
2,
'sha256',
))[0]
expect(blockchainResult).toBeDefined()
console.log('investorResult: ', blockchainResult)
})
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 {
await sleep(1000)
await blockchain.api.transact(
{
actions: [
{
account: CapitalContract.contractName.production,
name: CapitalContract.Actions.CreateClaim.actionName,
authorization: [
{
actor: 'voskhod',
permission: 'active',
},
],
data,
},
],
},
{
blocksBehind: 3,
expireSeconds: 30,
},
)
throw new Error('Ожидалась ошибка, но транзакция прошла успешно')
}
catch (error: any) {
const message = error.json?.error?.details?.[0]?.message
expect(message).toMatch(/Клайм уже существует/i)
}
})
})
@@ -0,0 +1,106 @@
import { expect } from 'vitest'
import { CapitalContract } from 'cooptypes'
import { getTotalRamUsage } from '../../utils/getTotalRamUsage'
export async function allocateFundsToResult(
blockchain: any,
coopname: string,
projectHash: string,
resultHash: string,
amount: string,
) {
console.log(`\n🔹 Начало финансирования результата: ${resultHash}, сумма: ${amount}`)
// Получение текущих данных перед финансированием
const prevResult = (await blockchain.getTableRows(
CapitalContract.contractName.production,
coopname,
'results',
1,
resultHash,
resultHash,
2,
'sha256',
))[0] || { available: '0.0000 RUB' }
const prevProject = (await blockchain.getTableRows(
CapitalContract.contractName.production,
coopname,
'projects',
1,
projectHash,
projectHash,
3,
'sha256',
))[0] || { available: '0.0000 RUB' }
console.log('📊 Балансы до финансирования:')
console.log('▶ Результат:', prevResult)
console.log('▶ Проект:', prevProject)
// Отправка транзакции финансирования
const allocateData: CapitalContract.Actions.Allocate.IAllocate = {
coopname,
application: coopname,
project_hash: projectHash,
result_hash: resultHash,
amount,
}
console.log(`\n🚀 Отправка транзакции Allocate для результата ${resultHash}`)
const allocateResult = await blockchain.api.transact(
{
actions: [
{
account: CapitalContract.contractName.production,
name: CapitalContract.Actions.Allocate.actionName,
authorization: [{ actor: coopname, permission: 'active' }],
data: allocateData,
},
],
},
{
blocksBehind: 3,
expireSeconds: 30,
},
)
getTotalRamUsage(allocateResult)
expect(allocateResult.transaction_id).toBeDefined()
// Получение обновленных данных
const updatedResult = (await blockchain.getTableRows(
CapitalContract.contractName.production,
coopname,
'results',
1,
resultHash,
resultHash,
2,
'sha256',
))[0]
const updatedProject = (await blockchain.getTableRows(
CapitalContract.contractName.production,
coopname,
'projects',
1,
projectHash,
projectHash,
3,
'sha256',
))[0]
console.log('\n📊 Балансы после финансирования:')
console.log('▶ Результат:', updatedResult)
console.log('▶ Проект:', updatedProject)
// Проверка изменения available
expect(parseFloat(updatedResult.available)).toBe(parseFloat(prevResult.available) + parseFloat(amount))
expect(parseFloat(updatedProject.available)).toBe(parseFloat(prevProject.available) - parseFloat(amount))
expect(parseFloat(updatedProject.allocated)).toBe(parseFloat(prevProject.allocated) + parseFloat(amount))
console.log(`\n✅ Финансирование ${amount} завершено успешно!`)
return { transactionId: allocateResult.transaction_id }
}
@@ -0,0 +1,283 @@
import { expect } from 'vitest'
import { CapitalContract, SovietContract } from 'cooptypes'
import { getTotalRamUsage } from '../../utils/getTotalRamUsage'
import { generateRandomSHA256 } from '../../utils/randomHash'
import { fakeDocument } from '../soviet/fakeDocument'
import { processDecision } from '../soviet/processDecision'
import { ratePerHour } from './consts'
export async function commitToResult(
blockchain: any,
coopname: string,
resultHash: string,
projectHash: string,
creator: string,
spendHours: number,
) {
const commitHash = generateRandomSHA256()
const totalSpended = `${(spendHours * parseFloat(ratePerHour)).toFixed(4)} RUB`
console.log(`\n🔹 Начало коммита: ${commitHash}, часы: ${spendHours}, сумма: ${totalSpended}`)
// Получение текущих данных перед коммитом
const prevResult = (await blockchain.getTableRows(
CapitalContract.contractName.production,
coopname,
'results',
1,
resultHash,
resultHash,
2,
'sha256',
))[0] || { spended: '0.0000 RUB', commits_count: 0 }
const prevProject = (await blockchain.getTableRows(
CapitalContract.contractName.production,
coopname,
'projects',
1,
projectHash,
projectHash,
3,
'sha256',
))[0] || { spended: '0.0000 RUB' }
const prevContributor = (await blockchain.getTableRows(
CapitalContract.contractName.production,
coopname,
'contributors',
1,
creator,
creator,
2,
'i64',
))[0] || { contributed_hours: 0, available: '0.0000 RUB' }
console.log('📊 Балансы до коммита:')
console.log('▶ Результат:', prevResult)
console.log('▶ Проект:', prevProject)
console.log('▶ Контрибьютор:', prevContributor)
// Создание коммита
const commitData: CapitalContract.Actions.CreateCommit.ICommit = {
coopname,
application: coopname,
result_hash: resultHash,
commit_hash: commitHash,
contributed_hours: spendHours,
username: creator,
}
console.log(`\n🚀 Отправка транзакции CreateCommit для результата ${resultHash}`)
const createCommitResult = await blockchain.api.transact(
{
actions: [
{
account: CapitalContract.contractName.production,
name: CapitalContract.Actions.CreateCommit.actionName,
authorization: [{ actor: coopname, permission: 'active' }],
data: commitData,
},
],
},
{
blocksBehind: 3,
expireSeconds: 30,
},
)
getTotalRamUsage(createCommitResult)
expect(createCommitResult.transaction_id).toBeDefined()
// Проверка созданного коммита
let blockchainCommit = (await blockchain.getTableRows(
CapitalContract.contractName.production,
coopname,
'commits',
1,
commitHash,
commitHash,
3,
'sha256',
))[0]
console.log('🔍 Коммит после создания:', blockchainCommit)
expect(blockchainCommit).toBeDefined()
expect(blockchainCommit.commit_hash).toBe(commitHash)
expect(blockchainCommit.spended).toBe(totalSpended)
expect(blockchainCommit.status).toBe('created')
// Утверждение коммита
const approveCommitData: SovietContract.Actions.Approves.ConfirmApprove.IConfirmApprove = {
coopname,
approval_hash: commitHash,
approved_document: fakeDocument,
}
console.log(`\n✅ Подтверждение коммита ${commitHash}`)
const approveCommitResult = await blockchain.api.transact(
{
actions: [
{
account: SovietContract.contractName.production,
name: SovietContract.Actions.Approves.ConfirmApprove.actionName,
authorization: [{ actor: coopname, permission: 'active' }],
data: approveCommitData,
},
],
},
{
blocksBehind: 3,
expireSeconds: 30,
},
)
getTotalRamUsage(approveCommitResult)
expect(approveCommitResult.transaction_id).toBeDefined()
// Проверка утвержденного коммита
blockchainCommit = (await blockchain.getTableRows(
CapitalContract.contractName.production,
coopname,
'commits',
1,
commitHash,
commitHash,
3,
'sha256',
))[0]
// Коммит удаляем после утверждения
expect(blockchainCommit).toBeUndefined()
// // Получение всех решений и выполнение последнего
// 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)
// {
// // Утверждение коммита
// 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,
// },
// )
// getTotalRamUsage(act1Result)
// expect(act1Result.transaction_id).toBeDefined()
// }
// {
// // Утверждение коммита
// 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,
// },
// )
// getTotalRamUsage(act2Result)
// expect(act2Result.transaction_id).toBeDefined()
// }
// Проверка результата после утверждения коммита
const finalResult = (await blockchain.getTableRows(
CapitalContract.contractName.production,
coopname,
'results',
1,
resultHash,
resultHash,
2,
'sha256',
))[0]
const finalProject = (await blockchain.getTableRows(
CapitalContract.contractName.production,
coopname,
'projects',
1,
projectHash,
projectHash,
3,
'sha256',
))[0]
const finalContributor = (await blockchain.getTableRows(
CapitalContract.contractName.production,
coopname,
'contributors',
1,
creator,
creator,
2,
'i64',
))[0]
console.log('\n📊 Балансы после утверждения коммита:')
console.log('▶ Результат:', finalResult)
console.log('▶ Проект:', finalProject)
console.log('▶ Контрибьютор:', finalContributor)
// 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)
// expect(parseFloat(finalContributor.available)).toBe(parseFloat(prevContributor.available) + parseFloat(totalSpended))
console.log(`\n✅ Коммит ${commitHash} завершен успешно!`)
return {
commitHash,
transactionId: approveCommitResult.transaction_id,
finalResult,
finalProject,
finalContributor,
}
}
@@ -0,0 +1,6 @@
export const sourceProgramId = 3
export const capitalProgramId = 4
export const walletProgramId = 1
export const ratePerHour = '1000.0000 RUB'
export const sourceProgramName = 'source'
export const capitalProgramName = 'capital'
@@ -0,0 +1,213 @@
import { expect } from 'vitest'
import { CapitalContract, SovietContract } from 'cooptypes'
import { getTotalRamUsage } from '../../utils/getTotalRamUsage'
import { generateRandomSHA256 } from '../../utils/randomHash'
import { getCoopProgramWallet, getUserProgramWallet } from '../wallet/walletUtils'
import { processDecision } from '../soviet/processDecision'
import { capitalProgramId, sourceProgramId } from './consts'
export async function investInProject(
blockchain: any,
coopname: string,
investor: string,
projectHash: string,
investAmount: string,
fakeDocument: any,
) {
const investHash = generateRandomSHA256()
console.log(`\n🔹 Начало инвестиции: ${investHash}`)
// Получение текущих данных перед инвестицией
const prevContributor = (await blockchain.getTableRows(
CapitalContract.contractName.production,
coopname,
'contributors',
1,
investor,
investor,
2,
'i64',
))[0] || { invested: '0.0000 RUB' }
const prevProject = (await blockchain.getTableRows(
CapitalContract.contractName.production,
coopname,
'projects',
1,
projectHash,
projectHash,
3,
'sha256',
))[0] || { invested: '0.0000 RUB', available: '0.0000 RUB' }
const prevUserWallet = await getUserProgramWallet(blockchain, coopname, investor, capitalProgramId) || { blocked: '0.0000 RUB' }
const prevProgramWallet = await getCoopProgramWallet(blockchain, coopname, capitalProgramId) || { blocked: '0.0000 RUB', share_contributions: '0.0000 RUB' }
console.log('📊 Балансы до инвестиции:')
console.log('▶ Контрибьютор:', prevContributor)
console.log('▶ Проект:', prevProject)
console.log('▶ Кошелек пользователя:', prevUserWallet)
console.log('▶ Кошелек программы:', prevProgramWallet)
// Создание инвестиции
const createInvestData: CapitalContract.Actions.CreateInvest.ICreateInvest = {
coopname,
application: coopname,
project_hash: projectHash,
username: investor,
invest_hash: investHash,
amount: investAmount,
statement: fakeDocument,
}
console.log(`\n🚀 Отправка транзакции CreateInvest для ${investor} на сумму ${investAmount}`)
const createInvestResult = await blockchain.api.transact(
{
actions: [
{
account: CapitalContract.contractName.production,
name: CapitalContract.Actions.CreateInvest.actionName,
authorization: [{ actor: coopname, permission: 'active' }],
data: createInvestData,
},
],
},
{
blocksBehind: 3,
expireSeconds: 30,
},
)
getTotalRamUsage(createInvestResult)
expect(createInvestResult.transaction_id).toBeDefined()
let blockchainInvest = (await blockchain.getTableRows(
CapitalContract.contractName.production,
coopname,
'invests',
1,
investHash,
investHash,
2,
'sha256',
))[0]
console.log('🔍 Инвестиция в блокчейне:', blockchainInvest)
expect(blockchainInvest).toBeDefined()
expect(blockchainInvest.status).toBe('created')
// Утверждение инвестиции
const approveInvestData: CapitalContract.Actions.ApproveInvest.IApproveInvest = {
coopname,
application: coopname,
approver: 'ant',
invest_hash: investHash,
approved_statement: fakeDocument,
}
console.log(`\n✅ Подтверждение инвестиции ${investHash}`)
const approveInvestResult = await blockchain.api.transact(
{
actions: [
{
account: CapitalContract.contractName.production,
name: CapitalContract.Actions.ApproveInvest.actionName,
authorization: [{ actor: coopname, permission: 'active' }],
data: approveInvestData,
},
],
},
{
blocksBehind: 3,
expireSeconds: 30,
},
)
getTotalRamUsage(approveInvestResult)
expect(approveInvestResult.transaction_id).toBeDefined()
blockchainInvest = (await blockchain.getTableRows(
CapitalContract.contractName.production,
coopname,
'invests',
1,
investHash,
investHash,
2,
'sha256',
))[0]
console.log('🔍 Инвестиция после утверждения:', blockchainInvest)
expect(blockchainInvest).toBeDefined()
expect(blockchainInvest.status).toBe('approved')
// Получение всех решений и выполнение последнего
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)
blockchainInvest = (await blockchain.getTableRows(
CapitalContract.contractName.production,
coopname,
'invests',
1,
investHash,
investHash,
2,
'sha256',
))[0]
console.log('📌 Инвестиция после завершения:', blockchainInvest)
expect(blockchainInvest).toBeUndefined()
// Получение новых данных после инвестиции
const contributor = (await blockchain.getTableRows(
CapitalContract.contractName.production,
coopname,
'contributors',
1,
investor,
investor,
2,
'i64',
))[0]
const project = (await blockchain.getTableRows(
CapitalContract.contractName.production,
coopname,
'projects',
1,
projectHash,
projectHash,
3,
'sha256',
))[0]
const userWallet = await getUserProgramWallet(blockchain, coopname, investor, capitalProgramId)
const programWallet = await getCoopProgramWallet(blockchain, coopname, capitalProgramId)
console.log('\n📊 Балансы после инвестиции:')
console.log('▶ Контрибьютор:', contributor)
console.log('▶ Проект:', project)
console.log('▶ Кошелек пользователя:', userWallet)
console.log('▶ Кошелек программы:', programWallet)
// Проверка изменения балансов
expect(parseFloat(contributor.invested)).toBe(parseFloat(prevContributor.invested) + parseFloat(investAmount))
expect(parseFloat(project.invested)).toBe(parseFloat(prevProject.invested) + parseFloat(investAmount))
expect(parseFloat(project.available)).toBe(parseFloat(prevProject.available) + parseFloat(investAmount))
expect(parseFloat(userWallet.blocked)).toBe(parseFloat(prevUserWallet.blocked) + parseFloat(investAmount))
expect(parseFloat(programWallet.blocked)).toBe(parseFloat(prevProgramWallet.blocked) + parseFloat(investAmount))
expect(parseFloat(programWallet.share_contributions)).toBe(parseFloat(prevProgramWallet.share_contributions) + parseFloat(investAmount))
console.log(`\n✅ Инвестирование на ${investAmount} завершено успешно!`)
return { investHash, transactionId: approveInvestResult.transaction_id }
}
@@ -0,0 +1,104 @@
import { expect } from 'vitest'
import { CapitalContract } from 'cooptypes'
import { getTotalRamUsage } from '../../utils/getTotalRamUsage'
import { fakeDocument } from '../soviet/fakeDocument'
export async function registerAndApproveUHDContract(
blockchain: any,
username: string,
project_hash: string,
) {
const info = await blockchain.getInfo()
console.log(`Регистрация договора УХД для ${username}, блок: ${info.head_block_time}`)
// Регистрация контрибьютора
const registerData: CapitalContract.Actions.RegisterContributor.IRegisterContributor = {
coopname: 'voskhod',
application: 'voskhod',
project_hash,
username,
created_at: info.head_block_time,
agreement: fakeDocument,
convert_percent: 0,
rate_per_hour: '1000.0000 RUB',
}
const registerResult = await blockchain.api.transact(
{
actions: [
{
account: CapitalContract.contractName.production,
name: CapitalContract.Actions.RegisterContributor.actionName,
authorization: [{ actor: 'voskhod', permission: 'active' }],
data: registerData,
},
],
},
{
blocksBehind: 3,
expireSeconds: 30,
},
)
getTotalRamUsage(registerResult)
expect(registerResult.transaction_id).toBeDefined()
let contributor = (await blockchain.getTableRows(
CapitalContract.contractName.production,
'voskhod',
'contributors',
1,
username,
username,
2,
'i64',
))[0]
console.log(`Контрибьютор ${username} после регистрации: `, contributor)
expect(contributor).toBeDefined()
// Утверждение регистрации
const approveData: CapitalContract.Actions.ApproveRegister.IApproveRegister = {
coopname: 'voskhod',
application: 'voskhod',
project_hash,
username,
approver: 'ant',
approved_agreement: fakeDocument,
}
const approveResult = await blockchain.api.transact(
{
actions: [
{
account: CapitalContract.contractName.production,
name: CapitalContract.Actions.ApproveRegister.actionName,
authorization: [{ actor: 'voskhod', permission: 'active' }],
data: approveData,
},
],
},
{
blocksBehind: 3,
expireSeconds: 30,
},
)
getTotalRamUsage(approveResult)
expect(approveResult.transaction_id).toBeDefined()
contributor = (await blockchain.getTableRows(
CapitalContract.contractName.production,
'voskhod',
'contributors',
1,
username,
username,
2,
'i64',
))[0]
console.log(`Контрибьютор ${username} после утверждения: `, contributor)
expect(contributor).toBeDefined()
expect(contributor.status).toBe('approved')
return contributor
}
@@ -0,0 +1,3 @@
export function registerContributor() {
}
@@ -0,0 +1,272 @@
import { expect } from 'vitest'
import { CapitalContract, GatewayContract, SovietContract } from 'cooptypes'
import { getTotalRamUsage } from '../../utils/getTotalRamUsage'
import { generateRandomSHA256 } from '../../utils/randomHash'
import { processDecision } from '../soviet/processDecision'
export async function registerExpense(
blockchain: any,
coopname: string,
resultHash: string,
projectHash: string,
creator: string,
fundId: number,
expenseAmount: string,
fakeDocument: any,
) {
const expenseHash = generateRandomSHA256()
console.log(`\n🔹 Начало регистрации расхода: ${expenseHash}, сумма: ${expenseAmount}`)
// Получаем текущие балансы
const prevResult = (await blockchain.getTableRows(
CapitalContract.contractName.production,
coopname,
'results',
1,
resultHash,
resultHash,
2,
'sha256',
))[0] || { available: '0.0000 RUB', expensed: '0.0000 RUB' }
const prevProject = (await blockchain.getTableRows(
CapitalContract.contractName.production,
coopname,
'projects',
1,
projectHash,
projectHash,
3,
'sha256',
))[0] || { expensed: '0.0000 RUB' }
const prevContributor = (await blockchain.getTableRows(
CapitalContract.contractName.production,
coopname,
'contributors',
1,
creator,
creator,
2,
'i64',
))[0] || { expensed: '0.0000 RUB' }
console.log('📊 Балансы до расхода:')
console.log('▶ Результат:', prevResult)
console.log('▶ Проект:', prevProject)
console.log('▶ Контрибьютор:', prevContributor)
// Создание расхода
const createExpenseData: CapitalContract.Actions.CreateExpense.ICreateExpense = {
coopname,
application: coopname,
expense_hash: expenseHash,
result_hash: resultHash,
creator,
fund_id: fundId,
amount: expenseAmount,
description: 'Купил подписку на то-сё',
statement: fakeDocument,
}
console.log(`\n🚀 Отправка транзакции CreateExpense для расхода ${expenseHash}`)
const createExpenseResult = await blockchain.api.transact(
{
actions: [
{
account: CapitalContract.contractName.production,
name: CapitalContract.Actions.CreateExpense.actionName,
authorization: [{ actor: coopname, permission: 'active' }],
data: createExpenseData,
},
],
},
{ blocksBehind: 3, expireSeconds: 30 },
)
getTotalRamUsage(createExpenseResult)
expect(createExpenseResult.transaction_id).toBeDefined()
let blockchainExpense = (await blockchain.getTableRows(
CapitalContract.contractName.production,
coopname,
'expenses',
1,
expenseHash,
expenseHash,
3,
'sha256',
))[0]
console.log('🔍 Расход после создания:', blockchainExpense)
expect(blockchainExpense).toBeDefined()
expect(blockchainExpense.status).toBe('created')
// Подтверждение расхода
const approveExpenseData: CapitalContract.Actions.ApproveExpense.IApproveExpense = {
coopname,
application: coopname,
approver: 'ant',
expense_hash: expenseHash,
approved_statement: fakeDocument,
}
console.log(`\n✅ Подтверждение расхода ${expenseHash}`)
const approveExpenseResult = await blockchain.api.transact(
{
actions: [
{
account: CapitalContract.contractName.production,
name: CapitalContract.Actions.ApproveExpense.actionName,
authorization: [{ actor: coopname, permission: 'active' }],
data: approveExpenseData,
},
],
},
{ blocksBehind: 3, expireSeconds: 30 },
)
getTotalRamUsage(approveExpenseResult)
expect(approveExpenseResult.transaction_id).toBeDefined()
blockchainExpense = (await blockchain.getTableRows(
CapitalContract.contractName.production,
coopname,
'expenses',
1,
expenseHash,
expenseHash,
3,
'sha256',
))[0]
console.log('🔍 Расход после подтверждения:', blockchainExpense)
expect(blockchainExpense).toBeDefined()
expect(blockchainExpense.status).toBe('approved')
// Получение решений и выполнение последнего
const decisions = await blockchain.getTableRows(
SovietContract.contractName.production,
coopname,
'decisions',
1000,
)
const lastDecision = decisions[decisions.length - 1]
console.log(`\n📜 Выполнение последнего решения:`, lastDecision)
await processDecision(blockchain, lastDecision.id)
blockchainExpense = (await blockchain.getTableRows(
CapitalContract.contractName.production,
coopname,
'expenses',
1,
expenseHash,
expenseHash,
3,
'sha256',
))[0]
console.log('🔍 Расход после авторизации:', blockchainExpense)
expect(blockchainExpense).toBeDefined()
expect(blockchainExpense.status).toBe('authorized')
const blockchainWithdraw = (await blockchain.getTableRows(
GatewayContract.contractName.production,
coopname,
GatewayContract.Tables.Outcomes.tableName,
1,
expenseHash,
expenseHash,
2,
'sha256',
))[0]
console.log('🔍 Вывод средств:', blockchainWithdraw)
expect(blockchainWithdraw).toBeDefined()
expect(blockchainWithdraw.outcome_hash).toBe(expenseHash)
expect(blockchainWithdraw.quantity).toBe(expenseAmount)
expect(blockchainWithdraw.status).toBe('pending')
// Завершение вывода
const completeWithdrawData: GatewayContract.Actions.CompleteOutcome.ICompleteOutcome = {
coopname,
outcome_hash: expenseHash,
}
console.log(`\n✅ Завершение вывода ${expenseHash}`)
const completeWithdrawResult = await blockchain.api.transact(
{
actions: [
{
account: GatewayContract.contractName.production,
name: GatewayContract.Actions.CompleteOutcome.actionName,
authorization: [{ actor: coopname, permission: 'active' }],
data: completeWithdrawData,
},
],
},
{ blocksBehind: 3, expireSeconds: 30 },
)
getTotalRamUsage(completeWithdrawResult)
expect(completeWithdrawResult.transaction_id).toBeDefined()
const finalProject = (await blockchain.getTableRows(
CapitalContract.contractName.production,
coopname,
'projects',
1,
projectHash,
projectHash,
3,
'sha256',
))[0]
console.log('\n📊 Проект после расхода:', finalProject)
expect(finalProject).toBeDefined()
expect(finalProject.expensed).toBe(
`${(parseFloat(prevProject.expensed) + parseFloat(expenseAmount)).toFixed(4)} RUB`,
)
const finalResult = (await blockchain.getTableRows(
CapitalContract.contractName.production,
coopname,
'results',
1,
resultHash,
resultHash,
2,
'sha256',
))[0]
console.log('\n📌 Результат после расхода:', finalResult)
expect(finalResult).toBeDefined()
expect(finalResult.available).toBe(
`${(parseFloat(prevResult.available) - parseFloat(expenseAmount)).toFixed(4)} RUB`,
)
expect(finalResult.expensed).toBe(
`${(parseFloat(prevResult.expensed) + parseFloat(expenseAmount)).toFixed(4)} RUB`,
)
const finalContributor = (await blockchain.getTableRows(
CapitalContract.contractName.production,
coopname,
'contributors',
1,
creator,
creator,
2,
'i64',
))[0]
console.log(`\n👤 Контрибьютор ${creator} после расхода:`, finalContributor)
expect(finalContributor).toBeDefined()
expect(finalContributor.expensed).toBe(
`${(parseFloat(prevContributor.expensed) + parseFloat(expenseAmount)).toFixed(4)} RUB`,
)
console.log(`\n✅ Расход ${expenseHash} успешно завершен!`)
return { expenseHash, transactionId: completeWithdrawResult.transaction_id, finalProject, finalResult, finalContributor }
}
@@ -0,0 +1,28 @@
import { expect } from 'vitest'
import { signAgreement } from '../soviet/signAgreement'
import { getCoopProgramWallet, getUserProgramWallet } from '../wallet/walletUtils'
import { capitalProgramName, sourceProgramId } from './consts'
export async function signCapitalAgreement(
blockchain: any,
coopname: string,
username: string,
fakeDocument: any,
) {
const txId = await signAgreement(blockchain, coopname, username, capitalProgramName, fakeDocument)
const wallet = await getUserProgramWallet(blockchain, coopname, username, sourceProgramId)
expect(wallet).toEqual(expect.objectContaining({
coopname,
username,
available: expect.any(String),
blocked: expect.any(String),
program_id: sourceProgramId,
membership_contribution: expect.any(String),
}))
const program = await getCoopProgramWallet(blockchain, coopname, sourceProgramId)
return { wallet, program, txId }
}
@@ -0,0 +1,28 @@
import { expect } from 'vitest'
import { signAgreement } from '../soviet/signAgreement'
import { getCoopProgramWallet, getUserProgramWallet } from '../wallet/walletUtils'
import { sourceProgramId, sourceProgramName } from './consts'
export async function signGenerationAgreement(
blockchain: any,
coopname: string,
username: string,
fakeDocument: any,
) {
const txId = await signAgreement(blockchain, coopname, username, sourceProgramName, fakeDocument)
const wallet = await getUserProgramWallet(blockchain, coopname, username, sourceProgramId)
expect(wallet).toEqual(expect.objectContaining({
coopname,
username,
available: expect.any(String),
blocked: expect.any(String),
program_id: sourceProgramId,
membership_contribution: expect.any(String),
}))
const program = await getCoopProgramWallet(blockchain, coopname, sourceProgramId)
return { wallet, program, txId }
}
@@ -0,0 +1,209 @@
import { expect } from 'vitest'
import { CapitalContract, SovietContract } from 'cooptypes'
import { getTotalRamUsage } from '../../utils/getTotalRamUsage'
import { generateRandomSHA256 } from '../../utils/randomHash'
import { getCoopProgramWallet, getUserProgramWallet } from '../wallet/walletUtils'
import { processDecision } from '../soviet/processDecision'
import { capitalProgramId, walletProgramId } from './consts'
export async function withdrawContribution(
blockchain: any,
coopname: string,
username: string,
resultHash: string,
projectHash: string, // Добавлен projectHash для проверки spend
commitHashes: string[],
withdrawAmount: string,
fakeDocument: any,
) {
const withdrawHash = generateRandomSHA256()
console.log(`\n🔹 Начало возврата: ${withdrawHash}, сумма: ${withdrawAmount}`)
// Получение текущих данных перед возвратом
const prevCooFundUserWallet = await getUserProgramWallet(blockchain, coopname, username, capitalProgramId)
const prevCooFundProgramWallet = await getCoopProgramWallet(blockchain, coopname, capitalProgramId)
const prevUserWallet = await getUserProgramWallet(blockchain, coopname, username, walletProgramId)
const prevProgramWallet = await getCoopProgramWallet(blockchain, coopname, walletProgramId)
const prevProject = (await blockchain.getTableRows(
CapitalContract.contractName.production,
coopname,
'projects',
1,
projectHash,
projectHash,
3,
'sha256',
))[0] || { spend: '0.0000 RUB' }
console.log('📊 Балансы до возврата:')
console.log('▶ cooFundUserWallet:', prevCooFundUserWallet)
console.log('▶ cooFundProgramWallet:', prevCooFundProgramWallet)
console.log('▶ userWallet:', prevUserWallet)
console.log('▶ programWallet:', prevProgramWallet)
console.log('▶ Проект:', prevProject)
// Создание заявления на возврат
const createWithdrawData: CapitalContract.Actions.WithdrawResult.IWithdrawFromResult = {
coopname,
application: coopname,
username,
result_hash: resultHash,
withdraw_hash: withdrawHash,
return_statement: fakeDocument,
amount: withdrawAmount,
}
console.log(`\n🚀 Отправка транзакции CreateWithdraw для ${username} на сумму ${withdrawAmount}`)
const createWithdrawResult = await blockchain.api.transact(
{
actions: [
{
account: CapitalContract.contractName.production,
name: CapitalContract.Actions.WithdrawResult.actionName,
authorization: [{ actor: coopname, permission: 'active' }],
data: createWithdrawData,
},
],
},
{
blocksBehind: 3,
expireSeconds: 30,
},
)
getTotalRamUsage(createWithdrawResult)
expect(createWithdrawResult.transaction_id).toBeDefined()
let blockchainWithdraw = (await blockchain.getTableRows(
CapitalContract.contractName.production,
coopname,
CapitalContract.Tables.ResultWithdraws.tableName,
1,
withdrawHash,
withdrawHash,
2,
'sha256',
))[0]
console.log('🔍 Возврат в блокчейне:', blockchainWithdraw)
expect(blockchainWithdraw).toBeDefined()
expect(blockchainWithdraw.status).toBe('created')
expect(blockchainWithdraw.amount).toBe(withdrawAmount)
// Подтверждение возврата
const approveWithdrawData: CapitalContract.Actions.ApproveWithdrawResult.IApproveWithdrawResult = {
coopname,
application: coopname,
approver: 'ant',
withdraw_hash: withdrawHash,
approved_return_statement: fakeDocument,
}
console.log(`\n✅ Подтверждение возврата ${withdrawHash}`)
const approveWithdrawResult = await blockchain.api.transact(
{
actions: [
{
account: CapitalContract.contractName.production,
name: CapitalContract.Actions.ApproveWithdrawResult.actionName,
authorization: [{ actor: coopname, permission: 'active' }],
data: approveWithdrawData,
},
],
},
{
blocksBehind: 3,
expireSeconds: 30,
},
)
getTotalRamUsage(approveWithdrawResult)
expect(approveWithdrawResult.transaction_id).toBeDefined()
blockchainWithdraw = (await blockchain.getTableRows(
CapitalContract.contractName.production,
coopname,
CapitalContract.Tables.ResultWithdraws.tableName,
1,
withdrawHash,
withdrawHash,
2,
'sha256',
))[0]
console.log('🔍 Возврат после подтверждения:', blockchainWithdraw)
expect(blockchainWithdraw).toBeDefined()
expect(blockchainWithdraw.status).toBe('approved')
// Получение всех решений и выполнение последнего
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)
blockchainWithdraw = (await blockchain.getTableRows(
CapitalContract.contractName.production,
coopname,
CapitalContract.Tables.ResultWithdraws.tableName,
1,
withdrawHash,
withdrawHash,
2,
'sha256',
))[0]
console.log('📌 Возврат после завершения:', blockchainWithdraw)
expect(blockchainWithdraw).toBeUndefined()
// Получение новых данных после возврата
const cooFundUserWallet = await getUserProgramWallet(blockchain, coopname, username, capitalProgramId)
const cooFundProgramWallet = await getCoopProgramWallet(blockchain, coopname, capitalProgramId)
const userWallet = await getUserProgramWallet(blockchain, coopname, username, walletProgramId)
const programWallet = await getCoopProgramWallet(blockchain, coopname, walletProgramId)
const finalProject = (await blockchain.getTableRows(
CapitalContract.contractName.production,
coopname,
'projects',
1,
projectHash,
projectHash,
3,
'sha256',
))[0]
console.log('\n📊 Балансы после возврата:')
console.log('▶ cooFundUserWallet:', cooFundUserWallet)
console.log('▶ cooFundProgramWallet:', cooFundProgramWallet)
console.log('▶ userWallet:', userWallet)
console.log('▶ programWallet:', programWallet)
console.log('▶ Проект:', finalProject)
// Проверка изменений балансов
expect(parseFloat(cooFundUserWallet.available)).toBe(parseFloat(prevCooFundUserWallet.available))
expect(parseFloat(cooFundUserWallet.blocked)).toBe(parseFloat(prevCooFundUserWallet.blocked))
expect(parseFloat(cooFundProgramWallet.available)).toBe(parseFloat(prevCooFundProgramWallet.available))
expect(parseFloat(cooFundProgramWallet.blocked)).toBe(parseFloat(prevCooFundProgramWallet.blocked))
expect(parseFloat(userWallet.available)).toBe(parseFloat(prevUserWallet.available) + parseFloat(withdrawAmount))
expect(parseFloat(programWallet.available)).toBe(parseFloat(prevProgramWallet.available) + parseFloat(withdrawAmount))
expect(parseFloat(userWallet.blocked)).toBe(parseFloat(prevUserWallet.blocked))
expect(parseFloat(programWallet.blocked)).toBe(parseFloat(prevProgramWallet.blocked))
// Проверка изменения spend в проекте
expect(parseFloat(finalProject.withdrawed)).toBe(parseFloat(prevProject.withdrawed) + parseFloat(withdrawAmount))
expect(parseFloat(finalProject.spend)).toBe(parseFloat(prevProject.spend))
console.log(`\n✅ Возврат на ${withdrawAmount} завершен успешно!`)
return { withdrawHash, transactionId: approveWithdrawResult.transaction_id, finalProject }
}
@@ -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
}
@@ -0,0 +1,6 @@
export const fakeDocument = {
hash: '157192B276DA23CC84AB078FC8755C051C5F0430BF4802E55718221E6B76C777',
public_key: 'PUB_K1_5JhMfxbsNebajHcTEK8yC9uNN9Dit9hEmzE8ri8yMhhzzEtUA4',
signature: 'SIG_K1_KmKWPBC8dZGGDGhbKEoZEzPr3h5crRrR2uLdGRF5DJbeibY1MY1bZ9sPwHsgmPfiGFv9psfoCVsXFh9TekcLuvaeuxRKA8',
meta: '{}',
}
@@ -0,0 +1,57 @@
import { SovietContract } from 'cooptypes'
import { expect } from 'vitest'
import { getTotalRamUsage } from '../../utils/getTotalRamUsage'
import { fakeDocument } from './fakeDocument'
export async function processDecision(blockchain: any, decisionId: number) {
const voteData: SovietContract.Actions.Decisions.VoteFor.IVoteForDecision = {
coopname: 'voskhod',
member: 'ant',
decision_id: decisionId,
}
const authData: SovietContract.Actions.Decisions.Authorize.IAuthorize = {
coopname: 'voskhod',
chairman: 'ant',
decision_id: decisionId,
document: fakeDocument,
}
const execData: SovietContract.Actions.Decisions.Exec.IExec = {
executer: 'ant',
coopname: 'voskhod',
decision_id: decisionId,
}
const result = await blockchain.api.transact(
{
actions: [
{
account: SovietContract.contractName.production,
name: SovietContract.Actions.Decisions.VoteFor.actionName,
authorization: [{ actor: 'ant', permission: 'active' }],
data: voteData,
},
{
account: SovietContract.contractName.production,
name: SovietContract.Actions.Decisions.Authorize.actionName,
authorization: [{ actor: 'ant', permission: 'active' }],
data: authData,
},
{
account: SovietContract.contractName.production,
name: SovietContract.Actions.Decisions.Exec.actionName,
authorization: [{ actor: 'ant', permission: 'active' }],
data: execData,
},
],
},
{
blocksBehind: 3,
expireSeconds: 30,
},
)
getTotalRamUsage(result)
expect(result.transaction_id).toBeDefined()
}

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