DeploySEALED

◆#▪╱■▓●*◇▪●&▫░@╳◆!█╳$~●●▫▓■◇*!▫╱●*@╲%╲╲░■▓□╳╱○?$▓#?~▒◆▒▫~□◆●#╳╲◆

Transaction ID

Timestamp

Dec 11, 2025, 03:10:48 AM UTC
2mo ago

Block Height

135,616,807

Computation

0

Execution Fee

0.00306 FLOW

Transaction Summary

Deploy

Contract deployment

Contract deployment

Script Arguments

0nameString
DCATransactionHandlerV2Loop
1codeString
import FlowTransactionScheduler from 0xe467b9dd11fa00df import FlowTransactionSchedulerUtils from 0xe467b9dd11fa00df import DCAControllerV2 from 0xca7ee55e4fc3251a import DCAPlanV2 from 0xca7ee55e4fc3251a import FungibleToken from 0xf233dcee88fe0abe import FlowToken from 0x1654653399040a61 import SwapRouter from 0xa6850776a94e6551 import EVMVMBridgedToken_f1815bd50389c46847f0bda824ec8da914045d14 from 0x1e4aa0b87d10b141 /// DCATransactionHandlerV2Loop: Self-rescheduling DCA handler /// /// Follows the official CounterLoopTransactionHandler pattern: /// - feeProviderCap passed directly in data (not fetched from controller) /// - Minimal rescheduling logic /// - 8 imports (reduced from 9) access(all) contract DCATransactionHandlerV2Loop { /// Loop configuration - matches official scaffold pattern access(all) struct LoopConfig { access(all) let planId: UInt64 access(all) let intervalSeconds: UFix64 access(all) let schedulerManagerCap: Capability<auth(FlowTransactionSchedulerUtils.Owner) &{FlowTransactionSchedulerUtils.Manager}> access(all) let feeProviderCap: Capability<auth(FungibleToken.Withdraw) &FlowToken.Vault> access(all) let priority: FlowTransactionScheduler.Priority access(all) let executionEffort: UInt64 init( planId: UInt64, intervalSeconds: UFix64, schedulerManagerCap: Capability<auth(FlowTransactionSchedulerUtils.Owner) &{FlowTransactionSchedulerUtils.Manager}>, feeProviderCap: Capability<auth(FungibleToken.Withdraw) &FlowToken.Vault>, priority: FlowTransactionScheduler.Priority, executionEffort: UInt64 ) { self.planId = planId self.intervalSeconds = intervalSeconds self.schedulerManagerCap = schedulerManagerCap self.feeProviderCap = feeProviderCap self.priority = priority self.executionEffort = executionEffort } } access(all) event Executed( transactionId: UInt64, planId: UInt64, amountIn: UFix64, amountOut: UFix64, nextScheduled: Bool ) access(all) event Failed( transactionId: UInt64, planId: UInt64, reason: String ) /// Handler resource access(all) resource Handler: FlowTransactionScheduler.TransactionHandler { access(self) let controllerCap: Capability<auth(DCAControllerV2.Owner) &DCAControllerV2.Controller> init(controllerCap: Capability<auth(DCAControllerV2.Owner) &DCAControllerV2.Controller>) { self.controllerCap = controllerCap } access(FlowTransactionScheduler.Execute) fun executeTransaction(id: UInt64, data: AnyStruct?) { // 1. Parse loop config (official pattern) let config = data as! LoopConfig? ?? panic("LoopConfig required") // 2. Execute swap let swapResult = self.doSwap(planId: config.planId) if !swapResult.success { emit Failed(transactionId: id, planId: config.planId, reason: swapResult.error ?? "swap failed") return } // 3. Reschedule if plan still active (official pattern) var nextScheduled = false let controller = self.controllerCap.borrow() if controller != nil { let plan = controller!.borrowPlan(id: config.planId) if plan != nil && plan!.status == DCAPlanV2.PlanStatus.Active && !plan!.hasReachedMaxExecutions() { nextScheduled = self.reschedule(config: config, data: data!) } } emit Executed( transactionId: id, planId: config.planId, amountIn: swapResult.amountIn ?? 0.0, amountOut: swapResult.amountOut ?? 0.0, nextScheduled: nextScheduled ) } /// Execute the swap - simplified access(self) fun doSwap(planId: UInt64): SwapResult { let controller = self.controllerCap.borrow() ?? panic("No controller") let plan = controller.borrowPlan(id: planId) ?? panic("No plan") if !plan.isReadyForExecution() || plan.hasReachedMaxExecutions() { return SwapResult(success: false, amountIn: nil, amountOut: nil, error: "not ready") } let sourceVaultCap = controller.getSourceVaultCapability() ?? panic("no source") let targetVaultCap = controller.getTargetVaultCapability() ?? panic("no target") let sourceVault = sourceVaultCap.borrow() ?? panic("borrow source") let amountIn = plan.amountPerInterval if sourceVault.balance < amountIn { return SwapResult(success: false, amountIn: nil, amountOut: nil, error: "insufficient balance") } let tokensToSwap <- sourceVault.withdraw(amount: amountIn) // Build path let sourceTypeId = plan.sourceTokenType.identifier let targetTypeId = plan.targetTokenType.identifier let tokenPath: [String] = [] if sourceTypeId.contains("EVMVMBridgedToken") && targetTypeId.contains("FlowToken") { tokenPath.append("A.1e4aa0b87d10b141.EVMVMBridgedToken_f1815bd50389c46847f0bda824ec8da914045d14") tokenPath.append("A.1654653399040a61.FlowToken") } else if targetTypeId.contains("EVMVMBridgedToken") && sourceTypeId.contains("FlowToken") { tokenPath.append("A.1654653399040a61.FlowToken") tokenPath.append("A.1e4aa0b87d10b141.EVMVMBridgedToken_f1815bd50389c46847f0bda824ec8da914045d14") } else { destroy tokensToSwap return SwapResult(success: false, amountIn: nil, amountOut: nil, error: "unsupported pair") } let expectedOut = SwapRouter.getAmountsOut(amountIn: amountIn, tokenKeyPath: tokenPath) let minOut = expectedOut[expectedOut.length - 1] * (10000.0 - UFix64(plan.maxSlippageBps)) / 10000.0 let swapped <- SwapRouter.swapExactTokensForTokens( exactVaultIn: <-tokensToSwap, amountOutMin: minOut, tokenKeyPath: tokenPath, deadline: getCurrentBlock().timestamp + 300.0 ) let amountOut = swapped.balance let targetVault = targetVaultCap.borrow() ?? panic("borrow target") targetVault.deposit(from: <-swapped) // Record execution plan.recordExecution(amountIn: amountIn, amountOut: amountOut) plan.scheduleNextExecution() return SwapResult(success: true, amountIn: amountIn, amountOut: amountOut, error: nil) } /// Reschedule - follows official pattern exactly access(self) fun reschedule(config: LoopConfig, data: AnyStruct): Bool { let future = getCurrentBlock().timestamp + config.intervalSeconds let estimate = FlowTransactionScheduler.estimate( data: data, timestamp: future, priority: config.priority, executionEffort: config.executionEffort ) if estimate.timestamp == nil && config.priority != FlowTransactionScheduler.Priority.Low { return false } // Get fees from feeProviderCap (official pattern) let feeVault = config.feeProviderCap.borrow() ?? panic("fee provider") let fees <- feeVault.withdraw(amount: estimate.flowFee ?? 0.0) let manager = config.schedulerManagerCap.borrow() ?? panic("manager") manager.scheduleByHandler( handlerTypeIdentifier: self.getType().identifier, handlerUUID: self.uuid, data: data, timestamp: future, priority: config.priority, executionEffort: config.executionEffort, fees: <-fees as! @FlowToken.Vault ) return true } } access(all) struct SwapResult { access(all) let success: Bool access(all) let amountIn: UFix64? access(all) let amountOut: UFix64? access(all) let error: String? init(success: Bool, amountIn: UFix64?, amountOut: UFix64?, error: String?) { self.success = success self.amountIn = amountIn self.amountOut = amountOut self.error = error } } access(all) fun createHandler( controllerCap: Capability<auth(DCAControllerV2.Owner) &DCAControllerV2.Controller> ): @Handler { return <- create Handler(controllerCap: controllerCap) } access(all) fun createLoopConfig( planId: UInt64, intervalSeconds: UFix64, schedulerManagerCap: Capability<auth(FlowTransactionSchedulerUtils.Owner) &{FlowTransactionSchedulerUtils.Manager}>, feeProviderCap: Capability<auth(FungibleToken.Withdraw) &FlowToken.Vault>, priority: FlowTransactionScheduler.Priority, executionEffort: UInt64 ): LoopConfig { return LoopConfig( planId: planId, intervalSeconds: intervalSeconds, schedulerManagerCap: schedulerManagerCap, feeProviderCap: feeProviderCap, priority: priority, executionEffort: executionEffort ) } }

Cadence Script

1transaction(name: String, code: String ) {
2		prepare(signer: auth(AddContract) &Account) {
3			signer.contracts.add(name: name, code: code.utf8 )
4		}
5	}