Skip to content

feat(stablecoin): implement withdraw_collateral (#92)#112

Merged
0x-r4bbit merged 5 commits into
mainfrom
stablecoin/withdraw-collateral
May 26, 2026
Merged

feat(stablecoin): implement withdraw_collateral (#92)#112
0x-r4bbit merged 5 commits into
mainfrom
stablecoin/withdraw-collateral

Conversation

@gravityblast
Copy link
Copy Markdown
Collaborator

@gravityblast gravityblast commented May 19, 2026

closes #92
closes #93
closes #94

Note: fee accrual and post-withdrawal collateralization checks are defered to be implemented together with generate_debt.

@gravityblast gravityblast requested a review from 3esmit May 19, 2026 14:00
@gravityblast gravityblast force-pushed the stablecoin/withdraw-collateral branch from 3a8e5c3 to b7257ad Compare May 19, 2026 14:02
@3esmit 3esmit requested a review from Copilot May 19, 2026 14:39
Copy link
Copy Markdown

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR implements the withdraw_collateral instruction for the stablecoin program (closes #92). The implementation mirrors the conventions established in open_position: validate inputs, decode the Position, verify position/vault PDAs, and emit a chained Token::Transfer from the vault to the destination under the vault's PDA authority. As called out in issue #92, full functionality requires stability fee accrual and a collateralization-ratio check (issues #95/#96/#97); until those land, the instruction hard-asserts Position.debt_amount == 0.

Changes:

  • Adds withdraw_collateral core logic that validates accounts, decrements Position.collateral_amount, and emits a chained Token::Transfer.
  • Wires the instruction into the guest entrypoint and the Instruction enum, regenerating the stablecoin IDL.
  • Adds 12 new unit tests covering the happy path, edge cases (zero/full drain), and each panic precondition.

Reviewed changes

Copilot reviewed 6 out of 6 changed files in this pull request and generated no comments.

Show a summary per file
File Description
stablecoin/src/withdraw_collateral.rs New module implementing the instruction's logic, account validation, and chained transfer emission.
stablecoin/src/lib.rs Exposes the new withdraw_collateral module.
stablecoin/src/tests.rs New helper constructors and 12 unit tests for the happy path and all panic preconditions.
stablecoin/core/src/lib.rs Adds the WithdrawCollateral { amount } variant to the Instruction enum with account-list documentation.
stablecoin/methods/guest/src/bin/stablecoin.rs Guest-side #[instruction] wrapper that delegates to withdraw_collateral.
artifacts/stablecoin-idl.json Regenerated IDL entry for the new instruction.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Copy link
Copy Markdown
Collaborator

@3esmit 3esmit left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Add a test that gives the vault a balance matching Position.collateral_amount and either executes the emitted transfer through token_program::transfer::transfer or, better, adds an integration test that opens a stablecoin position and then withdraws from it through LEZ chained-call execution

Comment thread stablecoin/src/tests.rs
let (post_states, chained_calls) = crate::withdraw_collateral::withdraw_collateral(
owner_account(),
init_position_account(initial_collateral, 0),
init_vault_account(),
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Vault account is initialized with balance 0

Comment thread stablecoin/src/tests.rs
#[test]
fn withdraw_collateral_updates_position_and_emits_transfer() {
let initial_collateral: u128 = 500;
let amount: u128 = 200;
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Withdraw requests for 200

Comment thread stablecoin/src/tests.rs
},
)
.with_pda_seeds(vec![compute_position_vault_pda_seed(position_id())]);
assert_eq!(chained_calls[0], expected_transfer);
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Only checks if Transfer is emmited, but the downstream token program would reject the transfer because it does not have balance.

@0x-r4bbit 0x-r4bbit force-pushed the stablecoin/withdraw-collateral branch from 47116c2 to cf3090b Compare May 25, 2026 19:04
@0x-r4bbit
Copy link
Copy Markdown
Collaborator

Rebased this PR on top of latest main

@0x-r4bbit
Copy link
Copy Markdown
Collaborator

I think the test move is actually replacing the test with a different check.
Let's get this align on this and I think then this can be merged.

@0x-r4bbit
Copy link
Copy Markdown
Collaborator

I revisited this again, and I think the integration test @gravityblast introduced is fine, in favor of @3esmit unit test

The unit test ensured that, if the vault's balance is 0 then the pre_state for the transfer will be of balance 0 as well so the transfer would fail. But this property is already covered by the environment.

@0x-r4bbit 0x-r4bbit merged commit cdb53a4 into main May 26, 2026
6 checks passed
@gravityblast gravityblast deleted the stablecoin/withdraw-collateral branch May 26, 2026 10:14
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.

Implement close_position Implement repay_debt Implement withdraw_collateral

4 participants