Skip to content

[WIP] Leveraged Basis trade vault #64

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 11 commits into from
Apr 7, 2025
Merged

[WIP] Leveraged Basis trade vault #64

merged 11 commits into from
Apr 7, 2025

Conversation

0xdomrom
Copy link
Contributor

No description provided.

@0xdomrom 0xdomrom changed the title Leveraged Basis trade vault [WIP] Leveraged Basis trade vault Feb 14, 2025
Copy link
Collaborator

@joshpwrk joshpwrk left a comment

Choose a reason for hiding this comment

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

LGMT, just some questions + nitpicks.

Feel free to not implement nitpicks into this basis trade deploy - but mostly leaving comments so we don't forget for next deploy.

bytes32 hash = getActionTypedDataHash(action);
// TODO: check we want caching. **If params are updated, old ones would not be revoked.**
// if (_getBaseSigningTSAStorage().signedData[hash]) return;
Copy link
Collaborator

Choose a reason for hiding this comment

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

can remove now?

tradeHelperVars.basePrice = _getBasePrice();
tradeHelperVars.perpPrice = _getPerpPrice();
(tradeHelperVars.perpPosition, tradeHelperVars.baseBalance, tradeHelperVars.cashBalance) = _getSubAccountStats();
tradeHelperVars.underlyingBase = _getConvertedMtM();
Copy link
Collaborator

Choose a reason for hiding this comment

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

I noticed this function actually reverts if mTm < 0. I think it was initially done to prevent deposits / withdrawals, but now that it's used in this generic helper, should we move this outside.

E.g. would this block any valid action / deleveraging when vault is in a dangerous situation?

if (convertedMtM < 0 || margin < 0) {
  revert CMTSA_PositionInsolvent();
}

Copy link
Contributor Author

Choose a reason for hiding this comment

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

If MtM < 0, its actually in the vault's interest to get liquidated before depositing, since you'd be paying off insolvency using new funds.

Will remove the margin check though, since if it is flagged, the action will be blocked anyways.

@joshpwrk
Copy link
Collaborator

joshpwrk commented Mar 6, 2025

Does this work for when the last user tries to withdraw?

function _verifyTradeDelta(TradeHelperVars memory tradeHelperVars, int amtDelta) internal view {
    LBTSAStorage storage $ = _getLBTSAStorage();

    uint perpBaseRatio = tradeHelperVars.perpPrice.divideDecimal(tradeHelperVars.basePrice);

    int deltaChange = tradeHelperVars.isBaseTrade ? amtDelta : amtDelta.multiplyDecimal(int(perpBaseRatio));

    // delta as a % of TVL
    int portfolioDeltaPercent = (
      int(tradeHelperVars.baseBalance) + tradeHelperVars.perpPosition.multiplyDecimal(int(perpBaseRatio))
    ).divideDecimal(int(tradeHelperVars.underlyingBase));
    int newDeltaPercent = portfolioDeltaPercent + deltaChange.divideDecimal(int(tradeHelperVars.underlyingBase));
    int targetDelta = $.lbParams.deltaTarget;

    if ((newDeltaPercent - targetDelta).abs() < (portfolioDeltaPercent - targetDelta).abs()) {
      // delta is improving
      return;
    }

    require(
      newDeltaPercent >= targetDelta - $.lbParams.deltaTargetTolerance
        && newDeltaPercent <= targetDelta + $.lbParams.deltaTargetTolerance,
      LBT_PostTradeDeltaOutOfRange()
    );
  }

e.g. if -amtDelta = basisBalance = underlyingBase and perpPosition = 0, doesn't that result in newDeltaPercent = 0?

It makes me think that the actual calculation might not be optimal? Here are some cases:


  LBTC = 100
  perp = 0
  USDC = 0

  withdraw 50 LBTC

	int portfolioDeltaPercent = (100 + 0).divideDecimal(100) = 1
	int newDeltaPercent = 1 + (-50).divideDecimal(100); -> 0.5 // in reality the actual delta percent should be 1

  LBTC = 100
  perp = 0
  USDC = 0

  withdraw 100 LBTC

	int portfolioDeltaPercent = (100 + 0).divideDecimal(100) = 1
	int newDeltaPercent = 1 + (-100).divideDecimal(100); -> 0 // in reality the actual delta percent should be 1


  LBTC = 100
  perp = 0
  USDC = 0

  withdraw 99 LBTC

	int portfolioDeltaPercent = (100 + 0).divideDecimal(100) = 1
	int newDeltaPercent = 1 + (-99).divideDecimal(100); -> 0.01 // in reality the actual delta percent should be 1

  LBTC = 100
  perp = 0
  USDC = 0

  withdraw 1 LBTC

	int portfolioDeltaPercent = (100 + 0).divideDecimal(100) = 1
	int newDeltaPercent = 1 + (-1).divideDecimal(100); -> 0.99 

