Skip to content

Conversation

@0xdomrom
Copy link
Contributor

No description provided.

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.

I think there are some edge cases because of how the non-atomic perfFees work w.r.t requestWithdrawal()

///////////////////////
// Action Validation //
///////////////////////
function _verifyAction(IMatching.Action memory action, bytes32 actionHash, bytes memory extraData)
Copy link
Collaborator

Choose a reason for hiding this comment

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

an idea for the future (def not this PR) - where you can build your own vault by adding on whatever guardrails you want.

For example, each ActionType has an "array" of hooks that get called in order.

Every vault would effectively just be a the Generalized Vault + a subsection of guardrails:

  1. depositGuardrails[ ]
  2. withdrawalGuardrails[ ]
  3. tradeGuardrails[ ]
  4. collateralGuardrails[ ]
  5. rfqGuardrails[ ]

Something like that might be much easier to build a "self-serve UX" for.

So the CoveredCallTSA would now just be:
GeneralizedTSA +

  1. depositGuardrails: [weekly deposit guardrail]
  2. withdrawGuadrails: [weekly withdraw guardrail]
  3. tradeGuardrails: [premium price guardrail, expiry guardrail]
  4. collateralGuardrails: [minimum collateral to cover short guardrail]
  5. rfqGuardrails: None


if (block.timestamp >= lastSnapshotTime + $.tsaParams.performanceFeeWindow) {
address feeRecipient = $.tsaParams.feeRecipient;
(uint perfFee, uint sharePrice) = _getPerfFee();
Copy link
Collaborator

Choose a reason for hiding this comment

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

nitpick: would remove uint sharePrice since it's not doing anything

}
}

function _collectWithdrawalPerfFee(uint sharesBurnt, uint withdrawAmount, uint perfFee, uint currentSharePrice)
Copy link
Collaborator

Choose a reason for hiding this comment

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

Because the _burn() and collection of perf fees happens non-atomically, I think there are two edge cases:

(1) the share price is calculated by doing totalSupply() / _accountValue(), but because requestWithdrawal() burns all withdraw shares, later the share price DURING the processWithdrawal() call will be higher than true value (esp. for big withdrawals).

This means big withdrawers would pay way higher perf fees and depositors that deposit during this dead space basically have high slippage.

(2) Can users avoid paying perf fees by timing their withdrawals? Let's say the vault has a weekly perf window and it just made 50%. As a user, I think I would:

  1. requestWithdraw like 1-30sec before the end of the window.
  2. Hopefully, the keeper doesn't process my withdrawal before window ends.
  3. window ends - I call collectFees(), which resets the $.lastShareValue
  4. By the time the share keeper gets to my withdrawal, the perfFee is 0% since storage values were reset.

@vladislavabramov
Copy link

vladislavabramov commented May 7, 2025

One random thought i had for the perf fee: might be nice to have a "baseline" performance number and have the fee be a % of (actualPerformance - baseline) x feePct

For example, the vault might expect a baseline expected growth of 5% APY, and perf fee should only be charged on w/e profits above 5%

This seems pretty common in tradfi: https://corporatefinanceinstitute.com/resources/career-map/sell-side/capital-markets/2-and-20-hedge-fund-fees/

The 2 and 20 is a hedge fund compensation structure consisting of a management fee and a performance fee. 2% represents a management fee which is applied to the total assets under management. A 20% performance fee is charged on the profits that the hedge fund generates, beyond a specified minimum threshold.

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.

4 participants