Skip to content

Commit 02a84b3

Browse files
authored
Merge pull request #2130 from onflow/cf/setup-tx
Add tx for Scheduled Transaction manager `setup` command
2 parents e71297c + c0987c0 commit 02a84b3

File tree

3 files changed

+169
-13
lines changed

3 files changed

+169
-13
lines changed

internal/schedule/contracts.go

Lines changed: 68 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,68 @@
1+
/*
2+
* Flow CLI
3+
*
4+
* Copyright Flow Foundation
5+
*
6+
* Licensed under the Apache License, Version 2.0 (the "License");
7+
* you may not use this file except in compliance with the License.
8+
* You may obtain a copy of the License at
9+
*
10+
* http://www.apache.org/licenses/LICENSE-2.0
11+
*
12+
* Unless required by applicable law or agreed to in writing, software
13+
* distributed under the License is distributed on an "AS IS" BASIS,
14+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15+
* See the License for the specific language governing permissions and
16+
* limitations under the License.
17+
*/
18+
19+
package schedule
20+
21+
import (
22+
"fmt"
23+
24+
flowsdk "github.com/onflow/flow-go-sdk"
25+
)
26+
27+
// ContractName represents a scheduler-related contract name
28+
type ContractName string
29+
30+
const (
31+
// FlowTransactionSchedulerUtils contract provides utility functions for transaction scheduling
32+
FlowTransactionSchedulerUtils ContractName = "FlowTransactionSchedulerUtils"
33+
// FlowTransactionScheduler contract handles the core transaction scheduling logic
34+
FlowTransactionScheduler ContractName = "FlowTransactionScheduler"
35+
)
36+
37+
// contractAddresses maps contract names to their addresses on different networks
38+
var contractAddresses = map[ContractName]map[flowsdk.ChainID]string{
39+
FlowTransactionSchedulerUtils: {
40+
flowsdk.Emulator: "0xf8d6e0586b0a20c7",
41+
flowsdk.Testnet: "0x8c5303eaa26202d6",
42+
},
43+
FlowTransactionScheduler: {
44+
flowsdk.Emulator: "0xf8d6e0586b0a20c7",
45+
flowsdk.Testnet: "0x8c5303eaa26202d6",
46+
},
47+
}
48+
49+
// getContractAddress returns the contract address for the given contract name and network
50+
func getContractAddress(contract ContractName, chainID flowsdk.ChainID) (string, error) {
51+
// Check if mainnet
52+
if chainID == flowsdk.Mainnet {
53+
return "", fmt.Errorf("transaction scheduling is not yet supported on mainnet")
54+
}
55+
56+
// Look up the contract address
57+
networkAddresses, contractExists := contractAddresses[contract]
58+
if !contractExists {
59+
return "", fmt.Errorf("unknown contract: %s", contract)
60+
}
61+
62+
contractAddress, networkSupported := networkAddresses[chainID]
63+
if !networkSupported {
64+
return "", fmt.Errorf("contract %s is not available on network %s", contract, chainID)
65+
}
66+
67+
return contractAddress, nil
68+
}

internal/schedule/setup.go

Lines changed: 87 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -19,13 +19,18 @@
1919
package schedule
2020

