diff --git a/flow/accounts/add-contract/add.go b/flow/accounts/add-contract/add.go index a69fef03b..96b9885e4 100644 --- a/flow/accounts/add-contract/add.go +++ b/flow/accounts/add-contract/add.go @@ -66,11 +66,10 @@ var Cmd = &cobra.Command{ }, ) - cli.PrepareAndSendTransaction( + cli.SendTransaction( projectConf.HostWithOverride(conf.Host), signerAccount, tx, - signerAccount.Address, conf.Results, ) }, diff --git a/flow/accounts/create/create.go b/flow/accounts/create/create.go index 4c733bcd0..a94f7efe5 100644 --- a/flow/accounts/create/create.go +++ b/flow/accounts/create/create.go @@ -100,13 +100,7 @@ var Cmd = &cobra.Command{ tx := templates.CreateAccount(accountKeys, contracts, signerAccount.Address) - cli.PrepareAndSendTransaction( - projectConf.HostWithOverride(conf.Host), - signerAccount, - tx, - signerAccount.Address, - conf.Results, - ) + cli.SendTransaction(projectConf.HostWithOverride(conf.Host), signerAccount, tx, conf.Results) }, } diff --git a/flow/accounts/update-contract/update.go b/flow/accounts/update-contract/update.go index 9a42e5511..789e004cf 100644 --- a/flow/accounts/update-contract/update.go +++ b/flow/accounts/update-contract/update.go @@ -66,11 +66,10 @@ var Cmd = &cobra.Command{ }, ) - cli.PrepareAndSendTransaction( + cli.SendTransaction( projectConf.HostWithOverride(conf.Host), signerAccount, tx, - signerAccount.Address, conf.Results, ) }, diff --git a/flow/send.go b/flow/send.go index 6f6961a76..3a86601c8 100644 --- a/flow/send.go +++ b/flow/send.go @@ -27,15 +27,7 @@ import ( "google.golang.org/grpc" ) -type SignerRole string - -const ( - SignerRoleAuthorizer SignerRole = "authorizer" - SignerRoleProposer SignerRole = "proposer" - SignerRolePayer SignerRole = "payer" -) - -func PrepareTransaction(host string, signerAccount *Account, tx *flow.Transaction, payer flow.Address) *flow.Transaction { +func SendTransaction(host string, signerAccount *Account, tx *flow.Transaction, withResults bool) { ctx := context.Background() flowClient, err := client.New(host, grpc.WithInsecure()) @@ -62,21 +54,13 @@ func PrepareTransaction(host string, signerAccount *Account, tx *flow.Transactio tx.SetReferenceBlockID(sealed.ID). SetProposalKey(signerAddress, accountKey.Index, accountKey.SequenceNumber). - SetPayer(payer) - - return tx -} - -func SendTransaction(host string, signerAccount *Account, tx *flow.Transaction, withResults bool) { - ctx := context.Background() + SetPayer(signerAddress) - flowClient, err := client.New(host, grpc.WithInsecure()) + err = tx.SignEnvelope(signerAddress, accountKey.Index, signerAccount.Signer) if err != nil { - Exitf(1, "Failed to connect to host: %s", err) + Exitf(1, "Failed to sign transaction: %s", err) } - tx = signTransaction(ctx, flowClient, signerAccount, SignerRolePayer, tx) - fmt.Printf("Submitting transaction with ID %s ...\n", tx.ID()) err = flowClient.SendTransaction(context.Background(), *tx) @@ -93,51 +77,3 @@ func SendTransaction(host string, signerAccount *Account, tx *flow.Transaction, printTxResult(tx, res, true) } } - -func PrepareAndSendTransaction(host string, signerAccount *Account, tx *flow.Transaction, payer flow.Address, withResults bool) { - preparedTx := PrepareTransaction(host, signerAccount, tx, payer) - SendTransaction(host, signerAccount, preparedTx, withResults) -} - -func SignTransaction(host string, signerAccount *Account, signerRole SignerRole, tx *flow.Transaction) *flow.Transaction { - ctx := context.Background() - - flowClient, err := client.New(host, grpc.WithInsecure()) - if err != nil { - Exitf(1, "Failed to connect to host: %s", err) - } - - tx = signTransaction(ctx, flowClient, signerAccount, signerRole, tx) - return tx -} - -func signTransaction( - ctx context.Context, - flowClient *client.Client, - signerAccount *Account, - signerRole SignerRole, - tx *flow.Transaction, -) *flow.Transaction { - signerAddress := signerAccount.Address - account, err := flowClient.GetAccount(ctx, signerAddress) - if err != nil { - Exitf(1, "Failed to get account with address %s: %s", signerAddress.Hex(), err) - } - accountKey := account.Keys[signerAccount.KeyIndex] - switch signerRole { - case SignerRoleAuthorizer: - err := tx.SignPayload(signerAddress, accountKey.Index, signerAccount.Signer) - if err != nil { - Exitf(1, "Failed to sign transaction: %s", err) - } - case SignerRolePayer: - err := tx.SignEnvelope(signerAddress, accountKey.Index, signerAccount.Signer) - if err != nil { - Exitf(1, "Failed to sign transaction: %s", err) - } - default: - Exitf(1, "Failed to sign transaction: unknown signer role %s", signerRole) - } - - return tx -} diff --git a/flow/transactions/send/send.go b/flow/transactions/send/send.go index c4de3f208..ec3934736 100644 --- a/flow/transactions/send/send.go +++ b/flow/transactions/send/send.go @@ -19,7 +19,6 @@ package send import ( - "encoding/hex" "io/ioutil" "log" "os" @@ -34,7 +33,6 @@ import ( type Config struct { Args string `default:"" flag:"args" info:"arguments in JSON-Cadence format"` Code string `flag:"code,c" info:"path to Cadence file"` - Partial string `flag:"partial-tx" info:"path to Partial Transaction file"` Host string `flag:"host" info:"Flow Access API host address"` Signer string `default:"service" flag:"signer,s"` Results bool `default:"false" flag:"results" info:"Display the results of the transaction"` @@ -57,63 +55,39 @@ var Cmd = &cobra.Command{ validateKeyPreReq(signerAccount) var ( - tx *flow.Transaction code []byte err error ) - if conf.Partial != "" && conf.Code != "" { - cli.Exitf(1, "Both a partial transaction and Cadence code file provided, but cannot use both") - } else if conf.Partial != "" { - partialTxHex, err := ioutil.ReadFile(conf.Partial) + if conf.Code != "" { + code, err = ioutil.ReadFile(conf.Code) if err != nil { - cli.Exitf(1, "Failed to read partial transaction from %s: %v", conf.Partial, err) + cli.Exitf(1, "Failed to read transaction script from %s", conf.Code) } - partialTxBytes, err := hex.DecodeString(string(partialTxHex)) - if err != nil { - cli.Exitf(1, "Failed to decode partial transaction from %s: %v", conf.Partial, err) - } - tx, err = flow.DecodeTransaction(partialTxBytes) + } + + tx := flow. + NewTransaction(). + SetScript(code). + AddAuthorizer(signerAccount.Address) + + // Arguments + if conf.Args != "" { + transactionArguments, err := cli.ParseArguments(conf.Args) if err != nil { - cli.Exitf(1, "Failed to decode transaction from %s: %v", conf.Partial, err) - } - } else { - if conf.Code != "" { - code, err = ioutil.ReadFile(conf.Code) - if err != nil { - cli.Exitf(1, "Failed to read transaction script from %s: %v", conf.Code, err) - } + cli.Exitf(1, "Invalid arguments passed: %s", conf.Args) } - tx = flow.NewTransaction(). - SetScript(code). - AddAuthorizer(signerAccount.Address) + for _, arg := range transactionArguments { + err := tx.AddArgument(arg) - // Arguments - if conf.Args != "" { - transactionArguments, err := cli.ParseArguments(conf.Args) if err != nil { - cli.Exitf(1, "Invalid arguments passed: %s", conf.Args) - } - - for _, arg := range transactionArguments { - err := tx.AddArgument(arg) - - if err != nil { - cli.Exitf(1, "Failed to add %s argument to a transaction ", conf.Code) - } + cli.Exitf(1, "Failed to add %s argument to a transaction ", conf.Code) } } - - tx = cli.PrepareTransaction(projectConf.HostWithOverride(conf.Host), signerAccount, tx, signerAccount.Address) } - cli.SendTransaction( - projectConf.HostWithOverride(conf.Host), - signerAccount, - tx, - conf.Results, - ) + cli.SendTransaction(projectConf.HostWithOverride(conf.Host), signerAccount, tx, conf.Results) }, } diff --git a/flow/transactions/sign/sign.go b/flow/transactions/sign/sign.go deleted file mode 100644 index 6eff1f81d..000000000 --- a/flow/transactions/sign/sign.go +++ /dev/null @@ -1,163 +0,0 @@ -/* - * Flow CLI - * - * Copyright 2019-2020 Dapper Labs, Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package sign - -import ( - "fmt" - "io/ioutil" - "log" - "os" - "strings" - - "github.com/onflow/flow-go-sdk" - "github.com/psiemens/sconfig" - "github.com/spf13/cobra" - - cli "github.com/onflow/flow-cli/flow" -) - -type Config struct { - Args string `default:"" flag:"args" info:"arguments in JSON-Cadence format"` - Signer string `default:"service" flag:"signer,s"` - Role string `default:"authorizer" flag:"role"` - AdditionalAuthorizers []string `flag:"additional-authorizers" info:"Additional authorizer addresses to add to the transaction"` - PayerAddress string `flag:"payer" info:"Specify payer of the transaction. Defaults to current signer."` - Code string `flag:"code,c" info:"path to Cadence file"` - Host string `flag:"host" info:"Flow Access API host address"` - Encoding string `default:"hexrlp" flag:"encoding" info:"Encoding to use for transactio (rlp)"` - Output string `default:"" flag:"output,o" info:"Output location for transaction file"` -} - -var conf Config - -var Cmd = &cobra.Command{ - Use: "sign", - Short: "Sign a transaction", - Run: func(cmd *cobra.Command, args []string) { - projectConf := cli.LoadConfig() - - signerAccount := projectConf.Accounts[conf.Signer] - validateKeyPreReq(signerAccount) - var ( - code []byte - payer flow.Address - err error - ) - - if conf.Code != "" { - code, err = ioutil.ReadFile(conf.Code) - if err != nil { - cli.Exitf(1, "Failed to read transaction script from %s", conf.Code) - } - } - - if conf.PayerAddress != "" { - payer = flow.HexToAddress(conf.PayerAddress) - } else { - payer = signerAccount.Address - } - - tx := flow.NewTransaction(). - SetScript(code) - - // Arguments - if conf.Args != "" { - transactionArguments, err := cli.ParseArguments(conf.Args) - if err != nil { - cli.Exitf(1, "Invalid arguments passed: %s", conf.Args) - } - - for _, arg := range transactionArguments { - err := tx.AddArgument(arg) - - if err != nil { - cli.Exitf(1, "Failed to add %s argument to a transaction ", conf.Code) - } - } - } - - signerRole := cli.SignerRole(conf.Role) - switch signerRole { - case cli.SignerRoleAuthorizer: - tx.AddAuthorizer(signerAccount.Address) - case cli.SignerRolePayer: - if payer != signerAccount.Address { - cli.Exitf(1, "Role specified as Payer, but Payer address also provided, and different: %s !=", payer, signerAccount.Address) - } - case cli.SignerRoleProposer: - cli.Exitf(1, "Proposer role not yet supported: %s", conf.Role) - default: - cli.Exitf(1, "unknown role %s", conf.Role) - } - - for _, authorizerString := range conf.AdditionalAuthorizers { - authorizerAddress := flow.HexToAddress(authorizerString) - tx.AddAuthorizer(authorizerAddress) - } - - cli.PrepareTransaction(projectConf.HostWithOverride(conf.Host), signerAccount, tx, payer) - - tx = cli.SignTransaction(projectConf.HostWithOverride(conf.Host), signerAccount, signerRole, tx) - - fmt.Printf("%s encoded transaction written to %s\n", conf.Encoding, conf.Output) - - output := fmt.Sprintf("%x", tx.Encode()) - if len(strings.TrimSpace(conf.Output)) == 0 { - fmt.Println(output) - return - } - err = ioutil.WriteFile(conf.Output, []byte(output), os.ModePerm) - if err != nil { - cli.Exitf(1, "Failed to save encoded transaction to file %s", conf.Output) - } - }, -} - -func init() { - initConfig() -} - -func initConfig() { - err := sconfig.New(&conf). - FromEnvironment(cli.EnvPrefix). - BindFlags(Cmd.PersistentFlags()). - Parse() - if err != nil { - log.Fatal(err) - } -} - -func validateKeyPreReq(account *cli.Account) { - if account.KeyType == cli.KeyTypeHex { - // Always Valid - return - } else if account.KeyType == cli.KeyTypeKMS { - // Check GOOGLE_APPLICATION_CREDENTIALS - googleAppCreds := os.Getenv("GOOGLE_APPLICATION_CREDENTIALS") - if len(googleAppCreds) == 0 { - if len(account.KeyContext["projectId"]) == 0 { - cli.Exitf(1, "Could not get GOOGLE_APPLICATION_CREDENTIALS, no google service account json provided but private key type is KMS", account.Address) - } - cli.GcloudApplicationSignin(account.KeyContext["projectId"]) - } - return - } - cli.Exitf(1, "Failed to validate %s key for %s", account.KeyType, account.Address) - -} diff --git a/flow/transactions/transactions.go b/flow/transactions/transactions.go index 03565b2f2..c0ff5c95f 100644 --- a/flow/transactions/transactions.go +++ b/flow/transactions/transactions.go @@ -22,7 +22,6 @@ import ( "github.com/spf13/cobra" "github.com/onflow/flow-cli/flow/transactions/send" - "github.com/onflow/flow-cli/flow/transactions/sign" "github.com/onflow/flow-cli/flow/transactions/status" ) @@ -34,6 +33,5 @@ var Cmd = &cobra.Command{ func init() { Cmd.AddCommand(send.Cmd) - Cmd.AddCommand(sign.Cmd) Cmd.AddCommand(status.Cmd) }