-
Notifications
You must be signed in to change notification settings - Fork 0
FLOW-10 - Validate betaRef parameter in createYieldVaultManager #146
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
Open
liobrasil
wants to merge
6
commits into
main
Choose a base branch
from
fix/FLOW-10-unused-betaref
base: main
Could not load branches
Branch not found: {{ refName }}
Loading
Could not load tags
Nothing to show
Loading
Are you sure you want to change the base?
Some commits from the old base branch may be removed from the timeline,
and old review comments may become outdated.
+221
−27
Open
Changes from all commits
Commits
Show all changes
6 commits
Select commit
Hold shift + click to select a range
488fe2c
Fix: Validate betaRef parameter in createYieldVaultManager
liobrasil aedf6e9
test: ensure createYieldVaultManager validates betaRef
liobrasil 4e50b3a
chore: refactor BetaBadge to use direct field access instead of getOw…
liobrasil 0e86777
fix: address m-Peter beta validation feedback
liobrasil 2ceced7
Merge branch 'main' into fix/FLOW-10-unused-betaref
liobrasil e092882
Merge branch 'main' into fix/FLOW-10-unused-betaref
vishalchangrani File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
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
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
137 changes: 137 additions & 0 deletions
137
cadence/contracts/mocks/FlowYieldVaultsClosedBeta_validate_beta_false.cdc
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
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,137 @@ | ||
| // TEST-ONLY MOCK CONTRACT. | ||
| // | ||
| // Some unit tests need a *well-typed* beta reference | ||
| // (`auth(FlowYieldVaultsClosedBeta.Beta) & FlowYieldVaultsClosedBeta.BetaBadge`) | ||
| // that fails validation, to prove that a call-site actually invokes | ||
| // `FlowYieldVaultsClosedBeta.validateBeta(...)`. | ||
| // | ||
| // In Cadence, resources like `BetaBadge` can only be created by the contract that | ||
| // declares them, which makes it difficult to "forge" an invalid badge/reference | ||
| // in a transaction. | ||
| // | ||
| // To keep tests deterministic, this file redeploys the `FlowYieldVaultsClosedBeta` | ||
| // contract with `validateBeta` hardcoded to return `false` for all inputs. The | ||
| // rest of the contract is kept aligned with `cadence/contracts/FlowYieldVaultsClosedBeta.cdc`. | ||
| // | ||
| // DO NOT deploy this mock to any network. | ||
| access(all) contract FlowYieldVaultsClosedBeta { | ||
|
|
||
| access(all) entitlement Admin | ||
| access(all) entitlement Beta | ||
|
|
||
| access(all) resource BetaBadge { | ||
| access(all) let assignedTo: Address | ||
| init(assignedTo: Address) { | ||
| self.assignedTo = assignedTo | ||
| } | ||
| } | ||
|
|
||
| // --- Paths --- | ||
| access(all) let UserBetaCapStoragePath: StoragePath | ||
| access(all) let AdminHandleStoragePath: StoragePath | ||
|
|
||
| // --- Registry: which capability was issued to which address, and revocation flags --- | ||
| access(all) struct AccessInfo { | ||
| access(all) let capID: UInt64 | ||
| access(all) let isRevoked: Bool | ||
|
|
||
| init(capID: UInt64, isRevoked: Bool) { | ||
| self.capID = capID | ||
| self.isRevoked = isRevoked | ||
| } | ||
| } | ||
| access(all) var issuedCapIDs: {Address: AccessInfo} | ||
|
|
||
| // --- Events --- | ||
| access(all) event BetaGranted(addr: Address, capID: UInt64) | ||
| access(all) event BetaRevoked(addr: Address, capID: UInt64?) | ||
|
|
||
| /// Per-user badge storage path (under the *contract/deployer* account) | ||
| access(contract) fun _badgePath(_ addr: Address): StoragePath { | ||
| return StoragePath(identifier: "FlowYieldVaultsBetaBadge_\(addr)")! | ||
| } | ||
|
|
||
| /// Ensure the admin-owned badge exists for the user | ||
| access(contract) fun _ensureBadge(_ addr: Address) { | ||
| let path = self._badgePath(addr) | ||
| if self.account.storage.type(at: path) == nil { | ||
| self.account.storage.save(<-create BetaBadge(assignedTo: addr), to: path) | ||
| } | ||
| } | ||
|
|
||
| access(contract) fun _destroyBadge(_ addr: Address) { | ||
| let path = self._badgePath(addr) | ||
| if let badge <- self.account.storage.load<@BetaBadge>(from: path) { | ||
| destroy badge | ||
| } | ||
| } | ||
|
|
||
| /// Issue a capability from the contract/deployer account and record its ID | ||
| access(contract) fun _issueBadgeCap(_ addr: Address): Capability<auth(Beta) &BetaBadge> { | ||
| let path = self._badgePath(addr) | ||
| let cap = self.account.capabilities.storage.issue<auth(Beta) &BetaBadge>(path) | ||
|
|
||
| self.issuedCapIDs[addr] = AccessInfo(capID: cap.id, isRevoked: false) | ||
|
|
||
| if let ctrl = self.account.capabilities.storage.getController(byCapabilityID: cap.id) { | ||
| ctrl.setTag("flowyieldvaults-beta") | ||
| } | ||
|
|
||
| emit BetaGranted(addr: addr, capID: cap.id) | ||
| return cap | ||
| } | ||
|
|
||
| /// Delete the recorded controller, revoking *all copies* of the capability | ||
| access(contract) fun _revokeByAddress(_ addr: Address) { | ||
| let info = self.issuedCapIDs[addr] ?? panic("No cap recorded for address") | ||
| let ctrl = self.account.capabilities.storage.getController(byCapabilityID: info.capID) | ||
| ?? panic("Missing controller for recorded cap ID") | ||
| ctrl.delete() | ||
| self.issuedCapIDs[addr] = AccessInfo(capID: info.capID, isRevoked: true) | ||
| self._destroyBadge(addr) | ||
| emit BetaRevoked(addr: addr, capID: info.capID) | ||
| } | ||
|
|
||
| // 2) A small in-account helper resource that performs privileged ops | ||
| access(all) resource AdminHandle { | ||
| access(Admin) fun grantBeta(addr: Address): Capability<auth(FlowYieldVaultsClosedBeta.Beta) &FlowYieldVaultsClosedBeta.BetaBadge> { | ||
| FlowYieldVaultsClosedBeta._ensureBadge(addr) | ||
| return FlowYieldVaultsClosedBeta._issueBadgeCap(addr) | ||
| } | ||
|
|
||
| access(Admin) fun revokeByAddress(addr: Address) { | ||
| FlowYieldVaultsClosedBeta._revokeByAddress(addr) | ||
| } | ||
| } | ||
|
|
||
| /// Read-only check used by any gated entrypoint | ||
| access(all) view fun getBetaCapID(_ addr: Address): UInt64? { | ||
| if let info = self.issuedCapIDs[addr] { | ||
| if info.isRevoked { | ||
| return nil | ||
| } | ||
| return info.capID | ||
| } | ||
| return nil | ||
| } | ||
|
|
||
| // TEST-ONLY: Always invalid, regardless of address or reference. | ||
| // Used to ensure beta-gated entrypoints actually call `validateBeta`. | ||
| access(all) view fun validateBeta(_ addr: Address?, _ betaRef: auth(Beta) &BetaBadge): Bool { | ||
| return false | ||
| } | ||
|
|
||
| init() { | ||
| self.AdminHandleStoragePath = StoragePath( | ||
| identifier: "FlowYieldVaultsClosedBetaAdmin_\(self.account.address)" | ||
| )! | ||
| self.UserBetaCapStoragePath = StoragePath( | ||
| identifier: "FlowYieldVaultsUserBetaCap_\(self.account.address)" | ||
| )! | ||
|
|
||
| self.issuedCapIDs = {} | ||
|
|
||
| // Create and store the admin handle in *this* (deployer) account | ||
| self.account.storage.save(<-create AdminHandle(), to: self.AdminHandleStoragePath) | ||
| } | ||
| } |
41 changes: 41 additions & 0 deletions
41
cadence/tests/create_yield_vault_manager_validation_test.cdc
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
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,41 @@ | ||
| import Test | ||
|
|
||
| import "test_helpers.cdc" | ||
|
|
||
| access(all) let flowYieldVaultsAccount = Test.getAccount(0x0000000000000009) | ||
|
|
||
| access(all) | ||
| fun setup() { | ||
| deployContracts() | ||
| } | ||
|
|
||
| access(all) | ||
| fun test_CreateYieldVaultManagerValidatesBetaRef() { | ||
| // Swap in a test-only FlowYieldVaultsClosedBeta implementation where `validateBeta` always returns false. | ||
| // This lets us assert that `FlowYieldVaults.createYieldVaultManager` actually calls `validateBeta`. | ||
| let err = Test.deployContract( | ||
| name: "FlowYieldVaultsClosedBeta", | ||
| path: "../contracts/mocks/FlowYieldVaultsClosedBeta_validate_beta_false.cdc", | ||
| arguments: [] | ||
| ) | ||
| Test.expect(err, Test.beNil()) | ||
|
|
||
| let user = Test.createAccount() | ||
| transferFlow(signer: serviceAccount, recipient: user.address, amount: 1.0) | ||
| grantBeta(flowYieldVaultsAccount, user) | ||
|
|
||
| let txn = Test.Transaction( | ||
| code: Test.readFile("../transactions/test/create_yield_vault_manager_with_beta_cap.cdc"), | ||
| authorizers: [user.address], | ||
| signers: [user], | ||
| arguments: [] | ||
| ) | ||
| let res = Test.executeTransaction(txn) | ||
| Test.expect(res, Test.beFailed()) | ||
| Test.assert(res.error != nil, message: "Expected transaction to fail with an error") | ||
| let errorMessage = res.error!.message | ||
| Test.assert( | ||
| errorMessage.contains("Invalid Beta Ref"), | ||
| message: "Unexpected error message: ".concat(errorMessage) | ||
| ) | ||
| } | ||
23 changes: 23 additions & 0 deletions
23
cadence/transactions/test/create_yield_vault_manager_with_beta_cap.cdc
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
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,23 @@ | ||
| import "FlowYieldVaults" | ||
| import "FlowYieldVaultsClosedBeta" | ||
|
|
||
| /// Creates (and destroys) a YieldVaultManager using the caller's stored beta capability. | ||
| transaction { | ||
| let betaRef: auth(FlowYieldVaultsClosedBeta.Beta) &FlowYieldVaultsClosedBeta.BetaBadge | ||
|
|
||
| prepare(signer: auth(BorrowValue, CopyValue) &Account) { | ||
| let betaCap = signer.storage.copy< | ||
| Capability<auth(FlowYieldVaultsClosedBeta.Beta) &FlowYieldVaultsClosedBeta.BetaBadge> | ||
| >(from: FlowYieldVaultsClosedBeta.UserBetaCapStoragePath) | ||
| ?? panic("Missing Beta capability at \(FlowYieldVaultsClosedBeta.UserBetaCapStoragePath)") | ||
|
|
||
| self.betaRef = betaCap.borrow() | ||
| ?? panic("Beta capability does not contain correct reference") | ||
| } | ||
|
|
||
| execute { | ||
| let manager <- FlowYieldVaults.createYieldVaultManager(betaRef: self.betaRef) | ||
| destroy manager | ||
| } | ||
| } | ||
|
|
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.
Uh oh!
There was an error while loading. Please reload this page.