I think the TLDR is - the smaller the TVL the less you are allowed to trade / withdraw at a time. Not sure if that's intentional + not sure if that breaks for last withdrawal

Dominic Romanowski added 2 commits March 10, 2025 21:19
@vladislavabramov
Copy link

vladislavabramov commented Mar 10, 2025

Does this work for when the last user tries to withdraw?

function _verifyTradeDelta(TradeHelperVars memory tradeHelperVars, int amtDelta) internal view {
    LBTSAStorage storage $ = _getLBTSAStorage();

    uint perpBaseRatio = tradeHelperVars.perpPrice.divideDecimal(tradeHelperVars.basePrice);

    int deltaChange = tradeHelperVars.isBaseTrade ? amtDelta : amtDelta.multiplyDecimal(int(perpBaseRatio));

    // delta as a % of TVL
    int portfolioDeltaPercent = (
      int(tradeHelperVars.baseBalance) + tradeHelperVars.perpPosition.multiplyDecimal(int(perpBaseRatio))
    ).divideDecimal(int(tradeHelperVars.underlyingBase));
    int newDeltaPercent = portfolioDeltaPercent + deltaChange.divideDecimal(int(tradeHelperVars.underlyingBase));
    int targetDelta = $.lbParams.deltaTarget;

    if ((newDeltaPercent - targetDelta).abs() < (portfolioDeltaPercent - targetDelta).abs()) {
      // delta is improving
      return;
    }

    require(
      newDeltaPercent >= targetDelta - $.lbParams.deltaTargetTolerance
        && newDeltaPercent <= targetDelta + $.lbParams.deltaTargetTolerance,
      LBT_PostTradeDeltaOutOfRange()
    );
  }

e.g. if -amtDelta = basisBalance = underlyingBase and perpPosition = 0, doesn't that result in newDeltaPercent = 0?

It makes me think that the actual calculation might not be optimal? Here are some cases:


  LBTC = 100
  perp = 0
  USDC = 0

  withdraw 50 LBTC

	int portfolioDeltaPercent = (100 + 0).divideDecimal(100) = 1
	int newDeltaPercent = 1 + (-50).divideDecimal(100); -> 0.5 // in reality the actual delta percent should be 1

  LBTC = 100
  perp = 0
  USDC = 0

  withdraw 100 LBTC

	int portfolioDeltaPercent = (100 + 0).divideDecimal(100) = 1
	int newDeltaPercent = 1 + (-100).divideDecimal(100); -> 0 // in reality the actual delta percent should be 1


  LBTC = 100
  perp = 0
  USDC = 0

  withdraw 99 LBTC

	int portfolioDeltaPercent = (100 + 0).divideDecimal(100) = 1
	int newDeltaPercent = 1 + (-99).divideDecimal(100); -> 0.01 // in reality the actual delta percent should be 1

  LBTC = 100
  perp = 0
  USDC = 0

  withdraw 1 LBTC

	int portfolioDeltaPercent = (100 + 0).divideDecimal(100) = 1
	int newDeltaPercent = 1 + (-1).divideDecimal(100); -> 0.99 

I think the TLDR is - the smaller the TVL the less you are allowed to trade / withdraw at a time. Not sure if that's intentional + not sure if that breaks for last withdrawal

oof good catch - i think the issue here is that the denominator underlyingBase doesn't account for the withdrawn funds, i.e. in your example 1 (100 LBTC withdraw 50) the delta should always be 1.0 (since in the end you have 50 LBTC delta with 50 LBTC TVL)

once that's resolved then for 1.0 target delta vault all withdrawals always pass the delta check (but are still subject to leverage check), and with non-1.0 delta you still need to split them up and close the hedges in-between, but that's expected

@0xdomrom 0xdomrom force-pushed the feat/lev-basis-vault branch from 0737eba to fc1535b Compare March 12, 2025 00:40
@0xdomrom 0xdomrom merged commit 927340a into master Apr 7, 2025
1 of 2 checks passed
@0xdomrom 0xdomrom deleted the feat/lev-basis-vault branch April 7, 2025 22:59
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.

3 participants