Performance package withdrawal limits - #494
Open
metapileks wants to merge 15 commits into
Open
metapileks wants to merge 15 commits into
metapileks wants to merge 15 commits into
Conversation
Contributor
|
Repository Guard
Repository GuardCargo dependency pinning
Cross-program Anchor/Solana version consistency
solana-program crate pin
Anchor.toml solana_version
Crate minimum age
Yarn package.json pinning
npm minimum age
Workflow toolchain consistency
GitHub Action SHA pinning
Sensitive program / config changes
Overall status: pass Lockfile freshness (Cargo.lock + yarn.lock) is checked by the workflow directly and cannot be bypassed. The sensitive-diff section is a review hint - CODEOWNERS handles the actual merge gate. |
metapileks
marked this pull request as ready for review
September 15, 2026 20:55
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Unlocking and withdrawing are now separate steps.
complete_unlockonly marks tranches as unlocked; the recipient pulls what is unlocked either as tokens (withdraw_tokens) or by selling into the DAO's spot pool and receiving the USDC (withdraw_via_sell).A package may carry a withdrawal policy: a cap on tokens and a cap on quote value per fixed window, a mode saying which of the two routes are open, and an end date after which the caps fall away. Token withdrawals are valued at the higher of the pool's price observation and its reserve price; sells count what the pool actually paid. Limits are set at creation or through the existing two-party change flow, which gains an
UnlockTermschange that moves the cliff and replaces the limits in one step. Without an active policy both routes are open and uncapped.The performance package account grows from 520 to 582 bytes. A permissionless resize migrates live packages, and every instruction refuses an unmigrated package.
Instruction changes
resize_performance_packagewithdrawal_policy = None; the payer covers the extra rent.AccountNotMigrateduntil the package is resized.initialize_performance_package_with_limits{ base, limits }and stores a policy anchored at the creation clock. Caps must be non-zero, the end in the future and the window at least one second (InvalidWithdrawalLimits).complete_unlockwithdraw_tokensamountfrom the vault, bounded by vault minus still-locked (InsufficientWithdrawableBalance). Under an active policy the mode must allow tokens and the window's token and quote caps must fit, valued from theDaoat the oracle account.withdraw_via_sellamountfrom its vault into the DAO's spot pool through futarchy'sspot_swap, guarded bymin_quote_out, and forwards exactly the proceeds. Under an active policy the mode must allow sells, the token cap applies and the quote cap counts the proceeds.propose_change/execute_changeChangeType::UnlockTerms { min_unlock_timestamp, limits: Option<LimitsParams> }, allowed in any state. Propose validates the limits; execute sets the cliff and replaces the policy: same window length keeps the usage, a different one re-anchors the windows at now,Noneremoves it.burn_performance_packageInvalidQuoteMint); the ATA and destination come together (QuoteSweepAccountsIncomplete). New accounts: recipient, its ATA, the three optional quote accounts, system and associated token programs.State, events and errors
PerformancePackage.withdrawal_policy: Option<WithdrawalPolicy>appended, withlimits: WithdrawalLimits(start, end, window seconds, both caps, modeTokens | Sell | Both) andusage: WindowUsage(window index, tokens used, quote used).OldPerformancePackagedecodes the 520-byte layout for the resize.futarchywith thecpifeature.TokensWithdrawn(withcapped: Option<CappedWithdrawal>, the valuation price, quote value and usage when limits were active) andTokensSold(amount, proceeds,min_quote_out,capped: Option<WindowUsage>).InvalidWithdrawalLimits,InsufficientWithdrawableBalance,TokenWindowLimitExceeded,QuoteWindowLimitExceeded,InvalidPriceObservation,WithdrawTokensDisabled,WithdrawViaSellDisabled,AccountNotMigrated,InvalidQuoteMint,QuoteSweepAccountsIncomplete.SDK and scripts
price_based_performance_package/v0.6regenerated in place.completeUnlockIxtakes only the package and oracle; newinitializePerformancePackageWithLimitsIx,withdrawTokensIx,withdrawViaSellIx,resizePerformancePackageIx;burnPerformancePackageIxtakes the recipient and, optionally,quoteMintandquoteDestinationfor the sweep;proposeChangeIxis typed withProposeChangeParams.price_based_performance_package/v0.6/withdrawalLimits: active policy, current window and effective usage, withdrawable balance, valuation price, maximum token withdrawal and a sell proceeds estimate, all computed from fetched accounts.resizePerformancePackages.ts(modelled onresizeDaos.ts), aproposePerformancePackageUnlockTermsDAO action with the Rip Cars admin enqueuerip-cars/proposeUnlockTerms.ts,executeChange.tsfor the recipient, and the burn script passing the new accounts.Greptile Summary
This PR separates tranche unlocking from withdrawal, adds capped token and sell-based withdrawal routes, migrates existing package accounts to the expanded state layout, and updates retirement, change-management, SDK, scripts, and tests accordingly.
Confidence Score: 5/5
The PR appears safe to merge; the previously reported SDK argument issue is fixed and no actionable new defect remains.
The earlier migration finding was correctly conceded and its thread is resolved. The quote-sweep builder now accepts a single typed pair, fully addressing the other previous finding. The changes since the prior review introduce no new blocking or non-blocking findings.
Important Files Changed
Reviews (2): Last reviewed commit: "burn pp - move quote sweep into a single..." | Re-trigger Greptile
Context used: