Skip to content

fix(deepbook-v3): repay_base/repay_quote no longer drain balance on amount=0#1032

Open
Danny-Devs wants to merge 1 commit intoMystenLabs:mainfrom
Danny-Devs:fix/deepbook-v3-repay-amount-zero
Open

fix(deepbook-v3): repay_base/repay_quote no longer drain balance on amount=0#1032
Danny-Devs wants to merge 1 commit intoMystenLabs:mainfrom
Danny-Devs:fix/deepbook-v3-repay-amount-zero

Conversation

@Danny-Devs
Copy link
Copy Markdown
Contributor

Description

MarginManagerContract.repayBase and repayQuote used a truthy guard (amount ? … : null) that collapsed amount = 0 onto the Option::None branch of the Option<u64> argument.

On the Move side, margin_manager::repay uses amount.destroy_with_default(available_balance) and clamps to the outstanding debt. None means "repay as much as possible using the asset balance held in the balance manager." So repayBase(mgr, 0) and repayQuote(mgr, 0) silently triggered a full-debt repayment instead of a no-op, which is the behavior the numeric argument suggests.

The guard now checks amount !== undefined, matching the pattern in marginLiquidations.ts and marginPool.ts:

  • amount = 0Option::Some(0) → no-op repay
  • amount = nOption::Some(n_scaled) → partial repay
  • amount omitted → Option::None → repay-all (unchanged)

The Option<u64> argument also switches from tx.object.option to tx.pure.option, again matching the sibling files and avoiding an extra 0x1::option::some/none PTB command per repay.

Test plan

Added test/unit/transactions/marginManager.test.ts covering all three cases on both methods. Each test inspects the emitted Option<u64> input bytes and decodes them with bcs.option(bcs.u64()):

  • repayBase(mgr, 0)Some("0")
  • repayBase(mgr, 1.5)Some("1500000000") (scaled by base scalar)
  • repayBase(mgr)None
  • Symmetrical cases for repayQuote.

Ran pnpm --filter @mysten/deepbook-v3 exec vitest run — 19/19 passing. Ran tsc --noEmit, oxlint, and prettier --check — all clean.


AI Assistance Notice

Please disclose the usage of AI. This is primarily to help inform reviewers of how careful they need to review PRs, and to keep track of AI usage across our team. Please fill this out accurately, and do not modify the content or heading for this section!

  • This PR was primarily written by AI.
  • I used AI for docs / tests, but manually wrote the source code.
  • I used AI to understand the problem space / repository.
  • I did not use AI for this PR.

…mount=0

The previous truthy guard (`amount ? … : null`) collapsed `0` onto the
Option::None branch. In Move, None means 'repay as much as possible
using the available balance of the asset in the balance manager',
capped at the full outstanding debt — so `repayBase(mgr, 0)` /
`repayQuote(mgr, 0)` silently triggered a full-debt repayment instead
of a no-op.

The guard now uses `amount !== undefined`, so `0` serializes as
Option::Some(0) and only an omitted argument becomes None. Also
switches the Option<u64> argument from `tx.object.option` to
`tx.pure.option`, matching marginLiquidations.ts and marginPool.ts
and avoiding an extra 0x1::option::some/none PTB command.

Adds unit tests that inspect the emitted Option<u64> input bytes for
all three cases (Some(0), Some(n), None) on both repay methods.
@Danny-Devs Danny-Devs requested a review from a team as a code owner April 22, 2026 04:58
@vercel
Copy link
Copy Markdown

vercel Bot commented Apr 22, 2026

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated (UTC)
sui-typescript-docs Ready Ready Preview, Comment Apr 22, 2026 5:00am

Request Review

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant