Создаем свою АБС на блокчейне
Всем привет. Сидел я тут как-то и думал, а почему бы не сделать свою автоматизированную банковскую систему на блокчейне и соблюсти почти все правила учета и отчетности от ЦБ РФ. Мне показалось это интересно и возможным сделать. Разумеется ЦБ не примет эту систему, но как для практики программирования идея думаю не плохая.
Буду создавать все в лайв режиме, поэтому не знаю получиться сделать все что задумал.
Теория
Начну с теории и что нам нужно будет сделать.
АБС (автоматизированная банковская система) это совокупность аппаратных средств и программ для создания информационной среды, которая выполняет управленческие и финансовые задачи в условии реального времени у банка.
Добавлю также, что не надо путать слова автоматизированные и автоматические. Автоматизированные, где человек принимает окончательное решение, а в автоматических машина.
То, что я делаю не может быть принято ЦБ, потому что есть нарушения с моей стороны ряда статей ФЗ "О ЦБ РФ". Поэтому рассматриваем этот проект как просто тренировка и закрепление знаний.
Также нужно понимать, что я не создаю банк. Я создаю вендор, который можно интегрировать (в теории) в свой банк на блокчейне, если вы его создадите.
Фрон-офис - это взаимодействие с клиентом
Бэк-офис - это функционал системы
Мидл-офис - это функционал проводки или бух учет.
На данной картинке выделены основные модули, которые нам нужно будет по идее реализовать. Но как я уже говорил, я делаю все в лайв режиме и не знаю на данный момент что получиться сделать, а что нет.
Бухгалтерский учет будет является транзакциями в блокчейне, поэтому как такового бух учета у нас не будет. Но называть я буду его все равно так.
Еще один из недостатков: у нас не будет наличного расчета :(.
Расписывать функционал каждого модуля не буду, потому что долго и не нужно. Когда будем подходить к реализации модуля, тогда и буду его объяснять.
Модуль является функциональным ядром интегрированной банковской системы
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 проект, где будут все тесты.
На гитхабе будет все, кто хочет посмотреть, то ссылка в конце статьи.
Если вы хотите проверить, или что то добавить пишите мне в тг. Его можно найти в профиле моего канала.
На этом я закончу эту статью. Пока что нет ни чего особенного и интересного, но в голове строится необычная картина. На данный момент я рассказал все, что хотел. Дальше больше. Вроде как таких похожих проектов не видел ни где, поэтому надеюсь зайдет кому-то.
Мой тг для связи в шапке канала
Мой тг канал
Этот проект на гитхабе