move contracts inside and make common setup script

This commit is contained in:
Alex Ant
2025-03-11 22:57:08 +05:00
parent 4d72c920c6
commit 2b6b56ace9
343 changed files with 54826 additions and 476 deletions
Vendored
BIN
View File
Binary file not shown.
+26 -7
View File
@@ -1,13 +1,32 @@
# MONOCOOP
# MONO
Моно-репозиторий компонент клиента системы электронного документооборота для потребительских и производственных кооперативов.
Моно-репозиторий компонент системы электронного документооборота для потребительских и производственных кооперативов.
## Инициализация
## Установка
```
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
pnpm install
```
## Конфигурация
```
pnpm setup
```
## Запуск
### Блокчейн и Контракты
```
pnpm boot
```
### Бэкенд
```
pnpm run dev:backend
```
### Фронтенд
```
pnpm run dev:desktop
```
## Лицензия
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=PASSWORD
SERVER_SECRET=SECRET
SERVER_URL=http://127.0.0.1:2998
MONGO_URI=mongodb://127.0.0.1:27017/cooperative
SIMPLE_EXPLORER_API=http://localhost:4000
SKIP_BLOCK_FETCH=TRUE
+12
View File
@@ -0,0 +1,12 @@
.cache
.DS_Store
.idea
*.log
*.tgz
coverage
dist
lib-cov
logs
node_modules
temp
.env
+2
View File
@@ -0,0 +1,2 @@
ignore-workspace-root-check=true
shell-emulator=true
+64
View File
@@ -0,0 +1,64 @@
# Change Log
All notable changes to this project will be documented in this file.
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
## [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 @@
# Загрузчик.
+12
View File
@@ -0,0 +1,12 @@
import { defineBuildConfig } from 'unbuild'
export default defineBuildConfig({
entries: [
'src/index',
],
declaration: true,
clean: true,
rollup: {
emitCJS: true,
},
})
+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
},
},
)
+51
View File
@@ -0,0 +1,51 @@
{
"name": "@coopenomics/boot",
"type": "module",
"version": "0.1.8",
"private": true,
"packageManager": "pnpm@9.0.6",
"description": "",
"author": "Alex Ant <dacom.dark.sun@gmail.com>",
"license": "",
"keywords": [],
"scripts": {
"enter": "./scripts/enter.sh",
"boot": "esno src/docker/boot.ts",
"cli": "esno src/index.ts",
"dev": "esno src/index.ts boot",
"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
File diff suppressed because it is too large Load Diff
+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:8080
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 =
+78
View File
@@ -0,0 +1,78 @@
/* 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(), '../build/contracts/system/contracts/eosio.boot'),
target: 'eosio',
},
{
name: 'eosio.system',
path: path.resolve(process.cwd(), '../build/contracts/system/contracts/eosio.system'),
target: 'eosio',
},
{
name: 'eosio.token',
path: path.resolve(process.cwd(), '../build/contracts/system/contracts/eosio.token'),
target: 'eosio.token',
},
{
name: 'eosio.msig',
path: path.resolve(process.cwd(), '../build/contracts/system/contracts/eosio.msig'),
target: 'eosio.msig',
},
{
name: 'eosio.wrap',
path: path.resolve(process.cwd(), '../build/contracts/system/contracts/eosio.wrap'),
target: 'eosio.wrap',
},
{
name: 'registrator',
path: path.resolve(process.cwd(), '../build/contracts/registrator'),
target: 'registrator',
},
{
name: 'soviet',
path: path.resolve(process.cwd(), '../build/contracts/soviet'),
target: 'soviet',
},
{
name: 'marketplace',
path: path.resolve(process.cwd(), '../build/contracts/marketplace'),
target: 'marketplace',
},
{
name: 'draft',
path: path.resolve(process.cwd(), '../build/contracts/draft'),
target: 'draft',
},
{
name: 'branch',
path: path.resolve(process.cwd(), '../build/contracts/branch'),
target: 'branch',
},
{
name: 'gateway',
path: path.resolve(process.cwd(), '../build/contracts/gateway'),
target: 'gateway',
},
{
name: 'fund',
path: path.resolve(process.cwd(), '../build/contracts/fund'),
target: 'fund',
},
{
name: 'contributor',
path: path.resolve(process.cwd(), '../build/contracts/contributor'),
target: 'contributor',
},
{
name: 'capital',
path: path.resolve(process.cwd(), '../build/contracts/capital'),
target: 'capital',
},
]
+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"
}
+201
View File
@@ -0,0 +1,201 @@
/* 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: '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)
}
+38
View File
@@ -0,0 +1,38 @@
import type { Container } from "dockerode"
import { findContainerByName } from "./find"
import { runContainer } from "./run"
export async function execCommand(command: string[]): Promise<string> {
const container = await runContainer(true)
const exec = await container.exec({
Cmd: command,
AttachStdout: true,
AttachStderr: true,
})
return new Promise((resolve, reject) => {
exec.start({}, (err: any, stream: any) => {
if (err) {
return reject(err)
}
let output = ""
// eslint-disable-next-line node/prefer-global/buffer
stream.on("data", (data: Buffer) => {
output += data.toString()
})
stream.on("end", () => {
output = output.replace(/^\d+\s*/, "")
console.log(output)
resolve(output)
})
stream.on("error", (err: any) => {
reject(err)
})
})
})
}
+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
}
+26
View File
@@ -0,0 +1,26 @@
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)
}
// eslint-disable-next-line unused-imports/no-unused-vars
catch (error: any) {
// console.error('Error:', error)
await sleep(1000)
return check() // Повторный вызов функции
}
}
return check()
}
+32
View File
@@ -0,0 +1,32 @@
import { promises as fs } from 'node:fs'
import * as path from 'node:path'
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)
}
}
+65
View File
@@ -0,0 +1,65 @@
/* eslint-disable node/prefer-global/process */
import path from 'node:path'
import type { Container } from 'dockerode'
import Docker from 'dockerode'
import { config } from 'dotenv'
import { findContainerByName } from './find'
config()
const docker = new Docker()
export async function runContainer(once = false): Promise<Container> {
const existingContainer = await findContainerByName('node')
if (existingContainer) {
return existingContainer
}
const container = await docker.createContainer({
Image: 'dicoop/blockchain_v5.1.1:dev',
name: 'node',
Tty: !once,
HostConfig: {
PortBindings: {
'8888/tcp': [{ HostPort: '8888' }],
'9876/tcp': [{ HostPort: '9876' }],
'8080/tcp': [{ HostPort: '8080' }],
},
Binds: [
`${path.resolve('./blockchain-data')}:/mnt/dev/data`,
`${path.resolve('./src/configs')}:/mnt/dev/config`,
`${path.resolve('./wallet-data')}:/root/eosio-wallet`,
`${path.resolve('../contracts/build/contracts')}:/contracts`,
],
AutoRemove: true,
},
ExposedPorts: {
'8888/tcp': {},
'9876/tcp': {},
'8080/tcp': {},
},
Env: Object.keys(process.env).map(key => `${key}=${process.env[key]}`),
Cmd: [
'/bin/bash',
'-c',
'/usr/local/bin/nodeos -d /mnt/dev/data --config-dir /mnt/dev/config --genesis-json /mnt/dev/config/genesis.json',
],
})
await container.start()
if (!once) {
const stream = await container.logs({
follow: true,
stdout: true,
stderr: true,
})
// eslint-disable-next-line node/prefer-global/buffer
stream.on('data', (data: Buffer) => {
console.log(data.toString())
})
}
return container
}
+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.`)
}
}
+183
View File
@@ -0,0 +1,183 @@
/* 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 { 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[]) => {
try {
console.log(cmd)
await execCommand(['cleos', ...cmd])
}
catch (error) {
console.error('Command execution failed:', error)
}
})
// Команда для запуска команды в контейнере
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 execCommand([
'cleos',
'wallet',
'unlock',
'--password',
process.env.PASSWORD!,
])
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 deleteFile(keosdPath)
await stopContainerByName('node')
await clearDirectory(basePath)
await sleep(5000)
await runContainer()
await checkHealth()
await boot()
console.log('Boot process completed')
}
catch (error) {
console.error('Failed to boot:', error)
}
})
// Команда для получения списка контейнеров
program
.command('clean-launch')
.description('Purge blockchain data and boot a Protocol')
.action(async () => {
try {
await deleteFile(keosdPath)
await stopContainerByName('node')
await clearDirectory(basePath)
await sleep(5000)
await runContainer()
await checkHealth()
}
catch (error) {
console.error('Failed to boot:', error)
}
})
// Команда для получения списка контейнеров
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()
}
+223
View File
@@ -0,0 +1,223 @@
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'
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 createAgreements(coopname: string) {
// console.log('создаём кооперативное соглашение/положение по кошельку')
await this.blockchain.makeCoagreement({
coopname,
administrator: coopname,
type: 'wallet',
draft_id: TCooperative.Registry.WalletAgreement.registry_id,
program_id: 1,
})
await this.blockchain.makeCoagreement({
coopname,
administrator: coopname,
type: 'signature',
draft_id: TCooperative.Registry.RegulationElectronicSignature.registry_id,
program_id: 0,
})
await this.blockchain.makeCoagreement({
coopname,
administrator: coopname,
type: 'user',
draft_id: TCooperative.Registry.UserAgreement.registry_id,
program_id: 0,
})
await this.blockchain.makeCoagreement({
coopname,
administrator: coopname,
type: 'privacy',
draft_id: TCooperative.Registry.PrivacyPolicy.registry_id,
program_id: 0,
})
await this.blockchain.makeCoagreement({
coopname,
administrator: coopname,
type: 'coopenomics',
draft_id: TCooperative.Registry.CoopenomicsAgreement.registry_id,
program_id: 0,
})
}
async createCooperative(username: string, keys?: Keys) {
const account = await this.blockchain.generateKeypair(
username,
keys,
'Аккаунт кооператива',
)
console.log('Регистрируем аккаунт')
await this.blockchain.registerAccount2({
registrator: config.provider,
coopname: config.provider,
referer: '',
username: account.username,
public_key: account.publicKey,
meta: '',
})
console.log('Регистрируем аккаунт как пользователя')
await this.blockchain.registerUser({
registrator: config.provider,
coopname: config.provider,
username: account.username,
type: 'organization',
})
console.log('Переводим аккаунт в организации')
await this.blockchain.registerOrganization({
username: account.username,
coopname: account.username,
params: {
is_cooperative: true,
coop_type: 'conscoop',
announce: 'Тестовый кооператив',
description: 'Тестовое описание',
initial: `100.0000 ${config.token.govern_symbol}`,
minimum: `300.0000 ${config.token.govern_symbol}`,
org_initial: `1000.0000 ${config.token.govern_symbol}`,
org_minimum: `3000.0000 ${config.token.govern_symbol}`,
},
document,
})
console.log('Отправляем заявление на вступление')
await this.blockchain.joinCoop({
registrator: config.provider_chairman,
coopname: config.provider,
username: account.username,
document,
braname: '',
})
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.createPrograms(username)
await this.createAgreements(username)
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('Кооператив предварительно подготовлен к установке совета.')
}
+315
View File
@@ -0,0 +1,315 @@
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: 'Russia',
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: '2023-04-01',
phone: '+71234567890',
email: 'ivanov@example.com',
full_address: 'Переулок Правды д. 1',
passport: {
series: 7122,
number: 112233,
issued_by: 'отделом УФМС по г. Москва',
issued_at: '22.04.2010',
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('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.createAgreements(config.provider)
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('Базовая установка завершена')
}
+129
View File
@@ -0,0 +1,129 @@
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 createParticipant(username: string, keys?: Keys) {
const account = await this.blockchain.generateKeypair(
username,
keys,
'Аккаунт участника',
)
console.log('Регистрируем аккаунт')
const data: RegistratorContract.Actions.AddUser.IAddUser = {
registrator: config.provider,
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 createParticipant(username: string) {
// инициализируем инстанс с ключами
const blockchain = new Blockchain(config.network, config.private_keys)
const cooperative = new CooperativeClass(blockchain)
await cooperative.createParticipant(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!,
})
}
+832
View File
@@ -0,0 +1,832 @@
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 { createParticipant } 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, 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 createParticipant(investor1)
tester1 = generateRandomUsername()
console.log('tester1: ', tester1)
await createParticipant(tester1)
tester2 = generateRandomUsername()
console.log('tester2: ', tester2)
await createParticipant(tester2)
tester3 = generateRandomUsername()
console.log('tester3: ', tester3)
await createParticipant(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', capitalProgramId)
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: 'cofund',
}
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 data: CapitalContract.Actions.CreateProject.ICreateProject = {
coopname: 'voskhod',
application: 'voskhod',
title: `Идея ${hash.slice(0, 10)}`,
description: `Описание ${hash.slice(0, 10)}`,
project_hash: hash,
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(),
}
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, 10000)
}
})
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_amount).toBe('10000.0000 RUB')
expect(finalResult.creators_bonus).toBe('3820.0000 RUB')
expect(finalResult.authors_bonus).toBe('16180.0000 RUB')
expect(finalResult.generated_amount).toBe('30000.0000 RUB')
expect(finalResult.participants_bonus).toBe('48540.0000 RUB')
expect(finalResult.total_amount).toBe('78540.0000 RUB')
})
it('добавить коммит создателя tester2 на 10 часов по 1000 RUB', async () => {
const { finalResult, commitHash } = await commitToResult(blockchain, 'voskhod', result1.result_hash, result1.project_hash, tester2, tester2CommitHours)
commits.push(commitHash)
expect(finalResult.creators_amount).toBe('20000.0000 RUB')
expect(finalResult.creators_bonus).toBe('7640.0000 RUB')
expect(finalResult.authors_bonus).toBe('32360.0000 RUB')
expect(finalResult.generated_amount).toBe('60000.0000 RUB')
expect(finalResult.participants_bonus).toBe('97080.0000 RUB')
expect(finalResult.total_amount).toBe('157080.0000 RUB')
})
// 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('started')
// })
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('добавляем второго автора tester2', async () => {
// const data: CapitalContract.Actions.AddAuthor.IAddAuthor = {
// coopname: 'voskhod',
// application: 'voskhod',
// project_hash: project1.project_hash,
// author: tester2,
// 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 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(2)
// expect(project.authors_shares).toBe(200)
// })
// it('добавляем коммиты создателей tester2 и tester3', async () => {
// // Добавляем второго создателя
// let data: CapitalContract.Actions.AddCreator.IAddCreator = {
// coopname: 'voskhod',
// application: 'voskhod',
// result_hash: result1.result_hash,
// creator: tester2,
// used: '100.0000 RUB',
// }
// let result = await blockchain.api.transact(
// {
// actions: [
// {
// account: CapitalContract.contractName.production,
// name: CapitalContract.Actions.AddCreator.actionName,
// authorization: [
// {
// actor: 'voskhod',
// permission: 'active',
// },
// ],
// data,
// },
// ],
// },
// {
// blocksBehind: 3,
// expireSeconds: 30,
// },
// )
// getTotalRamUsage(result)
// expect(result.transaction_id).toBeDefined()
// // Добавляем третьего создателя
// data = {
// coopname: 'voskhod',
// application: 'voskhod',
// result_hash: result1.result_hash,
// creator: tester3,
// used: '100.0000 RUB',
// }
// result = await blockchain.api.transact(
// {
// actions: [
// {
// account: CapitalContract.contractName.production,
// name: CapitalContract.Actions.AddCreator.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.creators_count).toBe(3)
// expect(blockchainResult.creators_amount).toBe('300.0000 RUB')
// // Ниже – пример ожидаемого роста, исходя из логики контракта
// expect(blockchainResult.creators_bonus).toBe('114.6000 RUB')
// expect(blockchainResult.authors_bonus).toBe('485.4000 RUB')
// expect(blockchainResult.generated_amount).toBe('900.0000 RUB')
// expect(blockchainResult.participants_bonus).toBe('1456.2000 RUB')
// expect(blockchainResult.total_amount).toBe('2356.2000 RUB')
// })
// it('удаляем создателя tester3', async () => {
// const data: CapitalContract.Actions.DelCreator.IDelCreator = {
// coopname: 'voskhod',
// application: 'voskhod',
// result_hash: result1.result_hash,
// creator: tester3,
// }
// const result = await blockchain.api.transact(
// {
// actions: [
// {
// account: CapitalContract.contractName.production,
// name: CapitalContract.Actions.DelCreator.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.creators_count).toBe(2)
// expect(blockchainResult.creators_amount).toBe('200.0000 RUB')
// // Уменьшаем все показатели ровно на величину последнего добавленного создателя
// expect(blockchainResult.creators_bonus).toBe('76.4000 RUB') // 114.6000 - 38.2000
// expect(blockchainResult.authors_bonus).toBe('323.6000 RUB') // 485.4000 - 161.8000
// expect(blockchainResult.generated_amount).toBe('600.0000 RUB') // 900.0000 - 300.0000
// expect(blockchainResult.participants_bonus).toBe('970.8000 RUB') // 1456.2000 - 485.4000
// expect(blockchainResult.total_amount).toBe('1570.8000 RUB') // 2356.2000 - 785.4000
// })
// it('стартуем распределение долей результата', async () => {
// const data: CapitalContract.Actions.Start.IStart = {
// coopname: 'voskhod',
// application: 'voskhod',
// result_hash: result1.result_hash,
// }
// const result = await blockchain.api.transact(
// {
// actions: [
// {
// account: CapitalContract.contractName.production,
// name: CapitalContract.Actions.Start.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.status).toBe('started')
// })
// it('пишем заявления и получаем NFT', async () => {
// const data: CapitalContract.Actions.SetStatement.ISetStatement = {
// coopname: 'voskhod',
// application: 'voskhod',
// statement: fakeDocument,
// nft_hash: generateRandomSHA256(),
// }
// const result = await blockchain.api.transact(
// {
// actions: [
// {
// account: CapitalContract.contractName.production,
// name: CapitalContract.Actions.SetStatement.actionName,
// authorization: [
// {
// actor: 'voskhod',
// permission: 'active',
// },
// ],
// data,
// },
// ],
// },
// {
// blocksBehind: 3,
// expireSeconds: 30,
// },
// )
// getTotalRamUsage(result)
// expect(result.transaction_id).toBeDefined()
// })
})
@@ -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,211 @@
import { expect } from 'vitest'
import { CapitalContract } from 'cooptypes'
import { getTotalRamUsage } from '../../utils/getTotalRamUsage'
import { generateRandomSHA256 } from '../../utils/randomHash'
import { fakeDocument } from '../soviet/fakeDocument'
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] || { spend: '0.0000 RUB', commits_count: 0 }
const prevProject = (await blockchain.getTableRows(
CapitalContract.contractName.production,
coopname,
'projects',
1,
projectHash,
projectHash,
3,
'sha256',
))[0] || { spend: '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,
creator,
commit_hash: commitHash,
specification: fakeDocument,
contributed_hours: spendHours,
}
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.spend).toBe(totalSpended)
expect(blockchainCommit.status).toBe('created')
// Утверждение коммита
const approveCommitData: CapitalContract.Actions.ApproveCommit.IApproveCommit = {
coopname,
application: coopname,
commit_hash: commitHash,
approver: 'ant',
approved_specification: fakeDocument,
}
console.log(`\n✅ Подтверждение коммита ${commitHash}`)
const approveCommitResult = await blockchain.api.transact(
{
actions: [
{
account: CapitalContract.contractName.production,
name: CapitalContract.Actions.ApproveCommit.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]
console.log('🔍 Коммит после утверждения:', blockchainCommit)
expect(blockchainCommit).toBeDefined()
expect(blockchainCommit.commit_hash).toBe(commitHash)
expect(blockchainCommit.status).toBe('approved')
// Проверка результата после утверждения коммита
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.spend)).toBe(parseFloat(prevResult.spend) + parseFloat(totalSpended))
expect(parseFloat(finalProject.spend)).toBe(parseFloat(prevProject.spend))
// Проверка, что у контрибьютора увеличились 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,3 @@
export const capitalProgramId = 3
export const walletProgramId = 1
export const ratePerHour = '1000.0000 RUB'
@@ -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 } 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,274 @@
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.Withdraws.tableName,
1,
expenseHash,
expenseHash,
3,
'sha256',
))[0]
console.log('🔍 Вывод средств:', blockchainWithdraw)
expect(blockchainWithdraw).toBeDefined()
expect(blockchainWithdraw.withdraw_hash).toBe(expenseHash)
expect(blockchainWithdraw.quantity).toBe(expenseAmount)
expect(blockchainWithdraw.status).toBe('authorized')
// Завершение вывода
const completeWithdrawData: GatewayContract.Actions.CompleteWithdraw.ICompleteWithdraw = {
coopname,
application: '',
memo: '',
withdraw_hash: expenseHash,
}
console.log(`\n✅ Завершение вывода ${expenseHash}`)
const completeWithdrawResult = await blockchain.api.transact(
{
actions: [
{
account: GatewayContract.contractName.production,
name: GatewayContract.Actions.CompleteWithdraw.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 { capitalProgramId } from './consts'
export async function signCapitalAgreement(
blockchain: any,
coopname: string,
username: string,
fakeDocument: any,
) {
const txId = await signAgreement(blockchain, coopname, username, 'cofund', fakeDocument)
const wallet = await getUserProgramWallet(blockchain, coopname, username, capitalProgramId)
expect(wallet).toEqual(expect.objectContaining({
coopname,
username,
available: expect.any(String),
blocked: expect.any(String),
program_id: capitalProgramId,
membership_contribution: expect.any(String),
}))
const program = await getCoopProgramWallet(blockchain, coopname, capitalProgramId)
return { wallet, program, txId }
}
@@ -0,0 +1,211 @@
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.CreateWithdraw1.ICreateWithdraw = {
coopname,
application: coopname,
username,
result_hash: resultHash,
withdraw_hash: withdrawHash,
commit_hashes: commitHashes,
contribution_statement: fakeDocument,
return_statement: fakeDocument,
}
console.log(`\n🚀 Отправка транзакции CreateWithdraw для ${username} на сумму ${withdrawAmount}`)
const createWithdrawResult = await blockchain.api.transact(
{
actions: [
{
account: CapitalContract.contractName.production,
name: CapitalContract.Actions.CreateWithdraw1.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,
'withdraws',
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.ApproveWithdraw.IApproveWithdraw = {
coopname,
application: coopname,
approver: 'ant',
withdraw_hash: withdrawHash,
approved_contribution_statement: fakeDocument,
approved_return_statement: fakeDocument,
}
console.log(`\n✅ Подтверждение возврата ${withdrawHash}`)
const approveWithdrawResult = await blockchain.api.transact(
{
actions: [
{
account: CapitalContract.contractName.production,
name: CapitalContract.Actions.ApproveWithdraw.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,
'withdraws',
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]
const prevLastDecision = decisions[decisions.length - 2]
console.log(`\n📜 Выполнение решений: ${prevLastDecision.id}, ${lastDecision.id}`)
await processDecision(blockchain, prevLastDecision.id)
await processDecision(blockchain, lastDecision.id)
blockchainWithdraw = (await blockchain.getTableRows(
CapitalContract.contractName.production,
coopname,
'withdraws',
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.spend)).toBe(parseFloat(prevProject.spend) + parseFloat(withdrawAmount))
console.log(`\n✅ Возврат на ${withdrawAmount} завершен успешно!`)
return { withdrawHash, transactionId: approveWithdrawResult.transaction_id, finalProject }
}
@@ -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()
}
@@ -0,0 +1,41 @@
import { expect } from 'vitest'
import { SovietContract } from 'cooptypes'
import { getTotalRamUsage } from '../../utils/getTotalRamUsage'
export async function signAgreement(
blockchain: any,
coopname: string,
username: string,
agreement_type: string,
fakeDocument: any,
) {
const data: SovietContract.Actions.Agreements.SendAgreement.ISendAgreement = {
coopname,
administrator: coopname,
username,
agreement_type,
document: fakeDocument,
}
const result = await blockchain.api.transact(
{
actions: [
{
account: SovietContract.contractName.production,
name: SovietContract.Actions.Agreements.SendAgreement.actionName,
authorization: [{ actor: username, permission: 'active' }],
data,
},
],
},
{
blocksBehind: 3,
expireSeconds: 30,
},
)
getTotalRamUsage(result)
expect(result.transaction_id).toBeDefined()
return result.transaction_id
}
+51
View File
@@ -0,0 +1,51 @@
import { afterAll, beforeAll, describe, expect, it } from 'vitest'
import Blockchain from '../blockchain'
import config from '../configs'
import { getTotalRamUsage, globalRamStats } from '../utils/getTotalRamUsage'
import { createParticipant } from '../init/participant'
import { generateRandomUsername } from '../utils/randomUsername'
import { signWalletAgreement } from './wallet/signWalletAgreement'
import { depositToWallet } from './wallet/depositToWallet'
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()
tester1 = generateRandomUsername()
console.log('tester1: ', tester1)
await createParticipant(tester1)
}, 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('тест Wallet в Soviet', () => {
it('подписываем соглашение ЦПП кошелька', async () => {
const { wallet, program } = await signWalletAgreement(blockchain, 'voskhod', 'ant', fakeDocument)
walletProgramStates1.push(program)
})
it('совершаем депозит в ЦПП кошелька', async () => {
const { depositId, program, userWallet } = await depositToWallet(blockchain, 'voskhod', 'ant', 100.0)
walletProgramStates1.push(program)
}, 20_000)
})
@@ -0,0 +1,92 @@
import { randomInt } from 'node:crypto'
import { GatewayContract } from 'cooptypes'
import { expect } from 'vitest'
import { getTotalRamUsage } from '../../utils/getTotalRamUsage'
import { compareTokenAmounts, getCoopProgramWallet, getCoopWallet, getDeposit, getUserProgramWallet } from './walletUtils'
export async function depositToWallet(blockchain: any, coopname: string, username: string, amount: number) {
const depositId = randomInt(100000)
const data: GatewayContract.Actions.CreateDeposit.ICreateDeposit = {
coopname,
username,
deposit_id: depositId,
type: 'deposit',
quantity: `${amount.toFixed(4)} RUB`,
}
const result = await blockchain.api.transact(
{
actions: [
{
account: GatewayContract.contractName.production,
name: GatewayContract.Actions.CreateDeposit.actionName,
authorization: [{ actor: username, permission: 'active' }],
data,
},
],
},
{
blocksBehind: 3,
expireSeconds: 30,
},
)
getTotalRamUsage(result)
expect(result.transaction_id).toBeDefined()
const deposit = await getDeposit(blockchain, coopname, depositId)
expect(deposit).toEqual(expect.objectContaining({
id: depositId,
username,
coopname,
type: 'deposit',
quantity: `${amount.toFixed(4)} RUB`,
status: 'pending',
}))
const prevUserWallet = await getUserProgramWallet(blockchain, coopname, username, 1)
const prevUserWalletAvailable = prevUserWallet?.available || '0.0000 RUB'
const prevCoopWallet = await getCoopWallet(blockchain, coopname)
const prevCoopWalletAvailable = prevCoopWallet?.circulating_account?.available || '0.0000 RUB'
const data2: GatewayContract.Actions.CompleteDeposit.ICompleteDeposit = {
coopname,
admin: coopname,
deposit_id: depositId,
memo: '',
}
const result2 = await blockchain.api.transact(
{
actions: [
{
account: GatewayContract.contractName.production,
name: GatewayContract.Actions.CompleteDeposit.actionName,
authorization: [{ actor: coopname, permission: 'active' }],
data: data2,
},
],
},
{
blocksBehind: 3,
expireSeconds: 30,
},
)
getTotalRamUsage(result2)
const deposit2 = await getDeposit(blockchain, coopname, depositId)
expect(deposit2.status).toBe('completed')
const program = await getCoopProgramWallet(blockchain, coopname, 1)
const userWallet = await getUserProgramWallet(blockchain, coopname, username, 1)
// Проверяем изменение балансов
compareTokenAmounts(prevUserWalletAvailable, userWallet.available, amount)
compareTokenAmounts(prevCoopWalletAvailable, (await getCoopWallet(blockchain, coopname)).circulating_account.available, amount)
return { depositId, program, userWallet }
}
@@ -0,0 +1,26 @@
import { expect } from 'vitest'
import { signAgreement } from '../soviet/signAgreement'
import { getCoopProgramWallet, getUserProgramWallet } from './walletUtils'
export async function signWalletAgreement(
blockchain: any,
coopname: string,
username: string,
fakeDocument: any,
) {
const txId = await signAgreement(blockchain, coopname, username, 'wallet', fakeDocument)
const wallet = await getUserProgramWallet(blockchain, coopname, username, 1)
expect(wallet).toEqual(expect.objectContaining({
coopname,
username,
available: expect.any(String),
blocked: expect.any(String),
program_id: 1,
membership_contribution: expect.any(String),
}))
const program = await getCoopProgramWallet(blockchain, coopname, 1)
return { wallet, program, txId }
}
@@ -0,0 +1,57 @@
import { FundContract, GatewayContract, SovietContract } from 'cooptypes'
import { expect } from 'vitest'
export async function getUserProgramWallet(blockchain: any, coopname: string, username: string, program_id: number) {
const wallets = await blockchain.getTableRows(
SovietContract.contractName.production,
coopname,
'progwallets',
100,
username,
username,
2,
)
return wallets.find((el: any) => el.program_id === program_id)
}
export async function getCoopProgramWallet(blockchain: any, coopname: string, program_id: number) {
const program = await blockchain.getTableRows(
SovietContract.contractName.production,
coopname,
'programs',
1000,
program_id.toString(),
program_id.toString(),
)
console.log('PROGRAMS:', program)
return program[0]
}
export async function getCoopWallet(blockchain: any, coopname: string) {
return (await blockchain.getTableRows(
FundContract.contractName.production,
coopname,
'coopwallet',
1,
))[0]
}
export async function getDeposit(blockchain: any, coopname: string, deposit_id: number) {
return (await blockchain.getTableRows(
GatewayContract.contractName.production,
coopname,
'deposits',
1,
deposit_id.toString(),
deposit_id.toString(),
))[0]
}
export function compareTokenAmounts(prevAmount: string, currentAmount: string, expectedIncrease: number): void {
const prev = parseFloat(prevAmount.split(' ')[0])
const current = parseFloat(currentAmount.split(' ')[0])
const expected = prev + expectedIncrease
expect(current).toBe(expected)
}
+28
View File
@@ -0,0 +1,28 @@
export interface Account {
name: string
ownerPublicKey: string
activePublicKey: string
}
export interface Network {
name: string
protocol: string
host: string
port: string
}
export interface Contract {
path: string
name: string
target: string
}
export interface Feature {
name: string
hash: string
}
export interface Keys {
privateKey: string
publicKey: string
}
@@ -0,0 +1,84 @@
export const globalRamStats: Record<string, number> = {} // Хранит RAM по каждому `actor:action`
interface RamDelta {
account: string
delta: number
}
interface ActInfo {
authorization: { actor: string }[] // Содержит `username`
account: string
name: string
}
interface ActionTrace {
act?: ActInfo
account_ram_delta?: RamDelta
account_ram_deltas?: RamDelta[]
inline_traces?: ActionTrace[]
}
interface TransactionTrace {
processed: {
action_traces: ActionTrace[]
}
}
function accumulateRam(trace: ActionTrace, loggedActions = new Set<string>()): number {
let totalDelta = 0
const ramDeltas: RamDelta[] = [
...(trace.account_ram_delta ? [trace.account_ram_delta] : []),
...(trace.account_ram_deltas || []),
]
const contract = trace.act?.account || 'unknown'
const action = trace.act?.name || 'unknown'
const key = `${contract}:${action}` // Ключ для фильтрации дублей
// Если RAM дельта = 0, но такой лог еще не был записан — логируем один раз
if (ramDeltas.length === 0 && !loggedActions.has(key)) {
console.log(`@none:${contract}:${action} = 0.00 kb`)
loggedActions.add(key)
}
// Логируем всех реальных плательщиков RAM
for (const { account, delta } of ramDeltas) {
totalDelta += delta
const deltaKb = (delta / 1024).toFixed(2)
console.log(`@${account}:${contract}:${action} = ${deltaKb} kb`)
}
// Рекурсия по inline-экшенам
if (trace.inline_traces?.length) {
for (const inlineTrace of trace.inline_traces) {
totalDelta += accumulateRam(inlineTrace, loggedActions)
}
}
return totalDelta
}
export function getTotalRamUsage(result: TransactionTrace): number {
if (!result?.processed?.action_traces)
return 0
let total = 0
let topLevelActor = 'unknown'
let topLevelAction = 'unknown'
for (const topLevelActionTrace of result.processed.action_traces) {
if (topLevelActor === 'unknown' && topLevelActionTrace.act) {
topLevelActor = topLevelActionTrace.act.authorization?.[0]?.actor || 'unknown'
topLevelAction = topLevelActionTrace.act.name
}
total += accumulateRam(topLevelActionTrace)
}
// Записываем RAM в глобальную статистику
const key = `${topLevelActor}:${topLevelAction}`
globalRamStats[key] = (globalRamStats[key] || 0) + total
console.log(`RAM used by ${key}: ${(total / 1024).toFixed(2)} kb`)
return total
}
+18
View File
@@ -0,0 +1,18 @@
import axios from 'axios'
export function sleep(ms: number) {
return new Promise(resolve => setTimeout(resolve, ms))
}
export async function sendPostToCoopbackWithSecret(url: string, data: any) {
// eslint-disable-next-line node/prefer-global/process
const base = process.env.SERVER_URL
return axios.post(`${base}${url}`, data, {
headers: {
// eslint-disable-next-line node/prefer-global/process
'server-secret': process.env.SERVER_SECRET,
'Content-Type': 'application/json',
},
})
}
+6
View File
@@ -0,0 +1,6 @@
import { createHash, randomBytes } from 'node:crypto'
export function generateRandomSHA256(): string {
const randomData = randomBytes(32).toString('hex') // 32 байта случайных данных
return createHash('sha256').update(randomData).digest('hex')
}
@@ -0,0 +1,14 @@
/**
* Генерирует случайное имя аккаунта длиной 12 символов из букв a-z
*/
export function generateRandomUsername(): string {
const alphabet = 'abcdefghijklmnopqrstuvwxyz'
let result = ''
for (let i = 0; i < 12; i++) {
const randomIndex = Math.floor(Math.random() * alphabet.length)
result += alphabet[randomIndex]
}
return result
}
+14
View File
@@ -0,0 +1,14 @@
{
"compilerOptions": {
"target": "ESNext",
"lib": ["ESNext"],
"module": "ESNext",
"moduleResolution": "Bundler",
"resolveJsonModule": true,
"strict": true,
"strictNullChecks": true,
"esModuleInterop": true,
"skipDefaultLibCheck": true,
"skipLibCheck": true
}
}
BIN
View File
Binary file not shown.
+2
View File
@@ -0,0 +1,2 @@
BasedOnStyle: Google
IndentWidth: 2
+18
View File
@@ -0,0 +1,18 @@
soviet/soviet.abi
soviet/soviet.wasm
registrator/registrator.abi
registrator/registrator.wasm
networks.sh
ano/ano.wasm
ano/ano.abi
lib/
Testing/
docs/html/*
docs/xml/*
docs/node_modules/*
node_modules
build/*
blockchain-data/*
wallet-data/*
docs/*
blocks/*
+70
View File
@@ -0,0 +1,70 @@
{
// Enable the ESlint flat config support
"eslint.experimental.useFlatConfig": true,
// Disable the default formatter, use eslint instead
"prettier.enable": false,
"editor.formatOnSave": true,
// Auto fix
"editor.codeActionsOnSave": {
"source.fixAll.eslint": "explicit"
// "source.fixAll": "explicit",
// "source.organizeImports": "never"
},
// Silent the stylistic rules in you IDE, but still auto fix them
"eslint.rules.customizations": [
{
"rule": "style/*",
"severity": "off"
},
{
"rule": "*-indent",
"severity": "off"
},
{
"rule": "*-spacing",
"severity": "off"
},
{
"rule": "*-spaces",
"severity": "off"
},
{
"rule": "*-order",
"severity": "off"
},
{
"rule": "*-dangle",
"severity": "off"
},
{
"rule": "*-newline",
"severity": "off"
},
{
"rule": "*quotes",
"severity": "off"
},
{
"rule": "*semi",
"severity": "off"
}
],
// Enable eslint for all supported languages
"eslint.validate": [
"javascript",
"javascriptreact",
"typescript",
"typescriptreact",
"vue",
"html",
"markdown",
"json",
"jsonc",
"yaml"
],
// "[cpp]": {
// "editor.defaultFormatter": "ms-vscode.cpptools",
// },
// "C_Cpp.vcFormat.indent.withinParentheses": "indent",
"C_Cpp.errorSquiggles": "disabled"
}
+49
View File
@@ -0,0 +1,49 @@
cmake_minimum_required(VERSION 3.5)
project(coopenomics)
include(ExternalProject)
# Распечатываем начальное значение BUILD_TARGET
message(STATUS "Initial BUILD_TARGET=${BUILD_TARGET}")
# Макрос для сборки контрактов с диагностическими сообщениями
macro(add_contract_build name)
string(STRIP "${BUILD_TARGET}" BUILD_TARGET_STRIPPED)
string(STRIP "${name}" NAME_STRIPPED)
if(NOT BUILD_TARGET_STRIPPED OR BUILD_TARGET_STRIPPED STREQUAL NAME_STRIPPED)
message(STATUS "COMPILING ${name} CONTRACT")
ExternalProject_Add(
${name}_contract
SOURCE_DIR ${CMAKE_SOURCE_DIR}/cpp/${name}
BINARY_DIR ${CMAKE_BINARY_DIR}/contracts/${name}
CMAKE_ARGS -DCMAKE_TOOLCHAIN_FILE=/cdt/build/lib/cmake/cdt/CDTWasmToolchain.cmake
UPDATE_COMMAND ""
PATCH_COMMAND ""
TEST_COMMAND ""
INSTALL_COMMAND ""
BUILD_ALWAYS 1
)
else()
message(STATUS "SKIPPING ${name} CONTRACT")
endif()
endmacro()
# Добавляем все контракты
add_contract_build(capital)
add_contract_build(branch)
add_contract_build(contributor)
add_contract_build(fund)
add_contract_build(draft)
add_contract_build(soviet)
add_contract_build(registrator)
add_contract_build(gateway)
add_contract_build(marketplace)
add_contract_build(system)
# Опции для тестов
option(BUILD_TESTS "Build unit tests" OFF)
if(BUILD_TESTS)
add_subdirectory(${CMAKE_SOURCE_DIR}/cpp/tests ${CMAKE_BINARY_DIR}/contracts/tests)
endif()
File diff suppressed because it is too large Load Diff
+156
View File
@@ -0,0 +1,156 @@
# Введение.
Репозиторий содержит в себе смарт-контракты операционной системы coopOS, образующих протокол COOPENOMICS.
## Окружение
В качестве окружения используется контейнер операционной системы coopOS. Для запуска выполните команду из корня репозитория:
```
pnpm run enter
```
После выполнения команды и входа в контейнер, выполняйте команды компиляции внутри него.
## Компиляция
Для компиляции выполните команду:
```
mkdir build
cd build
cmake -DBUILD_TARGET= ..
make
```
Компиляция всех контрактов произойдёт в папку build/contracts. Для указания конкретного контракта, который необходимо скомпилировать, используйте названия папок из директории cpp в качестве параметра -DBUILD_TARGET. Например, для контракта fund:
```
cmake -DBUILD_TARGET=fund ..
make
```
Для компиляции всех контрактов передавайте пустой параметр -DBUILD_TARGET= . Без явной передачи параметра используйте кэшированный, ранее переданный параметр, что может привести к путанице. Поэтому, всегда явно передавайте параметр цели компиляции.
## Загрузка
Перед автоматической загрузкой контрактов в локальную версию блокчейна - скомпилируйте их как показано выше. После чего, выйдите из контейнера и выполните команду установки загрузчика в вашем окружении:
```
pnpm install
```
Скопируйте файл .env-example в .env:
```
cp .env-example .env
```
И запустите загрузку:
```
pnpm run cli boot
```
Команда загрузки запустит блокчейн и произведет установку всех контрактов для начала работы. Параметры конфигурации блокчейна можно найти в файле scripts/restart.sh
Блокчейн будет запущен в контейнере и остановит свою работу при завершении работы программы. Данные сохраняются в ./blockchain-data корневой директории репозитория. Данные кошелька пишутся в ./wallet-data.
После остановки контейнера вы можете перезапустить его командной:
```
pnpm run cli start
```
Для перезагрузки блокчейна вновь вызовите:
```
pnpm run boot
```
Последняя команда очистит всю историю цепочки блоков и перезагрузит локальный блокчейн до начального состояния.
## Кошелёк
Для доступа командному кошельку cleos используйте команду
```
pnpm run cli cleos
```
Для отображения полного списка команд воспользуйтесь:
```
pnpm run cli cleos --help
```
Командный кошелёк позволяет совершать любые транзакции и просматривать любые таблицы в блокчейне. Для более удобной постоянной работы занесите алиас в файл ~/.bashrc для быстрого вызова:
```
alias=cd <REPLACE_TO_YOUR_LOCAL_REPOSITORY_DIR/boot> && pnpm run cli cleos
```
Подтяните изменения профиля:
```
source ~/.bashrc
```
Теперь утилита cleos доступна простой командной:
```
cleos get info
```
## Тесты
### Полные тесты
Тесты по-умолчанию НЕ компилируются вместе с контрактами. Для компиляции необходимо передать флаг конфигурации сборки -DBUILD_TESTS=ON:
```
cmake -DBUILD_TARGET= -DBUILD_TESTS=ON
make
```
Все контракты пересоберутся вместе со всеми тестами.
Для запуска тестов (из директории build):
```
ctest --test-dir contracts/tests --output-on-failure
```
### Выборочные тесты
Для выборочного указания тестового файла используйте из директории build:
```
cmake -DBUILD_TARGET=fund -DBUILD_TESTS=ON -DTEST_TARGET=fund.tester.cpp ..
make
```
Команды пересоберет указанный контракт и его тест. Выборочная сборка и тесты значительно ускоряют отладку.
### Информативные тесты
Для большей детализации тестового процесса добавьте флаг -DVERBOSE=ON при конфигурации сборки:
```
cmake -DBUILD_TARGET=fund -DTEST_TARGET=fund.tester.cpp -DVERBOSE=ON ..
make
```
Дополнительная вербозность показывает отладочную информацию из тестов, включая консоль контрактов, в которую информация выводится через методы print.
## Документация
Для генерации документации используйте команду Doxygen версии от 1.9.3:
```
git submodule update --init --recursive
doxygen
```
Документация будет собрана в папке docs/html, откройте файл index.html в браузере:
```
open docs/html/index.html
```
## Лицензия
Продукт Потребительского Кооператива "ВОСХОД" распространяется по лицензии BY-NC-SA 4.0.
Разрешено делиться, копировать и распространять материал на любом носителе и форме, адаптировать, делать ремиксы, видоизменять и создавать новое, опираясь на этот материал. При использовании, Вы должны обеспечить указание авторства, предоставить ссылку, и обозначить изменения, если таковые были сделаны. Если вы перерабатываете, преобразовываете материал или берёте его за основу для производного произведения, вы должны распространять переделанные вами части материала на условиях той же лицензии , в соответствии с которой распространяется оригинал. Запрещено коммерческое использование материала. Использование в коммерческих целях – это использование, в первую очередь направленное на получение коммерческого преимущества или денежного вознаграждения.
Юридический текст лицензии: https://creativecommons.org/licenses/by-nc-sa/4.0/legalcode.ru

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