DeploySEALED
█╳░~~╲&░&█$█**╳$▒□&~~&%@@▪◇#○█╳▫░╲▒~?□$?$▫?╳^□□▫*◇╳◇▓#○░■╱▪^*▓▪╲
Transaction ID
Execution Fee
0.0031 FLOWTransaction Summary
DeployContract deployment
Contract deployment
Script Arguments
0nameString
DCAHandlerEVMV3
1codeString
import FlowTransactionScheduler from 0xe467b9dd11fa00df
import FlowTransactionSchedulerUtils from 0xe467b9dd11fa00df
import FlowToken from 0x1654653399040a61
import FungibleToken from 0xf233dcee88fe0abe
import DCAServiceEVM from 0xca7ee55e4fc3251a
/// DCAHandlerEVMV3: Fixed Autonomous Scheduled Transaction Handler for EVM-Native DCA
///
/// This version stores capabilities in the Handler resource itself (not in TransactionData)
/// because capabilities cannot be serialized through the scheduler's data parameter.
///
access(all) contract DCAHandlerEVMV3 {
// ============================================================
// Events
// ============================================================
access(all) event HandlerCreated(uuid: UInt64)
access(all) event HandlerConfigured(uuid: UInt64)
access(all) event ExecutionTriggered(planId: UInt64, success: Bool, nextScheduled: Bool)
access(all) event ExecutionSkipped(planId: UInt64, reason: String)
access(all) event NextExecutionScheduled(planId: UInt64, scheduledId: UInt64, timestamp: UFix64)
access(all) event NextExecutionSchedulingFailed(planId: UInt64, reason: String)
// ============================================================
// Storage Paths
// ============================================================
access(all) let HandlerStoragePath: StoragePath
// ============================================================
// Transaction Data (simple - just planId)
// ============================================================
access(all) struct TransactionData {
access(all) let planId: UInt64
init(planId: UInt64) {
self.planId = planId
}
}
// ============================================================
// Handler Resource (stores capabilities internally)
// ============================================================
access(all) resource Handler: FlowTransactionScheduler.TransactionHandler {
// Scheduling configuration stored in resource (not in TransactionData)
access(self) var schedulerManagerCap: Capability<auth(FlowTransactionSchedulerUtils.Owner) &{FlowTransactionSchedulerUtils.Manager}>?
access(self) var feeVaultCap: Capability<auth(FungibleToken.Withdraw) &{FungibleToken.Vault}>?
access(all) var priority: FlowTransactionScheduler.Priority
access(all) var executionEffort: UInt64
/// Configure the handler with scheduling capabilities
/// Call this once after creating the handler
access(all) fun configure(
schedulerManagerCap: Capability<auth(FlowTransactionSchedulerUtils.Owner) &{FlowTransactionSchedulerUtils.Manager}>,
feeVaultCap: Capability<auth(FungibleToken.Withdraw) &{FungibleToken.Vault}>,
priority: FlowTransactionScheduler.Priority,
executionEffort: UInt64
) {
pre {
self.schedulerManagerCap == nil: "Handler already configured"
schedulerManagerCap.check(): "Invalid scheduler manager capability"
feeVaultCap.check(): "Invalid fee vault capability"
}
self.schedulerManagerCap = schedulerManagerCap
self.feeVaultCap = feeVaultCap
self.priority = priority
self.executionEffort = executionEffort
emit HandlerConfigured(uuid: self.uuid)
}
/// Main execution entrypoint called by FlowTransactionScheduler
access(FlowTransactionScheduler.Execute)
fun executeTransaction(id: UInt64, data: AnyStruct?) {
// Parse transaction data (simple - just planId)
let txData = data as? TransactionData
if txData == nil {
log("DCAHandlerEVMV3: Invalid transaction data")
return
}
let planId = txData!.planId
// Get plan details
let planOpt = DCAServiceEVM.getPlan(planId: planId)
if planOpt == nil {
emit ExecutionSkipped(planId: planId, reason: "Plan not found")
return
}
let plan = planOpt!
// Check if plan is active
if plan.getStatus() != DCAServiceEVM.PlanStatus.Active {
emit ExecutionSkipped(planId: planId, reason: "Plan not active")
return
}
// Execute the DCA plan via DCAServiceEVM
let success = DCAServiceEVM.executePlan(planId: planId)
// If successful and plan still active, schedule next execution
var nextScheduled = false
if success {
// Re-fetch plan to get updated nextExecutionTime
let updatedPlanOpt = DCAServiceEVM.getPlan(planId: planId)
if updatedPlanOpt != nil {
let updatedPlan = updatedPlanOpt!
// Only reschedule if plan is still active
if updatedPlan.getStatus() == DCAServiceEVM.PlanStatus.Active {
nextScheduled = self.scheduleNextExecution(
planId: planId,
nextExecutionTime: updatedPlan.nextExecutionTime
)
}
}
}
emit ExecutionTriggered(planId: planId, success: success, nextScheduled: nextScheduled)
}
/// Schedule the next execution using stored capabilities
access(self) fun scheduleNextExecution(
planId: UInt64,
nextExecutionTime: UFix64?
): Bool {
// Verify handler is configured
if self.schedulerManagerCap == nil || self.feeVaultCap == nil {
emit NextExecutionSchedulingFailed(planId: planId, reason: "Handler not configured")
return false
}
// Verify nextExecutionTime is provided
if nextExecutionTime == nil {
emit NextExecutionSchedulingFailed(planId: planId, reason: "Next execution time not set")
return false
}
// Prepare transaction data (just planId)
let nextTxData = TransactionData(planId: planId)
// Estimate fees
let estimate = FlowTransactionScheduler.estimate(
data: nextTxData,
timestamp: nextExecutionTime!,
priority: self.priority,
executionEffort: self.executionEffort
)
let feeAmount = estimate.flowFee ?? 0.001
let feeWithBuffer = feeAmount * 1.1
// Borrow fee vault
let feeVault = self.feeVaultCap!.borrow()
if feeVault == nil {
emit NextExecutionSchedulingFailed(planId: planId, reason: "Could not borrow fee vault")
return false
}
// Check balance
if feeVault!.balance < feeWithBuffer {
emit NextExecutionSchedulingFailed(
planId: planId,
reason: "Insufficient fees. Required: ".concat(feeWithBuffer.toString())
)
return false
}
// Withdraw fees
let fees <- feeVault!.withdraw(amount: feeWithBuffer)
// Borrow scheduler manager
let schedulerManager = self.schedulerManagerCap!.borrow()
if schedulerManager == nil {
feeVault!.deposit(from: <-fees)
emit NextExecutionSchedulingFailed(planId: planId, reason: "Could not borrow scheduler manager")
return false
}
// Schedule next execution using Manager.scheduleByHandler()
let scheduledId = schedulerManager!.scheduleByHandler(
handlerTypeIdentifier: self.getType().identifier,
handlerUUID: self.uuid,
data: nextTxData,
timestamp: nextExecutionTime!,
priority: self.priority,
executionEffort: self.executionEffort,
fees: <-fees as! @FlowToken.Vault
)
if scheduledId == 0 {
emit NextExecutionSchedulingFailed(planId: planId, reason: "scheduleByHandler returned 0")
return false
}
emit NextExecutionScheduled(planId: planId, scheduledId: scheduledId, timestamp: nextExecutionTime!)
return true
}
init() {
self.schedulerManagerCap = nil
self.feeVaultCap = nil
self.priority = FlowTransactionScheduler.Priority.Medium
self.executionEffort = 3500
emit HandlerCreated(uuid: self.uuid)
}
}
// ============================================================
// Factory Functions
// ============================================================
access(all) fun createHandler(): @Handler {
return <- create Handler()
}
access(all) fun createTransactionData(planId: UInt64): TransactionData {
return TransactionData(planId: planId)
}
// ============================================================
// Init
// ============================================================
init() {
self.HandlerStoragePath = /storage/DCAHandlerEVMV3
}
}
Cadence Script
1transaction(name: String, code: String ) {
2 prepare(signer: auth(AddContract) &Account) {
3 signer.contracts.add(name: name, code: code.utf8 )
4 }
5 }