@@ -23,7 +23,7 @@ access(all) contract RedemptionWrapper {
2323 moetBurned : UFix64 ,
2424 collateralType : String ,
2525 collateralReceived : UFix64 ,
26- oraclePrice : UFix64 ,
26+ collateralOraclePrice : UFix64 ,
2727 preRedemptionHealth : UFix128 ,
2828 postRedemptionHealth : UFix128
2929 )
@@ -42,7 +42,7 @@ access(all) contract RedemptionWrapper {
4242 access (all ) var minRedemptionAmount : UFix64
4343
4444 // Rate limiting
45- access (all ) var redemptionCooldown : UFix64
45+ access (all ) var redemptionCooldownSeconds : UFix64
4646 access (all ) var dailyRedemptionLimit : UFix64
4747 access (all ) var dailyRedemptionUsed : UFix64
4848 access (all ) var lastRedemptionResetDay : UFix64
@@ -51,6 +51,7 @@ access(all) contract RedemptionWrapper {
5151 // Oracle and health protections
5252 access (all ) var maxPriceAge : UFix64
5353 access (all ) var minPostRedemptionHealth : UFix128
54+ access (all ) var oracle : {DeFiActions .PriceOracle }
5455
5556 // Position tracking
5657 access (all ) var positionID : UInt64 ?
@@ -77,22 +78,26 @@ access(all) contract RedemptionWrapper {
7778 }
7879
7980 access (all ) fun setProtectionParams (
80- redemptionCooldown : UFix64 ,
81+ redemptionCooldownSeconds : UFix64 ,
8182 dailyRedemptionLimit : UFix64 ,
8283 maxPriceAge : UFix64 ,
8384 minPostRedemptionHealth : UFix128
8485 ) {
8586 pre {
86- redemptionCooldown < = 3600.0 : " Cooldown too long (max 1 hour)"
87+ redemptionCooldownSeconds < = 3600.0 : " Cooldown too long (max 1 hour)"
8788 dailyRedemptionLimit > 0.0 : " Daily limit must be positive"
8889 maxPriceAge < = 7200.0 : " Max price age too long (max 2 hours)"
8990 minPostRedemptionHealth > = FlowALPMath .toUFix128 (1.0 ): " Min post-redemption health must be >= 1.0"
9091 }
91- RedemptionWrapper .redemptionCooldown = redemptionCooldown
92+ RedemptionWrapper .redemptionCooldownSeconds = redemptionCooldownSeconds
9293 RedemptionWrapper .dailyRedemptionLimit = dailyRedemptionLimit
9394 RedemptionWrapper .maxPriceAge = maxPriceAge
9495 RedemptionWrapper .minPostRedemptionHealth = minPostRedemptionHealth
9596 }
97+
98+ access (all ) fun setOracle (_ newOracle : {DeFiActions .PriceOracle }) {
99+ RedemptionWrapper .oracle = newOracle
100+ }
96101
97102 access (all ) fun pause () {
98103 RedemptionWrapper .paused = true
@@ -123,7 +128,7 @@ access(all) contract RedemptionWrapper {
123128 moet : @MOET.Vault ,
124129 preferredCollateralType : Type ? ,
125130 receiver : Capability <&{FungibleToken .Receiver }>
126- ) {
131+ ): @ MOET.Vault ? {
127132 pre {
128133 ! RedemptionWrapper .reentrancyGuard : " Reentrancy detected"
129134 ! RedemptionWrapper .paused : " Redemptions are paused"
@@ -146,7 +151,7 @@ access(all) contract RedemptionWrapper {
146151 let userAddr = receiver .address
147152 if let lastTime = RedemptionWrapper .userLastRedemption [userAddr ] {
148153 assert (
149- getCurrentBlock ().timestamp - lastTime > = RedemptionWrapper .redemptionCooldown ,
154+ getCurrentBlock ().timestamp - lastTime > = RedemptionWrapper .redemptionCooldownSeconds ,
150155 message : " Redemption cooldown not elapsed"
151156 )
152157 }
@@ -179,23 +184,20 @@ access(all) contract RedemptionWrapper {
179184 let sink = position .createSink (type : Type <@MOET.Vault >())
180185 sink .depositCapacity (from : &moet as auth (FungibleToken.Withdraw ) &{FungibleToken .Vault })
181186 let repaid = moetAmount - moet .balance
182- destroy moet
183-
184- // Validate MOET was burned
185- assert (repaid > 0.0 , message : " No MOET was repaid/burned" )
187+
188+ // Validate MOET was repaid
189+ assert (repaid > 0.0 , message : " No MOET was repaid" )
186190
187191 // Determine collateral type (default to FlowToken if not specified)
188192 let collateralType = preferredCollateralType ?? Type <@FlowToken.Vault >()
189193
190194 // Get oracle price for the collateral
191- // Create a PriceOracle struct instance to access prices
192- let oracle = MockOracle .PriceOracle ()
193- let collateralPrice = oracle .price (ofToken : collateralType )
195+ let collateralPriceUSD = RedemptionWrapper .oracle .price (ofToken : collateralType )
194196 ?? panic (" Oracle price unavailable for collateral type" )
195197
196198 // Calculate exact collateral amount for 1:1 USD parity
197- // MOET is pegged to $1, so: collateralAmount = moetAmount / collateralPriceUSD
198- let collateralAmount = repaid / collateralPrice
199+ // MOET is pegged to $1, so: collateralAmount = repaid / collateralPriceUSD
200+ let collateralAmount = repaid / collateralPriceUSD
199201
200202 // Validate sufficient collateral is available
201203 let available = position .availableBalance (type : collateralType , pullFromTopUpSource : false )
@@ -236,27 +238,34 @@ access(all) contract RedemptionWrapper {
236238 moetBurned : repaid ,
237239 collateralType : collateralType .identifier ,
238240 collateralReceived : actualWithdrawn ,
239- oraclePrice : collateralPrice ,
241+ collateralOraclePrice : collateralPriceUSD ,
240242 preRedemptionHealth : preHealth ,
241243 postRedemptionHealth : postHealth
242244 )
245+
246+ if moet .balance > 0.0 {
247+ return <- moet
248+ }
249+ destroy moet
250+ return nil
243251 }
244252 }
245253
246254 /// Setup the redemption position with initial collateral
247255 /// This must be called once before any redemptions can occur
248256 /// If called multiple times (e.g., in tests), it will overwrite the previous position
249257 access (all ) fun setup (
258+ admin : &Admin ,
250259 initialCollateral : @{FungibleToken .Vault },
251260 issuanceSink : {DeFiActions .Sink },
252261 repaymentSource : {DeFiActions .Source }?
253262 ) {
254263 // Allow re-setup for testing - clean up previous position if exists
255264 if self .positionID ! = nil {
256265 // Remove old position (structs don't need destroying)
257- self .account .storage .load <FlowALP .Position >(from : self .RedemptionPositionStoragePath )
266+ let _ = self .account .storage .load <FlowALP .Position >(from : self .RedemptionPositionStoragePath )
258267 // Remove old pool cap (capabilities don't need destroying)
259- self .account .storage .load <Capability <auth (FlowALP.EParticipant , FlowALP.EPosition ) &FlowALP.Pool >>(from : self .PoolCapStoragePath )
268+ let unusedCap = self .account .storage .load <Capability <auth (FlowALP.EParticipant , FlowALP.EPosition ) &FlowALP.Pool >>(from : self .PoolCapStoragePath )
260269 }
261270
262271 let poolCap = self .account .storage .load <Capability <auth (FlowALP.EParticipant , FlowALP.EPosition ) &FlowALP.Pool >>(
@@ -318,7 +327,7 @@ access(all) contract RedemptionWrapper {
318327 self .minRedemptionAmount = 10.0 // Prevent spam
319328
320329 // Rate limiting for MEV protection
321- self .redemptionCooldown = 60.0 // 1 minute cooldown per user
330+ self .redemptionCooldownSeconds = 60.0 // 1 minute cooldown per user
322331 self .dailyRedemptionLimit = 100000.0 // 100k MOET per day circuit breaker
323332 self .dailyRedemptionUsed = 0.0
324333 self .lastRedemptionResetDay = UFix64 (getCurrentBlock ().timestamp ) / 86400.0
@@ -327,6 +336,7 @@ access(all) contract RedemptionWrapper {
327336 // Oracle and health protections
328337 self .maxPriceAge = 3600.0 // 1 hour max price age
329338 self .minPostRedemptionHealth = FlowALPMath .toUFix128 (1.15 ) // Require 115% health after redemption
339+ self .oracle = MockOracle .PriceOracle () // Default to MockOracle
330340
331341 // Position tracking
332342 self .positionID = nil
0 commit comments