Compare commits

...

25 Commits

Author SHA1 Message Date
Alex Ant e5e28ff652 chore(release): publish 2025-03-27 18:13:33 +05:00
Alex Ant 4957182480 update mutation simplification 2025-03-27 17:30:31 +05:00
Alex Ant 84927e943a make participants editable 2025-03-27 14:32:23 +05:00
Alex Ant 0d06114f00 change decision dto and logout on some auth problems 2025-03-26 22:18:12 +05:00
Alex Ant 2654760e16 Merge pull request #201 from coopenomics/kamilocean/sprint-4
Kamilocean/sprint 4
2025-03-26 20:09:37 +03:00
Alex Ant d02e7ba2be README.md for cleos wallet 2025-03-26 18:27:05 +05:00
Alex Ant e18fd94336 make cleos separated component 2025-03-26 18:19:52 +05:00
Alex Ant 03e2410556 make cleos wallet accessable 2025-03-26 13:08:04 +05:00
Alex Ant 0f1f34f621 make unnesassary result 2025-03-26 11:42:05 +05:00
Alex Ant c08473618f some updates on contracts and tests 2025-03-22 13:58:51 +05:00
Alex Ant 3b4fb195bb update 2025-03-21 17:58:33 +05:00
Alex Ant 827eb10cc2 Merge branch 'dev' into TSK-900 2025-03-19 10:58:53 +05:00
Alex Ant 6e7c60de6e Создание кошелька при регистрации участника 2025-03-19 10:58:20 +05:00
kamilocean 54a4449e0b Merge branch 'dev' into kamilocean/sprint-4 2025-03-17 16:07:50 +03:00
kamilocean 08c31171a0 WIP: fix EditableActions instead of ActionButton 2025-03-17 16:07:28 +03:00
Ilia Smirnov a6011f5d46 Merged readme fixes 2025-03-17 12:52:02 +03:00
Ilia Smirnov a1300e2b3c Merge branch 'dev' of github.com:coopenomics/mono into TSK-878 2025-03-17 12:49:40 +03:00
Alex Ant 8f58672403 Merge pull request #217 from coopenomics/dacom-dark-sun/sprint-4
Спринт-4 | dacom-dark-sun
2025-03-17 09:57:34 +03:00
Alex Ant b8d048bf3c README.md 2025-03-17 11:55:18 +05:00
Ilia Smirnov bb7b650ebc docs(install): updated installation instructions 2025-03-17 09:44:10 +03:00
kamilocean 5253de9279 WIP: add EditableOrganizationCard 2025-03-16 21:04:40 +03:00
Alex Ant 094945e350 make it works 2025-03-14 13:20:41 +05:00
kamilocean eb6b58e6db Merge branch 'dev' into kamilocean/sprint-4 2025-03-13 23:54:25 +03:00
kamilocean 7bcb6e30a7 fix: add Zeus type 2025-03-13 23:54:02 +03:00
kamilocean 44ab386835 WIP: EditableAccountCard 2025-03-13 00:30:00 +03:00
313 changed files with 4517 additions and 2492 deletions
Vendored
BIN
View File
Binary file not shown.
+1 -2
View File
@@ -1,5 +1,4 @@
node_modules/
lerna-debug.log
components/controller/graph.png
wallet-data/
blockchain-data/
blockchain-data/
+11
View File
@@ -3,6 +3,17 @@
All notable changes to this project will be documented in this file.
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
## [2.2.10](https://github.com/coopenomics/mono/compare/v2.2.9...v2.2.10) (2025-03-27)
### Bug Fixes
* add Zeus type ([7bcb6e3](https://github.com/coopenomics/mono/commit/7bcb6e30a77b0ab89c5293188b58f08f19c8761e))
## [2.2.9](https://github.com/coopenomics/mono/compare/v2.2.8...v2.2.9) (2025-03-12)
**Note:** Version bump only for package monocoop
+91 -11
View File
@@ -1,55 +1,135 @@
# MONO
Система управления взаимоотношениями в кооперативе. Включает в себя полный комплект программного обеспечения для подключения к платформе "Кооперативная Экономика" и управления взаимоотношениями с пайщиками в кооперативе и самим кооперативом на основе смарт-контрактов и простой электронной подписи.
## Ветки
- Для разработки используется ветка `dev`.
- Для разработки используется ветка `dev`.
- Для стейджа используется ветка `testnet`.
- Для продакшена используется ветка `main`.
## Установка
```
```sh
pnpm install
```
Также для работы потребуется установленная фабрика документов `weasyprint` для вашей операционной системы: <https://doc.courtbouillon.org/weasyprint/stable/first_steps.html#installation>
## Конфигурация
Для конфигурации потребуетcя установленный `docker` и `docker-compose`. Выполните команду и следуйте инструкциям:
```
```sh
pnpm run setup
```
## Запуск
### Инфраструктура
Для работы системы необходимы базы `mongo`, `postgres` и `redis`.
Для работы системы необходимы базы `mongo`, `postgres` и `redis`.
Команда запуска баз данных в контейнерах для работы в фоновом режиме:
```
```sh
docker compose up -d
```
### Блокчейн и контракты
```
```sh
pnpm boot
```
Команда запустит блокчейн и установит все смарт-контракты, подготовив систему к локальной разработке или применению.
Команда запустит блокчейн и установит все смарт-контракты, подготовив систему к локальной разработке или применению.
### Бэкенд
```
```sh
pnpm run dev:backend
```
Команда запустит набор сервисов бэкенда и точку доступа GraphQL-API на 2998 порту.
### Фронтенд
Команда запустит рабочий стол кооператива на 3005 порту:
```
```sh
pnpm run dev:desktop
```
### Очистка базы
Команда очистит базу mongodb и начнет производство блоков с начала:
```sh
pnpm run clear
```
Правильная последовательность команд при переустановке проекта "с нуля":
```sh
git pull
pnpm install
pnpm run setup
pnpm run clear
pnpm run boot
pnpm run dev:backend
pnpm run dev:desktop
```
### Кошелёк
Для работы с кошельком блокчейна используется утилита cleos, которая позволяет извлекать таблицы смарт-контрактов и отправлять транзакции в блокчейн если это требуется.
Для работы с командным кошельком `cleos` локально необходимо чтобы инфраструктура была поднята:
```
docker compose up -d
```
Запускаем контейнер с кошельком и входим в него командой:
```
pnpm run cleos
```
В кошельке уже находится дефолтный ключ для работы с локальной средой. Этот ключ зашифрован паролем. Пароль хранится в файле `password` и используется автоматически при разблокировке. Для разблокировки кошелька, находясь в контейнере выполняем:
```
./unlock.sh
```
Для использования кошелька выполняем:
```
./cleos.sh <command>
```
Для получения полного списка команд вызываем кошелек без команд:
```
./cleos.sh
```
Например, для получения информации о текущем состоянии блокчейна:
```
./cleos.sh get info
```
### Возможные проблемы
В случае, если при выполнении ./unlock.sh возникает проблема:
`Unable to connect to keosd, if keosd is running please kill the process and try again`, то выполните команду:
```
./reset.sh
```
Данная команда удалит созданный ранее сокет кошелька, после чего, выполните ./unlock.sh повторно.
## Лицензия
Продукт Потребительского Кооператива "ВОСХОД" распространяется по лицензии BY-NC-SA 4.0.
Продукт Потребительского Кооператива "ВОСХОД" распространяется по лицензии BY-NC-SA 4.0.
Разрешено делиться, копировать и распространять материал на любом носителе и форме, адаптировать, делать ремиксы, видоизменять и создавать новое, опираясь на этот материал. При использовании, Вы должны обеспечить указание авторства, предоставить ссылку, и обозначить изменения, если таковые были сделаны. Если вы перерабатываете, преобразовываете материал или берёте его за основу для производного произведения, вы должны распространять переделанные вами части материала на условиях той же лицензии , в соответствии с которой распространяется оригинал. Запрещено коммерческое использование материала. Использование в коммерческих целях – это использование, в первую очередь направленное на получение коммерческого преимущества или денежного вознаграждения.
Юридический текст лицензии: https://creativecommons.org/licenses/by-nc-sa/4.0/legalcode.ru
Юридический текст лицензии: <https://creativecommons.org/licenses/by-nc-sa/4.0/legalcode.ru>
BIN
View File
Binary file not shown.
+1 -1
View File
@@ -2,7 +2,7 @@ EOSIO_PUB_KEY=EOS6MRyAjQq8ud7hVNYcfnVPJqcVpscN5So8BhtHuGYqET5GDW5CV
EOSIO_PRV_KEY=5KQwrPbwdL6PhXujxW37FSSQZ1JiwsST4cqQzDeyXtP79zkvFD3
DATADIR=blockchain-data
BPACCOUNT=eosio
PASSWORD=PASSWORD
PASSWORD=PW5JGe4WsTPGrjnMzkGd4wfVdzoHCEySgbyq2WBWGAxSfevbXqAG4
SERVER_SECRET=SECRET
SERVER_URL=http://127.0.0.1:2998
MONGO_URI=mongodb://127.0.0.1:27017/cooperative-x
+8
View File
@@ -3,6 +3,14 @@
All notable changes to this project will be documented in this file.
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
## [2.2.10](https://github.com/coopenomics/mono/compare/v2.2.9...v2.2.10) (2025-03-27)
**Note:** Version bump only for package @coopenomics/boot
## [2.2.9](https://github.com/coopenomics/mono/compare/v2.2.8...v2.2.9) (2025-03-12)
**Note:** Version bump only for package @coopenomics/boot
+3 -1
View File
@@ -1,7 +1,7 @@
{
"name": "@coopenomics/boot",
"type": "module",
"version": "2.2.9",
"version": "2.2.10",
"private": true,
"packageManager": "pnpm@9.0.6",
"description": "",
@@ -11,6 +11,8 @@
"scripts": {
"enter": "./scripts/enter.sh",
"cli": "esno src/index.ts",
"cleos": "esno src/index.ts cleos",
"unlock": "esno src/index.ts unlock",
"boot": "esno src/index.ts boot",
"clear": "esno src/index.ts clear",
"start": "./scripts/restart.sh",
+21 -34
View File
@@ -1,38 +1,25 @@
import type { Container } from "dockerode"
import { findContainerByName } from "./find"
import { runContainer } from "./run"
import { exec } from 'node:child_process'
import { promisify } from 'node:util'
export async function execCommand(command: string[]): Promise<string> {
const container = await runContainer(true)
const execAsync = promisify(exec)
const exec = await container.exec({
Cmd: command,
AttachStdout: true,
AttachStderr: true,
})
export async function execCommand(command: string[]): Promise<void> {
const fullCmd = ['docker', 'compose', 'exec', 'node', ...command].join(' ')
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)
})
})
})
try {
// eslint-disable-next-line node/prefer-global/process
const { stdout, stderr } = await execAsync(fullCmd, { env: process.env })
if (stdout)
console.log(stdout.trim())
if (stderr)
console.error(stderr.trim())
}
catch (err: any) {
if (err.stdout)
console.log(err.stdout.trim())
if (err.stderr)
console.error(err.stderr.trim())
// опционально:
// console.error(`Command failed with code ${err.code}`)
}
}
+8
View File
@@ -6,6 +6,14 @@ export async function clearDB(): Promise<void> {
// eslint-disable-next-line node/prefer-global/process
await mongoose.connect(process.env.MONGO_URI as string)
try {
await mongoose.connection.collection('users').deleteMany({})
console.log('Все документы удалены из коллекции users')
}
catch (e) {
console.error('Ошибка при удалении:', e)
}
try {
await mongoose.connection.collection('sync').deleteMany({})
console.log('Все документы удалены из коллекции sync')
+10 -16
View File
@@ -31,17 +31,11 @@ program.version('0.1.0')
// Команда для запуска команды в контейнере
program
.command('cleos <cmd...>')
.command('cleos [cmd...]')
.description('Execute a cleos command in a Node container')
.allowUnknownOption()
.action(async (cmd: string[]) => {
try {
console.log(cmd)
await execCommand(['cleos', ...cmd])
}
catch (error) {
console.error('Command execution failed:', error)
}
.action(async (cmd: string[] = []) => {
await execCommand(['cleos', ...cmd])
})
// Команда для запуска команды в контейнере
@@ -54,14 +48,8 @@ program
.action(async (cmd: string, options: any) => {
try {
const { target, network } = options
await deleteFile(keosdPath)
await execCommand([
'cleos',
'wallet',
'unlock',
'--password',
process.env.PASSWORD!,
])
await deployCommand(cmd, target, network)
}
catch (error) {
@@ -126,6 +114,12 @@ program
.action(async () => {
try {
await stopContainerByName('node')
}
catch (e) {
console.log('Нет контейнера для остановки. Стартуем новый..')
}
try {
await clearDirectory(basePath)
await clearDB()
await runContainer()
+3 -3
View File
@@ -157,7 +157,7 @@ export async function startInfra() {
position: 'Председатель',
based_on: 'Решение общего собрания №1',
},
country: 'Russia',
country: 'Российская Федерация',
city: 'Москва',
fact_address: '117593 г. Москва, муниципальный округ Ясенево, проезд Соловьиный, дом 1, помещение 1/1',
full_address:
@@ -202,7 +202,7 @@ export async function startInfra() {
first_name: 'Иван',
last_name: 'Иванов',
middle_name: 'Иванович',
birthdate: '2023-04-01',
birthdate: '1990/04/01',
phone: '+71234567890',
email: 'ivanov@example.com',
full_address: 'Переулок Правды д. 1',
@@ -210,7 +210,7 @@ export async function startInfra() {
series: 7122,
number: 112233,
issued_by: 'отделом УФМС по г. Москва',
issued_at: '22.04.2010',
issued_at: '2010/05/10',
code: '111-232',
},
}
+306 -312
View File
@@ -17,7 +17,7 @@ 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 { capitalProgramId, ratePerHour, sourceProgramId, walletProgramId } from './capital/consts'
import { withdrawContribution } from './capital/withdrawContribution'
import { registerExpense } from './capital/registerExpense'
@@ -87,8 +87,8 @@ afterAll(() => {
})
describe('тест контракта CAPITAL', () => {
it('создаём целевую потребительскую программу', async () => {
const program = await getCoopProgramWallet(blockchain, 'voskhod', capitalProgramId)
it('создаём программу генерации', async () => {
const program = await getCoopProgramWallet(blockchain, 'voskhod', sourceProgramId)
if (!program) {
const data: SovietContract.Actions.Programs.CreateProgram.ICreateProgram = {
coopname: 'voskhod',
@@ -103,7 +103,53 @@ describe('тест контракта CAPITAL', () => {
fixed_membership_contribution: '0.0000 RUB',
membership_percent_fee: '0',
meta: '',
type: 'cofund',
type: 'source',
}
const result = await blockchain.api.transact(
{
actions: [
{
account: SovietContract.contractName.production,
name: SovietContract.Actions.Programs.CreateProgram.actionName,
authorization: [
{
actor: 'ant',
permission: 'active',
},
],
data,
},
],
},
{
blocksBehind: 3,
expireSeconds: 30,
},
)
getTotalRamUsage(result)
expect(result.transaction_id).toBeDefined()
}
})
it('создаём программу капитализации', async () => {
const program = await getCoopProgramWallet(blockchain, 'voskhod', capitalProgramId)
if (!program) {
const data: SovietContract.Actions.Programs.CreateProgram.ICreateProgram = {
coopname: 'voskhod',
is_can_coop_spend_share_contributions: false,
username: 'ant',
title: 'Капитализация',
announce: '',
description: '',
preview: '',
images: '',
calculation_type: 'free',
fixed_membership_contribution: '0.0000 RUB',
membership_percent_fee: '0',
meta: '',
type: 'capital',
}
const result = await blockchain.api.transact(
@@ -180,7 +226,7 @@ describe('тест контракта CAPITAL', () => {
it('создаём проект', async () => {
const hash = generateRandomSHA256()
const parehtHash = '0000000000000000000000000000000000000000000000000000000000000000'
const parentHash = '0000000000000000000000000000000000000000000000000000000000000000'
const data: CapitalContract.Actions.CreateProject.ICreateProject = {
coopname: 'voskhod',
@@ -188,7 +234,7 @@ describe('тест контракта CAPITAL', () => {
title: `Идея ${hash.slice(0, 10)}`,
description: `Описание ${hash.slice(0, 10)}`,
project_hash: hash,
parent_project_hash: parehtHash,
parent_project_hash: parentHash,
parent_distribution_ratio: 0,
terms: '',
subject: '',
@@ -403,7 +449,7 @@ describe('тест контракта CAPITAL', () => {
console.log('wallet investor1: ', wallet)
}
{
const { depositId, program, userWallet } = await depositToWallet(blockchain, 'voskhod', investor1, 10000)
const { depositId, program, userWallet } = await depositToWallet(blockchain, 'voskhod', investor1, 100000)
}
})
@@ -435,7 +481,7 @@ describe('тест контракта CAPITAL', () => {
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.capitalists_bonus).toBe('48540.0000 RUB')
expect(finalResult.total_amount).toBe('78540.0000 RUB')
})
@@ -447,60 +493,10 @@ describe('тест контракта CAPITAL', () => {
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.capitalists_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)
@@ -560,276 +556,274 @@ describe('тест контракта CAPITAL', () => {
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()
/// ____________
it('завершаем цикл и стартуем распределение', async () => {
const data: CapitalContract.Actions.StartDistribution.IStart = {
coopname: 'voskhod',
application: 'voskhod',
result_hash: result1.result_hash,
}
// const project = (await blockchain.getTableRows(
// CapitalContract.contractName.production,
// 'voskhod',
// 'projects',
// 1,
// project1.project_hash,
// project1.project_hash,
// 3,
// 'sha256',
// ))[0]
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,
},
)
// expect(project).toBeDefined()
// expect(project.authors_count).toBe(2)
// expect(project.authors_shares).toBe(200)
// })
getTotalRamUsage(result)
expect(result.transaction_id).toBeDefined()
// 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',
// }
const blockchainResult = (await blockchain.getTableRows(
CapitalContract.contractName.production,
'voskhod',
'results',
1,
result1.result_hash,
result1.result_hash,
2,
'sha256',
))[0]
// 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()
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('opened')
})
// // Добавляем третьего создателя
// data = {
// coopname: 'voskhod',
// application: 'voskhod',
// result_hash: result1.result_hash,
// creator: tester3,
// used: '100.0000 RUB',
// }
it('обновляем капитал первого создателя в результате', async () => {
const data: CapitalContract.Actions.CreateClaim.ICreateClaim = {
coopname: 'voskhod',
application: 'voskhod',
result_hash: result1.result_hash,
username: tester1,
}
// 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 result = await blockchain.api.transact(
{
actions: [
{
account: CapitalContract.contractName.production,
name: CapitalContract.Actions.CreateClaim.actionName,
authorization: [
{
actor: 'voskhod',
permission: 'active',
},
],
data,
},
],
},
{
blocksBehind: 3,
expireSeconds: 30,
},
)
getTotalRamUsage(result)
expect(result.transaction_id).toBeDefined()
// // Проверяем финальные значения
// const blockchainResult = (await blockchain.getTableRows(
// CapitalContract.contractName.production,
// 'voskhod',
// 'results',
// 1,
// result1.result_hash,
// result1.result_hash,
// 2,
// 'sha256',
// ))[0]
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')
// })
expect(blockchainResult).toBeDefined()
console.log('blockchainResult: ', blockchainResult)
})
// it('удаляем создателя tester3', async () => {
// const data: CapitalContract.Actions.DelCreator.IDelCreator = {
// coopname: 'voskhod',
// application: 'voskhod',
// result_hash: result1.result_hash,
// creator: tester3,
// }
it('обновляем капитал второго создателя в результате', async () => {
const data: CapitalContract.Actions.CreateClaim.ICreateClaim = {
coopname: 'voskhod',
application: 'voskhod',
result_hash: result1.result_hash,
username: tester2,
}
// 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 result = await blockchain.api.transact(
{
actions: [
{
account: CapitalContract.contractName.production,
name: CapitalContract.Actions.CreateClaim.actionName,
authorization: [
{
actor: 'voskhod',
permission: 'active',
},
],
data,
},
],
},
{
blocksBehind: 3,
expireSeconds: 30,
},
)
getTotalRamUsage(result)
expect(result.transaction_id).toBeDefined()
// // Проверяем обновленные значения после удаления
// const blockchainResult = (await blockchain.getTableRows(
// CapitalContract.contractName.production,
// 'voskhod',
// 'results',
// 1,
// result1.result_hash,
// result1.result_hash,
// 2,
// 'sha256',
// ))[0]
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
// })
expect(blockchainResult).toBeDefined()
console.log('blockchainResult: ', blockchainResult)
})
// it('стартуем распределение долей результата', async () => {
// const data: CapitalContract.Actions.Start.IStart = {
// coopname: 'voskhod',
// application: 'voskhod',
// result_hash: result1.result_hash,
// }
it('повторно обновляем капитал второго создателя в результате и ожидаем ошибку', async () => {
const data: CapitalContract.Actions.CreateClaim.ICreateClaim = {
coopname: 'voskhod',
application: 'voskhod',
result_hash: result1.result_hash,
username: tester2,
}
// 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()
try {
await sleep(1000)
await blockchain.api.transact(
{
actions: [
{
account: CapitalContract.contractName.production,
name: CapitalContract.Actions.CreateClaim.actionName,
authorization: [
{
actor: 'voskhod',
permission: 'active',
},
],
data,
},
],
},
{
blocksBehind: 3,
expireSeconds: 30,
},
)
throw new Error('Ожидалась ошибка, но транзакция прошла успешно')
}
catch (error: any) {
const message = error.json?.error?.details?.[0]?.message
expect(message).toMatch(/Клайм уже существует/i)
}
})
// const blockchainResult = (await blockchain.getTableRows(
// CapitalContract.contractName.production,
// 'voskhod',
// 'results',
// 1,
// result1.result_hash,
// result1.result_hash,
// 2,
// 'sha256',
// ))[0]
it('обновляем капитал инвестора в результате', async () => {
const data: CapitalContract.Actions.CreateClaim.ICreateClaim = {
coopname: 'voskhod',
application: 'voskhod',
result_hash: result1.result_hash,
username: investor1,
}
// expect(blockchainResult).toBeDefined()
// expect(blockchainResult.status).toBe('started')
// })
const result = await blockchain.api.transact(
{
actions: [
{
account: CapitalContract.contractName.production,
name: CapitalContract.Actions.CreateClaim.actionName,
authorization: [
{
actor: 'voskhod',
permission: 'active',
},
],
data,
},
],
},
{
blocksBehind: 3,
expireSeconds: 30,
},
)
getTotalRamUsage(result)
expect(result.transaction_id).toBeDefined()
// it('пишем заявления и получаем NFT', async () => {
// const data: CapitalContract.Actions.SetStatement.ISetStatement = {
// coopname: 'voskhod',
// application: 'voskhod',
// statement: fakeDocument,
// nft_hash: generateRandomSHA256(),
// }
const blockchainResult = (await blockchain.getTableRows(
CapitalContract.contractName.production,
'voskhod',
'results',
1,
result1.result_hash,
result1.result_hash,
2,
'sha256',
))[0]
// 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()
// })
expect(blockchainResult).toBeDefined()
console.log('investorResult: ', blockchainResult)
})
it('повторно обновляем капитал инвестора в результате и ожидаем ошибку', async () => {
const data: CapitalContract.Actions.CreateClaim.ICreateClaim = {
coopname: 'voskhod',
application: 'voskhod',
result_hash: result1.result_hash,
username: investor1,
}
try {
await sleep(1000)
await blockchain.api.transact(
{
actions: [
{
account: CapitalContract.contractName.production,
name: CapitalContract.Actions.CreateClaim.actionName,
authorization: [
{
actor: 'voskhod',
permission: 'active',
},
],
data,
},
],
},
{
blocksBehind: 3,
expireSeconds: 30,
},
)
throw new Error('Ожидалась ошибка, но транзакция прошла успешно')
}
catch (error: any) {
const message = error.json?.error?.details?.[0]?.message
expect(message).toMatch(/Клайм уже существует/i)
}
})
})
@@ -1,8 +1,9 @@
import { expect } from 'vitest'
import { CapitalContract } from 'cooptypes'
import { CapitalContract, SovietContract } from 'cooptypes'
import { getTotalRamUsage } from '../../utils/getTotalRamUsage'
import { generateRandomSHA256 } from '../../utils/randomHash'
import { fakeDocument } from '../soviet/fakeDocument'
import { processDecision } from '../soviet/processDecision'
import { ratePerHour } from './consts'
export async function commitToResult(
@@ -63,7 +64,7 @@ export async function commitToResult(
result_hash: resultHash,
creator,
commit_hash: commitHash,
specification: fakeDocument,
contribution_statement: fakeDocument,
contributed_hours: spendHours,
}
@@ -112,7 +113,7 @@ export async function commitToResult(
application: coopname,
commit_hash: commitHash,
approver: 'ant',
approved_specification: fakeDocument,
approved_statement: fakeDocument,
}
console.log(`\n✅ Подтверждение коммита ${commitHash}`)
@@ -153,6 +154,82 @@ export async function commitToResult(
expect(blockchainCommit.commit_hash).toBe(commitHash)
expect(blockchainCommit.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)
{
// Утверждение коммита
const act1Data: CapitalContract.Actions.SetAct1.ISetAct1 = {
coopname,
application: coopname,
username: creator,
commit_hash: commitHash,
act: fakeDocument,
}
console.log(`\n✅ Установка акта1 по коммиту ${commitHash}`)
const act1Result = await blockchain.api.transact(
{
actions: [
{
account: CapitalContract.contractName.production,
name: CapitalContract.Actions.SetAct1.actionName,
authorization: [{ actor: coopname, permission: 'active' }],
data: act1Data,
},
],
},
{
blocksBehind: 3,
expireSeconds: 30,
},
)
getTotalRamUsage(act1Result)
expect(act1Result.transaction_id).toBeDefined()
}
{
// Утверждение коммита
const act2Data: CapitalContract.Actions.SetAct2.ISetAct2 = {
coopname,
application: coopname,
username: creator,
commit_hash: commitHash,
act: fakeDocument,
}
console.log(`\n✅ Установка акта2 по коммиту ${commitHash}`)
const act2Result = await blockchain.api.transact(
{
actions: [
{
account: CapitalContract.contractName.production,
name: CapitalContract.Actions.SetAct2.actionName,
authorization: [{ actor: coopname, permission: 'active' }],
data: act2Data,
},
],
},
{
blocksBehind: 3,
expireSeconds: 30,
},
)
getTotalRamUsage(act2Result)
expect(act2Result.transaction_id).toBeDefined()
}
// Проверка результата после утверждения коммита
const finalResult = (await blockchain.getTableRows(
CapitalContract.contractName.production,
@@ -192,12 +269,12 @@ export async function commitToResult(
console.log('▶ Проект:', finalProject)
console.log('▶ Контрибьютор:', finalContributor)
expect(parseFloat(finalResult.spend)).toBe(parseFloat(prevResult.spend) + parseFloat(totalSpended))
expect(parseFloat(finalProject.spend)).toBe(parseFloat(prevProject.spend))
// expect(parseFloat(finalResult.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))
// 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} завершен успешно!`)
+4 -1
View File
@@ -1,3 +1,6 @@
export const capitalProgramId = 3
export const sourceProgramId = 3
export const capitalProgramId = 4
export const walletProgramId = 1
export const ratePerHour = '1000.0000 RUB'
export const sourceProgramName = 'source'
export const capitalProgramName = 'capital'
@@ -4,7 +4,7 @@ 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'
import { capitalProgramId, sourceProgramId } from './consts'
export async function investInProject(
blockchain: any,
@@ -1,7 +1,7 @@
import { expect } from 'vitest'
import { signAgreement } from '../soviet/signAgreement'
import { getCoopProgramWallet, getUserProgramWallet } from '../wallet/walletUtils'
import { capitalProgramId } from './consts'
import { capitalProgramName, sourceProgramId } from './consts'
export async function signCapitalAgreement(
blockchain: any,
@@ -9,20 +9,20 @@ export async function signCapitalAgreement(
username: string,
fakeDocument: any,
) {
const txId = await signAgreement(blockchain, coopname, username, 'cofund', fakeDocument)
const txId = await signAgreement(blockchain, coopname, username, capitalProgramName, fakeDocument)
const wallet = await getUserProgramWallet(blockchain, coopname, username, capitalProgramId)
const wallet = await getUserProgramWallet(blockchain, coopname, username, sourceProgramId)
expect(wallet).toEqual(expect.objectContaining({
coopname,
username,
available: expect.any(String),
blocked: expect.any(String),
program_id: capitalProgramId,
program_id: sourceProgramId,
membership_contribution: expect.any(String),
}))
const program = await getCoopProgramWallet(blockchain, coopname, capitalProgramId)
const program = await getCoopProgramWallet(blockchain, coopname, sourceProgramId)
return { wallet, program, txId }
}
@@ -0,0 +1,28 @@
import { expect } from 'vitest'
import { signAgreement } from '../soviet/signAgreement'
import { getCoopProgramWallet, getUserProgramWallet } from '../wallet/walletUtils'
import { sourceProgramId, sourceProgramName } from './consts'
export async function signGenerationAgreement(
blockchain: any,
coopname: string,
username: string,
fakeDocument: any,
) {
const txId = await signAgreement(blockchain, coopname, username, sourceProgramName, fakeDocument)
const wallet = await getUserProgramWallet(blockchain, coopname, username, sourceProgramId)
expect(wallet).toEqual(expect.objectContaining({
coopname,
username,
available: expect.any(String),
blocked: expect.any(String),
program_id: sourceProgramId,
membership_contribution: expect.any(String),
}))
const program = await getCoopProgramWallet(blockchain, coopname, sourceProgramId)
return { wallet, program, txId }
}
@@ -44,15 +44,14 @@ export async function withdrawContribution(
console.log('▶ Проект:', prevProject)
// Создание заявления на возврат
const createWithdrawData: CapitalContract.Actions.CreateWithdraw1.ICreateWithdraw = {
const createWithdrawData: CapitalContract.Actions.WithdrawResult.IWithdrawFromResult = {
coopname,
application: coopname,
username,
result_hash: resultHash,
withdraw_hash: withdrawHash,
commit_hashes: commitHashes,
contribution_statement: fakeDocument,
return_statement: fakeDocument,
amount: withdrawAmount,
}
console.log(`\n🚀 Отправка транзакции CreateWithdraw для ${username} на сумму ${withdrawAmount}`)
@@ -61,7 +60,7 @@ export async function withdrawContribution(
actions: [
{
account: CapitalContract.contractName.production,
name: CapitalContract.Actions.CreateWithdraw1.actionName,
name: CapitalContract.Actions.WithdrawResult.actionName,
authorization: [{ actor: coopname, permission: 'active' }],
data: createWithdrawData,
},
@@ -79,7 +78,7 @@ export async function withdrawContribution(
let blockchainWithdraw = (await blockchain.getTableRows(
CapitalContract.contractName.production,
coopname,
'withdraws',
CapitalContract.Tables.ResultWithdraws.tableName,
1,
withdrawHash,
withdrawHash,
@@ -93,12 +92,11 @@ export async function withdrawContribution(
expect(blockchainWithdraw.amount).toBe(withdrawAmount)
// Подтверждение возврата
const approveWithdrawData: CapitalContract.Actions.ApproveWithdraw.IApproveWithdraw = {
const approveWithdrawData: CapitalContract.Actions.ApproveWithdrawResult.IApproveWithdrawResult = {
coopname,
application: coopname,
approver: 'ant',
withdraw_hash: withdrawHash,
approved_contribution_statement: fakeDocument,
approved_return_statement: fakeDocument,
}
@@ -108,7 +106,7 @@ export async function withdrawContribution(
actions: [
{
account: CapitalContract.contractName.production,
name: CapitalContract.Actions.ApproveWithdraw.actionName,
name: CapitalContract.Actions.ApproveWithdrawResult.actionName,
authorization: [{ actor: coopname, permission: 'active' }],
data: approveWithdrawData,
},
@@ -126,7 +124,7 @@ export async function withdrawContribution(
blockchainWithdraw = (await blockchain.getTableRows(
CapitalContract.contractName.production,
coopname,
'withdraws',
CapitalContract.Tables.ResultWithdraws.tableName,
1,
withdrawHash,
withdrawHash,
@@ -146,17 +144,15 @@ export async function withdrawContribution(
1000,
)
const lastDecision = decisions[decisions.length - 1]
const prevLastDecision = decisions[decisions.length - 2]
console.log(`\n📜 Выполнение решений: ${prevLastDecision.id}, ${lastDecision.id}`)
console.log(`\n📜 Выполнение решения: ${lastDecision.id}`)
await processDecision(blockchain, prevLastDecision.id)
await processDecision(blockchain, lastDecision.id)
blockchainWithdraw = (await blockchain.getTableRows(
CapitalContract.contractName.production,
coopname,
'withdraws',
CapitalContract.Tables.ResultWithdraws.tableName,
1,
withdrawHash,
withdrawHash,
@@ -203,7 +199,9 @@ export async function withdrawContribution(
expect(parseFloat(programWallet.blocked)).toBe(parseFloat(prevProgramWallet.blocked))
// Проверка изменения spend в проекте
expect(parseFloat(finalProject.spend)).toBe(parseFloat(prevProject.spend) + parseFloat(withdrawAmount))
expect(parseFloat(finalProject.withdrawed)).toBe(parseFloat(prevProject.withdrawed) + parseFloat(withdrawAmount))
expect(parseFloat(finalProject.spend)).toBe(parseFloat(prevProject.spend))
console.log(`\n✅ Возврат на ${withdrawAmount} завершен успешно!`)
@@ -83,6 +83,7 @@ export async function depositToWallet(blockchain: any, coopname: string, usernam
const program = await getCoopProgramWallet(blockchain, coopname, 1)
const userWallet = await getUserProgramWallet(blockchain, coopname, username, 1)
console.log('▶ Кошелёк пользователя после пополнения: ', userWallet)
// Проверяем изменение балансов
compareTokenAmounts(prevUserWalletAvailable, userWallet.available, amount)
+2
View File
@@ -0,0 +1,2 @@
eosio-wallet/wallet.lock
eosio-wallet/keosd.sock
+8
View File
@@ -0,0 +1,8 @@
# Change Log
All notable changes to this project will be documented in this file.
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
## [2.2.10](https://github.com/coopenomics/mono/compare/v2.2.9...v2.2.10) (2025-03-27)
**Note:** Version bump only for package @coopenomics/cleos
+54
View File
@@ -0,0 +1,54 @@
# The filename (relative to data-dir) to create a unix socket for HTTP RPC; set blank to disable. (eosio::http_plugin)
# unix-socket-path = keosd.sock
# The local IP and port to listen for incoming http connections; setting to http-category-address to enable http-category-address option. leave blank to disable. (eosio::http_plugin)
# http-server-address =
# Specify the Access-Control-Allow-Origin to be returned on each request (eosio::http_plugin)
# access-control-allow-origin =
# Specify the Access-Control-Allow-Headers to be returned on each request (eosio::http_plugin)
# access-control-allow-headers =
# Specify the Access-Control-Max-Age to be returned on each request. (eosio::http_plugin)
# access-control-max-age =
# Specify if Access-Control-Allow-Credentials: true should be returned on each request. (eosio::http_plugin)
# access-control-allow-credentials = false
# The maximum body size in bytes allowed for incoming RPC requests (eosio::http_plugin)
# max-body-size = 2097152
# Maximum size in megabytes http_plugin should use for processing http requests. -1 for unlimited. 503 error response when exceeded. (eosio::http_plugin)
# http-max-bytes-in-flight-mb = 500
# Maximum number of requests http_plugin should use for processing http requests. 503 error response when exceeded. (eosio::http_plugin)
# http-max-in-flight-requests = -1
# Maximum time on main thread for processing a request, -1 for unlimited (eosio::http_plugin)
# http-max-response-time-ms = 15
# Append the error log to HTTP responses (eosio::http_plugin)
# verbose-http-errors = false
# If set to false, then any incoming "Host" header is considered valid (eosio::http_plugin)
# http-validate-host = true
# Additionally acceptable values for the "Host" header of incoming HTTP requests, can be specified multiple times. Includes http/s_server_address by default. (eosio::http_plugin)
# http-alias =
# Number of worker threads in http thread pool (eosio::http_plugin)
# http-threads = 2
# If set to false, do not keep HTTP connections alive, even if client requests. (eosio::http_plugin)
# http-keep-alive = true
# The path of the wallet files (absolute path or relative to application data dir) (eosio::wallet_plugin)
# wallet-dir = "."
# Timeout for unlocked wallet in seconds (default 900 (15 minutes)). Wallets will automatically lock after specified number of seconds of inactivity. Activity is defined as any wallet command e.g. list-wallets. (eosio::wallet_plugin)
# unlock-timeout = 900
# Plugin(s) to enable, may be specified multiple times
# plugin =
@@ -0,0 +1,3 @@
{
"cipher_keys": "710a43f09ece89ed7baf387cc1ae3127cb90d9fc16cffda660c71c75678d1fe4d8b22e1fd0476e232581a37e3c3beda3e25b873ae0a9d43c274f30b4d9ea394f4c583234a6d0715540163edc28db22de98b0aa7e9431ebfc6f28b1eaf665326d7456b55f1fa776e7eac61d90264871e6a58b3ebbd8dec377e05ef7fec64b348aef02459329f49d1384bf2af32fd02ce1"
}
+1
View File
@@ -0,0 +1 @@
PW5JGe4WsTPGrjnMzkGd4wfVdzoHCEySgbyq2WBWGAxSfevbXqAG4
+12
View File
@@ -0,0 +1,12 @@
{
"name": "@coopenomics/cleos",
"version": "2.2.10",
"private": true,
"description": "",
"scripts": {
"cleos": "./run.sh"
},
"keywords": [],
"author": "",
"license": "ISC"
}
+7
View File
@@ -0,0 +1,7 @@
docker run --rm -it --name cleos \
--network dicoop \
--volume ./eosio-wallet:/root/eosio-wallet \
--volume ./scripts:/root/scripts \
-w /root/scripts \
dicoop/blockchain_v5.1.1:dev /bin/bash
+5
View File
@@ -0,0 +1,5 @@
ls
exit
ls
./cleos.sh
exit
+3
View File
@@ -0,0 +1,3 @@
#!/bin/bash
cleos -u http://node:8888 "$@"
+2
View File
@@ -0,0 +1,2 @@
#!/bin/bash
rm ../eosio-wallet/keosd.sock
+3
View File
@@ -0,0 +1,3 @@
#!/bin/bash
cleos wallet unlock --name default < ../eosio-wallet/password
BIN
View File
Binary file not shown.
+8
View File
@@ -3,6 +3,14 @@
All notable changes to this project will be documented in this file.
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
## [2.2.10](https://github.com/coopenomics/mono/compare/v2.2.9...v2.2.10) (2025-03-27)
**Note:** Version bump only for package @coopenomics/contracts
## [2.2.9](https://github.com/coopenomics/mono/compare/v2.2.8...v2.2.9) (2025-03-12)
**Note:** Version bump only for package @coopenomics/contracts
Binary file not shown.
Binary file not shown.
+143 -61
View File
@@ -8,44 +8,54 @@
#include "src/investment/approveinvst.cpp"
#include "src/investment/capauthinvst.cpp"
#include "src/managment/init.cpp"
#include "src/claim/setact1.cpp"
#include "src/claim/setact2.cpp"
#include "src/claim/approveclaim.cpp"
#include "src/claim/createclaim.cpp"
#include "src/claim/setstatement.cpp"
#include "src/claim/authorize.cpp"
#include "src/claim/claimnow.cpp"
#include "src/claim/capauthclaim.cpp"
#include "src/registration/capregcontr.cpp"
#include "src/registration/approvereg.cpp"
#include "src/registration/regcontrib.cpp"
#include "src/managment/init.cpp"
#include "src/managment/createproj.cpp"
#include "src/managment/addauthor.cpp"
#include "src/managment/allocate.cpp"
#include "src/managment/diallocate.cpp"
#include "src/managment/wthdrcallbck.cpp"
#include "src/commit/createcmmt.cpp"
#include "src/commit/approvecmmt.cpp"
#include "src/commit/capauthcmmt.cpp"
#include "src/commit/setact1.cpp"
#include "src/commit/setact2.cpp"
#include "src/withdraw_from_result/createwthd1.cpp"
#include "src/withdraw_from_result/capauthwthdc.cpp"
#include "src/withdraw_from_result/capauthwthdr.cpp"
#include "src/withdraw_from_result/authwithdrw1.cpp"
#include "src/withdraw_from_result/capauthwthd1.cpp"
#include "src/withdraw_from_result/approvewthd1.cpp"
#include "src/withdraw_from_project/createwthd2.cpp"
#include "src/withdraw_from_project/capauthwthd2.cpp"
#include "src/withdraw_from_project/approvewthd2.cpp"
#include "src/withdraw_from_program/createwthd3.cpp"
#include "src/withdraw_from_program/capauthwthd3.cpp"
#include "src/withdraw_from_program/approvewthd3.cpp"
#include "src/convert/approvecnvrt.cpp"
#include "src/convert/createcnvrt.cpp"
#include "src/expense/approveexpns.cpp"
#include "src/expense/capauthexpns.cpp"
#include "src/expense/createexpnse.cpp"
#include "src/expense/expense_withdraw_callback.cpp"
#include "src/fund/fund.cpp"
#include "src/fund/refresh.cpp"
#include "src/fundproj/fundproj.cpp"
#include "src/fundproj/refreshproj.cpp"
#include "src/fundprog/fundprog.cpp"
#include "src/fundprog/refreshprog.cpp"
#include <optional>
@@ -53,47 +63,33 @@
// void capital::reduce_shares(name coopname, checksum256 project_hash, name username, asset amount) {
// require_auth(_capital);
// auto exist_project = get_project(coopname, project_hash);
// eosio::check(exist_project.has_value(), "Проект не найден");
// project_index projects(_capital, coopname.value);
// auto project = projects.find(exist_project->id);
// contributor_index contributors(_capital, coopname.value);
// auto idx = contributors.get_index<"byusername"_n>();
// auto itr = idx.find(username.value);
// eosio::check(itr != idx.end(), "Contributor not found");
// eosio::check(itr->share_balance >= amount, "Недостаточно долей для уменьшения");
// int64_t prev_total_shares = project->membership_total_shares.amount;
// int64_t new_total_shares = prev_total_shares - amount.amount;
// eosio::check(new_total_shares >= 0, "Нельзя уменьшить total_shares ниже 0");
// // Пересчёт cumulative_reward_per_share для корректного распределения будущих выплат
// if (new_total_shares > 0) {
// projects.modify(project, coopname, [&](auto &p) {
// p.membership_cumulative_reward_per_share =
// (p.membership_cumulative_reward_per_share * prev_total_shares) / new_total_shares;
// p.membership_total_shares -= amount;
// });
// } else {
// // Если все доли исчезли, просто обнуляем
// projects.modify(project, coopname, [&](auto &p) {
// p.membership_cumulative_reward_per_share = 0;
// p.membership_total_shares = asset(0, _root_govern_symbol);
// });
// }
// // Уменьшаем долю пользователя
// auto primary_itr = contributors.find(itr->id);
// contributors.modify(primary_itr, same_payer, [&](auto &c) {
// c.share_balance -= amount;
// });
// }
void capital::validate_project_hierarchy_depth(eosio::name coopname, checksum256 project_hash) {
uint8_t level = 0;
project_index projects(_capital, coopname.value);
auto current_project = get_project(coopname, project_hash);
eosio::check(current_project.has_value(), "Проект не найден");
while (current_project -> parent_project_hash != checksum256()) {
eosio::check(level < 12, "Превышено максимальное количество уровней родительских проектов (12)");
current_project = get_project(coopname, current_project->parent_project_hash);
eosio::check(current_project.has_value(), "Родительский проект не найден");
level++;
};
};
/**
* @brief Получает расход по хэшу.
* @param coopname Имя кооператива (scope таблицы).
@@ -201,6 +197,20 @@ std::optional<contributor> capital::get_active_contributor_or_fail(eosio::name c
return contributor;
}
std::optional<capital_tables::capitalist> capital::get_capitalist(eosio::name coopname, eosio::name username) {
capital_tables::capitalist_index capitalists(_capital, coopname.value);
auto itr = capitalists.find(username.value);
if (itr == capitalists.end()) {
return std::nullopt;
}
return *itr;
}
program capital::get_capital_program_or_fail(eosio::name coopname) {
auto program_id = get_program_id(_capital_program);
@@ -209,21 +219,34 @@ program capital::get_capital_program_or_fail(eosio::name coopname) {
}
program capital::get_cofund_program_or_fail(eosio::name coopname) {
auto program_id = get_program_id(_cofund_program);
program capital::get_source_program_or_fail(eosio::name coopname) {
auto program_id = get_program_id(_source_program);
auto program = get_program_or_fail(coopname, program_id);
return program;
};
int64_t capital::get_capital_program_share_balance(eosio::name coopname) {
auto capital_program = get_capital_program_or_fail(coopname);
return capital_program.available -> amount + capital_program.blocked -> amount;
};
int64_t capital::get_capital_user_share_balance(eosio::name coopname, eosio::name username) {
auto wallet = get_capital_wallet(coopname, username);
eosio::check(wallet.has_value(), "Кошелёк пайщика в программе не найден");
return wallet -> available.amount + wallet -> blocked -> amount;
}
std::optional<progwallet> capital::get_capital_wallet(eosio::name coopname, eosio::name username) {
auto state = get_global_state(coopname);
programs_index programs(_soviet, coopname.value);
auto program = programs.find(state.program_id);
eosio::check(program != programs.end(), "Программа капитализации не найдена");
auto program_id = get_program_id(_capital_program);
auto capital_wallet = get_program_wallet(coopname, username, state.program_id);
auto program = get_program_or_fail(coopname, program_id);
auto capital_wallet = get_program_wallet(coopname, username, _capital_program);
if (!capital_wallet.has_value()) {
return std::nullopt;
@@ -288,6 +311,13 @@ std::optional<result> capital::get_result(eosio::name coopname, const checksum25
return *result_itr;
}
result capital::get_result_or_fail(eosio::name coopname, const checksum256 &result_hash, const char* msg) {
auto maybe_result = get_result(coopname, result_hash);
eosio::check(maybe_result.has_value(), msg);
return *maybe_result;
}
std::optional<project> capital::get_project(eosio::name coopname, const checksum256 &project_hash) {
project_index projects(_capital, coopname.value);
auto project_hash_index = projects.get_index<"byhash"_n>();
@@ -328,6 +358,20 @@ std::optional<capital_tables::result_withdraw> capital::get_result_withdraw(eosi
}
std::optional<capital_tables::program_withdraw> capital::get_program_withdraw(eosio::name coopname, const checksum256 &hash) {
capital_tables::program_withdraws_index program_withdraws(_capital, coopname.value);
auto index = program_withdraws.get_index<"byhash"_n>();
auto itr = index.find(hash);
if (itr == index.end()) {
return std::nullopt;
}
return *itr;
}
std::optional<capital_tables::project_withdraw> capital::get_project_withdraw(eosio::name coopname, const checksum256 &hash) {
capital_tables::project_withdraws_index project_withdraws(_capital, coopname.value);
auto index = project_withdraws.get_index<"byhash"_n>();
@@ -342,17 +386,55 @@ std::optional<capital_tables::project_withdraw> capital::get_project_withdraw(eo
}
std::optional<claim> capital::get_claim(eosio::name coopname, const checksum256 &claim_hash) {
std::optional<claim> capital::get_claim(eosio::name coopname, const checksum256 &result_hash, eosio::name username) {
claim_index claims(_capital, coopname.value);
auto claim_hash_index = claims.get_index<"byhash"_n>();
auto idx = claims.get_index<"byresuser"_n>();
auto rkey = combine_checksum_ids(result_hash, username);
auto claim_itr = claim_hash_index.find(claim_hash);
auto it = idx.find(rkey);
if (it == idx.end()) {
return std::nullopt;
}
return *it;
}
if (claim_itr == claim_hash_index.end()) {
std::optional<convert> capital::get_convert(eosio::name coopname, const checksum256 &hash) {
convert_index converts(_capital, coopname.value);
auto index = converts.get_index<"byhash"_n>();
auto itr = index.find(hash);
if (itr == index.end()) {
return std::nullopt;
}
return *claim_itr;
return *itr;
}
claim capital::get_claim_or_fail(eosio::name coopname, const checksum256 &result_hash, eosio::name username, const char* msg) {
auto c = get_claim(coopname, result_hash, username);
eosio::check(c.has_value(), msg);
return *c;
}
std::optional<resactor> capital::get_resactor(eosio::name coopname, const checksum256 &result_hash, eosio::name username) {
resactor_index ractors(_capital, coopname.value);
auto idx = ractors.get_index<"byresuser"_n>();
auto rkey = combine_checksum_ids(result_hash, username);
auto it = idx.find(rkey);
if (it == idx.end()) {
return std::nullopt;
}
return *it;
}
resactor capital::get_resactor_or_fail(eosio::name coopname, const checksum256 &result_hash, eosio::name username, const char* msg) {
auto maybe_resactor = get_resactor(coopname, result_hash, username);
eosio::check(maybe_resactor.has_value(), msg);
return *maybe_resactor;
}
@@ -395,8 +477,8 @@ void capital::ensure_contributor(name coopname, name username) {
// - creators_bonus = spend * 0.382
// - authors_bonus = spend * 1.618
// - generated = spend + creators_bonus + authors_bonus
// - participants_bonus = generated * 1.618
// - total = generated + participants_bonus
// - capitalists_bonus = generated * 1.618
// - total = generated + capitalists_bonus
//----------------------------------------------------------------------------
bonus_result capital::calculcate_capital_amounts(int64_t spend_amount) {
bonus_result br{};
@@ -413,11 +495,11 @@ bonus_result capital::calculcate_capital_amounts(int64_t spend_amount) {
// 3) generated = spend + creators_bonus + authors_bonus
br.generated = int64_t(spend + br.creators_bonus + br.authors_bonus);
// 4) participants_bonus = generated * 1.618
br.participants_bonus = int64_t(double(br.generated) * 1.618);
// 4) capitalists_bonus = generated * 1.618
br.capitalists_bonus = int64_t(double(br.generated) * 1.618);
// 5) total = generated + participants_bonus
br.total = int64_t(br.generated + br.participants_bonus);
// 5) total = generated + capitalists_bonus
br.total = int64_t(br.generated + br.capitalists_bonus);
return br;
}
+79 -37
View File
@@ -35,16 +35,10 @@ public:
//Возврат из результата
[[eosio::action]]
void createwthd1(eosio::name coopname, eosio::name application, eosio::name username, checksum256 result_hash, checksum256 withdraw_hash, std::vector<checksum256> commit_hashes, document contribution_statement, document return_statement);
void createwthd1(eosio::name coopname, eosio::name application, eosio::name username, checksum256 result_hash, checksum256 withdraw_hash, asset amount, document return_statement);
[[eosio::action]]
void capauthwthdc(eosio::name coopname, uint64_t withdraw_id, document authorization);
[[eosio::action]]
void capauthwthdr(eosio::name coopname, uint64_t withdraw_id, document authorization);
[[eosio::action]]
void authwithdrw1(eosio::name coopname, checksum256 withdraw_hash);
void capauthwthd1(eosio::name coopname, uint64_t withdraw_id, document authorization);
// Возврат из проекта
[[eosio::action]]
@@ -56,6 +50,17 @@ public:
[[eosio::action]]
void approvewthd2(name coopname, name application, name approver, checksum256 withdraw_hash, document approved_return_statement);
// Возврат из программы
[[eosio::action]]
void createwthd3(name coopname, name application, name username, checksum256 project_hash, checksum256 withdraw_hash, asset amount, document return_statement);
[[eosio::action]]
void capauthwthd3(eosio::name coopname, uint64_t withdraw_id, document authorization);
[[eosio::action]]
void approvewthd3(name coopname, name application, name approver, checksum256 withdraw_hash, document approved_return_statement);
[[eosio::action]]
void createproj (
checksum256 project_hash,
@@ -69,33 +74,55 @@ public:
std::string subject
);
// claims
[[eosio::action]]
void createclaim(name coopname, name application, name owner, checksum256 result_hash, checksum256 claim_hash);
void createclaim(
eosio::name coopname,
eosio::name application,
eosio::name username,
checksum256 result_hash
);
[[eosio::action]]
void setstatement(name coopname, name application, name owner, checksum256 result_hash, document statement);
void claimnow(name coopname, name application, name username, checksum256 result_hash, document statement);
[[eosio::action]]
void authorize(eosio::name coopname, uint64_t claim_id, document decision);
void capauthclaim(eosio::name coopname, uint64_t claim_id, document decision);
[[eosio::action]]
void setact1(eosio::name coopname, eosio::name application, eosio::name owner, checksum256 claim_hash, document act);
void approveclaim(eosio::name coopname, eosio::name application, eosio::name approver, eosio::name username, checksum256 result_hash, document approved_statement);
// конвертация
[[eosio::action]]
void approvecnvrt(eosio::name coopname, eosio::name application, eosio::name approver, checksum256 convert_hash, document approved_statement);
[[eosio::action]]
void setact2(eosio::name coopname, eosio::name application, eosio::name owner, checksum256 result_hash, document act);
void createcnvrt(
eosio::name coopname,
eosio::name application,
eosio::name username,
checksum256 result_hash,
checksum256 convert_hash,
document convert_statement
);
[[eosio::action]]
void startdistrbn(name coopname, name application, checksum256 result_hash);
[[eosio::action]]
void addauthor(name coopname, name application, checksum256 project_hash, name author, uint64_t shares);
// Коммиты
[[eosio::action]]
void approvecmmt(eosio::name coopname, eosio::name application, eosio::name approver, checksum256 commit_hash, document approved_specification);
void approvecmmt(eosio::name coopname, eosio::name application, eosio::name approver, checksum256 commit_hash, document approved_statement);
[[eosio::action]]
void createcmmt(eosio::name coopname, eosio::name application, eosio::name creator, checksum256 result_hash, checksum256 commit_hash, uint64_t contributed_hours, document specification);
void createcmmt(eosio::name coopname, eosio::name application, eosio::name creator, checksum256 result_hash, checksum256 commit_hash, uint64_t contributed_hours, document contribution_statement);
[[eosio::action]]
void setact1(eosio::name coopname, eosio::name application, eosio::name username, checksum256 commit_hash, document act);
[[eosio::action]]
void setact2(eosio::name coopname, eosio::name application, eosio::name username, checksum256 commit_hash, document act);
[[eosio::action]]
void capauthcmmt(eosio::name coopname, uint64_t commit_id, document authorization);
// Регистрация
[[eosio::action]]
@@ -108,8 +135,10 @@ public:
// Инвестиции
[[eosio::action]]
void createinvest(name coopname, name application, name username, checksum256 project_hash, checksum256 invest_hash, asset amount, document statement);
[[eosio::action]]
void capauthinvst(eosio::name coopname, uint64_t invest_id, document authorization);
[[eosio::action]]
void approveinvst(name coopname, name application, name approver, checksum256 invest_hash, document approved_statement);
@@ -117,19 +146,26 @@ public:
void allocate(eosio::name coopname, eosio::name application, checksum256 project_hash, checksum256 result_hash, eosio::asset amount);
[[eosio::action]]
void approvewthd1(name coopname, name application, name approver, checksum256 withdraw_hash, document approved_contribution_statement, document approved_return_statement);
void diallocate(eosio::name coopname, eosio::name application, checksum256 project_hash, checksum256 result_hash, eosio::asset amount);
[[eosio::action]]
void approvewthd1(name coopname, name application, name approver, checksum256 withdraw_hash, document approved_return_statement);
// Расходы
[[eosio::action]]
void createexpnse(eosio::name coopname, eosio::name application, checksum256 expense_hash, checksum256 result_hash, name creator, uint64_t fund_id, asset amount, std::string description, document statement);
[[eosio::action]]
void approveexpns(name coopname, name application, name approver, checksum256 expense_hash, document approved_statement);
[[eosio::action]]
void capauthexpns(eosio::name coopname, uint64_t expense_id, document authorization);
// Членские взносы
void fund(eosio::name coopname, checksum256 project_hash, asset amount, std::string memo);
void refresh(name coopname, name application, checksum256 project_hash, name username);
[[eosio::action]] void fundproj(eosio::name coopname, checksum256 project_hash, asset amount, std::string memo);
[[eosio::action]] void refreshproj(name coopname, name application, checksum256 project_hash, name username);
[[eosio::action]] void fundprog(eosio::name coopname, asset amount, std::string memo);
[[eosio::action]] void refreshprog(name coopname, name application, name username);
private:
@@ -163,8 +199,18 @@ private:
std::optional<author> get_author(eosio::name coopname, eosio::name username, const checksum256 &project_hash);
std::optional<creator> get_creator(eosio::name coopname, eosio::name username, const checksum256 &result_hash);
std::optional<result> get_result(eosio::name coopname, const checksum256 &result_hash);
std::optional<project> get_project(eosio::name coopname, const checksum256 &project_hash);
std::optional<claim> get_claim(eosio::name coopname, const checksum256 &result_hash);
std::optional<project> get_master_project(eosio::name coopname);
void validate_project_hierarchy_depth(eosio::name coopname, checksum256 project_hash);
void distribute_project_membership_funds(eosio::name coopname, uint64_t project_id, asset amount, uint8_t level);
int64_t get_capital_user_share_balance(eosio::name coopname, eosio::name username);
std::optional<claim> get_claim(eosio::name coopname, const checksum256 &result_hash, eosio::name username);
std::optional<convert> get_convert(eosio::name coopname, const checksum256 &hash);
std::optional<result_author> get_result_author(eosio::name coopname, eosio::name username, const checksum256 &result_hash);
std::optional<commit> get_commit(eosio::name coopname, const checksum256 &hash);
std::optional<invest> get_invest(eosio::name coopname, const checksum256 &invest_hash);
@@ -174,32 +220,28 @@ private:
std::optional<expense> get_expense(eosio::name coopname, const checksum256 &hash);
program get_capital_program_or_fail(eosio::name coopname);
program get_cofund_program_or_fail(eosio::name coopname);
program get_source_program_or_fail(eosio::name coopname);
std::optional<progwallet> get_capital_wallet(eosio::name coopname, eosio::name username);
std::optional<contributor> get_contributor(eosio::name coopname, const checksum256 &project_hash, eosio::name username);
std::optional<contributor> get_active_contributor_or_fail(eosio::name coopname, const checksum256 &project_hash, eosio::name username);
std::optional<capital_tables::capitalist> get_capitalist(eosio::name coopname, eosio::name username);
int64_t get_capital_program_share_balance(eosio::name coopname);
std::optional<capital_tables::program_withdraw> get_program_withdraw(eosio::name coopname, const checksum256 &hash);
uint64_t count_authors_by_project(eosio::name coopname, const checksum256 &project_hash);
eosio::asset get_amount_for_withdraw_from_commit(eosio::name coopname, eosio::name username, const checksum256 &hash);
void expense_withdraw_callback(name coopname, checksum256 withdraw_hash);
void try_finalize_withdrawal(eosio::name coopname, const capital_tables::result_withdraws_index::const_iterator &withdraw) {
if (!is_document_empty(withdraw->authorized_return_statement) &&
!is_document_empty(withdraw->authorized_contribution_statement)) {
Wallet::add_blocked_funds(_capital, coopname, withdraw->username, withdraw->amount, _cofund_program);
action(
permission_level{_capital, "active"_n},
_capital,
"authwithdrw1"_n,
std::make_tuple(coopname, withdraw->withdraw_hash)
).send();
}
}
resactor get_resactor_or_fail(eosio::name coopname, const checksum256 &result_hash, eosio::name username, const char* msg);
std::optional<resactor> get_resactor(eosio::name coopname, const checksum256 &result_hash, eosio::name username);
claim get_claim_or_fail(eosio::name coopname, const checksum256 &result_hash, eosio::name username, const char* msg);
result get_result_or_fail(eosio::name coopname, const checksum256 &result_hash, const char* msg);
};
@@ -9,10 +9,49 @@ struct bonus_result {
int64_t creators_bonus;
int64_t authors_bonus;
int64_t generated;
int64_t participants_bonus;
int64_t capitalists_bonus;
int64_t total;
};
// resactors.hpp (или в capital.hpp)
struct [[eosio::table, eosio::contract(CAPITAL)]] resactor {
uint64_t id;
checksum256 project_hash; // С каким результатом связана запись
checksum256 result_hash; // С каким результатом связана запись
eosio::name username; // Чей это учёт
eosio::asset available = asset(0, _root_govern_symbol);
eosio::asset for_convert = asset(0, _root_govern_symbol);
eosio::asset spend = asset(0, _root_govern_symbol);
// Сколько пользователь имеет «авторских долей» в этом результате
uint64_t authors_shares = 0;
// Сколько пользователь имеет «создательских долей» в creators_bonus
uint64_t creators_bonus_shares = 0;
// Сколько часов вложено в результат
uint64_t contributed_hours = 0;
uint64_t primary_key() const { return id; }
checksum256 by_result_hash() const { return result_hash; } ///< Индекс по хэшу результата
checksum256 by_project_hash() const { return project_hash; } ///< Индекс по хэшу проекта
// Индекс по (result_hash + username)
uint128_t by_resuser() const {
return combine_checksum_ids(result_hash, username);
}
};
typedef eosio::multi_index<
"resactors"_n, resactor,
indexed_by<"byproject"_n, const_mem_fun<resactor, checksum256, &resactor::by_project_hash>>,
indexed_by<"byresult"_n, const_mem_fun<resactor, checksum256, &resactor::by_result_hash>>,
indexed_by<"byresuser"_n, const_mem_fun<resactor, uint128_t, &resactor::by_resuser>>
> resactor_index;
struct [[eosio::table, eosio::contract(CAPITAL)]] expense {
uint64_t id; ///< Уникальный идентификатор действия.
@@ -28,7 +67,7 @@ struct [[eosio::table, eosio::contract(CAPITAL)]] expense {
eosio::asset amount; ///< Сумма расхода.
std::string description; ///< Публичное описание расхода.
document statement; ///< Служебная записка
document expense_statement; ///< Служебная записка
document approved_statement; ///< принятая записка председателем или доверенным
document authorization; ///< утвержденная записка советом
@@ -60,17 +99,18 @@ struct [[eosio::table, eosio::contract(CAPITAL)]] commit {
name coopname; ///< Имя кооператива.
name application; ///< Приложение, инициировавшее действие.
name username; ///< Имя пользователя, совершившего действие.
name status = "created"_n; ///< Статус коммита (created | withdrawed | converted)
name status; ///< Статус коммита (created | approved | authorized | act1 | act2 )
checksum256 project_hash; ///< Хэш проекта, связанного с действием.
checksum256 result_hash; ///< Хэш результата, связанного с действием.
checksum256 commit_hash; ///< Хэш действия.
uint64_t contributed_hours; ///< Сумма временных затрат, связанная с действием.
eosio::asset spend; ///< Сумма затрат, связанная с действием.
document specification; ///< Техническое задание (спецификация) как приложение к договору УХД
document approved_specification; ///< Одобрение председателя или доверенного лица
document contribution_statement; ///< Техническое задание (спецификация) как приложение к договору УХД
document approved_statement; ///< Одобрение председателя или доверенного лица
document authorization; ///< Решение совета
document act1; ///< акт приема-передачи (1)
document act2; ///< акт приема-передачи (2)
time_point_sec created_at; ///< Дата и время создания действия.
uint64_t primary_key() const { return id; } ///< Основной ключ.
@@ -103,7 +143,7 @@ struct [[eosio::table, eosio::contract(CAPITAL)]] invest {
eosio::asset amount = asset(0, _root_govern_symbol); ///< Сумма инвестиции.
name status; ///< created | signed | authorized | blocked
time_point_sec invested_at; ///< Дата приёма инвестиции.
document statement; ///< Заявление на зачёт из кошелька.
document invest_statement; ///< Заявление на зачёт из кошелька.
document approved_statement; ///< Подпись председателя на принятом заявлении.
uint64_t primary_key() const { return id; } ///< Основной ключ.
@@ -138,22 +178,21 @@ struct [[eosio::table, eosio::contract(CAPITAL)]] contributor {
eosio::asset invested = asset(0, _root_govern_symbol);
uint64_t contributed_hours;
eosio::asset rate_per_hour;
eosio::asset spend = asset(0, _root_govern_symbol);
uint64_t convert_percent;
eosio::asset for_convert = asset(0, _root_govern_symbol);
uint64_t contributed_hours;
eosio::asset available = asset(0, _root_govern_symbol);
eosio::asset rate_per_hour = asset(0, _root_govern_symbol);
eosio::asset spend = asset(0, _root_govern_symbol);
eosio::asset withdrawed = asset(0, _root_govern_symbol);
eosio::asset converted = asset(0, _root_govern_symbol);
eosio::asset expensed = asset(0, _root_govern_symbol);
eosio::asset returned = asset(0, _root_govern_symbol);
eosio::asset claimed = asset(0, _root_govern_symbol);
eosio::asset share_balance = asset(0, _root_govern_symbol); ///< Баланс долей вкладчика
eosio::asset share_balance = asset(0, _root_govern_symbol); ///< Баланс долей пайщика
eosio::asset pending_rewards = asset(0, _root_govern_symbol); ///< Накопленные награды
int64_t reward_per_share_last = 0; ///< Последний зафиксированный cumulative_reward_per_share
int64_t reward_per_share_last = 0; ///< Последний зафиксированный cumulative_reward_per_share по проекту
uint64_t primary_key() const { return id; }
uint64_t by_username() const { return username.value; }
@@ -170,7 +209,7 @@ typedef eosio::multi_index<
/**
* @brief Таблица идей (проектов)
* @brief Таблица проектов
*
*/
struct [[eosio::table, eosio::contract(CAPITAL)]] project {
@@ -197,11 +236,14 @@ struct [[eosio::table, eosio::contract(CAPITAL)]] project {
eosio::asset expensed = asset(0, _root_govern_symbol);
eosio::asset spend = asset(0, _root_govern_symbol);
eosio::asset generated = asset(0, _root_govern_symbol);
eosio::asset converted = asset(0, _root_govern_symbol);
eosio::asset claimed = asset(0, _root_govern_symbol);
eosio::asset withdrawed = asset(0, _root_govern_symbol);
double membership_parent_distribution_ratio = 1;
double parent_distribution_ratio = 1;
int64_t membership_cumulative_reward_per_share = 0;
eosio::asset membership_total_shares = asset(0, _root_govern_symbol); ///< Общее количество долей пайщиков в проекте
eosio::asset total_share_balance = asset(0, _root_govern_symbol); ///< Общее количество долей пайщиков в проекте
eosio::asset membership_funded = asset(0, _root_govern_symbol); ///< Общее количество поступивших членских взносов
eosio::asset membership_available = asset(0, _root_govern_symbol); ///< Доступное количество членских взносов для участников проекта согласно долям
eosio::asset membership_distributed = asset(0, _root_govern_symbol); ///< Распределенное количество членских взносов на участников проекта
@@ -223,30 +265,40 @@ struct [[eosio::table, eosio::contract(CAPITAL)]] result {
uint64_t id;
checksum256 result_hash;
checksum256 project_hash;
eosio::name status = "created"_n; ///< created | started | expired?
eosio::name status = "created"_n; ///< created
eosio::name coopname;
time_point_sec created_at = current_time_point();
time_point_sec expired_at = eosio::time_point_sec(eosio::current_time_point().sec_since_epoch() + 365 * 86400);
uint64_t authors_shares;
uint64_t authors_count;
uint64_t total_creators_bonus_shares;
uint64_t authors_count;
uint64_t commits_count;
eosio::asset allocated = asset(0, _root_govern_symbol); ///< аллоцированные на создание результата средства
eosio::asset available = asset(0, _root_govern_symbol); ///< зарезерированные на создание результата средства
eosio::asset spend = asset(0, _root_govern_symbol); ///< фактически потраченные ресурсы на создание результат в виде времени (паевые взносы-возвраты)
eosio::asset expensed = asset(0, _root_govern_symbol); ///< фактически потраченные на создание результата средства в виде расходов (подписки, прочее)
eosio::asset withdrawed = asset(0, _root_govern_symbol); ///< фактически возвращенные средства из результата
eosio::asset creators_amount = asset(0, _root_govern_symbol); ///< себестоимость РИД
eosio::asset generated_amount = asset(0, _root_govern_symbol); ///< стоимость РИД с учётом премий авторов и создателей
eosio::asset creators_bonus = asset(0, _root_govern_symbol); ///< премии создателей - 0.382 от себестоимости (creators_amount)
eosio::asset authors_bonus = asset(0, _root_govern_symbol); ///< премии авторов - 1.618 от себестоимости (creators_amount)
eosio::asset generated_amount = asset(0, _root_govern_symbol); ///< стоимость РИД с учётом премий авторов и создателей
eosio::asset participants_bonus = asset(0, _root_govern_symbol); ///< премии пайщиков кооператива - 1.618 от generated_amount
eosio::asset capitalists_bonus = asset(0, _root_govern_symbol); ///< премии пайщиков кооператива - 1.618 от generated_amount
eosio::asset total_amount = asset(0, _root_govern_symbol); ///< Капитализация РИД (стоимость РИД в generated_amount + capitalists_bonus)
eosio::asset authors_bonus_remain = asset(0, _root_govern_symbol); ///< сумма остатка для выплаты авторам
eosio::asset creators_amount_remain = asset(0, _root_govern_symbol); ///< сумма остатка для выплаты авторам
eosio::asset creators_bonus_remain = asset(0, _root_govern_symbol); ///< сумма остатка для выплаты авторам
eosio::asset capitalists_bonus_remain = asset(0, _root_govern_symbol); ///< сумма остатка для выплаты пайщикам
eosio::asset total_amount = asset(0, _root_govern_symbol); ///< Капитализация РИД (стоимость РИД в generated_amount + participants_bonus)
eosio::asset participants_bonus_remain = asset(0, _root_govern_symbol); ///< сумма остатка для выплаты пайщикам
uint64_t primary_key() const { return id; } ///< Основной ключ.
checksum256 by_hash() const { return result_hash; } ///< Индекс по хэшу результата.
checksum256 by_project_hash() const { return project_hash; } ///< Индекс по хэшу идеи
@@ -261,44 +313,81 @@ struct [[eosio::table, eosio::contract(CAPITAL)]] result {
struct [[eosio::table, eosio::contract(CAPITAL)]] claim {
uint64_t id;
checksum256 claim_hash;
checksum256 project_hash;
checksum256 result_hash;
eosio::name coopname;
eosio::name owner;
eosio::name username;
eosio::name type; ///< intellectual | property
eosio::name status = "created"_n; ///< created | statement | decision | act1 | act2 | completed
time_point_sec created_at = current_time_point();
eosio::asset amount = asset(0, _root_govern_symbol);
document statement; ///< Заявление
document decision; ///< Решение
document act1; ///< Акт передачи
document act2; ///< Акт приёма
eosio::asset author_amount = asset(0, _root_govern_symbol);
eosio::asset creator_amount = asset(0, _root_govern_symbol);
eosio::asset capitalist_amount = asset(0, _root_govern_symbol);
eosio::asset total_amount = asset(0, _root_govern_symbol);
document claim_statement; ///< Заявление
document approved_statement; ///< Принятое заявление
document authorization; ///< Решение
uint64_t primary_key() const { return id; } ///< Основной ключ.
uint64_t by_owner() const { return owner.value; } ///< Индекс по владельцу
checksum256 by_hash() const { return claim_hash; } ///< Индекс по хэшу
uint64_t by_username() const { return username.value; } ///< Индекс по владельцу
checksum256 by_result_hash() const { return result_hash; } ///< Индекс по хэшу
checksum256 by_project_hash() const { return project_hash; } ///< Индекс по хэшу идеи
checksum256 by_project_hash() const { return project_hash; } ///< Индекс по хэшу проекта
uint128_t by_result_user() const {
return combine_checksum_ids(result_hash, owner);
return combine_checksum_ids(result_hash, username);
}
};
typedef eosio::multi_index<"claims"_n, claim,
indexed_by<"byowner"_n, const_mem_fun<claim, uint64_t, &claim::by_owner>>,
indexed_by<"byhash"_n, const_mem_fun<claim, checksum256, &claim::by_hash>>,
indexed_by<"byresulthash"_n, const_mem_fun<claim, checksum256, &claim::by_result_hash>>,
indexed_by<"byusername"_n, const_mem_fun<claim, uint64_t, &claim::by_username>>,
indexed_by<"byresult"_n, const_mem_fun<claim, checksum256, &claim::by_result_hash>>,
indexed_by<"byprojecthash"_n, const_mem_fun<claim, checksum256, &claim::by_project_hash>>,
indexed_by<"byresuser"_n, const_mem_fun<claim, uint128_t, &claim::by_result_user>>
> claim_index;
struct [[eosio::table, eosio::contract(CAPITAL)]] convert {
uint64_t id;
checksum256 project_hash;
checksum256 result_hash;
checksum256 convert_hash;
eosio::name coopname;
eosio::name username;
eosio::name status = "created"_n; ///< created
eosio::asset convert_amount = asset(0, _root_govern_symbol);
document convert_statement; ///< Заявление
time_point_sec created_at = current_time_point();
uint64_t primary_key() const { return id; } ///< Основной ключ.
uint64_t by_username() const { return username.value; } ///< Индекс по владельцу
checksum256 by_convert_hash() const { return convert_hash; } ///< Индекс по хэшу
checksum256 by_result_hash() const { return result_hash; } ///< Индекс по хэшу
checksum256 by_project_hash() const { return project_hash; } ///< Индекс по хэшу проекта
uint128_t by_result_user() const {
return combine_checksum_ids(result_hash, username);
}
};
typedef eosio::multi_index<"converts"_n, convert,
indexed_by<"byusername"_n, const_mem_fun<convert, uint64_t, &convert::by_username>>,
indexed_by<"byhash"_n, const_mem_fun<convert, checksum256, &convert::by_convert_hash>>,
indexed_by<"byresult"_n, const_mem_fun<convert, checksum256, &convert::by_result_hash>>,
indexed_by<"byprojecthash"_n, const_mem_fun<convert, checksum256, &convert::by_project_hash>>
> convert_index;
struct [[eosio::table, eosio::contract(CAPITAL)]] author {
uint64_t id;
checksum256 project_hash;
@@ -384,6 +473,13 @@ struct [[eosio::table, eosio::contract(CAPITAL)]] creator {
struct [[eosio::table, eosio::contract(CAPITAL)]] global_state {
eosio::name coopname; ///< Имя кооператива глобального состояния.
uint64_t program_id; ///< Идентификатор целевой программы.
asset program_membership_funded = asset(0, _root_govern_symbol); ///< Общая сумма членских взносов по программе
asset program_membership_available = asset(0, _root_govern_symbol); ///< Доступная сумма членских взносов по программе
asset program_membership_distributed = asset(0, _root_govern_symbol); ///< Распределенная сумма членских взносов по программе
int64_t program_membership_cumulative_reward_per_share; ///< Накопительное вознаграждение на долю в членских взносах
asset total_shares = asset(0, _root_govern_symbol); ///< Общая сумма долей всех участников.
asset total_contributions = asset(0, _root_govern_symbol); ///< Общая сумма всех вкладов.
asset total_rewards_distributed = asset(0, _root_symbol); ///< Общая сумма распределенных вознаграждений.
@@ -400,6 +496,18 @@ struct [[eosio::table, eosio::contract(CAPITAL)]] global_state {
namespace capital_tables {
struct [[eosio::table, eosio::contract(CAPITAL)]] capitalist {
name username; ///< Имя пользователя
name coopname; ///< Имя кооператива
asset pending_rewards = asset(0, _root_govern_symbol); ///< Вознаграждения ожидающие получения
asset returned_rewards = asset(0, _root_govern_symbol); ///< Полученные вознаграждения
int64_t reward_per_share_last; ///< Крайнее вознаграждение за долю
uint64_t primary_key() const { return username.value; } ///< Основной ключ.
};
typedef eosio::multi_index<"capitalists"_n, capitalist> capitalist_index; ///< Таблица для хранения участников программы капитализации
struct [[eosio::table, eosio::contract(CAPITAL)]] result_withdraw {
uint64_t id; ///< Уникальный ID запроса на возврат.
@@ -409,7 +517,6 @@ namespace capital_tables {
checksum256 withdraw_hash; ///< Уникальный внешний ключ
name username; ///< Имя аккаунта участника, запрашивающего возврат.
name status = "created"_n; ///< Статус взноса-возврата (created | approved | )
std::vector<checksum256> commit_hashes; ///< Погашаемые коммиты
asset amount = asset(0, _root_govern_symbol); ///< Запрошенная сумма для возврата.
document contribution_statement; ///< Заявление на паевой взнос авторскими правами
document return_statement; ///< Заявление на возврат паевого взноса деньгами
@@ -428,7 +535,7 @@ namespace capital_tables {
checksum256 by_hash() const { return withdraw_hash; } ///< Индекс по хэшу
};
typedef eosio::multi_index<"rwithdraws"_n, result_withdraw,
typedef eosio::multi_index<"reswithdraws"_n, result_withdraw,
indexed_by<"byhash"_n, const_mem_fun<result_withdraw, checksum256, &result_withdraw::by_hash>>,
indexed_by<"byusername"_n, const_mem_fun<result_withdraw, uint64_t, &result_withdraw::by_account>>,
indexed_by<"bycreated"_n, const_mem_fun<result_withdraw, uint64_t, &result_withdraw::by_created>>
@@ -447,8 +554,6 @@ namespace capital_tables {
document approved_return_statement; ///< Принятое председателем заявление на возврат взноса деньгами
document authorized_return_statement; ///< Решение совета на возврат взноса
time_point_sec created_at = current_time_point(); ///< Дата и время создания действия. ///< Время создания запроса.
uint64_t primary_key() const { return id; } ///< Основной ключ.
@@ -458,11 +563,37 @@ namespace capital_tables {
checksum256 by_project_hash() const { return project_hash; } ///< Индекс по хэшу проекта
};
typedef eosio::multi_index<"pwithdraws"_n, project_withdraw,
typedef eosio::multi_index<"prjwithdraws"_n, project_withdraw,
indexed_by<"byhash"_n, const_mem_fun<project_withdraw, checksum256, &project_withdraw::by_hash>>,
indexed_by<"byprojhash"_n, const_mem_fun<project_withdraw, checksum256, &project_withdraw::by_project_hash>>,
indexed_by<"byusername"_n, const_mem_fun<project_withdraw, uint64_t, &project_withdraw::by_account>>,
indexed_by<"bycreated"_n, const_mem_fun<project_withdraw, uint64_t, &project_withdraw::by_created>>
> project_withdraws_index; ///< Таблица для хранения запросов на возврат из проекта.
struct [[eosio::table, eosio::contract(CAPITAL)]] program_withdraw {
uint64_t id; ///< Уникальный ID запроса на возврат.
name coopname; ///< Имя аккаунта кооператива
checksum256 withdraw_hash; ///< Уникальный внешний ключ
name username; ///< Имя аккаунта участника, запрашивающего возврат.
name status = "created"_n; ///< Статус взноса-возврата (created | approved | )
asset amount = asset(0, _root_govern_symbol); ///< Запрошенная сумма для возврата.
document return_statement; ///< Заявление на возврат паевого взноса деньгами
document approved_return_statement; ///< Принятое председателем заявление на возврат взноса деньгами
time_point_sec created_at = current_time_point(); ///< Дата и время создания действия. ///< Время создания запроса.
uint64_t primary_key() const { return id; } ///< Основной ключ.
uint64_t by_account() const { return username.value; } ///< Вторичный индекс по аккаунту.
uint64_t by_created() const { return created_at.sec_since_epoch(); }
checksum256 by_hash() const { return withdraw_hash; } ///< Индекс по хэшу
};
typedef eosio::multi_index<"prgwithdraws"_n, program_withdraw,
indexed_by<"byhash"_n, const_mem_fun<program_withdraw, checksum256, &program_withdraw::by_hash>>,
indexed_by<"byusername"_n, const_mem_fun<program_withdraw, uint64_t, &program_withdraw::by_account>>,
indexed_by<"bycreated"_n, const_mem_fun<program_withdraw, uint64_t, &program_withdraw::by_created>>
> program_withdraws_index; ///< Таблица для хранения запросов на возврат из проекта.
}
Binary file not shown.
@@ -0,0 +1,25 @@
void capital::approveclaim(eosio::name coopname, eosio::name application, eosio::name approver, eosio::name username, checksum256 result_hash, document approved_statement){
check_auth_or_fail(_capital, coopname, application, "approveclaim"_n);
verify_document_or_fail(approved_statement);
auto exist_claim = get_claim(coopname, result_hash, username);
eosio::check(exist_claim.has_value(), "Клайм пользователя для результата не существует");
auto result = get_result(coopname, result_hash);
eosio::check(result.has_value(), "Результат не найден");
claim_index claims(_capital, coopname.value);
auto claim = claims.find(exist_claim -> id);
claims.modify(claim, coopname, [&](auto &a) {
a.status = "approved"_n;
a.approved_statement = approved_statement;
});
//отправляем в совет
action(permission_level{ _capital, "active"_n}, _soviet, "createagenda"_n,
std::make_tuple(coopname, claim -> username, _capital, _capital_claim_authorize_action, claim -> id, claim -> claim_statement, std::string("")))
.send();
};
@@ -1,16 +0,0 @@
void capital::authorize(eosio::name coopname, uint64_t claim_id, document decision) {
require_auth(_soviet);
claim_index claims(_capital, coopname.value);
auto claim = claims.find(claim_id);
eosio::check(claim != claims.end(), "Объект запроса доли не найден");
// Проверяем статус.
eosio::check(claim -> status == "statement"_n, "Неверный статус");
claims.modify(claim, coopname, [&](auto &n){
n.status = "decision"_n;
n.decision = decision;
});
};
@@ -0,0 +1,39 @@
void capital::capauthclaim(eosio::name coopname, uint64_t claim_id, document decision) {
require_auth(_soviet);
claim_index claims(_capital, coopname.value);
auto claim = claims.find(claim_id);
eosio::check(claim != claims.end(), "Объект запроса доли не найден");
// Проверяем статус
eosio::check(claim -> status == "statement"_n, "Неверный статус");
auto exist = get_project(coopname, claim -> project_hash);
eosio::check(exist.has_value(),"Проект не найден");
project_index projects(_capital, coopname.value);
auto project = projects.find(exist -> id);
auto contributor = get_active_contributor_or_fail(coopname, claim -> project_hash, claim -> username);
contributor_index contributors(_capital, coopname.value);
auto contributor_for_modify = contributors.find(contributor -> id);
contributors.modify(contributor_for_modify, coopname, [&](auto &c){
c.claimed += claim -> total_amount;
c.share_balance += claim -> total_amount;
});
projects.modify(project, coopname, [&](auto &p) {
p.claimed += claim -> total_amount;
p.total_share_balance += claim -> total_amount;
});
std::string memo = "Зачёт части целевого паевого взноса по договору УХД с ID: " + std::to_string(contributor -> id) + " в качестве паевого взноса по программе 'Цифровой Кошелёк' с ID: " + std::to_string(claim_id);
//Увеличиваем баланс средств в капитализации
Wallet::add_blocked_funds(_capital, coopname, claim -> username, claim -> total_amount, _capital_program, memo);
//Удаляем объект claim за ненадобностью
claims.erase(claim);
};
@@ -0,0 +1,22 @@
void capital::claimnow(name coopname, name application, name username, checksum256 result_hash, document statement) {
check_auth_or_fail(_capital, coopname, application, "claimnow"_n);
// проверяем заявление
verify_document_or_fail(statement);
// извлекаем клайм
auto claim = get_claim(coopname, result_hash, username);
eosio::check(claim.has_value(), "Объект запроса доли не найден");
eosio::check(claim->status == "pending"_n, "Нельзя изменить статус клайма");
eosio::check(claim -> username == username, "Неверно указано имя пользователя владельца результата");
// обновляем клайм, добавляя заявление
claim_index claims(_capital, coopname.value);
auto claim_for_modify = claims.find(claim->id);
claims.modify(claim_for_modify, coopname, [&](auto &c){
c.status = "statement"_n;
c.claim_statement = statement;
});
}
@@ -1,91 +1,131 @@
void capital::createclaim(name coopname, name application, name owner, checksum256 result_hash, checksum256 claim_hash) {
check_auth_or_fail(_capital, coopname, application, "createclaim"_n);
// извлекаем программу и кошелек пайщика в программе
auto capital_program = get_capital_program_or_fail(coopname);
auto capital_wallet = get_capital_wallet(coopname, owner);
eosio::check(!capital_wallet.has_value(), "Для участия необходимо подписать соглашение целевой потребительской программы!");
// извлекаем результат
auto result = get_result(coopname, result_hash);
eosio::check(result.has_value(), "Результат не найден");
// извлекаем проект
auto project = get_project(coopname, result -> project_hash);
eosio::check(project.has_value(), "Проект не найден");
// извлекаем клайм, и падаем, если он уже есть
auto existing_claim = get_claim(coopname, claim_hash);
eosio::check(!existing_claim.has_value(), "Объект запроса доли уже существует");
uint64_t author_amount = 0;
uint64_t creator_amount = 0;
uint64_t creator_bonus_amount = 0;
uint64_t participant_amount = 0;
// считаем авторское вознаграждение
auto author = get_result_author(coopname, owner, result_hash);
if (author.has_value()) {
author_amount = uint64_t(double(author->shares) * double(result->authors_bonus.amount) / double(result->authors_shares));
}
// считаем вознаграждение создателя
auto contributor = get_active_contributor_or_fail(coopname, result -> project_hash, owner);
if (result -> creators_amount.amount > 0) {
/**
- for_convert - это то, что гарантированно готовится стать share_balance,
- available - это то, что может быть выведено до момента claim.
*/
creator_amount = contributor -> available.amount + contributor -> for_convert.amount;
double creator_bonus_share = double(creator_amount) / double(result -> creators_amount.amount);
creator_bonus_amount = uint64_t(creator_bonus_share * double(result -> creators_bonus.amount));
};
// считаем премию пайщика
if (
capital_program.available -> amount > 0 &&
capital_wallet -> available.amount > 0 &&
result -> participants_bonus_remain.amount > 0)
{
double participant_share = double(capital_wallet -> available.amount) / double(capital_program.available -> amount);
participant_amount = uint64_t(participant_share * double(result -> participants_bonus.amount));
void capital::createclaim(
eosio::name coopname,
eosio::name application,
eosio::name username,
checksum256 result_hash
) {
// Авторизация
check_auth_or_fail(_capital, coopname, application, "createclaim"_n);
if (participant_amount > result -> participants_bonus_remain.amount) {
participant_amount = result -> participants_bonus_remain.amount;
// Получаем результат (или кидаем ошибку)
auto exist_result = get_result_or_fail(coopname, result_hash, "Результат не найден");
eosio::check(exist_result.status == "opened"_n, "Распределение стоимости результата еще не начато или уже завершено");
// Проверяем, нет ли уже такого клайма
auto existing_claim = get_claim(coopname, result_hash, username);
eosio::check(!existing_claim.has_value(), "Клайм уже существует");
// Находим запись в таблице results
result_index results(_capital, coopname.value);
auto result = results.find(exist_result.id);
// Получаем контрибьютора
auto exist_contributor = get_active_contributor_or_fail(coopname, exist_result.project_hash, username);
contributor_index contributors(_capital, coopname.value);
auto contributor = contributors.find(exist_contributor->id);
// Попробуем найти resactor
auto optional_resactor = get_resactor(coopname, result_hash, username);
//=== (A) Авторская часть ===
uint64_t author_amount = 0;
{
// Если resactor есть, считаем долю.
if (optional_resactor.has_value()) {
auto resactor = *optional_resactor;
// Исходная сумма (просто authors_bonus.amount)
uint64_t authors_total = result -> authors_bonus.amount;
// Доля пользователя
uint64_t user_auth_shares = resactor.authors_shares;
// Всего долей авторов
uint64_t total_auth_shares = result -> authors_shares;
if (authors_total > 0 && total_auth_shares > 0 && user_auth_shares > 0) {
uint128_t tmp = (uint128_t)authors_total * (uint128_t)user_auth_shares;
author_amount = (uint64_t)(tmp / (uint128_t)total_auth_shares);
print(result->authors_bonus_remain.amount, ", ", author_amount);
eosio::check(result->authors_bonus_remain.amount >= author_amount,
"Недостаточно средств для авторов");
}
}
}
}
//DEBUG
print("author_amount: ", author_amount);
print("creator_amount: ", creator_amount);
print("creator_bonus_amount: ", creator_bonus_amount);
print("participant_amount:", participant_amount);
eosio::asset amount = eosio::asset(author_amount + creator_amount + creator_bonus_amount + participant_amount, _root_govern_symbol);
// создаём объект запроса доли
claim_index claims(_capital, coopname.value);
uint64_t claim_id = get_global_id_in_scope(_capital, coopname, "claims"_n);
claims.emplace(coopname, [&](auto &n) {
n.id = claim_id;
n.claim_hash = claim_hash;
n.owner = owner;
n.result_hash = result_hash;
n.coopname = coopname;
n.status = "pending"_n;
n.amount = amount;
});
//=== (B) Создательская часть бонусов ===
uint64_t creator_amount = 0;
{
if (optional_resactor.has_value()) {
auto resactor = *optional_resactor;
// обновляем оставшиеся выплаты пайщикам
result_index results(_capital, coopname.value);
auto result_for_modify = results.find(result -> id);
eosio::check(result_for_modify -> participants_bonus_remain.amount >= participant_amount, "Недостаточно средств в результате для оплаты премии пайщика");
results.modify(result_for_modify, coopname, [&](auto &r){
r.participants_bonus_remain -= asset(participant_amount, _root_govern_symbol);
});
uint64_t creators_bonus_total = result->creators_bonus.amount; // вся сумма создателей
uint64_t user_creator_bonus_shares = resactor.creators_bonus_shares;
uint64_t total_creators_bonus_shares= result->total_creators_bonus_shares;
if (creators_bonus_total > 0 && total_creators_bonus_shares > 0 && user_creator_bonus_shares > 0) {
uint128_t tmp = (uint128_t)creators_bonus_total * (uint128_t)user_creator_bonus_shares;
creator_amount = (uint64_t)(tmp / (uint128_t)total_creators_bonus_shares);
eosio::check(result->creators_bonus_remain.amount >= creator_amount, "Недостаточно средств для создателей");
}
}
}
//=== (C) Капиталисты ===
// здесь resactor НЕ обязателен, доли берём из глобальных методов
uint64_t capitalist_amount = 0;
{
// Полная сумма для капиталистов
uint64_t capitals_total = result->capitalists_bonus.amount;
// Пользовательские доли берем из кошелька программы
uint64_t user_cap_shares = get_capital_user_share_balance(coopname, username);
// Общее число долей капиталистов во всей программе
uint64_t total_cap_shares = get_capital_program_share_balance(coopname);
if (capitals_total > 0 && total_cap_shares > 0 && user_cap_shares > 0) {
uint128_t tmp = (uint128_t)capitals_total * (uint128_t)user_cap_shares;
capitalist_amount = (uint64_t)(tmp / (uint128_t)total_cap_shares);
eosio::check(result->capitalists_bonus_remain.amount >= capitalist_amount,
"Недостаточно средств для пайщиков");
}
}
//=== Складываем всё ===
uint64_t total_claim_amount = author_amount + creator_amount + capitalist_amount;
eosio::asset total_amount(total_claim_amount, _root_govern_symbol);
//=== Создаём запись в claims ===
claim_index claims(_capital, coopname.value);
uint64_t claim_id = get_global_id_in_scope(_capital, coopname, "claims"_n);
claims.emplace(coopname, [&](auto &n) {
n.id = claim_id;
n.username = username;
n.result_hash = result_hash;
n.coopname = coopname;
n.status = "created"_n;
n.author_amount = asset(author_amount, _root_govern_symbol);
n.creator_amount = asset(creator_amount, _root_govern_symbol);
n.capitalist_amount = asset(capitalist_amount, _root_govern_symbol);
n.total_amount = total_amount;
});
//=== Уменьшаем остаток bonus_remain ===
results.modify(result, coopname, [&](auto &r){
// авторы
if (author_amount > 0) {
r.authors_bonus_remain -= eosio::asset(author_amount, _root_govern_symbol);
}
// создатели
if (creator_amount > 0) {
r.creators_bonus_remain -= eosio::asset(creator_amount, _root_govern_symbol);
}
// капиталисты
if (capitalist_amount > 0) {
r.capitalists_bonus_remain -= eosio::asset(capitalist_amount, _root_govern_symbol);
}
});
}
@@ -1,24 +0,0 @@
void capital::setact1(eosio::name coopname, eosio::name application, eosio::name owner, checksum256 claim_hash, document act) {
check_auth_or_fail(_capital, coopname, application, "setact1"_n);
verify_document_or_fail(act);
// claims
auto claim = get_claim(coopname, claim_hash);
eosio::check(claim.has_value(), "Объект запроса доли не найден");
eosio::check(claim -> owner == owner, "Неверно указано имя пользователя владельца результата");
auto result = get_result(coopname, claim -> result_hash);
eosio::check(result.has_value(), "Результат не найден");
claim_index claims(_capital, coopname.value);
auto claim_for_modify = claims.find(claim -> id);
// Проверяем статус.
eosio::check(result -> status == "decision"_n, "Неверный статус для поставки акта приёма-передачи");
claims.modify(claim_for_modify, coopname, [&](auto &n){
n.status = "act1"_n;
n.act1 = act;
});
};
@@ -1,52 +0,0 @@
void capital::setact2(eosio::name coopname, eosio::name application, eosio::name owner, checksum256 claim_hash, document act) {
check_auth_or_fail(_capital, coopname, application, "setact2"_n);
verify_document_or_fail(act);
auto exist_claim = get_claim(coopname, claim_hash);
eosio::check(exist_claim.has_value(), "Объект запроса доли не найден");
eosio::check(exist_claim -> owner == owner, "Неверно указано имя пользователя владельца результата");
auto result = get_result(coopname, exist_claim -> result_hash);
eosio::check(result.has_value(), "Результат не найден");
auto project = get_project(coopname, result -> project_hash);
eosio::check(project.has_value(), "Проект не найден");
// Проверяем статус
eosio::check(exist_claim -> status == "act1"_n, "Неверный статус для поставки акта");
claim_index claims(coopname, coopname.value);
auto claim = claims.find(exist_claim -> id);
claims.modify(claim, coopname, [&](auto &n) {
n.status = "act2"_n;
n.act2 = act;
});
auto contributor = capital::get_active_contributor_or_fail(coopname, result -> project_hash, exist_claim -> owner);
contributor_index contributors(_capital, coopname.value);
auto contributor_for_modify = contributors.find(contributor -> id);
// Увеличиваем share_balance на сумму остатка создательского баланса
contributors.modify(contributor_for_modify, coopname, [&](auto &c) {
c.share_balance += claim -> amount;
});
project_index projects(_capital, coopname.value);
auto project_for_modify = projects.find(project -> id);
// учитываем увеличение долей в проекте
projects.modify(project_for_modify, coopname, [&](auto &p){
p.membership_total_shares += claim -> amount;
});
// списание с УХД
Wallet::sub_blocked_funds(_capital, coopname, claim -> owner, claim -> amount, _cofund_program);
// добавление на капитализацию
Wallet::add_blocked_funds(_capital, coopname, claim -> owner, claim -> amount, _capital_program);
};
@@ -1,27 +0,0 @@
void capital::setstatement(name coopname, name application, name owner, checksum256 claim_hash, document statement) {
check_auth_or_fail(_capital, coopname, application, "setstatement"_n);
// проверяем заявление
verify_document_or_fail(statement);
// извлекаем клайм
auto claim = get_claim(coopname, claim_hash);
eosio::check(claim.has_value(), "Объект запроса доли не найден");
eosio::check(claim->status == "pending"_n, "Нельзя изменить статус клайма");
eosio::check(claim -> owner == owner, "Неверно указано имя пользователя владельца результата");
// обновляем клайм, добавляя заявление
claim_index claims(_capital, coopname.value);
auto claim_for_modify = claims.find(claim->id);
claims.modify(claim_for_modify, coopname, [&](auto &c){
c.status = "statement"_n;
c.statement = statement;
});
// Отправляем заявление в совет
action(permission_level{_capital, "active"_n}, _soviet, "claim"_n,
std::make_tuple(coopname, owner, claim->id, statement))
.send();
}
@@ -1,7 +1,7 @@
void capital::approvecmmt(eosio::name coopname, eosio::name application, eosio::name approver, checksum256 commit_hash, document approved_specification){
void capital::approvecmmt(eosio::name coopname, eosio::name application, eosio::name approver, checksum256 commit_hash, document approved_statement){
check_auth_or_fail(_capital, coopname, application, "approvecmmt"_n);
verify_document_or_fail(approved_specification);
verify_document_or_fail(approved_statement);
auto exist_commit = get_commit(coopname, commit_hash);
eosio::check(exist_commit.has_value(), "Действие с указанным хэшем не существует");
@@ -14,67 +14,14 @@ void capital::approvecmmt(eosio::name coopname, eosio::name application, eosio::
commit_index commits(_capital, coopname.value);
auto commit = commits.find(exist_commit -> id);
commits.modify(commit, coopname, [&](auto &a){
commits.modify(commit, coopname, [&](auto &a) {
a.status = "approved"_n;
a.approved_specification = approved_specification;
a.approved_statement = approved_statement;
});
auto exist_contributor = get_active_contributor_or_fail(coopname, result -> project_hash, commit -> username);
contributor_index contributors(_capital, coopname.value);
auto contributor = contributors.find(exist_contributor -> id);
// Рассчитываем долю, которая идет в for_convert
double convert_ratio = static_cast<double>(contributor->convert_percent) / HUNDR_PERCENTS;
asset for_convert = asset(static_cast<int64_t>(commit->spend.amount * convert_ratio), commit->spend.symbol);
// Остаток идет в available
asset available = commit -> spend - for_convert;
contributors.modify(contributor, coopname, [&](auto &c){
c.available += available;
c.for_convert += for_convert;
c.contributed_hours = commit -> contributed_hours;
c.spend += commit -> spend;
});
auto br = capital::calculcate_capital_amounts(commit -> spend.amount);
// Формируем eosio::asset из результатов
eosio::asset creators_bonus(br.creators_bonus, commit -> spend.symbol);
eosio::asset authors_bonus(br.authors_bonus, commit -> spend.symbol);
eosio::asset generated(br.generated, commit -> spend.symbol);
eosio::asset participants_bonus(br.participants_bonus, commit -> spend.symbol);
eosio::asset total(br.total, commit -> spend.symbol);
// Обновляем запись в таблице results
result_index results(_capital, coopname.value);
auto result_for_modyfy = results.find(result -> id);
eosio::check(result -> available >= commit -> spend, "Недостаточно средств в результате для приёма действия");
results.modify(result_for_modyfy, coopname, [&](auto& row) {
row.available -= commit -> spend;
row.spend += commit -> spend;
row.creators_amount += commit -> spend;
row.creators_bonus += creators_bonus;
row.authors_bonus += authors_bonus;
row.generated_amount += generated;
row.participants_bonus += participants_bonus;
row.participants_bonus_remain += participants_bonus;
row.total_amount += total;
row.commits_count++;
});
//обновить сгенерированную сумму по проекту
auto exist_project = get_project(coopname, result -> project_hash);
project_index projects(_capital, coopname.value);
auto project = projects.find(exist_project->id);
projects.modify(project, _capital, [&](auto &p) {
p.generated += generated;
});
//отправляем в совет
action(permission_level{ _capital, "active"_n}, _soviet, "createagenda"_n,
std::make_tuple(coopname, commit -> username, _capital, _capital_commit_authorize_action, commit -> id, commit -> contribution_statement, std::string("")))
.send();
};
@@ -0,0 +1,16 @@
void capital::capauthcmmt(eosio::name coopname, uint64_t commit_id, document authorization) {
require_auth(_soviet);
commit_index commits(_capital, coopname.value);
auto commit = commits.find(commit_id);
eosio::check(commit != commits.end(), "Коммит не найден");
auto contributor = get_active_contributor_or_fail(coopname, commit->project_hash, commit->username);
//TODO: change to coopname
commits.modify(commit, _soviet, [&](auto &n) {
n.status = "authorized"_n;
n.authorization = authorization;
});
};
@@ -1,7 +1,7 @@
void capital::createcmmt(eosio::name coopname, eosio::name application, eosio::name creator, checksum256 result_hash, checksum256 commit_hash, uint64_t contributed_hours, document specification){
void capital::createcmmt(eosio::name coopname, eosio::name application, eosio::name creator, checksum256 result_hash, checksum256 commit_hash, uint64_t contributed_hours, document contribution_statement){
check_auth_or_fail(_capital, coopname, application, "createcmmt"_n);
verify_document_or_fail(specification);
verify_document_or_fail(contribution_statement);
auto result = get_result(coopname, result_hash);
eosio::check(result.has_value(), "Результат не найден");
@@ -19,6 +19,7 @@ void capital::createcmmt(eosio::name coopname, eosio::name application, eosio::n
commits.emplace(coopname, [&](auto &a) {
a.id = get_global_id_in_scope(_capital, coopname, "commits"_n);
a.status = "created"_n;
a.coopname = coopname;
a.application = application;
a.username = creator;
@@ -28,6 +29,7 @@ void capital::createcmmt(eosio::name coopname, eosio::name application, eosio::n
a.contributed_hours = contributed_hours;
a.spend = spend;
a.created_at = current_time_point();
a.specification = specification;
a.contribution_statement = contribution_statement;
});
}
@@ -0,0 +1,24 @@
void capital::setact1(eosio::name coopname, eosio::name application, eosio::name username, checksum256 commit_hash, document act) {
check_auth_or_fail(_capital, coopname, application, "setact1"_n);
verify_document_or_fail(act);
// commits
auto commit = get_commit(coopname, commit_hash);
eosio::check(commit.has_value(), "Объект коммита не найден");
eosio::check(commit -> username == username, "Неверно указано имя пользователя владельца результата");
auto result = get_result(coopname, commit -> result_hash);
eosio::check(result.has_value(), "Результат не найден");
commit_index commits(_capital, coopname.value);
auto commit_for_modify = commits.find(commit -> id);
// Проверяем статус.
eosio::check(commit_for_modify -> status == "authorized"_n, "Неверный статус для поставки акта приёма-передачи");
commits.modify(commit_for_modify, coopname, [&](auto &n){
n.status = "act1"_n;
n.act1 = act;
});
};
@@ -0,0 +1,124 @@
/**
* @brief Принятие второго акта (act2). Убираем любой CRPS, просто плюсуем бонусы.
*/
void capital::setact2(
eosio::name coopname,
eosio::name application,
eosio::name username,
checksum256 commit_hash,
document act
) {
check_auth_or_fail(_capital, coopname, application, "setact2"_n);
verify_document_or_fail(act);
// Ищем коммит
auto exist_commit = get_commit(coopname, commit_hash);
eosio::check(exist_commit.has_value(), "Коммит не найден");
eosio::check(exist_commit -> username == username, "Неверно указано имя пользователя владельца результата");
eosio::check(exist_commit -> status == "act1"_n, "Неверный статус для поставки акта");
// Обновляем коммит
commit_index commits(_capital, coopname.value);
auto commit = commits.find(exist_commit->id);
commits.modify(commit, coopname, [&](auto &c) {
c.status = "act2"_n;
c.act2 = act;
});
// Ищем результат и проект
auto exist_result = get_result_or_fail(coopname, commit->result_hash, "Результат не найден");
auto exist_project = get_project(coopname, exist_result.project_hash);
eosio::check(exist_project.has_value(), "Проект не найден");
// Ищем вкладчика
auto exist_contributor = get_active_contributor_or_fail(coopname, exist_result.project_hash, commit->username);
contributor_index contributors(_capital, coopname.value);
auto contributor = contributors.find(exist_contributor->id);
// Распределяем spend на available / for_convert
// convert_percent — целое число от 0 до HUNDR_PERCENTS
int64_t for_convert_amount = (commit->spend.amount * contributor->convert_percent) / HUNDR_PERCENTS;
eosio::asset for_convert(for_convert_amount, commit->spend.symbol);
eosio::asset available = commit->spend - for_convert;
// Вычисляем bonus
auto br = capital::calculcate_capital_amounts(commit->spend.amount);
eosio::asset creators_bonus (br.creators_bonus, commit->spend.symbol);
eosio::asset authors_bonus (br.authors_bonus, commit->spend.symbol);
eosio::asset generated (br.generated, commit->spend.symbol);
eosio::asset capitalists_bonus (br.capitalists_bonus, commit->spend.symbol);
eosio::asset total (br.total, commit->spend.symbol);
// Обновляем result
result_index results(_capital, coopname.value);
auto result = results.find(exist_result.id);
eosio::check(result->available >= commit->spend, "Недостаточно средств в результате для приёма коммита");
results.modify(result, coopname, [&](auto &row) {
row.available -= commit->spend;
row.spend += commit->spend;
row.creators_amount += commit->spend;
row.total_creators_bonus_shares += commit->spend.amount;
row.creators_bonus += creators_bonus;
row.authors_bonus += authors_bonus;
row.generated_amount += generated;
row.capitalists_bonus += capitalists_bonus;
row.total_amount += total;
row.commits_count++;
});
// Обновляем проект
project_index projects(_capital, coopname.value);
auto project = projects.find(exist_project->id);
// Обновляем актора и проект
contributors.modify(contributor, coopname, [&](auto &c){
c.spend += commit->spend;
c.share_balance += commit->spend;
c.contributed_hours += commit->contributed_hours;
});
projects.modify(project, coopname, [&](auto &p) {
p.generated += generated;
p.spend += commit->spend;
p.available += commit->spend;
p.total_share_balance += commit->spend;
});
// Обновляем запись в resactors (создательские доли)
auto exist_resactor = get_resactor(coopname, commit->result_hash, commit->username);
resactor_index ractors(_capital, coopname.value);
if (!exist_resactor.has_value()) {
ractors.emplace(coopname, [&](auto &ra){
ra.id = ractors.available_primary_key();
ra.project_hash = commit->project_hash;
ra.result_hash = commit->result_hash;
ra.username = commit->username;
ra.creators_bonus_shares = commit->spend.amount;
ra.spend = commit->spend;
ra.for_convert = for_convert;
ra.available = available;
ra.contributed_hours = commit->contributed_hours;
});
} else {
auto resactor = ractors.find(exist_resactor->id);
ractors.modify(resactor, coopname, [&](auto &ra) {
ra.creators_bonus_shares += commit -> spend.amount;
ra.for_convert += for_convert;
ra.available += available;
ra.spend += commit->spend;
ra.contributed_hours += commit->contributed_hours;
});
}
// 10) Добавляем заблокированные средства на договор УХД
std::string memo = "Приём паевого взноса по договору УХД с contributor_id: " + std::to_string(contributor->id);
Wallet::add_blocked_funds(_capital, coopname, contributor->username, commit->spend, _source_program, memo);
}
@@ -0,0 +1,48 @@
void capital::approvecnvrt(eosio::name coopname, eosio::name application, eosio::name approver, checksum256 convert_hash, document approved_statement){
check_auth_or_fail(_capital, coopname, application, "approvecnvrt"_n);
verify_document_or_fail(approved_statement);
auto exist_convert = get_convert(coopname, convert_hash);
eosio::check(exist_convert.has_value(), "Конвертация пользователя для результата не найдена");
convert_index converts(_capital, coopname.value);
auto convert = converts.find(exist_convert -> id);
auto result = get_result(coopname, convert -> result_hash);
eosio::check(result.has_value(), "Результат не найден");
// добавляем доли актору и отмечаем статистику сконвертированных сумм
auto contributor = get_active_contributor_or_fail(coopname, convert -> project_hash, convert -> username);
contributor_index contributors(_capital, coopname.value);
auto contributor_for_modify = contributors.find(contributor -> id);
contributors.modify(contributor_for_modify, coopname, [&](auto &c){
c.converted += convert -> convert_amount;
c.share_balance += convert -> convert_amount;
});
// добавляем доли в проект
auto exist = get_project(coopname, convert -> project_hash);
eosio::check(exist.has_value(),"Проект не найден");
project_index projects(_capital, coopname.value);
auto project = projects.find(exist -> id);
projects.modify(project, coopname, [&](auto &p) {
p.converted += convert -> convert_amount;
p.total_share_balance += convert -> convert_amount;
});
std::string memo = "Зачёт части целевого паевого взноса по договору УХД с ID: " + std::to_string(contributor -> id) + " в качестве паевого взноса по программе 'Капитализация' с ID: " + std::to_string(convert -> id);
//Списываем баланс средств с УХД только при наличии convert_amount в claim
Wallet::sub_blocked_funds(_capital, coopname, convert -> username, convert -> convert_amount, _source_program, memo);
//Увеличиваем баланс средств в капитализации
Wallet::add_blocked_funds(_capital, coopname, convert -> username, convert -> convert_amount, _capital_program, memo);
// удаляем объект конвертации
converts.erase(convert);
};
@@ -0,0 +1,67 @@
void capital::createcnvrt(
eosio::name coopname,
eosio::name application,
eosio::name username,
checksum256 result_hash,
checksum256 convert_hash,
document convert_statement
) {
// Авторизация
check_auth_or_fail(_capital, coopname, application, "createcnvrt"_n);
// Получаем результат (или кидаем ошибку)
auto exist_result = get_result_or_fail(coopname, result_hash, "Результат не найден");
eosio::check(exist_result.status == "opened"_n || exist_result.status == "created"_n, "Распределение стоимости результата еще не начато или уже завершено");
// Проверяем, нет ли уже такой конвертации
auto existing_convert = get_convert(coopname, convert_hash);
eosio::check(!existing_convert.has_value(), "Объект конвертации с указанным хэшем уже существует");
// Находим запись в таблице results
result_index results(_capital, coopname.value);
auto result = results.find(exist_result.id);
// Получаем контрибьютора
auto exist_contributor = get_active_contributor_or_fail(coopname, exist_result.project_hash, username);
contributor_index contributors(_capital, coopname.value);
auto contributor = contributors.find(exist_contributor->id);
// Попробуем найти resactor
auto exist_resactor = get_resactor_or_fail(coopname, result_hash, username, "Объект актора в результате не найден");
//=== Сумма к конвертации ===
asset convert_amount = exist_resactor.available + exist_resactor.for_convert;
eosio::check(convert_amount.amount > 0, "Нет доступных средств для конвертации");
//=== Создаём запись в converts ===
convert_index converts(_capital, coopname.value);
uint64_t convert_id = get_global_id_in_scope(_capital, coopname, "converts"_n);
converts.emplace(coopname, [&](auto &n) {
n.id = convert_id;
n.username = username;
n.project_hash = exist_result.project_hash;
n.result_hash = result_hash;
n.convert_hash = convert_hash;
n.coopname = coopname;
n.status = "created"_n;
n.convert_amount = convert_amount;
n.convert_statement = convert_statement;
});
eosio::check(result -> creators_amount_remain >= convert_amount, "Недостаточно средств в result.creators_amount_remain для конвертации");
results.modify(result, coopname, [&](auto &r) {
r.creators_amount_remain -= convert_amount;
});
resactor_index ractors(_capital, coopname.value);
auto resactor = ractors.find(exist_resactor.id);
//обнуляем доступные средства к выводу или конвертации
ractors.modify(resactor, coopname, [&](auto &ra) {
ra.for_convert = asset(0, _root_govern_symbol);
ra.available = asset(0, _root_govern_symbol);
});
}
@@ -29,7 +29,7 @@ void capital::approveexpns(name coopname, name application, name approver, check
//отправляем в совет
action(permission_level{ _capital, "active"_n}, _soviet, "createagenda"_n,
std::make_tuple(coopname, expense -> username, _capital, _capital_expense_authorize_action, expense -> id, expense -> statement, std::string("")))
std::make_tuple(coopname, expense -> username, _capital, _capital_expense_authorize_action, expense -> id, expense -> expense_statement, std::string("")))
.send();
}
@@ -17,7 +17,7 @@ void capital::capauthexpns(eosio::name coopname, uint64_t expense_id, document a
// создаём объект исходящего платежа в gateway с коллбэком после обработки
action(permission_level{ _capital, "active"_n}, _gateway, _gateway_create_expense_withdraw_action,
std::make_tuple(coopname, ""_n, expense -> username, expense -> expense_hash, expense -> amount, expense -> statement, _capital, _gateway_to_capital_expense_callback_type, std::string("")))
std::make_tuple(coopname, ""_n, expense -> username, expense -> expense_hash, expense -> amount, expense -> expense_statement, _capital, _gateway_to_capital_expense_callback_type, std::string("")))
.send();
}
@@ -31,9 +31,9 @@ void capital::createexpnse(eosio::name coopname, eosio::name application, checks
i.fund_id = fund_id;
i.status = "created"_n;
i.spend_at = current_time_point();
i.statement = statement;
i.amount = amount;
i.description = description;
i.expense_statement = statement;
i.amount = amount;
i.description = description;
});
}
@@ -1,57 +0,0 @@
void capital::fund(eosio::name coopname, checksum256 project_hash, asset amount, std::string memo) {
auto payer = check_auth_and_get_payer_or_fail({_soviet, _gateway});
Wallet::validate_asset(amount);
auto exist_project = get_project(coopname, project_hash);
eosio::check(exist_project.has_value(), "Проект не найден");
project_index projects(_capital, coopname.value);
auto project = projects.find(exist_project->id);
// Коэффициент распределения (0.0 - всё в проект, 1.0 - всё в глобал).
double ratio = project->membership_parent_distribution_ratio;
// Считаем суммы для локального и глобального фондов
int64_t membership_parent_fund_amount = static_cast<int64_t>(amount.amount * ratio);
int64_t membership_current_fund_amount = amount.amount - membership_parent_fund_amount;
asset membership_parent_fund(membership_parent_fund_amount, amount.symbol);
asset membership_current_fund(membership_current_fund_amount, amount.symbol);
// Обновляем поля проекта
projects.modify(project, coopname, [&](auto &p) {
p.membership_funded += amount;
p.membership_available += membership_current_fund;
// Если в проекте уже есть доли участников (total_shares),
// распределяем поступивший membership_current_fund пропорционально им
if (p.membership_total_shares.amount > 0) {
// REWARD_SCALE - ваш масштаб (например, 1e8), чтобы не терять точность
int64_t delta = (membership_current_fund.amount * REWARD_SCALE)
/ p.membership_total_shares.amount;
p.membership_cumulative_reward_per_share += delta;
}
// Иначе, если нет долей, просто накапливаем средства (p.membership_current_fund)
// и не трогаем membership_cumulative_reward_per_share
});
// Если есть родительский проект, добавляем программное распределение в него
if (project -> parent_project_hash != checksum256()) {
auto exist_parent = get_project(coopname, project->parent_project_hash);
eosio::check(exist_parent.has_value(), "Родительский проект не найден");
auto parent_project = projects.find(exist_parent->id);
eosio::check(parent_project != projects.end(), "Ошибка при поиске родительского проекта");
projects.modify(parent_project, coopname, [&](auto &p) {
p.membership_funded += membership_parent_fund; // Отмечаем факт поступления
p.membership_available += membership_parent_fund;
if (p.membership_total_shares.amount > 0) {
int64_t delta = (membership_parent_fund.amount * REWARD_SCALE) / p.membership_total_shares.amount;
p.membership_cumulative_reward_per_share += delta;
};
});
}
}
@@ -1,77 +0,0 @@
[[eosio::action]]
void capital::refresh(name coopname, name application, checksum256 project_hash, name username) {
check_auth_or_fail(_capital, coopname, application, "contribute"_n);
// 1. Получаем ТЕКУЩИЙ проект
auto exist_project = get_project(coopname, project_hash);
eosio::check(exist_project.has_value(), "Проект не найден");
project_index projects(_capital, coopname.value);
auto project = projects.find(exist_project->id);
// 2. Находим вкладчика в ТЕКУЩЕМ проекте
auto exist = get_active_contributor_or_fail(coopname, project_hash, username);
eosio::check(exist.has_value(), "Contributor not found in current project");
contributor_index contributors(_capital, coopname.value);
auto contributor = contributors.find(exist->id);
// 3. Считаем дельту CRPS
int64_t current_crps = project->membership_cumulative_reward_per_share;
int64_t last_crps = contributor->reward_per_share_last;
int64_t delta = current_crps - last_crps;
if (delta > 0) {
// Начисляем вознаграждение
int64_t reward_amount_int = (contributor->share_balance.amount * delta) / REWARD_SCALE;
asset reward_amount = asset(reward_amount_int, contributor->share_balance.symbol);
// Обновляем вкладчика
contributors.modify(contributor, same_payer, [&](auto &c) {
c.pending_rewards += reward_amount;
c.reward_per_share_last = current_crps;
});
}
// 4. Проверяем, есть ли родительский проект
if (project->parent_project_hash != checksum256()) {
// Находим родительский проект
auto exist_parent = get_project(coopname, project->parent_project_hash);
// Если родитель не найден, просто завершаем (или можно вернуть ошибку)
if (!exist_parent.has_value()) {
return;
}
auto parent_project = projects.find(exist_parent->id);
eosio::check(parent_project != projects.end(), "Ошибка при поиске родительского проекта");
// 5. Ищем вкладчика в РОДИТЕЛЬСКОМ проекте по тому же username
// Предполагаем, что запись там уже существует.
auto parent_contributor_opt = get_contributor(coopname, project->parent_project_hash, username);
// если вкладчик не найден, можно либо ничего не делать, либо автоматически создать – зависит от требований
if (!parent_contributor_opt.has_value()) {
return; // нет записи о таком вкладчике в родительском проекте
}
// 6. Нашли родительского вкладчика
auto parent_contributor = contributors.find(parent_contributor_opt->id);
eosio::check(parent_contributor != contributors.end(), "Parent contributor record not found");
// 7. Считаем дельту для родительского CRPS
int64_t parent_crps = parent_project->membership_cumulative_reward_per_share;
int64_t parent_last = parent_contributor->reward_per_share_last;
int64_t delta_parent = parent_crps - parent_last;
if (delta_parent > 0) {
// Начисляем вознаграждение
int64_t reward_amount_int = (parent_contributor->share_balance.amount * delta_parent) / REWARD_SCALE;
asset reward_amount = asset(reward_amount_int, parent_contributor->share_balance.symbol);
// Обновляем родительского вкладчика
contributors.modify(parent_contributor, same_payer, [&](auto &c) {
c.pending_rewards += reward_amount;
c.reward_per_share_last = parent_crps;
});
}
}
}
@@ -0,0 +1,20 @@
void capital::fundprog(eosio::name coopname, asset amount, std::string memo) {
auto payer = check_auth_and_get_payer_or_fail({_soviet, _gateway});
Wallet::validate_asset(amount);
int64_t total_share_balance = get_capital_program_share_balance(coopname);
auto state = get_global_state(coopname);
state.program_membership_funded += amount;
state.program_membership_available += amount;
if (total_share_balance > 0) {
// REWARD_SCALE - ваш масштаб (например, 1e8), чтобы не терять точность
int64_t delta = (amount.amount * REWARD_SCALE) / total_share_balance;
state.program_membership_cumulative_reward_per_share += delta;
};
update_global_state(state);
};
@@ -0,0 +1,36 @@
[[eosio::action]] void capital::refreshprog(name coopname, name application, name username) {
check_auth_or_fail(_capital, coopname, application, "refreshprog"_n);
// Находим капиталиста в программе
capital_tables::capitalist_index capitalists(_capital, coopname.value);
auto capitalist = capitalists.find(username.value);
auto state = get_global_state(coopname);
// 3. Считаем дельту CRPS
int64_t current_crps = state.program_membership_cumulative_reward_per_share;
int64_t last_crps = capitalist == capitalists.end() ? 0 : capitalist -> reward_per_share_last;
int64_t delta = current_crps - last_crps;
int64_t share_balance = get_capital_user_share_balance(coopname, username);
if (delta > 0 && share_balance > 0) {
// Начисляем вознаграждение
int64_t reward_amount_int = (share_balance * delta) / REWARD_SCALE;
asset reward_amount = asset(reward_amount_int, _root_govern_symbol);
if (capitalist == capitalists.end()){
capitalists.emplace(coopname, [&](auto &p){
p.username = username;
p.coopname = coopname;
p.pending_rewards = reward_amount;
p.reward_per_share_last = current_crps;
});
} else {
capitalists.modify(capitalist, coopname, [&](auto &p) {
p.pending_rewards += reward_amount;
p.reward_per_share_last = current_crps;
});
};
};
};
@@ -0,0 +1,42 @@
void capital::fundproj(eosio::name coopname, checksum256 project_hash, asset amount, std::string memo) {
auto payer = check_auth_and_get_payer_or_fail({ _soviet, _gateway });
Wallet::validate_asset(amount);
auto exist_project = get_project(coopname, project_hash);
eosio::check(exist_project.has_value(), "Проект не найден");
capital::distribute_project_membership_funds(coopname, exist_project->id, amount, 0);
};
void capital::distribute_project_membership_funds(eosio::name coopname, uint64_t project_id, asset amount, uint8_t level) {
eosio::check(level < 12, "Превышено максимальное количество уровней распределения (12)");
project_index projects(_capital, coopname.value);
auto project = projects.find(project_id);
eosio::check(project != projects.end(), "Проект не найден");
double ratio = project -> parent_distribution_ratio;
int64_t membership_parent_fund_amount = static_cast<int64_t>(amount.amount * ratio);
int64_t membership_current_fund_amount = amount.amount - membership_parent_fund_amount;
asset membership_parent_fund(membership_parent_fund_amount, amount.symbol);
asset membership_current_fund(membership_current_fund_amount, amount.symbol);
projects.modify(project, coopname, [&](auto &p) {
p.membership_funded += amount;
p.membership_available += membership_current_fund;
if (project -> total_share_balance.amount > 0) {
int64_t delta = (membership_current_fund.amount * REWARD_SCALE) / project->total_share_balance.amount;
p.membership_cumulative_reward_per_share += delta;
};
});
if (ratio > 0 && project -> parent_project_hash != checksum256()) {
auto parent_project = get_project(coopname, project -> parent_project_hash);
eosio::check(parent_project.has_value(), "Родительский проект не найден");
distribute_project_membership_funds(coopname, parent_project->id, membership_parent_fund, level + 1);
};
};
@@ -0,0 +1,35 @@
[[eosio::action]] void capital::refreshproj(name coopname, name application, checksum256 project_hash, name username) {
check_auth_or_fail(_capital, coopname, application, "contribute"_n);
// 1. Получаем проект
auto exist_project = get_project(coopname, project_hash);
eosio::check(exist_project.has_value(), "Проект не найден");
project_index projects(_capital, coopname.value);
auto project = projects.find(exist_project->id);
// 2. Находим пайщика в проекте
auto exist = get_active_contributor_or_fail(coopname, project_hash, username);
contributor_index contributors(_capital, coopname.value);
auto contributor = contributors.find(exist->id);
// 3. Считаем дельту CRPS
int64_t current_crps = project -> membership_cumulative_reward_per_share;
int64_t last_crps = contributor -> reward_per_share_last;
int64_t delta = current_crps - last_crps;
int64_t share_balance = contributor -> share_balance.amount;
if (delta > 0 && share_balance > 0) {
// Начисляем вознаграждение
int64_t reward_amount_int = (share_balance * delta) / REWARD_SCALE;
asset reward_amount = asset(reward_amount_int, _root_govern_symbol);
// Обновляем вкладчика
contributors.modify(contributor, same_payer, [&](auto &c) {
c.pending_rewards += reward_amount;
c.reward_per_share_last = current_crps;
});
}
}
@@ -16,6 +16,6 @@ void capital::approveinvst(name coopname, name application, name approver, check
//отправляем в совет
action(permission_level{ _capital, "active"_n}, _soviet, _capital_invest_authorize_action,
std::make_tuple(coopname, invest -> username, invest -> id, invest -> statement, std::string("")))
std::make_tuple(coopname, invest -> username, invest -> id, invest -> invest_statement, std::string("")))
.send();
};
@@ -1,5 +1,5 @@
/**
* @brief Принимаем решение совета и вносим средства на кошелек пайщика
* @brief Принимаем решение совета и вносим средства на кошелек пайщика при УХД
*
*/
void capital::capauthinvst(eosio::name coopname, uint64_t invest_id, document authorization) {
@@ -26,31 +26,25 @@ void capital::capauthinvst(eosio::name coopname, uint64_t invest_id, document au
project_index projects(_capital, coopname.value);
auto project = projects.find(exist -> id);
projects.modify(project, coopname, [&](auto &p) {
p.invested += invest -> amount;
p.available += invest -> amount;
// добавляем новые доли в проект
p.membership_total_shares += invest -> amount;
p.total_share_balance += invest -> amount;
});
// Если есть родительский проект — там тоже отмечается часть инвестиций
if (project -> parent_project_hash != checksum256()) {
auto exist_parent = get_project(coopname, project->parent_project_hash);
eosio::check(exist_parent.has_value(), "Родительский проект не найден");
auto parent_project = projects.find(exist_parent->id);
eosio::check(parent_project != projects.end(), "Ошибка при поиске родительского проекта");
projects.modify(parent_project, coopname, [&](auto &p) {
p.membership_total_shares += invest -> amount; // Родитель тоже получает доли
});
};
// пополняем кошелек и блокируем средства в нём
Wallet::add_blocked_funds(_capital, coopname, contributor -> username, invest -> amount, _cofund_program);
std::string memo = "Зачёт части целевого паевого взноса по программе 'Цифровой Кошелёк' в качестве паевого взноса по договору УХД с contributor_id:" + std::to_string(contributor -> id);
// списываем заблокированные средства с кошелька
Wallet::sub_blocked_funds(_capital, coopname, contributor -> username, invest -> amount, _wallet_program, memo);
// добавляем доступные средства в УХД
// TODO: ???
// списываем доступные средства с УХД
// пополняем программу капитализации и блокируем средства в ней
Wallet::add_blocked_funds(_capital, coopname, contributor -> username, invest -> amount, _capital_program, memo);
// Удаляем объект за ненадобностью
invests.erase(invest);
@@ -1,5 +1,5 @@
void capital::createinvest(name coopname, name application, name username, checksum256 project_hash, checksum256 invest_hash, asset amount, document statement) {
check_auth_or_fail(_capital, coopname, application, "contribute"_n);
check_auth_or_fail(_capital, coopname, application, "createinvest"_n);
verify_document_or_fail(statement);
@@ -28,8 +28,12 @@ void capital::createinvest(name coopname, name application, name username, check
i.invest_hash = invest_hash;
i.status = "created"_n;
i.invested_at = current_time_point();
i.statement = statement;
i.invest_statement = statement;
i.amount = amount;
});
std::string memo = "Зачёт части целевого паевого взноса по программе 'Цифровой Кошелёк' в качестве паевого взноса по договору УХД с ID: " + std::to_string(contributor -> id);
// блокируем средства в программе кошелька
Wallet::block_funds(_capital, coopname, contributor -> username, amount, _wallet_program, memo);
}
Binary file not shown.
@@ -1,2 +0,0 @@
1. Создаём проект createproj
2. Добавляем авторов addauthor
@@ -15,18 +15,18 @@ void capital::addauthor(name coopname, name application, checksum256 project_has
auto author_itr = project_author_index.find(combined_id);
authors.emplace(coopname, [&](auto& row) {
row.id = get_global_id_in_scope(_capital, coopname, "authors"_n);
row.project_hash = project_hash;
row.username = author;
row.shares = shares;
row.id = get_global_id_in_scope(_capital, coopname, "authors"_n);
row.project_hash = project_hash;
row.username = author;
row.shares = shares;
});
project_index projects(_capital, coopname.value);
auto project_for_modify = projects.find(project -> id);
// Обновляем shares и authors_count в идее
// Обновляем shares и authors_count в проекте
projects.modify(project_for_modify, coopname, [&](auto& row) {
row.authors_shares += shares;
row.authors_count++;
row.authors_shares += shares;
row.authors_count++;
});
}
@@ -15,25 +15,28 @@ void capital::createproj (
auto exist = get_project(_capital, project_hash);
eosio::check(!exist.has_value(), "Проект с указанным хэшем уже существует");
if (parent_project_hash != checksum256()) {
auto parent_exist = get_project(_capital, parent_project_hash);
eosio::check(exist.has_value(), "Родительский проект с указанным хэшем не существует");
};
project_index projects(_capital, coopname.value);
eosio::check(parent_distribution_ratio >=0 && parent_distribution_ratio <= 1, "parent_distribution_ratio должен быть от 0 до 1");
project_index projects(_capital, coopname.value);
if (parent_project_hash != checksum256()) {
// проверяем глубину количества родительский связей проекта
validate_project_hierarchy_depth(coopname, parent_project_hash);
};
if (parent_distribution_ratio > 0)
eosio::check(parent_project_hash != checksum256(), "Родительский проект должен быть установлен при parent_distribution_ratio > 0");
projects.emplace(coopname, [&](auto& row) {
row.id = get_global_id_in_scope(_capital, coopname, "projects"_n);
row.project_hash = project_hash;
row.parent_project_hash = parent_project_hash;
row.membership_parent_distribution_ratio = parent_distribution_ratio;
row.parent_distribution_ratio = parent_distribution_ratio;
row.coopname = coopname;
row.application = application;
row.title = title;
row.description = description;
row.terms = terms;
row.subject = subject;
});
});
}
@@ -0,0 +1,28 @@
void capital::diallocate(eosio::name coopname, eosio::name application, checksum256 project_hash, checksum256 result_hash, eosio::asset amount) {
check_auth_or_fail(_capital, coopname, application, "diallocate"_n);
Wallet::validate_asset(amount);
auto project = get_project(coopname, project_hash);
eosio::check(project.has_value(), "Проект с указанным хэшем не найден");
auto result = get_result(coopname, result_hash);
eosio::check(result.has_value(), "Объект результата не найден");
eosio::check(result -> available >= amount, "Недостаточно средств в результате для возврата в проект");
result_index results(_capital, coopname.value);
auto result_for_modify = results.find(result -> id);
results.modify(result_for_modify, coopname, [&](auto& row) {
row.available -= amount;
row.allocated -= amount;
});
project_index projects(_capital, coopname.value);
auto project_for_modify = projects.find(project -> id);
projects.modify(project_for_modify, coopname, [&](auto& row) {
row.available += amount;
row.allocated -= amount;
});
};
@@ -18,4 +18,12 @@ void capital::capregcontr(eosio::name coopname, uint64_t contributor_id, documen
c.status = "authorized"_n;
c.authorization = authorization;
});
auto program_wallet = get_program_wallet(coopname, contributor -> username, _source_program);
if (!program_wallet.has_value()) {
action(permission_level{ _capital, "active"_n}, _soviet, "openprogwall"_n,
std::make_tuple(coopname, contributor -> username, _source_program, uint64_t(0)))
.send();
};
};
@@ -24,23 +24,23 @@ void capital::createresult(name coopname, name application, checksum256 project_
// Перебираем всех авторов с данным project_hash
auto author_itr = authors_hash_index.lower_bound(project_hash);
result_authors_index result_authors(_capital, coopname.value);
uint64_t authors_count = 0;
resactor_index ractors(_capital, coopname.value);
// Копируем запись автора идеи в result_authors
while(author_itr != authors_hash_index.end() && author_itr->project_hash == project_hash) {
result_authors.emplace(coopname, [&](auto &n){
n.id = get_global_id_in_scope(_capital, coopname, "resauthors"_n);
n.username = author_itr->username;
n.result_hash = result_hash;
n.project_hash = project_hash;
n.shares = author_itr -> shares;
ractors.emplace(coopname, [&](auto &ra){
ra.id = ractors.available_primary_key();
ra.result_hash = result_hash;
ra.project_hash = project_hash;
ra.username = author_itr->username;
ra.authors_shares = author_itr -> shares;
});
authors_count++;
author_itr++;
}
eosio::check(authors_count > 0, "Нельзя создать результат без установленных авторов в проекте");
}
@@ -12,13 +12,10 @@ void capital::startdistrbn(name coopname, name application, checksum256 result_h
auto result_for_modify = results.find(result -> id);
results.modify(result_for_modify, coopname, [&](auto& row) {
row.status = "started"_n;
row.status = "opened"_n;
row.authors_bonus_remain = row.authors_bonus;
row.creators_amount_remain = row.creators_amount;
row.creators_bonus_remain = row.creators_bonus;
row.capitalists_bonus_remain = row.capitalists_bonus;
});
// projects_index projects(_capital, coopname.value);
// auto project_for_modify = projects.find(project -> id);
// projects.modify(project_for_modify, coopname, [&](auto &p) {
// p.available =
// });
};
@@ -0,0 +1,22 @@
void capital::approvewthd3(name coopname, name application, name approver, checksum256 withdraw_hash, document approved_return_statement) {
check_auth_or_fail(_capital, coopname, application, "approvewthd3"_n);
verify_document_or_fail(approved_return_statement);
auto exist_withdraw = get_project_withdraw(coopname, withdraw_hash);
eosio::check(exist_withdraw.has_value(), "Объект возврата не найден");
capital_tables::program_withdraws_index program_withdraws(_capital, coopname.value);
auto withdraw = program_withdraws.find(exist_withdraw -> id);
program_withdraws.modify(withdraw, coopname, [&](auto &i) {
i.status = "approved"_n;
i.approved_return_statement = approved_return_statement;
});
//отправляем в совет
action(permission_level{ _capital, "active"_n}, _soviet, "createagenda"_n,
std::make_tuple(coopname, exist_withdraw -> username, _capital, _capital_withdraw_from_program_authorize_action, exist_withdraw -> id, exist_withdraw -> return_statement, std::string("")))
.send();
};
@@ -0,0 +1,14 @@
void capital::capauthwthd3(name coopname, uint64_t withdraw_id, document authorization) {
require_auth(_soviet);
capital_tables::program_withdraws_index program_withdraws(_capital, coopname.value);
auto withdraw = program_withdraws.find(withdraw_id);
eosio::check(withdraw != program_withdraws.end(), "Объект возврата не найден");
std::string memo = "Зачёт части целевого паевого взноса по программе 'Капитализация' в качестве паевого взноса по программе 'Цифровой Кошелёк' с ID: " + std::to_string(withdraw_id);
Wallet::sub_blocked_funds(_capital, coopname, withdraw->username, withdraw->amount, _capital_program, memo);
Wallet::add_available_funds(_capital, coopname, withdraw->username, withdraw->amount, _wallet_program, memo);
program_withdraws.erase(withdraw);
}
@@ -0,0 +1,65 @@
void capital::createwthd3(name coopname, name application, name username, checksum256 project_hash, checksum256 withdraw_hash, asset amount, document return_statement) {
check_auth_or_fail(_capital, coopname, application, "createwthd3"_n);
verify_document_or_fail(return_statement);
auto exist_project = get_project(coopname, project_hash);
eosio::check(exist_project.has_value(), "Проект с указанным хэшем не найден");
capital_tables::capitalist_index capitalists(_capital, coopname.value);
auto capitalist = capitalists.find(username.value);
eosio::check(capitalist != capitalists.end(), "Капиталист не найден");
eosio::check(capitalist -> pending_rewards >= amount, "Недостаточно накопленных средств для создания запроса на возврат");
int64_t share_balance = get_capital_user_share_balance(coopname, username);
eosio::check(share_balance >= amount.amount, "Недостаточно долей для уменьшения");
// Обновление данных капиталиста
capitalists.modify(capitalist, coopname, [&](auto &c) {
c.pending_rewards -= amount;
c.returned_rewards += amount;
});
// Обновление глобального состояния
auto state = get_global_state(coopname);
auto program_share_balance = get_capital_program_share_balance(coopname);
int64_t prev_total_shares = program_share_balance;
int64_t new_total_shares = prev_total_shares - amount.amount;
eosio::check(new_total_shares >= 0, "Нельзя уменьшить total_shares ниже 0");
const int64_t PRECISION = 100000000; // 1e8 — масштаб фиксированной дроби
if (new_total_shares > 0) {
eosio::check(state.program_membership_cumulative_reward_per_share >= 0, "Некорректное значение reward_per_share");
// Переводим значение в фиксированную точку
int128_t base = static_cast<int128_t>(state.program_membership_cumulative_reward_per_share);
int128_t scaled = base * PRECISION;
int128_t scaled_result = (scaled * prev_total_shares) / new_total_shares;
// Обратно в i64, округляя
state.program_membership_cumulative_reward_per_share = static_cast<int64_t>(scaled_result / PRECISION);
} else {
state.program_membership_cumulative_reward_per_share = 0;
}
update_global_state(state);
auto exist_withdraw = get_program_withdraw(coopname, withdraw_hash);
eosio::check(!exist_withdraw.has_value(), "Заявка на возврат с таким хэшем уже существует");
capital_tables::program_withdraws_index program_withdraws(_capital, coopname.value);
program_withdraws.emplace(coopname, [&](auto &w) {
w.id = get_global_id_in_scope(_capital, coopname, "withdraws3"_n);
w.coopname = coopname;
w.withdraw_hash = withdraw_hash;
w.username = username;
w.amount = amount;
w.return_statement = return_statement;
});
}
@@ -1,29 +1,14 @@
void capital::capauthwthd2(eosio::name coopname, uint64_t withdraw_id, document authorization) {
void capital::capauthwthd2(name coopname, uint64_t withdraw_id, document authorization) {
require_auth(_soviet);
capital_tables::project_withdraws_index project_withdraws(_capital, coopname.value);
auto withdraw = project_withdraws.find(withdraw_id);
eosio::check(withdraw != project_withdraws.end(), "Объект возврата не найден");
auto exist_contributor = capital::get_active_contributor_or_fail(coopname, withdraw -> project_hash, withdraw -> username);
contributor_index contributors(_capital, coopname.value);
auto contributor = contributors.find(exist_contributor -> id);
contributors.modify(contributor, coopname, [&](auto &c) {
c.returned += withdraw -> amount;
});
project_withdraws.modify(withdraw, _capital, [&](auto &w){
w.authorized_return_statement = authorization;
});
std::string memo = "Зачёт части целевого паевого взноса по программе 'Капитализация' в качестве паевого взноса по участию в 'Цифровой Кошелёк'";
Wallet::sub_blocked_funds(_capital, coopname, withdraw->username, withdraw->amount, _capital_program, memo);
Wallet::add_available_funds(_capital, coopname, withdraw->username, withdraw->amount, _wallet_program, memo);
// списание с капитализации
Wallet::sub_blocked_funds(_capital, coopname, withdraw -> username, withdraw -> amount, _capital_program);
// добавление в кошелёк
Wallet::add_available_funds(_capital, coopname, withdraw -> username, withdraw -> amount, _wallet_program);
project_withdraws.erase(withdraw);
}
@@ -5,24 +5,47 @@ void capital::createwthd2(name coopname, name application, name username, checks
auto exist_project = get_project(coopname, project_hash);
eosio::check(exist_project.has_value(), "Проект с указанным хэшем не найден");
auto exist_contributor = capital::get_active_contributor_or_fail(coopname, project_hash, username);
eosio::check(exist_contributor -> pending_rewards >= amount, "Недостаточно накопленных средств для создания запроса на возврат");
contributor_index contributors(_capital, coopname.value);
auto contributor = contributors.find(exist_contributor -> id);
eosio::check(contributor->share_balance >= amount, "Недостаточно долей для уменьшения");
// Обновление долей
contributors.modify(contributor, coopname, [&](auto &c) {
c.pending_rewards -= amount;
c.returned += amount;
c.share_balance -= amount;
});
// Обновление проекта
project_index projects(_capital, coopname.value);
auto project = projects.find(exist_project->id);
int64_t prev_total_shares = project->total_share_balance.amount;
int64_t new_total_shares = prev_total_shares - amount.amount;
eosio::check(new_total_shares >= 0, "Нельзя уменьшить total_shares ниже 0");
if (new_total_shares > 0) {
projects.modify(project, coopname, [&](auto &p) {
p.membership_cumulative_reward_per_share = (p.membership_cumulative_reward_per_share * prev_total_shares) / new_total_shares;
p.total_share_balance -= amount;
});
} else {
projects.modify(project, coopname, [&](auto &p) {
p.membership_cumulative_reward_per_share = 0;
p.total_share_balance = asset(0, _root_govern_symbol);
});
}
// Запись возврата
auto exist_withdraw = get_result_withdraw(coopname, withdraw_hash);
eosio::check(!exist_withdraw.has_value(), "Заявка на взнос-возврат с таким хэшем уже существует");
capital_tables::project_withdraws_index project_withdraws(_capital, coopname.value);
project_withdraws.emplace(coopname, [&](auto &w) {
w.id = get_global_id_in_scope(_capital, coopname, "withdraws2"_n);
w.coopname = coopname;
@@ -32,4 +55,4 @@ void capital::createwthd2(name coopname, name application, name username, checks
w.amount = amount;
w.return_statement = return_statement;
});
}
}
@@ -1,7 +1,6 @@
void capital::approvewthd1(name coopname, name application, name approver, checksum256 withdraw_hash, document approved_contribution_statement, document approved_return_statement) {
void capital::approvewthd1(name coopname, name application, name approver, checksum256 withdraw_hash, document approved_return_statement) {
check_auth_or_fail(_capital, coopname, application, "approvewthd1"_n);
verify_document_or_fail(approved_contribution_statement);
verify_document_or_fail(approved_return_statement);
auto exist_withdraw = get_result_withdraw(coopname, withdraw_hash);
@@ -12,17 +11,12 @@ void capital::approvewthd1(name coopname, name application, name approver, check
result_withdraws.modify(withdraw, coopname, [&](auto &i) {
i.status = "approved"_n;
i.approved_contribution_statement = approved_contribution_statement;
i.approved_return_statement = approved_return_statement;
});
//отправляем в совет
action(permission_level{ _capital, "active"_n}, _soviet, _capital_withdraw_from_result_authorize_contribution_action,
std::make_tuple(coopname, withdraw -> username, withdraw -> id, withdraw -> contribution_statement, std::string("")))
.send();
action(permission_level{ _capital, "active"_n}, _soviet, _capital_withdraw_from_result_authorize_return_action,
std::make_tuple(coopname, withdraw -> username, withdraw -> id, withdraw -> return_statement, std::string("")))
action(permission_level{ _capital, "active"_n}, _soviet, "createagenda"_n,
std::make_tuple(coopname, withdraw -> username, _capital, _capital_withdraw_from_result_authorize_action, withdraw -> id, withdraw -> return_statement, std::string("")))
.send();
};
@@ -1,37 +0,0 @@
// действие авторизации возврата вызывается после получения авторизаций совета на взнос и возврат взноса
void capital::authwithdrw1(eosio::name coopname, checksum256 withdraw_hash) {
require_auth(_capital);
auto exist_withdraw = get_result_withdraw(coopname, withdraw_hash);
eosio::check(exist_withdraw.has_value(), "Объект взноса-возврата не найден");
capital_tables::result_withdraws_index result_withdraws(_capital, coopname.value);
auto withdraw = result_withdraws.find(exist_withdraw -> id);
//обновить сумму выводов по проекту
auto exist_project = get_project(coopname, withdraw -> project_hash);
project_index projects(_capital, coopname.value);
auto project = projects.find(exist_project->id);
projects.modify(project, _capital, [&](auto &p){
p.spend += withdraw -> amount;
});
auto exist_contributor = capital::get_active_contributor_or_fail(coopname, withdraw -> project_hash, withdraw -> username);
contributor_index contributors(_capital, coopname.value);
auto contributor = contributors.find(exist_contributor -> id);
contributors.modify(contributor, coopname, [&](auto &c) {
c.withdrawed += withdraw -> amount;
});
// списание с УХД
Wallet::sub_blocked_funds(_capital, coopname, withdraw -> username, withdraw -> amount, _cofund_program);
// добавление в кошелёк
Wallet::add_available_funds(_capital, coopname, withdraw -> username, withdraw -> amount, _wallet_program);
result_withdraws.erase(withdraw);
}
@@ -0,0 +1,22 @@
void capital::capauthwthd1(eosio::name coopname, uint64_t withdraw_id, document authorization) {
require_auth(_soviet);
//Получаем объект возврата
capital_tables::result_withdraws_index result_withdraws(_capital, coopname.value);
auto withdraw = result_withdraws.find(withdraw_id);
eosio::check(withdraw != result_withdraws.end(), "Объект взноса-возврата не найден");
auto exist_contributor = capital::get_active_contributor_or_fail(coopname, withdraw -> project_hash, withdraw -> username);
auto exist_result = get_result_or_fail(coopname, withdraw -> result_hash, "Результат не найден");
// списание с УХД
std::string memo_out = "Зачёт части целевого паевого взноса по договору УХД с ID: " + std::to_string(exist_contributor -> id) + " в качестве паевого взноса по программе 'Цифровой Кошелёк'";
// списываем с кошелька программы генерации при договоре УХД
Wallet::sub_blocked_funds(_capital, coopname, withdraw -> username, withdraw -> amount, _source_program, memo_out);
// добавление в кошелёк
Wallet::add_available_funds(_capital, coopname, withdraw -> username, withdraw -> amount, _wallet_program, memo_out);
result_withdraws.erase(withdraw);
}
@@ -1,13 +0,0 @@
void capital::capauthwthdc(eosio::name coopname, uint64_t withdraw_id, document authorization) {
require_auth(_soviet);
capital_tables::result_withdraws_index result_withdraws(_capital, coopname.value);
auto withdraw = result_withdraws.find(withdraw_id);
eosio::check(withdraw != result_withdraws.end(), "Объект взноса-возврата не найден");
result_withdraws.modify(withdraw, _capital, [&](auto &w){
w.authorized_contribution_statement = authorization;
});
capital::try_finalize_withdrawal(coopname, withdraw);
}
@@ -1,13 +0,0 @@
void capital::capauthwthdr(eosio::name coopname, uint64_t withdraw_id, document authorization) {
require_auth(_soviet);
capital_tables::result_withdraws_index result_withdraws(_capital, coopname.value);
auto withdraw = result_withdraws.find(withdraw_id);
eosio::check(withdraw != result_withdraws.end(), "Объект взноса-возврата не найден");
result_withdraws.modify(withdraw, _capital, [&](auto &w){
w.authorized_return_statement = authorization;
});
try_finalize_withdrawal(coopname, withdraw);
}
@@ -1,38 +1,61 @@
void capital::createwthd1(eosio::name coopname, eosio::name application, eosio::name username, checksum256 result_hash, checksum256 withdraw_hash, std::vector<checksum256> commit_hashes, document contribution_statement, document return_statement) {
void capital::createwthd1(eosio::name coopname, eosio::name application, eosio::name username, checksum256 result_hash, checksum256 withdraw_hash, asset amount, document return_statement) {
check_auth_or_fail(_capital, coopname, application, "createwthd1"_n);
verify_document_or_fail(contribution_statement);
verify_document_or_fail(return_statement);
Wallet::validate_asset(amount);
auto exist_result = get_result(coopname, result_hash);
eosio::check(exist_result.has_value(), "Результат с указанным хэшем не найден");
auto exist_project = get_project(coopname, exist_result -> project_hash);
eosio::check(exist_project.has_value(), "Проект с указанным хэшем не найден");
auto exist_contributor = capital::get_active_contributor_or_fail(coopname, exist_result -> project_hash, username);
eosio::asset amount = asset(0, _root_govern_symbol);
uint64_t count = 0;
for (const auto& commit_hash : commit_hashes) {
amount += get_amount_for_withdraw_from_commit(coopname, username, commit_hash);
count++;
eosio::check(count <= 20, "Нельзя оформить более 20 коммитов на раз");
}
contributor_index contributors(_capital, coopname.value);
auto contributor = contributors.find(exist_contributor -> id);
eosio::check(contributor -> available >= amount, "Недостаточно средств для создания запроса на материальную помощь");
contributors.modify(contributor, coopname, [&](auto &c) {
c.available -= amount;
//обновить сумму выводов по проекту
project_index projects(_capital, coopname.value);
auto project = projects.find(exist_project->id);
eosio::check(project -> total_share_balance >= amount, "Недостаточно средств в project.total_share_balance проекта для осуществления возврата");
projects.modify(project, _capital, [&](auto &p){
p.withdrawed += amount;
p.total_share_balance -= amount;
});
auto exist_contributor = capital::get_active_contributor_or_fail(coopname, exist_result -> project_hash, username);
contributor_index contributors(_capital, coopname.value);
auto contributor = contributors.find(exist_contributor -> id);
eosio::check(contributor -> share_balance >= amount, "Недостаточно средств в contributor.share_balance для осуществления возврата");
contributors.modify(contributor, coopname, [&](auto &c) {
c.withdrawed += amount;
c.share_balance -= amount;
});
auto exist_resactor = get_resactor_or_fail(coopname, exist_result->result_hash, username, "Объект актора в результате не найден");
resactor_index ractors(_capital, coopname.value);
auto resactor = ractors.find(exist_resactor.id);
eosio::check(resactor -> available >= amount, "Недостаточно средств для создания возврата");
eosio::check(resactor -> creators_bonus_shares >= amount.amount, "Недостаточно средств в creators_bonus_shares для создания возврата");
ractors.modify(resactor, coopname, [&](auto &ra) {
ra.available -= amount;
ra.creators_bonus_shares -= amount.amount;
});
result_index results(_capital, coopname.value);
auto result = results.find(exist_result -> id);
eosio::check(result -> total_creators_bonus_shares >= amount.amount, "Недостаточное количество result -> total_creators_bonus_shares для осуществления возврата");
results.modify(result, coopname, [&](auto &row) {
row.total_creators_bonus_shares -= amount.amount;
});
auto exist_withdraw = get_result_withdraw(coopname, withdraw_hash);
eosio::check(!exist_withdraw.has_value(), "Заявка на взнос-возврат с таким хэшем уже существует");
eosio::check(!exist_withdraw.has_value(), "Заявка на возврат с таким хэшем уже существует");
capital_tables::result_withdraws_index result_withdraws(_capital, coopname.value);
@@ -40,12 +63,10 @@ void capital::createwthd1(eosio::name coopname, eosio::name application, eosio::
w.id = get_global_id_in_scope(_capital, coopname, "withdraws1"_n);
w.coopname = coopname;
w.withdraw_hash = withdraw_hash;
w.commit_hashes = commit_hashes;
w.result_hash = result_hash;
w.project_hash = exist_result -> project_hash;
w.username = username;
w.amount = amount;
w.contribution_statement = contribution_statement;
w.return_statement = return_statement;
});
};
+4 -6
View File
@@ -56,16 +56,13 @@ void gateway::adduser(eosio::name coopname, eosio::name username, eosio::asset i
).send();
if (spread_initial) {
action(
permission_level{ _gateway, "active"_n},
_fund,
"addinitial"_n,
std::make_tuple(coopname, initial)
).send();
}
}
/**
@@ -113,7 +110,9 @@ void gateway::createwthdrw(eosio::name coopname, eosio::name application, eosio:
std::make_tuple(coopname, username, id, document)
).send();
Wallet::block_funds(_gateway, coopname, username, quantity, _wallet_program);
std::string memo_in = "Возврат части целевого паевого взноса по программе 'Цифровой Кошелёк' с ID: " + std::to_string(id);
Wallet::block_funds(_gateway, coopname, username, quantity, _wallet_program, memo_in);
};
@@ -244,7 +243,6 @@ void gateway::wthdfail(eosio::name coopname, eosio::name application, uint64_t w
permission_level{ _gateway, "active"_n},
_soviet,
"unblockbal"_n,
std::make_tuple(coopname, withdraw -> username, _wallet_program_id, withdraw -> quantity)
std::make_tuple(coopname, withdraw -> username, _wallet_program_id, withdraw -> quantity, memo)
).send();
}
@@ -109,7 +109,7 @@ void gateway::dpcomplete(eosio::name coopname, eosio::name admin, uint64_t depos
permission_level{ _gateway, "active"_n},
_soviet,
"addbal"_n,
std::make_tuple(coopname, deposit -> username, _wallet_program_id, deposit -> quantity)
std::make_tuple(coopname, deposit -> username, _wallet_program_id, deposit -> quantity, std::string("Паевой взнос в ЦПП 'Цифровой Кошелёк'"))
).send();
action(
@@ -165,7 +165,7 @@ void gateway::dprefund(eosio::name coopname, eosio::name admin, uint64_t deposit
permission_level{ _gateway, "active"_n},
_soviet,
"subbal"_n,
std::make_tuple(coopname, deposit -> username, _wallet_program_id, deposit -> quantity, true)
std::make_tuple(coopname, deposit -> username, _wallet_program_id, deposit -> quantity, true, "Отмена паевого взноса в ЦПП 'Цифровой Кошелёк'")
).send();
action(
+7 -3
View File
@@ -79,12 +79,16 @@ static constexpr eosio::name _product_return_action = "productrtrn"_n;
// capitalization linked actions
static constexpr eosio::name _capital_contributor_authorize_action = "capregcontr"_n;
static constexpr eosio::name _capital_invest_authorize_action = "capauthinvst"_n;
static constexpr eosio::name _capital_withdraw_from_result_authorize_contribution_action = "capauthwthdc"_n;
static constexpr eosio::name _capital_withdraw_from_result_authorize_return_action = "capauthwthdr"_n;
static constexpr eosio::name _capital_withdraw_from_result_authorize_action = "capauthwthd1"_n;
static constexpr eosio::name _capital_expense_authorize_action = "capauthexpns"_n;
static constexpr eosio::name _capital_commit_authorize_action = "capauthcmmt"_n;
static constexpr eosio::name _capital_claim_authorize_action = "capauthclaim"_n;
static constexpr eosio::name _capital_withdraw_from_project_authorize_action = "capauthwthd2"_n;
static constexpr eosio::name _capital_withdraw_from_program_authorize_action = "capauthwthd3"_n;
static constexpr eosio::name _claim_action = "claim"_n;
@@ -104,7 +108,7 @@ static constexpr eosio::name _withdraw_callback_action = "wthdrcallbck"_n;
//program_types
static constexpr eosio::name _wallet_program = "wallet"_n;
static constexpr eosio::name _sosedi_program = "cooplace"_n;
static constexpr eosio::name _cofund_program = "cofund"_n;
static constexpr eosio::name _source_program = "source"_n;
static constexpr eosio::name _capital_program = "capital"_n;
//program_ids
+19 -17
View File
@@ -46,21 +46,6 @@ typedef eosio::multi_index<
> programs_index; /*!< Тип мультииндекса для таблицы целевых программ */
std::optional<progwallet> get_program_wallet (eosio::name coopname, eosio::name username, uint64_t program_id) {
progwallets_index progwallets(_soviet, coopname.value);
auto balances_by_username_and_program = progwallets.template get_index<"byuserprog"_n>();
auto username_and_program_index = combine_ids(username.value, program_id);
auto wallet = balances_by_username_and_program.find(username_and_program_index);
if (wallet == balances_by_username_and_program.end()) {
return std::nullopt;
}
return *wallet;
}
program get_program_or_fail(eosio::name coopname, uint64_t program_id) {
programs_index programs(_soviet, coopname.value);
print("program_id: ", program_id);
@@ -136,7 +121,7 @@ struct ProgramInfo {
static const std::map<eosio::name, ProgramInfo> program_map = {
{_wallet_program, {1, 1}}, // program_id = 1, draft_id = 1
{_sosedi_program, {2, 699}}, // program_id = 2, draft_id = 699
{_cofund_program, {3, 0}}, // program_id = 3, draft_id = 0
{_source_program, {3, 0}}, // program_id = 3, draft_id = 0
{_capital_program, {4, 1000}} // program_id = 4, draft_id = 1000
};
@@ -157,4 +142,21 @@ inline uint64_t get_draft_id(const eosio::name& type) {
auto it = program_map.find(type);
eosio::check(it != program_map.end(), "Недопустимый тип программы");
return it->second.draft_id;
}
}
std::optional<progwallet> get_program_wallet (eosio::name coopname, eosio::name username, name type) {
auto program_id = get_program_id(type);
progwallets_index progwallets(_soviet, coopname.value);
auto balances_by_username_and_program = progwallets.template get_index<"byuserprog"_n>();
auto username_and_program_index = combine_ids(username.value, program_id);
auto wallet = balances_by_username_and_program.find(username_and_program_index);
if (wallet == balances_by_username_and_program.end()) {
return std::nullopt;
}
return *wallet;
}
+34 -14
View File
@@ -1,88 +1,108 @@
namespace Wallet {
inline void validate_asset(const eosio::asset& amount) {
check(amount.symbol == _root_govern_symbol, "Invalid token symbol");
check(amount.is_valid(), "Invalid asset");
check(amount.amount > 0, "Amount must be positive");
}
inline void add_available_funds(eosio::name contract, eosio::name coopname, eosio::name username, eosio::asset amount, eosio::name program_type) {
inline void add_available_funds(eosio::name contract, eosio::name coopname, eosio::name username, eosio::asset amount, eosio::name program_type, std::string memo) {
auto program = get_program_or_fail(coopname, get_program_id(program_type));
action(
permission_level{ contract, "active"_n },
_soviet,
"addbal"_n,
std::make_tuple(coopname, username, program.id, amount)
std::make_tuple(coopname, username, program.id, amount, memo)
).send();
}
inline void sub_available_funds(eosio::name contract, eosio::name coopname, eosio::name username, eosio::asset amount, eosio::name program_type) {
inline void sub_available_funds(eosio::name contract, eosio::name coopname, eosio::name username, eosio::asset amount, eosio::name program_type, std::string memo) {
auto program = get_program_or_fail(coopname, get_program_id(program_type));
action(
permission_level{ contract, "active"_n },
_soviet,
"subbal"_n,
std::make_tuple(coopname, username, program.id, amount, false)
std::make_tuple(coopname, username, program.id, amount, false, memo)
).send();
}
inline void add_blocked_funds(eosio::name contract, eosio::name coopname, eosio::name username, eosio::asset amount, eosio::name program_type) {
inline void add_blocked_funds(eosio::name contract, eosio::name coopname, eosio::name username, eosio::asset amount, eosio::name program_type, std::string memo) {
auto program = get_program_or_fail(coopname, get_program_id(program_type));
action(
permission_level{ contract, "active"_n },
_soviet,
"addbal"_n,
std::make_tuple(coopname, username, program.id, amount)
std::make_tuple(coopname, username, program.id, amount, memo)
).send();
action(
permission_level{ contract, "active"_n },
_soviet,
"blockbal"_n,
std::make_tuple(coopname, username, program.id, amount)
std::make_tuple(coopname, username, program.id, amount, memo)
).send();
}
inline void sub_blocked_funds(eosio::name contract, eosio::name coopname, eosio::name username, eosio::asset amount, eosio::name program_type) {
inline void sub_blocked_funds(eosio::name contract, eosio::name coopname, eosio::name username, eosio::asset amount, eosio::name program_type, std::string memo) {
auto program = get_program_or_fail(coopname, get_program_id(program_type));
action(
permission_level{ contract, "active"_n },
_soviet,
"unblockbal"_n,
std::make_tuple(coopname, username, program.id, amount)
std::make_tuple(coopname, username, program.id, amount, memo)
).send();
action(
permission_level{ contract, "active"_n },
_soviet,
"subbal"_n,
std::make_tuple(coopname, username, program.id, amount, false)
std::make_tuple(coopname, username, program.id, amount, false, memo)
).send();
}
inline void block_funds(eosio::name contract, eosio::name coopname, eosio::name username, eosio::asset amount, eosio::name program_type){
inline void block_funds(eosio::name contract, eosio::name coopname, eosio::name username, eosio::asset amount, eosio::name program_type, std::string memo){
auto program = get_program_or_fail(coopname, get_program_id(program_type));
action(
permission_level{ contract, "active"_n },
_soviet,
"blockbal"_n,
std::make_tuple(coopname, username, program.id, amount)
std::make_tuple(coopname, username, program.id, amount, memo)
).send();
}
inline void unblock_funds(eosio::name contract, eosio::name coopname, eosio::name username, eosio::asset amount, eosio::name program_type){
inline void unblock_funds(eosio::name contract, eosio::name coopname, eosio::name username, eosio::asset amount, eosio::name program_type, std::string memo){
auto program = get_program_or_fail(coopname, get_program_id(program_type));
action(
permission_level{ contract, "active"_n },
_soviet,
"unblockbal"_n,
std::make_tuple(coopname, username, program.id, amount)
std::make_tuple(coopname, username, program.id, amount, memo)
).send();
}
inline void pay_membership_fee(name contract, name coopname, name username, name amount, eosio::name program_type, std::string memo) {
auto program = get_program_or_fail(coopname, get_program_id(program_type));
action(
permission_level{ contract, "active"_n },
_soviet,
"subbal"_n,
std::make_tuple(coopname, username, program.id, amount, false, memo)
).send();
action(
permission_level{ contract, "active"_n },
_soviet,
"addmemberfee"_n,
std::make_tuple(coopname, username, program.id, amount, memo)
).send();
}
}
@@ -107,32 +107,8 @@ void marketplace::create_parent(eosio::name type, const exchange_params& params)
auto program = get_program_or_fail(params.coopname, params.program_id);
//Специальные проверки
if (type == "offer"_n) {
//срок жизни продукта должен быть установлен
eosio::check(params.product_lifecycle_secs > 0, "Гарантийный срок возврата для имущества должен быть установлен");
}
else if(type == "order"_n) {
eosio::asset quantity = params.unit_cost * params.units;
action(
permission_level{ _marketplace, "active"_n},
_soviet,
"addbal"_n,
std::make_tuple(params.coopname, params.username, params.program_id, quantity)
).send();
action(
permission_level{ _marketplace, "active"_n},
_soviet,
"blockbal"_n,
std::make_tuple(params.coopname, params.username, params.program_id, quantity)
).send();
};
//срок гарантийного возврата должен быть установлен
eosio::check(params.product_lifecycle_secs > 0, "Гарантийный срок возврата для имущества должен быть установлен");
exchange.emplace(_marketplace, [&](auto &i) {
i.id = id;
@@ -229,12 +205,14 @@ void marketplace::create_child(eosio::name type, const exchange_params& params)
//родительская заявка должна быть противоположного типа
eosio::check(parent_change -> type == "offer"_n, "Неверный тип родительской заявки");
std::string memo = "Начало поставки по программе №" + std::to_string(params.program_id) + " с ID: " + std::to_string(id);
//Для блокировки средств необходимо их иметь на ЦПП, т.е. предварительно необходимо сконвертировать их с ЦПП кошелька
action(
permission_level{ _marketplace, "active"_n},
_soviet,
"blockbal"_n,
std::make_tuple(params.coopname, params.username, params.program_id, total_cost)
std::make_tuple(params.coopname, params.username, params.program_id, total_cost, memo)
).send();
}
@@ -402,19 +380,21 @@ void marketplace::create_child(eosio::name type, const exchange_params& params)
ch.status = "supplied2"_n;
ch.product_contribution_act = document;
});
std::string memo = "Приём имущественного паевого взноса по программе №" + std::to_string(change -> program_id) + " с ID: " + std::to_string(change -> id);
action(
permission_level{ _marketplace, "active"_n},
_soviet,
"addbal"_n,
std::make_tuple(coopname, change -> product_contributor, change -> program_id, change -> supplier_amount)
std::make_tuple(coopname, change -> product_contributor, change -> program_id, change -> supplier_amount, memo)
).send();
action(
permission_level{ _marketplace, "active"_n},
_soviet,
"blockbal"_n,
std::make_tuple(coopname, change -> product_contributor, change -> program_id, change -> supplier_amount)
std::make_tuple(coopname, change -> product_contributor, change -> program_id, change -> supplier_amount, memo)
).send();
//увеличиваем паевой фонд
@@ -702,20 +682,22 @@ void marketplace::create_child(eosio::name type, const exchange_params& params)
});
auto program = get_program_or_fail(coopname, change -> program_id);
std::string memo = "Успешное завершение поставки имущества по программе №" + std::to_string(change -> program_id) + " с ID: " + std::to_string(change -> id);
//Заказчику разблокируем баланс ЦПП кооплекса и списываем его
action(
permission_level{ _marketplace, "active"_n},
_soviet,
"unblockbal"_n,
std::make_tuple(coopname, change -> money_contributor, change -> program_id, change -> total_cost)
std::make_tuple(coopname, change -> money_contributor, change -> program_id, change -> total_cost, memo)
).send();
action(
permission_level{ _marketplace, "active"_n},
_soviet,
"subbal"_n,
std::make_tuple(coopname, change -> money_contributor, change -> program_id, change -> total_cost, false)
std::make_tuple(coopname, change -> money_contributor, change -> program_id, change -> total_cost, false, memo)
).send();
@@ -724,7 +706,7 @@ void marketplace::create_child(eosio::name type, const exchange_params& params)
permission_level{ _marketplace, "active"_n},
_soviet,
"unblockbal"_n,
std::make_tuple(coopname, change -> product_contributor, change -> program_id, change -> supplier_amount)
std::make_tuple(coopname, change -> product_contributor, change -> program_id, change -> supplier_amount, memo)
).send();
@@ -742,7 +724,7 @@ void marketplace::create_child(eosio::name type, const exchange_params& params)
permission_level{ _marketplace, "active"_n},
_soviet,
"addmemberfee"_n,
std::make_tuple(coopname, change -> money_contributor, change -> program_id, change -> membership_fee)
std::make_tuple(coopname, change -> money_contributor, change -> program_id, change -> membership_fee, memo)
).send();
}
}
@@ -779,7 +761,6 @@ void marketplace::create_child(eosio::name type, const exchange_params& params)
eosio::check(parent_change != exchange.end(), "Родительская заявка не найдена");
eosio::check(change -> status == "published"_n, "Только заявка в статусе ожидания может быть отклонена");
exchange.modify(change, _marketplace, [&](auto &o){
o.status = "declined"_n;
o.declined_at = eosio::time_point_sec(eosio::current_time_point().sec_since_epoch());
@@ -787,12 +768,13 @@ void marketplace::create_child(eosio::name type, const exchange_params& params)
});
if (change -> type == "order"_n) {
std::string memo = "Отказ в поставке по программе №" + std::to_string(change -> program_id) + " с ID: " + std::to_string(change -> id);
action(
permission_level{ _marketplace, "active"_n},
_soviet,
"unblockbal"_n,
std::make_tuple(coopname, change -> money_contributor, change -> program_id, change -> total_cost)
std::make_tuple(coopname, change -> money_contributor, change -> program_id, change -> total_cost, memo)
).send();
};
@@ -868,11 +850,13 @@ void marketplace::cancel_child(eosio::name coopname, eosio::name username, uint6
// оповещаем совет об отмене и разблокируем средства
if (change -> type == "order"_n) {
std::string memo = "Отмена поставки по программе №" + std::to_string(change -> program_id) + " с ID: " + std::to_string(change -> id);
action(
permission_level{ _marketplace, "active"_n},
_soviet,
"unblockbal"_n,
std::make_tuple(coopname, change -> money_contributor, change -> program_id, change -> total_cost)
std::make_tuple(coopname, change -> money_contributor, change -> program_id, change -> total_cost, memo)
).send();
};
+1 -18
View File
@@ -17,9 +17,7 @@
#include "src/decisions.cpp"
#include "src/branch.cpp"
#include "src/capital.cpp"
#include "src/capital/capauthwthdc.cpp"
#include "src/capital/capauthwthdr.cpp"
#include "src/openprogwall.cpp"
#include "src/agenda.cpp"
using namespace eosio;
@@ -104,17 +102,6 @@ void soviet::migrate() {
m.minimum_amount = _provider_minimum;
});
// wallets_index wallets(_soviet, _provider.value);
// wallets.emplace(_system, [&](auto &w) {
// w.username = _provider_chairman;
// w.coopname = _provider;
// w.available = asset(0, _root_govern_symbol);
// w.blocked = asset(0, _root_govern_symbol);
// w.minimum = _provider_minimum;
// });
board_member member {
.username = _provider_chairman,
.is_voting = true,
@@ -260,10 +247,6 @@ void soviet::exec(eosio::name executer, eosio::name coopname, uint64_t decision_
soviet::subaccum_effect(executer, coopname, decision->id, decision->batch_id);
} else if (decision -> type == _free_decision_action) {//операция свободного решения
soviet::freedecision_effect(executer, coopname, decision->id);
} else if (decision -> type == _capital_withdraw_from_result_authorize_contribution_action) {//операция взноса в момент вывода по контракту капитализации
soviet::capital_contribute_on_withdraw_effect(executer, coopname, decision -> id);
} else if (decision -> type == _capital_withdraw_from_result_authorize_return_action) {//операция взноса в момент вывода по контракту капитализации
soviet::capital_return_on_withdraw_effect(executer, coopname, decision -> id);
} else if (decision -> type == _capital_contributor_authorize_action) {//операция регистрации контрибьютора (заключение договора УХД)
soviet::capital_register_contributor_authorize_action_effect(executer, coopname, decision -> id);
} else if (decision -> type == _capital_invest_authorize_action) {//операция приёма паевого взноса с кошелька на проект
+6 -13
View File
@@ -82,7 +82,7 @@ public:
[[eosio::action]] void regpaid(eosio::name coopname, eosio::name username);
[[eosio::action]] void openprogwall(name coopname, name username, name program_type, uint64_t agreement_id);
//voting.cpp
[[eosio::action]] void votefor(eosio::name coopname, eosio::name member, uint64_t decision_id);
@@ -118,11 +118,11 @@ public:
// [[eosio::action]] void subprogbal(eosio::name coopname, eosio::name username, uint64_t program_id, eosio::asset quantity);
void withdraw_effect(eosio::name executer, eosio::name coopname, uint64_t decision_id, uint64_t batch_id);
[[eosio::action]] void addbal(eosio::name coopname, eosio::name username, uint64_t program_id, eosio::asset quantity);
[[eosio::action]] void subbal(eosio::name coopname, eosio::name username, uint64_t program_id, eosio::asset quantity, bool skip_available_check);
[[eosio::action]] void blockbal(eosio::name coopname, eosio::name username, uint64_t program_id, eosio::asset quantity);
[[eosio::action]] void unblockbal(eosio::name coopname, eosio::name username, uint64_t program_id, eosio::asset quantity);
[[eosio::action]] void addmemberfee(eosio::name coopname, eosio::name username, uint64_t program_id, eosio::asset quantity);
[[eosio::action]] void addbal(eosio::name coopname, eosio::name username, uint64_t program_id, eosio::asset quantity, std::string memo);
[[eosio::action]] void subbal(eosio::name coopname, eosio::name username, uint64_t program_id, eosio::asset quantity, bool skip_available_check, std::string memo);
[[eosio::action]] void blockbal(eosio::name coopname, eosio::name username, uint64_t program_id, eosio::asset quantity, std::string memo);
[[eosio::action]] void unblockbal(eosio::name coopname, eosio::name username, uint64_t program_id, eosio::asset quantity, std::string memo);
[[eosio::action]] void addmemberfee(eosio::name coopname, eosio::name username, uint64_t program_id, eosio::asset quantity, std::string memo);
//addresses.cpp
@@ -150,8 +150,6 @@ public:
[[eosio::action]] void deletebranch(eosio::name coopname, eosio::name braname);
//capital.cpp
[[eosio::action]] void claim(eosio::name coopname, eosio::name username, uint64_t result_id, document statement, std::string meta);
void capital_contribute_on_withdraw_effect(eosio::name executer, eosio::name coopname, uint64_t decision_id);
void capital_return_on_withdraw_effect(eosio::name executer, eosio::name coopname, uint64_t decision_id);
[[eosio::action]] void capregcontr(eosio::name coopname, eosio::name username, uint64_t contributor_id, document statement, std::string meta);
@@ -159,11 +157,6 @@ public:
void capital_invest_authorize_action_effect(eosio::name executer, eosio::name coopname, uint64_t decision_id);
[[eosio::action]] void capauthinvst(eosio::name coopname, eosio::name username, uint64_t invest_id, document statement, std::string meta);
[[eosio::action]] void capauthwthdc(eosio::name coopname, eosio::name username, uint64_t withdraw_id, document statement, std::string meta);
[[eosio::action]] void capauthwthdr(eosio::name coopname, eosio::name username, uint64_t withdraw_id, document statement, std::string meta);
};
@@ -113,30 +113,4 @@ void soviet::capital_register_contributor_authorize_action_effect(eosio::name ex
decisions.erase(decision);
}
[[eosio::action]] void soviet::claim(eosio::name coopname, eosio::name username, uint64_t result_id, document statement, std::string meta) {
check_auth_or_fail(_soviet, coopname, username, "claim"_n);
decisions_index decisions(_soviet, coopname.value);
auto decision_id = get_id(_soviet, coopname, "decisions"_n);
decisions.emplace(_soviet, [&](auto &d){
d.id = decision_id;
d.coopname = coopname;
d.username = username;
d.type = _claim_action;
d.batch_id = result_id;
d.statement = statement;
d.created_at = eosio::time_point_sec(eosio::current_time_point().sec_since_epoch());
d.expired_at = eosio::time_point_sec(eosio::current_time_point().sec_since_epoch() + _decision_expiration);
d.meta = meta;
});
action(
permission_level{ _soviet, "active"_n},
_soviet,
"newsubmitted"_n,
std::make_tuple(coopname, username, _claim_action, decision_id, statement)
).send();
}
@@ -1,59 +0,0 @@
[[eosio::action]] void soviet::capauthwthdc(eosio::name coopname, eosio::name username, uint64_t withdraw_id, document statement, std::string meta) {
require_auth(_capital);
decisions_index decisions(_soviet, coopname.value);
auto decision_id = get_id(_soviet, coopname, "decisions"_n);
decisions.emplace(_soviet, [&](auto &d){
d.id = decision_id;
d.coopname = coopname;
d.username = username;
d.type = _capital_withdraw_from_result_authorize_contribution_action;
d.batch_id = withdraw_id;
d.statement = statement;
d.created_at = eosio::time_point_sec(eosio::current_time_point().sec_since_epoch());
d.expired_at = eosio::time_point_sec(eosio::current_time_point().sec_since_epoch() + _decision_expiration);
d.meta = meta;
});
action(
permission_level{ _soviet, "active"_n},
_soviet,
"newsubmitted"_n,
std::make_tuple(coopname, username, _capital_withdraw_from_result_authorize_contribution_action, decision_id, statement)
).send();
}
void soviet::capital_contribute_on_withdraw_effect(eosio::name executer, eosio::name coopname, uint64_t decision_id) {
decisions_index decisions(_soviet, coopname.value);
auto decision = decisions.find(decision_id);
action(
permission_level{ _soviet, "active"_n},
_capital,
_capital_withdraw_from_result_authorize_contribution_action,
std::make_tuple(coopname, decision -> batch_id, decision -> authorization)
).send();
action(
permission_level{ _soviet, "active"_n},
_soviet,
"newresolved"_n,
std::make_tuple(coopname, decision -> username, decision -> type, decision_id, decision -> statement)
).send();
action(
permission_level{ _soviet, "active"_n},
_soviet,
"newdecision"_n,
std::make_tuple(coopname, decision -> username, decision -> type, decision_id, decision -> authorization)
).send();
decisions.erase(decision);
};
@@ -1,58 +0,0 @@
[[eosio::action]] void soviet::capauthwthdr(eosio::name coopname, eosio::name username, uint64_t withdraw_id, document statement, std::string meta) {
require_auth(_capital);
decisions_index decisions(_soviet, coopname.value);
auto decision_id = get_id(_soviet, coopname, "decisions"_n);
decisions.emplace(_soviet, [&](auto &d){
d.id = decision_id;
d.coopname = coopname;
d.username = username;
d.type = _capital_withdraw_from_result_authorize_return_action;
d.batch_id = withdraw_id;
d.statement = statement;
d.created_at = eosio::time_point_sec(eosio::current_time_point().sec_since_epoch());
d.expired_at = eosio::time_point_sec(eosio::current_time_point().sec_since_epoch() + _decision_expiration);
d.meta = meta;
});
action(
permission_level{ _soviet, "active"_n},
_soviet,
"newsubmitted"_n,
std::make_tuple(coopname, username, _capital_withdraw_from_result_authorize_return_action, decision_id, statement)
).send();
}
void soviet::capital_return_on_withdraw_effect(eosio::name executer, eosio::name coopname, uint64_t decision_id) {
decisions_index decisions(_soviet, coopname.value);
auto decision = decisions.find(decision_id);
action(
permission_level{ _soviet, "active"_n},
_capital,
_capital_withdraw_from_result_authorize_return_action,
std::make_tuple(coopname, decision -> batch_id, decision -> authorization)
).send();
action(
permission_level{ _soviet, "active"_n},
_soviet,
"newresolved"_n,
std::make_tuple(coopname, decision -> username, decision -> type, decision_id, decision -> statement)
).send();
action(
permission_level{ _soviet, "active"_n},
_soviet,
"newdecision"_n,
std::make_tuple(coopname, decision -> username, decision -> type, decision_id, decision -> authorization)
).send();
decisions.erase(decision);
};
@@ -14,7 +14,7 @@ inline void set_prog_available(program &prog, const eosio::asset &newval) {
prog.available = newval; // достаточно прямого присвоения
}
void soviet::addmemberfee(eosio::name coopname, eosio::name username, uint64_t program_id, eosio::asset quantity){
void soviet::addmemberfee(eosio::name coopname, eosio::name username, uint64_t program_id, eosio::asset quantity, std::string memo){
eosio::check(has_auth(_marketplace) || has_auth(_soviet), "Недостаточно прав доступа");
auto cooperative = get_cooperative_or_fail(coopname);
@@ -39,7 +39,7 @@ void soviet::addmemberfee(eosio::name coopname, eosio::name username, uint64_t p
}
void soviet::addbal(eosio::name coopname, eosio::name username, uint64_t program_id, eosio::asset quantity) {
void soviet::addbal(eosio::name coopname, eosio::name username, uint64_t program_id, eosio::asset quantity, std::string memo) {
eosio::check(has_auth(_marketplace) || has_auth(_soviet) || has_auth(_capital) || has_auth(_gateway), "Недостаточно прав доступа");
programs_index programs(_soviet, coopname.value);
@@ -67,7 +67,7 @@ void soviet::addbal(eosio::name coopname, eosio::name username, uint64_t program
}
void soviet::subbal(eosio::name coopname, eosio::name username, uint64_t program_id, eosio::asset quantity, bool skip_available_check) {
void soviet::subbal(eosio::name coopname, eosio::name username, uint64_t program_id, eosio::asset quantity, bool skip_available_check, std::string memo) {
eosio::check(has_auth(_marketplace) || has_auth(_soviet) || has_auth(_capital) || has_auth(_gateway), "Недостаточно прав доступа");
programs_index programs(_soviet, coopname.value);
@@ -103,7 +103,7 @@ void soviet::subbal(eosio::name coopname, eosio::name username, uint64_t program
}
void soviet::blockbal(eosio::name coopname, eosio::name username, uint64_t program_id, eosio::asset quantity) {
void soviet::blockbal(eosio::name coopname, eosio::name username, uint64_t program_id, eosio::asset quantity, std::string memo) {
eosio::check(has_auth(_marketplace) || has_auth(_gateway) || has_auth(_soviet) || has_auth(_capital), "Недостаточно прав доступа");
auto cooperative = get_cooperative_or_fail(coopname);
@@ -136,7 +136,7 @@ void soviet::blockbal(eosio::name coopname, eosio::name username, uint64_t progr
}
void soviet::unblockbal(eosio::name coopname, eosio::name username, uint64_t program_id, eosio::asset quantity) {
void soviet::unblockbal(eosio::name coopname, eosio::name username, uint64_t program_id, eosio::asset quantity, std::string memo) {
eosio::check(has_auth(_marketplace) || has_auth(_gateway) || has_auth(_soviet) || has_auth(_capital), "Недостаточно прав доступа");
eosio::name payer = has_auth(_marketplace) ? _marketplace : _soviet;
@@ -0,0 +1,31 @@
void soviet::openprogwall(name coopname, name username, name program_type, uint64_t agreement_id) {
name payer = check_auth_and_get_payer_or_fail(contracts_whitelist);
auto program_wallet = get_program_wallet(coopname, username, program_type);
if (!program_wallet.has_value()) {
auto program_id = get_program_id(program_type);
if (agreement_id > 0) {
agreements_index agreements(_soviet, coopname.value);
auto agreement = agreements.find(agreement_id);
check(agreement != agreements.end(), "Соглашение не найдено");
check(agreement -> username == username, "Неверный пользователь соглашения и кошелька");
};
progwallets_index progwallets(_soviet, coopname.value);
//TODO: make payer coopname
progwallets.emplace(_soviet, [&](auto &b) {
b.id = progwallets.available_primary_key();
b.program_id = program_id;
b.coopname = coopname;
b.username = username;
b.agreement_id = agreement_id;
b.available = asset(0, _root_govern_symbol);
b.blocked = asset(0, _root_govern_symbol);
b.membership_contribution = asset(0, _root_govern_symbol);
});
};
};
+1 -1
View File
@@ -1,6 +1,6 @@
{
"name": "@coopenomics/contracts",
"version": "2.2.9",
"version": "2.2.10",
"private": true,
"scripts": {
"build:all": "./build-all.sh",

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