Когда в интерфейсе lending-протокола нажимают Supply, кажется, что произошло что-то простое: токены ушли в протокол, баланс вырос, APY начал капать.
На уровне смарт-контракта это уже другая история.
Протокол должен одновременно:
- принять underlying asset;
- выдать пользователю claim на депозит;
- начать начислять проценты без ручного пересчёта каждого кошелька;
- связать supply с borrow capacity;
- при borrow — создать долговую запись, которая тоже растёт со временем;
- однозначно понять, какая именно позиция принадлежит какому участнику;
- позже корректно обработать withdraw, repay, liquidation и transfer.
Именно здесь появляются два важных инженерных слоя, о которых реже говорят в «пользовательских» обзорах lending:
- token accounting — как протокол представляет депозит и долг в виде токенов или внутренних индексов;
- position identity — как протокол идентифицирует позицию: по адресу кошелька, по
tokenIdNFT или по отдельному loan id.
Если объяснять просто, lending — это не только «залог против займа», но и система бухгалтерии onchain, где каждый депозит и каждый долг должны иметь однозначный идентификатор и понятную механику роста во времени.
Ниже — разбор без лишнего жаргона: что происходит при добавлении токенов, как устроены receipt tokens и debt tokens, зачем позиции оформляют как NFT, где возникают риски и какой automation layer имеет смысл строить вокруг учёта позиций.
Что происходит при добавлении токенов в lending pool
Когда пользователь делает supply, снаружи видно одну транзакцию. Внутри протокола обычно проходит цепочка из четырёх шагов.
Шаг 1. Transfer underlying в pool
Пользователь отправляет, например, USDC или WETH в lending market contract.
После этого актив физически лежит в контракте протокола и становится частью общей ликвидности market.
Шаг 2. Запись claim пользователя
Протокол должен зафиксировать:
- сколько underlying пользователь внёс;
- в какой market;
- с какого момента на этот claim начинают начисляться проценты;
- можно ли этот claim использовать как collateral для borrow.
Здесь протокол выбирает модель учёта.
Шаг 3. Mint receipt token или обновление internal balance
В большинстве современных протоколов пользователь получает не «просто запись в mapping», а отдельный токен-расписку:
aUSDC,aWETHв Aave;cUSDC,cETHв Compound;- share token в ERC-4626 vault-подобных market.
Эта расписка означает:
«протокол должен мне underlying плюс накопленный процент».
Шаг 4. Collateral flag и borrow capacity
Если актив разрешён как collateral, supply автоматически увеличивает borrow capacity пользователя.
Теперь система может считать:
- стоимость collateral;
- текущий debt;
- health factor;
- доступный лимит для нового borrow.
То есть supply — это не passive deposit, а вход в risk account, даже если пользователь ещё ничего не занимал.
Receipt tokens: как протокол представляет депозит
Receipt token — это onchain-представление депозита в lending market.
Если убрать бренды, идея простая:
- вы отдали протоколу 1 000 USDC;
- протокол выдал вам token, который подтверждает ваш claim;
- со временем claim растёт за счёт процентов;
- когда захотите выйти, сожжёте receipt token и получите underlying обратно.
Две основные модели начисления процентов
1. Rebasing balance
Баланс receipt token у пользователя сам увеличивается со временем.
Например:
- положили 1 000 aUSDC;
- через месяц в кошельке уже 1 004 aUSDC без дополнительных транзакций.
Плюсы:
- интуитивно для пользователя;
- легко читать баланс в wallet UI.
Минусы:
- rebasing токены хуже встраиваются в composability;
- некоторые контракты не ожидают, что balance меняется сам по себе;
- для automation нужно отдельно отслеживать rebase events.
2. Exchange rate / liquidity index
Баланс receipt token может не меняться, но exchange rate растёт.
Например:
- положили 1 000 USDC;
- получили 1 000 cUSDC;
- через месяц 1 cUSDC redeem’ится уже не в 1 USDC, а в 1.004 USDC.
Плюсы:
- проще для DeFi composability;
- transfer и accounting стабильнее;
- многие vault-like системы так и работают.
Минусы:
- пользователю сложнее «на глаз» видеть доходность;
- automation layer должен считать underlying value, а не только token balance.
Что важно для инженера
Receipt token — это не просто UI-абстракция. Это:
- transferable claim;
- потенциальный collateral;
- источник событий для indexers;
- объект учёта для treasury и vault automation.
Если automation-система смотрит только на raw underlying balance пользователя в wallet, она не видит реальную lending position.
Что происходит при borrow
Borrow — зеркальная, но более опасная операция.
Шаг 1. Проверка collateral и лимитов
Протокол пересчитывает:
- стоимость залога;
- текущий debt;
- borrow capacity;
- health factor после новой операции;
- наличие свободной ликвидности в market.
Шаг 2. Transfer borrowed asset пользователю
Если проверки прошли, протокол отправляет, например, USDC на адрес заёмщика.
Шаг 3. Создание debt record
Здесь протокол должен зафиксировать долг так, чтобы он:
- рос со временем;
- учитывался в health factor;
- мог быть погашен частично или полностью;
- мог быть ликвидирован;
- был однозначно привязан к позиции.
Debt tokens
Во многих протоколах долг тоже представлен отдельным токеном:
- variable debt token;
- stable debt token;
- internal debt share.
Логика похожа на receipt tokens, только в обратную сторону:
- receipt token = «мне должны»;
- debt token = «я должен».
Проценты увеличивают debt balance или exchange rate debt token.
Почему debt token удобнее plain mapping
Если долг — отдельный onchain asset, протокол получает:
- прозрачный учёт;
- возможность composability;
- события для indexers;
- иногда — transferability debt position, если это задумано дизайном.
Но transferability debt — отдельный risk design choice. Не каждый протокол это разрешает.
Как протокол идентифицирует lending position
Вот ключевой вопрос: что такое «позиция» в lending?
На практике есть три распространённые модели.
1. Account-based position
Самая частая модель в classic lending markets.
Позиция привязана к адресу:
user address → supplies in market A, B, C
user address → debts in market X, Y
user address → health factor across portfolio
Примеры подхода: Aave-style pooled markets, Compound-style markets.
Как это работает
- один wallet = одна агрегированная позиция;
- все supply и borrow внутри протокола сводятся к account state;
- health factor считается по всему account;
- liquidation бьёт по account, а не по одному изолированному loan object.
Плюсы
- простая UX-модель;
- легко понять «мой account в протоколе»;
- хорошо работает для fungible collateral;
- проще automation для типового retail user.
Минусы
- сложнее изолировать риск между несколькими стратегиями на одном адресе;
- transfer «части позиции» неестественен;
- treasury ops на одном адресе быстро смешивают разные mandates.
2. NFT as position ID
Здесь каждая позиция получает уникальный onchain-идентификатор в виде NFT.
Обычно это ERC-721 token:
tokenId #4821 → конкретная borrow position
tokenId #4821 → collateral set, debt amount, market params
NFT не обязательно «картинка». Это просто non-fungible identifier, который можно:
- хранить в wallet;
- transferить;
- использовать как ключ в контракте;
- индексировать отдельно от user address.
Зачем это делают
Изолированные позиции
Один пользователь может иметь несколько независимых loans:
- tokenId 101 — ETH collateral / USDC debt;
- tokenId 102 — wBTC collateral / USDC debt;
- tokenId 103 — experimental market position.
Liquidation одной не обязана автоматически смешиваться с другой, если протокол так спроектирован.
Transferability позиции
Иногда протокол сознательно делает loan position transferable:
- новый владелец NFT принимает на себя debt и права на collateral;
- можно передать позицию без полного close + reopen;
- появляется secondary market на сами loan positions.
Это мощно, но повышает complexity и risk.
Удобство для automation и portfolio systems
Для vault, fund или strategy manager NFT position ID удобен тем, что:
- каждая стратегия живёт в отдельном tokenId;
- легче строить monitoring per position;
- проще audit trail;
- можно привязать policy к конкретному NFT, а не ко всему wallet.
Где это встречается
Прямо «NFT как ID borrow position» — не самый массовый паттерн в classic Aave/Compound, но он хорошо виден в:
- isolated lending designs;
- некоторых permissioned / structured credit markets;
- протоколах, где позиция должна быть отдельным объектом учёта;
- NFT-backed lending, где loan часто имеет собственный id и иногда оформляется через NFT-like ownership model.
Важно не путать два разных смысла NFT в lending:
- NFT как collateral — залогом является NFT-коллекция;
- NFT как ID позиции — сама loan position идентифицируется tokenId.
Это разные вещи, хотя могут существовать одновременно.
3. Loan ID без NFT
Промежуточная модель: позиция имеет numeric loan id, но не является transferable NFT.
loanId 91822 → borrower, collateral, debt, status
Это часто встречается в:
- NFT collateral lending;
- P2P loan protocols;
- private credit pools;
- order-book-like credit markets.
Плюсы
- проще, чем ERC-721 infrastructure;
- легче хранить status machine: active / repaid / liquidated / defaulted;
- удобно для backend automation.
Минусы
- loan id обычно не transferable;
- UX беднее для onchain portfolio composition;
- secondary market сложнее.
NFT как collateral vs NFT как position ID
Это самая частая путаница.
NFT as collateral
Пользователь залогом приносит, например:
- Bored Ape;
- Art Blocks;
- gaming asset;
- RWAs wrapped as NFT.
Протокол оценивает NFT floor/oracle price и выдаёт loan.
Здесь NFT — asset in the vault, а не identifier всей lending position.
Типичный flow:
- пользователь deposit NFT;
- протокол создаёт loan record;
- loan имеет
loanId; - при repay NFT возвращается;
- при default NFT уходит на auction / liquidator.
NFT as position ID
Здесь NFT представляет саму loan position.
Transfer NFT может означать:
- смену debtor;
- смену owner rights на collateral/debt bundle;
- transfer structured credit claim.
Это гораздо более чувствительный design choice.
Как выглядит полный lifecycle с token accounting
Возьмём типовой сценарий: supply WETH, borrow USDC, потом частично repay.
Supply WETH
- пользователь approve + supply WETH;
- протокол забирает WETH;
- mint
aWETHили аналог; - collateral capacity увеличивается;
- indexer фиксирует receipt token mint.
Borrow USDC
- протокол проверяет health factor;
- transfer USDC пользователю;
- mint variable debt token или увеличивает debt record;
- health factor уменьшается;
- monitoring должен пересчитать liquidation distance.
Interest accrual
Со временем без новых tx:
- receipt token value растёт;
- debt value растёт;
- health factor меняется;
- utilization pool меняется.
Automation layer обязан это пересчитывать offchain постоянно, потому что onchain state меняется даже когда пользователь «ничего не делает».
Repay
- пользователь возвращает USDC;
- debt token burn или debt balance уменьшается;
- health factor улучшается;
- часть collateral можно withdraw, если лимиты позволяют.
Withdraw collateral
- протокол проверяет, не станет ли позиция unsafe;
- burn receipt token;
- transfer underlying пользователю.
Если на любом шаге health factor ломается — withdraw или borrow блокируется.
Что меняется, если позиция — NFT
Если borrow position оформлена как tokenId, lifecycle похож, но identity layer другой.
Mint position NFT
При open loan:
- создаётся новый
tokenId; - в storage записываются collateral, debt, market params;
- NFT mint’ится на wallet пользователя;
- все последующие actions идут через
tokenId.
Operations by tokenId
Вместо «изменить account state» протокол делает:
repay(tokenId, amount);addCollateral(tokenId, asset);removeCollateral(tokenId, asset);liquidate(tokenId).
Automation становится проще per strategy, но сложнее на уровне wallet aggregation.
Transfer NFT
Если позиция transferable:
- старый владелец теряет control;
- новый владелец принимает debt + collateral bundle;
- протокол должен проверить, разрешён ли такой transfer;
- monitoring должен пере-привязать alerts к новому owner.
Это критичный риск: transfer position = transfer liability.
Из чего состоит accounting layer протокола
Если смотреть архитектурно, lending accounting почти всегда включает пять блоков.
1. Market ledger
Общий учёт ликвидности market:
- total supply;
- total borrow;
- available liquidity;
- utilization;
- interest rate index.
2. User / position ledger
Учёт конкретных claims:
- receipt token balances;
- debt token balances;
- или storage by
tokenId.
3. Price oracle layer
Оценка collateral и debt для risk math.
4. Risk engine
Считает:
- LTV / health factor;
- borrow limits;
- liquidation thresholds;
- isolation constraints.
5. Event layer
Emit events для indexers:
- Supply;
- Withdraw;
- Borrow;
- Repay;
- Liquidation;
- Transfer;
- Mint/Burn receipt or debt tokens;
- Mint/Transfer position NFT.
Без хорошего event layer automation снаружи почти слепая.
Где возникают главные риски
1. Неправильный учёт receipt vs underlying
Automation может ошибиться, если считает:
- receipt token 1:1 к underlying всегда;
- debt token balance без interest index;
- wallet balance вместо protocol claim.
2. Смешение account-based и position-based logic
Если один wallet держит несколько NFT positions, нельзя мониторить только aggregate wallet health.
Нужен per-position view.
3. Transferability surprises
Transfer debt NFT или position NFT может:
- неожиданно сменить debtor;
- обойти internal compliance assumptions;
- сломать treasury mandate;
- передать underwater position новому владельцу.
4. Rebasing / index mismatch
Indexer, treasury dashboard и liquidation bot должны использовать одну и ту же формулу перевода receipt/debt token в underlying value.
5. Collateral enabled flag
Supply receipt token не всегда означает, что asset уже работает как collateral.
Нужно отдельно отслеживать:
- supplied balance;
- collateral enabled/disabled;
- isolated market constraints.
6. NFT appraisal risk
Для NFT collateral lending ошибка oracle или floor price может:
- создать fake borrow capacity;
- delay liquidation;
- оставить протокол с неликвидным залогом.
Position NFT id не решает эту проблему сам по себе.
Какой automation layer нужен вокруг учёта
Если строить ops/control plane для lending, одного health factor alert недостаточно.
1. Position normalizer
Сервис, который приводит разные модели к единому виду:
position_id
owner
supplies[]
debts[]
health_factor
collateral_enabled
market_type: pooled | isolated | nft-collateral
Источник position_id:
- user address;
- NFT tokenId;
- loanId.
2. Receipt/debt valuation engine
Отдельный модуль, который считает:
- underlying value of receipt tokens;
- underlying value of debt;
- net account equity;
- accrued interest since last sync.
3. Per-position monitoring
Особенно важно для:
- treasury with multiple strategies;
- NFT-backed loans;
- transferable position NFTs;
- isolated markets.
Alerts:
- HF below threshold;
- debt growth anomaly;
- receipt token depeg from expected index;
- collateral disabled by governance;
- ownership change on position NFT.
4. Lifecycle tracker
Нужен state machine:
- supplied;
- borrowed;
- repaid partially;
- withdrawn;
- liquidated;
- transferred;
- closed.
Для NFT/loanId positions это должно быть привязано к конкретному id, а не только к wallet.
5. Integration adapters
Если вы работаете с несколькими протоколами, adapter layer должен понимать:
- Aave-style aToken / debtToken;
- Compound-style exchange rate;
- ERC-4626 share vault;
- NFT collateral loan contract;
- custom position NFT registry.
MVP: lending accounting monitor
Практичный MVP не требует собственного lending protocol.
Формулировка
Indexer + dashboard, который для выбранного протокола показывает normalized positions: receipt token value, debt value, health factor и ownership changes по NFT/loan id.
Минимальные компоненты
1. Indexer
Слушает:
- Supply / Withdraw;
- Borrow / Repay;
- Liquidate;
- Transfer receipt/debt token;
- Mint / Transfer position NFT.
2. Valuation worker
Пересчитывает:
- underlying from receipt token;
- debt including index;
- USD value via oracle feed.
3. Position registry
Хранит:
position_id;owner;protocol;status;last_health_factor.
4. Alert router
Шлёт:
- HF warnings;
- ownership transfer on position NFT;
- debt growth above baseline;
- collateral factor change from governance.
Стек:
- Go для workers и API;
- PostgreSQL для positions и events;
- Redis для recalc queues;
- onchain reads via RPC / indexer.
Что стоит запомнить
Lending в DeFi — это не только механика «положил залог → взял долг». На уровне контрактов это система учёта, где:
- supply создаёт receipt token или share claim;
- borrow создаёт debt record, часто тоже в виде token;
- позиция может жить как account state, loanId или NFT tokenId;
- interest accrual меняет стоимость claim и debt без новых пользовательских tx;
- automation должен понимать все три слоя: tokens, position identity и risk.
Если упростить:
- receipt token = «сколько мне должны»;
- debt token = «сколько я должен»;
- position id = «какой именно loan object мы мониторим и кто им владеет»;
- NFT as position id = способ сделать позицию отдельным onchain-объектом, иногда даже transferable.
Для продуктовой команды, treasury или infrastructure builder это означает простую вещь: monitoring только wallet balances недостаточно. Нужен accounting-aware automation layer, который понимает, как протокол представляет депозит, долг и identity позиции.
Если нужен такой слой — position normalizer, valuation engine, NFT/loanId tracker или lending ops dashboard — можно обсудить архитектуру под ваш протокол или стек интеграций: свяжитесь со мной.