diff --git a/cadence/tests/cap_test.cdc b/cadence/tests/cap_test.cdc index 0cf9491f..d58c2a54 100644 --- a/cadence/tests/cap_test.cdc +++ b/cadence/tests/cap_test.cdc @@ -22,15 +22,6 @@ import "test_helpers.cdc" // Published via the FIXED publish_beta_cap.cdc. // Cap stored at FlowALPv0.PoolCapStoragePath. // -// ePositionUser — Capability -// EPosition-only capability; can perform pool-level position -// ops on any position by ID. No EParticipant. -// Cap stored at FlowALPv0.PoolCapStoragePath. -// -// eParticipantPositionUser — Capability over-grant -// Current (unfixed) beta cap — grants EPosition unnecessarily. -// Cap stored at FlowALPv0.PoolCapStoragePath. -// // eRebalanceUser — Capability // Narrowly-scoped cap for rebalancer contracts. // Cap stored at FlowALPv0.PoolCapStoragePath. @@ -52,7 +43,7 @@ import "test_helpers.cdc" // ============================================================================= -// Position created for PROTOCOL_ACCOUNT in setup — used as target for EPosition tests. +// Position created for PROTOCOL_ACCOUNT in setup — used as target for ERebalance tests. access(all) var setupPid: UInt64 = 0 access(all) var ePositionAdminPid: UInt64 = 0 @@ -61,8 +52,6 @@ access(all) var snapshot: UInt64 = 0 // Role accounts access(all) var userWithoutCap = Test.createAccount() access(all) var eParticipantUser = Test.createAccount() -access(all) var ePositionUser = Test.createAccount() -access(all) var eParticipantPositionUser = Test.createAccount() access(all) var eRebalanceUser = Test.createAccount() access(all) var ePositionAdminUser = Test.createAccount() access(all) var eGovernanceUser = Test.createAccount() @@ -71,7 +60,7 @@ access(all) var eGovernanceUser = Test.createAccount() /// Used in negative tests to verify governance methods are inaccessible to them. access(all) fun getNonGovernanceUsers(): [Test.TestAccount] { - return [eParticipantUser, ePositionUser, eParticipantPositionUser, eRebalanceUser, ePositionAdminUser] + return [eParticipantUser, eRebalanceUser, ePositionAdminUser] } access(all) @@ -150,28 +139,6 @@ fun setup() { Test.beSucceeded() ) - // ───────────────────────────────────────────────────────────────────────── - // EPosition user — EPosition-ONLY capability (no EParticipant) - // ───────────────────────────────────────────────────────────────────────── - setupMoetVault(ePositionUser, beFailed: false) - mintMoet(signer: PROTOCOL_ACCOUNT, to: ePositionUser.address, amount: 100.0, beFailed: false) - Test.expect( - _execute2Signers( - "../tests/transactions/flow-alp/setup/grant_eposition_cap.cdc", - [], - PROTOCOL_ACCOUNT, - ePositionUser - ), - Test.beSucceeded() - ) - - // ───────────────────────────────────────────────────────────────────────── - // EParticipantPosition user — EParticipant+EPosition capability (current over-grant) - // ───────────────────────────────────────────────────────────────────────── - setupMoetVault(eParticipantPositionUser, beFailed: false) - mintMoet(signer: PROTOCOL_ACCOUNT, to: eParticipantPositionUser.address, amount: 100.0, beFailed: false) - grantBetaPoolParticipantAccess(PROTOCOL_ACCOUNT, eParticipantPositionUser) - // ───────────────────────────────────────────────────────────────────────── // ERebalance user — ERebalance-only capability (rebalancer simulation) // ───────────────────────────────────────────────────────────────────────── @@ -277,222 +244,6 @@ fun testEParticipant_CreateAndDeposit() { Test.assertEqual(6.0, creditBalance) } -// ============================================================================= -// EParticipant+EPosition — over-grant (current beta cap via publish_beta_cap.cdc) -// ============================================================================= -// -// Actor: eParticipantPositionUser — Capability -// Issued by publish_beta_cap.cdc and stored at FlowALPv0.PoolCapStoragePath. -// This is the CURRENT (unfixed) beta cap. EPosition is NOT needed for normal -// user actions; its presence lets this actor perform pool-level position ops -// on ANY position, including positions owned by other accounts. -// -// Matrix rows: createPosition (EParticipant), depositToPosition (EParticipant), -// withdraw [OVERGRANT], withdrawAndPull [OVERGRANT], depositAndPush [OVERGRANT], -// lockPosition [OVERGRANT], unlockPosition [OVERGRANT], rebalancePosition [OVERGRANT], -// rebalance (Position) [OVERGRANT — same entry point as rebalancePosition] -// -// The [OVERGRANT] rows confirm the security issue: a normal beta user can operate on -// positions they do not own (setupPid is owned by PROTOCOL_ACCOUNT). - -/// Over-granted beta cap still allows EParticipant operations (createPosition, depositToPosition). -access(all) -fun testEParticipantPosition_CreateAndDeposit() { - safeReset() - - let result = _executeTransaction( - "../tests/transactions/flow-alp/eparticipant/create_and_deposit_via_cap.cdc", - [], - eParticipantPositionUser - ) - Test.expect(result, Test.beSucceeded()) - - // Verify position was created and funded: create_and_deposit_via_cap.cdc deposits - // 5.0 MOET (createPosition) + 1.0 MOET (depositToPosition) = 6.0 MOET credit. - let newPid = getLastPositionId() - let creditBalance = getCreditBalanceForType( - details: getPositionDetails(pid: newPid, beFailed: false), - vaultType: Type<@MOET.Vault>() - ) - Test.assertEqual(6.0, creditBalance) -} - -/// Over-granted beta cap allows Pool.withdraw on ANY position — including -/// setupPid owned by PROTOCOL_ACCOUNT. -access(all) -fun testEParticipantPosition_WithdrawAnyPosition() { - safeReset() - - let balanceBefore = getBalance(address: eParticipantPositionUser.address, vaultPublicPath: MOET.VaultPublicPath)! - let result = _executeTransaction( - "../tests/transactions/flow-alp/eposition/withdraw_any.cdc", - [setupPid, 1.0], - eParticipantPositionUser - ) - Test.expect(result, Test.beSucceeded()) - let balanceAfter = getBalance(address: eParticipantPositionUser.address, vaultPublicPath: MOET.VaultPublicPath)! - Test.assertEqual(balanceAfter, balanceBefore + 1.0) -} - -/// Over-granted beta cap allows Pool.withdrawAndPull on ANY position — including -/// positions owned by other accounts. -access(all) -fun testEParticipantPosition_WithdrawAndPullAnyPosition() { - safeReset() - - let balanceBefore = getBalance(address: eParticipantPositionUser.address, vaultPublicPath: MOET.VaultPublicPath)! - let result = _executeTransaction( - "../tests/transactions/flow-alp/eposition/withdraw_and_pull_any.cdc", - [setupPid, 1.0], - eParticipantPositionUser - ) - Test.expect(result, Test.beSucceeded()) - let balanceAfter = getBalance(address: eParticipantPositionUser.address, vaultPublicPath: MOET.VaultPublicPath)! - Test.assertEqual(balanceAfter, balanceBefore + 1.0) -} - -/// Over-granted beta cap allows Pool.depositAndPush on ANY position — including -/// positions owned by other accounts. -access(all) -fun testEParticipantPosition_DepositAndPushAnyPosition() { - safeReset() - - let creditBefore = getCreditBalanceForType( - details: getPositionDetails(pid: setupPid, beFailed: false), - vaultType: Type<@MOET.Vault>() - ) - let result = _executeTransaction( - "../tests/transactions/flow-alp/eposition/deposit_and_push_any.cdc", - [setupPid, 1.0], - eParticipantPositionUser - ) - Test.expect(result, Test.beSucceeded()) - let creditAfter = getCreditBalanceForType( - details: getPositionDetails(pid: setupPid, beFailed: false), - vaultType: Type<@MOET.Vault>() - ) - Test.assertEqual(creditBefore + 1.0, creditAfter) -} - -/// Over-granted beta cap allows Pool.lockPosition and Pool.unlockPosition on ANY position — -/// including positions owned by other accounts. -access(all) -fun testEParticipantPosition_LockUnlockAnyPosition() { - safeReset() - - let result = _executeTransaction( - "../tests/transactions/flow-alp/eposition/lock_any.cdc", - [setupPid], - eParticipantPositionUser - ) - Test.expect(result, Test.beSucceeded()) -} - -/// Over-granted beta cap allows Pool.rebalancePosition on any position. -access(all) -fun testEParticipantPosition_RebalancePosition() { - safeReset() - - let result = _executeTransaction( - "../tests/transactions/flow-alp/eposition/rebalance_position_via_cap.cdc", - [setupPid, true], - eParticipantPositionUser - ) - Test.expect(result, Test.beSucceeded()) -} - -// ============================================================================= -// EPosition — narrowly-scoped EPosition-only Pool capability -// ============================================================================= -// -// Actor: ePositionUser — Capability -// Matrix rows: withdraw, withdrawAndPull, depositAndPush, lockPosition, unlockPosition, -// rebalancePosition - -/// EPosition cap allows Pool.withdraw on ANY position by ID — including -/// setupPid owned by PROTOCOL_ACCOUNT. -access(all) -fun testEPosition_WithdrawAnyPosition() { - safeReset() - - let balanceBefore = getBalance(address: ePositionUser.address, vaultPublicPath: MOET.VaultPublicPath)! - let result = _executeTransaction( - "../tests/transactions/flow-alp/eposition/withdraw_any.cdc", - [setupPid, 1.0], - ePositionUser - ) - Test.expect(result, Test.beSucceeded()) - let balanceAfter = getBalance(address: ePositionUser.address, vaultPublicPath: MOET.VaultPublicPath)! - Test.assertEqual(balanceAfter, balanceBefore + 1.0) -} - -/// EPosition cap allows Pool.withdrawAndPull on ANY position — including positions -/// owned by other accounts. -access(all) -fun testEPosition_WithdrawAndPullAnyPosition() { - safeReset() - - let balanceBefore = getBalance(address: ePositionUser.address, vaultPublicPath: MOET.VaultPublicPath)! - let result = _executeTransaction( - "../tests/transactions/flow-alp/eposition/withdraw_and_pull_any.cdc", - [setupPid, 1.0], - ePositionUser - ) - Test.expect(result, Test.beSucceeded()) - let balanceAfter = getBalance(address: ePositionUser.address, vaultPublicPath: MOET.VaultPublicPath)! - Test.assertEqual(balanceAfter, balanceBefore + 1.0) -} - -/// EPosition cap allows Pool.depositAndPush on ANY position — including positions -/// owned by other accounts. -access(all) -fun testEPosition_DepositAndPushAnyPosition() { - safeReset() - - let creditBefore = getCreditBalanceForType( - details: getPositionDetails(pid: setupPid, beFailed: false), - vaultType: Type<@MOET.Vault>() - ) - let result = _executeTransaction( - "../tests/transactions/flow-alp/eposition/deposit_and_push_any.cdc", - [setupPid, 1.0], - ePositionUser - ) - Test.expect(result, Test.beSucceeded()) - let creditAfter = getCreditBalanceForType( - details: getPositionDetails(pid: setupPid, beFailed: false), - vaultType: Type<@MOET.Vault>() - ) - Test.assertEqual(creditBefore + 1.0, creditAfter) -} - -/// EPosition cap allows Pool.lockPosition and Pool.unlockPosition on ANY position — -/// including positions owned by other accounts. -access(all) -fun testEPosition_LockUnlockAnyPosition() { - safeReset() - - let result = _executeTransaction( - "../tests/transactions/flow-alp/eposition/lock_any.cdc", - [setupPid], - ePositionUser - ) - Test.expect(result, Test.beSucceeded()) -} - -/// EPosition cap allows Pool.rebalancePosition. -access(all) -fun testEPosition_RebalancePosition() { - safeReset() - - let result = _executeTransaction( - "../tests/transactions/flow-alp/eposition/rebalance_position_via_cap.cdc", - [setupPid, true], - ePositionUser - ) - Test.expect(result, Test.beSucceeded()) -} - // ============================================================================= // ERebalance — narrowly-scoped rebalancer capability // ============================================================================= diff --git a/cadence/tests/contracts/AdversarialReentrancyConnectors.cdc b/cadence/tests/contracts/AdversarialReentrancyConnectors.cdc index 4eda4bd1..054761b5 100644 --- a/cadence/tests/contracts/AdversarialReentrancyConnectors.cdc +++ b/cadence/tests/contracts/AdversarialReentrancyConnectors.cdc @@ -4,6 +4,7 @@ import "FungibleTokenMetadataViews" import "DeFiActionsUtils" import "DeFiActions" import "FlowALPv0" +import "FlowALPPositionResources" import "FlowALPModels" import "MOET" @@ -107,17 +108,18 @@ access(all) contract AdversarialReentrancyConnectors { } access(all) resource LiveData { - /// Optional: Pool capability for recursive withdrawAndPull call - access(all) var recursivePool: Capability? - /// Optional: Position ID for recursive withdrawAndPull call + /// Capability to the attacker's PositionManager for recursive withdrawal + access(all) var positionManagerCap: Capability? + /// Position ID for recursive withdrawal access(all) var recursivePositionID: UInt64? - init() { self.recursivePositionID = nil; self.recursivePool = nil } - access(all) fun setRecursivePool(_ pool: Capability) { - self.recursivePool = pool - } - access(all) fun setRecursivePositionID(_ positionID: UInt64) { - self.recursivePositionID = positionID + init() { self.recursivePositionID = nil; self.positionManagerCap = nil } + access(all) fun setRecursivePosition( + managerCap: Capability, + pid: UInt64 + ) { + self.positionManagerCap = managerCap + self.recursivePositionID = pid } } access(all) fun createLiveData(): @LiveData { @@ -203,27 +205,18 @@ access(all) contract AdversarialReentrancyConnectors { access(FungibleToken.Withdraw) fun withdrawAvailable(maxAmount: UFix64): @{FungibleToken.Vault} { // If recursive withdrawAndPull is configured, call it first log("VaultSource.withdrawAvailable called with maxAmount: \(maxAmount)") - log("=====Recursive pool: \(self.liveDataCap.check())") + log("=====Recursive position manager: \(self.liveDataCap.check())") let liveData = self.liveDataCap.borrow() ?? panic("cant borrow LiveData") - let poolRef = liveData.recursivePool!.borrow() ?? panic("cant borrow Recursive pool is nil") - // Call withdrawAndPull on the position - let recursiveVault <- poolRef.withdrawAndPull( - pid: liveData.recursivePositionID!, - // type: Type<@MOET.Vault>(), + let manager = liveData.positionManagerCap!.borrow() ?? panic("cant borrow PositionManager") + let position = manager.borrowAuthorizedPosition(pid: liveData.recursivePositionID!) + // Attempt reentrant withdrawal via Position (should fail due to position lock) + let recursiveVault <- position.withdraw( type: Type<@FlowToken.Vault>(), - // type: tokenType, - amount: 900.0, - pullFromTopUpSource: false + amount: 900.0 ) - log("Recursive withdrawAndPull returned vault with balance: \(recursiveVault.balance)") - // If we got funds from the recursive call, return them - if recursiveVault.balance > 0.0 { - return <-recursiveVault - } - // Otherwise, destroy the empty vault and continue with normal withdrawal + log("Recursive withdraw succeeded with balance: \(recursiveVault.balance) (should not reach here)") destroy recursiveVault - // Normal vault withdrawal let available = self.minimumAvailable() if !self.withdrawVault.check() || available == 0.0 || maxAmount == 0.0 { diff --git a/cadence/tests/paid_auto_balance_test.cdc b/cadence/tests/paid_auto_balance_test.cdc index 50a92369..7873f9c5 100644 --- a/cadence/tests/paid_auto_balance_test.cdc +++ b/cadence/tests/paid_auto_balance_test.cdc @@ -316,6 +316,15 @@ access(all) fun test_supervisor_executed() { /// fixReschedule(uuid:) force-unwrapped borrowRebalancer(uuid)! which panicked on a stale UUID, /// reverting the whole executeTransaction and blocking recovery for all other rebalancers. access(all) fun test_supervisor_stale_uuid_does_not_panic() { + // Let the initial cron tick fire first (supervisor set is empty, so it does nothing + // except emit Executed). This avoids a race where the cron fires during the add/delete + // transactions below before the stale state is set up. + Test.moveTime(by: 100.0) + Test.commitBlock() + + let initialExecutedEvts = Test.eventsOfType(Type()) + Test.assert(initialExecutedEvts.length >= 1, message: "Initial cron tick should have fired") + // Get the UUID of the paid rebalancer created during setup. let createdEvts = Test.eventsOfType(Type()) Test.assertEqual(1, createdEvts.length) @@ -328,14 +337,14 @@ access(all) fun test_supervisor_stale_uuid_does_not_panic() { // stale UUID in the Supervisor's paidRebalancers set, simulating the FLO-27 bug scenario. deletePaidRebalancer(signer: userAccount, paidRebalancerStoragePath: paidRebalancerStoragePath) - // Advance time to trigger the Supervisor's scheduled tick. + // Advance time to trigger the next Supervisor tick. Test.moveTime(by: 60.0 * 60.0) Test.commitBlock() // The Supervisor must have executed without panicking. If fixReschedule force-unwrapped // the missing rebalancer the entire transaction would revert and Executed would not be emitted. let executedEvts = Test.eventsOfType(Type()) - Test.assert(executedEvts.length >= 1, message: "Supervisor should have executed at least 1 time") + Test.assert(executedEvts.length >= 2, message: "Supervisor should have executed at least 2 times (initial + stale prune)") // The stale UUID must have been pruned from the Supervisor's set. let removedEvts = Test.eventsOfType(Type()) diff --git a/cadence/tests/transactions/flow-alp/eposition/deposit_and_push_any.cdc b/cadence/tests/transactions/flow-alp/eposition/deposit_and_push_any.cdc deleted file mode 100644 index 3855b7fc..00000000 --- a/cadence/tests/transactions/flow-alp/eposition/deposit_and_push_any.cdc +++ /dev/null @@ -1,28 +0,0 @@ -import "FungibleToken" -import "FlowALPv0" -import "FlowALPModels" -import "MOET" - -/// Deposits MOET into any position via an EPosition capability at PoolCapStoragePath. -/// EPosition allows operations on any position by ID, regardless of ownership. -/// -/// @param pid: Target position ID (owned by a different account) -/// @param amount: Amount of MOET to deposit -transaction(pid: UInt64, amount: UFix64) { - let pool: auth(FlowALPModels.EPosition) &FlowALPv0.Pool - let funds: @{FungibleToken.Vault} - - prepare(signer: auth(BorrowValue) &Account) { - let cap = signer.storage.borrow<&Capability>( - from: FlowALPv0.PoolCapStoragePath - ) ?? panic("EPosition capability not found") - self.pool = cap.borrow() ?? panic("Could not borrow Pool with EPosition") - let vault = signer.storage.borrow(from: MOET.VaultStoragePath) - ?? panic("Could not borrow MOET vault with Withdraw entitlement") - self.funds <- vault.withdraw(amount: amount) - } - - execute { - self.pool.depositAndPush(pid: pid, from: <-self.funds, pushToDrawDownSink: false) - } -} diff --git a/cadence/tests/transactions/flow-alp/eposition/lock_any.cdc b/cadence/tests/transactions/flow-alp/eposition/lock_any.cdc deleted file mode 100644 index a6884a2e..00000000 --- a/cadence/tests/transactions/flow-alp/eposition/lock_any.cdc +++ /dev/null @@ -1,22 +0,0 @@ -import "FlowALPv0" -import "FlowALPModels" - -/// Locks then unlocks any position via an EPosition capability at PoolCapStoragePath. -/// EPosition allows operations on any position by ID, regardless of ownership. -/// -/// @param pid: Target position ID (may belong to a different account) -transaction(pid: UInt64) { - let pool: auth(FlowALPModels.EPosition) &FlowALPv0.Pool - - prepare(signer: auth(BorrowValue) &Account) { - let cap = signer.storage.borrow<&Capability>( - from: FlowALPv0.PoolCapStoragePath - ) ?? panic("EPosition capability not found") - self.pool = cap.borrow() ?? panic("Could not borrow Pool with EPosition") - } - - execute { - self.pool.lockPosition(pid) - self.pool.unlockPosition(pid) - } -} diff --git a/cadence/tests/transactions/flow-alp/eposition/rebalance_position_via_cap.cdc b/cadence/tests/transactions/flow-alp/eposition/rebalance_position_via_cap.cdc deleted file mode 100644 index 337aec42..00000000 --- a/cadence/tests/transactions/flow-alp/eposition/rebalance_position_via_cap.cdc +++ /dev/null @@ -1,23 +0,0 @@ -import "FlowALPv0" -import "FlowALPModels" - -/// Rebalances a position via an EPosition capability at PoolCapStoragePath. -/// EPosition satisfies the EPosition | ERebalance requirement of Pool.rebalancePosition. -/// -/// @param pid: Position to rebalance -/// @param force: Whether to force rebalance regardless of health bounds -transaction(pid: UInt64, force: Bool) { - let pool: auth(FlowALPModels.EPosition) &FlowALPv0.Pool - - prepare(signer: auth(BorrowValue) &Account) { - let cap = signer.storage.borrow<&Capability>( - from: FlowALPv0.PoolCapStoragePath - ) ?? panic("EPosition capability not found at PoolCapStoragePath") - self.pool = cap.borrow() ?? panic("Could not borrow Pool with EPosition") - } - - execute { - // Pool.rebalancePosition — requires EPosition | ERebalance; EPosition alone is sufficient - self.pool.rebalancePosition(pid: pid, force: force) - } -} diff --git a/cadence/tests/transactions/flow-alp/eposition/withdraw_and_pull_any.cdc b/cadence/tests/transactions/flow-alp/eposition/withdraw_and_pull_any.cdc deleted file mode 100644 index 72748857..00000000 --- a/cadence/tests/transactions/flow-alp/eposition/withdraw_and_pull_any.cdc +++ /dev/null @@ -1,33 +0,0 @@ -import "FungibleToken" -import "FlowALPv0" -import "FlowALPModels" -import "MOET" - -/// Withdraws and pulls MOET from any position via an EPosition capability at PoolCapStoragePath. -/// EPosition allows operations on any position by ID, regardless of ownership. -/// -/// @param pid: Target position ID (owned by a different account) -/// @param amount: Amount to withdraw -transaction(pid: UInt64, amount: UFix64) { - let pool: auth(FlowALPModels.EPosition) &FlowALPv0.Pool - let receiver: &{FungibleToken.Receiver} - - prepare(signer: auth(BorrowValue) &Account) { - let cap = signer.storage.borrow<&Capability>( - from: FlowALPv0.PoolCapStoragePath - ) ?? panic("EPosition capability not found") - self.pool = cap.borrow() ?? panic("Could not borrow Pool with EPosition") - self.receiver = signer.storage.borrow<&{FungibleToken.Receiver}>(from: MOET.VaultStoragePath) - ?? panic("No MOET vault receiver") - } - - execute { - let vault <- self.pool.withdrawAndPull( - pid: pid, - type: Type<@MOET.Vault>(), - amount: amount, - pullFromTopUpSource: false - ) - self.receiver.deposit(from: <-vault) - } -} diff --git a/cadence/tests/transactions/flow-alp/eposition/withdraw_any.cdc b/cadence/tests/transactions/flow-alp/eposition/withdraw_any.cdc deleted file mode 100644 index 3b7edb14..00000000 --- a/cadence/tests/transactions/flow-alp/eposition/withdraw_any.cdc +++ /dev/null @@ -1,28 +0,0 @@ -import "FungibleToken" -import "FlowALPv0" -import "FlowALPModels" -import "MOET" - -/// Withdraws MOET from any position via an EPosition capability at PoolCapStoragePath. -/// EPosition allows operations on any position by ID, regardless of ownership. -/// -/// @param pid: Target position ID (owned by a different account) -/// @param amount: Amount to withdraw -transaction(pid: UInt64, amount: UFix64) { - let pool: auth(FlowALPModels.EPosition) &FlowALPv0.Pool - let receiver: &{FungibleToken.Receiver} - - prepare(signer: auth(BorrowValue) &Account) { - let cap = signer.storage.borrow<&Capability>( - from: FlowALPv0.PoolCapStoragePath - ) ?? panic("EPosition capability not found") - self.pool = cap.borrow() ?? panic("Could not borrow Pool with EPosition") - self.receiver = signer.storage.borrow<&{FungibleToken.Receiver}>(from: MOET.VaultStoragePath) - ?? panic("No MOET vault receiver") - } - - execute { - let vault <- self.pool.withdraw(pid: pid, amount: amount, type: Type<@MOET.Vault>()) - self.receiver.deposit(from: <-vault) - } -} diff --git a/cadence/tests/transactions/flow-alp/setup/grant_beta_cap.cdc b/cadence/tests/transactions/flow-alp/setup/grant_beta_cap.cdc index a8b7fc04..cc5315a6 100644 --- a/cadence/tests/transactions/flow-alp/setup/grant_beta_cap.cdc +++ b/cadence/tests/transactions/flow-alp/setup/grant_beta_cap.cdc @@ -7,12 +7,12 @@ transaction() { admin: auth(Capabilities, Storage) &Account, tester: auth(Storage) &Account ) { - let poolCap: Capability = + let poolCap = admin.capabilities.storage.issue< - auth(FlowALPModels.EParticipant, FlowALPModels.EPosition) &FlowALPv0.Pool + auth(FlowALPModels.EParticipant) &FlowALPv0.Pool >(FlowALPv0.PoolStoragePath) if tester.storage.type(at: FlowALPv0.PoolCapStoragePath) != nil { - tester.storage.load>( + tester.storage.load>( from: FlowALPv0.PoolCapStoragePath ) } diff --git a/cadence/tests/transactions/flow-alp/setup/grant_eposition_cap.cdc b/cadence/tests/transactions/flow-alp/setup/grant_eposition_cap.cdc deleted file mode 100644 index 5fee69a5..00000000 --- a/cadence/tests/transactions/flow-alp/setup/grant_eposition_cap.cdc +++ /dev/null @@ -1,25 +0,0 @@ -import "FlowALPv0" -import "FlowALPModels" - -/// TEST SETUP — grants an EPosition-ONLY Pool capability to a user account. -/// This is a narrowly-scoped capability — no EParticipant, so the holder cannot -/// createPosition. EPosition alone allows pool-level position operations on any -/// position by ID (withdraw, depositAndPush, lockPosition, rebalancePosition, etc.). -/// Stored at FlowALPv0.PoolCapStoragePath. -transaction { - prepare( - admin: auth(IssueStorageCapabilityController) &Account, - user: auth(Storage) &Account - ) { - let cap = admin.capabilities.storage.issue( - FlowALPv0.PoolStoragePath - ) - // Overwrite any existing cap at this path - if user.storage.type(at: FlowALPv0.PoolCapStoragePath) != nil { - user.storage.load>( - from: FlowALPv0.PoolCapStoragePath - ) - } - user.storage.save(cap, to: FlowALPv0.PoolCapStoragePath) - } -} diff --git a/cadence/tests/transactions/position-manager/create_position_reentrancy.cdc b/cadence/tests/transactions/position-manager/create_position_reentrancy.cdc index 7f03ef2a..d611d650 100644 --- a/cadence/tests/transactions/position-manager/create_position_reentrancy.cdc +++ b/cadence/tests/transactions/position-manager/create_position_reentrancy.cdc @@ -29,7 +29,7 @@ transaction(amount: UFix64, vaultStoragePath: StoragePath, pushToDrawDownSink: B // the position manager in the signer's account where we should store the new position let positionManager: auth(FlowALPModels.EPositionAdmin) &FlowALPPositionResources.PositionManager // the authorized Pool capability - let poolCap: Capability + let poolCap: Capability // reference to signer's account for saving capability back let signerAccount: auth(LoadValue, BorrowValue, SaveValue, IssueStorageCapabilityController, PublishCapability, UnpublishCapability) &Account @@ -83,7 +83,7 @@ transaction(amount: UFix64, vaultStoragePath: StoragePath, pushToDrawDownSink: B ?? panic("PositionManager not found") // Load the authorized Pool capability from storage - self.poolCap = signer.storage.load>( + self.poolCap = signer.storage.load>( from: FlowALPv0.PoolCapStoragePath ) ?? panic("Could not load Pool capability from storage - ensure the signer has been granted Pool access with EParticipant entitlement") } @@ -104,10 +104,12 @@ transaction(amount: UFix64, vaultStoragePath: StoragePath, pushToDrawDownSink: B self.positionManager.addPosition(position: <-position) let sourceRef = self.source as! AdversarialReentrancyConnectors.VaultSourceHacked - + let liveData = sourceRef.liveDataCap.borrow() ?? panic("cant borrow LiveData") - liveData.setRecursivePool(self.poolCap) - liveData.setRecursivePositionID(pid) + let managerCap = self.signerAccount.capabilities.storage.issue< + auth(FungibleToken.Withdraw, FlowALPModels.EPositionAdmin) &FlowALPPositionResources.PositionManager + >(FlowALPv0.PositionStoragePath) + liveData.setRecursivePosition(managerCap: managerCap, pid: pid) self.signerAccount.storage.save(self.poolCap, to: FlowALPv0.PoolCapStoragePath) } diff --git a/cadence/tests/transactions/position-manager/create_position_spoofing_source.cdc b/cadence/tests/transactions/position-manager/create_position_spoofing_source.cdc index b61510ae..6add45fc 100644 --- a/cadence/tests/transactions/position-manager/create_position_spoofing_source.cdc +++ b/cadence/tests/transactions/position-manager/create_position_spoofing_source.cdc @@ -30,7 +30,7 @@ transaction(amount: UFix64, vaultStoragePath: StoragePath, pushToDrawDownSink: B // the position manager in the signer's account where we should store the new position let positionManager: auth(FlowALPModels.EPositionAdmin) &FlowALPPositionResources.PositionManager // the authorized Pool capability - let poolCap: Capability + let poolCap: Capability // reference to signer's account for saving capability back let signerAccount: auth(LoadValue,BorrowValue, SaveValue, IssueStorageCapabilityController, PublishCapability, UnpublishCapability) &Account @@ -83,7 +83,7 @@ transaction(amount: UFix64, vaultStoragePath: StoragePath, pushToDrawDownSink: B ?? panic("PositionManager not found") // Load the authorized Pool capability from storage - self.poolCap = signer.storage.load>( + self.poolCap = signer.storage.load>( from: FlowALPv0.PoolCapStoragePath ) ?? panic("Could not load Pool capability from storage - ensure the signer has been granted Pool access with EParticipant entitlement") } diff --git a/cadence/transactions/flow-alp/beta/claim_and_save_beta_cap.cdc b/cadence/transactions/flow-alp/beta/claim_and_save_beta_cap.cdc index 12c71ff9..fef64e81 100644 --- a/cadence/transactions/flow-alp/beta/claim_and_save_beta_cap.cdc +++ b/cadence/transactions/flow-alp/beta/claim_and_save_beta_cap.cdc @@ -6,14 +6,14 @@ transaction(adminAddr: Address) { prepare(user: auth(SaveValue, LoadValue, ClaimInboxCapability) &Account) { // Save claimed cap at the protocol-defined storage path to satisfy consumers/tests expecting this path let capPath = FlowALPv0.PoolCapStoragePath - let claimed: Capability = + let claimed = user.inbox.claim< - auth(FlowALPModels.EParticipant, FlowALPModels.EPosition) &FlowALPv0.Pool + auth(FlowALPModels.EParticipant) &FlowALPv0.Pool >("FlowALPv0BetaCap", provider: adminAddr) ?? panic("No beta capability found in inbox") if user.storage.type(at: capPath) != nil { - let _ = user.storage.load>(from: capPath) + let _ = user.storage.load>(from: capPath) } user.storage.save(claimed, to: capPath) } diff --git a/cadence/transactions/flow-alp/beta/publish_beta_cap.cdc b/cadence/transactions/flow-alp/beta/publish_beta_cap.cdc index ae857ad0..9dd57240 100644 --- a/cadence/transactions/flow-alp/beta/publish_beta_cap.cdc +++ b/cadence/transactions/flow-alp/beta/publish_beta_cap.cdc @@ -4,9 +4,9 @@ import "FlowALPModels" transaction(grantee: Address) { prepare(admin: auth(IssueStorageCapabilityController, PublishInboxCapability) &Account) { - let poolCap: Capability = + let poolCap = admin.capabilities.storage.issue< - auth(FlowALPModels.EParticipant, FlowALPModels.EPosition) &FlowALPv0.Pool + auth(FlowALPModels.EParticipant) &FlowALPv0.Pool >(FlowALPv0.PoolStoragePath) assert(poolCap.check(), message: "Failed to issue beta capability") diff --git a/cadence/transactions/flow-alp/pool-management/rebalance_position.cdc b/cadence/transactions/flow-alp/pool-management/rebalance_position.cdc index 7f199918..15bcb94d 100644 --- a/cadence/transactions/flow-alp/pool-management/rebalance_position.cdc +++ b/cadence/transactions/flow-alp/pool-management/rebalance_position.cdc @@ -8,10 +8,10 @@ import "FlowALPModels" /// the position is beyond its min/max health. If `true`, the rebalance executes regardless of its relative health. /// transaction(pid: UInt64, force: Bool) { - let pool: auth(FlowALPModels.EPosition) &FlowALPv0.Pool + let pool: auth(FlowALPModels.ERebalance) &FlowALPv0.Pool prepare(signer: auth(BorrowValue) &Account) { - self.pool = signer.storage.borrow(from: FlowALPv0.PoolStoragePath) + self.pool = signer.storage.borrow(from: FlowALPv0.PoolStoragePath) ?? panic("Could not borrow reference to Pool from \(FlowALPv0.PoolStoragePath) - ensure a Pool has been configured") } diff --git a/cadence/transactions/flow-alp/position/create_position.cdc b/cadence/transactions/flow-alp/position/create_position.cdc index 5062ef3d..e50585f7 100644 --- a/cadence/transactions/flow-alp/position/create_position.cdc +++ b/cadence/transactions/flow-alp/position/create_position.cdc @@ -22,7 +22,7 @@ transaction(amount: UFix64, vaultStoragePath: StoragePath, pushToDrawDownSink: B // the position manager in the signer's account where we should store the new position let positionManager: auth(FlowALPModels.EPositionAdmin) &FlowALPPositionResources.PositionManager // the authorized Pool capability - let poolCap: Capability + let poolCap: Capability // reference to signer's account for saving capability back let signerAccount: auth(Storage) &Account @@ -78,7 +78,7 @@ transaction(amount: UFix64, vaultStoragePath: StoragePath, pushToDrawDownSink: B ?? panic("PositionManager not found") // Load the authorized Pool capability from storage - self.poolCap = signer.storage.load>( + self.poolCap = signer.storage.load>( from: FlowALPv0.PoolCapStoragePath ) ?? panic("Could not load Pool capability from storage - ensure the signer has been granted Pool access with EParticipant entitlement") } diff --git a/cadence/transactions/flow-alp/position/create_position_not_managed.cdc b/cadence/transactions/flow-alp/position/create_position_not_managed.cdc index 99951c11..626496a0 100644 --- a/cadence/transactions/flow-alp/position/create_position_not_managed.cdc +++ b/cadence/transactions/flow-alp/position/create_position_not_managed.cdc @@ -19,7 +19,7 @@ transaction(amount: UFix64, vaultStoragePath: StoragePath, pushToDrawDownSink: B // this DeFiActions Source that will allow for the repayment of a loan if the position becomes undercollateralized let source: {DeFiActions.Source} // the authorized Pool capability - let poolCap: Capability + let poolCap: Capability // reference to signer's account for saving capability back let signerAccount: auth(Storage) &Account @@ -60,7 +60,7 @@ transaction(amount: UFix64, vaultStoragePath: StoragePath, pushToDrawDownSink: B ) // Load the authorized Pool capability from storage - self.poolCap = signer.storage.load>( + self.poolCap = signer.storage.load>( from: FlowALPv0.PoolCapStoragePath ) ?? panic("Could not load Pool capability from storage - ensure the signer has been granted Pool access with EParticipant entitlement") } diff --git a/flow.json b/flow.json index 154d3e71..3289b703 100644 --- a/flow.json +++ b/flow.json @@ -3,15 +3,15 @@ "AdversarialReentrancyConnectors": { "source": "./cadence/tests/contracts/AdversarialReentrancyConnectors.cdc", "aliases": { - "testing": "0000000000000008", - "mainnet-fork": "6b00ff876c299c61" + "mainnet-fork": "6b00ff876c299c61", + "testing": "0000000000000008" } }, "AdversarialTypeSpoofingConnectors": { "source": "./cadence/tests/contracts/AdversarialTypeSpoofingConnectors.cdc", "aliases": { - "testing": "0000000000000008", - "mainnet-fork": "6b00ff876c299c61" + "mainnet-fork": "6b00ff876c299c61", + "testing": "0000000000000008" } }, "BandOracleConnectors": { @@ -45,167 +45,167 @@ "DummyConnectors": { "source": "./cadence/contracts/mocks/DummyConnectors.cdc", "aliases": { - "testing": "0000000000000007", - "mainnet-fork": "6d888f175c158410" + "mainnet-fork": "6d888f175c158410", + "testing": "0000000000000007" } }, "ExampleToken1": { "source": "./cadence/tests/contracts/ExampleToken1.cdc", "aliases": { - "testing": "0000000000000008", + "mainnet": "6b00ff876c299c61", "mainnet-fork": "6b00ff876c299c61", - "mainnet": "6b00ff876c299c61" + "testing": "0000000000000008" } }, "ExampleToken2": { "source": "./cadence/tests/contracts/ExampleToken2.cdc", "aliases": { - "testing": "0000000000000008", + "mainnet": "6b00ff876c299c61", "mainnet-fork": "6b00ff876c299c61", - "mainnet": "6b00ff876c299c61" + "testing": "0000000000000008" } }, "FlowALPEvents": { "source": "./cadence/contracts/FlowALPEvents.cdc", "aliases": { - "testing": "0000000000000007", - "mainnet-fork": "6b00ff876c299c61" + "mainnet-fork": "6b00ff876c299c61", + "testing": "0000000000000007" + } + }, + "FlowALPHealth": { + "source": "./cadence/contracts/FlowALPHealth.cdc", + "aliases": { + "mainnet-fork": "6b00ff876c299c61", + "testing": "0000000000000007" } }, "FlowALPInterestRates": { "source": "./cadence/contracts/FlowALPInterestRates.cdc", "aliases": { - "testing": "0000000000000007", - "mainnet-fork": "6b00ff876c299c61" + "mainnet-fork": "6b00ff876c299c61", + "testing": "0000000000000007" } }, - "FlowALPHealth": { - "source": "./cadence/contracts/FlowALPHealth.cdc", + "FlowALPMath": { + "source": "./cadence/lib/FlowALPMath.cdc", "aliases": { - "testing": "0000000000000007", - "mainnet-fork": "6b00ff876c299c61" + "mainnet": "6d888f175c158410", + "testing": "0000000000000007" } }, "FlowALPModels": { "source": "./cadence/contracts/FlowALPModels.cdc", "aliases": { - "testing": "0000000000000007", - "mainnet-fork": "6b00ff876c299c61" + "mainnet-fork": "6b00ff876c299c61", + "testing": "0000000000000007" } }, "FlowALPPositionResources": { "source": "./cadence/contracts/FlowALPPositionResources.cdc", "aliases": { - "testing": "0000000000000007", - "mainnet-fork": "6b00ff876c299c61" - } - }, - "FlowALPMath": { - "source": "./cadence/lib/FlowALPMath.cdc", - "aliases": { - "testing": "0000000000000007", - "mainnet": "6d888f175c158410" + "mainnet-fork": "6b00ff876c299c61", + "testing": "0000000000000007" } }, "FlowALPRebalancerPaidv1": { "source": "./cadence/contracts/FlowALPRebalancerPaidv1.cdc", "aliases": { - "testing": "0000000000000007", - "mainnet-fork": "6b00ff876c299c61" + "mainnet-fork": "6b00ff876c299c61", + "testing": "0000000000000007" } }, "FlowALPRebalancerv1": { "source": "./cadence/contracts/FlowALPRebalancerv1.cdc", "aliases": { - "testing": "0000000000000007", - "mainnet-fork": "6b00ff876c299c61" + "mainnet-fork": "6b00ff876c299c61", + "testing": "0000000000000007" } }, "FlowALPSupervisorv1": { "source": "./cadence/contracts/FlowALPSupervisorv1.cdc", "aliases": { - "testing": "0000000000000007", - "mainnet-fork": "6b00ff876c299c61" + "mainnet-fork": "6b00ff876c299c61", + "testing": "0000000000000007" } }, "FlowALPv0": { "source": "./cadence/contracts/FlowALPv0.cdc", "aliases": { - "testing": "0000000000000007", "mainnet": "6b00ff876c299c61", - "mainnet-fork": "6b00ff876c299c61" + "mainnet-fork": "6b00ff876c299c61", + "testing": "0000000000000007" } }, "FungibleTokenConnectors": { "source": "./FlowActions/cadence/contracts/connectors/FungibleTokenConnectors.cdc", "aliases": { - "testing": "0000000000000006", + "mainnet": "6b00ff876c299c61", "mainnet-fork": "6b00ff876c299c61", - "mainnet": "6b00ff876c299c61" + "testing": "0000000000000006" } }, "MOET": { "source": "./cadence/contracts/MOET.cdc", "aliases": { - "testing": "0000000000000007", - "mainnet": "6b00ff876c299c61" + "mainnet": "6b00ff876c299c61", + "testing": "0000000000000007" } }, "MockDexSwapper": { "source": "./cadence/contracts/mocks/MockDexSwapper.cdc", "aliases": { - "testing": "0000000000000007", - "testnet": "d2580caf2ef07c2f", "mainnet": "6b00ff876c299c61", - "mainnet-fork": "6b00ff876c299c61" + "mainnet-fork": "6b00ff876c299c61", + "testing": "0000000000000007", + "testnet": "d2580caf2ef07c2f" } }, "MockOracle": { "source": "./cadence/contracts/mocks/MockOracle.cdc", "aliases": { - "testing": "0000000000000007", - "testnet": "d2580caf2ef07c2f", "mainnet": "6b00ff876c299c61", - "mainnet-fork": "6b00ff876c299c61" + "mainnet-fork": "6b00ff876c299c61", + "testing": "0000000000000007", + "testnet": "d2580caf2ef07c2f" } }, "MockYieldToken": { "source": "./cadence/contracts/mocks/MockYieldToken.cdc", "aliases": { - "testing": "0000000000000007", - "mainnet-fork": "6b00ff876c299c61" + "mainnet-fork": "6b00ff876c299c61", + "testing": "0000000000000007" } }, "MultiMockOracle": { "source": "./cadence/tests/contracts/MultiMockOracle.cdc", "aliases": { - "testing": "0000000000000007", + "mainnet": "6b00ff876c299c61", "mainnet-fork": "6b00ff876c299c61", - "mainnet": "6b00ff876c299c61" + "testing": "0000000000000007" } }, "OracleStorage": { "source": "./cadence/tests/contracts/OracleStorage.cdc", "aliases": { - "testing": "0000000000000008", + "mainnet": "6b00ff876c299c61", "mainnet-fork": "6b00ff876c299c61", - "mainnet": "6b00ff876c299c61" + "testing": "0000000000000008" } }, "PriceOracleAggregatorv1": { "source": "./cadence/contracts/PriceOracleAggregatorv1.cdc", "aliases": { - "testing": "0000000000000007", + "mainnet": "6b00ff876c299c61", "mainnet-fork": "6b00ff876c299c61", - "mainnet": "6b00ff876c299c61" + "testing": "0000000000000007" } }, "PriceOracleRouterv1": { "source": "./cadence/contracts/PriceOracleRouterv1.cdc", "aliases": { - "testing": "0000000000000007", + "mainnet": "6b00ff876c299c61", "mainnet-fork": "6b00ff876c299c61", - "mainnet": "6b00ff876c299c61" + "testing": "0000000000000007" } } }, @@ -515,4 +515,4 @@ ] } } -} +} \ No newline at end of file