1+ import " FlowTransactionScheduler"
2+ import " FlowTransactionSchedulerUtils"
3+ import " FungibleToken"
4+ import " FlowToken"
5+ import " FlowCron"
6+ import " FlowCreditMarketSupervisorV1"
7+
8+ transaction (
9+ cronExpression : String ,
10+ cronHandlerStoragePath : StoragePath ,
11+ keeperExecutionEffort : UInt64 ,
12+ executorExecutionEffort : UInt64 ,
13+ ) {
14+ let signer : auth (BorrowValue , IssueStorageCapabilityController , SaveValue ) &Account
15+ let feeProviderCap : Capability <auth (FungibleToken.Withdraw ) &FlowToken.Vault >
16+
17+ prepare (signer : auth (BorrowValue , IssueStorageCapabilityController , SaveValue ) &Account ) {
18+ self .feeProviderCap = signer .capabilities .storage .issue <auth (FungibleToken.Withdraw ) &FlowToken.Vault >(/storage/flowTokenVault )
19+ self .signer = signer
20+ }
21+
22+ execute {
23+ let supervisor <- FlowCreditMarketSupervisorV1 .createSupervisor ()
24+ self .signer .storage .save (<- supervisor , to : /storage/flowCreditMarketSupervisor )
25+ let wrappedHandlerCap =
26+ self .signer .capabilities .storage .issue <auth (FlowTransactionScheduler.Execute ) &{FlowTransactionScheduler .TransactionHandler }
27+ >(/storage/flowCreditMarketSupervisor )
28+ assert (wrappedHandlerCap .check (), message : " Invalid wrapped handler capability" )
29+ self .signer .storage .save (<- FlowTransactionSchedulerUtils .createManager (), to : FlowTransactionSchedulerUtils .managerStoragePath )
30+ let schedulerManagerCap : Capability <auth (FlowTransactionSchedulerUtils.Owner ) &{FlowTransactionSchedulerUtils .Manager }> = self .signer .capabilities .storage .issue <auth (FlowTransactionSchedulerUtils.Owner ) &{FlowTransactionSchedulerUtils .Manager }>(
31+ FlowTransactionSchedulerUtils .managerStoragePath
32+ )
33+ let manager = self .signer .storage .borrow <auth (FlowTransactionSchedulerUtils.Owner ) &{FlowTransactionSchedulerUtils .Manager }>(
34+ from : FlowTransactionSchedulerUtils .managerStoragePath
35+ ) ?? panic (" Cannot borrow manager" )
36+ assert (schedulerManagerCap .check (), message : " Invalid scheduler manager capability" )
37+ let cronHandler <- FlowCron .createCronHandler (
38+ cronExpression : cronExpression ,
39+ wrappedHandlerCap : wrappedHandlerCap ,
40+ feeProviderCap : self .feeProviderCap ,
41+ schedulerManagerCap : schedulerManagerCap
42+ )
43+ self .signer .storage .save (<- cronHandler , to : cronHandlerStoragePath )
44+ let cronHandlerCap = self .signer .capabilities .storage .issue <auth (FlowTransactionScheduler.Execute ) &{FlowTransactionScheduler .TransactionHandler }>(cronHandlerStoragePath )
45+ assert (cronHandlerCap .check (), message : " Invalid cron handler capability" )
46+
47+ let executorEstimate = FlowTransactionScheduler .estimate (
48+ data : nil ,
49+ timestamp : UFix64 (getCurrentBlock ().timestamp + 1.0 ),
50+ priority : FlowTransactionScheduler .Priority .Low ,
51+ executionEffort : executorExecutionEffort
52+ )
53+
54+ let executorFee = executorEstimate .flowFee ! * 2.0
55+
56+ let keeperEstimate = FlowTransactionScheduler .estimate (
57+ data : nil ,
58+ timestamp : UFix64 (getCurrentBlock ().timestamp + 2.0 ),
59+ priority : FlowTransactionScheduler .Priority .Low ,
60+ executionEffort : keeperExecutionEffort
61+ )
62+
63+ let keeperFee = keeperEstimate .flowFee ! * 2.0
64+
65+ let totalFee = executorFee + keeperFee
66+
67+ // Borrow fee vault and check balance
68+ let feeVault = self .signer .storage .borrow <auth (FungibleToken.Withdraw ) &FlowToken.Vault >(from : /storage/flowTokenVault )
69+ ?? panic (" Flow token vault not found" )
70+
71+ if feeVault .balance < totalFee {
72+ panic (" Insufficient funds: required " .concat (totalFee .toString ()).concat (" FLOW (executor: " ).concat (executorFee .toString ()).concat (" , keeper: " ).concat (keeperFee .toString ()).concat (" ), available " ).concat (feeVault .balance .toString ()))
73+ }
74+
75+ // Withdraw fees for BOTH transactions
76+ let executorFees <- feeVault .withdraw (amount : executorFee ) as ! @FlowToken.Vault
77+ let keeperFees <- feeVault .withdraw (amount : keeperFee ) as ! @FlowToken.Vault
78+
79+ let executorContext = FlowCron .CronContext (
80+ executionMode : FlowCron .ExecutionMode .Executor ,
81+ executorPriority : FlowTransactionScheduler .Priority .Low ,
82+ executorExecutionEffort : executorExecutionEffort ,
83+ keeperExecutionEffort : keeperExecutionEffort ,
84+ wrappedData : nil
85+ )
86+
87+ let executorTxID = manager .schedule (
88+ handlerCap : cronHandlerCap ,
89+ data : executorContext ,
90+ timestamp : UFix64 (getCurrentBlock ().timestamp + 1.0 ),
91+ priority : FlowTransactionScheduler .Priority .Low ,
92+ executionEffort : executorExecutionEffort ,
93+ fees : <- executorFees
94+ )
95+
96+
97+ let keeperContext = FlowCron .CronContext (
98+ executionMode : FlowCron .ExecutionMode .Keeper ,
99+ executorPriority : FlowTransactionScheduler .Priority .Low ,
100+ executorExecutionEffort : executorExecutionEffort ,
101+ keeperExecutionEffort : keeperExecutionEffort ,
102+ wrappedData : nil
103+ )
104+
105+ // Schedule KEEPER transaction (1 second after executor to prevent race conditions)
106+ let keeperTxID = manager .schedule (
107+ handlerCap : cronHandlerCap ,
108+ data : keeperContext ,
109+ timestamp : UFix64 (getCurrentBlock ().timestamp + 2.0 ),
110+ priority : FlowCron .keeperPriority ,
111+ executionEffort : keeperExecutionEffort ,
112+ fees : <- keeperFees
113+ )
114+ }
115+ }
0 commit comments