@@ -5,8 +5,10 @@ import { integrationPreviewerAbi, marketUsdcAbi, ratePreviewerAbi } from "./gene
55import anvilClient from "./utils/anvilClient.js" ;
66import MAX_UINT256 from "../src/fixed-point-math/MAX_UINT256.js" ;
77import divWad from "../src/fixed-point-math/divWad.js" ;
8- import { MATURITY_INTERVAL } from "../src/interest-rate-model/fixedRate.js" ;
8+ import mulWad from "../src/fixed-point-math/mulWad.js" ;
9+ import { MATURITY_INTERVAL , WAD } from "../src/interest-rate-model/fixedRate.js" ;
910import fixedRepayAssets , { type FixedRepaySnapshot } from "../src/market/fixedRepayAssets.js" ;
11+ import fixedRepayPosition from "../src/market/fixedRepayPosition.js" ;
1012import floatingDepositRates from "../src/market/floatingDepositRates.js" ;
1113
1214describe ( "floating deposit rate" , ( ) => {
@@ -149,4 +151,141 @@ describe("fixed repay", () => {
149151 expect ( repayAssets ) . toBe ( 0n ) ;
150152 } ) ;
151153 } ) ;
154+
155+ describe ( "position" , ( ) => {
156+ it ( "calculates before maturity" , async ( ) => {
157+ const timestamp = 69_420 ;
158+ const repayAssets = 420_000_000n ;
159+
160+ const positionAssets = fixedRepayPosition ( snapshot , MATURITY_INTERVAL , repayAssets , timestamp ) ;
161+
162+ const { data = "0x" } = await anvilClient . call ( {
163+ account : inject ( "deployer" ) ,
164+ to : inject ( "MarketUSDC" ) ,
165+ data : encodeFunctionData ( {
166+ functionName : "repayAtMaturity" ,
167+ args : [ BigInt ( MATURITY_INTERVAL ) , positionAssets , MAX_UINT256 , inject ( "deployer" ) ] ,
168+ abi : marketUsdcAbi ,
169+ } ) ,
170+ blockOverrides : { time : BigInt ( timestamp ) } ,
171+ } ) ;
172+
173+ expect ( repayAssets ) . toBe ( decodeFunctionResult ( { data, functionName : "repayAtMaturity" , abi : marketUsdcAbi } ) ) ;
174+ } ) ;
175+
176+ it ( "calculates after maturity" , async ( ) => {
177+ const timestamp = 69_420 + MATURITY_INTERVAL ;
178+ const repayAssets = 420_000_000n ;
179+
180+ const positionAssets = fixedRepayPosition ( snapshot , MATURITY_INTERVAL , repayAssets , timestamp ) ;
181+
182+ const { data = "0x" } = await anvilClient . call ( {
183+ account : inject ( "deployer" ) ,
184+ to : inject ( "MarketUSDC" ) ,
185+ data : encodeFunctionData ( {
186+ functionName : "repayAtMaturity" ,
187+ args : [ BigInt ( MATURITY_INTERVAL ) , positionAssets , MAX_UINT256 , inject ( "deployer" ) ] ,
188+ abi : marketUsdcAbi ,
189+ } ) ,
190+ blockOverrides : { time : BigInt ( timestamp ) } ,
191+ } ) ;
192+ const actualRepayAssets = decodeFunctionResult ( { data, functionName : "repayAtMaturity" , abi : marketUsdcAbi } ) ;
193+
194+ expect ( actualRepayAssets ) . toBeLessThanOrEqual ( repayAssets ) ;
195+ expect ( repayAssets - actualRepayAssets ) . toBeLessThanOrEqual ( 1n ) ;
196+ } ) ;
197+
198+ it ( "calculates with max position" , ( ) => {
199+ const positionAssets = fixedRepayPosition ( snapshot , MATURITY_INTERVAL , MAX_UINT256 , 69_420 ) ;
200+
201+ expect ( positionAssets ) . toBe ( snapshot . principal + snapshot . fee ) ;
202+ } ) ;
203+
204+ it ( "calculates with empty position" , ( ) => {
205+ const positionAssets = fixedRepayPosition (
206+ { ...snapshot , principal : 0n , fee : 0n } ,
207+ MATURITY_INTERVAL ,
208+ MAX_UINT256 ,
209+ 69_420 ,
210+ ) ;
211+
212+ expect ( positionAssets ) . toBe ( 0n ) ;
213+ } ) ;
214+
215+ it ( "calculates without unassigned earnings" , ( ) => {
216+ const repayAssets = 420_000_000n ;
217+
218+ const positionAssets = fixedRepayPosition (
219+ { ...snapshot , unassignedEarnings : 0n } ,
220+ MATURITY_INTERVAL ,
221+ repayAssets ,
222+ 69_420 ,
223+ ) ;
224+
225+ expect ( positionAssets ) . toBe ( repayAssets ) ;
226+ } ) ;
227+
228+ it ( "calculates without backup supplied" , ( ) => {
229+ const repayAssets = 420_000_000n ;
230+
231+ const positionAssets = fixedRepayPosition (
232+ { ...snapshot , supplied : snapshot . borrowed } ,
233+ MATURITY_INTERVAL ,
234+ repayAssets ,
235+ 69_420 ,
236+ ) ;
237+
238+ expect ( positionAssets ) . toBe ( repayAssets ) ;
239+ } ) ;
240+
241+ it ( "calculates without principal" , ( ) => {
242+ const repayAssets = 69n ;
243+
244+ const positionAssets = fixedRepayPosition ( { ...snapshot , principal : 0n } , MATURITY_INTERVAL , repayAssets , 69_420 ) ;
245+
246+ expect ( positionAssets ) . toBe ( repayAssets ) ;
247+ } ) ;
248+
249+ it ( "calculates without net unassigned earnings" , ( ) => {
250+ const repayAssets = 420_000_000n ;
251+
252+ const positionAssets = fixedRepayPosition (
253+ { ...snapshot , unassignedEarnings : 1n } ,
254+ MATURITY_INTERVAL ,
255+ repayAssets ,
256+ 69_420 ,
257+ ) ;
258+
259+ expect ( positionAssets ) . toBe ( repayAssets ) ;
260+ } ) ;
261+
262+ it ( "calculates with high earnings proportion" , ( ) => {
263+ const timestamp = 69_420 ;
264+ const repayAssets = 420_000_000n ;
265+
266+ const positionAssets = fixedRepayPosition (
267+ { ...snapshot , supplied : snapshot . borrowed - 1n , lastAccrual : BigInt ( timestamp ) } ,
268+ MATURITY_INTERVAL ,
269+ repayAssets ,
270+ timestamp ,
271+ ) ;
272+
273+ expect ( positionAssets ) . toBe ( repayAssets + mulWad ( snapshot . unassignedEarnings , WAD - snapshot . backupFeeRate ) ) ;
274+ } ) ;
275+
276+ it ( "calculates with high saturated fallback" , ( ) => {
277+ const timestamp = 69_420 ;
278+ const repayAssets = 420_000_000n ;
279+ const unassignedEarnings = 420n ;
280+
281+ const positionAssets = fixedRepayPosition (
282+ { ...snapshot , supplied : snapshot . borrowed - 420n , unassignedEarnings, lastAccrual : BigInt ( timestamp ) } ,
283+ MATURITY_INTERVAL ,
284+ repayAssets ,
285+ timestamp ,
286+ ) ;
287+
288+ expect ( positionAssets ) . toBe ( repayAssets + mulWad ( unassignedEarnings , WAD - snapshot . backupFeeRate ) ) ;
289+ } ) ;
290+ } ) ;
152291} ) ;
0 commit comments