Skip to content
Merged
Show file tree
Hide file tree
Changes from 9 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
43 changes: 18 additions & 25 deletions cadence/tests/contracts/AdversarialReentrancyConnectors.cdc
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import "FungibleTokenMetadataViews"
import "DeFiActionsUtils"
import "DeFiActions"
import "FlowALPv0"
import "FlowALPPositionResources"
import "FlowALPModels"

import "MOET"
Expand Down Expand Up @@ -107,17 +108,18 @@ access(all) contract AdversarialReentrancyConnectors {
}

access(all) resource LiveData {
/// Optional: Pool capability for recursive withdrawAndPull call
access(all) var recursivePool: Capability<auth(FlowALPModels.EPosition) &FlowALPv0.Pool>?
/// Optional: Position ID for recursive withdrawAndPull call
/// Capability to the attacker's PositionManager for recursive withdrawal
access(all) var positionManagerCap: Capability<auth(FungibleToken.Withdraw, FlowALPModels.EPositionAdmin) &FlowALPPositionResources.PositionManager>?
/// Position ID for recursive withdrawal
access(all) var recursivePositionID: UInt64?

init() { self.recursivePositionID = nil; self.recursivePool = nil }
access(all) fun setRecursivePool(_ pool: Capability<auth(FlowALPModels.EPosition) &FlowALPv0.Pool>) {
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<auth(FungibleToken.Withdraw, FlowALPModels.EPositionAdmin) &FlowALPPositionResources.PositionManager>,
pid: UInt64
) {
self.positionManagerCap = managerCap
self.recursivePositionID = pid
}
}
access(all) fun createLiveData(): @LiveData {
Expand Down Expand Up @@ -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 {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,12 +7,12 @@ transaction() {
admin: auth(Capabilities, Storage) &Account,
tester: auth(Storage) &Account
) {
let poolCap: Capability<auth(FlowALPModels.EParticipant, FlowALPModels.EPosition) &FlowALPv0.Pool> =
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<Capability<auth(FlowALPModels.EParticipant, FlowALPModels.EPosition) &FlowALPv0.Pool>>(
tester.storage.load<Capability<auth(FlowALPModels.EParticipant) &FlowALPv0.Pool>>(
from: FlowALPv0.PoolCapStoragePath
)
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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<auth(FlowALPModels.EParticipant, FlowALPModels.EPosition) &FlowALPv0.Pool>
let poolCap: Capability<auth(FlowALPModels.EParticipant) &FlowALPv0.Pool>
// reference to signer's account for saving capability back
let signerAccount: auth(LoadValue, BorrowValue, SaveValue, IssueStorageCapabilityController, PublishCapability, UnpublishCapability) &Account

Expand Down Expand Up @@ -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<Capability<auth(FlowALPModels.EParticipant, FlowALPModels.EPosition) &FlowALPv0.Pool>>(
self.poolCap = signer.storage.load<Capability<auth(FlowALPModels.EParticipant) &FlowALPv0.Pool>>(
from: FlowALPv0.PoolCapStoragePath
) ?? panic("Could not load Pool capability from storage - ensure the signer has been granted Pool access with EParticipant entitlement")
}
Expand All @@ -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)
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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<auth(FlowALPModels.EParticipant, FlowALPModels.EPosition) &FlowALPv0.Pool>
let poolCap: Capability<auth(FlowALPModels.EParticipant) &FlowALPv0.Pool>
// reference to signer's account for saving capability back
let signerAccount: auth(LoadValue,BorrowValue, SaveValue, IssueStorageCapabilityController, PublishCapability, UnpublishCapability) &Account

Expand Down Expand Up @@ -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<Capability<auth(FlowALPModels.EParticipant, FlowALPModels.EPosition) &FlowALPv0.Pool>>(
self.poolCap = signer.storage.load<Capability<auth(FlowALPModels.EParticipant) &FlowALPv0.Pool>>(
from: FlowALPv0.PoolCapStoragePath
) ?? panic("Could not load Pool capability from storage - ensure the signer has been granted Pool access with EParticipant entitlement")
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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<auth(FlowALPModels.EParticipant, FlowALPModels.EPosition) &FlowALPv0.Pool> =
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<Capability<auth(FlowALPModels.EParticipant, FlowALPModels.EPosition) &FlowALPv0.Pool>>(from: capPath)
let _ = user.storage.load<Capability<auth(FlowALPModels.EParticipant) &FlowALPv0.Pool>>(from: capPath)
}
user.storage.save(claimed, to: capPath)
}
Expand Down
4 changes: 2 additions & 2 deletions cadence/transactions/flow-alp/beta/publish_beta_cap.cdc
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,9 @@ import "FlowALPModels"
transaction(grantee: Address) {

prepare(admin: auth(IssueStorageCapabilityController, PublishInboxCapability) &Account) {
let poolCap: Capability<auth(FlowALPModels.EParticipant, FlowALPModels.EPosition) &FlowALPv0.Pool> =
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")
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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<auth(FlowALPModels.EPosition) &FlowALPv0.Pool>(from: FlowALPv0.PoolStoragePath)
self.pool = signer.storage.borrow<auth(FlowALPModels.ERebalance) &FlowALPv0.Pool>(from: FlowALPv0.PoolStoragePath)
?? panic("Could not borrow reference to Pool from \(FlowALPv0.PoolStoragePath) - ensure a Pool has been configured")
}

Expand Down
4 changes: 2 additions & 2 deletions cadence/transactions/flow-alp/position/create_position.cdc
Original file line number Diff line number Diff line change
Expand Up @@ -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<auth(FlowALPModels.EParticipant, FlowALPModels.EPosition) &FlowALPv0.Pool>
let poolCap: Capability<auth(FlowALPModels.EParticipant) &FlowALPv0.Pool>
// reference to signer's account for saving capability back
let signerAccount: auth(Storage) &Account

Expand Down Expand Up @@ -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<Capability<auth(FlowALPModels.EParticipant, FlowALPModels.EPosition) &FlowALPv0.Pool>>(
self.poolCap = signer.storage.load<Capability<auth(FlowALPModels.EParticipant) &FlowALPv0.Pool>>(
from: FlowALPv0.PoolCapStoragePath
) ?? panic("Could not load Pool capability from storage - ensure the signer has been granted Pool access with EParticipant entitlement")
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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<auth(FlowALPModels.EParticipant, FlowALPModels.EPosition) &FlowALPv0.Pool>
let poolCap: Capability<auth(FlowALPModels.EParticipant) &FlowALPv0.Pool>
// reference to signer's account for saving capability back
let signerAccount: auth(Storage) &Account

Expand Down Expand Up @@ -60,7 +60,7 @@ transaction(amount: UFix64, vaultStoragePath: StoragePath, pushToDrawDownSink: B
)

// Load the authorized Pool capability from storage
self.poolCap = signer.storage.load<Capability<auth(FlowALPModels.EParticipant, FlowALPModels.EPosition) &FlowALPv0.Pool>>(
self.poolCap = signer.storage.load<Capability<auth(FlowALPModels.EParticipant) &FlowALPv0.Pool>>(
from: FlowALPv0.PoolCapStoragePath
) ?? panic("Could not load Pool capability from storage - ensure the signer has been granted Pool access with EParticipant entitlement")
}
Expand Down
Loading
Loading