@@ -50,6 +50,9 @@ import { UnacceptableSwap, UnreliablePrice, UnexpectedDecimals, InvalidPerc, Inv
5050 * Lenders can buy perps from the bill broker contract when it's under-priced,
5151 * hold the perp tokens until the market price recovers and sell it back to the bill broker contract.
5252 *
53+ * Single Sided deposits:
54+ * The pool also supports single sided deposits with either perps or usd tokens
55+ * insofar as it brings the pool back into balance.
5356 *
5457 */
5558contract BillBroker is
@@ -112,6 +115,29 @@ contract BillBroker is
112115 /// the swap fees transition from a flat percentage fee to a linear function.
113116 Range public arSoftBound;
114117
118+ //--------------------------------------------------------------------------
119+ // Events
120+
121+ /// @notice Emitted when a user deposits USD tokens to mint LP tokens.
122+ /// @param usdAmtIn The amount of USD tokens deposited.
123+ /// @param preOpState The reserve state before the deposit operation.
124+ event DepositUSD (uint256 usdAmtIn , ReserveState preOpState );
125+
126+ /// @notice Emitted when a user deposits Perp tokens to mint LP tokens.
127+ /// @param perpAmtIn The amount of Perp tokens deposited.
128+ /// @param preOpState The reserve state before the deposit operation.
129+ event DepositPerp (uint256 perpAmtIn , ReserveState preOpState );
130+
131+ /// @notice Emitted when a user swaps Perp tokens for USD tokens.
132+ /// @param perpAmtIn The amount of Perp tokens swapped in.
133+ /// @param preOpState The reserve state before the swap operation.
134+ event SwapPerpsForUSD (uint256 perpAmtIn , ReserveState preOpState );
135+
136+ /// @notice Emitted when a user swaps USD tokens for Perp tokens.
137+ /// @param usdAmtIn The amount of USD tokens swapped in.
138+ /// @param preOpState The reserve state before the swap operation.
139+ event SwapUSDForPerps (uint256 usdAmtIn , ReserveState preOpState );
140+
115141 //--------------------------------------------------------------------------
116142 // Modifiers
117143
@@ -289,6 +315,90 @@ contract BillBroker is
289315 _mint (msg .sender , mintAmt);
290316 }
291317
318+ /// @notice Single sided usd token deposit and mint LP tokens.
319+ /// @param usdAmtIn The amount of usd tokens to be deposited.
320+ /// @param postOpAssetRatioMax The system asset ratio can be no higher than this value after deposit.
321+ /// @return mintAmt The amount of LP tokens minted.
322+ function depositUSD (
323+ uint256 usdAmtIn ,
324+ uint256 postOpAssetRatioMax
325+ ) external nonReentrant whenNotPaused returns (uint256 mintAmt ) {
326+ ReserveState memory preOpState = reserveState ();
327+ uint256 preOpAssetRatio = assetRatio (preOpState);
328+ uint256 postOpAssetRatio = assetRatio (
329+ ReserveState ({
330+ usdBalance: preOpState.usdBalance + usdAmtIn,
331+ perpBalance: preOpState.perpBalance,
332+ usdPrice: preOpState.usdPrice,
333+ perpPrice: preOpState.perpPrice
334+ })
335+ );
336+
337+ // We allow minting only pool is underweight usd
338+ if (preOpAssetRatio >= ONE || postOpAssetRatio > ONE) {
339+ return 0 ;
340+ }
341+
342+ mintAmt = computeMintAmtWithUSD (usdAmtIn, preOpState);
343+ if (mintAmt <= 0 ) {
344+ return 0 ;
345+ }
346+ if (postOpAssetRatio > postOpAssetRatioMax) {
347+ revert SlippageTooHigh ();
348+ }
349+
350+ // Transfer usd tokens from the user
351+ usd.safeTransferFrom (msg .sender , address (this ), usdAmtIn);
352+
353+ // mint LP tokens to the user
354+ _mint (msg .sender , mintAmt);
355+
356+ // Emit deposit info
357+ emit DepositUSD (usdAmtIn, preOpState);
358+ }
359+
360+ /// @notice Single sided perp token deposit and mint LP tokens.
361+ /// @param perpAmtIn The amount of perp tokens to be deposited.
362+ /// @param postOpAssetRatioMin The system asset ratio can be no lower than this value after deposit.
363+ /// @return mintAmt The amount of LP tokens minted.
364+ function depositPerp (
365+ uint256 perpAmtIn ,
366+ uint256 postOpAssetRatioMin
367+ ) external nonReentrant whenNotPaused returns (uint256 mintAmt ) {
368+ ReserveState memory preOpState = reserveState ();
369+ uint256 preOpAssetRatio = assetRatio (preOpState);
370+ uint256 postOpAssetRatio = assetRatio (
371+ ReserveState ({
372+ usdBalance: preOpState.usdBalance,
373+ perpBalance: preOpState.perpBalance + perpAmtIn,
374+ usdPrice: preOpState.usdPrice,
375+ perpPrice: preOpState.perpPrice
376+ })
377+ );
378+
379+ // We allow minting only pool is underweight perp
380+ if (preOpAssetRatio <= ONE || postOpAssetRatio < ONE) {
381+ return 0 ;
382+ }
383+
384+ mintAmt = computeMintAmtWithPerp (perpAmtIn, preOpState);
385+ if (mintAmt <= 0 ) {
386+ return 0 ;
387+ }
388+ if (postOpAssetRatio < postOpAssetRatioMin) {
389+ revert SlippageTooHigh ();
390+ }
391+
392+ // Transfer perp tokens from the user
393+ perp.safeTransferFrom (msg .sender , address (this ), perpAmtIn);
394+
395+ // mint LP tokens to the user
396+ _mint (msg .sender , mintAmt);
397+
398+ // Emit deposit info
399+ emit DepositPerp (perpAmtIn, preOpState);
400+ }
401+
292402 /// @notice Burns LP tokens and redeems usd and perp tokens.
293403 /// @param burnAmt The LP tokens to be burnt.
294404 /// @return usdAmtOut The amount usd tokens returned.
@@ -323,10 +433,11 @@ contract BillBroker is
323433 uint256 perpAmtMin
324434 ) external nonReentrant whenNotPaused returns (uint256 perpAmtOut ) {
325435 // compute perp amount out
436+ ReserveState memory preOpState = reserveState ();
326437 uint256 protocolFeePerpAmt;
327438 (perpAmtOut, , protocolFeePerpAmt) = computeUSDToPerpSwapAmt (
328439 usdAmtIn,
329- reserveState ()
440+ preOpState
330441 );
331442 if (usdAmtIn <= 0 || perpAmtOut <= 0 ) {
332443 revert UnacceptableSwap ();
@@ -345,6 +456,9 @@ contract BillBroker is
345456
346457 // transfer perps out to the user
347458 perp.safeTransfer (msg .sender , perpAmtOut);
459+
460+ // Emit swap info
461+ emit SwapUSDForPerps (usdAmtIn, preOpState);
348462 }
349463
350464 /// @notice Swaps perp tokens from the user for usd tokens from the reserve.
@@ -356,11 +470,9 @@ contract BillBroker is
356470 uint256 usdAmtMin
357471 ) external nonReentrant whenNotPaused returns (uint256 usdAmtOut ) {
358472 // Compute swap amount
473+ ReserveState memory preOpState = reserveState ();
359474 uint256 protocolFeeUsdAmt;
360- (usdAmtOut, , protocolFeeUsdAmt) = computePerpToUSDSwapAmt (
361- perpAmtIn,
362- reserveState ()
363- );
475+ (usdAmtOut, , protocolFeeUsdAmt) = computePerpToUSDSwapAmt (perpAmtIn, preOpState);
364476 if (perpAmtIn <= 0 || usdAmtOut <= 0 ) {
365477 revert UnacceptableSwap ();
366478 }
@@ -378,11 +490,30 @@ contract BillBroker is
378490
379491 // transfer usd out to the user
380492 usd.safeTransfer (msg .sender , usdAmtOut);
493+
494+ // Emit swap info
495+ emit SwapPerpsForUSD (perpAmtIn, preOpState);
381496 }
382497
383498 //-----------------------------------------------------------------------------
384499 // Public methods
385500
501+ /// @notice Computes the amount of LP tokens minted,
502+ /// when the given number of usd tokens are deposited.
503+ /// @param usdAmtIn The amount of usd tokens deposited.
504+ /// @return mintAmt The amount of LP tokens minted.
505+ function computeMintAmtWithUSD (uint256 usdAmtIn ) public returns (uint256 mintAmt ) {
506+ return computeMintAmtWithUSD (usdAmtIn, reserveState ());
507+ }
508+
509+ /// @notice Computes the amount of LP tokens minted,
510+ /// when the given number of perp tokens are deposited.
511+ /// @param perpAmtIn The amount of perp tokens deposited.
512+ /// @return mintAmt The amount of LP tokens minted.
513+ function computeMintAmtWithPerp (uint256 perpAmtIn ) public returns (uint256 mintAmt ) {
514+ return computeMintAmtWithPerp (perpAmtIn, reserveState ());
515+ }
516+
386517 /// @notice Computes the amount of usd tokens swapped out,
387518 /// when the given number of perp tokens are sent in.
388519 /// @param perpAmtIn The amount of perp tokens swapped in.
@@ -508,6 +639,58 @@ contract BillBroker is
508639 mintAmt = mintAmt.mulDiv (ONE - fees.mintFeePerc, ONE);
509640 }
510641
642+ /// @notice Computes the amount of LP tokens minted,
643+ /// when the given number of usd tokens are deposited.
644+ /// @param usdAmtIn The amount of usd tokens deposited.
645+ /// @param s The current reserve state.
646+ /// @return mintAmt The amount of LP tokens minted.
647+ function computeMintAmtWithUSD (
648+ uint256 usdAmtIn ,
649+ ReserveState memory s
650+ ) public view returns (uint256 ) {
651+ if (usdAmtIn <= 0 ) {
652+ return 0 ;
653+ }
654+
655+ uint256 valueIn = s.usdPrice.mulDiv (usdAmtIn, usdUnitAmt);
656+ uint256 totalReserveVal = (s.usdPrice.mulDiv (s.usdBalance, usdUnitAmt) +
657+ s.perpPrice.mulDiv (s.perpBalance, perpUnitAmt));
658+
659+ return
660+ (totalReserveVal > 0 )
661+ ? valueIn.mulDiv (totalSupply (), totalReserveVal).mulDiv (
662+ ONE - fees.mintFeePerc,
663+ ONE
664+ )
665+ : 0 ;
666+ }
667+
668+ /// @notice Computes the amount of LP tokens minted,
669+ /// when the given number of perp tokens are deposited.
670+ /// @param perpAmtIn The amount of perp tokens deposited.
671+ /// @param s The current reserve state.
672+ /// @return mintAmt The amount of LP tokens minted.
673+ function computeMintAmtWithPerp (
674+ uint256 perpAmtIn ,
675+ ReserveState memory s
676+ ) public view returns (uint256 ) {
677+ if (perpAmtIn <= 0 ) {
678+ return 0 ;
679+ }
680+
681+ uint256 valueIn = s.perpPrice.mulDiv (perpAmtIn, perpUnitAmt);
682+ uint256 totalReserveVal = (s.usdPrice.mulDiv (s.usdBalance, usdUnitAmt) +
683+ s.perpPrice.mulDiv (s.perpBalance, perpUnitAmt));
684+
685+ return
686+ (totalReserveVal > 0 )
687+ ? valueIn.mulDiv (totalSupply (), totalReserveVal).mulDiv (
688+ ONE - fees.mintFeePerc,
689+ ONE
690+ )
691+ : 0 ;
692+ }
693+
511694 /// @notice Computes the amount of usd and perp tokens redeemed,
512695 /// when the given number of LP tokens are burnt.
513696 /// @param burnAmt The amount of LP tokens to be burnt.
0 commit comments