Каждая банкнота имеет свой блокчейн, блоками в которой являются транзакции (операции передачи банкнот между кошельками), таким образом сохраняется полная история движения банкноты. Эту историю может видеть и анализировать, например, банк, выпускающий банкноты.
[!NOTE] Это почти полностью переработанная, обновленная и дополненная версия старого приложения, которое можно найти здесь (в том числе произведена миграция с Fragments на Compose с новым дизайном, описанном в Figma)
Документация проекта Open Digital Cash
Home | Settings | History | Wallet details | |
---|---|---|---|---|
Light | ||||
Dark |
Демонстрация работы приложения (запись экрана), в том числе 2-х splash-screen (системного android и внутреннего в приложении), анимаций.
[!NOTE] Во время передачи банкнот устройство взаимодействует по Bluetooth Classic с находящимся рядом другим смартфоном с такой же версией приложения OpenDigitalCash. Прием и отправка выглядят одинаково на обоих устройствах.
Показать принципиальную возможность реализации цифрового аналога фиатной валюты (см. Электронные Деньги):
Multi-module, Clean Architecture, SOLID, DI, MVI, MVVM, Unit-Testing (Junit5), Material Design, Material 3.
Примечание: скорее всего, возможно ещё улучшить независимость модулей, если найти способ преобразовать модели в :core:wallet в локальные и вынести аналогичные общие в модуль :core:model. Таким образом будет убраны лишние связи других модулей с :core:wallet, которые возникают только из-за общих моделей.
:app: | :build-logic: | :core: | :feature: |
---|---|---|---|
convention | common-android | atm | |
common-jvm | history | ||
connectivity | home | ||
database | p2p | ||
datastore | settings | ||
design-system | wallet-details | ||
domain | |||
model | |||
network | |||
testing | |||
transaction-logic | |||
ui | |||
wallet | |||
wallet-repository |
[!NOTE] В этой версии модуль, реализующий кошелек, является открытым, а банкноты хранятся в базе данных. В Минимально Жизнеспособном Продукте кошелек должен находиться в отдельном защищенном разделе смартфона (например, на специальной симкарте OpenDigitalCash; потеря симкарты равна потере кошелька).
Использованы Kotlin Coroutines и Flows (с соблюдением структурированного паралеллизма) для асинхронного выполнения и возможности отмены всех ресурсоемких операций приложения.
Для UI использован Jetpack Compose со стандартной библиотекой навигации и 2 NavHost (вложенная навигация), паттерн MVI. Всего 7 основных экранов, из которых 3 верхнего уровня.
UI работает в режиме edgeToEdge() , адаптируясь и к системной навигации 3-мя клавишами и жестами, и к открытию IME (экранной клавиатуры). Состояние приложения полностью сохраняется и адаптируется при смене конфигурации смартфона.
Используются кастомные анимации.
Схема нового алгоритма передачи (схему старого можно найти в документации ODC к прошлой версии приложения):
В этой версии передача между кошельками происходит по защищенному каналу Bluetooth, используя два собственных протокола передачи данных:
Для разбиения больших пакетов (в виде массивов байт) на фрагменты малого размера и сборки целого пакета из его фрагментов, поскольку соединение (например, Bluetooth) имеет ограничение по размеру одного пакета. Для передачи большого пакета по частям сначала передается размер будущего пакета в байтах в виде лидирующего пакета 4 байта, после все части пакета по очереди.
Получатель ожидает лидирующий массив байт с размером, далее последовательно собирает большой пакет из фрагментов, после чего большой пакет (массив байт) обрабатывается по протоколу 2.
Для двойной сериализации и десериализации многоуровневых DTO в массивы байт и обратно:
Получателю известно, что пришедший массив байт всегда является сериализованным DataPacket, поэтому после получения по протоколу 1 всего пакета, он
Оба этих подхода в совокупности позволяют легко расширять DTO и добавлять их новые типы независимо от алгоритма передачи данных, при этом протокол 1 и протокол 2 никак не зависят друг от друга.
Для обоих протоколов написаны Unit-тесты (Junit5).
Обычный Bluetooth не позволяет отфильтровать пользователей по UUID сервиса, поэтому реализована фильтрация по имени устройства.
Начинается поиск устройств Bluetooth, но фильтруются и остаются только те, у которых в начале имени есть определенный префикс.
Таким образом, личные настройки смартфона пользователя сохраняются нетронутыми.
Пользователь запрашивает сумму из своего кошелька; эта же ситуация может возникнуть и с обычным банкоматом.
Задача: можно ли из имеющихся банкнот (неделимых, как и бумажных) собрать точную сумму, и если да, то из каких именно?
Является задачей о сумме подмножеств, NP-Complete или NP-hard (в зависимости от задачи). Решена здесь при помощи динамического программирования с использованием Kotlin Coroutines, написаны Unit-тесты на Junit5.
КИБ, OpenDigitalCash