Skip to content
Merged
Changes from all 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
103 changes: 72 additions & 31 deletions cadence/contracts/FlowYieldVaultsSchedulerV1.cdc
Original file line number Diff line number Diff line change
Expand Up @@ -73,6 +73,17 @@ access(all) contract FlowYieldVaultsSchedulerV1 {
timestamp: UFix64
)

/// Emitted when Supervisor fails to self-reschedule.
///
/// This is primarily used to surface insufficient fee vault balance, which would otherwise
/// cause the Supervisor to stop monitoring without any on-chain signal.
access(all) event SupervisorRescheduleFailed(
timestamp: UFix64,
requiredFee: UFix64?,
availableBalance: UFix64?,
error: String
)

/// Entitlement to schedule transactions
access(all) entitlement Schedule

Expand Down Expand Up @@ -213,10 +224,9 @@ access(all) contract FlowYieldVaultsSchedulerV1 {

// Borrow the AutoBalancer and call scheduleNextRebalance() directly
let autoBalancerRef = scheduleCap!.borrow()!
let scheduleError = autoBalancerRef.scheduleNextRebalance(whileExecuting: nil)

if scheduleError != nil {
emit YieldVaultRecoveryFailed(yieldVaultID: yieldVaultID, error: scheduleError!)
if let scheduleError = autoBalancerRef.scheduleNextRebalance(whileExecuting: nil) {
emit YieldVaultRecoveryFailed(yieldVaultID: yieldVaultID, error: scheduleError)
// Leave in pending queue for retry on next Supervisor run
continue
}
Expand Down Expand Up @@ -262,9 +272,24 @@ access(all) contract FlowYieldVaultsSchedulerV1 {
destroy txn

let nextTimestamp = getCurrentBlock().timestamp + recurringInterval
let supervisorCap = FlowYieldVaultsSchedulerRegistry.getSupervisorCap()

if supervisorCap == nil || !supervisorCap!.check() {
let supervisorCap = FlowYieldVaultsSchedulerRegistry.getSupervisorCap()
if supervisorCap == nil {
emit SupervisorRescheduleFailed(
timestamp: nextTimestamp,
requiredFee: nil,
availableBalance: nil,
error: "Missing Supervisor capability"
)
return
}
if !supervisorCap!.check() {
emit SupervisorRescheduleFailed(
timestamp: nextTimestamp,
requiredFee: nil,
availableBalance: nil,
error: "Invalid Supervisor capability"
)
return
}

Expand All @@ -276,34 +301,50 @@ access(all) contract FlowYieldVaultsSchedulerV1 {
let baseFee = est.flowFee ?? FlowYieldVaultsSchedulerV1.MIN_FEE_FALLBACK
let required = baseFee * FlowYieldVaultsSchedulerV1.FEE_MARGIN_MULTIPLIER

if let vaultRef = self.feesCap.borrow() {
if vaultRef.balance >= required {
let fees <- vaultRef.withdraw(amount: required) as! @FlowToken.Vault
let vaultRef = self.feesCap.borrow()
if vaultRef == nil {
emit SupervisorRescheduleFailed(
Comment thread
liobrasil marked this conversation as resolved.
timestamp: nextTimestamp,
requiredFee: required,
availableBalance: nil,
error: "Could not borrow fee vault"
)
return
}
if vaultRef!.balance < required {
emit SupervisorRescheduleFailed(
timestamp: nextTimestamp,
requiredFee: required,
availableBalance: vaultRef!.balance,
error: "Insufficient fee vault balance"
)
return
}

let nextData: {String: AnyStruct} = {
"priority": priority.rawValue,
"executionEffort": executionEffort,
"recurringInterval": recurringInterval,
"scanForStuck": scanForStuck
}
let fees <- vaultRef!.withdraw(amount: required) as! @FlowToken.Vault

let selfTxn <- FlowTransactionScheduler.schedule(
handlerCap: supervisorCap!,
data: nextData,
timestamp: nextTimestamp,
priority: priority,
executionEffort: executionEffort,
fees: <-fees
)

emit SupervisorRescheduled(
scheduledTransactionID: selfTxn.id,
timestamp: nextTimestamp
)

self._scheduledTransaction <-! selfTxn
}
let nextData = {
"priority": priority.rawValue,
"executionEffort": executionEffort,
"recurringInterval": recurringInterval,
"scanForStuck": scanForStuck
}

let selfTxn <- FlowTransactionScheduler.schedule(
handlerCap: supervisorCap!,
data: nextData,
timestamp: nextTimestamp,
priority: priority,
executionEffort: executionEffort,
fees: <-fees
)

emit SupervisorRescheduled(
scheduledTransactionID: selfTxn.id,
timestamp: nextTimestamp
)

self._scheduledTransaction <-! selfTxn
}

/// Cancels the scheduled transaction if it is scheduled.
Expand Down Expand Up @@ -401,7 +442,7 @@ access(all) contract FlowYieldVaultsSchedulerV1 {
access(account) fun enqueuePendingYieldVault(yieldVaultID: UInt64) {
assert(
FlowYieldVaultsSchedulerRegistry.isRegistered(yieldVaultID: yieldVaultID),
message: "enqueuePendingYieldVault: YieldVault #".concat(yieldVaultID.toString()).concat(" is not registered")
message: "enqueuePendingYieldVault: YieldVault #\(yieldVaultID.toString()) is not registered"
)
FlowYieldVaultsSchedulerRegistry.enqueuePending(yieldVaultID: yieldVaultID)
}
Expand Down
Loading