Создаем свою АБС на блокчейне
Всем привет. Сидел я тут как-то и думал, а почему бы не сделать свою автоматизированную банковскую систему на блокчейне и соблюсти почти все правила учета и отчетности от ЦБ РФ. Мне показалось это интересно и возможным сделать. Разумеется ЦБ не примет эту систему, но как для практики программирования идея думаю не плохая.
Буду создавать все в лайв режиме, поэтому не знаю получиться сделать все что задумал.
Теория
Начну с теории и что нам нужно будет сделать.
АБС (автоматизированная банковская система) это совокупность аппаратных средств и программ для создания информационной среды, которая выполняет управленческие и финансовые задачи в условии реального времени у банка.
Добавлю также, что не надо путать слова автоматизированные и автоматические. Автоматизированные, где человек принимает окончательное решение, а в автоматических машина.
То, что я делаю не может быть принято ЦБ, потому что есть нарушения с моей стороны ряда статей ФЗ "О ЦБ РФ". Поэтому рассматриваем этот проект как просто тренировка и закрепление знаний.
Также нужно понимать, что я не создаю банк. Я создаю вендор, который можно интегрировать (в теории) в свой банк на блокчейне, если вы его создадите.
Фрон-офис - это взаимодействие с клиентом
Бэк-офис - это функционал системы
Мидл-офис - это функционал проводки или бух учет.
На данной картинке выделены основные модули, которые нам нужно будет по идее реализовать. Но как я уже говорил, я делаю все в лайв режиме и не знаю на данный момент что получиться сделать, а что нет.
Бухгалтерский учет будет является транзакциями в блокчейне, поэтому как такового бух учета у нас не будет. Но называть я буду его все равно так.
Еще один из недостатков: у нас не будет наличного расчета :(.
Расписывать функционал каждого модуля не буду, потому что долго и не нужно. Когда будем подходить к реализации модуля, тогда и буду его объяснять.
Модуль является функциональным ядром интегрированной банковской системы
1. Тип клиента
2. Ведение счетов
3. Платежный документооборот
4. Безналичные расчеты
5. Картотеки (дебетовые и кредитные карты)
6. Валютный учет(основой сделаем доллар)
7. Хранение всей информации о платежах
8. Учет и отчетность
В данной статье я реализую все кроме:
Валютный учет
Безналичные расчеты
Учет и отчетность
Код
И так для начала кину весь код, который есть на данный момент:
// SPDX-License-Identifier: UNLICENSED pragma solidity ^0.8.9; contract Core { address owner; constructor(){ owner = msg.sender; } struct client{ string name; address clientOwner; uint clientType; bool accountDebet; bool accountCredit; bytes32[] paymentInfo; document[] documents; } struct document{ uint typeDocument; string documentInfo; address document; } mapping(address=>mapping(uint=>bool)) initSubscribe; mapping(address=>client) clients; modifier onlyOwner() { require(owner == msg.sender, "faild"); _; } function initializeClient(string calldata _name) public payable{ client storage newClientInfo = clients[msg.sender]; newClientInfo.name = _name; newClientInfo.clientOwner = msg.sender; newClientInfo.accountDebet = false; newClientInfo.accountCredit = false; uint size; address addr = msg.sender; assembly { size := extcodesize(addr) } if (size > 0) { bytes4 expectedFunctionSignature = bytes4(keccak256("myFunction(uint256,address)")); (bool success, ) = addr.call(abi.encodeWithSelector(expectedFunctionSignature, 1, addr)); require(success, "faild"); if(success == true){ newClientInfo.clientType = 1; newClientInfo.documents.push(document(0, "entity person", msg.sender)); } }else{ newClientInfo.clientType = 0; newClientInfo.documents.push(document(0, "natural person", msg.sender)); } newClientInfo.paymentInfo.push(bytes32(keccak256(bytes("Create client")))); } function addAccountDebet() public{ require(msg.sender == clients[msg.sender].clientOwner); initSubscribe[msg.sender][0] = true; } function addAccountCredit() public{ require(msg.sender == clients[msg.sender].clientOwner); initSubscribe[msg.sender][1] = true; } function complitesubscribersAccount(address _client, uint typeAccount) public onlyOwner{ require(initSubscribe[_client][typeAccount] == true, "not complite"); require(typeAccount == 0 || typeAccount == 1, "error"); if(typeAccount == 0){ clients[_client].accountDebet = true; initSubscribe[_client][typeAccount] = false; } if(typeAccount == 1){ clients[_client].accountCredit = true; initSubscribe[_client][typeAccount] = false; } } function deletAccountDebet() public{ require(msg.sender == clients[msg.sender].clientOwner); require(clients[msg.sender].accountDebet == true, "not open"); initSubscribe[msg.sender][0] = true; } function deletAccountCredit() public{ require(msg.sender == clients[msg.sender].clientOwner); require(clients[msg.sender].accountCredit == true, "not open"); initSubscribe[msg.sender][1] = true; } function comliteDeletAccount(address _client, uint typeAccount) public onlyOwner{ require(initSubscribe[_client][typeAccount] == true, "not complite"); require(typeAccount == 0 || typeAccount == 1, "error"); if(typeAccount == 0){ clients[_client].accountDebet = false; initSubscribe[_client][typeAccount] = false; } if(typeAccount == 1){ clients[_client].accountCredit = false; initSubscribe[_client][typeAccount] = false; } } }
Сразу говорю, что не буду размусоливать его. Буду показывать основные моменты и общую концепцию. Это не конечная версия кода, будет еще все меняться и добавляться.
Для начала я создаю структуру client которая будет содержать все данные клиента. И структуру document, которая должна содержать информацию о ценных бумагах или важных расписках например.
Дальше создаю маппинг, который будет нужен для подтверждения открытия счета initSubscribe. И маппинг для общего сбора всех клиентов clients.
Функция initializeClient будет нужна для регистрации клиента в банке. Будут ставиться дефолтные значения, которые в будущем можно менять открывая новые привилегии. Из интересного, я решил разделять юрлицо и физлицо на два типа: если клиент, это обычный адрес кошелька, он будет физлицом, если же смарт-контракт то юрлицо. Проверку делаю через ассемблер функцией проверки на наличие кода extcodesize. Но так как это не гарантирует, что вызов идет от смарт-контракта, я добавил условие, что каждый контракт должен иметь функцию check, которая вызывается при проверке низкоуровневым вызовом, чтоб убедиться в том, что данный вызов идет из стороннего смарт-контракта.
Функции addAccountDebet, addAccountCredit, deletAccountDebet, deletAccountCredit нужны для запроса открытия/закрытия счета в банке.
complitesubscribersAccount и comliteDeletAccount нужны для владельца который будет решать можно ли открыть данному лицу счет или нет
Я создал смарт-контракт, который хочет открыть счет в банке, чтоб удостовериться в работе моей концепции.
contract OtherContract { address public coreAddress; Core public coreInstance; constructor(address _coreAddress) { coreAddress = _coreAddress; coreInstance = Core(coreAddress); } function check(uint num, address addr) public pure{ } function callInitializeClient(string calldata _name) external { coreInstance.initializeClient(_name); } }
Тут все просто. Передаю адрес Core и после создаю экземпляр смарт-контракта.
Дальше обязательно добавляем функцию check и функцию callInitializeClient, которая вызывает initializeClient
Чтоб все проверить, я создал hardhat проект, где будут все тесты.
На гитхабе будет все, кто хочет посмотреть, то ссылка в конце статьи.
Если вы хотите проверить, или что то добавить пишите мне в тг. Его можно найти в профиле моего канала.
На этом я закончу эту статью. Пока что нет ни чего особенного и интересного, но в голове строится необычная картина. На данный момент я рассказал все, что хотел. Дальше больше. Вроде как таких похожих проектов не видел ни где, поэтому надеюсь зайдет кому-то.
Мой тг для связи в шапке канала
Мой тг канал
Этот проект на гитхабе