feat(STBLE-3855): Adding fine grained RBAC for solana contract - #20
Conversation
✅ Heimdall Review Status
|
0050951 to
57aab2e
Compare
Split pause/unpause/treasury/configure roles, add withdraw-recipient allowlist, and support one-shot migration from the legacy layout with Anchor and bankrun test coverage.
57aab2e to
f097b93
Compare
Restore CustomStable naming to shrink the RBAC PR diff; no behavioral change. Co-authored-by: Cursor <cursoragent@cursor.com>
Co-authored-by: Cursor <cursoragent@cursor.com>
sddioulde
left a comment
There was a problem hiding this comment.
mostly looks good to me. left some comments
Roles can only be rotated by their current holder, so a role assigned the default pubkey is unrecoverable. Reject it in initialize, in each rotation instruction, and in migrate_authorities. Give the migration's checks their own errors instead of reporting everything as LegacyDiscriminatorMismatch: wrong owner, wrong account size, and each legacy co-signer now fail distinctly, which also puts the previously unused LegacySizeMismatch to work. Document that the legacy operations authority funds the realloc, and derive the growth from the layout constants so the byte count cannot go stale.
denys-cb
left a comment
There was a problem hiding this comment.
Overall migration and testing is solid, left some comments, also worth reconciling with PPS a little bit, for example there is no whitelist anymore (mentioned in Configure Authority)
| // MUST stay named `LiquidityPool`. Renaming it would break re-deserialization of every | ||
| // existing pool on devnet/mainnet and break the migration's discriminator check. | ||
| #[account] | ||
| pub struct LiquidityPool { |
There was a problem hiding this comment.
Needs a documented runbook order - legacy pools stop deserializing under the new layout, so between upgrade and migrate everything taking Account fails, pause_swaps included.
There was a problem hiding this comment.
Will provide a runbook async.
| **/deploy/*.json | ||
| **/*-keypair.json | ||
| **/id.json | ||
| package-lock.json |
| Ok(()) | ||
| } | ||
|
|
||
| pub fn update_pause_authority( |
There was a problem hiding this comment.
Each role only rotates itself, so a compromised hot key can't be revoked, and a
typo'd rotation is equally unrecoverable. EVM survives both because the admin can
revoke via grantRole/revokeRole.
Do we need same or similar approach here?
For example, we can make configure_authority to rotate any role, with pending/accept on its
own rotation.
Or maybe separate admin role?
There was a problem hiding this comment.
Like to push back on this. As long as the cold key for upgrades isn't compromised we always have a way forwards to reset authorities, and that authority lives outside of the program. I'm not sure if we want to actually want to expose additional role setting logic anywhere at the moment.
90fd84c to
0f9d487
Compare
Description
Breaking Change: Replace the legacy two-authority pool model with a four-role model (pause / unpause / treasury / configure), add a withdraw-recipient allowlist, and ship a one-shot migrate_authorities path for existing pools—covered by expanded Anchor tests and a bankrun migration test.
On-chain (programs/stable-swapper)
migrate_authorities: realloc legacy layout (1719) → RBAC layout (2107); co-signed by legacy ops + pause; seeds allowlist; rejects double-migrate / zero keys / wrong owner
Tests
Migration was also verified via localnet and devnet scripts that can be found here in a separate branch.
General flow of verification:
Below are some artifacts produced via a singular run:
Type of Change
Checklist