2121
import (
22+
"context"
2223
"fmt"
2324

25+
flowsdk "github.com/onflow/flow-go-sdk"
2426
"github.com/spf13/cobra"
2527

2628
"github.com/onflow/flowkit/v2"
29+
"github.com/onflow/flowkit/v2/accounts"
2730
"github.com/onflow/flowkit/v2/output"
31+
"github.com/onflow/flowkit/v2/transactions"
2832

33+
"github.com/onflow/flow-cli/common/branding"
2934
"github.com/onflow/flow-cli/internal/command"
3035
"github.com/onflow/flow-cli/internal/util"
3136
)
@@ -74,35 +79,104 @@ func setupRun(
7479

7580
address := signer.Address
7681

77-
// Log network and account information
78-
logger.Info(fmt.Sprintf("Network: %s", globalFlags.Network))
79-
logger.Info(fmt.Sprintf("Signer: %s (%s)", setupFlags.Signer, address.String()))
80-
logger.Info("Setting up Flow Transaction Scheduler Manager resource...")
82+
chainID, err := util.NetworkToChainID(globalFlags.Network)
83+
if err != nil {
84+
return nil, err
85+
}
86+
87+
// Check if network is supported
88+
if chainID == flowsdk.Mainnet {
89+
return nil, fmt.Errorf("transaction scheduling is not yet supported on mainnet")
90+
}
91+
92+
contractAddress, err := getContractAddress(FlowTransactionSchedulerUtils, chainID)
93+
if err != nil {
94+
return nil, err
95+
}
96+
97+
// Log setup information with styled output
98+
networkStr := branding.GrayStyle.Render(globalFlags.Network)
99+
addressStr := branding.PurpleStyle.Render(address.HexWithPrefix())
100+
signerStr := branding.GrayStyle.Render(setupFlags.Signer)
101+
102+
logger.Info(fmt.Sprintf("🌐 Network: %s", networkStr))
103+
logger.Info(fmt.Sprintf("📝 Signer: %s (%s)", signerStr, addressStr))
104+
logger.Info("")
105+
logger.Info("⚡ Setting up Transaction Scheduler Manager...")
106+
107+
// Transaction checks if manager exists and only creates it if needed
108+
setupTx := fmt.Sprintf(`import FlowTransactionSchedulerUtils from %s
109+
110+
transaction() {
111+
prepare(signer: auth(BorrowValue, SaveValue) &Account) {
112+
// Check if Manager already exists
113+
if signer.storage.borrow<&{FlowTransactionSchedulerUtils.Manager}>(from: FlowTransactionSchedulerUtils.managerStoragePath) == nil {
114+
// Create and save Manager
115+
signer.storage.save(
116+
<-FlowTransactionSchedulerUtils.createManager(),
117+
to: FlowTransactionSchedulerUtils.managerStoragePath
118+
)
119+
}
120+
}
121+
}`, contractAddress)
122+
123+
_, txResult, err := flow.SendTransaction(
124+
context.Background(),
125+
transactions.AccountRoles{
126+
Proposer: *signer,
127+
Authorizers: []accounts.Account{*signer},
128+
Payer: *signer,
129+
},
130+
flowkit.Script{
131+
Code: []byte(setupTx),
132+
Args: nil,
133+
},
134+
1000,
135+
)
136+
137+
if err != nil {
138+
return nil, fmt.Errorf("failed to setup transaction scheduler: %w", err)
139+
}
140+
141+
if txResult.Error != nil {
142+
return nil, fmt.Errorf("setup transaction failed: %s", txResult.Error.Error())
143+
}
144+
145+
// Log success with styled output
146+
logger.Info("")
147+
successIcon := branding.GreenStyle.Render("✅")
148+
successMsg := branding.GreenStyle.Render("Transaction Scheduler Manager is setup")
149+
logger.Info(fmt.Sprintf("%s %s", successIcon, successMsg))
81150

82-
// TODO: Implement setup logic for Transaction Scheduler Manager resource
151+
logger.Info("")
152+
noteIcon := branding.GrayStyle.Render("📝")
153+
noteText := branding.GrayStyle.Render("Note: If the manager already existed, no changes were made")
154+
logger.Info(fmt.Sprintf("%s %s", noteIcon, noteText))
83155

84156
return &setupResult{
85-
success: true,
86-
message: "Transaction Scheduler Manager resource created successfully",
157+
success: true,
158+
transactionID: txResult.TransactionID.String(),
87159
}, nil
88160
}
89161

90162
type setupResult struct {
91-
success bool
92-
message string
163+
success bool
164+
transactionID string
93165
}
94166

95167
func (r *setupResult) JSON() any {
96168
return map[string]any{
97-
"success": r.success,
98-
"message": r.message,
169+
"success": r.success,
170+
"transactionID": r.transactionID,
171+
"message": "Transaction Scheduler Manager is ready",
99172
}
100173
}
101174

102175
func (r *setupResult) String() string {
103-
return r.message
176+
// Return empty string since we already logged everything in the command
177+
return ""
104178
}
105179

106180
func (r *setupResult) Oneliner() string {
107-
return r.message
181+
return "Transaction Scheduler Manager is ready"
108182
}

internal/util/util.go

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -224,6 +224,20 @@ func GetAddressNetwork(address flow.Address) (flow.ChainID, error) {
224224
return "", fmt.Errorf("address not valid for any known chain: %s", address)
225225
}
226226

227+
// NetworkToChainID converts a network name string to a ChainID
228+
func NetworkToChainID(network string) (flow.ChainID, error) {
229+
switch network {
230+
case "mainnet":
231+
return flow.Mainnet, nil
232+
case "testnet":
233+
return flow.Testnet, nil
234+
case "emulator":
235+
return flow.Emulator, nil
236+
default:
237+
return "", fmt.Errorf("unknown network: %s", network)
238+
}
239+
}
240+
227241
func CreateTabWriter(b *bytes.Buffer) *tabwriter.Writer {
228242
return tabwriter.NewWriter(b, 0, 8, 1, '\t', tabwriter.AlignRight)
229243
}

0 commit comments

Comments
 (0)