Аккаунты
Аккаунт в MONO
- это составной объект с информацией о пользователе. Он составляется из информации, которая описывает состояние пользователя на разных уровнях работы платформы с идентификацией по username
- имени аккаунта пользователя в блокчейне.
username
— это уникальный идентификатор пользователя в системе. Обычно он состоит из 12 латинских букв без пробелов и специальных символов. С помощью него производится сквозная идентификация принадлежности аккаунта к пользователю во всех кооперативных системах платформы. У всех пайщиков, кооперативов и кооперативных участков есть свои уникальные username
.
Временные ограничения
Блокчейн позволяет регистрировать и более короткие имена аккаунтов длинной до 12 символов a-z
и цифрами от 1 до 5, но на текущий момент эта функциональность недоступна.
Объект аккаунта¶
У каждого аккаунта есть 4 уровня хранения информации, которые удобно проследить по объекту Account
в GraphQL-API
:
BlockchainAccount
- объект аккаунта в блокчейне содержит системную информацию, такую как публичные ключи доступа, доступные вычислительные ресурсы, информация об установленном смарт-контракте, и т.д. и т.п. Это системный уровень обслуживания, где у каждого пайщика есть аккаунт, но не каждый аккаунт может быть пайщиком в каком-либо кооперативе. Все смарт-контракты устанавливаются и исполняются на этом уровне.
UserAccount
- объект пользователя кооперативной экономики содержит в блокчейне информацию о типе аккаунта пайщика (физическое лицо, ИП или организация), а также, обезличенные публичные данные (хэши) для верификации пайщиков между кооперативами. Этот уровень предназначен для хранения информации пайщика, которая необходима всем кооперативам, но не относится к какому-либо из них конкретно.
ParticipantAccount
- объект пайщика кооператива в таблице блокчейна, который определяет членство пайщика в конкретном кооперативе. Поскольку MONO
обслуживает только один кооператив, то в participant_account обычно содержится информация, которая описывает членство пайщика в том кооперативе, для которого развернут MONO
. Этот объект обезличен, публичен, и хранится в блокчейне.
ProviderAccount
- объект аккаунта в системе учёта провайдера, т.е. MONO. Здесь хранится приватная информация о пайщике кооператива, которая содержит его приватные данные. Эти данные не публикуются в блокчейне и не выходят за пределы базы данных провайдера. Они используются для заполнения шаблонов документов при нажатии соответствующих кнопок на платформе. Также, эта информация используется провайдером для организации входа пользователя в систему по наличию соответстветсвия между email и username в его базе данных и блокчейне (подробнее)
Зарегистрировать аккаунт¶
🛠️ SDK: Mutations.Accounts.RegisterAccount | 🔗 GraphQL API: Mutation.registerAccount
Вызов мутации регистрации аккаунта создаёт объект аккаунта в системе учета провайдера (но не регистрирует его в блокчейне). После вызова, пользователь получает возможность входа в систему на основании предоставленного при регистрации публичного ключа и адреса электронной почты.
Успешный вызов мутации НЕ означает, что пользователь становится пайщиком и получает блокчейн-аккаунт. При вызове мутации пользователь получает только объект ProviderAccount
, а для его перехода в пайщики необходимо пройти дополнительный путь, описанный в разделе Регистрация Пайщика.
Зарегистрировать аккаунт пользователя в системе
Регистрация аккаунта производится мутацией RegisterAccount, где в качестве переменных принимаются данные пользователя одного из трех типов, определяемых в перечислении AccountType
: Individual (физическое лицо), Organization (юридическое лицо) или Entrepreneur (индивидуальный предприниматель).
При указании типа пользователя Individual необходимо передать объект individual_data с данными физлица, при регистрации Organization - ожидается обязательная передача organization_data, при указании типа Entrepreneur - entrepreneur_data.
Имя пользователя username и публичный ключ public_key генерируются при создании экземпляра класса Account:
import { Classes } from '@coopenomics/sdk'
//генерируем новый аккант
const account = new Classes.Account()
В объекте account после генерации аккаунта содержится имя пользователя, приватный и публичный ключ. Сгенерированный приватный ключ из объекта аккаунта будет требоваться для входа в систему после регистрации.
// console.log(account)
{
name: "randomuserr",
private_key: "5JxyzABC1234567890defGHIJKLMNopqRSTUV",
public_key: "EOS6MRyAjQq8ud7hVNYcfnVPJqcVpscN5SozEZ8i8jUBS6yX79y6"
}
Используя сгенерированный объект аккаунта с ключами, проводим регистрацию в системе учёта провайдера, вызывая мутацию:
import { Mutations } from '@coopenomics/sdk';
const variables: Mutations.Accounts.RegisterAccount.IInput = {
data: {
email: <string>; // Электронная почта
entrepreneur_data?: <null | {
bank_account: {
account_number: <string>; // Номер банковского счета
bank_name: <string>; // Название банка
card_number?: <null | string>; // Номер карты
currency: <string>; // Валюта счета
details: {
bik: <string>; // БИК банка
corr: <string>; // Корреспондентский счет
kpp: <string>; // КПП банка
};
};
birthdate: <string>; // Дата рождения
city: <string>; // Город
country: <Russia>; // Страна
details: {
inn: <string>; // ИНН
ogrn: <string>; // ОГРН
};
first_name: <string>; // Имя
full_address: <string>; // Полный адрес
last_name: <string>; // Фамилия
middle_name: <string>; // Отчество
phone: <string>; // Телефон
}>; // Данные индивидуального предпринимателя
individual_data?: <null | {
birthdate: <string>; // Дата рождения
first_name: <string>; // Имя
full_address: <string>; // Полный адрес
last_name: <string>; // Фамилия
middle_name: <string>; // Отчество
passport?: <null | {
code: <string>;
issued_at: <string>;
issued_by: <string>;
number: <number>;
series: <number>;
}>; // Данные паспорта
phone: <string>; // Телефон
}>; // Данные физического лица
organization_data?: <null | {
bank_account: {
account_number: <string>; // Номер банковского счета
bank_name: <string>; // Название банка
card_number?: <null | string>; // Номер карты
currency: <string>; // Валюта счета
details: {
bik: <string>; // БИК банка
corr: <string>; // Корреспондентский счет
kpp: <string>; // КПП банка
};
};
city: <string>; // Город
country: <string>; // Страна
details: {
inn: <string>;
kpp: <string>;
ogrn: <string>;
};
fact_address: <string>; // Фактический адрес
full_address: <string>; // Полный адрес
full_name: <string>; // Полное наименование организации
phone: <string>; // Телефон
represented_by: {
based_on: <string>;
first_name: <string>;
last_name: <string>;
middle_name: <string>;
position: <string>;
};
short_name: <string>; // Краткое наименование организации
type: <OrganizationType>; // Тип организации
}>; // Данные организации
public_key?: <null | string>; // Публичный ключ
referer?: <null | string>; // Имя аккаунта реферера
type: <AccountType>; // Тип аккаунта
username: <string>; // Имя пользователя
};
};
const { [Mutations.Accounts.RegisterAccount.name]: result } = await client.Mutation(
Mutations.Accounts.RegisterAccount.mutation,
{ variables }
);
По-умолчанию, каждый пайщик регистрирует новый аккаунт в том кооперативе, в который вступает. Кооператив, при этом, самостоятельно управляет процессом восстановления ключей доступа, в случае их утери. Другими словами, обычно у одного пайщика, который состоит в несколькоих кооперативах - несколько аккаунтов.
Карта пайщика
Карта пайщика (CARDCOOP) - это сервис хранения ключей и данных пайщиков, который позволяет входить в несколько кооперативов без повторной регистрации в них, используя т.н. "быстрый вход" или "войти с помощью CARDCOOP". На текущий момент сервис в разработке. Однако, каждое имя аккаунта, связанные с ним приватные данные пайщика и ключи, могут рассматриваться как виртуальная карта пайщика в кооперативе.
Извлечь аккаунт¶
🛠️ SDK: Queries.Accounts.GetAccount | 🔗 GraphQL API: Query.getAccount
Запрос извлечения объекта аккаунта по username
может быть выполнен председателем или членом совета на любой аккаунт, или пользователем, если он получает свои собственные данные.
Аккаунты извлекаются по именам пользователей с помощью запроса GetAccount
. В случае, если у username
нет какого-либо уровня аккаунта из представленных выше, то они будут null
.
import { Queries } from '@coopenomics/sdk';
const variables: Queries.Accounts.GetAccount.IInput = {
data: {
username: <string>; // Имя аккаунта пользователя
};
};
const { [Queries.Accounts.GetAccount.name]: result } = await client.Query(
Queries.Accounts.GetAccount.query,
{ variables }
);
Извлечь лист аккаунтов¶
🛠️ SDK: Queries.Accounts.GetAccounts | 🔗 GraphQL API: Query.getAccounts
Получить лист аккаунтов списком с пагинацией. В качестве пераметров можно передать роль аккаунта, тип сортировки, направление, страницу и лимит.
import { Queries } from '@coopenomics/sdk';
const variables: Queries.Accounts.GetAccounts.IInput = {
data?: {
role?: <null | string>;
};
options?: {
limit: <number>; // Количество элементов на странице
page: <number>; // Номер страницы
sortBy?: <null | string>; // Ключ сортировки (например, "name")
sortOrder: <string>; // Направление сортировки ("ASC" или "DESC")
};
};
const { [Queries.Accounts.GetAccounts.name]: result } = await client.Query(
Queries.Accounts.GetAccounts.query,
{ variables }
);
Результат будет представлен в виде объекта с массивом items, где каждый элемент массива - это составной объект аккаунта.
interface IOutput {
getAccounts: {
currentPage: <number>; // Текущая страница
items: <{
blockchain_account?: {
account_name: <string>; // Имя аккаунта
core_liquid_balance?: <null | string>; // Баланс
cpu_limit: {
available: <string>; // Доступные ресурсы
current_used?: <null | string>; // Текущее использование ресурсов
last_usage_update_time?: <null | string>; // Время последнего обновления использования ресурсов
max: <string>; // Максимальное количество ресурсов
used: <string>; // Использовано ресурсов
};
cpu_weight: <string>; // Вес CPU
created: <string>; // Дата создания
head_block_num: <number>; // Номер последнего блока
head_block_time: <string>; // Время последнего блока
last_code_update: <string>; // Время последнего обновления кода
net_limit: {
available: <string>; // Доступные ресурсы
current_used?: <null | string>; // Текущее использование ресурсов
last_usage_update_time?: <null | string>; // Время последнего обновления использования ресурсов
max: <string>; // Максимальное количество ресурсов
used: <string>; // Использовано ресурсов
};
net_weight: <string>; // Вес сети
permissions: <{
parent: <string>; // Родительское разрешение
perm_name: <string>; // Имя разрешения
required_auth: {
accounts: <{
permission: {
actor: <...>; // Актор
permission: <...>; // Разрешение
};
weight: <number>; // Вес
}[]>; // Уровни разрешений
keys: <{
key: <string>; // Ключ
weight: <number>; // Вес
}[]>; // Ключи
threshold: <number>; // Порог
waits: <{
wait_sec: <number>; // Время ожидания в секундах
weight: <number>; // Вес
}[]>; // Вес ожидания
};
}[]>; // Разрешения
privileged: <boolean>; // Флаг привилегий
ram_quota: <number>; // Квота RAM
ram_usage: <number>; // Использование RAM
refund_request?: {
cpu_amount: <string>; // Сумма CPU
net_amount: <string>; // Сумма сети
owner: <string>; // Владелец
request_time: <string>; // Время запроса
};
rex_info?: <null | string>; // Информация о REX
self_delegated_bandwidth?: {
cpu_weight: <string>; // Вес CPU
from: <string>; // Отправитель
net_weight: <string>; // Вес сети
to: <string>; // Получатель
};
total_resources?: {
cpu_weight: <string>; // Вес CPU
net_weight: <string>; // Вес сети
owner: <string>; // Владелец
ram_bytes: <number>; // Используемая RAM
};
voter_info?: <null | string>; // Информация о голосовании
};
participant_account?: {
braname?: <null | string>; // Имя кооперативного участка
created_at: <unknown>; // Время создания записи о члене
has_vote: <boolean>; // LEGACY Флаг, имеет ли член право голоса
is_initial: <boolean>; // LEGACY Флаг, внесен ли регистрационный взнос
is_minimum: <boolean>; // LEGACY Флаг, внесен ли минимальный паевый взнос
last_min_pay: <unknown>; // Время последнего минимального платежа
last_update: <unknown>; // Время последнего обновления информации о члене
status: <string>; // Статус члена кооператива (accepted | blocked)
type?: <null | string>; // Тип участника (individual | entrepreneur | organization)
username: <string>; // Уникальное имя члена кооператива
};
provider_account?: {
email: <string>; // Электронная почта пользователя
has_account: <boolean>; // Есть ли у пользователя аккаунт
initial_order?: <null | string>; // ID начального заказа
is_email_verified: <boolean>; // Подтверждена ли электронная почта
is_registered: <boolean>; // Зарегистрирован ли пользователь
message?: <null | string>; // Сообщение
public_key: <string>; // Публичный ключ пользователя
referer: <string>; // Реферер пользователя
role: <string>; // Роль пользователя
status: <UserStatus>; // Статус пользователя
type: <string>; // Тип пользователя
username: <string>; // Имя пользователя
};
user_account?: {
meta: <string>; // Метаинформация
referer: <string>; // Реферал
registered_at: <string>; // Дата регистрации
registrator: <string>; // Регистратор
status: <string>; // Статус аккаунта
storages: <string[]>; // Список хранилищ
type: <string>; // Тип учетной записи
username: <string>; // Имя аккаунта
verifications: <{
created_at: <string>; // Дата создания верификации
is_verified: <boolean>; // Флаг верификации
last_update: <string>; // Дата последнего обновления верификации
notice: <string>; // Заметка верификации
procedure: <string>; // Процедура верификации
verificator: <string>; // Имя верификатора
}[]>; // Дата регистрации
};
username: <string>; // Имя аккаунта кооператива
}[]>; // Элементы текущей страницы
totalCount: <number>; // Общее количество элементов
totalPages: <number>; // Общее количество страниц
};
}
Обновить аккаунт¶
🛠️ SDK: Mutations.Accounts.UpdateAccount | 🔗 GraphQL API: Mutation.updateAccount
Обновление аккаунта пользователя производится по username. Мутация позволяет изменить приватные данные пользователя, а также, адрес электронной почты в MONO
. Использовать мутацию может только председатель совета.
import { Mutations } from '@coopenomics/sdk';
const variables: Mutations.Accounts.UpdateAccount.IInput = {
data: {
email: <string>; // Электронная почта
entrepreneur_data?: <null | {
birthdate: <string>; // Дата рождения
city: <string>; // Город
country: <Russia>; // Страна
details: {
inn: <string>; // ИНН
ogrn: <string>; // ОГРН
};
first_name: <string>; // Имя
full_address: <string>; // Полный адрес
last_name: <string>; // Фамилия
middle_name: <string>; // Отчество
phone: <string>; // Телефон
}>; // Данные индивидуального предпринимателя
individual_data?: <null | {
birthdate: <string>; // Дата рождения
first_name: <string>; // Имя
full_address: <string>; // Полный адрес
last_name: <string>; // Фамилия
middle_name: <string>; // Отчество
passport?: <null | {
code: <string>;
issued_at: <string>;
issued_by: <string>;
number: <number>;
series: <number>;
}>; // Данные паспорта
phone: <string>; // Телефон
}>; // Данные физического лица
organization_data?: <null | {
city: <string>; // Город
country: <string>; // Страна
details: {
inn: <string>;
kpp: <string>;
ogrn: <string>;
};
fact_address: <string>; // Фактический адрес
full_address: <string>; // Полный адрес
full_name: <string>; // Полное наименование организации
phone: <string>; // Телефон
represented_by: {
based_on: <string>;
first_name: <string>;
last_name: <string>;
middle_name: <string>;
position: <string>;
};
short_name: <string>; // Краткое наименование организации
type: <OrganizationType>; // Тип организации
}>; // Данные организации
public_key?: <null | string>; // Публичный ключ
referer?: <null | string>; // Имя аккаунта реферера
role: <User>; // Роль пользователя
type: <AccountType>; // Тип аккаунта
username: <string>; // Имя пользователя
};
};
const { [Mutations.Accounts.UpdateAccount.name]: result } = await client.Mutation(
Mutations.Accounts.UpdateAccount.mutation,
{ variables }
);
Обновление персональных данных в базе MONO
производится добавлением нового объекта с указанием последнего необратимого блока в блокчейне, что позволяет использовать исторические данные для сверки и восстановления документов. Вся история изменений данных аккаунтов сохраняется.
Восстановить доступ к аккаунту¶
В случае утери ключа доступа к аккаунту - ключ возможно заменить. Для этого, необходимо последовательно применить две мутации: StartResetKey
- для получения токена на замену ключа и ResetKey - мутация для непосредственной замены ключа доступа для аккаунта.
Получить токен для замены¶
🛠️ SDK: Mutations.Accounts.StartResetKey | 🔗 GraphQL API: Mutation.startResetKey
Метод запуска процесса замены ключа. Замена ключа в блокчейне производится за подписью кооператива. Для того, чтобы произвести замену, пайщику необходим токен доступа, который будет отправлен ему на почту после вызова этой мутации.
import { Mutations } from '@coopenomics/sdk';
const variables: Mutations.Accounts.StartResetKey.IInput = {
data: {
email: <string>; // Электронная почта
};
};
const { [Mutations.Accounts.StartResetKey.name]: result } = await client.Mutation(
Mutations.Accounts.StartResetKey.mutation,
{ variables }
);
Заменить ключ¶
🛠️ SDK: Mutations.Accounts.ResetKey | 🔗 GraphQL API: Mutation.resetKey
Метод производит замену публичного ключа аккаунта в блокчейне на переданный. На текущий момент здесь не используется каких-либо дополнительных децентрализованных сценариев проверки. Считаем, что если кооператив меняет ключ пайщика - значит так надо, т.к. обычно сейчас один пайщик только с одним аккаунтом и является пайщиком только одного кооператива.
Однако, в дальнейшем, при введении функционала "карты пайщика", которая сделает допустимым "быстрый вход" для пайщиков одного кооператива - в другой, система замены ключа будет требовать подтверждения нескольких кооперативов.
import { Mutations } from '@coopenomics/sdk';
const variables: Mutations.Accounts.ResetKey.IInput = {
data: {
public_key: <string>; // Публичный ключ для замены
token: <string>; // Токен авторизации для замены ключа, полученный по email
};
};
const { [Mutations.Accounts.ResetKey.name]: result } = await client.Mutation(
Mutations.Accounts.ResetKey.mutation,
{ variables }
);