LP shares can be minted against an old mark for a loaned asset the vault no longer holds

Abierto
#65 0 comentarios 0 reacciones 0 asignados Ver en GitHub

Nadie ha tomado este issue todavía.

Evaluación

Dificultad
4/5
Tiempo estimado
3-5 días
Aptitud para principiantes
15/100
Tipo de issue
Error
Claridad
Bastante claro
Estado de actividad
Activo
Área
backend

Línea de trabajo

Start in src/backend/main.mo by comparing vaultLentOutUsd, which values outstanding base-token loans, with vaultHeldLegMarkIssue and stagedLpMarkets, which only check assets whose vault balance is positive. Also read vaultAssetBalance, the wait-list test. Done means an LP deposit or staged release holds for a fresh mark on any loan token that contributes to vault value, even when the physical balance is zero. Reproducing the zero-ETH loan state needs the signed replay in the issue, so this is not a quick first change.

Escrito por el modelo de indexación a partir del texto del issue.

Descripción

An LP deposit can settle during a pending price jump for an asset that is still owed to the vault but absent from its wallet. The loan's price contributes to vault net asset value, yet the deposit's mark gate and wait list check only assets the vault physically holds. The new LP can receive too many shares before the loan's mark updates.

At commit a225a74, vaultLentOutUsd marks every outstanding base-token loan into vault value. vaultHeldLegMarkIssue checks pending and stale marks only when the vault balance for that asset is positive (main.mo:19992-20038). stagedLpMarkets uses the same held-balance test when it decides which fresh quotes a deposit must wait for (main.mo:21739-21781).

The vault values a loan with the token's mark:

if (owed > 0) { sum += Fixed.mul(owed, poolRefPrice(marketId), false) };

The staged request's wait list uses physical holdings instead:

if (vaultAssetBalance(vv, asset) > 0) { List.add(out, market) };
Reproduce on an isolated development canister

Use signed accounts for LPs, a margin trader, a maker, and a swapper. Controller hooks seed simulated balances, set test oracle marks, and pause timers. Trading, LP, and loan repayment calls are signed. The important starting state is zero ETH in the vault with an outstanding ETH loan; the following signed sequence reaches it without editing the vault balance.

  1. An LP deposits 10 BTC, 50 ETH, and 1,200,000 ICPUSD. Set BTC at $50,000 and ETH at $3,000. A maker rests a bid for 11.56249999 ETH at $2,995. A margin pool funded with 100,000 ICPUSD stages a short of that amount. Another user stages a 125,000 ICPUSD-to-ETH swap.
  2. Refresh ETH at $3,000 and requote. The short borrows and sells 11.56249999 ETH to the maker. The swap takes the remaining 38.43750001 ETH from the AMM asks posted before that borrow. The vault now holds 0 ETH and still owns the 11.56249999 ETH loan.
  3. From that state, stage an LP deposit of 2,000 SOL at $100 while a move from $3,000 to $6,000 ETH is pending confirmation. Refresh the markets in the request's wait list, BTC and SOL. The deposit settles before ETH confirms. Then confirm ETH at $6,000, repay the ETH loan, and redeem the new LP's shares.
  4. For the control, restore the same zero-ETH state. Confirm ETH at $6,000 before the 2,000 SOL deposit, then repay the loan and redeem the shares in the same way.
Result Deposit before ETH confirmation Deposit after ETH confirmation
LP shares minted 199,844.83416425 196,169.50670037
Claim after ETH confirmation, before loan close $203,381.77849274 $200,000.00187202
Final wallet after loan repayment and LP exit $402,573.30459796 $399,204.97071741

The depositor began each branch with assets worth $400,000 at the final marks. The early-deposit branch produced $2,573.30459796 net gain after the 40 bp LP exit fee, fees, and interest. The control lost $795.02928259. The initial share-pricing error gave the depositor about $3,381.78 in extra claim after ETH confirmation. The $3,368.33388055 final wallet difference also includes small timing and trade-path differences. At 5% and 10% ETH moves, the share over-allocation was smaller than the immediate exit fee; the demonstrated profitable full exit used the 100% move.

Please include every outstanding loan token whose mark contributes to vault value in the LP deposit, withdrawal, and staged-release mark checks. A pending or stale loan mark should hold settlement until a fresh mark arrives, even if the vault's physical balance of that token is zero. Rechecking the AMM inventory floor after borrowing would block this zero-balance route, but the LP mark gate also needs the loan dependency.

This replay used a local #dev build with simulated balances. It did not send a transaction to a public deployment. The public canisters checked on 2026-11-03 reported #play mode and a module hash different from the local build. The replay establishes the checked source path, not live real-asset exposure.

Lenguaje dominante
Shell
Estrellas
19
Forks
7
Métricas de merge de PR
Sin PR fusionados en 30 d

Preparar el entorno

Este proyecto no incluye contenedor de desarrollo, Dockerfile ni guía de contribución, así que la configuración corre por tu cuenta: empieza por su README y consulta nuestra guía para la primera contribución para los pasos generales.

Primeros pasos

  1. Lee el issue completo y luego la guía de contribución del proyecto.
  2. Comenta en el issue que vas a ocuparte — evita que dos personas hagan lo mismo.
  3. Haz un fork del repositorio y trabaja en una rama.
  4. Abre un pull request que haga referencia al número del issue.

Más de dfinity/public-multidex

Todos los issues de dfinity/public-multidex

Issues similares

Más issues de Shell/Bash

Recibe los nuevos issues en tu correo

Un resumen breve de issues de GitHub para principiantes.