Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 3 additions & 1 deletion cadence/contracts/FlowALPv0.cdc
Original file line number Diff line number Diff line change
Expand Up @@ -3332,8 +3332,10 @@ access(all) contract FlowALPv0 {

// Step 7: Build withdrawals map for event (vaults are in same order as collateralTypes)
let withdrawalsByType: {Type: UFix64} = {}
for i in InclusiveRange(0, vaults.length-1) {
var i = 0
while i < vaults.length {
withdrawalsByType[vaults[i].getType()] = vaults[i].balance
i = i + 1
}

// Step 8: Emit position closed event
Expand Down
78 changes: 78 additions & 0 deletions cadence/tests/close_position_empty_position_test.cdc
Original file line number Diff line number Diff line change
@@ -0,0 +1,78 @@
import Test
import BlockchainHelpers

import "MOET"
import "FlowALPv0"
import "test_helpers.cdc"

access(all) var snapshot: UInt64 = 0

access(all)
fun safeReset() {
let cur = getCurrentBlockHeight()
if cur > snapshot {
Test.reset(to: snapshot)
}
}

access(all)
fun setup() {
deployContracts()
createAndStorePool(signer: PROTOCOL_ACCOUNT, defaultTokenIdentifier: MOET_TOKEN_IDENTIFIER, beFailed: false)
snapshot = getCurrentBlockHeight()
}

/// Regression test for closePosition empty-withdrawals map handling.
///
/// Scenario:
/// 1) Open a position with collateral and no debt.
/// 2) Withdraw all collateral so the position has no balances.
/// 3) Close the position.
///
/// Expected: close succeeds (must not panic on empty vault array).
access(all)
fun test_closePosition_afterFullWithdrawal_noDebtNoCollateral() {
safeReset()

setMockOraclePrice(signer: PROTOCOL_ACCOUNT, forTokenIdentifier: FLOW_TOKEN_IDENTIFIER, price: 1.0)
addSupportedTokenZeroRateCurve(
signer: PROTOCOL_ACCOUNT,
tokenTypeIdentifier: FLOW_TOKEN_IDENTIFIER,
collateralFactor: 0.8,
borrowFactor: 1.0,
depositRate: 1_000_000.0,
depositCapacityCap: 1_000_000.0
)

let user = Test.createAccount()
setupMoetVault(user, beFailed: false)
mintFlow(to: user, amount: 1_000.0)
grantBetaPoolParticipantAccess(PROTOCOL_ACCOUNT, user)

let openRes = _executeTransaction(
"../transactions/flow-alp/position/create_position.cdc",
[100.0, FLOW_VAULT_STORAGE_PATH, false],
user
)
Test.expect(openRes, Test.beSucceeded())

let withdrawRes = _executeTransaction(
"./transactions/position-manager/withdraw_from_position.cdc",
[UInt64(0), FLOW_TOKEN_IDENTIFIER, 100.0, false],
user
)
Test.expect(withdrawRes, Test.beSucceeded())

let closeRes = _executeTransaction(
"../transactions/flow-alp/position/repay_and_close_position.cdc",
[UInt64(0)],
user
)
Test.expect(closeRes, Test.beSucceeded())

let flowBalanceAfter = getBalance(address: user.address, vaultPublicPath: /public/flowTokenReceiver)!
Test.assert(
flowBalanceAfter >= 1_000.0 - DEFAULT_UFIX_VARIANCE,
message: "Expected all FLOW to be returned after full withdrawal and close"
)
}