Skip to content

Add personal staking helpers with GOV claim-and-stake - #1

Open
cryptoharry wants to merge 8 commits into
mainfrom
feat/personal-staking-helper
Open

cryptoharry wants to merge 8 commits into
mainfrom
feat/personal-staking-helper

Conversation

@cryptoharry

@cryptoharry cryptoharry commented Oct 26, 2026 •

Copy link
Copy Markdown
Collaborator

Users can enter existing Monolith GOV rewards pools with Coin, existing sCoin, or Coin acquired through an ERC20 swap. One personal helper per owner and DAO composes the existing vault and pool accounting, without a shared user ledger or parent-protocol changes.

  • depositAndStake() deposits Coin into the vault for sCoin pools, or stakes Coin directly for Coin pools.
  • stake() accepts existing sCoin without redeeming it, or Coin for direct-Coin pools. Both plain entry routes have receiver overloads: the caller funds the position and the receiver owns it.
  • zapAndStake() approves a router for the supplied input amount, executes its calldata in the caller's helper, clears the input approval, and deposits and stakes the full Coin balance. minCoinOut bounds fresh Coin received; minShares bounds the resulting stake. predictHelper() provides a stable first-use swap caller/recipient.

Zaps now require an admin-approved router. The factory rejects unlisted targets before helper creation or token transfers, preventing direct token-approval and pool-withdrawal payloads. The helper and its permissions are unchanged.

Deploy with PersonalStakingHelperFactory(coinDAOFactory, routerAdmin). The router list starts empty; the explicit admin manages it through setRouter(router, allowed), with a public getter and event. This reuses the existing OpenZeppelin Ownable dependency. Router changes need no new factory or helpers, and disabling routers leaves plain entries, claims and withdrawals available.

The admin must approve vetted swap routers. Listing tokens, pools or helpers can reopen arbitrary-call access; removal does not revoke approvals left by earlier calls. Standard factory ownership transfer/renunciation changes router administration, while helper owners and markets remain fixed. Receiver addresses must be wallets or authenticated contracts able to operate the helper, not helper/predicted-helper addresses.

Owner-only claims, optional GOV claiming on withdrawal, and GOV claimAndStake() remain available. The zap supports ERC20 routers that are also the allowance spender; unexpected non-Coin input remains owner-recoverable.

Validation: all 186 tests pass locally: 93 helper tests, nine real Monolith/CoinDAOFactory integration scenarios, and 84 governance regressions. Coverage includes malicious unlisted targets, router callback identity, admin permissions, router removal/re-enabling, full-balance staking, output bounds and owner isolation. The integration zap verifies rewards and withdrawal after router removal. Fuzz tests run 512 cases each; stateful invariants mix entry routes, withdrawals and claims across owners and DAOs.

CI repeats these suites. External collateral, its feed and the swap router are simulated; no live aggregator quote or deployment is claimed.

This supersedes GovernanceFactory #12; earlier discussion remains in Monolith #60. The README covers deployment, integration and testing.

@cryptoharry cryptoharry changed the title Add personal deposit-and-stake helpers for CoinDAOs Add personal staking helpers with GOV claim-and-stake Oct 26, 2026
}

/// @notice Stakes exactly the pool tokens just supplied by the factory.
function stake(uint256 shares) external onlyFactory nonReentrant {

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Is there any reason to have this be onlyFactory? If there's some reason in the future where we might want a contract to stake on behalf of users, it'd be useful to have this be open for anyone to call.

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

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

I’d keep this restriction, as stake() uses tokens already held by the helper. Opening it would let anyone stake the owner’s loose tokens. The factory receiver option below would cover third-party deposits.


/// @notice Stakes Token directly, or deposits and stakes sToken, as configured by the DAO.
/// @dev Existing/donated balances are excluded. There is no shared accounting.
function depositAndStake(uint256 assets, uint256 minShares)

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

May be worth having an additional overload of this function that looks like depositAndStake(uint256 assets, uint256 minShares, address receiver) to let contracts and users deposit on behalf of others. Similar for the other functions.

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

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

Each helper belongs to one fixed owner, so I think receiver selection belongs in the factory. I’d keep the helper interface as it is.

Comment thread src/PersonalStakingHelperFactory.sol Resolved
@cryptoharry
cryptoharry requested a review from 08xmt October 29, 2026 11:52
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.

2 participants