From bc095b5b532881173ee9946e335e4500afb724a1 Mon Sep 17 00:00:00 2001 From: Gregor Gololicic Date: Tue, 30 Mar 2021 20:05:42 +0200 Subject: [PATCH 001/137] added gateway send, sign, prepare tx methods --- pkg/flowcli/gateway/gateway.go | 3 ++- pkg/flowcli/gateway/grpc.go | 40 ++++++++++++++++++---------------- 2 files changed, 23 insertions(+), 20 deletions(-) diff --git a/pkg/flowcli/gateway/gateway.go b/pkg/flowcli/gateway/gateway.go index e834979d0..c48352be5 100644 --- a/pkg/flowcli/gateway/gateway.go +++ b/pkg/flowcli/gateway/gateway.go @@ -27,7 +27,8 @@ import ( type Gateway interface { GetAccount(flow.Address) (*flow.Account, error) - SendTransaction(*flow.Transaction, *project.Account) (*flow.Transaction, error) + SendTransaction(*project.Transaction) (*flow.Transaction, error) + PrepareTransactionPayload(*project.Transaction) (*project.Transaction, error) GetTransactionResult(*flow.Transaction, bool) (*flow.TransactionResult, error) GetTransaction(flow.Identifier) (*flow.Transaction, error) ExecuteScript([]byte, []cadence.Value) (cadence.Value, error) diff --git a/pkg/flowcli/gateway/grpc.go b/pkg/flowcli/gateway/grpc.go index 3bdf9f39b..c98cbfd22 100644 --- a/pkg/flowcli/gateway/grpc.go +++ b/pkg/flowcli/gateway/grpc.go @@ -30,6 +30,10 @@ import ( "google.golang.org/grpc" ) +const ( + defaultGasLimit = 1000 +) + // GrpcGateway contains all functions that need flow client to execute type GrpcGateway struct { client *client.Client @@ -61,37 +65,35 @@ func (g *GrpcGateway) GetAccount(address flow.Address) (*flow.Account, error) { return account, nil } -// TODO: replace with txsender - much nicer implemented -// SendTransaction send a transaction to flow -func (g *GrpcGateway) SendTransaction(tx *flow.Transaction, signer *project.Account) (*flow.Transaction, error) { - account, err := g.GetAccount(signer.Address()) +// PrepareTransactionPayload prepares the payload for the transaction from the network +func (g *GrpcGateway) PrepareTransactionPayload(tx *project.Transaction) (*project.Transaction, error) { + signerAddress := tx.Signer().Address() + account, err := g.GetAccount(signerAddress) if err != nil { - return nil, fmt.Errorf("Failed to get account with address %s: 0x%s", signer.Address(), err) + return nil, err } - // Default 0, i.e. first key - accountKey := account.Keys[0] + accountKey := account.Keys[tx.Signer().DefaultKey().Index()] sealed, err := g.client.GetLatestBlockHeader(g.ctx, true) if err != nil { return nil, fmt.Errorf("Failed to get latest sealed block: %s", err) } - tx.SetReferenceBlockID(sealed.ID). - SetProposalKey(signer.Address(), accountKey.Index, accountKey.SequenceNumber). - SetPayer(signer.Address()) + tx.FlowTransaction(). + SetReferenceBlockID(sealed.ID). + SetGasLimit(defaultGasLimit). + SetProposalKey(signerAddress, accountKey.Index, accountKey.SequenceNumber). + SetPayer(signerAddress) - sig, err := signer.DefaultKey().Signer(g.ctx) - if err != nil { - return nil, err - } + return tx, nil +} - err = tx.SignEnvelope(signer.Address(), accountKey.Index, sig) - if err != nil { - return nil, fmt.Errorf("Failed to sign transaction: %s", err) - } +// SendSignedTransaction sends a transaction to flow that is already prepared and signed +func (g *GrpcGateway) SendSignedTransaction(transaction *project.Transaction) (*flow.Transaction, error) { + tx := transaction.FlowTransaction() - err = g.client.SendTransaction(g.ctx, *tx) + err := g.client.SendTransaction(g.ctx, *tx) if err != nil { return nil, fmt.Errorf("Failed to submit transaction: %s", err) } From d223a968280dd94370b2230cd201bb0fc1ee7f0c Mon Sep 17 00:00:00 2001 From: Gregor Gololicic Date: Tue, 30 Mar 2021 20:06:22 +0200 Subject: [PATCH 002/137] add transaction model with extracted functionality from services --- pkg/flowcli/project/transaction.go | 187 +++++++++++++++++++++++++++++ 1 file changed, 187 insertions(+) create mode 100644 pkg/flowcli/project/transaction.go diff --git a/pkg/flowcli/project/transaction.go b/pkg/flowcli/project/transaction.go new file mode 100644 index 000000000..e66feac8e --- /dev/null +++ b/pkg/flowcli/project/transaction.go @@ -0,0 +1,187 @@ +package project + +import ( + "context" + "encoding/hex" + "fmt" + "io/ioutil" + + "github.com/onflow/flow-cli/pkg/flowcli" + + "github.com/onflow/cadence" + "github.com/onflow/flow-go-sdk" + + "github.com/onflow/flow-cli/pkg/flowcli/util" +) + +type signerRole string + +const ( + SignerRoleAuthorizer signerRole = "authorizer" + SignerRoleProposer signerRole = "proposer" + SignerRolePayer signerRole = "payer" +) + +func NewTransaction() *Transaction { + return &Transaction{ + tx: flow.NewTransaction(), + } +} + +type Transaction struct { + signer *Account + role signerRole + proposer *Account + payer flow.Address + tx *flow.Transaction +} + +func (t *Transaction) Signer() *Account { + return t.signer +} + +func (t *Transaction) FlowTransaction() *flow.Transaction { + return t.tx +} + +func (t *Transaction) SetPayloadFromFile(filename string) error { + partialTxHex, err := ioutil.ReadFile(filename) + if err != nil { + return fmt.Errorf("failed to read partial transaction from %s: %v", filename, err) + } + partialTxBytes, err := hex.DecodeString(string(partialTxHex)) + if err != nil { + return fmt.Errorf("failed to decode partial transaction from %s: %v", filename, err) + } + tx, err := flow.DecodeTransaction(partialTxBytes) + if err != nil { + return fmt.Errorf("failed to decode transaction from %s: %v", filename, err) + } + + t.tx = tx + return nil +} + +func (t *Transaction) SetScriptWithArgsFromFile(filepath string, args []string, argsJSON string) error { + script, err := util.LoadFile(filepath) + if err != nil { + return err + } + + t.tx.SetScript(script) + return t.AddRawArguments(args, argsJSON) +} + +func (t *Transaction) SetSigner(account *Account) error { + err := account.ValidateKey() + if err != nil { + return err + } + + t.signer = account + return nil +} + +func (t *Transaction) SetProposer(account *Account) error { + err := account.ValidateKey() + if err != nil { + return err + } + + t.proposer = account + return nil +} + +func (t *Transaction) SetPayer(address flow.Address) { + t.payer = address +} + +func (t *Transaction) AddRawArguments(args []string, argsJSON string) error { + txArguments, err := flowcli.ParseArguments(args, argsJSON) + if err != nil { + return err + } + + return t.AddArguments(txArguments) +} + +func (t *Transaction) AddArguments(args []cadence.Value) error { + for _, arg := range args { + err := t.AddArgument(arg) + if err != nil { + return err + } + } + + return nil +} + +func (t *Transaction) AddArgument(arg cadence.Value) error { + return t.tx.AddArgument(arg) +} + +func (t *Transaction) AddAuthorizers(addresses []string) error { + for _, address := range addresses { + err := t.AddAuthorizer(address) + if err != nil { // return error even if one breaks + return err + } + } + + return nil +} + +func (t *Transaction) AddAuthorizer(address string) error { + authorizerAddress := flow.HexToAddress(address) + if authorizerAddress == flow.EmptyAddress { + return fmt.Errorf("invalid authorizer address provided %s", address) + } + + t.tx.AddAuthorizer(authorizerAddress) + return nil +} + +func (t *Transaction) SignerRole(role string) error { + t.role = signerRole(role) + + switch t.role { + case SignerRoleAuthorizer: // Ignored if we're loading from a tx payload + err := t.AddAuthorizer(t.signer.Address().String()) + if err != nil { + return err + } + case SignerRolePayer: + if t.payer != t.signer.Address() { + return fmt.Errorf("role specified as Payer, but Payer address also provided, and different: %s != %s", t.payer, t.signer.Address()) + } + case SignerRoleProposer: // Just sign payload, no special actions needed + default: + return fmt.Errorf("unknown role %s", role) + } + + return nil +} + +func (t *Transaction) Sign() (*Transaction, error) { + keyIndex := t.signer.DefaultKey().Index() + signerAddress := t.signer.Address() + signer, err := t.signer.DefaultKey().Signer(context.Background()) + if err != nil { + return nil, err + } + + switch t.role { + case SignerRoleAuthorizer, SignerRoleProposer: + err := t.tx.SignPayload(signerAddress, keyIndex, signer) + if err != nil { + return nil, fmt.Errorf("failed to sign transaction: %s", err) + } + case SignerRolePayer: + err := t.tx.SignEnvelope(signerAddress, keyIndex, signer) + if err != nil { + return nil, fmt.Errorf("failed to sign transaction: %s", err) + } + } + + return t, nil +} From a204dadcbcc1f0a80e06b3b069c8b26601008a41 Mon Sep 17 00:00:00 2001 From: Gregor Gololicic Date: Tue, 30 Mar 2021 20:06:38 +0200 Subject: [PATCH 003/137] show error as part of result if present --- internal/transactions/transactions.go | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/internal/transactions/transactions.go b/internal/transactions/transactions.go index 816b58070..df1949ac5 100644 --- a/internal/transactions/transactions.go +++ b/internal/transactions/transactions.go @@ -52,6 +52,7 @@ func (r *TransactionResult) JSON() interface{} { result := make(map[string]string) result["Hash"] = r.tx.ID().String() result["Status"] = r.result.Status.String() + result["Error"] = r.result.Error.Error() if r.result != nil { result["Events"] = fmt.Sprintf("%s", r.result.Events) @@ -69,10 +70,14 @@ func (r *TransactionResult) String() string { fmt.Fprintf(writer, "Status\t %s\n", r.result.Status) fmt.Fprintf(writer, "Payer\t %s\n", r.tx.Payer.Hex()) - events := events.EventResult{ + if r.result.Error != nil { + fmt.Fprintf(writer, "\n❌ Transaction Error \n%s\n", r.result.Error.Error()) + } + + e := events.EventResult{ Events: r.result.Events, } - fmt.Fprintf(writer, "Events\t %s\n", events.String()) + fmt.Fprintf(writer, "Events\t %s\n", e.String()) if r.code { fmt.Fprintf(writer, "Code\n\n%s\n", r.tx.Script) From 555d9f98a2b4a4b453e5fdfa7cdbacba0403552d Mon Sep 17 00:00:00 2001 From: Gregor Gololicic Date: Tue, 30 Mar 2021 20:06:55 +0200 Subject: [PATCH 004/137] implement new function in send --- internal/transactions/send.go | 2 ++ 1 file changed, 2 insertions(+) diff --git a/internal/transactions/send.go b/internal/transactions/send.go index 82ff0b6ac..e057414ba 100644 --- a/internal/transactions/send.go +++ b/internal/transactions/send.go @@ -30,6 +30,7 @@ type flagsSend struct { ArgsJSON string `default:"" flag:"args-json" info:"arguments in JSON-Cadence format"` Args []string `default:"" flag:"arg" info:"argument in Type:Value format"` Signer string `default:"emulator-account" flag:"signer"` + Payload string `flag:"payload" info:"path to the transaction payload file"` Code string `default:"" flag:"code" info:"⚠️ DEPRECATED: use filename argument"` Results bool `default:"" flag:"results" info:"⚠️ DEPRECATED: all transactions will provide result"` } @@ -60,6 +61,7 @@ var SendCommand = &command.Command{ tx, result, err := services.Transactions.Send( args[0], // filename + sendFlags.Payload, sendFlags.Signer, sendFlags.Args, sendFlags.ArgsJSON, From f348fb43f8c2cbebd5cc01b550cf45c1a7559384 Mon Sep 17 00:00:00 2001 From: Gregor Gololicic Date: Tue, 30 Mar 2021 20:07:07 +0200 Subject: [PATCH 005/137] validate key as part of account --- pkg/flowcli/project/account.go | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/pkg/flowcli/project/account.go b/pkg/flowcli/project/account.go index ceae333dd..4d81d9a60 100644 --- a/pkg/flowcli/project/account.go +++ b/pkg/flowcli/project/account.go @@ -32,6 +32,18 @@ func (a *Account) SetDefaultKey(key AccountKey) { a.keys[0] = key } +func (a *Account) ValidateKey() error { + if a.DefaultKey().Type() == config.KeyTypeGoogleKMS { + resourceID := a.DefaultKey().ToConfig().Context[config.KMSContextField] + err := util.GcloudApplicationSignin(resourceID) + if err != nil { + return err + } + } + + return nil +} + func accountsFromConfig(conf *config.Config) ([]*Account, error) { accounts := make([]*Account, 0, len(conf.Accounts)) From 9a7119dbf1d809de38eb52e9ce5a7a7864491ce4 Mon Sep 17 00:00:00 2001 From: Gregor Gololicic Date: Tue, 30 Mar 2021 20:08:23 +0200 Subject: [PATCH 006/137] change gateway interface signature send signed --- pkg/flowcli/gateway/emulator.go | 2 +- pkg/flowcli/gateway/gateway.go | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/pkg/flowcli/gateway/emulator.go b/pkg/flowcli/gateway/emulator.go index 2e084cd57..31f6f34f7 100644 --- a/pkg/flowcli/gateway/emulator.go +++ b/pkg/flowcli/gateway/emulator.go @@ -50,7 +50,7 @@ func (g *EmulatorGateway) GetAccount(address flow.Address) (*flow.Account, error return g.emulator.GetAccount(address) } -func (g *EmulatorGateway) SendTransaction(tx *flow.Transaction, signer *project.Account) (*flow.Transaction, error) { +func (g *EmulatorGateway) SendSignedTransaction(tx *flow.Transaction, signer *project.Account) (*flow.Transaction, error) { return nil, fmt.Errorf("Not Supported Yet") } diff --git a/pkg/flowcli/gateway/gateway.go b/pkg/flowcli/gateway/gateway.go index c48352be5..f9cc5d044 100644 --- a/pkg/flowcli/gateway/gateway.go +++ b/pkg/flowcli/gateway/gateway.go @@ -27,7 +27,7 @@ import ( type Gateway interface { GetAccount(flow.Address) (*flow.Account, error) - SendTransaction(*project.Transaction) (*flow.Transaction, error) + SendSignedTransaction(*project.Transaction) (*flow.Transaction, error) PrepareTransactionPayload(*project.Transaction) (*project.Transaction, error) GetTransactionResult(*flow.Transaction, bool) (*flow.TransactionResult, error) GetTransaction(flow.Identifier) (*flow.Transaction, error) From 77e5ff69c71112580b4b7ce1ce1ee8441d8331fa Mon Sep 17 00:00:00 2001 From: Gregor Gololicic Date: Tue, 30 Mar 2021 21:33:10 +0200 Subject: [PATCH 007/137] refactor transaction service to use transaction model --- pkg/flowcli/services/transactions.go | 209 ++++++++++++++++++--------- 1 file changed, 140 insertions(+), 69 deletions(-) diff --git a/pkg/flowcli/services/transactions.go b/pkg/flowcli/services/transactions.go index 6905d261c..7659db096 100644 --- a/pkg/flowcli/services/transactions.go +++ b/pkg/flowcli/services/transactions.go @@ -22,13 +22,10 @@ import ( "fmt" "strings" - "github.com/onflow/flow-cli/pkg/flowcli" "github.com/onflow/flow-cli/pkg/flowcli/output" "github.com/onflow/flow-cli/pkg/flowcli/project" - "github.com/onflow/flow-cli/pkg/flowcli/config" "github.com/onflow/flow-cli/pkg/flowcli/gateway" - "github.com/onflow/flow-cli/pkg/flowcli/util" "github.com/onflow/flow-go-sdk" "github.com/onflow/flow-go-sdk/crypto" ) @@ -53,87 +50,140 @@ func NewTransactions( } } -// Send transaction -func (t *Transactions) Send( - transactionFilename string, - signerName string, - args []string, - argsJSON string, +// GetStatus of transaction +func (t *Transactions) GetStatus( + transactionID string, + waitSeal bool, ) (*flow.Transaction, *flow.TransactionResult, error) { - if t.project == nil { - return nil, nil, fmt.Errorf("missing configuration, initialize it: flow project init") - } + txID := flow.HexToID( + strings.ReplaceAll(transactionID, "0x", ""), + ) - signer := t.project.AccountByName(signerName) - if signer == nil { - return nil, nil, fmt.Errorf("signer account: [%s] doesn't exists in configuration", signerName) - } + t.logger.StartProgress("Fetching Transaction...") - code, err := util.LoadFile(transactionFilename) + tx, err := t.gateway.GetTransaction(txID) if err != nil { return nil, nil, err } - return t.send(code, signer, args, argsJSON) + if waitSeal { + t.logger.StartProgress("Waiting for transaction to be sealed...") + } + + result, err := t.gateway.GetTransactionResult(tx, waitSeal) + + t.logger.StopProgress("") + + return tx, result, err } -// SendForAddressWithCode send transaction for address and private key specified with code -func (t *Transactions) SendForAddressWithCode( - code []byte, - signerAddress string, - signerPrivateKey string, +// Sign transaction +func (t *Transactions) Sign( + signerName string, + proposerName string, + payerAddress string, + additionalAuthorizers []string, + role string, + scriptFilename string, + payloadFilename string, args []string, - argsJSON string, -) (*flow.Transaction, *flow.TransactionResult, error) { - address := flow.HexToAddress(signerAddress) + argsJSON string) (*project.Transaction, error) { + tx := project.NewTransaction() - privateKey, err := crypto.DecodePrivateKeyHex(crypto.ECDSA_P256, signerPrivateKey) - if err != nil { - return nil, nil, fmt.Errorf("private key is not correct") + if payloadFilename != "" && scriptFilename != "" { + return nil, fmt.Errorf("both a partial transaction and Cadence code file provided, but cannot use both") } - account := project.AccountFromAddressAndKey(address, privateKey) + if t.project == nil { + return nil, fmt.Errorf("missing configuration, initialize it: flow project init") + } - return t.send(code, account, args, argsJSON) -} + // get the signer account + signerAccount := t.project.AccountByName(signerName) + if signerAccount == nil { + return nil, fmt.Errorf("signer account: [%s] doesn't exists in configuration", signerName) + } -func (t *Transactions) send( - code []byte, - signer *project.Account, - args []string, - argsJSON string, -) (*flow.Transaction, *flow.TransactionResult, error) { + err := tx.SetSigner(signerAccount) + if err != nil { + return nil, err + } - // if google kms account then sign in TODO discuss refactor - move to account - if signer.DefaultKey().Type() == config.KeyTypeGoogleKMS { - resourceID := signer.DefaultKey().ToConfig().Context[config.KMSContextField] - err := util.GcloudApplicationSignin(resourceID) + if proposerName != "" { + proposerAccount := t.project.AccountByName(proposerName) + if proposerAccount == nil { + return nil, fmt.Errorf("proposer account: [%s] doesn't exists in configuration", signerName) + } + + err = tx.SetProposer(proposerAccount) if err != nil { - return nil, nil, err + return nil, err } } - t.logger.StartProgress("Sending Transaction...") - - tx := flow.NewTransaction(). - SetScript(code). - AddAuthorizer(signer.Address()) + if payerAddress != "" { + tx.SetPayer(flow.HexToAddress(payerAddress)) + } - transactionArguments, err := flowcli.ParseArguments(args, argsJSON) + err = tx.SignerRole(role) if err != nil { - return nil, nil, err + return nil, err } - for _, arg := range transactionArguments { - err := tx.AddArgument(arg) + if payloadFilename != "" { + err = tx.SetPayloadFromFile(payloadFilename) if err != nil { - return nil, nil, fmt.Errorf("failed to add %s argument to a transaction", arg) + return nil, err } + } else { + if scriptFilename != "" { + err = tx.SetScriptWithArgsFromFile(scriptFilename, args, argsJSON) + if err != nil { + return nil, err + } + } + + err = tx.AddAuthorizers(additionalAuthorizers) + if err != nil { + return nil, err + } + + tx, err = t.gateway.PrepareTransactionPayload(tx) + if err != nil { + return nil, err + } + } + + return tx.Sign() +} + +// Send transaction +func (t *Transactions) Send( + transactionFilename string, + payloadFilename string, + signerName string, + args []string, + argsJSON string, +) (*flow.Transaction, *flow.TransactionResult, error) { + + signed, err := t.Sign( + signerName, + "", + "", + []string{}, + "authorizer", + transactionFilename, + payloadFilename, + args, + argsJSON, + ) + if err != nil { + return nil, nil, err } - t.logger.Info(fmt.Sprintf("Sending transaction with ID %s", tx.ID())) + t.logger.StartProgress("Sending Transaction...") - tx, err = t.gateway.SendTransaction(tx, signer) + tx, err := t.gateway.SendSignedTransaction(signed) if err != nil { return nil, nil, err } @@ -147,29 +197,50 @@ func (t *Transactions) send( return tx, res, err } -// GetStatus of transaction -func (t *Transactions) GetStatus( - transactionID string, - waitSeal bool, +// SendForAddressWithCode send transaction for address and private key specified with code +func (t *Transactions) SendForAddressWithCode( + code []byte, + signerAddress string, + signerPrivateKey string, + args []string, + argsJSON string, ) (*flow.Transaction, *flow.TransactionResult, error) { - txID := flow.HexToID( - strings.ReplaceAll(transactionID, "0x", ""), - ) + address := flow.HexToAddress(signerAddress) - t.logger.StartProgress("Fetching Transaction...") + privateKey, err := crypto.DecodePrivateKeyHex(crypto.ECDSA_P256, signerPrivateKey) + if err != nil { + return nil, nil, fmt.Errorf("private key is not correct") + } - tx, err := t.gateway.GetTransaction(txID) + signer := project.AccountFromAddressAndKey(address, privateKey) + + tx := project.NewTransaction() + err = tx.SetSigner(signer) if err != nil { return nil, nil, err } - if waitSeal { - t.logger.StartProgress("Waiting for transaction to be sealed...") + err = tx.SetScriptWithArgs(code, args, argsJSON) + if err != nil { + return nil, nil, err } - result, err := t.gateway.GetTransactionResult(tx, waitSeal) + tx, err = tx.Sign() + if err != nil { + return nil, nil, err + } - t.logger.StopProgress("") + t.logger.StartProgress("Sending Transaction...") - return tx, result, err + sentTx, err := t.gateway.SendSignedTransaction(tx) + if err != nil { + return nil, nil, err + } + + t.logger.StartProgress("Waiting for transaction to be sealed...") + + res, err := t.gateway.GetTransactionResult(sentTx, true) + + t.logger.StopProgress("") + return sentTx, res, err } From 43f0e6c13910a5f6eef801c7c0a0218dea400ddd Mon Sep 17 00:00:00 2001 From: Gregor Gololicic Date: Tue, 30 Mar 2021 21:33:45 +0200 Subject: [PATCH 008/137] add templates for creating acc and contracts --- pkg/flowcli/project/transaction.go | 68 +++++++++++++++++++++++++++--- 1 file changed, 62 insertions(+), 6 deletions(-) diff --git a/pkg/flowcli/project/transaction.go b/pkg/flowcli/project/transaction.go index e66feac8e..723e56b66 100644 --- a/pkg/flowcli/project/transaction.go +++ b/pkg/flowcli/project/transaction.go @@ -5,6 +5,9 @@ import ( "encoding/hex" "fmt" "io/ioutil" + "strings" + + "github.com/onflow/flow-go-sdk/templates" "github.com/onflow/flow-cli/pkg/flowcli" @@ -24,16 +27,18 @@ const ( func NewTransaction() *Transaction { return &Transaction{ - tx: flow.NewTransaction(), + tx: flow.NewTransaction(), + contracts: []templates.Contract{}, } } type Transaction struct { - signer *Account - role signerRole - proposer *Account - payer flow.Address - tx *flow.Transaction + signer *Account + role signerRole + proposer *Account + payer flow.Address + tx *flow.Transaction + contracts []templates.Contract } func (t *Transaction) Signer() *Account { @@ -68,6 +73,10 @@ func (t *Transaction) SetScriptWithArgsFromFile(filepath string, args []string, return err } + return t.SetScriptWithArgs(script, args, argsJSON) +} + +func (t *Transaction) SetScriptWithArgs(script []byte, args []string, argsJSON string) error { t.tx.SetScript(script) return t.AddRawArguments(args, argsJSON) } @@ -185,3 +194,50 @@ func (t *Transaction) Sign() (*Transaction, error) { return t, nil } + +func (t *Transaction) AddContractsFromArgs(contractArgs []string) error { + for _, contract := range contractArgs { + contractFlagContent := strings.SplitN(contract, ":", 2) + if len(contractFlagContent) != 2 { + return fmt.Errorf("wrong format for contract. Correct format is name:path, but got: %s", contract) + } + contractName := contractFlagContent[0] + contractPath := contractFlagContent[1] + + contractSource, err := util.LoadFile(contractPath) + if err != nil { + return err + } + + t.AddContract(contractName, string(contractSource)) + } + + return nil +} + +func (t *Transaction) AddContract(name string, source string) { + t.contracts = append(t.contracts, + templates.Contract{ + Name: name, + Source: source, + }, + ) +} + +func (t *Transaction) SetCreateAccount(keys []*flow.AccountKey) { + t.tx = templates.CreateAccount(keys, t.contracts, t.signer.Address()) +} + +func (t *Transaction) SetUpdateContract(name string, source string) { + t.AddContract(name, source) + t.tx = templates.UpdateAccountContract(t.signer.Address(), t.contracts[0]) +} + +func (t *Transaction) SetDeployContract(name string, source string) { + t.AddContract(name, source) + t.tx = templates.AddAccountContract(t.signer.Address(), t.contracts[0]) +} + +func (t *Transaction) SetRemoveContract(name string) { + t.tx = templates.RemoveAccountContract(t.signer.Address(), name) +} From 7d624d8afa6235adb4571ba52f22e21e68b173d9 Mon Sep 17 00:00:00 2001 From: Gregor Gololicic Date: Tue, 30 Mar 2021 21:34:02 +0200 Subject: [PATCH 009/137] support new transaction model in project --- pkg/flowcli/services/project.go | 16 +++++++++++----- 1 file changed, 11 insertions(+), 5 deletions(-) diff --git a/pkg/flowcli/services/project.go b/pkg/flowcli/services/project.go index dd1c3b05e..120c1a226 100644 --- a/pkg/flowcli/services/project.go +++ b/pkg/flowcli/services/project.go @@ -142,7 +142,8 @@ func (p *Project) Deploy(network string, update bool) ([]*contracts.Contract, er return nil, fmt.Errorf("failed to fetch information for account %s with error %s", targetAccount.Address(), err.Error()) } - var tx *flow.Transaction + //var tx *flow.Transaction + tx := project.NewTransaction() _, exists := targetAccountInfo.Contracts[contract.Name()] if exists { @@ -153,12 +154,17 @@ func (p *Project) Deploy(network string, update bool) ([]*contracts.Contract, er continue } - tx = prepareUpdateContractTransaction(targetAccount.Address(), contract) + err := tx.SetSigner(targetAccount) + if err != nil { + errs = append(errs, err) + } + + tx.SetUpdateContract(contract.Name(), contract.TranspiledCode()) } else { - tx = prepareAddContractTransaction(targetAccount.Address(), contract) + tx.SetDeployContract(contract.Name(), contract.TranspiledCode()) } - tx, err = p.gateway.SendTransaction(tx, targetAccount) + sentTx, err := p.gateway.SendSignedTransaction(tx) if err != nil { p.logger.Error(err.Error()) errs = append(errs, err) @@ -168,7 +174,7 @@ func (p *Project) Deploy(network string, update bool) ([]*contracts.Contract, er fmt.Sprintf("%s deploying...", util.Bold(contract.Name())), ) - result, err := p.gateway.GetTransactionResult(tx, true) + result, err := p.gateway.GetTransactionResult(sentTx, true) if err != nil { p.logger.Error(err.Error()) errs = append(errs, err) From 24d0f88169a54894eb22bfc6fbf561cc366415b1 Mon Sep 17 00:00:00 2001 From: Gregor Gololicic Date: Tue, 30 Mar 2021 21:34:10 +0200 Subject: [PATCH 010/137] support new transaction model in accounts --- pkg/flowcli/services/accounts.go | 85 ++++++++++++++------------------ 1 file changed, 36 insertions(+), 49 deletions(-) diff --git a/pkg/flowcli/services/accounts.go b/pkg/flowcli/services/accounts.go index 0a3285b1f..d6ebd9b3d 100644 --- a/pkg/flowcli/services/accounts.go +++ b/pkg/flowcli/services/accounts.go @@ -35,7 +35,6 @@ import ( tmpl "github.com/onflow/flow-core-contracts/lib/go/templates" "github.com/onflow/flow-go-sdk" "github.com/onflow/flow-go-sdk/crypto" - "github.com/onflow/flow-go-sdk/templates" ) // Accounts service handles all interactions for accounts @@ -240,38 +239,33 @@ func (a *Accounts) Create( } } - var contractTemplates []templates.Contract + tx := project.NewTransaction() - for _, contract := range contracts { - contractFlagContent := strings.SplitN(contract, ":", 2) - if len(contractFlagContent) != 2 { - return nil, fmt.Errorf("wrong format for contract. Correct format is name:path, but got: %s", contract) - } - contractName := contractFlagContent[0] - contractPath := contractFlagContent[1] + err = tx.AddContractsFromArgs(contracts) + if err != nil { + return nil, err + } - contractSource, err := util.LoadFile(contractPath) - if err != nil { - return nil, err - } + err = tx.SetSigner(signer) + if err != nil { + return nil, err + } - contractTemplates = append(contractTemplates, - templates.Contract{ - Name: contractName, - Source: string(contractSource), - }, - ) + tx.SetCreateAccount(accountKeys) + + signed, err := tx.Sign() + if err != nil { + return nil, err } - tx := templates.CreateAccount(accountKeys, contractTemplates, signer.Address()) - tx, err = a.gateway.SendTransaction(tx, signer) + sentTx, err := a.gateway.SendSignedTransaction(signed) if err != nil { return nil, err } a.logger.StartProgress("Waiting for transaction to be sealed...") - result, err := a.gateway.GetTransactionResult(tx, true) + result, err := a.gateway.GetTransactionResult(sentTx, true) if err != nil { return nil, err } @@ -336,47 +330,33 @@ func (a *Accounts) addContract( fmt.Sprintf("Adding Contract '%s' to the account '%s'...", contractName, account.Address()), ) - if account.DefaultKey().Type() == config.KeyTypeGoogleKMS { - a.logger.StartProgress("Connecting to KMS...") - resourceID := account.DefaultKey().ToConfig().Context[config.KMSContextField] - err := util.GcloudApplicationSignin(resourceID) - if err != nil { - return nil, err - } + contractSource, err := util.LoadFile(contractFilename) + if err != nil { + return nil, err } - contractSource, err := util.LoadFile(contractFilename) + tx := project.NewTransaction() + + err = tx.SetSigner(account) if err != nil { return nil, err } - tx := templates.AddAccountContract( - account.Address(), - templates.Contract{ - Name: contractName, - Source: string(contractSource), - }, - ) + tx.SetDeployContract(contractName, string(contractSource)) // if we are updating contract if updateExisting { - tx = templates.UpdateAccountContract( - account.Address(), - templates.Contract{ - Name: contractName, - Source: string(contractSource), - }, - ) + tx.SetUpdateContract(contractName, string(contractSource)) } // send transaction with contract - tx, err = a.gateway.SendTransaction(tx, account) + sentTx, err := a.gateway.SendSignedTransaction(tx) if err != nil { return nil, err } // we wait for transaction to be sealed - trx, err := a.gateway.GetTransactionResult(tx, true) + trx, err := a.gateway.GetTransactionResult(sentTx, true) if err != nil { return nil, err } @@ -434,13 +414,20 @@ func (a *Accounts) removeContract( fmt.Sprintf("Removing Contract %s from %s...", contractName, account.Address()), ) - tx := templates.RemoveAccountContract(account.Address(), contractName) - tx, err := a.gateway.SendTransaction(tx, account) + tx := project.NewTransaction() + err := tx.SetSigner(account) + if err != nil { + return nil, err + } + + tx.SetRemoveContract(contractName) + + sentTx, err := a.gateway.SendSignedTransaction(tx) if err != nil { return nil, err } - txr, err := a.gateway.GetTransactionResult(tx, true) + txr, err := a.gateway.GetTransactionResult(sentTx, true) if err != nil { return nil, err } From 5ee368ecb3932192ff7aa256e298099366cf59f6 Mon Sep 17 00:00:00 2001 From: Gregor Gololicic Date: Tue, 30 Mar 2021 21:44:37 +0200 Subject: [PATCH 011/137] refactored transaction for new tx model and sign --- pkg/flowcli/services/transactions.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pkg/flowcli/services/transactions.go b/pkg/flowcli/services/transactions.go index 7659db096..0cd6fdcd9 100644 --- a/pkg/flowcli/services/transactions.go +++ b/pkg/flowcli/services/transactions.go @@ -171,7 +171,7 @@ func (t *Transactions) Send( "", "", []string{}, - "authorizer", + string(project.SignerRoleAuthorizer), transactionFilename, payloadFilename, args, From 166e1812c0f0686ee79b70e649adf15194bdf8ba Mon Sep 17 00:00:00 2001 From: Gregor Gololicic Date: Tue, 30 Mar 2021 21:59:42 +0200 Subject: [PATCH 012/137] added sign command --- internal/transactions/sign.go | 68 +++++++++++++++++++++++++++++++++++ 1 file changed, 68 insertions(+) create mode 100644 internal/transactions/sign.go diff --git a/internal/transactions/sign.go b/internal/transactions/sign.go new file mode 100644 index 000000000..a1312181d --- /dev/null +++ b/internal/transactions/sign.go @@ -0,0 +1,68 @@ +package transactions + +import ( + "fmt" + + "github.com/onflow/flow-cli/internal/command" + "github.com/onflow/flow-cli/pkg/flowcli/services" + "github.com/spf13/cobra" +) + +type flagsSign struct { + ArgsJSON string `default:"" flag:"args-json" info:"arguments in JSON-Cadence format"` + Args []string `default:"" flag:"arg" info:"argument in Type:Value format"` + Signer string `default:"emulator-account" flag:"signer"` + Payload string `flag:"payload" info:"path to the transaction payload file"` + Code string `default:"" flag:"code" info:"⚠️ DEPRECATED: use filename argument"` + Results bool `default:"" flag:"results" info:"⚠️ DEPRECATED: all transactions will provide result"` + Proposer string `default:"" flag:"proposer"` + Role string `default:"authorizer" flag:"role"` + AdditionalAuthorizers []string `flag:"additional-authorizers" info:"Additional authorizer addresses to add to the transaction"` + PayerAddress string `flag:"payer-address" info:"Specify payer of the transaction. Defaults to current signer."` + Encoding string `default:"hexrlp" flag:"encoding" info:"Encoding to use for transactio (rlp)"` +} + +var signFlags = flagsSign{} + +var SignCommand = &command.Command{ + Cmd: &cobra.Command{ + Use: "sign", + Short: "Sign a transaction", + Example: `flow transactions sign`, + }, + Flags: &signFlags, + Run: func( + cmd *cobra.Command, + args []string, + globalFlags command.GlobalFlags, + services *services.Services, + ) (command.Result, error) { + if sendFlags.Code != "" { + return nil, fmt.Errorf("⚠️ DEPRECATED: use filename argument") + } + + if sendFlags.Results { + return nil, fmt.Errorf("⚠️ DEPRECATED: all transactions will provide results") + } + + signed, err := services.Transactions.Sign( + signFlags.Signer, + signFlags.Proposer, + signFlags.PayerAddress, + signFlags.AdditionalAuthorizers, + signFlags.Role, + signFlags.Code, + signFlags.Payload, + signFlags.Args, + signFlags.ArgsJSON, + ) + if err != nil { + return nil, err + } + + return &TransactionResult{ + result: nil, + tx: signed.FlowTransaction(), + }, nil + }, +} From 0228e9ba2ce2ba8f912cc163ea5e85b7bdc70217 Mon Sep 17 00:00:00 2001 From: Gregor Gololicic Date: Wed, 31 Mar 2021 09:47:21 +0200 Subject: [PATCH 013/137] moved key validation --- pkg/flowcli/project/account.go | 12 ------------ pkg/flowcli/project/keys.go | 12 ++++++++++++ pkg/flowcli/project/transaction.go | 4 ++-- 3 files changed, 14 insertions(+), 14 deletions(-) diff --git a/pkg/flowcli/project/account.go b/pkg/flowcli/project/account.go index 4d81d9a60..ceae333dd 100644 --- a/pkg/flowcli/project/account.go +++ b/pkg/flowcli/project/account.go @@ -32,18 +32,6 @@ func (a *Account) SetDefaultKey(key AccountKey) { a.keys[0] = key } -func (a *Account) ValidateKey() error { - if a.DefaultKey().Type() == config.KeyTypeGoogleKMS { - resourceID := a.DefaultKey().ToConfig().Context[config.KMSContextField] - err := util.GcloudApplicationSignin(resourceID) - if err != nil { - return err - } - } - - return nil -} - func accountsFromConfig(conf *config.Config) ([]*Account, error) { accounts := make([]*Account, 0, len(conf.Accounts)) diff --git a/pkg/flowcli/project/keys.go b/pkg/flowcli/project/keys.go index 2b7d63a78..313bd101b 100644 --- a/pkg/flowcli/project/keys.go +++ b/pkg/flowcli/project/keys.go @@ -23,6 +23,8 @@ import ( "encoding/hex" "fmt" + "github.com/onflow/flow-cli/pkg/flowcli/util" + "github.com/onflow/flow-go-sdk" "github.com/onflow/flow-go-sdk/crypto" "github.com/onflow/flow-go-sdk/crypto/cloudkms" @@ -37,6 +39,7 @@ type AccountKey interface { HashAlgo() crypto.HashAlgorithm Signer(ctx context.Context) (crypto.Signer, error) ToConfig() config.AccountKey + Validate() error } func NewAccountKey(accountKeyConf config.AccountKey) (AccountKey, error) { @@ -82,6 +85,10 @@ func (a *baseAccountKey) Index() int { return a.index } +func (a *baseAccountKey) Validate() error { + return nil +} + type KmsAccountKey struct { *baseAccountKey kmsKey cloudkms.Key @@ -117,6 +124,11 @@ func (a *KmsAccountKey) Signer(ctx context.Context) (crypto.Signer, error) { return accountKMSSigner, nil } +func (a *KmsAccountKey) Validate() error { + resourceID := a.ToConfig().Context[config.KMSContextField] + return util.GcloudApplicationSignin(resourceID) +} + func newKmsAccountKey(key config.AccountKey) (AccountKey, error) { accountKMSKey, err := cloudkms.KeyFromResourceID(key.Context[config.KMSContextField]) if err != nil { diff --git a/pkg/flowcli/project/transaction.go b/pkg/flowcli/project/transaction.go index 723e56b66..87d959b9c 100644 --- a/pkg/flowcli/project/transaction.go +++ b/pkg/flowcli/project/transaction.go @@ -82,7 +82,7 @@ func (t *Transaction) SetScriptWithArgs(script []byte, args []string, argsJSON s } func (t *Transaction) SetSigner(account *Account) error { - err := account.ValidateKey() + err := account.DefaultKey().Validate() if err != nil { return err } @@ -92,7 +92,7 @@ func (t *Transaction) SetSigner(account *Account) error { } func (t *Transaction) SetProposer(account *Account) error { - err := account.ValidateKey() + err := account.DefaultKey().Validate() if err != nil { return err } From eb85e1068954669b66aa453cd9f5e363b9e72b2a Mon Sep 17 00:00:00 2001 From: Gregor Gololicic Date: Wed, 31 Mar 2021 11:04:00 +0200 Subject: [PATCH 014/137] account add contract, update contract, remove contract new transaction factory method --- pkg/flowcli/gateway/gateway.go | 1 + pkg/flowcli/gateway/grpc.go | 15 +++ pkg/flowcli/project/transaction.go | 149 ++++++++++++++++++----------- pkg/flowcli/services/accounts.go | 54 +++++------ pkg/flowcli/services/project.go | 45 ++------- 5 files changed, 140 insertions(+), 124 deletions(-) diff --git a/pkg/flowcli/gateway/gateway.go b/pkg/flowcli/gateway/gateway.go index f9cc5d044..df38caf45 100644 --- a/pkg/flowcli/gateway/gateway.go +++ b/pkg/flowcli/gateway/gateway.go @@ -27,6 +27,7 @@ import ( type Gateway interface { GetAccount(flow.Address) (*flow.Account, error) + SendTransaction(*project.Transaction) (*flow.Transaction, error) SendSignedTransaction(*project.Transaction) (*flow.Transaction, error) PrepareTransactionPayload(*project.Transaction) (*project.Transaction, error) GetTransactionResult(*flow.Transaction, bool) (*flow.TransactionResult, error) diff --git a/pkg/flowcli/gateway/grpc.go b/pkg/flowcli/gateway/grpc.go index c98cbfd22..f0ecb08c6 100644 --- a/pkg/flowcli/gateway/grpc.go +++ b/pkg/flowcli/gateway/grpc.go @@ -89,6 +89,21 @@ func (g *GrpcGateway) PrepareTransactionPayload(tx *project.Transaction) (*proje return tx, nil } +// SendTransaction prepares, signs and sends the transaction to the network +func (g *GrpcGateway) SendTransaction(transaction *project.Transaction) (*flow.Transaction, error) { + tx, err := g.PrepareTransactionPayload(transaction) + if err != nil { + return nil, err + } + + tx, err = tx.Sign() + if err != nil { + return nil, err + } + + return g.SendSignedTransaction(tx) +} + // SendSignedTransaction sends a transaction to flow that is already prepared and signed func (g *GrpcGateway) SendSignedTransaction(transaction *project.Transaction) (*flow.Transaction, error) { tx := transaction.FlowTransaction() diff --git a/pkg/flowcli/project/transaction.go b/pkg/flowcli/project/transaction.go index 87d959b9c..32ff0533f 100644 --- a/pkg/flowcli/project/transaction.go +++ b/pkg/flowcli/project/transaction.go @@ -27,18 +27,104 @@ const ( func NewTransaction() *Transaction { return &Transaction{ - tx: flow.NewTransaction(), - contracts: []templates.Contract{}, + tx: flow.NewTransaction(), } } +func NewUpdateAccountContractTransaction(signer *Account, name string, source string) (*Transaction, error) { + contract := templates.Contract{ + Name: name, + Source: source, + } + + tx := &Transaction{ + tx: templates.UpdateAccountContract(signer.Address(), contract), + } + + err := tx.SetSigner(signer) + if err != nil { + return nil, err + } + + return tx, nil +} + +func NewAddAccountContractTransaction(signer *Account, name string, source string) (*Transaction, error) { + contract := templates.Contract{ + Name: name, + Source: source, + } + + tx := &Transaction{ + tx: templates.AddAccountContract(signer.Address(), contract), + } + + err := tx.SetSigner(signer) + if err != nil { + return nil, err + } + + return tx, nil +} + +func NewRemoveAccountContractTransaction(signer *Account, name string) (*Transaction, error) { + tx := &Transaction{ + tx: templates.RemoveAccountContract(signer.Address(), name), + } + + err := tx.SetSigner(signer) + if err != nil { + return nil, err + } + + return tx, nil +} + +func NewCreateAccountTransaction( + signer *Account, + keys []*flow.AccountKey, + contractArgs []string, +) (*Transaction, error) { + + contracts := make([]templates.Contract, 0) + + for _, contract := range contractArgs { + contractFlagContent := strings.SplitN(contract, ":", 2) + if len(contractFlagContent) != 2 { + return nil, fmt.Errorf("wrong format for contract. Correct format is name:path, but got: %s", contract) + } + contractName := contractFlagContent[0] + contractPath := contractFlagContent[1] + + contractSource, err := util.LoadFile(contractPath) + if err != nil { + return nil, err + } + + contracts = append(contracts, templates.Contract{ + Name: contractName, + Source: string(contractSource), + }) + } + + tx := &Transaction{ + tx: templates.CreateAccount(keys, contracts, signer.Address()), + } + + err := tx.SetSigner(signer) + if err != nil { + return nil, err + } + + return tx, nil +} + type Transaction struct { - signer *Account - role signerRole - proposer *Account - payer flow.Address - tx *flow.Transaction - contracts []templates.Contract + signer *Account + role signerRole + proposer *Account + payer flow.Address + tx *flow.Transaction } func (t *Transaction) Signer() *Account { @@ -194,50 +280,3 @@ func (t *Transaction) Sign() (*Transaction, error) { return t, nil } - -func (t *Transaction) AddContractsFromArgs(contractArgs []string) error { - for _, contract := range contractArgs { - contractFlagContent := strings.SplitN(contract, ":", 2) - if len(contractFlagContent) != 2 { - return fmt.Errorf("wrong format for contract. Correct format is name:path, but got: %s", contract) - } - contractName := contractFlagContent[0] - contractPath := contractFlagContent[1] - - contractSource, err := util.LoadFile(contractPath) - if err != nil { - return err - } - - t.AddContract(contractName, string(contractSource)) - } - - return nil -} - -func (t *Transaction) AddContract(name string, source string) { - t.contracts = append(t.contracts, - templates.Contract{ - Name: name, - Source: source, - }, - ) -} - -func (t *Transaction) SetCreateAccount(keys []*flow.AccountKey) { - t.tx = templates.CreateAccount(keys, t.contracts, t.signer.Address()) -} - -func (t *Transaction) SetUpdateContract(name string, source string) { - t.AddContract(name, source) - t.tx = templates.UpdateAccountContract(t.signer.Address(), t.contracts[0]) -} - -func (t *Transaction) SetDeployContract(name string, source string) { - t.AddContract(name, source) - t.tx = templates.AddAccountContract(t.signer.Address(), t.contracts[0]) -} - -func (t *Transaction) SetRemoveContract(name string) { - t.tx = templates.RemoveAccountContract(t.signer.Address(), name) -} diff --git a/pkg/flowcli/services/accounts.go b/pkg/flowcli/services/accounts.go index d6ebd9b3d..17fc2db39 100644 --- a/pkg/flowcli/services/accounts.go +++ b/pkg/flowcli/services/accounts.go @@ -239,26 +239,9 @@ func (a *Accounts) Create( } } - tx := project.NewTransaction() + tx, err := project.NewCreateAccountTransaction(signer, accountKeys, contracts) - err = tx.AddContractsFromArgs(contracts) - if err != nil { - return nil, err - } - - err = tx.SetSigner(signer) - if err != nil { - return nil, err - } - - tx.SetCreateAccount(accountKeys) - - signed, err := tx.Sign() - if err != nil { - return nil, err - } - - sentTx, err := a.gateway.SendSignedTransaction(signed) + sentTx, err := a.gateway.SendTransaction(tx) if err != nil { return nil, err } @@ -335,22 +318,34 @@ func (a *Accounts) addContract( return nil, err } - tx := project.NewTransaction() - - err = tx.SetSigner(account) + tx, err := project.NewAddAccountContractTransaction( + account, + contractName, + string(contractSource), + ) if err != nil { return nil, err } - tx.SetDeployContract(contractName, string(contractSource)) - // if we are updating contract if updateExisting { - tx.SetUpdateContract(contractName, string(contractSource)) + tx, err = project.NewUpdateAccountContractTransaction( + account, + contractName, + string(contractSource), + ) + if err != nil { + return nil, err + } + } + + signed, err := tx.Sign() + if err != nil { + return nil, err } // send transaction with contract - sentTx, err := a.gateway.SendSignedTransaction(tx) + sentTx, err := a.gateway.SendSignedTransaction(signed) if err != nil { return nil, err } @@ -414,15 +409,12 @@ func (a *Accounts) removeContract( fmt.Sprintf("Removing Contract %s from %s...", contractName, account.Address()), ) - tx := project.NewTransaction() - err := tx.SetSigner(account) + tx, err := project.NewRemoveAccountContractTransaction(account, contractName) if err != nil { return nil, err } - tx.SetRemoveContract(contractName) - - sentTx, err := a.gateway.SendSignedTransaction(tx) + sentTx, err := a.gateway.SendTransaction(tx) if err != nil { return nil, err } diff --git a/pkg/flowcli/services/project.go b/pkg/flowcli/services/project.go index 120c1a226..c5d83f0c2 100644 --- a/pkg/flowcli/services/project.go +++ b/pkg/flowcli/services/project.go @@ -22,15 +22,12 @@ import ( "fmt" "strings" - "github.com/onflow/flow-go-sdk" - "github.com/onflow/flow-go-sdk/crypto" - "github.com/onflow/flow-go-sdk/templates" - "github.com/onflow/flow-cli/pkg/flowcli/contracts" "github.com/onflow/flow-cli/pkg/flowcli/gateway" "github.com/onflow/flow-cli/pkg/flowcli/output" "github.com/onflow/flow-cli/pkg/flowcli/project" "github.com/onflow/flow-cli/pkg/flowcli/util" + "github.com/onflow/flow-go-sdk/crypto" ) // Project service handles all interactions for project @@ -142,8 +139,10 @@ func (p *Project) Deploy(network string, update bool) ([]*contracts.Contract, er return nil, fmt.Errorf("failed to fetch information for account %s with error %s", targetAccount.Address(), err.Error()) } - //var tx *flow.Transaction - tx := project.NewTransaction() + tx, err := project.NewAddAccountContractTransaction(targetAccount, contract.Name(), contract.TranspiledCode()) + if err != nil { + errs = append(errs, err) + } _, exists := targetAccountInfo.Contracts[contract.Name()] if exists { @@ -154,17 +153,13 @@ func (p *Project) Deploy(network string, update bool) ([]*contracts.Contract, er continue } - err := tx.SetSigner(targetAccount) + tx, err = project.NewUpdateAccountContractTransaction(targetAccount, contract.Name(), contract.TranspiledCode()) if err != nil { errs = append(errs, err) } - - tx.SetUpdateContract(contract.Name(), contract.TranspiledCode()) - } else { - tx.SetDeployContract(contract.Name(), contract.TranspiledCode()) } - sentTx, err := p.gateway.SendSignedTransaction(tx) + sentTx, err := p.gateway.SendTransaction(tx) if err != nil { p.logger.Error(err.Error()) errs = append(errs, err) @@ -205,29 +200,3 @@ func (p *Project) Deploy(network string, update bool) ([]*contracts.Contract, er return contracts, nil } - -func prepareUpdateContractTransaction( - targetAccount flow.Address, - contract *contracts.Contract, -) *flow.Transaction { - return templates.UpdateAccountContract( - targetAccount, - templates.Contract{ - Name: contract.Name(), - Source: contract.TranspiledCode(), - }, - ) -} - -func prepareAddContractTransaction( - targetAccount flow.Address, - contract *contracts.Contract, -) *flow.Transaction { - return templates.AddAccountContract( - targetAccount, - templates.Contract{ - Name: contract.Name(), - Source: contract.TranspiledCode(), - }, - ) -} From 0a7b5f4ffb0e0780b9043a51f55f0686cee46a93 Mon Sep 17 00:00:00 2001 From: Gregor Gololicic Date: Wed, 31 Mar 2021 16:05:30 +0200 Subject: [PATCH 015/137] bugfix role signer auth --- pkg/flowcli/project/transaction.go | 41 +++++++++++++++++++--------- pkg/flowcli/services/transactions.go | 4 +-- 2 files changed, 30 insertions(+), 15 deletions(-) diff --git a/pkg/flowcli/project/transaction.go b/pkg/flowcli/project/transaction.go index 32ff0533f..5c1209221 100644 --- a/pkg/flowcli/project/transaction.go +++ b/pkg/flowcli/project/transaction.go @@ -20,9 +20,10 @@ import ( type signerRole string const ( - SignerRoleAuthorizer signerRole = "authorizer" - SignerRoleProposer signerRole = "proposer" - SignerRolePayer signerRole = "payer" + SignerRoleAuthorizer signerRole = "authorizer" + SignerRoleProposer signerRole = "proposer" + SignerRolePayer signerRole = "payer" + SignerRoleAuthorizerPayer signerRole = "authorizer-payer" ) func NewTransaction() *Transaction { @@ -87,7 +88,6 @@ func NewCreateAccountTransaction( ) (*Transaction, error) { contracts := make([]templates.Contract, 0) - for _, contract := range contractArgs { contractFlagContent := strings.SplitN(contract, ":", 2) if len(contractFlagContent) != 2 { @@ -116,15 +116,20 @@ func NewCreateAccountTransaction( return nil, err } + err = tx.SetSignerRole(string(SignerRoleAuthorizerPayer)) + if err != nil { + return nil, err + } + return tx, nil } type Transaction struct { - signer *Account - role signerRole - proposer *Account - payer flow.Address - tx *flow.Transaction + signer *Account + signerRole signerRole + proposer *Account + payer flow.Address + tx *flow.Transaction } func (t *Transaction) Signer() *Account { @@ -236,15 +241,20 @@ func (t *Transaction) AddAuthorizer(address string) error { return nil } -func (t *Transaction) SignerRole(role string) error { - t.role = signerRole(role) +func (t *Transaction) SetSignerRole(role string) error { + t.signerRole = signerRole(role) - switch t.role { + switch t.signerRole { case SignerRoleAuthorizer: // Ignored if we're loading from a tx payload err := t.AddAuthorizer(t.signer.Address().String()) if err != nil { return err } + case SignerRoleAuthorizerPayer: + err := t.AddAuthorizer(t.signer.Address().String()) + if err != nil { + return err + } case SignerRolePayer: if t.payer != t.signer.Address() { return fmt.Errorf("role specified as Payer, but Payer address also provided, and different: %s != %s", t.payer, t.signer.Address()) @@ -265,7 +275,7 @@ func (t *Transaction) Sign() (*Transaction, error) { return nil, err } - switch t.role { + switch t.signerRole { case SignerRoleAuthorizer, SignerRoleProposer: err := t.tx.SignPayload(signerAddress, keyIndex, signer) if err != nil { @@ -276,6 +286,11 @@ func (t *Transaction) Sign() (*Transaction, error) { if err != nil { return nil, fmt.Errorf("failed to sign transaction: %s", err) } + case SignerRoleAuthorizerPayer: + err := t.tx.SignEnvelope(signerAddress, keyIndex, signer) + if err != nil { + return nil, fmt.Errorf("failed to sign transaction: %s", err) + } } return t, nil diff --git a/pkg/flowcli/services/transactions.go b/pkg/flowcli/services/transactions.go index 0cd6fdcd9..7aeb75e8b 100644 --- a/pkg/flowcli/services/transactions.go +++ b/pkg/flowcli/services/transactions.go @@ -125,7 +125,7 @@ func (t *Transactions) Sign( tx.SetPayer(flow.HexToAddress(payerAddress)) } - err = tx.SignerRole(role) + err = tx.SetSignerRole(role) if err != nil { return nil, err } @@ -171,7 +171,7 @@ func (t *Transactions) Send( "", "", []string{}, - string(project.SignerRoleAuthorizer), + string(project.SignerRoleAuthorizerPayer), transactionFilename, payloadFilename, args, From 942891bd9bf97f1084dd94126199d7ebcb9e440a Mon Sep 17 00:00:00 2001 From: Gregor Gololicic Date: Wed, 31 Mar 2021 16:05:39 +0200 Subject: [PATCH 016/137] test mock added --- tests/e2e_test.go | 4 ++-- tests/mockGateway.go | 34 ++++++++++++++++++++++------------ 2 files changed, 24 insertions(+), 14 deletions(-) diff --git a/tests/e2e_test.go b/tests/e2e_test.go index b4e22a776..9d705dc2d 100644 --- a/tests/e2e_test.go +++ b/tests/e2e_test.go @@ -236,7 +236,7 @@ func TestTransactions(t *testing.T) { var txID1 flow.Identifier t.Run("Test Transactions", func(t *testing.T) { - tx, tr, err := transactions.Send("./transaction.cdc", emulatorAccount, []string{"String:Hello"}, "") + tx, tr, err := transactions.Send("./transaction.cdc", "", emulatorAccount, []string{"String:Hello"}, "") txID1 = tx.ID() assert.NoError(t, err) @@ -245,7 +245,7 @@ func TestTransactions(t *testing.T) { }) t.Run("Test Failed Transactions", func(t *testing.T) { - tx, tr, err := transactions.Send("./transactionErr.cdc", emulatorAccount, []string{}, "") + tx, tr, err := transactions.Send("./transactionErr.cdc", "", emulatorAccount, []string{}, "") assert.NoError(t, err) assert.Equal(t, tx.Payer.String(), serviceAddress) diff --git a/tests/mockGateway.go b/tests/mockGateway.go index e30261154..177b881aa 100644 --- a/tests/mockGateway.go +++ b/tests/mockGateway.go @@ -9,16 +9,18 @@ import ( ) type MockGateway struct { - GetAccountMock func(address flow.Address) (*flow.Account, error) - SendTransactionMock func(tx *flow.Transaction, signer *project.Account) (*flow.Transaction, error) - GetTransactionResultMock func(tx *flow.Transaction) (*flow.TransactionResult, error) - GetTransactionMock func(id flow.Identifier) (*flow.Transaction, error) - ExecuteScriptMock func(script []byte, arguments []cadence.Value) (cadence.Value, error) - GetLatestBlockMock func() (*flow.Block, error) - GetEventsMock func(string, uint64, uint64) ([]client.BlockEvents, error) - GetCollectionMock func(id flow.Identifier) (*flow.Collection, error) - GetBlockByHeightMock func(uint64) (*flow.Block, error) - GetBlockByIDMock func(flow.Identifier) (*flow.Block, error) + GetAccountMock func(address flow.Address) (*flow.Account, error) + SendTransactionMock func(tx *project.Transaction) (*flow.Transaction, error) + PrepareTransactionPayloadMock func(tx *project.Transaction) (*project.Transaction, error) + SendSignedTransactionMock func(tx *project.Transaction) (*flow.Transaction, error) + GetTransactionResultMock func(tx *flow.Transaction) (*flow.TransactionResult, error) + GetTransactionMock func(id flow.Identifier) (*flow.Transaction, error) + ExecuteScriptMock func(script []byte, arguments []cadence.Value) (cadence.Value, error) + GetLatestBlockMock func() (*flow.Block, error) + GetEventsMock func(string, uint64, uint64) ([]client.BlockEvents, error) + GetCollectionMock func(id flow.Identifier) (*flow.Collection, error) + GetBlockByHeightMock func(uint64) (*flow.Block, error) + GetBlockByIDMock func(flow.Identifier) (*flow.Block, error) } func NewMockGateway() gateway.Gateway { @@ -29,8 +31,16 @@ func (g *MockGateway) GetAccount(address flow.Address) (*flow.Account, error) { return g.GetAccountMock(address) } -func (g *MockGateway) SendTransaction(tx *flow.Transaction, signer *project.Account) (*flow.Transaction, error) { - return g.SendTransactionMock(tx, signer) +func (g *MockGateway) SendTransaction(tx *project.Transaction) (*flow.Transaction, error) { + return g.SendTransactionMock(tx) +} + +func (g *MockGateway) SendSignedTransaction(tx *project.Transaction) (*flow.Transaction, error) { + return g.SendSignedTransactionMock(tx) +} + +func (g *MockGateway) PrepareTransactionPayload(tx *project.Transaction) (*project.Transaction, error) { + return g.PrepareTransactionPayloadMock(tx) } func (g *MockGateway) GetTransactionResult(tx *flow.Transaction, waitSeal bool) (*flow.TransactionResult, error) { From c7a52d46298e138bb1edec5efdd0e4d5bd191544 Mon Sep 17 00:00:00 2001 From: Gregor Gololicic Date: Wed, 31 Mar 2021 18:46:42 +0200 Subject: [PATCH 017/137] bug fix --- internal/command/command.go | 3 ++- pkg/flowcli/project/project.go | 2 +- pkg/flowcli/project/transaction.go | 40 +++++++--------------------- pkg/flowcli/services/accounts.go | 8 ++---- pkg/flowcli/services/transactions.go | 2 +- tests/e2e_test.go | 7 ++--- 6 files changed, 19 insertions(+), 43 deletions(-) diff --git a/internal/command/command.go b/internal/command/command.go index 33663a01e..ebb386174 100644 --- a/internal/command/command.go +++ b/internal/command/command.go @@ -281,7 +281,8 @@ func handleError(description string, err error) { } else if strings.Contains(err.Error(), "NotFound desc =") { fmt.Fprintf(os.Stderr, "❌ Not Found:%s \n", strings.Split(err.Error(), "NotFound desc =")[1]) } else if strings.Contains(err.Error(), "code = InvalidArgument desc = ") { - fmt.Fprintf(os.Stderr, "❌ Invalid argument: %s \n", strings.Split(err.Error(), "code = InvalidArgument desc = ")[1]) + desc := strings.Split(err.Error(), "code = InvalidArgument desc = ") + fmt.Fprintf(os.Stderr, "❌ Invalid argument: %s \n", desc[len(desc)-1]) if strings.Contains(err.Error(), "is invalid for chain") { fmt.Fprintf(os.Stderr, "🙏 Check you are connecting to the correct network or account address you use is correct.") } else { diff --git a/pkg/flowcli/project/project.go b/pkg/flowcli/project/project.go index 304dcf609..2ec6381b9 100644 --- a/pkg/flowcli/project/project.go +++ b/pkg/flowcli/project/project.go @@ -227,7 +227,7 @@ func (p *Project) AddAccount(account *Account) { p.accounts = append(p.accounts, account) } -// AddOrUpdateAccount addds or updates account +// AddOrUpdateAccount adds or updates account func (p *Project) AddOrUpdateAccount(account *Account) { for i, existingAccount := range p.accounts { if existingAccount.name == account.name { diff --git a/pkg/flowcli/project/transaction.go b/pkg/flowcli/project/transaction.go index 5c1209221..e7b3bdf7d 100644 --- a/pkg/flowcli/project/transaction.go +++ b/pkg/flowcli/project/transaction.go @@ -20,10 +20,9 @@ import ( type signerRole string const ( - SignerRoleAuthorizer signerRole = "authorizer" - SignerRoleProposer signerRole = "proposer" - SignerRolePayer signerRole = "payer" - SignerRoleAuthorizerPayer signerRole = "authorizer-payer" + SignerRoleAuthorizer signerRole = "authorizer" + SignerRoleProposer signerRole = "proposer" + SignerRolePayer signerRole = "payer" ) func NewTransaction() *Transaction { @@ -116,11 +115,6 @@ func NewCreateAccountTransaction( return nil, err } - err = tx.SetSignerRole(string(SignerRoleAuthorizerPayer)) - if err != nil { - return nil, err - } - return tx, nil } @@ -244,24 +238,14 @@ func (t *Transaction) AddAuthorizer(address string) error { func (t *Transaction) SetSignerRole(role string) error { t.signerRole = signerRole(role) - switch t.signerRole { - case SignerRoleAuthorizer: // Ignored if we're loading from a tx payload - err := t.AddAuthorizer(t.signer.Address().String()) - if err != nil { - return err - } - case SignerRoleAuthorizerPayer: + if t.signerRole == SignerRoleAuthorizer { err := t.AddAuthorizer(t.signer.Address().String()) if err != nil { return err } - case SignerRolePayer: - if t.payer != t.signer.Address() { - return fmt.Errorf("role specified as Payer, but Payer address also provided, and different: %s != %s", t.payer, t.signer.Address()) - } - case SignerRoleProposer: // Just sign payload, no special actions needed - default: - return fmt.Errorf("unknown role %s", role) + } + if t.signerRole == SignerRolePayer && t.payer != t.signer.Address() { + return fmt.Errorf("role specified as Payer, but Payer address also provided, and different: %s != %s", t.payer, t.signer.Address()) } return nil @@ -275,18 +259,12 @@ func (t *Transaction) Sign() (*Transaction, error) { return nil, err } - switch t.signerRole { - case SignerRoleAuthorizer, SignerRoleProposer: + if t.signerRole == SignerRoleAuthorizer || t.signerRole == SignerRoleProposer { err := t.tx.SignPayload(signerAddress, keyIndex, signer) if err != nil { return nil, fmt.Errorf("failed to sign transaction: %s", err) } - case SignerRolePayer: - err := t.tx.SignEnvelope(signerAddress, keyIndex, signer) - if err != nil { - return nil, fmt.Errorf("failed to sign transaction: %s", err) - } - case SignerRoleAuthorizerPayer: + } else { err := t.tx.SignEnvelope(signerAddress, keyIndex, signer) if err != nil { return nil, fmt.Errorf("failed to sign transaction: %s", err) diff --git a/pkg/flowcli/services/accounts.go b/pkg/flowcli/services/accounts.go index 17fc2db39..ed2799733 100644 --- a/pkg/flowcli/services/accounts.go +++ b/pkg/flowcli/services/accounts.go @@ -69,6 +69,7 @@ func (a *Accounts) Get(address string) (*flow.Account, error) { return account, err } +// Add account to the configuration func (a *Accounts) Add( name string, accountAddress string, @@ -339,13 +340,8 @@ func (a *Accounts) addContract( } } - signed, err := tx.Sign() - if err != nil { - return nil, err - } - // send transaction with contract - sentTx, err := a.gateway.SendSignedTransaction(signed) + sentTx, err := a.gateway.SendTransaction(tx) if err != nil { return nil, err } diff --git a/pkg/flowcli/services/transactions.go b/pkg/flowcli/services/transactions.go index 7aeb75e8b..2a977ec95 100644 --- a/pkg/flowcli/services/transactions.go +++ b/pkg/flowcli/services/transactions.go @@ -171,7 +171,7 @@ func (t *Transactions) Send( "", "", []string{}, - string(project.SignerRoleAuthorizerPayer), + "", transactionFilename, payloadFilename, args, diff --git a/tests/e2e_test.go b/tests/e2e_test.go index 9d705dc2d..de41e8c29 100644 --- a/tests/e2e_test.go +++ b/tests/e2e_test.go @@ -222,9 +222,9 @@ func TestScripts(t *testing.T) { } func TestTransactions(t *testing.T) { - if e2e == "" { - t.Skip("Skipping end-to-end tests") - } + //if e2e == "" { + // t.Skip("Skipping end-to-end tests") + //} gw, err := gateway.NewGrpcGateway(host) assert.NoError(t, err) @@ -239,6 +239,7 @@ func TestTransactions(t *testing.T) { tx, tr, err := transactions.Send("./transaction.cdc", "", emulatorAccount, []string{"String:Hello"}, "") txID1 = tx.ID() + assert.NoError(t, tr.Error) assert.NoError(t, err) assert.Equal(t, tx.Payer.String(), serviceAddress) assert.Equal(t, tr.Status.String(), "SEALED") From 43b7a86bd4d078f5257f79e60fc95e8f258c2eb7 Mon Sep 17 00:00:00 2001 From: Gregor Gololicic Date: Thu, 1 Apr 2021 11:49:24 +0200 Subject: [PATCH 018/137] bug fix --- pkg/flowcli/project/transaction.go | 5 +++++ pkg/flowcli/services/transactions.go | 10 +++++----- 2 files changed, 10 insertions(+), 5 deletions(-) diff --git a/pkg/flowcli/project/transaction.go b/pkg/flowcli/project/transaction.go index e7b3bdf7d..85eb440a4 100644 --- a/pkg/flowcli/project/transaction.go +++ b/pkg/flowcli/project/transaction.go @@ -265,6 +265,11 @@ func (t *Transaction) Sign() (*Transaction, error) { return nil, fmt.Errorf("failed to sign transaction: %s", err) } } else { + // make sure we have at least signer as authorizer + if len(t.tx.Authorizers) == 0 { + t.tx.AddAuthorizer(t.signer.Address()) + } + err := t.tx.SignEnvelope(signerAddress, keyIndex, signer) if err != nil { return nil, fmt.Errorf("failed to sign transaction: %s", err) diff --git a/pkg/flowcli/services/transactions.go b/pkg/flowcli/services/transactions.go index 2a977ec95..9c3d12557 100644 --- a/pkg/flowcli/services/transactions.go +++ b/pkg/flowcli/services/transactions.go @@ -109,6 +109,11 @@ func (t *Transactions) Sign( return nil, err } + err = tx.SetSignerRole(role) + if err != nil { + return nil, err + } + if proposerName != "" { proposerAccount := t.project.AccountByName(proposerName) if proposerAccount == nil { @@ -125,11 +130,6 @@ func (t *Transactions) Sign( tx.SetPayer(flow.HexToAddress(payerAddress)) } - err = tx.SetSignerRole(role) - if err != nil { - return nil, err - } - if payloadFilename != "" { err = tx.SetPayloadFromFile(payloadFilename) if err != nil { From fe1f5c5569fc020fc432ed3e510f287cab7de7cf Mon Sep 17 00:00:00 2001 From: Gregor Gololicic Date: Thu, 1 Apr 2021 15:23:04 +0200 Subject: [PATCH 019/137] improved output logic --- internal/command/command.go | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/internal/command/command.go b/internal/command/command.go index ebb386174..5b6d5d6b4 100644 --- a/internal/command/command.go +++ b/internal/command/command.go @@ -163,7 +163,7 @@ func (c Command) AddToParent(parent *cobra.Command) { handleError("Result", err) // output result - err = outputResult(formattedResult, flags.Save) + err = outputResult(formattedResult, flags.Save, flags.Format, flags.Filter) handleError("Output Error", err) } @@ -236,7 +236,7 @@ func formatResult(result Result, filterFlag string, formatFlag string) (string, return fmt.Sprintf("%v", jsonResult[filterFlag]), nil } - switch formatFlag { + switch strings.ToLower(formatFlag) { case "json": jsonRes, _ := json.Marshal(result.JSON()) return string(jsonRes), nil @@ -248,7 +248,7 @@ func formatResult(result Result, filterFlag string, formatFlag string) (string, } // outputResult to selected media -func outputResult(result string, saveFlag string) error { +func outputResult(result string, saveFlag string, formatFlag string, filterFlag string) error { if saveFlag != "" { af := afero.Afero{ Fs: afero.NewOsFs(), @@ -258,8 +258,11 @@ func outputResult(result string, saveFlag string) error { return af.WriteFile(saveFlag, []byte(result), 0644) } - // default normal output - fmt.Fprintf(os.Stdout, "%s\n", result) + if formatFlag == "inline" || filterFlag != "" { + fmt.Fprintf(os.Stdout, "%s", result) + } else { // default normal output + fmt.Fprintf(os.Stdout, "\n%s\n\n", result) + } return nil } From db0948f04fac32f0254c92d5a42ac80be744c123 Mon Sep 17 00:00:00 2001 From: Gregor Gololicic Date: Thu, 1 Apr 2021 15:23:32 +0200 Subject: [PATCH 020/137] sign command and result added --- internal/transactions/sign.go | 70 ++++++++++++++++++++++++--- internal/transactions/transactions.go | 1 + 2 files changed, 63 insertions(+), 8 deletions(-) diff --git a/internal/transactions/sign.go b/internal/transactions/sign.go index a1312181d..7bc8ab5e4 100644 --- a/internal/transactions/sign.go +++ b/internal/transactions/sign.go @@ -1,7 +1,11 @@ package transactions import ( + "bytes" "fmt" + "text/tabwriter" + + "github.com/onflow/flow-cli/pkg/flowcli/project" "github.com/onflow/flow-cli/internal/command" "github.com/onflow/flow-cli/pkg/flowcli/services" @@ -13,22 +17,20 @@ type flagsSign struct { Args []string `default:"" flag:"arg" info:"argument in Type:Value format"` Signer string `default:"emulator-account" flag:"signer"` Payload string `flag:"payload" info:"path to the transaction payload file"` - Code string `default:"" flag:"code" info:"⚠️ DEPRECATED: use filename argument"` - Results bool `default:"" flag:"results" info:"⚠️ DEPRECATED: all transactions will provide result"` Proposer string `default:"" flag:"proposer"` Role string `default:"authorizer" flag:"role"` AdditionalAuthorizers []string `flag:"additional-authorizers" info:"Additional authorizer addresses to add to the transaction"` PayerAddress string `flag:"payer-address" info:"Specify payer of the transaction. Defaults to current signer."` - Encoding string `default:"hexrlp" flag:"encoding" info:"Encoding to use for transactio (rlp)"` } var signFlags = flagsSign{} var SignCommand = &command.Command{ Cmd: &cobra.Command{ - Use: "sign", + Use: "sign ", Short: "Sign a transaction", Example: `flow transactions sign`, + Args: cobra.MaximumNArgs(1), }, Flags: &signFlags, Run: func( @@ -51,7 +53,7 @@ var SignCommand = &command.Command{ signFlags.PayerAddress, signFlags.AdditionalAuthorizers, signFlags.Role, - signFlags.Code, + args[0], // optional filename code signFlags.Payload, signFlags.Args, signFlags.ArgsJSON, @@ -60,9 +62,61 @@ var SignCommand = &command.Command{ return nil, err } - return &TransactionResult{ - result: nil, - tx: signed.FlowTransaction(), + return &SignResult{ + signed: signed, }, nil }, } + +type SignResult struct { + signed *project.Transaction +} + +// JSON convert result to JSON +func (r *SignResult) JSON() interface{} { + tx := r.signed.FlowTransaction() + result := make(map[string]string) + result["Payload"] = fmt.Sprintf("%x", tx.Encode()) + result["Authorizers"] = fmt.Sprintf("%s", tx.Authorizers) + + return result +} + +// String convert result to string +func (r *SignResult) String() string { + var b bytes.Buffer + writer := tabwriter.NewWriter(&b, 0, 8, 1, '\t', tabwriter.AlignRight) + tx := r.signed.FlowTransaction() + + fmt.Fprintf(writer, "Authorizers\t%s\n", tx.Authorizers) + + fmt.Fprintf(writer, + "\nProposal Key:\t\n Address\t%s\n Index\t%v\n Sequence\t%v\n", + tx.ProposalKey.Address, tx.ProposalKey.KeyIndex, tx.ProposalKey.SequenceNumber, + ) + + for i, e := range tx.PayloadSignatures { + fmt.Fprintf(writer, "\nPayload Signature %v:\n", i) + fmt.Fprintf(writer, " Address\t%s\n", e.Address) + fmt.Fprintf(writer, " Signature\t%x\n", e.Signature) + fmt.Fprintf(writer, " Key Index\t%v\n", e.KeyIndex) + } + + for i, e := range tx.EnvelopeSignatures { + fmt.Fprintf(writer, "\nEnvelope Signature %v:\n", i) + fmt.Fprintf(writer, " Address\t%s\n", e.Address) + fmt.Fprintf(writer, " Signature\t%s\n", e.Signature) + fmt.Fprintf(writer, " Key Index\t%s\n", e.KeyIndex) + } + + fmt.Fprintf(writer, "\n\nTransaction Payload:\n%x", tx.Encode()) + + writer.Flush() + return b.String() +} + +// Oneliner show result as one liner grep friendly +func (r *SignResult) Oneliner() string { + tx := r.signed.FlowTransaction() + return fmt.Sprintf("Payload: %x, Authorizers: %s", tx.Encode(), tx.Authorizers) +} diff --git a/internal/transactions/transactions.go b/internal/transactions/transactions.go index df1949ac5..bf82bbe4c 100644 --- a/internal/transactions/transactions.go +++ b/internal/transactions/transactions.go @@ -38,6 +38,7 @@ var Cmd = &cobra.Command{ func init() { GetCommand.AddToParent(Cmd) SendCommand.AddToParent(Cmd) + SignCommand.AddToParent(Cmd) } // TransactionResult represent result from all account commands From e5cb11165f68688467757b8b0bb6be1759c12087 Mon Sep 17 00:00:00 2001 From: Gregor Gololicic Date: Thu, 1 Apr 2021 20:05:38 +0200 Subject: [PATCH 021/137] arg parsing --- internal/transactions/send.go | 9 +++++++-- internal/transactions/sign.go | 8 +++++++- 2 files changed, 14 insertions(+), 3 deletions(-) diff --git a/internal/transactions/send.go b/internal/transactions/send.go index e057414ba..77b4a1faa 100644 --- a/internal/transactions/send.go +++ b/internal/transactions/send.go @@ -41,7 +41,7 @@ var SendCommand = &command.Command{ Cmd: &cobra.Command{ Use: "send ", Short: "Send a transaction", - Args: cobra.ExactArgs(1), + Args: cobra.MaximumNArgs(1), Example: `flow transactions send tx.cdc --arg String:"Hello world"`, }, Flags: &sendFlags, @@ -59,8 +59,13 @@ var SendCommand = &command.Command{ return nil, fmt.Errorf("⚠️ DEPRECATED: all transactions will provide results") } + filename := "" + if len(args) > 0 { + filename = args[0] + } + tx, result, err := services.Transactions.Send( - args[0], // filename + filename, sendFlags.Payload, sendFlags.Signer, sendFlags.Args, diff --git a/internal/transactions/sign.go b/internal/transactions/sign.go index 7bc8ab5e4..8e14c561b 100644 --- a/internal/transactions/sign.go +++ b/internal/transactions/sign.go @@ -47,13 +47,18 @@ var SignCommand = &command.Command{ return nil, fmt.Errorf("⚠️ DEPRECATED: all transactions will provide results") } + codeFilename := "" + if len(args) > 0 { + codeFilename = args[0] + } + signed, err := services.Transactions.Sign( signFlags.Signer, signFlags.Proposer, signFlags.PayerAddress, signFlags.AdditionalAuthorizers, signFlags.Role, - args[0], // optional filename code + codeFilename, signFlags.Payload, signFlags.Args, signFlags.ArgsJSON, @@ -89,6 +94,7 @@ func (r *SignResult) String() string { tx := r.signed.FlowTransaction() fmt.Fprintf(writer, "Authorizers\t%s\n", tx.Authorizers) + fmt.Fprintf(writer, "Payer\t%s\n", tx.Payer) fmt.Fprintf(writer, "\nProposal Key:\t\n Address\t%s\n Index\t%v\n Sequence\t%v\n", From 9aac01f2ad2259324637df5ceb20be6f9c53ccbf Mon Sep 17 00:00:00 2001 From: Gregor Gololicic Date: Thu, 1 Apr 2021 20:05:56 +0200 Subject: [PATCH 022/137] payer set --- pkg/flowcli/gateway/grpc.go | 3 +-- pkg/flowcli/project/transaction.go | 1 + 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/pkg/flowcli/gateway/grpc.go b/pkg/flowcli/gateway/grpc.go index f0ecb08c6..1a8ed5a02 100644 --- a/pkg/flowcli/gateway/grpc.go +++ b/pkg/flowcli/gateway/grpc.go @@ -83,8 +83,7 @@ func (g *GrpcGateway) PrepareTransactionPayload(tx *project.Transaction) (*proje tx.FlowTransaction(). SetReferenceBlockID(sealed.ID). SetGasLimit(defaultGasLimit). - SetProposalKey(signerAddress, accountKey.Index, accountKey.SequenceNumber). - SetPayer(signerAddress) + SetProposalKey(signerAddress, accountKey.Index, accountKey.SequenceNumber) return tx, nil } diff --git a/pkg/flowcli/project/transaction.go b/pkg/flowcli/project/transaction.go index 85eb440a4..298a6c49e 100644 --- a/pkg/flowcli/project/transaction.go +++ b/pkg/flowcli/project/transaction.go @@ -188,6 +188,7 @@ func (t *Transaction) SetProposer(account *Account) error { func (t *Transaction) SetPayer(address flow.Address) { t.payer = address + t.tx.SetPayer(address) } func (t *Transaction) AddRawArguments(args []string, argsJSON string) error { From 0f84bd5785c02ab8e5b6bf232b78c305726ebe70 Mon Sep 17 00:00:00 2001 From: Gregor Gololicic Date: Fri, 2 Apr 2021 10:40:30 +0200 Subject: [PATCH 023/137] improve transaction result display --- internal/transactions/transactions.go | 39 +++++++++++++++++++++++---- 1 file changed, 34 insertions(+), 5 deletions(-) diff --git a/internal/transactions/transactions.go b/internal/transactions/transactions.go index bf82bbe4c..96cdcefc3 100644 --- a/internal/transactions/transactions.go +++ b/internal/transactions/transactions.go @@ -67,14 +67,43 @@ func (r *TransactionResult) String() string { var b bytes.Buffer writer := tabwriter.NewWriter(&b, 0, 8, 1, '\t', tabwriter.AlignRight) - fmt.Fprintf(writer, "Hash\t %s\n", r.tx.ID()) - fmt.Fprintf(writer, "Status\t %s\n", r.result.Status) - fmt.Fprintf(writer, "Payer\t %s\n", r.tx.Payer.Hex()) - if r.result.Error != nil { - fmt.Fprintf(writer, "\n❌ Transaction Error \n%s\n", r.result.Error.Error()) + fmt.Fprintf(writer, "❌ Transaction Error \n%s\n\n\n", r.result.Error.Error()) + } + + statusBadge := "" + if r.result.Status == flow.TransactionStatusSealed { + statusBadge = "✅" } + fmt.Fprintf(writer, "Status\t%s %s\n", statusBadge, r.result.Status) + fmt.Fprintf(writer, "Hash\t%s\n", r.tx.ID()) + fmt.Fprintf(writer, "Payer\t%s\n", r.tx.Payer.Hex()) + + fmt.Fprintf(writer, "Authorizers\t%s\n", r.tx.Authorizers) + fmt.Fprintf(writer, "Payer\t%s\n", r.tx.Payer) + + fmt.Fprintf(writer, + "\nProposal Key:\t\n Address\t%s\n Index\t%v\n Sequence\t%v\n", + r.tx.ProposalKey.Address, r.tx.ProposalKey.KeyIndex, r.tx.ProposalKey.SequenceNumber, + ) + + for i, e := range r.tx.PayloadSignatures { + fmt.Fprintf(writer, "\nPayload Signature %v:\n", i) + fmt.Fprintf(writer, " Address\t%s\n", e.Address) + fmt.Fprintf(writer, " Signature\t%x\n", e.Signature) + fmt.Fprintf(writer, " Key Index\t%d\n", e.KeyIndex) + } + + for i, e := range r.tx.EnvelopeSignatures { + fmt.Fprintf(writer, "\nEnvelope Signature %v:\n", i) + fmt.Fprintf(writer, " Address\t%s\n", e.Address) + fmt.Fprintf(writer, " Signature\t%x\n", e.Signature) + fmt.Fprintf(writer, " Key Index\t%d\n", e.KeyIndex) + } + + fmt.Fprintf(writer, "\n\nTransaction Payload:\n%x", r.tx.Encode()) + e := events.EventResult{ Events: r.result.Events, } From b65c37370889cec6a3b1b351cbed42537f607eab Mon Sep 17 00:00:00 2001 From: Gregor Gololicic Date: Fri, 2 Apr 2021 11:35:37 +0200 Subject: [PATCH 024/137] event output display improved --- internal/events/events.go | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/internal/events/events.go b/internal/events/events.go index bdd56efdb..7e2ea4404 100644 --- a/internal/events/events.go +++ b/internal/events/events.go @@ -111,10 +111,10 @@ func eventsString(writer io.Writer, events []flow.Event) { } func eventString(writer io.Writer, event flow.Event) { - fmt.Fprintf(writer, "\n\t Index\t %v\n", event.EventIndex) - fmt.Fprintf(writer, "\t Type\t %s\n", event.Type) - fmt.Fprintf(writer, "\t Tx ID\t %s\n", event.TransactionID) - fmt.Fprintf(writer, "\t Values\n") + fmt.Fprintf(writer, "\n Index\t%d\n", event.EventIndex) + fmt.Fprintf(writer, " Type\t%s\n", event.Type) + fmt.Fprintf(writer, " Tx ID\t%s\n", event.TransactionID) + fmt.Fprintf(writer, " Values\n") for i, field := range event.Value.EventType.Fields { value := event.Value.Fields[i] @@ -132,8 +132,8 @@ func printField(writer io.Writer, field cadence.Field, value cadence.Value) { typeInfo = "Address" } - fmt.Fprintf(writer, "\t\t") - fmt.Fprintf(writer, " %s (%s)\t", field.Identifier, typeInfo) + fmt.Fprintf(writer, "\t\t-") + fmt.Fprintf(writer, " %s (%s):\t", field.Identifier, typeInfo) // Try the two most obvious cases if address, ok := v.([8]byte); ok { fmt.Fprintf(writer, "%x", address) From 2d6ff1162496f36f8faace8d491c03a8c65cffdc Mon Sep 17 00:00:00 2001 From: Gregor Gololicic Date: Fri, 2 Apr 2021 13:15:29 +0200 Subject: [PATCH 025/137] command text fix --- internal/transactions/get.go | 2 +- internal/transactions/send.go | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/internal/transactions/get.go b/internal/transactions/get.go index 7e45127b3..dec34c163 100644 --- a/internal/transactions/get.go +++ b/internal/transactions/get.go @@ -34,7 +34,7 @@ var statusFlags = flagsStatus{} var GetCommand = &command.Command{ Cmd: &cobra.Command{ Use: "get ", - Short: "Get the transaction status", + Short: "Get transaction by ID", Args: cobra.ExactArgs(1), }, Flags: &statusFlags, diff --git a/internal/transactions/send.go b/internal/transactions/send.go index 77b4a1faa..25473846c 100644 --- a/internal/transactions/send.go +++ b/internal/transactions/send.go @@ -29,7 +29,7 @@ import ( type flagsSend struct { ArgsJSON string `default:"" flag:"args-json" info:"arguments in JSON-Cadence format"` Args []string `default:"" flag:"arg" info:"argument in Type:Value format"` - Signer string `default:"emulator-account" flag:"signer"` + Signer string `default:"emulator-account" flag:"signer" info:"name of the account used to sign"` Payload string `flag:"payload" info:"path to the transaction payload file"` Code string `default:"" flag:"code" info:"⚠️ DEPRECATED: use filename argument"` Results bool `default:"" flag:"results" info:"⚠️ DEPRECATED: all transactions will provide result"` From 20b18dafa2dfa26dec8a89f160bea813e8e2e27e Mon Sep 17 00:00:00 2001 From: Gregor Gololicic Date: Fri, 2 Apr 2021 13:15:56 +0200 Subject: [PATCH 026/137] sign result use from tx result --- internal/transactions/sign.go | 72 ++++------------------------------- 1 file changed, 7 insertions(+), 65 deletions(-) diff --git a/internal/transactions/sign.go b/internal/transactions/sign.go index 8e14c561b..e967d6511 100644 --- a/internal/transactions/sign.go +++ b/internal/transactions/sign.go @@ -1,11 +1,7 @@ package transactions import ( - "bytes" "fmt" - "text/tabwriter" - - "github.com/onflow/flow-cli/pkg/flowcli/project" "github.com/onflow/flow-cli/internal/command" "github.com/onflow/flow-cli/pkg/flowcli/services" @@ -15,12 +11,12 @@ import ( type flagsSign struct { ArgsJSON string `default:"" flag:"args-json" info:"arguments in JSON-Cadence format"` Args []string `default:"" flag:"arg" info:"argument in Type:Value format"` - Signer string `default:"emulator-account" flag:"signer"` + Signer string `default:"emulator-account" flag:"signer" info:"name of the account used to sign"` Payload string `flag:"payload" info:"path to the transaction payload file"` - Proposer string `default:"" flag:"proposer"` - Role string `default:"authorizer" flag:"role"` - AdditionalAuthorizers []string `flag:"additional-authorizers" info:"Additional authorizer addresses to add to the transaction"` - PayerAddress string `flag:"payer-address" info:"Specify payer of the transaction. Defaults to current signer."` + Proposer string `default:"" flag:"proposer" info:"name of the account that is proposing the transaction"` + Role string `default:"authorizer" flag:"role" info:"Specify a role of the signer, values: proposer, payer, authorizer"` + AdditionalAuthorizers []string `flag:"add-authorizer" info:"Additional authorizer addresses to add to the transaction"` + PayerAddress string `flag:"payer-address" info:"Specify payer of the transaction. Defaults to first signer."` } var signFlags = flagsSign{} @@ -67,62 +63,8 @@ var SignCommand = &command.Command{ return nil, err } - return &SignResult{ - signed: signed, + return &TransactionResult{ + tx: signed.FlowTransaction(), }, nil }, } - -type SignResult struct { - signed *project.Transaction -} - -// JSON convert result to JSON -func (r *SignResult) JSON() interface{} { - tx := r.signed.FlowTransaction() - result := make(map[string]string) - result["Payload"] = fmt.Sprintf("%x", tx.Encode()) - result["Authorizers"] = fmt.Sprintf("%s", tx.Authorizers) - - return result -} - -// String convert result to string -func (r *SignResult) String() string { - var b bytes.Buffer - writer := tabwriter.NewWriter(&b, 0, 8, 1, '\t', tabwriter.AlignRight) - tx := r.signed.FlowTransaction() - - fmt.Fprintf(writer, "Authorizers\t%s\n", tx.Authorizers) - fmt.Fprintf(writer, "Payer\t%s\n", tx.Payer) - - fmt.Fprintf(writer, - "\nProposal Key:\t\n Address\t%s\n Index\t%v\n Sequence\t%v\n", - tx.ProposalKey.Address, tx.ProposalKey.KeyIndex, tx.ProposalKey.SequenceNumber, - ) - - for i, e := range tx.PayloadSignatures { - fmt.Fprintf(writer, "\nPayload Signature %v:\n", i) - fmt.Fprintf(writer, " Address\t%s\n", e.Address) - fmt.Fprintf(writer, " Signature\t%x\n", e.Signature) - fmt.Fprintf(writer, " Key Index\t%v\n", e.KeyIndex) - } - - for i, e := range tx.EnvelopeSignatures { - fmt.Fprintf(writer, "\nEnvelope Signature %v:\n", i) - fmt.Fprintf(writer, " Address\t%s\n", e.Address) - fmt.Fprintf(writer, " Signature\t%s\n", e.Signature) - fmt.Fprintf(writer, " Key Index\t%s\n", e.KeyIndex) - } - - fmt.Fprintf(writer, "\n\nTransaction Payload:\n%x", tx.Encode()) - - writer.Flush() - return b.String() -} - -// Oneliner show result as one liner grep friendly -func (r *SignResult) Oneliner() string { - tx := r.signed.FlowTransaction() - return fmt.Sprintf("Payload: %x, Authorizers: %s", tx.Encode(), tx.Authorizers) -} From 57e473ba614dc607f836a2845d5d96c52b0d9ad5 Mon Sep 17 00:00:00 2001 From: Gregor Gololicic Date: Fri, 2 Apr 2021 13:16:17 +0200 Subject: [PATCH 027/137] tx from payload factory --- pkg/flowcli/project/transaction.go | 63 ++++++++++++++++++---------- pkg/flowcli/services/transactions.go | 60 ++++++++++++++------------ 2 files changed, 74 insertions(+), 49 deletions(-) diff --git a/pkg/flowcli/project/transaction.go b/pkg/flowcli/project/transaction.go index 298a6c49e..cfda86626 100644 --- a/pkg/flowcli/project/transaction.go +++ b/pkg/flowcli/project/transaction.go @@ -31,6 +31,36 @@ func NewTransaction() *Transaction { } } +func NewTransactionFromPayload(signer *Account, filename string, role string) (*Transaction, error) { + partialTxHex, err := ioutil.ReadFile(filename) + if err != nil { + return nil, fmt.Errorf("failed to read partial transaction from %s: %v", filename, err) + } + + partialTxBytes, err := hex.DecodeString(string(partialTxHex)) + if err != nil { + return nil, fmt.Errorf("failed to decode partial transaction from %s: %v", filename, err) + } + + decodedTx, err := flow.DecodeTransaction(partialTxBytes) + if err != nil { + return nil, fmt.Errorf("failed to decode transaction from %s: %v", filename, err) + } + + tx := &Transaction{ + tx: decodedTx, + } + + err = tx.SetSigner(signer) + if err != nil { + return nil, err + } + // we need to set the role here for signing purpose, so we know what to sign envelope or payload + tx.signerRole = signerRole(role) + + return tx, nil +} + func NewUpdateAccountContractTransaction(signer *Account, name string, source string) (*Transaction, error) { contract := templates.Contract{ Name: name, @@ -45,6 +75,7 @@ func NewUpdateAccountContractTransaction(signer *Account, name string, source st if err != nil { return nil, err } + tx.SetPayer(signer.Address()) return tx, nil } @@ -63,6 +94,7 @@ func NewAddAccountContractTransaction(signer *Account, name string, source strin if err != nil { return nil, err } + tx.SetPayer(signer.Address()) return tx, nil } @@ -114,6 +146,7 @@ func NewCreateAccountTransaction( if err != nil { return nil, err } + tx.SetPayer(signer.Address()) return tx, nil } @@ -122,7 +155,6 @@ type Transaction struct { signer *Account signerRole signerRole proposer *Account - payer flow.Address tx *flow.Transaction } @@ -134,24 +166,6 @@ func (t *Transaction) FlowTransaction() *flow.Transaction { return t.tx } -func (t *Transaction) SetPayloadFromFile(filename string) error { - partialTxHex, err := ioutil.ReadFile(filename) - if err != nil { - return fmt.Errorf("failed to read partial transaction from %s: %v", filename, err) - } - partialTxBytes, err := hex.DecodeString(string(partialTxHex)) - if err != nil { - return fmt.Errorf("failed to decode partial transaction from %s: %v", filename, err) - } - tx, err := flow.DecodeTransaction(partialTxBytes) - if err != nil { - return fmt.Errorf("failed to decode transaction from %s: %v", filename, err) - } - - t.tx = tx - return nil -} - func (t *Transaction) SetScriptWithArgsFromFile(filepath string, args []string, argsJSON string) error { script, err := util.LoadFile(filepath) if err != nil { @@ -187,10 +201,13 @@ func (t *Transaction) SetProposer(account *Account) error { } func (t *Transaction) SetPayer(address flow.Address) { - t.payer = address t.tx.SetPayer(address) } +func (t *Transaction) HasPayer() bool { + return t.tx.Payer != flow.EmptyAddress +} + func (t *Transaction) AddRawArguments(args []string, argsJSON string) error { txArguments, err := flowcli.ParseArguments(args, argsJSON) if err != nil { @@ -245,8 +262,8 @@ func (t *Transaction) SetSignerRole(role string) error { return err } } - if t.signerRole == SignerRolePayer && t.payer != t.signer.Address() { - return fmt.Errorf("role specified as Payer, but Payer address also provided, and different: %s != %s", t.payer, t.signer.Address()) + if t.signerRole == SignerRolePayer && t.tx.Payer != t.signer.Address() { + return fmt.Errorf("role specified as Payer, but Payer address also provided, and different: %s != %s", t.tx.Payer, t.signer.Address()) } return nil @@ -266,7 +283,7 @@ func (t *Transaction) Sign() (*Transaction, error) { return nil, fmt.Errorf("failed to sign transaction: %s", err) } } else { - // make sure we have at least signer as authorizer + // make sure we have at least signer as authorizer else add self if len(t.tx.Authorizers) == 0 { t.tx.AddAuthorizer(t.signer.Address()) } diff --git a/pkg/flowcli/services/transactions.go b/pkg/flowcli/services/transactions.go index 9c3d12557..fc4b1e4c5 100644 --- a/pkg/flowcli/services/transactions.go +++ b/pkg/flowcli/services/transactions.go @@ -88,12 +88,6 @@ func (t *Transactions) Sign( payloadFilename string, args []string, argsJSON string) (*project.Transaction, error) { - tx := project.NewTransaction() - - if payloadFilename != "" && scriptFilename != "" { - return nil, fmt.Errorf("both a partial transaction and Cadence code file provided, but cannot use both") - } - if t.project == nil { return nil, fmt.Errorf("missing configuration, initialize it: flow project init") } @@ -104,6 +98,25 @@ func (t *Transactions) Sign( return nil, fmt.Errorf("signer account: [%s] doesn't exists in configuration", signerName) } + if payloadFilename != "" && scriptFilename != "" { + return nil, fmt.Errorf("can not use both a transaction payload and Cadence code file") + } else if payloadFilename == "" && scriptFilename == "" { + return nil, fmt.Errorf("provide either a transaction payload or Cadence code file") + } + + // if we received already created transaction payload, create from payload and return signed + if payloadFilename != "" { + tx, err := project.NewTransactionFromPayload(signerAccount, payloadFilename, role) + if err != nil { + return nil, err + } + + return tx.Sign() + } + + // we are creating a new transaction + tx := project.NewTransaction() + err := tx.SetSigner(signerAccount) if err != nil { return nil, err @@ -114,6 +127,7 @@ func (t *Transactions) Sign( return nil, err } + // if proposer is specified and exists assign it if proposerName != "" { proposerAccount := t.project.AccountByName(proposerName) if proposerAccount == nil { @@ -126,32 +140,26 @@ func (t *Transactions) Sign( } } + // set payer if specified, else set current signer as payer if tx doesn't have one yet associated if payerAddress != "" { tx.SetPayer(flow.HexToAddress(payerAddress)) + } else if !tx.HasPayer() { + tx.SetPayer(signerAccount.Address()) } - if payloadFilename != "" { - err = tx.SetPayloadFromFile(payloadFilename) - if err != nil { - return nil, err - } - } else { - if scriptFilename != "" { - err = tx.SetScriptWithArgsFromFile(scriptFilename, args, argsJSON) - if err != nil { - return nil, err - } - } + err = tx.SetScriptWithArgsFromFile(scriptFilename, args, argsJSON) + if err != nil { + return nil, err + } - err = tx.AddAuthorizers(additionalAuthorizers) - if err != nil { - return nil, err - } + err = tx.AddAuthorizers(additionalAuthorizers) + if err != nil { + return nil, err + } - tx, err = t.gateway.PrepareTransactionPayload(tx) - if err != nil { - return nil, err - } + tx, err = t.gateway.PrepareTransactionPayload(tx) + if err != nil { + return nil, err } return tx.Sign() From c86a32aea59dde8c864aad0010d7c877d7254c8b Mon Sep 17 00:00:00 2001 From: Gregor Gololicic Date: Fri, 2 Apr 2021 13:16:27 +0200 Subject: [PATCH 028/137] improve tx result output --- internal/transactions/transactions.go | 41 +++++++++++++++------------ 1 file changed, 23 insertions(+), 18 deletions(-) diff --git a/internal/transactions/transactions.go b/internal/transactions/transactions.go index 96cdcefc3..adf25e885 100644 --- a/internal/transactions/transactions.go +++ b/internal/transactions/transactions.go @@ -52,11 +52,14 @@ type TransactionResult struct { func (r *TransactionResult) JSON() interface{} { result := make(map[string]string) result["Hash"] = r.tx.ID().String() - result["Status"] = r.result.Status.String() - result["Error"] = r.result.Error.Error() + result["Payload"] = fmt.Sprintf("%x", r.tx.Encode()) + result["Authorizers"] = fmt.Sprintf("%s", r.tx.Authorizers) + result["Payer"] = r.tx.Payer.String() if r.result != nil { result["Events"] = fmt.Sprintf("%s", r.result.Events) + result["Status"] = r.result.Status.String() + result["Error"] = r.result.Error.Error() } return result @@ -67,21 +70,21 @@ func (r *TransactionResult) String() string { var b bytes.Buffer writer := tabwriter.NewWriter(&b, 0, 8, 1, '\t', tabwriter.AlignRight) - if r.result.Error != nil { - fmt.Fprintf(writer, "❌ Transaction Error \n%s\n\n\n", r.result.Error.Error()) - } - - statusBadge := "" - if r.result.Status == flow.TransactionStatusSealed { - statusBadge = "✅" + if r.result != nil { + if r.result.Error != nil { + fmt.Fprintf(writer, "❌ Transaction Error \n%s\n\n\n", r.result.Error.Error()) + } + + statusBadge := "" + if r.result.Status == flow.TransactionStatusSealed { + statusBadge = "✅" + } + fmt.Fprintf(writer, "Status\t%s %s\n", statusBadge, r.result.Status) } - fmt.Fprintf(writer, "Status\t%s %s\n", statusBadge, r.result.Status) fmt.Fprintf(writer, "Hash\t%s\n", r.tx.ID()) fmt.Fprintf(writer, "Payer\t%s\n", r.tx.Payer.Hex()) - fmt.Fprintf(writer, "Authorizers\t%s\n", r.tx.Authorizers) - fmt.Fprintf(writer, "Payer\t%s\n", r.tx.Payer) fmt.Fprintf(writer, "\nProposal Key:\t\n Address\t%s\n Index\t%v\n Sequence\t%v\n", @@ -102,15 +105,17 @@ func (r *TransactionResult) String() string { fmt.Fprintf(writer, " Key Index\t%d\n", e.KeyIndex) } - fmt.Fprintf(writer, "\n\nTransaction Payload:\n%x", r.tx.Encode()) - - e := events.EventResult{ - Events: r.result.Events, + if r.result != nil { + e := events.EventResult{ + Events: r.result.Events, + } + fmt.Fprintf(writer, "\n\nEvents:\t %s\n", e.String()) } - fmt.Fprintf(writer, "Events\t %s\n", e.String()) + + fmt.Fprintf(writer, "\n\nPayload:\n%x", r.tx.Encode()) if r.code { - fmt.Fprintf(writer, "Code\n\n%s\n", r.tx.Script) + fmt.Fprintf(writer, "\n\nCode\n\n%s\n", r.tx.Script) } writer.Flush() From 9aafd6c8492865ed33197181fabb993389b06d06 Mon Sep 17 00:00:00 2001 From: Gregor Gololicic Date: Fri, 2 Apr 2021 13:16:43 +0200 Subject: [PATCH 029/137] wip docs --- docs/sign-transaction.md | 215 +++++++++++++++++++++++++++++++++++++++ tests/e2e_test.go | 7 +- 2 files changed, 219 insertions(+), 3 deletions(-) create mode 100644 docs/sign-transaction.md diff --git a/docs/sign-transaction.md b/docs/sign-transaction.md new file mode 100644 index 000000000..1db61f4da --- /dev/null +++ b/docs/sign-transaction.md @@ -0,0 +1,215 @@ +```bash +Authorizers [f8d6e0586b0a20c7] + +Proposal Key: + Address f8d6e0586b0a20c7 + Index 0 + Sequence 16 + +Payload Signature 0: + Address f8d6e0586b0a20c7...e888b1a5840e8881caa78208a45ac1ce9f77d98cb85ac982c4c8ca6b3510 + Key Index 0 + + +Transaction Payload: +f90183f90137b8d17472616e73616374696f6e286772656574696e673a20537472696e6729207b0a20206c657420677 +56573743a20416464726573730a0a20207072657061726528617574686f72697a65723a20417574684163636f756e74 +29207b0a2020202073656c662e6775657374203d20617574686f72697a65722e616464726573730a20207d0a0a20206 +5786563757465207b0a202020206c6f67286772656574696e672e636f6e63617428222c22292e636f6e636174287365 +6c662e67756573742e746f537472696e67282929290a20207d0a7de1a07b2274797065223a22537472696e67222c227 + + +``` + + +Example: + +Simple two step sign send +``` +> transactions sign ./tests/transaction.cdc --arg String:"Foo" + +Authorizers [f8d6e0586b0a20c7] +Payer f8d6e0586b0a20c7 + +Proposal Key: + Address f8d6e0586b0a20c7 + Index 0 + Sequence 4 + +Payload Signature 0: + Address f8d6e0586b0a20c7 + Signature bccac2e89d0407300a1a24f900757cdf15a49ef5e9ca92cc6cc54ea56ddda841bc8f47b803e5a97768f155d105376d62d40c2dbeaa822944289b92ad7eb33b9b + Key Index 0 + + +Transaction Payload: +f90183f90137b8d17472616e73616374696f6e286772656574696e673a20537472696e6729207b0a20206c65742067756573743a20416464726573730a0a20207072657061726528617574686f72697a65723a20417574684163636f756e7429207b0a2020202073656c662e6775657374203d20617574686f72697a65722e616464726573730a20207d0a0a202065786563757465207b0a202020206c6f67286772656574696e672e636f6e63617428222c22292e636f6e6361742873656c662e67756573742e746f537472696e67282929290a20207d0a7de1a07b2274797065223a22537472696e67222c2276616c7565223a22466f6f227d0aa076a251f4028186c2a934efa598e2cd41a6a33700893ae7098475cd05cc6c37fb8203e888f8d6e0586b0a20c7800488f8d6e0586b0a20c7c988f8d6e0586b0a20c7f846f8448080b840bccac2e89d0407300a1a24f900757cdf15a49ef5e9ca92cc6cc54ea56ddda841bc8f47b803e5a97768f155d105376d62d40c2dbeaa822944289b92ad7eb33b9bc0 + + +> transactions send --payload payload1 + +Hash 3130447e195587ef7a01ad40effd281680a02e7411b204391c837d451e246d42 +Status SEALED +Payer f8d6e0586b0a20c7 +Events + + +``` + + +Different Payer: +``` +> keys generate +🔴️ Store Private Key safely and don't share with anyone! +Private Key 8fea7a92c85aa1b653eb5fe407842886b76a2c009b800e82c570767cf010f384 +Public Key ad26f02fbdd3f372e2fbcf94bf0374c9502e6fdf2446a3009772642195b811be528143217139d8111dda7a7b30f7a57ec798cc12d86d2e850f5e0cccbb195da2 + +> accounts create --key ad26f02fbdd3f372e2fbcf94bf0374c9502e6fdf2446a3009772642195b811be528143217139d8111dda7a7b30f7a57ec798cc12d86d2e850f5e0cccbb195da2 +Address 0x179b6b1cb6755e31 +Balance 10000000 +Keys 1 + +Key 0 Public Key ad26f02fbdd3f372e2fbcf94bf0374c9502e6fdf2446a3009772642195b811be528143217139d8111dda7a7b30f7a57ec798cc12d86d2e850f5e0cccbb195da2 + Weight 1000 + Signature Algorithm ECDSA_P256 + Hash Algorithm SHA3_256 + +Contracts Deployed: 0 + + +> transactions sign ./tests/transaction.cdc --arg String:"Foo" --payer-address 0x179b6b1cb6755e31 --filter Payload --save payload2 + +> cmd/flow/main.go transactions sign --payload payload2 --role payer --signer payer-account + +Authorizers [f8d6e0586b0a20c7] +Payer 179b6b1cb6755e31 + +Proposal Key: + Address f8d6e0586b0a20c7 + Index 0 + Sequence 3 + +Payload Signature 0: + Address f8d6e0586b0a20c7 + Signature ce858a8bd8a58d29f2cf37e4de1aad2d6c577b342ef285e02762cf224614d90bac8de3fe0ea742e0c5d78e4dc981c0e84ba1d208fc4ec4554bd9e732290567ee + Key Index 0 + +Envelope Signature 0: + Address 179b6b1cb6755e31 + Signature 4ba3a88be452a684f54b29a9ddc72469a98f3863992d173ed0ab3c52efe7f0c0c0a4fc03d343c971086929f097e5c1032655b61efc3a5e87ea3ab22755aad409 + Key Index 0 + + +Transaction Payload: +f901caf90137b8d17472616e73616374696f6e286772656574696e673a20537472696e6729207b0a20206c65742067756573743a20416464726573730a0a20207072657061726528617574686f72697a65723a20417574684163636f756e7429207b0a2020202073656c662e6775657374203d20617574686f72697a65722e616464726573730a20207d0a0a202065786563757465207b0a202020206c6f67286772656574696e672e636f6e63617428222c22292e636f6e6361742873656c662e67756573742e746f537472696e67282929290a20207d0a7de1a07b2274797065223a22537472696e67222c2276616c7565223a22466f6f227d0aa0baaeb14e65391f51236b203665764aae224171aefc60bbfd1c2899a56e604c128203e888f8d6e0586b0a20c7800388179b6b1cb6755e31c988f8d6e0586b0a20c7f846f8448080b840ce858a8bd8a58d29f2cf37e4de1aad2d6c577b342ef285e02762cf224614d90bac8de3fe0ea742e0c5d78e4dc981c0e84ba1d208fc4ec4554bd9e732290567eef846f8440180b8404ba3a88be452a684f54b29a9ddc72469a98f3863992d173ed0ab3c52efe7f0c0c0a4fc03d343c971086929f097e5c1032655b61efc3a5e87ea3ab22755aad409 + + + + + +> go run cmd/flow/main.go transactions send --payload payload3 + +Hash 047b9fab1ff28fd7fed35672c611dcef40ace745ed535417dae714062497dec4 +Status SEALED +Payer 179b6b1cb6755e31 +Events + +``` + +Different Authorizer + +``` + +> transactions sign ./tests/transaction.cdc --arg String:"Foo" --add-authorizer 179b6b1cb6755e31 + +Authorizers [f8d6e0586b0a20c7 179b6b1cb6755e31] +Payer 0000000000000000 + +Proposal Key: + Address f8d6e0586b0a20c7 + Index 0 + Sequence 4 + +Payload Signature 0: + Address f8d6e0586b0a20c7 + Signature 64c0a6cb39c55364cff5c6d73622d22165efa994deb9a5b8b53ff80f0931db74380311ff9765bafcbce666d9b407638d9b0e26ad97b7a9dad963337d623b0de3 + Key Index 0 + + +Transaction Payload: +f9018cf90140b8d17472616e73616374696f6e286772656574696e673a20537472696e6729207b0a20206c65742067756573743a20416464726573730a0a20207072657061726528617574686f72697a65723a20417574684163636f756e7429207b0a2020202073656c662e6775657374203d20617574686f72697a65722e616464726573730a20207d0a0a202065786563757465207b0a202020206c6f67286772656574696e672e636f6e63617428222c22292e636f6e6361742873656c662e67756573742e746f537472696e67282929290a20207d0a7de1a07b2274797065223a22537472696e67222c2276616c7565223a22466f6f227d0aa076a251f4028186c2a934efa598e2cd41a6a33700893ae7098475cd05cc6c37fb8203e888f8d6e0586b0a20c78004880000000000000000d288f8d6e0586b0a20c788179b6b1cb6755e31f846f8448080b84064c0a6cb39c55364cff5c6d73622d22165efa994deb9a5b8b53ff80f0931db74380311ff9765bafcbce666d9b407638d9b0e26ad97b7a9dad963337d623b0de3c0 + + + +> transactions sign --payload payload1 --signer payer-account + +Hash 9f6b7f270c1471991890935f3eb82d9913e9ad172e0bb5f0d445a8a511e5e4df +Payer f8d6e0586b0a20c7 +Authorizers [f8d6e0586b0a20c7 179b6b1cb6755e31] + +Proposal Key: + Address f8d6e0586b0a20c7 + Index 0 + Sequence 5 + +Payload Signature 0: + Address f8d6e0586b0a20c7 + Signature 5c56f2e465b13f289f341733a95b8673aeb9bfa8e3ed9021ca6d51a0b59a4ed278ef95491efdfb7c30e6d599d52358b4b698431782096e7e38a499130dfaeb1e + Key Index 0 + +Payload Signature 1: + Address 179b6b1cb6755e31 + Signature ca04dafea2a5438ba6d5ac7811bc2656035a23001eee3c96ddf581d015683006c42943b8475d3c61e6131578cc3fe80470ae8706e489b186bc2b333ff12f7282 + Key Index 0 + + +Payload: +f901d2f90140b8d17472616e73616374696f6e286772656574696e673a20537472696e6729207b0a20206c65742067756573743a20416464726573730a0a20207072657061726528617574686f72697a65723a20417574684163636f756e7429207b0a2020202073656c662e6775657374203d20617574686f72697a65722e616464726573730a20207d0a0a202065786563757465207b0a202020206c6f67286772656574696e672e636f6e63617428222c22292e636f6e6361742873656c662e67756573742e746f537472696e67282929290a20207d0a7de1a07b2274797065223a22537472696e67222c2276616c7565223a22466f6f227d0aa0ff25bc88a84e5989cafda9da5e55baa9308e511a12fd4d2788c0c359c3f1e6738203e888f8d6e0586b0a20c7800588f8d6e0586b0a20c7d288f8d6e0586b0a20c788179b6b1cb6755e31f88cf8448080b8405c56f2e465b13f289f341733a95b8673aeb9bfa8e3ed9021ca6d51a0b59a4ed278ef95491efdfb7c30e6d599d52358b4b698431782096e7e38a499130dfaeb1ef8440180b840ca04dafea2a5438ba6d5ac7811bc2656035a23001eee3c96ddf581d015683006c42943b8475d3c61e6131578cc3fe80470ae8706e489b186bc2b333ff12f7282c0 + + + + +> transactions send --payload payload2 + + +❌ Transaction Error +execution error code 100: Execution failed: +error: authorizer count mismatch for transaction: expected 1, got 2 +--> 5fde5868a7f23b64335fea2c92eee97272bdc3d6bd5389a26ba25c496fe141e8 + + + +Status ✅ SEALED +Hash 5fde5868a7f23b64335fea2c92eee97272bdc3d6bd5389a26ba25c496fe141e8 +Payer f8d6e0586b0a20c7 +Authorizers [f8d6e0586b0a20c7 179b6b1cb6755e31] + +Proposal Key: + Address f8d6e0586b0a20c7 + Index 0 + Sequence 5 + +Payload Signature 0: + Address f8d6e0586b0a20c7 + Signature 5c56f2e465b13f289f341733a95b8673aeb9bfa8e3ed9021ca6d51a0b59a4ed278ef95491efdfb7c30e6d599d52358b4b698431782096e7e38a499130dfaeb1e + Key Index 0 + +Payload Signature 1: + Address 179b6b1cb6755e31 + Signature d02d792d0157ce357b87a1a8381e7a8a599386782d5ac0ae0738d2c1f1e96d495aad6fc058f0f81b6dfecc0c72b2358c55cfe6f68aaf13882cf177f48d44c337 + Key Index 0 + +Envelope Signature 0: + Address f8d6e0586b0a20c7 + Signature 2fce0b37e3cc7c44b0e709c7d2a8f145bf9af9aab8be7b1e4e76e20a1e6abc67958dd1be5c4a19f2283c9cddc9ace243688a3c2198858a502551dfd70b32790a + Key Index 0 + + +Events: + + +Payload: +f90219f90140b8d17472616e73616374696f6e286772656574696e673a20537472696e6729207b0a20206c65742067756573743a20416464726573730a0a20207072657061726528617574686f72697a65723a20417574684163636f756e7429207b0a2020202073656c662e6775657374203d20617574686f72697a65722e616464726573730a20207d0a0a202065786563757465207b0a202020206c6f67286772656574696e672e636f6e63617428222c22292e636f6e6361742873656c662e67756573742e746f537472696e67282929290a20207d0a7de1a07b2274797065223a22537472696e67222c2276616c7565223a22466f6f227d0aa0ff25bc88a84e5989cafda9da5e55baa9308e511a12fd4d2788c0c359c3f1e6738203e888f8d6e0586b0a20c7800588f8d6e0586b0a20c7d288f8d6e0586b0a20c788179b6b1cb6755e31f88cf8448080b8405c56f2e465b13f289f341733a95b8673aeb9bfa8e3ed9021ca6d51a0b59a4ed278ef95491efdfb7c30e6d599d52358b4b698431782096e7e38a499130dfaeb1ef8440180b840d02d792d0157ce357b87a1a8381e7a8a599386782d5ac0ae0738d2c1f1e96d495aad6fc058f0f81b6dfecc0c72b2358c55cfe6f68aaf13882cf177f48d44c337f846f8448080b8402fce0b37e3cc7c44b0e709c7d2a8f145bf9af9aab8be7b1e4e76e20a1e6abc67958dd1be5c4a19f2283c9cddc9ace243688a3c2198858a502551dfd70b32790a + + +``` \ No newline at end of file diff --git a/tests/e2e_test.go b/tests/e2e_test.go index de41e8c29..fc4b538a1 100644 --- a/tests/e2e_test.go +++ b/tests/e2e_test.go @@ -222,9 +222,9 @@ func TestScripts(t *testing.T) { } func TestTransactions(t *testing.T) { - //if e2e == "" { - // t.Skip("Skipping end-to-end tests") - //} + if e2e == "" { + t.Skip("Skipping end-to-end tests") + } gw, err := gateway.NewGrpcGateway(host) assert.NoError(t, err) @@ -249,6 +249,7 @@ func TestTransactions(t *testing.T) { tx, tr, err := transactions.Send("./transactionErr.cdc", "", emulatorAccount, []string{}, "") assert.NoError(t, err) + assert.NotNil(t, tr.Error) assert.Equal(t, tx.Payer.String(), serviceAddress) assert.Equal(t, tr.Status.String(), "SEALED") require.Greater(t, len(tr.Error.Error()), 100) From eb99a6ce8d3c7d614fe3867874734ce1ba3876a2 Mon Sep 17 00:00:00 2001 From: Gregor Gololicic Date: Fri, 2 Apr 2021 14:41:49 +0200 Subject: [PATCH 030/137] spinner fix to not take new line --- pkg/flowcli/output/logger.go | 8 ++++---- pkg/flowcli/output/spinner.go | 9 ++++----- pkg/flowcli/services/accounts.go | 10 +++++----- pkg/flowcli/services/blocks.go | 2 +- pkg/flowcli/services/events.go | 2 +- pkg/flowcli/services/project.go | 10 ++++------ pkg/flowcli/services/transactions.go | 6 +++--- 7 files changed, 22 insertions(+), 25 deletions(-) diff --git a/pkg/flowcli/output/logger.go b/pkg/flowcli/output/logger.go index c8a6f7901..045ed0780 100644 --- a/pkg/flowcli/output/logger.go +++ b/pkg/flowcli/output/logger.go @@ -37,7 +37,7 @@ type Logger interface { Info(string) Error(string) StartProgress(string) - StopProgress(string) + StopProgress() } // NewStdoutLogger create new logger @@ -82,20 +82,20 @@ func (s *StdoutLogger) StartProgress(msg string) { } if s.spinner != nil { - s.spinner.Stop("") + s.spinner.Stop() } s.spinner = NewSpinner(msg, "") s.spinner.Start() } -func (s *StdoutLogger) StopProgress(msg string) { +func (s *StdoutLogger) StopProgress() { if s.level == NoneLog { return } if s.spinner != nil { - s.spinner.Stop(msg) + s.spinner.Stop() s.spinner = nil } } diff --git a/pkg/flowcli/output/spinner.go b/pkg/flowcli/output/spinner.go index e67e0e65a..d26e6db6a 100644 --- a/pkg/flowcli/output/spinner.go +++ b/pkg/flowcli/output/spinner.go @@ -54,8 +54,8 @@ func (s *Spinner) run() { for { select { - case message := <-s.done: - _, _ = fmt.Fprintln(writer, message) + case <-s.done: + _, _ = fmt.Fprintf(writer, "\r") _ = writer.Flush() close(s.done) return @@ -73,7 +73,6 @@ func (s *Spinner) run() { } } -func (s *Spinner) Stop(message string) { - s.done <- message - <-s.done +func (s *Spinner) Stop() { + s.done <- "" } diff --git a/pkg/flowcli/services/accounts.go b/pkg/flowcli/services/accounts.go index ed2799733..aee47ffa3 100644 --- a/pkg/flowcli/services/accounts.go +++ b/pkg/flowcli/services/accounts.go @@ -64,7 +64,7 @@ func (a *Accounts) Get(address string) (*flow.Account, error) { flowAddress := flow.HexToAddress(address) account, err := a.gateway.GetAccount(flowAddress) - a.logger.StopProgress("") + a.logger.StopProgress() return account, err } @@ -192,7 +192,7 @@ func (a *Accounts) StakingInfo(accountAddress string) (*cadence.Value, *cadence. return nil, nil, fmt.Errorf("error getting delegation info: %s", err.Error()) } - a.logger.StopProgress("") + a.logger.StopProgress() return &stakingValue, &delegationValue, nil } @@ -264,7 +264,7 @@ func (a *Accounts) Create( return nil, fmt.Errorf("new account address couldn't be fetched") } - a.logger.StopProgress("") + a.logger.StopProgress() return a.gateway.GetAccount(*newAccountAddress) } @@ -359,7 +359,7 @@ func (a *Accounts) addContract( update, err := a.gateway.GetAccount(account.Address()) - a.logger.StopProgress("") + a.logger.StopProgress() if updateExisting { a.logger.Info(fmt.Sprintf("Contract '%s' updated on the account '%s'.", contractName, account.Address())) @@ -424,7 +424,7 @@ func (a *Accounts) removeContract( return nil, txr.Error } - a.logger.StopProgress("") + a.logger.StopProgress() a.logger.Info(fmt.Sprintf("Contract %s removed from account %s\n", contractName, account.Address())) return a.gateway.GetAccount(account.Address()) diff --git a/pkg/flowcli/services/blocks.go b/pkg/flowcli/services/blocks.go index 64f85ff83..fcabf00f7 100644 --- a/pkg/flowcli/services/blocks.go +++ b/pkg/flowcli/services/blocks.go @@ -99,7 +99,7 @@ func (e *Blocks) GetBlock( } } - e.logger.StopProgress("") + e.logger.StopProgress() return block, events, collections, err } diff --git a/pkg/flowcli/services/events.go b/pkg/flowcli/services/events.go index 0cfc25044..8b27dc21a 100644 --- a/pkg/flowcli/services/events.go +++ b/pkg/flowcli/services/events.go @@ -94,6 +94,6 @@ func (e *Events) Get(name string, start string, end string) ([]client.BlockEvent return nil, err } - e.logger.StopProgress("") + e.logger.StopProgress() return events, nil } diff --git a/pkg/flowcli/services/project.go b/pkg/flowcli/services/project.go index c5d83f0c2..309dcd91b 100644 --- a/pkg/flowcli/services/project.go +++ b/pkg/flowcli/services/project.go @@ -176,13 +176,11 @@ func (p *Project) Deploy(network string, update bool) ([]*contracts.Contract, er } if result.Error == nil { - p.logger.StopProgress( - fmt.Sprintf("%s -> 0x%s", util.Green(contract.Name()), contract.Target()), - ) + p.logger.StopProgress() + fmt.Printf("%s -> 0x%s\n", util.Green(contract.Name()), contract.Target()) + } else { - p.logger.StopProgress( - fmt.Sprintf("%s error", util.Red(contract.Name())), - ) + p.logger.StopProgress() p.logger.Error( fmt.Sprintf("%s error: %s", contract.Name(), result.Error), ) diff --git a/pkg/flowcli/services/transactions.go b/pkg/flowcli/services/transactions.go index fc4b1e4c5..ab3f98b78 100644 --- a/pkg/flowcli/services/transactions.go +++ b/pkg/flowcli/services/transactions.go @@ -72,7 +72,7 @@ func (t *Transactions) GetStatus( result, err := t.gateway.GetTransactionResult(tx, waitSeal) - t.logger.StopProgress("") + t.logger.StopProgress() return tx, result, err } @@ -200,7 +200,7 @@ func (t *Transactions) Send( res, err := t.gateway.GetTransactionResult(tx, true) - t.logger.StopProgress("") + t.logger.StopProgress() return tx, res, err } @@ -249,6 +249,6 @@ func (t *Transactions) SendForAddressWithCode( res, err := t.gateway.GetTransactionResult(sentTx, true) - t.logger.StopProgress("") + t.logger.StopProgress() return sentTx, res, err } From f51c13389f16a43927057784842f995597db0af6 Mon Sep 17 00:00:00 2001 From: Gregor Gololicic Date: Fri, 2 Apr 2021 17:20:20 +0200 Subject: [PATCH 031/137] improved tx output --- internal/transactions/transactions.go | 31 +++++++++++++++++++++++---- 1 file changed, 27 insertions(+), 4 deletions(-) diff --git a/internal/transactions/transactions.go b/internal/transactions/transactions.go index adf25e885..f011b327d 100644 --- a/internal/transactions/transactions.go +++ b/internal/transactions/transactions.go @@ -91,6 +91,14 @@ func (r *TransactionResult) String() string { r.tx.ProposalKey.Address, r.tx.ProposalKey.KeyIndex, r.tx.ProposalKey.SequenceNumber, ) + if len(r.tx.PayloadSignatures) == 0 { + fmt.Fprintf(writer, "\nNo Payload Signatures\n") + } + + if len(r.tx.EnvelopeSignatures) == 0 { + fmt.Fprintf(writer, "\nNo Envelope Signatures\n") + } + for i, e := range r.tx.PayloadSignatures { fmt.Fprintf(writer, "\nPayload Signature %v:\n", i) fmt.Fprintf(writer, " Address\t%s\n", e.Address) @@ -109,15 +117,30 @@ func (r *TransactionResult) String() string { e := events.EventResult{ Events: r.result.Events, } - fmt.Fprintf(writer, "\n\nEvents:\t %s\n", e.String()) + + eventsOutput := e.String() + if eventsOutput == "" { + eventsOutput = "None" + } + + fmt.Fprintf(writer, "\n\nEvents:\t %s\n", eventsOutput) } - fmt.Fprintf(writer, "\n\nPayload:\n%x", r.tx.Encode()) + if r.tx.Script != nil { + if len(r.tx.Arguments) == 0 { + fmt.Fprintf(writer, "\n\nArguments\tNo arguments\n") + } else { + fmt.Fprintf(writer, "\n\nArguments (%d):\n", len(r.tx.Arguments)) + for i, argument := range r.tx.Arguments { + fmt.Fprintf(writer, " - Argument %d: %s\n", i, argument) + } + } - if r.code { - fmt.Fprintf(writer, "\n\nCode\n\n%s\n", r.tx.Script) + fmt.Fprintf(writer, "\nCode\n\n%s\n", r.tx.Script) } + fmt.Fprintf(writer, "\n\nPayload:\n%x", r.tx.Encode()) + writer.Flush() return b.String() } From 8d8bd30f3159a7709630eff438383e4b6e7cf3f4 Mon Sep 17 00:00:00 2001 From: Gregor Gololicic Date: Fri, 2 Apr 2021 17:20:29 +0200 Subject: [PATCH 032/137] approve signing --- pkg/flowcli/services/transactions.go | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/pkg/flowcli/services/transactions.go b/pkg/flowcli/services/transactions.go index ab3f98b78..7b050ccf9 100644 --- a/pkg/flowcli/services/transactions.go +++ b/pkg/flowcli/services/transactions.go @@ -111,7 +111,12 @@ func (t *Transactions) Sign( return nil, err } - return tx.Sign() + approved, err := output.ApproveTransactionPrompt(tx) + if approved { + return tx.Sign() + } else { + return nil, fmt.Errorf("transaction was not approved for signing") + } } // we are creating a new transaction From 1c27ef4dc4f433e3d1e9341db220d99354a02fb5 Mon Sep 17 00:00:00 2001 From: Gregor Gololicic Date: Fri, 2 Apr 2021 17:20:41 +0200 Subject: [PATCH 033/137] helpers --- go.mod | 1 + go.sum | 7 +++++++ pkg/flowcli/util/utilities.go | 9 +++++++++ 3 files changed, 17 insertions(+) diff --git a/go.mod b/go.mod index 98f622737..b069667f5 100644 --- a/go.mod +++ b/go.mod @@ -8,6 +8,7 @@ require ( github.com/fsnotify/fsnotify v1.4.9 // indirect github.com/gosuri/uilive v0.0.4 github.com/kr/text v0.2.0 // indirect + github.com/manifoldco/promptui v0.8.0 github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e // indirect github.com/onflow/cadence v0.13.7 github.com/onflow/cadence/languageserver v0.13.1 diff --git a/go.sum b/go.sum index c15688bf5..aa9cf9e26 100644 --- a/go.sum +++ b/go.sum @@ -128,6 +128,7 @@ github.com/cespare/xxhash/v2 v2.1.1/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XL github.com/cheekybits/genny v1.0.0 h1:uGGa4nei+j20rOSeDeP5Of12XVm7TGUd4dJA9RDitfE= github.com/cheekybits/genny v1.0.0/go.mod h1:+tQajlRqAUrPI7DOSpB0XAqZYtQakVtB7wXkRAgjxjQ= github.com/chzyer/logex v1.1.10/go.mod h1:+Ywpsq7O8HXn0nuIou7OrIPyXbp3wmkHB+jjWRnGsAI= +github.com/chzyer/readline v0.0.0-20180603132655-2972be24d48e h1:fY5BOSpyZCqRo5OhCuC+XN+r/bBCmeuuJtjz+bCNIf8= github.com/chzyer/readline v0.0.0-20180603132655-2972be24d48e/go.mod h1:nSuG5e5PlCu98SY8svDHJxuZscDgtXS6KTTbou5AhLI= github.com/chzyer/test v0.0.0-20180213035817-a1ea475d72b1/go.mod h1:Q3SI9o4m/ZMnBNeIyt5eFwwo7qiLfzFZmjNmxjkiQlU= github.com/clbanning/x2j v0.0.0-20191024224557-825249438eec/go.mod h1:jMjuTZXRI4dUb/I5gc9Hdhagfvm9+RyrPryS/auMzxE= @@ -426,6 +427,8 @@ github.com/jstemmer/go-junit-report v0.0.0-20190106144839-af01ea7f8024/go.mod h1 github.com/jstemmer/go-junit-report v0.9.1/go.mod h1:Brl9GWCQeLvo8nXZwPNNblvFj/XSXhF0NWZEnDohbsk= github.com/jtolds/gls v4.20.0+incompatible h1:xdiiI2gbIgH/gLH7ADydsJ1uDOEzR8yvV7C0MuV77Wo= github.com/jtolds/gls v4.20.0+incompatible/go.mod h1:QJZ7F/aHp+rZTRtaJ1ow/lLfFfVYBRgL+9YlvaHOwJU= +github.com/juju/ansiterm v0.0.0-20180109212912-720a0952cc2a h1:FaWFmfWdAUKbSCtOU2QjDaorUexogfaMgbipgYATUMU= +github.com/juju/ansiterm v0.0.0-20180109212912-720a0952cc2a/go.mod h1:UJSiEoRfvx3hP73CvoARgeLjaIOjybY9vj8PUPPFGeU= github.com/julienschmidt/httprouter v1.1.1-0.20170430222011-975b5c4c7c21/go.mod h1:SYymIcj16QtmaHHD7aYtjjsJG7VTCxuUUipMqKk8s4w= github.com/julienschmidt/httprouter v1.2.0/go.mod h1:SYymIcj16QtmaHHD7aYtjjsJG7VTCxuUUipMqKk8s4w= github.com/julienschmidt/httprouter v1.3.0/go.mod h1:JR6WtHb+2LUe8TCKY3cZOxFyyO8IZAc4RVcycCCAKdM= @@ -600,6 +603,8 @@ github.com/lightstep/lightstep-tracer-common/golang/gogo v0.0.0-20190605223551-b github.com/lightstep/lightstep-tracer-go v0.18.1/go.mod h1:jlF1pusYV4pidLvZ+XD0UBX0ZE6WURAspgAczcDHrL4= github.com/logrusorgru/aurora v0.0.0-20200102142835-e9ef32dff381 h1:bqDmpDG49ZRnB5PcgP0RXtQvnMSgIF14M7CBd2shtXs= github.com/logrusorgru/aurora v0.0.0-20200102142835-e9ef32dff381/go.mod h1:7rIyQOR62GCctdiQpZ/zOJlFyk6y+94wXzv6RNZgaR4= +github.com/lunixbochs/vtclean v0.0.0-20180621232353-2d01aacdc34a h1:weJVJJRzAJBFRlAiJQROKQs8oC9vOxvm4rZmBBk0ONw= +github.com/lunixbochs/vtclean v0.0.0-20180621232353-2d01aacdc34a/go.mod h1:pHhQNgMf3btfWnGBVipUOjRYhoOsdGqdm/+2c2E2WMI= github.com/lyft/protoc-gen-validate v0.0.13/go.mod h1:XbGvPuh87YZc5TdIa2/I4pLk0QoUACkjt2znoq26NVQ= github.com/m4ksio/wal v1.0.0 h1:PucHOZPz58BgWowe+Gf+gZUbgEdd4zFx+He45SGkHG0= github.com/m4ksio/wal v1.0.0/go.mod h1:S3UyatBTuMdoI5QTuz2DWb8Csd9568vYrFAmMI/bnMw= @@ -607,6 +612,8 @@ github.com/magiconair/properties v1.8.0/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czP github.com/magiconair/properties v1.8.1 h1:ZC2Vc7/ZFkGmsVC9KvOjumD+G5lXy2RtTKyzRKO2BQ4= github.com/magiconair/properties v1.8.1/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czPbwD3XqdrwzmxQ= github.com/mailru/easyjson v0.0.0-20180823135443-60711f1a8329/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc= +github.com/manifoldco/promptui v0.8.0 h1:R95mMF+McvXZQ7j1g8ucVZE1gLP3Sv6j9vlF9kyRqQo= +github.com/manifoldco/promptui v0.8.0/go.mod h1:n4zTdgP0vr0S3w7/O/g98U+e0gwLScEXGwov2nIKuGQ= github.com/mattn/go-colorable v0.0.9/go.mod h1:9vuHe8Xs5qXnSaW/c/ABM9alt+Vo+STaOChaDxuIBZU= github.com/mattn/go-colorable v0.1.0/go.mod h1:9vuHe8Xs5qXnSaW/c/ABM9alt+Vo+STaOChaDxuIBZU= github.com/mattn/go-colorable v0.1.1/go.mod h1:FuOcm+DKB9mbwrcAfNl7/TZVBZ6rcnceauSikq3lYCQ= diff --git a/pkg/flowcli/util/utilities.go b/pkg/flowcli/util/utilities.go index 27069a21f..797b92a2a 100644 --- a/pkg/flowcli/util/utilities.go +++ b/pkg/flowcli/util/utilities.go @@ -99,3 +99,12 @@ func GetAddressNetwork(address flow.Address) (flow.ChainID, error) { return flow.ChainID(""), fmt.Errorf("unrecognized address not valid for any known chain: %s", address) } + +func ContainsString(s []string, e string) bool { + for _, a := range s { + if a == e { + return true + } + } + return false +} From 0dcf78a2043cf62ba37a24e385f8e06e23c99a8b Mon Sep 17 00:00:00 2001 From: Gregor Gololicic Date: Fri, 2 Apr 2021 17:20:50 +0200 Subject: [PATCH 034/137] added prompts --- pkg/flowcli/output/prompt.go | 79 ++++++++++++++++++++++++++++++++++++ 1 file changed, 79 insertions(+) create mode 100644 pkg/flowcli/output/prompt.go diff --git a/pkg/flowcli/output/prompt.go b/pkg/flowcli/output/prompt.go new file mode 100644 index 000000000..10c5f7df4 --- /dev/null +++ b/pkg/flowcli/output/prompt.go @@ -0,0 +1,79 @@ +package output + +import ( + "fmt" + + "github.com/gosuri/uilive" + "github.com/manifoldco/promptui" + + "github.com/onflow/flow-cli/pkg/flowcli/project" +) + +func ApproveTransactionPrompt(transaction *project.Transaction) (bool, error) { + writer := uilive.New() + tx := transaction.FlowTransaction() + + fmt.Fprintf(writer, "\n") + fmt.Fprintf(writer, "Hash\t%s\n", tx.ID()) + fmt.Fprintf(writer, "Payer\t%x\n", tx.Payer) + fmt.Fprintf(writer, "Authorizers\t%s\n", tx.Authorizers) + + fmt.Fprintf(writer, + "\nProposal Key:\t\n Address\t%s\n Index\t%v\n Sequence\t%v\n", + tx.ProposalKey.Address, tx.ProposalKey.KeyIndex, tx.ProposalKey.SequenceNumber, + ) + + if len(tx.PayloadSignatures) == 0 { + fmt.Fprintf(writer, "\nNo Payload Signatures\n") + } + + if len(tx.EnvelopeSignatures) == 0 { + fmt.Fprintf(writer, "\nNo Envelope Signatures\n") + } + + for i, e := range tx.PayloadSignatures { + fmt.Fprintf(writer, "\nPayload Signature %v:\n", i) + fmt.Fprintf(writer, " Address\t%s\n", e.Address) + fmt.Fprintf(writer, " Signature\t%x\n", e.Signature) + fmt.Fprintf(writer, " Key Index\t%d\n", e.KeyIndex) + } + + for i, e := range tx.EnvelopeSignatures { + fmt.Fprintf(writer, "\nEnvelope Signature %v:\n", i) + fmt.Fprintf(writer, " Address\t%s\n", e.Address) + fmt.Fprintf(writer, " Signature\t%x\n", e.Signature) + fmt.Fprintf(writer, " Key Index\t%d\n", e.KeyIndex) + } + + if tx.Script != nil { + if len(tx.Arguments) == 0 { + fmt.Fprintf(writer, "\n\nArguments\tNo arguments\n") + } else { + fmt.Fprintf(writer, "\n\nArguments (%d):\n", len(tx.Arguments)) + for i, argument := range tx.Arguments { + fmt.Fprintf(writer, " - Argument %d: %s\n", i, argument) + } + } + + fmt.Fprintf(writer, "\nCode\n\n%s\n", tx.Script) + } + + fmt.Fprintf(writer, "\n\n") + writer.Flush() + + prompt := promptui.Select{ + Label: "⚠️ Do you want to sign this transaction?", + Items: []string{"No", "Yes"}, + } + + _, result, err := prompt.Run() + + fmt.Fprintf(writer, "\r\r") + writer.Flush() + + if err != nil { + return false, fmt.Errorf("Prompt failed %v\n", err) + } + + return result == "Yes", nil +} From 423a698e1b5ef160239fc33ba7cecd27d052a161 Mon Sep 17 00:00:00 2001 From: Gregor Gololicic Date: Fri, 2 Apr 2021 17:24:19 +0200 Subject: [PATCH 035/137] fix --- pkg/flowcli/output/prompt.go | 10 +++------- pkg/flowcli/services/transactions.go | 12 +++++++++--- 2 files changed, 12 insertions(+), 10 deletions(-) diff --git a/pkg/flowcli/output/prompt.go b/pkg/flowcli/output/prompt.go index 10c5f7df4..dc417b19c 100644 --- a/pkg/flowcli/output/prompt.go +++ b/pkg/flowcli/output/prompt.go @@ -9,7 +9,7 @@ import ( "github.com/onflow/flow-cli/pkg/flowcli/project" ) -func ApproveTransactionPrompt(transaction *project.Transaction) (bool, error) { +func ApproveTransactionPrompt(transaction *project.Transaction) bool { writer := uilive.New() tx := transaction.FlowTransaction() @@ -66,14 +66,10 @@ func ApproveTransactionPrompt(transaction *project.Transaction) (bool, error) { Items: []string{"No", "Yes"}, } - _, result, err := prompt.Run() + _, result, _ := prompt.Run() fmt.Fprintf(writer, "\r\r") writer.Flush() - if err != nil { - return false, fmt.Errorf("Prompt failed %v\n", err) - } - - return result == "Yes", nil + return result == "Yes" } diff --git a/pkg/flowcli/services/transactions.go b/pkg/flowcli/services/transactions.go index 7b050ccf9..4121d1d79 100644 --- a/pkg/flowcli/services/transactions.go +++ b/pkg/flowcli/services/transactions.go @@ -87,7 +87,9 @@ func (t *Transactions) Sign( scriptFilename string, payloadFilename string, args []string, - argsJSON string) (*project.Transaction, error) { + argsJSON string, + approveSigning bool, +) (*project.Transaction, error) { if t.project == nil { return nil, fmt.Errorf("missing configuration, initialize it: flow project init") } @@ -111,8 +113,11 @@ func (t *Transactions) Sign( return nil, err } - approved, err := output.ApproveTransactionPrompt(tx) - if approved { + if approveSigning { + return tx.Sign() + } + + if output.ApproveTransactionPrompt(tx) { return tx.Sign() } else { return nil, fmt.Errorf("transaction was not approved for signing") @@ -189,6 +194,7 @@ func (t *Transactions) Send( payloadFilename, args, argsJSON, + true, ) if err != nil { return nil, nil, err From bf32ec8d95f888c6a86491614a7a5b8ed958edab Mon Sep 17 00:00:00 2001 From: Gregor Gololicic Date: Fri, 2 Apr 2021 17:30:35 +0200 Subject: [PATCH 036/137] add global approve flag --- internal/command/command.go | 10 ++++++++++ internal/transactions/sign.go | 1 + 2 files changed, 11 insertions(+) diff --git a/internal/command/command.go b/internal/command/command.go index 5b6d5d6b4..098b08dfe 100644 --- a/internal/command/command.go +++ b/internal/command/command.go @@ -61,6 +61,7 @@ type GlobalFlags struct { Host string Log string Network string + Yes bool } var flags = GlobalFlags{ @@ -70,6 +71,7 @@ var flags = GlobalFlags{ Host: "", Log: "info", Network: "", + Yes: false, } // InitFlags init all the global persistent flags @@ -129,6 +131,14 @@ func InitFlags(cmd *cobra.Command) { flags.Network, "Network from configuration file", ) + + cmd.PersistentFlags().BoolVarP( + &flags.Yes, + "yes", + "n", + flags.Yes, + "Approve any prompts", + ) } // AddToParent add new command to main parent cmd diff --git a/internal/transactions/sign.go b/internal/transactions/sign.go index e967d6511..bb5bc1c6e 100644 --- a/internal/transactions/sign.go +++ b/internal/transactions/sign.go @@ -58,6 +58,7 @@ var SignCommand = &command.Command{ signFlags.Payload, signFlags.Args, signFlags.ArgsJSON, + globalFlags.Yes, ) if err != nil { return nil, err From 1f882ef9ed0143e62f44109f4293df376e9806c5 Mon Sep 17 00:00:00 2001 From: Gregor Gololicic Date: Fri, 2 Apr 2021 17:43:16 +0200 Subject: [PATCH 037/137] fixed tests for signing tx --- pkg/flowcli/services/accounts_test.go | 38 +++++++-------- pkg/flowcli/services/transactions_test.go | 56 ++++++++++++++++++----- 2 files changed, 64 insertions(+), 30 deletions(-) diff --git a/pkg/flowcli/services/accounts_test.go b/pkg/flowcli/services/accounts_test.go index 1dddcc956..153b5c653 100644 --- a/pkg/flowcli/services/accounts_test.go +++ b/pkg/flowcli/services/accounts_test.go @@ -46,9 +46,9 @@ func TestAccounts(t *testing.T) { t.Run("Create an Account", func(t *testing.T) { newAddress := "192440c99cb17282" - mock.SendTransactionMock = func(tx *flow.Transaction, signer *project.Account) (*flow.Transaction, error) { - assert.Equal(t, tx.Authorizers[0].String(), serviceAddress) - assert.Equal(t, signer.Address().String(), serviceAddress) + mock.SendTransactionMock = func(tx *project.Transaction) (*flow.Transaction, error) { + assert.Equal(t, tx.FlowTransaction().Authorizers[0].String(), serviceAddress) + assert.Equal(t, tx.Signer().Address().String(), serviceAddress) return tests.NewTransaction(), nil } @@ -73,10 +73,10 @@ func TestAccounts(t *testing.T) { t.Run("Create an Account with Contract", func(t *testing.T) { newAddress := "192440c99cb17282" - mock.SendTransactionMock = func(tx *flow.Transaction, signer *project.Account) (*flow.Transaction, error) { - assert.Equal(t, tx.Authorizers[0].String(), serviceAddress) - assert.Equal(t, signer.Address().String(), serviceAddress) - assert.True(t, strings.Contains(string(tx.Script), "acct.contracts.add")) + mock.SendTransactionMock = func(tx *project.Transaction) (*flow.Transaction, error) { + assert.Equal(t, tx.FlowTransaction().Authorizers[0].String(), serviceAddress) + assert.Equal(t, tx.Signer().Address().String(), serviceAddress) + assert.True(t, strings.Contains(string(tx.FlowTransaction().Script), "acct.contracts.add")) return tests.NewTransaction(), nil } @@ -99,10 +99,10 @@ func TestAccounts(t *testing.T) { }) t.Run("Contract Add for Account", func(t *testing.T) { - mock.SendTransactionMock = func(tx *flow.Transaction, signer *project.Account) (*flow.Transaction, error) { - assert.Equal(t, tx.Authorizers[0].String(), serviceAddress) - assert.Equal(t, signer.Address().String(), serviceAddress) - assert.True(t, strings.Contains(string(tx.Script), "signer.contracts.add")) + mock.SendTransactionMock = func(tx *project.Transaction) (*flow.Transaction, error) { + assert.Equal(t, tx.FlowTransaction().Authorizers[0].String(), serviceAddress) + assert.Equal(t, tx.Signer().Address().String(), serviceAddress) + assert.True(t, strings.Contains(string(tx.FlowTransaction().Script), "signer.contracts.add")) return tests.NewTransaction(), nil } @@ -123,10 +123,10 @@ func TestAccounts(t *testing.T) { }) t.Run("Contract Update for Account", func(t *testing.T) { - mock.SendTransactionMock = func(tx *flow.Transaction, signer *project.Account) (*flow.Transaction, error) { - assert.Equal(t, tx.Authorizers[0].String(), serviceAddress) - assert.Equal(t, signer.Address().String(), serviceAddress) - assert.True(t, strings.Contains(string(tx.Script), "signer.contracts.update__experimental")) + mock.SendTransactionMock = func(tx *project.Transaction) (*flow.Transaction, error) { + assert.Equal(t, tx.FlowTransaction().Authorizers[0].String(), serviceAddress) + assert.Equal(t, tx.Signer().Address().String(), serviceAddress) + assert.True(t, strings.Contains(string(tx.FlowTransaction().Script), "signer.contracts.update__experimental")) return tests.NewTransaction(), nil } @@ -147,10 +147,10 @@ func TestAccounts(t *testing.T) { }) t.Run("Contract Remove for Account", func(t *testing.T) { - mock.SendTransactionMock = func(tx *flow.Transaction, signer *project.Account) (*flow.Transaction, error) { - assert.Equal(t, tx.Authorizers[0].String(), serviceAddress) - assert.Equal(t, signer.Address().String(), serviceAddress) - assert.True(t, strings.Contains(string(tx.Script), "signer.contracts.remove")) + mock.SendTransactionMock = func(tx *project.Transaction) (*flow.Transaction, error) { + assert.Equal(t, tx.FlowTransaction().Authorizers[0].String(), serviceAddress) + assert.Equal(t, tx.Signer().Address().String(), serviceAddress) + assert.True(t, strings.Contains(string(tx.FlowTransaction().Script), "signer.contracts.remove")) return tests.NewTransaction(), nil } diff --git a/pkg/flowcli/services/transactions_test.go b/pkg/flowcli/services/transactions_test.go index 429c09a3a..3ee6293e0 100644 --- a/pkg/flowcli/services/transactions_test.go +++ b/pkg/flowcli/services/transactions_test.go @@ -16,6 +16,15 @@ import ( func TestTransactions(t *testing.T) { mock := &tests.MockGateway{} + // default implementations + mock.PrepareTransactionPayloadMock = func(tx *project.Transaction) (*project.Transaction, error) { + return tx, nil + } + + mock.SendSignedTransactionMock = func(tx *project.Transaction) (*flow.Transaction, error) { + return tx.FlowTransaction(), nil + } + proj, err := project.Init(crypto.ECDSA_P256, crypto.SHA3_256) assert.NoError(t, err) @@ -50,18 +59,24 @@ func TestTransactions(t *testing.T) { return tests.NewTransactionResult(nil), nil } - mock.SendTransactionMock = func(tx *flow.Transaction, signer *project.Account) (*flow.Transaction, error) { + mock.SendSignedTransactionMock = func(tx *project.Transaction) (*flow.Transaction, error) { called++ - arg, err := tx.Argument(0) + arg, err := tx.FlowTransaction().Argument(0) assert.NoError(t, err) assert.Equal(t, arg.String(), "\"Bar\"") - assert.Equal(t, signer.Address().String(), serviceAddress) - assert.Equal(t, len(string(tx.Script)), 209) + assert.Equal(t, tx.Signer().Address().String(), serviceAddress) + assert.Equal(t, len(string(tx.FlowTransaction().Script)), 209) return tests.NewTransaction(), nil } - _, _, err := transactions.Send("../../../tests/transaction.cdc", serviceName, []string{"String:Bar"}, "") + _, _, err := transactions.Send( + "../../../tests/transaction.cdc", + "", + serviceName, + []string{"String:Bar"}, + "", + ) assert.NoError(t, err) assert.Equal(t, called, 2) @@ -75,15 +90,16 @@ func TestTransactions(t *testing.T) { return tests.NewTransactionResult(nil), nil } - mock.SendTransactionMock = func(tx *flow.Transaction, signer *project.Account) (*flow.Transaction, error) { + mock.SendSignedTransactionMock = func(tx *project.Transaction) (*flow.Transaction, error) { called++ - assert.Equal(t, signer.Address().String(), serviceAddress) - assert.Equal(t, len(string(tx.Script)), 209) + assert.Equal(t, tx.Signer().Address().String(), serviceAddress) + assert.Equal(t, len(string(tx.FlowTransaction().Script)), 209) return tests.NewTransaction(), nil } _, _, err := transactions.Send( "../../../tests/transaction.cdc", + "", serviceName, nil, "[{\"type\": \"String\", \"value\": \"Bar\"}]", @@ -94,17 +110,35 @@ func TestTransactions(t *testing.T) { }) t.Run("Send Transaction Fails wrong args", func(t *testing.T) { - _, _, err := transactions.Send("../../../tests/transaction.cdc", serviceName, []string{"Bar"}, "") + _, _, err := transactions.Send( + "../../../tests/transaction.cdc", + "", + serviceName, + []string{"Bar"}, + "", + ) assert.Equal(t, err.Error(), "Argument not passed in correct format, correct format is: Type:Value, got Bar") }) t.Run("Send Transaction Fails wrong filename", func(t *testing.T) { - _, _, err := transactions.Send("nooo.cdc", serviceName, []string{"Bar"}, "") + _, _, err := transactions.Send( + "nooo.cdc", + "", + serviceName, + []string{"Bar"}, + "", + ) assert.Equal(t, err.Error(), "Failed to load file: nooo.cdc") }) t.Run("Send Transaction Fails wrong args", func(t *testing.T) { - _, _, err := transactions.Send("../../../tests/transaction.cdc", serviceName, nil, "[{\"Bar\":\"No\"}]") + _, _, err := transactions.Send( + "../../../tests/transaction.cdc", + "", + serviceName, + nil, + "[{\"Bar\":\"No\"}]", + ) assert.Equal(t, err.Error(), "failed to decode value: invalid JSON Cadence structure") }) } From eaaad811f58d69fbc04c102636593fac9a4c9e1c Mon Sep 17 00:00:00 2001 From: Gregor Gololicic Date: Fri, 2 Apr 2021 17:47:24 +0200 Subject: [PATCH 038/137] global flag fix --- internal/command/command.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/internal/command/command.go b/internal/command/command.go index 098b08dfe..a398920ee 100644 --- a/internal/command/command.go +++ b/internal/command/command.go @@ -135,7 +135,7 @@ func InitFlags(cmd *cobra.Command) { cmd.PersistentFlags().BoolVarP( &flags.Yes, "yes", - "n", + "y", flags.Yes, "Approve any prompts", ) From f898ce821626dbad2a6bc0c0724f4253ca4317dc Mon Sep 17 00:00:00 2001 From: Gregor Gololicic Date: Fri, 2 Apr 2021 18:15:36 +0200 Subject: [PATCH 039/137] readme update for signing transctions --- docs/account-staking-info.md | 2 +- docs/get-accounts.md | 11 +- docs/send-transactions.md | 26 +- docs/sign-transaction.md | 474 ++++++++++++++++++++++++++++++++++- docs/template.md | 4 +- 5 files changed, 506 insertions(+), 11 deletions(-) diff --git a/docs/account-staking-info.md b/docs/account-staking-info.md index da26fa24b..a6a94613a 100644 --- a/docs/account-staking-info.md +++ b/docs/account-staking-info.md @@ -45,7 +45,7 @@ Tokens Unstaking: 0.00000000 ### Address - Name: `address` -- Valid Input: Flow account address +- Valid Input: Flow account address. Flow [account address](https://docs.onflow.org/concepts/accounts-and-keys/) (prefixed with `0x` or not). diff --git a/docs/get-accounts.md b/docs/get-accounts.md index 75fa16b39..8020ad5f8 100644 --- a/docs/get-accounts.md +++ b/docs/get-accounts.md @@ -33,6 +33,16 @@ Contract: 'FlowStorageFees' ``` +## Arguments + +### Address + +- Name: `address` +- Valid Input: Flow account address + +Flow [account address](https://docs.onflow.org/concepts/accounts-and-keys/) (prefixed with `0x` or not). + + ## Flags ### Contracts @@ -44,7 +54,6 @@ Display contracts deployed to the account. ### Code ⚠️ DEPRECATED: use contracts flag instead. - ### Host - Flag: `--host` diff --git a/docs/send-transactions.md b/docs/send-transactions.md index fd8f2be89..0430a7c0f 100644 --- a/docs/send-transactions.md +++ b/docs/send-transactions.md @@ -12,7 +12,6 @@ any Flow Access API. ## Example Usage ```shell -# Submit a transaction to Flow Testnet > flow transactions send --signer my-testnet-account \ --host access.testnet.nodes.onflow.org:9000 @@ -66,6 +65,31 @@ transaction to be executed. Specify the name of the account that will be used to sign the transaction. +### Arguments + +- Flag: `--arg` +- Valid inputs: argument in `Type:Value` format. + +Arguments passed to the Cadence transaction in `Type:Value` format. +The `Type` must be the same as type in the transaction source code for that argument. + +### Arguments JSON + +- Flag: `--argsJSON` +- Valid inputs: arguments in JSON-Cadence form. + +Arguments passed to the Cadence transaction in `Type:Value` format. +The `Type` must be the same type as the corresponding parameter +in the Cadence transaction code. + +### Payload + +- Flag: `--payload` +- Valid inputs: any filename and path valid on the system. + +Specify the filename containing valid transaction payload that will be used for signing. +To be used with the `flow transaction sign` command. + ### Host - Flag: `--host` diff --git a/docs/sign-transaction.md b/docs/sign-transaction.md index 1db61f4da..11f5b36ef 100644 --- a/docs/sign-transaction.md +++ b/docs/sign-transaction.md @@ -1,3 +1,355 @@ +--- +title: Sign a Transaction with the Flow CLI +sidebar_title: Sign a Transaction +description: How to sign a Flow transaction from the command line +--- + +The Flow CLI provides a command to sign transactions with options to specify +authorizator accounts, payer accounts and proposer accounts. + +`flow transctions sign` + +## Example Usage + +```shell +> flow transactions sign ./tests/transaction.cdc --arg String:"Meow" + +Hash b03b18a8d9d30ff7c9f0fdaa80fcaab242c2f36eedb687dd9b368326311fe376 +Payer f8d6e0586b0a20c7 +Authorizers [f8d6e0586b0a20c7] + +Proposal Key: + Address f8d6e0586b0a20c7 + Index 0 + Sequence 6 + +No Envelope Signatures + +Payload Signature 0: + Address f8d6e0586b0a20c7 + Signature b5b1dfed2a899037...164e1b224a7ac924018e7033b68b0df86769dd54 + Key Index 0 + + +Arguments (1): + - Argument 0: {"type":"String","value":"Meow"} + + +Code + +transaction(greeting: String) { + let guest: Address + + prepare(authorizer: AuthAccount) { + self.guest = authorizer.address + } + + execute { + log(greeting.concat(",").concat(self.guest.toString())) + } +} + + +Payload: +f90184f...a199bfd9b837a11a0885f9104b54014750f5e3e5bfe4a5795968b0df86769dd54c0 +``` + + +### Example Sign and Send + +```shell + +> flow transactions sign ./tests/transaction.cdc --arg String:"Meow" --filter Payload --save payload1 +💾 result saved to: payload1 + + +> flow transactions send --payload payload1 + +Status ✅ SEALED +Hash 9a38fb25c9fedc20b008aaed7a5ff00169a178411238573d6a6a55982a645129 +Payer f8d6e0586b0a20c7 +Authorizers [f8d6e0586b0a20c7] + +Proposal Key: + Address f8d6e0586b0a20c7 + Index 0 + Sequence 6 + +Payload Signature 0: + Address f8d6e0586b0a20c7 + Signature c7ede88cfd45c7c01b2...097e4d5040f730f640c1d4ac + Key Index 0 + +Envelope Signature 0: + Address f8d6e0586b0a20c7 + Signature fb8226d6c61ddd58a2b...798e7a9be084eb622cf40f4f + Key Index 0 + + +Events: None + + +Arguments (1): + - Argument 0: {"type":"String","value":"Meow"} + + +Code + +transaction(greeting: String) { + let guest: Address + + prepare(authorizer: AuthAccount) { + self.guest = authorizer.address + } + + execute { + log(greeting.concat(",").concat(self.guest.toString())) + } +} + + +Payload: +f901cbf90138b......4649a4088797523c02d53f0c798e7a9be084eb622cf40f4f + + +``` + +### Example Different Payer and Signer + +```shell +> flow transactions sign ./tests/transaction.cdc --arg String:"Meow" --payer-address 179b6b1cb6755e31 --filter Payload --save payload1 +💾 result saved to: payload1 + + +> flow transactions sign --payload payload1 --role payer --signer alice --filter Payload --save payload2 +💾 result saved to: payload2 + + +> transactions send --payload payload2 + +Status ✅ SEALED +Hash 379ccb941b956c760f19307bbc961cc1e6bcdd7334b5941e9f55ab2151f52d43 +Payer 179b6b1cb6755e31 +Authorizers [f8d6e0586b0a20c7] + +Proposal Key: + Address f8d6e0586b0a20c7 + Index 0 + Sequence 7 + +Payload Signature 0: + Address f8d6e0586b0a20c7 + Signature f940766ce...3d2001e0b4b795e4f35345a18a04abc87466f6d0f1617b949b + Key Index 0 + +Envelope Signature 0: + Address f8d6e0586b0a20c7 + Signature 000621...6ff9cdef2d62fb5e98ebbc7a7bacdb505ab799522c76f1d6e5aa3 + Key Index 0 + +Envelope Signature 1: + Address 179b6b1cb6755e31 + Signature c423ebae6...a855564dc927dcd3f764b81c67048d7936af131abe1952dc80 + Key Index 0 + + +Events: None + + +Arguments (1): + - Argument 0: {"type":"String","value":"Meow"} + + +Code + +transaction(greeting: String) { + let guest: Address + + prepare(authorizer: AuthAccount) { + self.guest = authorizer.address + } + + execute { + log(greeting.concat(",").concat(self.guest.toString())) + } +} + + +Payload: +f90211f901...7a6520417574684163636f756e7429207b0a2020202073656c662e67756573 + +``` + + +## Arguments + +### Filename (optional) +- Name: `filename` +- Valid inputs: Any filename and path valid on the system. + +The first argument is a path to a Cadence file containing the +transaction to be executed. This argument is optional as we can +use `--payload` flag if we already have created a transaction and +we would just like to sign it. + +## Flags + +### Signer + +- Flag: `--signer` +- Valid inputs: the name of an account defined in the configuration (`flow.json`) + +Specify the name of the account that will be used to sign the transaction. + +### Payload + +- Flag: `--payload` +- Valid inputs: any filename and path valid on the system. + +Specify the filename containing valid transaction payload that will be used for signing. + +### Proposer + +- Flag: `--proposer` +- Valid inputs: account from configuration. + +Specify a name of the account that is proposing the transaction. +Account must be defined in flow configuration. + +### Role + +- Flag: `--role` +- Valid inputs: authorizer, proposer, payer. + +Specify a role of the signer. +Read more about signer roles [here](https://docs.onflow.org/concepts/accounts-and-keys/). + +### Add Authorizers + +- Flag: `--add-authorizer` +- Valid Input: Flow account address. + +Additional authorizer addresses to add to the transaction. +Read more about authorizers [here](https://docs.onflow.org/concepts/accounts-and-keys/). + +### Payer Address + +- Flag: `--payer-address` +- Valid Input: Flow account address. + +Specify account address that will be paying for the transaction. +Read more about payers [here](https://docs.onflow.org/concepts/accounts-and-keys/). + +### Arguments + +- Flag: `--arg` +- Valid inputs: argument in `Type:Value` format. + +Arguments passed to the Cadence transaction in `Type:Value` format. +The `Type` must be the same as type in the transaction source code for that argument. + +### Arguments JSON + +- Flag: `--argsJSON` +- Valid inputs: arguments in JSON-Cadence form. + +Arguments passed to the Cadence transaction in `Type:Value` format. +The `Type` must be the same type as the corresponding parameter +in the Cadence transaction code. + +### Host +- Flag: `--host` +- Valid inputs: an IP address or hostname. +- Default: `127.0.0.1:3569` (Flow Emulator) + +Specify the hostname of the Access API that will be +used to execute the commands. + +### Network + +- Flag: `--network` +- Short Flag: `-n` +- Valid inputs: the name of a network defined in the configuration (`flow.json`) + +Specify which network you want the command to use for execution. + +### Filter + +- Flag: `--filter` +- Short Flag: `-x` +- Valid inputs: case-sensitive name of the result property. + +Specify any property name from the result you want to return as the only value. + +### Output + +- Flag: `--output` +- Short Flag: `-o` +- Valid inputs: `json`, `inline` + +Specify in which format you want to display the result. + +### Save + +- Flag: `--save` +- Short Flag: `-s` +- Valid inputs: valid filename + +Specify the filename where you want the result to be saved. + +### Log + +- Flag: `--log` +- Short Flag: `-l` +- Valid inputs: `none`, `error`, `debug` +- Default: `info` + +Specify the log level. Control how much output you want to see while command execution. + +### Configuration + +- Flag: `--conf` +- Short Flag: `-f` +- Valid inputs: valid filename + +Specify a filename for the configuration files, you can provide multiple configuration +files by using `-f` flag multiple times. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + ```bash Authorizers [f8d6e0586b0a20c7] @@ -139,7 +491,7 @@ Payload Signature 0: Transaction Payload: f9018cf90140b8d17472616e73616374696f6e286772656574696e673a20537472696e6729207b0a20206c65742067756573743a20416464726573730a0a20207072657061726528617574686f72697a65723a20417574684163636f756e7429207b0a2020202073656c662e6775657374203d20617574686f72697a65722e616464726573730a20207d0a0a202065786563757465207b0a202020206c6f67286772656574696e672e636f6e63617428222c22292e636f6e6361742873656c662e67756573742e746f537472696e67282929290a20207d0a7de1a07b2274797065223a22537472696e67222c2276616c7565223a22466f6f227d0aa076a251f4028186c2a934efa598e2cd41a6a33700893ae7098475cd05cc6c37fb8203e888f8d6e0586b0a20c78004880000000000000000d288f8d6e0586b0a20c788179b6b1cb6755e31f846f8448080b84064c0a6cb39c55364cff5c6d73622d22165efa994deb9a5b8b53ff80f0931db74380311ff9765bafcbce666d9b407638d9b0e26ad97b7a9dad963337d623b0de3c0 - +// saved to payload 1 > transactions sign --payload payload1 --signer payer-account @@ -166,12 +518,10 @@ Payload Signature 1: Payload: f901d2f90140b8d17472616e73616374696f6e286772656574696e673a20537472696e6729207b0a20206c65742067756573743a20416464726573730a0a20207072657061726528617574686f72697a65723a20417574684163636f756e7429207b0a2020202073656c662e6775657374203d20617574686f72697a65722e616464726573730a20207d0a0a202065786563757465207b0a202020206c6f67286772656574696e672e636f6e63617428222c22292e636f6e6361742873656c662e67756573742e746f537472696e67282929290a20207d0a7de1a07b2274797065223a22537472696e67222c2276616c7565223a22466f6f227d0aa0ff25bc88a84e5989cafda9da5e55baa9308e511a12fd4d2788c0c359c3f1e6738203e888f8d6e0586b0a20c7800588f8d6e0586b0a20c7d288f8d6e0586b0a20c788179b6b1cb6755e31f88cf8448080b8405c56f2e465b13f289f341733a95b8673aeb9bfa8e3ed9021ca6d51a0b59a4ed278ef95491efdfb7c30e6d599d52358b4b698431782096e7e38a499130dfaeb1ef8440180b840ca04dafea2a5438ba6d5ac7811bc2656035a23001eee3c96ddf581d015683006c42943b8475d3c61e6131578cc3fe80470ae8706e489b186bc2b333ff12f7282c0 - - +// saved to payload 2 > transactions send --payload payload2 - ❌ Transaction Error execution error code 100: Execution failed: error: authorizer count mismatch for transaction: expected 1, got 2 @@ -206,10 +556,124 @@ Envelope Signature 0: Events: - + None Payload: f90219f90140b8d17472616e73616374696f6e286772656574696e673a20537472696e6729207b0a20206c65742067756573743a20416464726573730a0a20207072657061726528617574686f72697a65723a20417574684163636f756e7429207b0a2020202073656c662e6775657374203d20617574686f72697a65722e616464726573730a20207d0a0a202065786563757465207b0a202020206c6f67286772656574696e672e636f6e63617428222c22292e636f6e6361742873656c662e67756573742e746f537472696e67282929290a20207d0a7de1a07b2274797065223a22537472696e67222c2276616c7565223a22466f6f227d0aa0ff25bc88a84e5989cafda9da5e55baa9308e511a12fd4d2788c0c359c3f1e6738203e888f8d6e0586b0a20c7800588f8d6e0586b0a20c7d288f8d6e0586b0a20c788179b6b1cb6755e31f88cf8448080b8405c56f2e465b13f289f341733a95b8673aeb9bfa8e3ed9021ca6d51a0b59a4ed278ef95491efdfb7c30e6d599d52358b4b698431782096e7e38a499130dfaeb1ef8440180b840d02d792d0157ce357b87a1a8381e7a8a599386782d5ac0ae0738d2c1f1e96d495aad6fc058f0f81b6dfecc0c72b2358c55cfe6f68aaf13882cf177f48d44c337f846f8448080b8402fce0b37e3cc7c44b0e709c7d2a8f145bf9af9aab8be7b1e4e76e20a1e6abc67958dd1be5c4a19f2283c9cddc9ace243688a3c2198858a502551dfd70b32790a +``` + + + + + +Kan Implementation - Multiple authorizers + +``` +go run cmd/flow/main.go transactions sign --payload payload11 --role authorizer --signer payer-account +^C +MacBook-Pro:flow-cli Dapper$ go run cmd/flow/main.go transactions sign --payload payload11 --role authorizer --signer payer-account --output payload12 +⚠️ You are using a new experimental configuration format. Support for this format is not yet available across all CLI commands. +⚠️ You are using a new experimental configuration format. Support for this format is not yet available across all CLI commands. +Authorizers (2): + Authorizer 0: f8d6e0586b0a20c7 + Authorizer 1: 179b6b1cb6755e31 + +Arguments (1): + Argument 0: {"type":"String","value":"Hello"} + + +Script: +transaction(greeting: String) { + let guest: Address + + prepare(authorizer: AuthAccount) { + self.guest = authorizer.address + } + + execute { + log(greeting.concat(",").concat(self.guest.toString())) + } +} +=== +Proposer Address: f8d6e0586b0a20c7 +Proposer Key Index: 0 +Payer Address: f8d6e0586b0a20c7 +=== +Payload Signatures (1): + Signature 0 Signer Address: f8d6e0586b0a20c7 + Signature 0 Signer Key Index: 0 +=== +Does this look correct? (y/n) +> y +Payload contents verified +hexrlp encoded transaction written to payload12 +MacBook-Pro:flow-cli Dapper$ cat payload12 +f901d2f90140b8d17472616e73616374696f6e286772656574696e673a20537472696e6729207b0a20206c65742067756573743a20416464726573730a0a20207072657061726528617574686f72697a65723a20417574684163636f756e7429207b0a2020202073656c662e6775657374203d20617574686f72697a65722e616464726573730a20207d0a0a202065786563757465207b0a202020206c6f67286772656574696e672e636f6e63617428222c22292e636f6e6361742873656c662e67756573742e746f537472696e67282929290a20207d0a7de3a27b2274797065223a22537472696e67222c2276616c7565223a2248656c6c6f227d0aa085710ebc28deba306bba85d19cf09aa525f1d4badd37843acc677f01fbcfc1f18088f8d6e0586b0a20c7800588f8d6e0586b0a20c7d288f8d6e0586b0a20c788179b6b1cb6755e31f88cf8448080b840ad1ea2b2ea309d875f4a54c49449bd891b45d76eaf3aafa0597d8e9b9e9822b8f86885c23d4eacc99ca3e4f4b0b321a375aebe972e6404d906fa77c0e674daa4f8440180b840267801d484a57a9be7136786807ef2f27059c4635f8412bb594e49b08b8b1af458ec93804d98ae24163987443ffb7847b57e188762aa483dc792ce902df67459c0MacBook-Pro:flow-cli Dapper$ +MacBook-Pro:flow-cli Dapper$ +MacBook-Pro:flow-cli Dapper$ +MacBook-Pro:flow-cli Dapper$ go run cmd/flow/main.go transactions send --payload payload12 --signer emulator-account --results +⚠️ You are using a new experimental configuration format. Support for this format is not yet available across all CLI commands. +⚠️ You are using a new experimental configuration format. Support for this format is not yet available across all CLI commands. +Authorizers (2): + Authorizer 0: f8d6e0586b0a20c7 + Authorizer 1: 179b6b1cb6755e31 + +Arguments (1): + Argument 0: {"type":"String","value":"Hello"} + + +Script: +transaction(greeting: String) { + let guest: Address + + prepare(authorizer: AuthAccount) { + self.guest = authorizer.address + } + + execute { + log(greeting.concat(",").concat(self.guest.toString())) + } +} +=== +Proposer Address: f8d6e0586b0a20c7 +Proposer Key Index: 0 +Payer Address: f8d6e0586b0a20c7 +=== +Payload Signatures (2): + Signature 0 Signer Address: f8d6e0586b0a20c7 + Signature 0 Signer Key Index: 0 + Signature 1 Signer Address: 179b6b1cb6755e31 + Signature 1 Signer Key Index: 0 +=== +Does this look correct? (y/n) +> y +Payload contents verified +Submitting transaction with ID b0aea61a31b3e872c2dac826d37a9667f252bc82f3e1d2be98f25485a0c09bd7 ... +Successfully submitted transaction with ID b0aea61a31b3e872c2dac826d37a9667f252bc82f3e1d2be98f25485a0c09bd7 +Waiting for transaction b0aea61a31b3e872c2dac826d37a9667f252bc82f3e1d2be98f25485a0c09bd7 to be sealed... + +Transaction b0aea61a31b3e872c2dac826d37a9667f252bc82f3e1d2be98f25485a0c09bd7 sealed + +Status: SEALED +Execution Error: execution error code 100: Execution failed: +error: authorizer count mismatch for transaction: expected 1, got 2 +--> b0aea61a31b3e872c2dac826d37a9667f252bc82f3e1d2be98f25485a0c09bd7 + +Code: +transaction(greeting: String) { + let guest: Address + + prepare(authorizer: AuthAccount) { + self.guest = authorizer.address + } + + execute { + log(greeting.concat(",").concat(self.guest.toString())) + } +} +Events: + None + ``` \ No newline at end of file diff --git a/docs/template.md b/docs/template.md index bf4c3aaa6..7c0ce4532 100644 --- a/docs/template.md +++ b/docs/template.md @@ -13,11 +13,9 @@ description: ## Example Usage ```shell -{usage example} +{usage example with response} ``` -### Example response - ## Arguments ### {Argument 1} From ec38a71779ff73f07177bfecead12935fb6ffc22 Mon Sep 17 00:00:00 2001 From: Gregor Gololicic Date: Fri, 2 Apr 2021 18:15:45 +0200 Subject: [PATCH 040/137] output fix --- pkg/flowcli/output/prompt.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pkg/flowcli/output/prompt.go b/pkg/flowcli/output/prompt.go index dc417b19c..7959eed6c 100644 --- a/pkg/flowcli/output/prompt.go +++ b/pkg/flowcli/output/prompt.go @@ -15,7 +15,7 @@ func ApproveTransactionPrompt(transaction *project.Transaction) bool { fmt.Fprintf(writer, "\n") fmt.Fprintf(writer, "Hash\t%s\n", tx.ID()) - fmt.Fprintf(writer, "Payer\t%x\n", tx.Payer) + fmt.Fprintf(writer, "Payer\t%s\n", tx.Payer.Hex()) fmt.Fprintf(writer, "Authorizers\t%s\n", tx.Authorizers) fmt.Fprintf(writer, From b5f96929408c4a0104913025d8c99bfad746b23e Mon Sep 17 00:00:00 2001 From: Gregor Gololicic Date: Tue, 6 Apr 2021 14:03:09 +0200 Subject: [PATCH 041/137] divide contracts.go to multiple files --- pkg/flowcli/contracts/contracts.go | 97 ------------------------- pkg/flowcli/contracts/loader.go | 41 +++++++++++ pkg/flowcli/contracts/preprocessor.go | 101 ++++++++++++++++++++++++++ 3 files changed, 142 insertions(+), 97 deletions(-) create mode 100644 pkg/flowcli/contracts/loader.go create mode 100644 pkg/flowcli/contracts/preprocessor.go diff --git a/pkg/flowcli/contracts/contracts.go b/pkg/flowcli/contracts/contracts.go index 4325ea583..d861054f8 100644 --- a/pkg/flowcli/contracts/contracts.go +++ b/pkg/flowcli/contracts/contracts.go @@ -20,7 +20,6 @@ package contracts import ( "fmt" - "io/ioutil" "path" "strings" @@ -133,106 +132,10 @@ func (c *Contract) addAlias(location string, target flow.Address) { c.aliases[location] = target } -type Loader interface { - Load(source string) (string, error) - Normalize(base, relative string) string -} - -type FilesystemLoader struct{} - -func (f FilesystemLoader) Load(source string) (string, error) { - codeBytes, err := ioutil.ReadFile(source) - if err != nil { - return "", err - } - - return string(codeBytes), nil -} - -func (f FilesystemLoader) Normalize(base, relative string) string { - return absolutePath(base, relative) -} - func absolutePath(basePath, relativePath string) string { return path.Join(path.Dir(basePath), relativePath) } -type Preprocessor struct { - loader Loader - aliases map[string]string - contracts []*Contract - contractsBySource map[string]*Contract -} - -func NewPreprocessor(loader Loader, aliases map[string]string) *Preprocessor { - return &Preprocessor{ - loader: loader, - aliases: aliases, - contracts: make([]*Contract, 0), - contractsBySource: make(map[string]*Contract), - } -} - -func (p *Preprocessor) AddContractSource( - contractName, - contractSource string, - target flow.Address, -) error { - contractCode, err := p.loader.Load(contractSource) - if err != nil { - return err - } - - c, err := newContract( - len(p.contracts), - contractName, - contractSource, - contractCode, - target, - ) - if err != nil { - return err - } - - p.contracts = append(p.contracts, c) - p.contractsBySource[c.source] = c - - return nil -} - -func (p *Preprocessor) ResolveImports() error { - for _, c := range p.contracts { - for _, location := range c.imports() { - importPath := p.loader.Normalize(c.source, location) - importAlias, isAlias := p.aliases[importPath] - importContract, isContract := p.contractsBySource[importPath] - - if isContract { - c.addDependency(location, importContract) - } else if isAlias { - c.addAlias(location, flow.HexToAddress(importAlias)) - } else { - return fmt.Errorf("Import from %s could not be found: %s, make sure import path is correct.", c.name, importPath) - } - } - } - - return nil -} - -func (p *Preprocessor) ContractBySource(contractSource string) *Contract { - return p.contractsBySource[contractSource] -} - -func (p *Preprocessor) ContractDeploymentOrder() ([]*Contract, error) { - sorted, err := sortByDeploymentOrder(p.contracts) - if err != nil { - return nil, err - } - - return sorted, nil -} - type CyclicImportError struct { Cycles [][]*Contract } diff --git a/pkg/flowcli/contracts/loader.go b/pkg/flowcli/contracts/loader.go new file mode 100644 index 000000000..89e79963a --- /dev/null +++ b/pkg/flowcli/contracts/loader.go @@ -0,0 +1,41 @@ +/* + * Flow CLI + * + * Copyright 2019-2021 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 contracts + +import "io/ioutil" + +type Loader interface { + Load(source string) (string, error) + Normalize(base, relative string) string +} + +type FilesystemLoader struct{} + +func (f FilesystemLoader) Load(source string) (string, error) { + codeBytes, err := ioutil.ReadFile(source) + if err != nil { + return "", err + } + + return string(codeBytes), nil +} + +func (f FilesystemLoader) Normalize(base, relative string) string { + return absolutePath(base, relative) +} diff --git a/pkg/flowcli/contracts/preprocessor.go b/pkg/flowcli/contracts/preprocessor.go new file mode 100644 index 000000000..9eb464e23 --- /dev/null +++ b/pkg/flowcli/contracts/preprocessor.go @@ -0,0 +1,101 @@ +/* + * Flow CLI + * + * Copyright 2019-2021 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 contracts + +import ( + "fmt" + + "github.com/onflow/flow-go-sdk" +) + +type Preprocessor struct { + loader Loader + aliases map[string]string + contracts []*Contract + contractsBySource map[string]*Contract +} + +func NewPreprocessor(loader Loader, aliases map[string]string) *Preprocessor { + return &Preprocessor{ + loader: loader, + aliases: aliases, + contracts: make([]*Contract, 0), + contractsBySource: make(map[string]*Contract), + } +} + +func (p *Preprocessor) AddContractSource( + contractName, + contractSource string, + target flow.Address, +) error { + contractCode, err := p.loader.Load(contractSource) + if err != nil { + return err + } + + c, err := newContract( + len(p.contracts), + contractName, + contractSource, + contractCode, + target, + ) + if err != nil { + return err + } + + p.contracts = append(p.contracts, c) + p.contractsBySource[c.source] = c + + return nil +} + +func (p *Preprocessor) ResolveImports() error { + for _, c := range p.contracts { + for _, location := range c.imports() { + importPath := p.loader.Normalize(c.source, location) + importAlias, isAlias := p.aliases[importPath] + importContract, isContract := p.contractsBySource[importPath] + + if isContract { + c.addDependency(location, importContract) + } else if isAlias { + c.addAlias(location, flow.HexToAddress(importAlias)) + } else { + return fmt.Errorf("Import from %s could not be found: %s, make sure import path is correct.", c.name, importPath) + } + } + } + + return nil +} + +func (p *Preprocessor) ContractBySource(contractSource string) *Contract { + return p.contractsBySource[contractSource] +} + +func (p *Preprocessor) ContractDeploymentOrder() ([]*Contract, error) { + sorted, err := sortByDeploymentOrder(p.contracts) + if err != nil { + return nil, err + } + + return sorted, nil +} From 6b7eede90fa9ec5efd68ae51df0aee77e7b096a5 Mon Sep 17 00:00:00 2001 From: Gregor Gololicic Date: Tue, 6 Apr 2021 17:31:05 +0200 Subject: [PATCH 042/137] add aliases type --- pkg/flowcli/contracts/preprocessor.go | 6 ++++-- pkg/flowcli/project/project.go | 6 ++++-- 2 files changed, 8 insertions(+), 4 deletions(-) diff --git a/pkg/flowcli/contracts/preprocessor.go b/pkg/flowcli/contracts/preprocessor.go index 9eb464e23..ba52186b0 100644 --- a/pkg/flowcli/contracts/preprocessor.go +++ b/pkg/flowcli/contracts/preprocessor.go @@ -21,17 +21,19 @@ package contracts import ( "fmt" + "github.com/onflow/flow-cli/pkg/flowcli/project" + "github.com/onflow/flow-go-sdk" ) type Preprocessor struct { loader Loader - aliases map[string]string + aliases project.Aliases contracts []*Contract contractsBySource map[string]*Contract } -func NewPreprocessor(loader Loader, aliases map[string]string) *Preprocessor { +func NewPreprocessor(loader Loader, aliases project.Aliases) *Preprocessor { return &Preprocessor{ loader: loader, aliases: aliases, diff --git a/pkg/flowcli/project/project.go b/pkg/flowcli/project/project.go index 711fcfbf7..321c6c951 100644 --- a/pkg/flowcli/project/project.go +++ b/pkg/flowcli/project/project.go @@ -266,9 +266,11 @@ func (p *Project) AccountByName(name string) *Account { return account } +type Aliases map[string]string + // AliasesForNetwork returns all deployment aliases for a network. -func (p *Project) AliasesForNetwork(network string) map[string]string { - aliases := make(map[string]string) +func (p *Project) AliasesForNetwork(network string) Aliases { + aliases := make(Aliases) // get all contracts for selected network and if any has an address as target make it an alias for _, contract := range p.conf.Contracts.GetByNetwork(network) { From 85efc4d09ab1521880b77f69a47876c44d58c4cd Mon Sep 17 00:00:00 2001 From: Gregor Gololicic Date: Tue, 6 Apr 2021 20:51:34 +0200 Subject: [PATCH 043/137] resolver imports and tests --- pkg/flowcli/contracts/resolver.go | 95 ++++++++++++++++++++++++++ pkg/flowcli/contracts/resolver_test.go | 70 +++++++++++++++++++ pkg/flowcli/services/scripts.go | 3 + 3 files changed, 168 insertions(+) create mode 100644 pkg/flowcli/contracts/resolver.go create mode 100644 pkg/flowcli/contracts/resolver_test.go diff --git a/pkg/flowcli/contracts/resolver.go b/pkg/flowcli/contracts/resolver.go new file mode 100644 index 000000000..a904fbe1f --- /dev/null +++ b/pkg/flowcli/contracts/resolver.go @@ -0,0 +1,95 @@ +package contracts + +import ( + "fmt" + "path" + "path/filepath" + "strings" + + "github.com/onflow/cadence/runtime/ast" + "github.com/onflow/cadence/runtime/common" + "github.com/onflow/cadence/runtime/parser2" + "github.com/onflow/flow-cli/pkg/flowcli/project" +) + +type Resolver struct { + code string + program *ast.Program +} + +func NewResolver(code []byte) (*Resolver, error) { + program, err := parser2.ParseProgram(string(code)) + if err != nil { + return nil, err + } + + return &Resolver{ + code: string(code), + program: program, + }, nil +} + +func (r *Resolver) ResolveImports( + contracts []project.Contract, + aliases project.Aliases, +) string { + imports := r.parseImports() + sourceTarget := r.getSourceTarget(contracts, aliases) + + fmt.Println(absolutePath("./tests/Foo.cdc", "./Foo.cdc"), path.Clean("./tests/Foo.cdc")) + fmt.Println(filepath.Abs("./Foo.cdc")) + fmt.Println(filepath.Abs("./tests/Foo.cdc")) + + for _, imp := range imports { + fmt.Println(absolutePath(imp, sourceTarget[imp])) + fmt.Println(imp, sourceTarget[imp], sourceTarget) + + if sourceTarget[imp] != "" { + r.code = r.replaceImport(imp, sourceTarget[imp]) + } + } + + return r.code +} + +func (r *Resolver) replaceImport(from string, to string) string { + return strings.Replace( + r.code, + fmt.Sprintf(`"%s"`, from), + fmt.Sprintf("0x%s", to), + 1, + ) +} + +func (r *Resolver) getSourceTarget( + contracts []project.Contract, + aliases project.Aliases, +) map[string]string { + sourceTarget := make(map[string]string, 0) + for _, contract := range contracts { + sourceTarget[path.Clean(contract.Source)] = contract.Target.String() + } + + for source, target := range aliases { + sourceTarget[source] = target + } + + return sourceTarget +} + +func (r *Resolver) ImportExists() bool { + return len(r.parseImports()) > 0 +} + +func (r *Resolver) parseImports() []string { + imports := make([]string, 0) + + for _, importDeclaration := range r.program.ImportDeclarations() { + location, ok := importDeclaration.Location.(common.StringLocation) + if ok { + imports = append(imports, location.String()) + } + } + + return imports +} diff --git a/pkg/flowcli/contracts/resolver_test.go b/pkg/flowcli/contracts/resolver_test.go new file mode 100644 index 000000000..f52dbaa92 --- /dev/null +++ b/pkg/flowcli/contracts/resolver_test.go @@ -0,0 +1,70 @@ +package contracts + +import ( + "testing" + + "github.com/onflow/flow-cli/pkg/flowcli/project" + "github.com/onflow/flow-go-sdk" + + "github.com/stretchr/testify/assert" +) + +func TestResolver(t *testing.T) { + + contracts := []project.Contract{{ + Name: "Kibble", + Source: "./../contracts/Kibble.cdc", + Target: flow.HexToAddress("0x1"), + }, { + Name: "FT", + Source: "./../contracts/FT.cdc", + Target: flow.HexToAddress("0x2"), + }, { + Name: "NFT", + Source: "./../contracts/NFT.cdc", + Target: flow.HexToAddress("0x3"), + }} + + t.Run("Import exists", func(t *testing.T) { + resolver, err := NewResolver([]byte(` + import Kibble from "../../contracts/Kibble.cdc" + pub fun main() {} + `)) + assert.NoError(t, err) + assert.True(t, resolver.ImportExists()) + }) + + t.Run("Import doesn't exists", func(t *testing.T) { + resolver, err := NewResolver([]byte(` + pub fun main() {} + `)) + assert.NoError(t, err) + assert.False(t, resolver.ImportExists()) + }) + + t.Run("Parse imports", func(t *testing.T) { + resolver, err := NewResolver([]byte(` + import Kibble from "../../contracts/Kibble.cdc" + import FT from "../../contracts/FT.cdc" + pub fun main() {} + `)) + assert.NoError(t, err) + assert.Equal(t, resolver.parseImports(), []string{ + "../../contracts/Kibble.cdc", "../../contracts/FT.cdc", + }) + }) + + t.Run("Resolve imports", func(t *testing.T) { + resolver, err := NewResolver([]byte(` + import Kibble from "./Kibble.cdc" + import FT from "./FT.cdc" + pub fun main() {} + `)) + + code := resolver.ResolveImports(contracts, make(map[string]string)) + + assert.NoError(t, err) + assert.Equal(t, code, "") + }) + +} diff --git a/pkg/flowcli/services/scripts.go b/pkg/flowcli/services/scripts.go index c2f6973fe..c6bcd5df9 100644 --- a/pkg/flowcli/services/scripts.go +++ b/pkg/flowcli/services/scripts.go @@ -69,5 +69,8 @@ func (s *Scripts) execute(code []byte, args []string, argsJSON string) (cadence. return nil, err } + // code has imports + // code = project resolveImports + return s.gateway.ExecuteScript(code, scriptArgs) } From 3677d67612d765af4a053a01af6acd8442924dfe Mon Sep 17 00:00:00 2001 From: Gregor Gololicic Date: Wed, 7 Apr 2021 13:18:43 +0200 Subject: [PATCH 044/137] resolver get relative path from script --- pkg/flowcli/contracts/resolver.go | 32 ++++++++---------- pkg/flowcli/contracts/resolver_test.go | 45 ++++++++++++++++---------- pkg/flowcli/services/scripts.go | 38 ++++++++++++++++++---- 3 files changed, 73 insertions(+), 42 deletions(-) diff --git a/pkg/flowcli/contracts/resolver.go b/pkg/flowcli/contracts/resolver.go index a904fbe1f..684712c8d 100644 --- a/pkg/flowcli/contracts/resolver.go +++ b/pkg/flowcli/contracts/resolver.go @@ -3,7 +3,6 @@ package contracts import ( "fmt" "path" - "path/filepath" "strings" "github.com/onflow/cadence/runtime/ast" @@ -13,7 +12,7 @@ import ( ) type Resolver struct { - code string + code []byte program *ast.Program } @@ -24,41 +23,38 @@ func NewResolver(code []byte) (*Resolver, error) { } return &Resolver{ - code: string(code), + code: code, program: program, }, nil } func (r *Resolver) ResolveImports( + scriptPath string, contracts []project.Contract, aliases project.Aliases, -) string { +) ([]byte, error) { imports := r.parseImports() sourceTarget := r.getSourceTarget(contracts, aliases) - fmt.Println(absolutePath("./tests/Foo.cdc", "./Foo.cdc"), path.Clean("./tests/Foo.cdc")) - fmt.Println(filepath.Abs("./Foo.cdc")) - fmt.Println(filepath.Abs("./tests/Foo.cdc")) - for _, imp := range imports { - fmt.Println(absolutePath(imp, sourceTarget[imp])) - fmt.Println(imp, sourceTarget[imp], sourceTarget) - - if sourceTarget[imp] != "" { - r.code = r.replaceImport(imp, sourceTarget[imp]) + target := sourceTarget[absolutePath(scriptPath, imp)] + if target != "" { + r.code = r.replaceImport(imp, target) + } else { + return nil, fmt.Errorf("import %s could not be resolved from the configuration", imp) } } - return r.code + return r.code, nil } -func (r *Resolver) replaceImport(from string, to string) string { - return strings.Replace( - r.code, +func (r *Resolver) replaceImport(from string, to string) []byte { + return []byte(strings.Replace( + string(r.code), fmt.Sprintf(`"%s"`, from), fmt.Sprintf("0x%s", to), 1, - ) + )) } func (r *Resolver) getSourceTarget( diff --git a/pkg/flowcli/contracts/resolver_test.go b/pkg/flowcli/contracts/resolver_test.go index f52dbaa92..b83834572 100644 --- a/pkg/flowcli/contracts/resolver_test.go +++ b/pkg/flowcli/contracts/resolver_test.go @@ -1,6 +1,7 @@ package contracts import ( + "regexp" "testing" "github.com/onflow/flow-cli/pkg/flowcli/project" @@ -9,25 +10,38 @@ import ( "github.com/stretchr/testify/assert" ) +func cleanCode(code []byte) string { + space := regexp.MustCompile(`\s+`) + return space.ReplaceAllString(string(code), " ") +} + func TestResolver(t *testing.T) { contracts := []project.Contract{{ Name: "Kibble", - Source: "./../contracts/Kibble.cdc", + Source: "./tests/Kibble.cdc", Target: flow.HexToAddress("0x1"), }, { Name: "FT", - Source: "./../contracts/FT.cdc", + Source: "./tests/FT.cdc", Target: flow.HexToAddress("0x2"), }, { Name: "NFT", - Source: "./../contracts/NFT.cdc", + Source: "./tests/NFT.cdc", Target: flow.HexToAddress("0x3"), }} + scripts := [][]byte{ + []byte(` + import Kibble from "./Kibble.cdc" + import FT from "./FT.cdc" + pub fun main() {} + `), + } + t.Run("Import exists", func(t *testing.T) { resolver, err := NewResolver([]byte(` - import Kibble from "../../contracts/Kibble.cdc" + import Kibble from "./Kibble.cdc" pub fun main() {} `)) assert.NoError(t, err) @@ -43,28 +57,25 @@ func TestResolver(t *testing.T) { }) t.Run("Parse imports", func(t *testing.T) { - resolver, err := NewResolver([]byte(` - import Kibble from "../../contracts/Kibble.cdc" - import FT from "../../contracts/FT.cdc" - pub fun main() {} - `)) + resolver, err := NewResolver(scripts[0]) assert.NoError(t, err) assert.Equal(t, resolver.parseImports(), []string{ - "../../contracts/Kibble.cdc", "../../contracts/FT.cdc", + "./Kibble.cdc", "./FT.cdc", }) }) t.Run("Resolve imports", func(t *testing.T) { - resolver, err := NewResolver([]byte(` - import Kibble from "./Kibble.cdc" - import FT from "./FT.cdc" - pub fun main() {} - `)) + resolver, err := NewResolver(scripts[0]) + assert.NoError(t, err) - code := resolver.ResolveImports(contracts, make(map[string]string)) + code, err := resolver.ResolveImports("./tests/foo.cdc", contracts, make(map[string]string)) assert.NoError(t, err) - assert.Equal(t, code, "") + assert.Equal(t, cleanCode(code), cleanCode([]byte(` + import Kibble from 0x0000000000000001 + import FT from 0x0000000000000002 + pub fun main() {} + `))) }) } diff --git a/pkg/flowcli/services/scripts.go b/pkg/flowcli/services/scripts.go index c6bcd5df9..e6e7410b6 100644 --- a/pkg/flowcli/services/scripts.go +++ b/pkg/flowcli/services/scripts.go @@ -19,7 +19,10 @@ package services import ( + "fmt" + "github.com/onflow/cadence" + "github.com/onflow/flow-cli/pkg/flowcli/contracts" "github.com/onflow/flow-cli/pkg/flowcli" "github.com/onflow/flow-cli/pkg/flowcli/gateway" @@ -49,28 +52,49 @@ func NewScripts( } // Execute executes a Cadence script from a file. -func (s *Scripts) Execute(scriptFilename string, args []string, argsJSON string) (cadence.Value, error) { - script, err := util.LoadFile(scriptFilename) +func (s *Scripts) Execute(scriptPath string, args []string, argsJSON string, network string) (cadence.Value, error) { + script, err := util.LoadFile(scriptPath) if err != nil { return nil, err } - return s.execute(script, args, argsJSON) + return s.execute(script, args, argsJSON, scriptPath, network) } // Execute executes a Cadence script from a source code string. func (s *Scripts) ExecuteWithCode(code []byte, args []string, argsJSON string) (cadence.Value, error) { - return s.execute(code, args, argsJSON) + return s.execute(code, args, argsJSON, "", "") } -func (s *Scripts) execute(code []byte, args []string, argsJSON string) (cadence.Value, error) { +func (s *Scripts) execute(code []byte, args []string, argsJSON string, scriptPath string, network string) (cadence.Value, error) { scriptArgs, err := flowcli.ParseArguments(args, argsJSON) if err != nil { return nil, err } - // code has imports - // code = project resolveImports + resolver, err := contracts.NewResolver(code) + if err != nil { + return nil, err + } + + if resolver.ImportExists() { + if s.project == nil { + return nil, fmt.Errorf("missing configuration, initialize it: flow init") + } else if network == "" { + return nil, fmt.Errorf("missing network, specify which network to use to resolve imports in script code") + } else if scriptPath == "" { // when used as lib with code we don't support imports + return nil, fmt.Errorf("resolving imports in scripts not supported") + } + + code, err = resolver.ResolveImports( + scriptPath, + s.project.ContractsByNetwork(network), + s.project.AliasesForNetwork(network), + ) + if err != nil { + return nil, err + } + } return s.gateway.ExecuteScript(code, scriptArgs) } From 7c2a89205d288535e694c241fc03130930e9d78e Mon Sep 17 00:00:00 2001 From: Gregor Gololicic Date: Wed, 7 Apr 2021 13:21:24 +0200 Subject: [PATCH 045/137] add network to scripts --- go.mod | 1 + go.sum | 7 +++++++ internal/scripts/execute.go | 1 + 3 files changed, 9 insertions(+) diff --git a/go.mod b/go.mod index 98f622737..b069667f5 100644 --- a/go.mod +++ b/go.mod @@ -8,6 +8,7 @@ require ( github.com/fsnotify/fsnotify v1.4.9 // indirect github.com/gosuri/uilive v0.0.4 github.com/kr/text v0.2.0 // indirect + github.com/manifoldco/promptui v0.8.0 github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e // indirect github.com/onflow/cadence v0.13.7 github.com/onflow/cadence/languageserver v0.13.1 diff --git a/go.sum b/go.sum index c15688bf5..aa9cf9e26 100644 --- a/go.sum +++ b/go.sum @@ -128,6 +128,7 @@ github.com/cespare/xxhash/v2 v2.1.1/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XL github.com/cheekybits/genny v1.0.0 h1:uGGa4nei+j20rOSeDeP5Of12XVm7TGUd4dJA9RDitfE= github.com/cheekybits/genny v1.0.0/go.mod h1:+tQajlRqAUrPI7DOSpB0XAqZYtQakVtB7wXkRAgjxjQ= github.com/chzyer/logex v1.1.10/go.mod h1:+Ywpsq7O8HXn0nuIou7OrIPyXbp3wmkHB+jjWRnGsAI= +github.com/chzyer/readline v0.0.0-20180603132655-2972be24d48e h1:fY5BOSpyZCqRo5OhCuC+XN+r/bBCmeuuJtjz+bCNIf8= github.com/chzyer/readline v0.0.0-20180603132655-2972be24d48e/go.mod h1:nSuG5e5PlCu98SY8svDHJxuZscDgtXS6KTTbou5AhLI= github.com/chzyer/test v0.0.0-20180213035817-a1ea475d72b1/go.mod h1:Q3SI9o4m/ZMnBNeIyt5eFwwo7qiLfzFZmjNmxjkiQlU= github.com/clbanning/x2j v0.0.0-20191024224557-825249438eec/go.mod h1:jMjuTZXRI4dUb/I5gc9Hdhagfvm9+RyrPryS/auMzxE= @@ -426,6 +427,8 @@ github.com/jstemmer/go-junit-report v0.0.0-20190106144839-af01ea7f8024/go.mod h1 github.com/jstemmer/go-junit-report v0.9.1/go.mod h1:Brl9GWCQeLvo8nXZwPNNblvFj/XSXhF0NWZEnDohbsk= github.com/jtolds/gls v4.20.0+incompatible h1:xdiiI2gbIgH/gLH7ADydsJ1uDOEzR8yvV7C0MuV77Wo= github.com/jtolds/gls v4.20.0+incompatible/go.mod h1:QJZ7F/aHp+rZTRtaJ1ow/lLfFfVYBRgL+9YlvaHOwJU= +github.com/juju/ansiterm v0.0.0-20180109212912-720a0952cc2a h1:FaWFmfWdAUKbSCtOU2QjDaorUexogfaMgbipgYATUMU= +github.com/juju/ansiterm v0.0.0-20180109212912-720a0952cc2a/go.mod h1:UJSiEoRfvx3hP73CvoARgeLjaIOjybY9vj8PUPPFGeU= github.com/julienschmidt/httprouter v1.1.1-0.20170430222011-975b5c4c7c21/go.mod h1:SYymIcj16QtmaHHD7aYtjjsJG7VTCxuUUipMqKk8s4w= github.com/julienschmidt/httprouter v1.2.0/go.mod h1:SYymIcj16QtmaHHD7aYtjjsJG7VTCxuUUipMqKk8s4w= github.com/julienschmidt/httprouter v1.3.0/go.mod h1:JR6WtHb+2LUe8TCKY3cZOxFyyO8IZAc4RVcycCCAKdM= @@ -600,6 +603,8 @@ github.com/lightstep/lightstep-tracer-common/golang/gogo v0.0.0-20190605223551-b github.com/lightstep/lightstep-tracer-go v0.18.1/go.mod h1:jlF1pusYV4pidLvZ+XD0UBX0ZE6WURAspgAczcDHrL4= github.com/logrusorgru/aurora v0.0.0-20200102142835-e9ef32dff381 h1:bqDmpDG49ZRnB5PcgP0RXtQvnMSgIF14M7CBd2shtXs= github.com/logrusorgru/aurora v0.0.0-20200102142835-e9ef32dff381/go.mod h1:7rIyQOR62GCctdiQpZ/zOJlFyk6y+94wXzv6RNZgaR4= +github.com/lunixbochs/vtclean v0.0.0-20180621232353-2d01aacdc34a h1:weJVJJRzAJBFRlAiJQROKQs8oC9vOxvm4rZmBBk0ONw= +github.com/lunixbochs/vtclean v0.0.0-20180621232353-2d01aacdc34a/go.mod h1:pHhQNgMf3btfWnGBVipUOjRYhoOsdGqdm/+2c2E2WMI= github.com/lyft/protoc-gen-validate v0.0.13/go.mod h1:XbGvPuh87YZc5TdIa2/I4pLk0QoUACkjt2znoq26NVQ= github.com/m4ksio/wal v1.0.0 h1:PucHOZPz58BgWowe+Gf+gZUbgEdd4zFx+He45SGkHG0= github.com/m4ksio/wal v1.0.0/go.mod h1:S3UyatBTuMdoI5QTuz2DWb8Csd9568vYrFAmMI/bnMw= @@ -607,6 +612,8 @@ github.com/magiconair/properties v1.8.0/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czP github.com/magiconair/properties v1.8.1 h1:ZC2Vc7/ZFkGmsVC9KvOjumD+G5lXy2RtTKyzRKO2BQ4= github.com/magiconair/properties v1.8.1/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czPbwD3XqdrwzmxQ= github.com/mailru/easyjson v0.0.0-20180823135443-60711f1a8329/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc= +github.com/manifoldco/promptui v0.8.0 h1:R95mMF+McvXZQ7j1g8ucVZE1gLP3Sv6j9vlF9kyRqQo= +github.com/manifoldco/promptui v0.8.0/go.mod h1:n4zTdgP0vr0S3w7/O/g98U+e0gwLScEXGwov2nIKuGQ= github.com/mattn/go-colorable v0.0.9/go.mod h1:9vuHe8Xs5qXnSaW/c/ABM9alt+Vo+STaOChaDxuIBZU= github.com/mattn/go-colorable v0.1.0/go.mod h1:9vuHe8Xs5qXnSaW/c/ABM9alt+Vo+STaOChaDxuIBZU= github.com/mattn/go-colorable v0.1.1/go.mod h1:FuOcm+DKB9mbwrcAfNl7/TZVBZ6rcnceauSikq3lYCQ= diff --git a/internal/scripts/execute.go b/internal/scripts/execute.go index ecb97fb3b..655a91d28 100644 --- a/internal/scripts/execute.go +++ b/internal/scripts/execute.go @@ -72,6 +72,7 @@ var ExecuteCommand = &command.Command{ filename, scriptFlags.Arg, scriptFlags.ArgsJSON, + globalFlags.Network, ) if err != nil { return nil, err From 23ec4175cfec4cefb1ffaf31c9be76b515cf2777 Mon Sep 17 00:00:00 2001 From: Gregor Gololicic Date: Wed, 7 Apr 2021 13:29:27 +0200 Subject: [PATCH 046/137] better host and network handling and default network value --- internal/command/command.go | 21 ++++++++++++++------- 1 file changed, 14 insertions(+), 7 deletions(-) diff --git a/internal/command/command.go b/internal/command/command.go index e8b0e86dd..5b0d40a3d 100644 --- a/internal/command/command.go +++ b/internal/command/command.go @@ -67,7 +67,7 @@ var flags = GlobalFlags{ Save: "", Host: "", Log: "info", - Network: "", + Network: project.DefaultEmulatorNetworkName, ConfigPath: project.DefaultConfigPaths, } @@ -180,19 +180,26 @@ func createGateway(host string) (gateway.Gateway, error) { // resolveHost from the flags provided func resolveHost(proj *project.Project, hostFlag string, networkFlag string) (string, error) { - host := hostFlag + // don't allow both network and host flag as the host might be different + if networkFlag != "" && hostFlag != "" { + return "", fmt.Errorf("shouldn't use both host and network flags, better to use network flag") + } + + // host flag has highest priority + if hostFlag != "" { + return hostFlag, nil + } + // network flag with project initialized is next if networkFlag != "" && proj != nil { check := proj.NetworkByName(networkFlag) if check == nil { return "", fmt.Errorf("provided network with name %s doesn't exists in condiguration", networkFlag) } - host = proj.NetworkByName(networkFlag).Host - } else if host == "" { - host = project.DefaultEmulatorHost + return proj.NetworkByName(networkFlag).Host, nil } - - return host, nil + // default to emulator host + return project.DefaultEmulatorHost, nil } // create logger utility From a3e431f3f4b50c2fc538c6ffdf53222383b29f22 Mon Sep 17 00:00:00 2001 From: Gregor Gololicic Date: Wed, 7 Apr 2021 13:35:56 +0200 Subject: [PATCH 047/137] added resolving to transactions --- internal/transactions/send.go | 1 + pkg/flowcli/contracts/resolver.go | 4 ++-- pkg/flowcli/services/transactions.go | 35 ++++++++++++++++++++++++---- 3 files changed, 34 insertions(+), 6 deletions(-) diff --git a/internal/transactions/send.go b/internal/transactions/send.go index 5afe73add..67c01a3d8 100644 --- a/internal/transactions/send.go +++ b/internal/transactions/send.go @@ -79,6 +79,7 @@ var SendCommand = &command.Command{ sendFlags.Signer, sendFlags.Arg, sendFlags.ArgsJSON, + globalFlags.Network, ) if err != nil { return nil, err diff --git a/pkg/flowcli/contracts/resolver.go b/pkg/flowcli/contracts/resolver.go index 684712c8d..25cdb49d9 100644 --- a/pkg/flowcli/contracts/resolver.go +++ b/pkg/flowcli/contracts/resolver.go @@ -29,7 +29,7 @@ func NewResolver(code []byte) (*Resolver, error) { } func (r *Resolver) ResolveImports( - scriptPath string, + codePath string, contracts []project.Contract, aliases project.Aliases, ) ([]byte, error) { @@ -37,7 +37,7 @@ func (r *Resolver) ResolveImports( sourceTarget := r.getSourceTarget(contracts, aliases) for _, imp := range imports { - target := sourceTarget[absolutePath(scriptPath, imp)] + target := sourceTarget[absolutePath(codePath, imp)] if target != "" { r.code = r.replaceImport(imp, target) } else { diff --git a/pkg/flowcli/services/transactions.go b/pkg/flowcli/services/transactions.go index 2cd1ee8f0..6afb51f92 100644 --- a/pkg/flowcli/services/transactions.go +++ b/pkg/flowcli/services/transactions.go @@ -22,6 +22,8 @@ import ( "fmt" "strings" + "github.com/onflow/flow-cli/pkg/flowcli/contracts" + "github.com/onflow/flow-go-sdk" "github.com/onflow/flow-go-sdk/crypto" @@ -55,10 +57,11 @@ func NewTransactions( // Send sends a transaction from a file. func (t *Transactions) Send( - transactionFilename string, + codePath string, signerName string, args []string, argsJSON string, + network string, ) (*flow.Transaction, *flow.TransactionResult, error) { if t.project == nil { return nil, nil, fmt.Errorf("missing configuration, initialize it: flow init") @@ -69,12 +72,12 @@ func (t *Transactions) Send( return nil, nil, fmt.Errorf("signer account: [%s] doesn't exists in configuration", signerName) } - code, err := util.LoadFile(transactionFilename) + code, err := util.LoadFile(codePath) if err != nil { return nil, nil, err } - return t.send(code, signer, args, argsJSON) + return t.send(code, signer, args, argsJSON, codePath, network) } // SendForAddress send transaction for address and private key, code passed via filename @@ -110,7 +113,7 @@ func (t *Transactions) SendForAddressWithCode( account := project.AccountFromAddressAndKey(address, privateKey) - return t.send(code, account, args, argsJSON) + return t.send(code, account, args, argsJSON, "", "") } func (t *Transactions) send( @@ -118,6 +121,8 @@ func (t *Transactions) send( signer *project.Account, args []string, argsJSON string, + codePath string, + network string, ) (*flow.Transaction, *flow.TransactionResult, error) { // if google kms account then sign in @@ -132,6 +137,28 @@ func (t *Transactions) send( t.logger.StartProgress("Sending transaction...") + resolver, err := contracts.NewResolver(code) + if err != nil { + return nil, nil, err + } + + if resolver.ImportExists() { + if network == "" { + return nil, nil, fmt.Errorf("missing network, specify which network to use to resolve imports in transaction code") + } else if codePath == "" { // when used as lib with code we don't support imports + return nil, nil, fmt.Errorf("resolving imports in transactions not supported") + } + + code, err = resolver.ResolveImports( + codePath, + t.project.ContractsByNetwork(network), + t.project.AliasesForNetwork(network), + ) + if err != nil { + return nil, nil, err + } + } + tx := flow.NewTransaction(). SetScript(code). AddAuthorizer(signer.Address()) From a60b3328e103464f9ea401ed125bd2ee75ed273c Mon Sep 17 00:00:00 2001 From: Gregor Gololicic Date: Wed, 7 Apr 2021 13:41:42 +0200 Subject: [PATCH 048/137] add comments --- pkg/flowcli/contracts/resolver.go | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/pkg/flowcli/contracts/resolver.go b/pkg/flowcli/contracts/resolver.go index 25cdb49d9..e51bc1a38 100644 --- a/pkg/flowcli/contracts/resolver.go +++ b/pkg/flowcli/contracts/resolver.go @@ -11,11 +11,13 @@ import ( "github.com/onflow/flow-cli/pkg/flowcli/project" ) +// Resolver handles resolving imports in Cadence code type Resolver struct { code []byte program *ast.Program } +// NewResolver creates a new resolver func NewResolver(code []byte) (*Resolver, error) { program, err := parser2.ParseProgram(string(code)) if err != nil { @@ -28,6 +30,11 @@ func NewResolver(code []byte) (*Resolver, error) { }, nil } +// ResolveImports resolves imports in code to addresses +// +// resolving is done based on code file path and is resolved to +// addresses defined in configuration for contracts or their aliases +// func (r *Resolver) ResolveImports( codePath string, contracts []project.Contract, @@ -48,6 +55,7 @@ func (r *Resolver) ResolveImports( return r.code, nil } +// replaceImport replaces import from path to address func (r *Resolver) replaceImport(from string, to string) []byte { return []byte(strings.Replace( string(r.code), @@ -57,6 +65,7 @@ func (r *Resolver) replaceImport(from string, to string) []byte { )) } +// getSourceTarget return a map with contract paths as keys and addresses as values func (r *Resolver) getSourceTarget( contracts []project.Contract, aliases project.Aliases, @@ -73,10 +82,12 @@ func (r *Resolver) getSourceTarget( return sourceTarget } +// ImportExists checks if there is an import statement present in Cadence code func (r *Resolver) ImportExists() bool { return len(r.parseImports()) > 0 } +// parseImports returns all imports from Cadence code as an array func (r *Resolver) parseImports() []string { imports := make([]string, 0) From a0e566f8e13664783b59de195102ddb1a253ba81 Mon Sep 17 00:00:00 2001 From: Gregor Gololicic Date: Wed, 7 Apr 2021 15:09:20 +0200 Subject: [PATCH 049/137] added tests for aliases --- pkg/flowcli/contracts/resolver_test.go | 61 ++++++++++++++++++++------ 1 file changed, 48 insertions(+), 13 deletions(-) diff --git a/pkg/flowcli/contracts/resolver_test.go b/pkg/flowcli/contracts/resolver_test.go index b83834572..d144a778e 100644 --- a/pkg/flowcli/contracts/resolver_test.go +++ b/pkg/flowcli/contracts/resolver_test.go @@ -25,17 +25,47 @@ func TestResolver(t *testing.T) { Name: "FT", Source: "./tests/FT.cdc", Target: flow.HexToAddress("0x2"), - }, { - Name: "NFT", - Source: "./tests/NFT.cdc", - Target: flow.HexToAddress("0x3"), }} + aliases := map[string]string{ + "./tests/NFT.cdc": flow.HexToAddress("0x4").String(), + } + + paths := []string{ + "./tests/foo.cdc", + "./scripts/bar/foo.cdc", + "./scripts/bar/foo.cdc", + } + scripts := [][]byte{ []byte(` import Kibble from "./Kibble.cdc" import FT from "./FT.cdc" pub fun main() {} + `), []byte(` + import Kibble from "../../tests/Kibble.cdc" + import FT from "../../tests/FT.cdc" + pub fun main() {} + `), []byte(` + import Kibble from "../../tests/Kibble.cdc" + import NFT from "../../tests/NFT.cdc" + pub fun main() {} + `), + } + + resolved := [][]byte{ + []byte(` + import Kibble from 0x0000000000000001 + import FT from 0x0000000000000002 + pub fun main() {} + `), []byte(` + import Kibble from 0x0000000000000001 + import FT from 0x0000000000000002 + pub fun main() {} + `), []byte(` + import Kibble from 0x0000000000000001 + import NFT from 0x0000000000000004 + pub fun main() {} `), } @@ -51,6 +81,13 @@ func TestResolver(t *testing.T) { t.Run("Import doesn't exists", func(t *testing.T) { resolver, err := NewResolver([]byte(` pub fun main() {} + `)) + assert.NoError(t, err) + assert.False(t, resolver.ImportExists()) + + resolver, err = NewResolver([]byte(` + import Foo from 0xf8d6e0586b0a20c7 + pub fun main() {} `)) assert.NoError(t, err) assert.False(t, resolver.ImportExists()) @@ -65,17 +102,15 @@ func TestResolver(t *testing.T) { }) t.Run("Resolve imports", func(t *testing.T) { - resolver, err := NewResolver(scripts[0]) - assert.NoError(t, err) + for i, script := range scripts { + resolver, err := NewResolver(script) + assert.NoError(t, err) - code, err := resolver.ResolveImports("./tests/foo.cdc", contracts, make(map[string]string)) + code, err := resolver.ResolveImports(paths[i], contracts, aliases) - assert.NoError(t, err) - assert.Equal(t, cleanCode(code), cleanCode([]byte(` - import Kibble from 0x0000000000000001 - import FT from 0x0000000000000002 - pub fun main() {} - `))) + assert.NoError(t, err) + assert.Equal(t, cleanCode(code), cleanCode(resolved[i])) + } }) } From c06fb9edff6ceb907ae14229d9e29c43f7f6f1a1 Mon Sep 17 00:00:00 2001 From: Gregor Gololicic Date: Wed, 7 Apr 2021 15:09:41 +0200 Subject: [PATCH 050/137] ignore address imports --- pkg/flowcli/contracts/resolver.go | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/pkg/flowcli/contracts/resolver.go b/pkg/flowcli/contracts/resolver.go index e51bc1a38..5ebb6ac89 100644 --- a/pkg/flowcli/contracts/resolver.go +++ b/pkg/flowcli/contracts/resolver.go @@ -5,6 +5,8 @@ import ( "path" "strings" + "github.com/onflow/flow-go-sdk" + "github.com/onflow/cadence/runtime/ast" "github.com/onflow/cadence/runtime/common" "github.com/onflow/cadence/runtime/parser2" @@ -76,7 +78,7 @@ func (r *Resolver) getSourceTarget( } for source, target := range aliases { - sourceTarget[source] = target + sourceTarget[path.Clean(source)] = target } return sourceTarget @@ -93,7 +95,7 @@ func (r *Resolver) parseImports() []string { for _, importDeclaration := range r.program.ImportDeclarations() { location, ok := importDeclaration.Location.(common.StringLocation) - if ok { + if ok && flow.HexToAddress(location.String()) == flow.EmptyAddress { imports = append(imports, location.String()) } } From 32a1bccaaa80fc59da2f1ff9401c464239e64367 Mon Sep 17 00:00:00 2001 From: Gregor Gololicic Date: Wed, 7 Apr 2021 15:23:18 +0200 Subject: [PATCH 051/137] removed flag value --- internal/transactions/send.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/internal/transactions/send.go b/internal/transactions/send.go index 67c01a3d8..e9f2a33e6 100644 --- a/internal/transactions/send.go +++ b/internal/transactions/send.go @@ -33,7 +33,7 @@ type flagsSend struct { Signer string `default:"emulator-account" flag:"signer"` Code string `default:"" flag:"code" info:"⚠️ Deprecated: use filename argument"` Results bool `default:"" flag:"results" info:"⚠️ Deprecated: all transactions will provide result"` - Args string `default:"false" flag:"args" info:"⚠️ Deprecated: use arg or args-json flag"` + Args string `default:"" flag:"args" info:"⚠️ Deprecated: use arg or args-json flag"` } var sendFlags = flagsSend{} From 768d6135e2cbff09620b75db0ae31d9bc6fcfae1 Mon Sep 17 00:00:00 2001 From: Gregor Gololicic Date: Wed, 7 Apr 2021 15:55:37 +0200 Subject: [PATCH 052/137] better handle addresses --- pkg/flowcli/arguments.go | 5 +++++ pkg/flowcli/contracts/resolver.go | 2 +- 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/pkg/flowcli/arguments.go b/pkg/flowcli/arguments.go index b175a72c9..e52d46cbe 100644 --- a/pkg/flowcli/arguments.go +++ b/pkg/flowcli/arguments.go @@ -75,6 +75,11 @@ func ParseArgumentsCommaSplit(input []string) ([]cadence.Value, error) { ) } + // if we are passing address check and handle without 0x prefix as else it wont work and error is not descriptive + if argInput[0] == "Address" && !strings.Contains(argInput[1], "0x") { + argInput[1] = fmt.Sprintf("0x%s", argInput[1]) + } + args = append(args, map[string]string{ "value": argInput[1], "type": argInput[0], diff --git a/pkg/flowcli/contracts/resolver.go b/pkg/flowcli/contracts/resolver.go index 5ebb6ac89..b30a5c3bf 100644 --- a/pkg/flowcli/contracts/resolver.go +++ b/pkg/flowcli/contracts/resolver.go @@ -78,7 +78,7 @@ func (r *Resolver) getSourceTarget( } for source, target := range aliases { - sourceTarget[path.Clean(source)] = target + sourceTarget[path.Clean(source)] = flow.HexToAddress(target).String() } return sourceTarget From 0f0365da95af22490dd3b9499480aa8059768849 Mon Sep 17 00:00:00 2001 From: Gregor Gololicic Date: Wed, 7 Apr 2021 16:01:55 +0200 Subject: [PATCH 053/137] test fixes --- pkg/flowcli/services/scripts_test.go | 2 +- pkg/flowcli/services/transactions_test.go | 33 ++++++++++++++++++++--- tests/e2e_test.go | 8 +++--- 3 files changed, 34 insertions(+), 9 deletions(-) diff --git a/pkg/flowcli/services/scripts_test.go b/pkg/flowcli/services/scripts_test.go index 47c6778f4..e72b1d39d 100644 --- a/pkg/flowcli/services/scripts_test.go +++ b/pkg/flowcli/services/scripts_test.go @@ -45,7 +45,7 @@ func TestScripts(t *testing.T) { return arguments[0], nil } - _, err := scripts.Execute("../../../tests/script.cdc", []string{"String:Foo"}, "") + _, err := scripts.Execute("../../../tests/script.cdc", []string{"String:Foo"}, "", "") assert.NoError(t, err) }) diff --git a/pkg/flowcli/services/transactions_test.go b/pkg/flowcli/services/transactions_test.go index 4893822ab..761f37cf2 100644 --- a/pkg/flowcli/services/transactions_test.go +++ b/pkg/flowcli/services/transactions_test.go @@ -78,7 +78,13 @@ func TestTransactions(t *testing.T) { return tests.NewTransaction(), nil } - _, _, err := transactions.Send("../../../tests/transaction.cdc", serviceName, []string{"String:Bar"}, "") + _, _, err := transactions.Send( + "../../../tests/transaction.cdc", + serviceName, + []string{"String:Bar"}, + "", + "", + ) assert.NoError(t, err) assert.Equal(t, called, 2) @@ -104,6 +110,7 @@ func TestTransactions(t *testing.T) { serviceName, nil, "[{\"type\": \"String\", \"value\": \"Bar\"}]", + "", ) assert.NoError(t, err) @@ -111,17 +118,35 @@ func TestTransactions(t *testing.T) { }) t.Run("Send Transaction Fails wrong args", func(t *testing.T) { - _, _, err := transactions.Send("../../../tests/transaction.cdc", serviceName, []string{"Bar"}, "") + _, _, err := transactions.Send( + "../../../tests/transaction.cdc", + serviceName, + []string{"Bar"}, + "", + "", + ) assert.Equal(t, err.Error(), "argument not passed in correct format, correct format is: Type:Value, got Bar") }) t.Run("Send Transaction Fails wrong filename", func(t *testing.T) { - _, _, err := transactions.Send("nooo.cdc", serviceName, []string{"Bar"}, "") + _, _, err := transactions.Send( + "nooo.cdc", + serviceName, + []string{"Bar"}, + "", + "", + ) assert.Equal(t, err.Error(), "Failed to load file: nooo.cdc") }) t.Run("Send Transaction Fails wrong args", func(t *testing.T) { - _, _, err := transactions.Send("../../../tests/transaction.cdc", serviceName, nil, "[{\"Bar\":\"No\"}]") + _, _, err := transactions.Send( + "../../../tests/transaction.cdc", + serviceName, + nil, + "[{\"Bar\":\"No\"}]", + "", + ) assert.Equal(t, err.Error(), "failed to decode value: invalid JSON Cadence structure") }) } diff --git a/tests/e2e_test.go b/tests/e2e_test.go index ed0d6db39..abb4aa671 100644 --- a/tests/e2e_test.go +++ b/tests/e2e_test.go @@ -207,14 +207,14 @@ func TestScripts(t *testing.T) { scripts := services.NewScripts(gateway, project, logger) t.Run("Test Script", func(t *testing.T) { - val, err := scripts.Execute("./script.cdc", []string{"String:Mr G"}, "") + val, err := scripts.Execute("./script.cdc", []string{"String:Mr G"}, "", "") assert.NoError(t, err) assert.Equal(t, val.String(), `"Hello Mr G"`) }) t.Run("Test Script JSON args", func(t *testing.T) { - val, err := scripts.Execute("./script.cdc", []string{}, "[{\"type\": \"String\", \"value\": \"Mr G\"}]") + val, err := scripts.Execute("./script.cdc", []string{}, "[{\"type\": \"String\", \"value\": \"Mr G\"}]", "") assert.NoError(t, err) assert.Equal(t, val.String(), `"Hello Mr G"`) @@ -236,7 +236,7 @@ func TestTransactions(t *testing.T) { var txID1 flow.Identifier t.Run("Test Transactions", func(t *testing.T) { - tx, tr, err := transactions.Send("./transaction.cdc", emulatorAccount, []string{"String:Hello"}, "") + tx, tr, err := transactions.Send("./transaction.cdc", emulatorAccount, []string{"String:Hello"}, "", "") txID1 = tx.ID() assert.NoError(t, err) @@ -245,7 +245,7 @@ func TestTransactions(t *testing.T) { }) t.Run("Test Failed Transactions", func(t *testing.T) { - tx, tr, err := transactions.Send("./transactionErr.cdc", emulatorAccount, []string{}, "") + tx, tr, err := transactions.Send("./transactionErr.cdc", emulatorAccount, []string{}, "", "") assert.NoError(t, err) assert.Equal(t, tx.Payer.String(), serviceAddress) From 5f12a30ae7cd0ebf0a5d82419c96859baf13de9e Mon Sep 17 00:00:00 2001 From: Gregor Gololicic Date: Fri, 9 Apr 2021 14:49:12 +0200 Subject: [PATCH 054/137] add version check --- internal/command/command.go | 25 +++++++++++++++++++++++++ 1 file changed, 25 insertions(+) diff --git a/internal/command/command.go b/internal/command/command.go index 2cf4cf64f..807677067 100644 --- a/internal/command/command.go +++ b/internal/command/command.go @@ -22,9 +22,13 @@ import ( "encoding/json" "errors" "fmt" + "io/ioutil" + "net/http" "os" "strings" + "github.com/onflow/flow-cli/build" + "github.com/onflow/flow-go-sdk/client" "github.com/psiemens/sconfig" "github.com/spf13/afero" @@ -166,6 +170,8 @@ func (c Command) AddToParent(parent *cobra.Command) { service := services.NewServices(clientGateway, proj, logger) + checkVersion(logger) + // run command result, err := c.Run(cmd, args, flags, service) handleError("Command Error", err) @@ -340,6 +346,25 @@ func handleError(description string, err error) { os.Exit(1) } +// checkVersion fetches latest version and compares it to local +func checkVersion(logger output.Logger) { + resp, err := http.Get("https://raw.githubusercontent.com/onflow/flow-cli/master/version.txt") + if err != nil || resp.StatusCode >= 400 { + return + } + + defer resp.Body.Close() + latestVersion, _ := ioutil.ReadAll(resp.Body) + + if string(latestVersion) != build.Semver() { + logger.Info(fmt.Sprintf( + "\n⚠️ Version Warning: New version %s of Flow CLI is available.\n"+ + "Follow the Flow CLI installation guide for instructions on how to install or upgrade the CLI: https://docs.onflow.org/flow-cli/install", + strings.ReplaceAll(string(latestVersion), "\n", ""), + )) + } +} + // bindFlags bind all the flags needed func bindFlags(command Command) { err := sconfig.New(command.Flags). From a98d31824c0491b65fd3d9cc06b25e85ef5b54cd Mon Sep 17 00:00:00 2001 From: Greg <75445744+sideninja@users.noreply.github.com> Date: Mon, 12 Apr 2021 11:02:26 +0200 Subject: [PATCH 055/137] Update internal/transactions/sign.go Co-authored-by: Peter Siemens --- internal/transactions/sign.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/internal/transactions/sign.go b/internal/transactions/sign.go index bb5bc1c6e..fd1dc6001 100644 --- a/internal/transactions/sign.go +++ b/internal/transactions/sign.go @@ -25,7 +25,7 @@ var SignCommand = &command.Command{ Cmd: &cobra.Command{ Use: "sign ", Short: "Sign a transaction", - Example: `flow transactions sign`, + Example: "flow transactions sign", Args: cobra.MaximumNArgs(1), }, Flags: &signFlags, From 23530dd10e97f8ad83b1b9bb7759eeea269c53cf Mon Sep 17 00:00:00 2001 From: Greg <75445744+sideninja@users.noreply.github.com> Date: Mon, 12 Apr 2021 11:02:33 +0200 Subject: [PATCH 056/137] Update internal/transactions/transactions.go Co-authored-by: Peter Siemens --- internal/transactions/transactions.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/internal/transactions/transactions.go b/internal/transactions/transactions.go index f011b327d..de978dcf8 100644 --- a/internal/transactions/transactions.go +++ b/internal/transactions/transactions.go @@ -82,7 +82,7 @@ func (r *TransactionResult) String() string { fmt.Fprintf(writer, "Status\t%s %s\n", statusBadge, r.result.Status) } - fmt.Fprintf(writer, "Hash\t%s\n", r.tx.ID()) + fmt.Fprintf(writer, "ID\t%s\n", r.tx.ID()) fmt.Fprintf(writer, "Payer\t%s\n", r.tx.Payer.Hex()) fmt.Fprintf(writer, "Authorizers\t%s\n", r.tx.Authorizers) From 285d47f5be8d59aaf83c8a80754567a005413626 Mon Sep 17 00:00:00 2001 From: Greg <75445744+sideninja@users.noreply.github.com> Date: Mon, 12 Apr 2021 11:02:40 +0200 Subject: [PATCH 057/137] Update pkg/flowcli/output/prompt.go Co-authored-by: Peter Siemens --- pkg/flowcli/output/prompt.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pkg/flowcli/output/prompt.go b/pkg/flowcli/output/prompt.go index 7959eed6c..34089ff89 100644 --- a/pkg/flowcli/output/prompt.go +++ b/pkg/flowcli/output/prompt.go @@ -14,7 +14,7 @@ func ApproveTransactionPrompt(transaction *project.Transaction) bool { tx := transaction.FlowTransaction() fmt.Fprintf(writer, "\n") - fmt.Fprintf(writer, "Hash\t%s\n", tx.ID()) + fmt.Fprintf(writer, "ID\t%s\n", tx.ID()) fmt.Fprintf(writer, "Payer\t%s\n", tx.Payer.Hex()) fmt.Fprintf(writer, "Authorizers\t%s\n", tx.Authorizers) From 878a563c9ac2af20896462b301120740443093cc Mon Sep 17 00:00:00 2001 From: Greg <75445744+sideninja@users.noreply.github.com> Date: Mon, 12 Apr 2021 11:04:44 +0200 Subject: [PATCH 058/137] Update pkg/flowcli/services/transactions.go Co-authored-by: Peter Siemens --- pkg/flowcli/services/transactions.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pkg/flowcli/services/transactions.go b/pkg/flowcli/services/transactions.go index 4121d1d79..6cddd2bcd 100644 --- a/pkg/flowcli/services/transactions.go +++ b/pkg/flowcli/services/transactions.go @@ -249,7 +249,7 @@ func (t *Transactions) SendForAddressWithCode( return nil, nil, err } - t.logger.StartProgress("Sending Transaction...") + t.logger.StartProgress("Sending transaction...") sentTx, err := t.gateway.SendSignedTransaction(tx) if err != nil { From ad1bf2242546437990f850502ae8fb9893c2386c Mon Sep 17 00:00:00 2001 From: Gregor Gololicic Date: Mon, 12 Apr 2021 11:43:40 +0200 Subject: [PATCH 059/137] merge fixes --- go.mod | 1 + go.sum | 2 ++ internal/command/command.go | 24 ++++++++++++------------ internal/transactions/get.go | 2 ++ internal/transactions/send.go | 1 + pkg/flowcli/services/accounts.go | 1 - pkg/flowcli/services/project.go | 4 ++-- pkg/flowcli/services/transactions.go | 3 --- 8 files changed, 20 insertions(+), 18 deletions(-) diff --git a/go.mod b/go.mod index c59d773ec..b1ce19c7f 100644 --- a/go.mod +++ b/go.mod @@ -7,6 +7,7 @@ require ( github.com/fatih/color v1.7.0 github.com/gosuri/uilive v0.0.4 github.com/magiconair/properties v1.8.1 // indirect + github.com/manifoldco/promptui v0.8.0 github.com/onflow/cadence v0.14.4 github.com/onflow/cadence/languageserver v0.14.4 github.com/onflow/flow-core-contracts/lib/go/templates v0.6.0 diff --git a/go.sum b/go.sum index e5acaa78e..7ec8efcb2 100644 --- a/go.sum +++ b/go.sum @@ -125,9 +125,11 @@ github.com/cespare/xxhash/v2 v2.1.1 h1:6MnRN8NT7+YBpUIWxHtefFZOKTAPgGjpQSxqLNn0+ github.com/cespare/xxhash/v2 v2.1.1/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= github.com/cheekybits/genny v1.0.0 h1:uGGa4nei+j20rOSeDeP5Of12XVm7TGUd4dJA9RDitfE= github.com/cheekybits/genny v1.0.0/go.mod h1:+tQajlRqAUrPI7DOSpB0XAqZYtQakVtB7wXkRAgjxjQ= +github.com/chzyer/logex v1.1.10 h1:Swpa1K6QvQznwJRcfTfQJmTE72DqScAa40E+fbHEXEE= github.com/chzyer/logex v1.1.10/go.mod h1:+Ywpsq7O8HXn0nuIou7OrIPyXbp3wmkHB+jjWRnGsAI= github.com/chzyer/readline v0.0.0-20180603132655-2972be24d48e h1:fY5BOSpyZCqRo5OhCuC+XN+r/bBCmeuuJtjz+bCNIf8= github.com/chzyer/readline v0.0.0-20180603132655-2972be24d48e/go.mod h1:nSuG5e5PlCu98SY8svDHJxuZscDgtXS6KTTbou5AhLI= +github.com/chzyer/test v0.0.0-20180213035817-a1ea475d72b1 h1:q763qf9huN11kDQavWsoZXJNW3xEE4JJyHa5Q25/sd8= github.com/chzyer/test v0.0.0-20180213035817-a1ea475d72b1/go.mod h1:Q3SI9o4m/ZMnBNeIyt5eFwwo7qiLfzFZmjNmxjkiQlU= github.com/clbanning/x2j v0.0.0-20191024224557-825249438eec/go.mod h1:jMjuTZXRI4dUb/I5gc9Hdhagfvm9+RyrPryS/auMzxE= github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw= diff --git a/internal/command/command.go b/internal/command/command.go index 7cabea185..affeb475f 100644 --- a/internal/command/command.go +++ b/internal/command/command.go @@ -55,13 +55,13 @@ type Command struct { } type GlobalFlags struct { - Filter string - Format string - Save string - Host string - Log string - Network string - Yes bool + Filter string + Format string + Save string + Host string + Log string + Network string + Yes bool ConfigPath []string } @@ -79,13 +79,13 @@ const ( ) var flags = GlobalFlags{ - Filter: "", + Filter: "", Format: formatText, - Save: "", - Host: "", + Save: "", + Host: "", Log: logLevelInfo, - Network: "", - Yes: false, + Network: "", + Yes: false, ConfigPath: project.DefaultConfigPaths, } diff --git a/internal/transactions/get.go b/internal/transactions/get.go index 2a6179c5a..8f74c9faf 100644 --- a/internal/transactions/get.go +++ b/internal/transactions/get.go @@ -19,6 +19,8 @@ package transactions import ( + "fmt" + "github.com/onflow/flow-cli/internal/command" "github.com/onflow/flow-cli/pkg/flowcli/services" "github.com/spf13/cobra" diff --git a/internal/transactions/send.go b/internal/transactions/send.go index 122cc2fcc..232384dc1 100644 --- a/internal/transactions/send.go +++ b/internal/transactions/send.go @@ -76,6 +76,7 @@ var SendCommand = &command.Command{ tx, result, err := services.Transactions.Send( filename, + sendFlags.Payload, sendFlags.Signer, sendFlags.Arg, sendFlags.ArgsJSON, diff --git a/pkg/flowcli/services/accounts.go b/pkg/flowcli/services/accounts.go index b8484b068..b1b4e627f 100644 --- a/pkg/flowcli/services/accounts.go +++ b/pkg/flowcli/services/accounts.go @@ -35,7 +35,6 @@ import ( tmpl "github.com/onflow/flow-core-contracts/lib/go/templates" "github.com/onflow/flow-go-sdk" "github.com/onflow/flow-go-sdk/crypto" - "github.com/onflow/flow-go-sdk/templates" ) // Accounts is a service that handles all account-related interactions. diff --git a/pkg/flowcli/services/project.go b/pkg/flowcli/services/project.go index a31acf9d4..31b45502a 100644 --- a/pkg/flowcli/services/project.go +++ b/pkg/flowcli/services/project.go @@ -150,7 +150,7 @@ func (p *Project) Deploy(network string, update bool) ([]*contracts.Contract, er tx, err := project.NewAddAccountContractTransaction(targetAccount, contract.Name(), contract.TranspiledCode()) if err != nil { - errs = append(errs, err) + return nil, err } _, exists := targetAccountInfo.Contracts[contract.Name()] @@ -167,7 +167,7 @@ func (p *Project) Deploy(network string, update bool) ([]*contracts.Contract, er tx, err = project.NewUpdateAccountContractTransaction(targetAccount, contract.Name(), contract.TranspiledCode()) if err != nil { - errs = append(errs, err) + return nil, err } } diff --git a/pkg/flowcli/services/transactions.go b/pkg/flowcli/services/transactions.go index 0604d3512..65f7e67dd 100644 --- a/pkg/flowcli/services/transactions.go +++ b/pkg/flowcli/services/transactions.go @@ -22,13 +22,10 @@ import ( "fmt" "strings" - "github.com/onflow/flow-cli/pkg/flowcli" "github.com/onflow/flow-cli/pkg/flowcli/output" "github.com/onflow/flow-cli/pkg/flowcli/project" - "github.com/onflow/flow-cli/pkg/flowcli/config" "github.com/onflow/flow-cli/pkg/flowcli/gateway" - "github.com/onflow/flow-cli/pkg/flowcli/util" "github.com/onflow/flow-go-sdk" "github.com/onflow/flow-go-sdk/crypto" ) From 3824ec12e8c4e5f96d52df5e7d41e0047379ba11 Mon Sep 17 00:00:00 2001 From: Gregor Gololicic Date: Mon, 12 Apr 2021 13:26:35 +0200 Subject: [PATCH 060/137] filter to lower --- internal/command/command.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/internal/command/command.go b/internal/command/command.go index affeb475f..cb71436b8 100644 --- a/internal/command/command.go +++ b/internal/command/command.go @@ -282,7 +282,7 @@ func outputResult(result string, saveFlag string, formatFlag string, filterFlag return af.WriteFile(saveFlag, []byte(result), 0644) } - if formatFlag == "inline" || filterFlag != "" { + if formatFlag == formatInline || filterFlag != "" { fmt.Fprintf(os.Stdout, "%s", result) } else { // default normal output fmt.Fprintf(os.Stdout, "\n%s\n\n", result) @@ -304,7 +304,7 @@ func filterResultValue(result Result, filter string) (interface{}, error) { possibleFilters = append(possibleFilters, key) } - value := jsonResult[filter] + value := jsonResult[strings.ToLower(filter)] if value == nil { return nil, fmt.Errorf("value for filter: '%s' doesn't exists, possible values to filter by: %s", filter, possibleFilters) From c7b69726506e52affd3244ee76209fa4626ae3e0 Mon Sep 17 00:00:00 2001 From: Gregor Gololicic Date: Mon, 12 Apr 2021 15:13:29 +0200 Subject: [PATCH 061/137] if proposer specified use it --- pkg/flowcli/gateway/grpc.go | 12 ++++++++---- pkg/flowcli/project/transaction.go | 4 ++++ 2 files changed, 12 insertions(+), 4 deletions(-) diff --git a/pkg/flowcli/gateway/grpc.go b/pkg/flowcli/gateway/grpc.go index ef7973f17..98d6ecdd7 100644 --- a/pkg/flowcli/gateway/grpc.go +++ b/pkg/flowcli/gateway/grpc.go @@ -67,13 +67,17 @@ func (g *GrpcGateway) GetAccount(address flow.Address) (*flow.Account, error) { // PrepareTransactionPayload prepares the payload for the transaction from the network func (g *GrpcGateway) PrepareTransactionPayload(tx *project.Transaction) (*project.Transaction, error) { - signerAddress := tx.Signer().Address() - account, err := g.GetAccount(signerAddress) + proposalAddress := tx.Signer().Address() + if tx.Proposer() != nil { // default proposer is signer + proposalAddress = tx.Proposer().Address() + } + + proposer, err := g.GetAccount(proposalAddress) if err != nil { return nil, err } - accountKey := account.Keys[tx.Signer().DefaultKey().Index()] + proposerKey := proposer.Keys[tx.Signer().DefaultKey().Index()] sealed, err := g.client.GetLatestBlockHeader(g.ctx, true) if err != nil { @@ -83,7 +87,7 @@ func (g *GrpcGateway) PrepareTransactionPayload(tx *project.Transaction) (*proje tx.FlowTransaction(). SetReferenceBlockID(sealed.ID). SetGasLimit(defaultGasLimit). - SetProposalKey(signerAddress, accountKey.Index, accountKey.SequenceNumber) + SetProposalKey(proposalAddress, proposerKey.Index, proposerKey.SequenceNumber) return tx, nil } diff --git a/pkg/flowcli/project/transaction.go b/pkg/flowcli/project/transaction.go index cfda86626..aac7802e0 100644 --- a/pkg/flowcli/project/transaction.go +++ b/pkg/flowcli/project/transaction.go @@ -162,6 +162,10 @@ func (t *Transaction) Signer() *Account { return t.signer } +func (t *Transaction) Proposer() *Account { + return t.proposer +} + func (t *Transaction) FlowTransaction() *flow.Transaction { return t.tx } From 3055dcb42f2801cb333eb90bdfbfb703b4027f90 Mon Sep 17 00:00:00 2001 From: Gregor Gololicic Date: Mon, 12 Apr 2021 15:13:39 +0200 Subject: [PATCH 062/137] payload flag --- internal/transactions/send.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/internal/transactions/send.go b/internal/transactions/send.go index 232384dc1..d090e7ac6 100644 --- a/internal/transactions/send.go +++ b/internal/transactions/send.go @@ -70,8 +70,8 @@ var SendCommand = &command.Command{ } else if sendFlags.Code != "" { fmt.Println("⚠️ DEPRECATION WARNING: use filename as a command argument ") filename = sendFlags.Code - } else { - return nil, fmt.Errorf("provide a valide filename command argument") + } else if sendFlags.Payload == "" { + return nil, fmt.Errorf("provide a valid filename command argument") } tx, result, err := services.Transactions.Send( From 423f6f3dc8120ca55f6bda777127cec355880031 Mon Sep 17 00:00:00 2001 From: Gregor Gololicic Date: Mon, 12 Apr 2021 15:13:45 +0200 Subject: [PATCH 063/137] add test tx --- tests/transaction3Auths.cdc | 11 +++++++++++ 1 file changed, 11 insertions(+) create mode 100644 tests/transaction3Auths.cdc diff --git a/tests/transaction3Auths.cdc b/tests/transaction3Auths.cdc new file mode 100644 index 000000000..e7042162e --- /dev/null +++ b/tests/transaction3Auths.cdc @@ -0,0 +1,11 @@ +transaction(greeting: String) { + let guest: Address + + prepare(authorizer1: AuthAccount, authorizer2: AuthAccount, authorizer3: AuthAccount) { + self.guest = authorizer1.address + } + + execute { + log(greeting.concat(",").concat(self.guest.toString())) + } +} \ No newline at end of file From a5c92c281ea567fc2c5ca19273ef4288e328de49 Mon Sep 17 00:00:00 2001 From: Gregor Gololicic Date: Mon, 12 Apr 2021 15:19:24 +0200 Subject: [PATCH 064/137] more strict checks --- internal/transactions/sign.go | 9 --------- pkg/flowcli/services/transactions.go | 10 ++++++++++ 2 files changed, 10 insertions(+), 9 deletions(-) diff --git a/internal/transactions/sign.go b/internal/transactions/sign.go index fd1dc6001..0026eefa9 100644 --- a/internal/transactions/sign.go +++ b/internal/transactions/sign.go @@ -1,8 +1,6 @@ package transactions import ( - "fmt" - "github.com/onflow/flow-cli/internal/command" "github.com/onflow/flow-cli/pkg/flowcli/services" "github.com/spf13/cobra" @@ -35,13 +33,6 @@ var SignCommand = &command.Command{ globalFlags command.GlobalFlags, services *services.Services, ) (command.Result, error) { - if sendFlags.Code != "" { - return nil, fmt.Errorf("⚠️ DEPRECATED: use filename argument") - } - - if sendFlags.Results { - return nil, fmt.Errorf("⚠️ DEPRECATED: all transactions will provide results") - } codeFilename := "" if len(args) > 0 { diff --git a/pkg/flowcli/services/transactions.go b/pkg/flowcli/services/transactions.go index 65f7e67dd..991136a9e 100644 --- a/pkg/flowcli/services/transactions.go +++ b/pkg/flowcli/services/transactions.go @@ -108,6 +108,16 @@ func (t *Transactions) Sign( // if we received already created transaction payload, create from payload and return signed if payloadFilename != "" { + if payerAddress != "" { + return nil, fmt.Errorf("setting a payer is not permissible when using transaction payload") + } else if proposerName != "" { + return nil, fmt.Errorf("setting a proposer is not possible when using transaction payload") + } else if len(args) > 0 || argsJSON != "" { + return nil, fmt.Errorf("setting arguments is not possible when using transaction payload") + } else if len(additionalAuthorizers) > 0 { + return nil, fmt.Errorf("setting additional authorizers is not possible when using transaction payload") + } + tx, err := project.NewTransactionFromPayload(signerAccount, payloadFilename, role) if err != nil { return nil, err From 612d76103dafaced55231a988c154730dfac3f35 Mon Sep 17 00:00:00 2001 From: Gregor Gololicic Date: Mon, 12 Apr 2021 15:31:53 +0200 Subject: [PATCH 065/137] lints and tests fixes --- internal/command/command.go | 13 +++++-------- internal/transactions/get.go | 3 ++- internal/transactions/send.go | 3 ++- internal/transactions/sign.go | 3 ++- pkg/flowcli/gateway/grpc.go | 3 ++- pkg/flowcli/services/accounts.go | 10 ++++++---- pkg/flowcli/services/project.go | 3 ++- pkg/flowcli/services/transactions.go | 8 ++++---- pkg/flowcli/services/transactions_test.go | 7 +++---- 9 files changed, 28 insertions(+), 25 deletions(-) diff --git a/internal/command/command.go b/internal/command/command.go index cb71436b8..c9c144bad 100644 --- a/internal/command/command.go +++ b/internal/command/command.go @@ -25,18 +25,15 @@ import ( "os" "strings" - "github.com/onflow/flow-cli/pkg/flowcli/util" - - "github.com/onflow/flow-cli/pkg/flowcli/output" - "github.com/onflow/flow-cli/pkg/flowcli/project" - "github.com/onflow/flow-cli/pkg/flowcli/config" - - "github.com/psiemens/sconfig" - "github.com/onflow/flow-cli/pkg/flowcli/gateway" + "github.com/onflow/flow-cli/pkg/flowcli/output" + "github.com/onflow/flow-cli/pkg/flowcli/project" "github.com/onflow/flow-cli/pkg/flowcli/services" + "github.com/onflow/flow-cli/pkg/flowcli/util" + "github.com/onflow/flow-go-sdk/client" + "github.com/psiemens/sconfig" "github.com/spf13/afero" "github.com/spf13/cobra" ) diff --git a/internal/transactions/get.go b/internal/transactions/get.go index 8f74c9faf..4563651e3 100644 --- a/internal/transactions/get.go +++ b/internal/transactions/get.go @@ -21,9 +21,10 @@ package transactions import ( "fmt" + "github.com/spf13/cobra" + "github.com/onflow/flow-cli/internal/command" "github.com/onflow/flow-cli/pkg/flowcli/services" - "github.com/spf13/cobra" ) type flagsGet struct { diff --git a/internal/transactions/send.go b/internal/transactions/send.go index d090e7ac6..ba529ce8b 100644 --- a/internal/transactions/send.go +++ b/internal/transactions/send.go @@ -21,9 +21,10 @@ package transactions import ( "fmt" + "github.com/spf13/cobra" + "github.com/onflow/flow-cli/internal/command" "github.com/onflow/flow-cli/pkg/flowcli/services" - "github.com/spf13/cobra" ) type flagsSend struct { diff --git a/internal/transactions/sign.go b/internal/transactions/sign.go index 0026eefa9..9f926ee98 100644 --- a/internal/transactions/sign.go +++ b/internal/transactions/sign.go @@ -1,9 +1,10 @@ package transactions import ( + "github.com/spf13/cobra" + "github.com/onflow/flow-cli/internal/command" "github.com/onflow/flow-cli/pkg/flowcli/services" - "github.com/spf13/cobra" ) type flagsSign struct { diff --git a/pkg/flowcli/gateway/grpc.go b/pkg/flowcli/gateway/grpc.go index 98d6ecdd7..13b79fc2a 100644 --- a/pkg/flowcli/gateway/grpc.go +++ b/pkg/flowcli/gateway/grpc.go @@ -24,10 +24,11 @@ import ( "time" "github.com/onflow/cadence" - "github.com/onflow/flow-cli/pkg/flowcli/project" "github.com/onflow/flow-go-sdk" "github.com/onflow/flow-go-sdk/client" "google.golang.org/grpc" + + "github.com/onflow/flow-cli/pkg/flowcli/project" ) const ( diff --git a/pkg/flowcli/services/accounts.go b/pkg/flowcli/services/accounts.go index b1b4e627f..da76b852a 100644 --- a/pkg/flowcli/services/accounts.go +++ b/pkg/flowcli/services/accounts.go @@ -24,14 +24,13 @@ import ( "strings" "github.com/onflow/flow-cli/pkg/flowcli" + "github.com/onflow/flow-cli/pkg/flowcli/config" + "github.com/onflow/flow-cli/pkg/flowcli/gateway" "github.com/onflow/flow-cli/pkg/flowcli/output" "github.com/onflow/flow-cli/pkg/flowcli/project" + "github.com/onflow/flow-cli/pkg/flowcli/util" "github.com/onflow/cadence" - - "github.com/onflow/flow-cli/pkg/flowcli/config" - "github.com/onflow/flow-cli/pkg/flowcli/gateway" - "github.com/onflow/flow-cli/pkg/flowcli/util" tmpl "github.com/onflow/flow-core-contracts/lib/go/templates" "github.com/onflow/flow-go-sdk" "github.com/onflow/flow-go-sdk/crypto" @@ -251,6 +250,9 @@ func (a *Accounts) Create( } tx, err := project.NewCreateAccountTransaction(signer, accountKeys, contracts) + if err != nil { + return nil, err + } sentTx, err := a.gateway.SendTransaction(tx) if err != nil { diff --git a/pkg/flowcli/services/project.go b/pkg/flowcli/services/project.go index 31b45502a..07fd2ffe2 100644 --- a/pkg/flowcli/services/project.go +++ b/pkg/flowcli/services/project.go @@ -22,12 +22,13 @@ import ( "fmt" "strings" + "github.com/onflow/flow-go-sdk/crypto" + "github.com/onflow/flow-cli/pkg/flowcli/contracts" "github.com/onflow/flow-cli/pkg/flowcli/gateway" "github.com/onflow/flow-cli/pkg/flowcli/output" "github.com/onflow/flow-cli/pkg/flowcli/project" "github.com/onflow/flow-cli/pkg/flowcli/util" - "github.com/onflow/flow-go-sdk/crypto" ) // Project is a service that handles all interactions for a project. diff --git a/pkg/flowcli/services/transactions.go b/pkg/flowcli/services/transactions.go index 991136a9e..a5f892b62 100644 --- a/pkg/flowcli/services/transactions.go +++ b/pkg/flowcli/services/transactions.go @@ -22,12 +22,12 @@ import ( "fmt" "strings" - "github.com/onflow/flow-cli/pkg/flowcli/output" - "github.com/onflow/flow-cli/pkg/flowcli/project" - - "github.com/onflow/flow-cli/pkg/flowcli/gateway" "github.com/onflow/flow-go-sdk" "github.com/onflow/flow-go-sdk/crypto" + + "github.com/onflow/flow-cli/pkg/flowcli/gateway" + "github.com/onflow/flow-cli/pkg/flowcli/output" + "github.com/onflow/flow-cli/pkg/flowcli/project" ) // Transactions is a service that handles all transaction-related interactions. diff --git a/pkg/flowcli/services/transactions_test.go b/pkg/flowcli/services/transactions_test.go index f081526dd..d35487e48 100644 --- a/pkg/flowcli/services/transactions_test.go +++ b/pkg/flowcli/services/transactions_test.go @@ -21,14 +21,13 @@ package services import ( "testing" - "github.com/onflow/flow-cli/pkg/flowcli/output" - "github.com/onflow/flow-cli/pkg/flowcli/project" - "github.com/onflow/flow-go-sdk" + "github.com/onflow/flow-go-sdk/crypto" "github.com/stretchr/testify/assert" + "github.com/onflow/flow-cli/pkg/flowcli/output" + "github.com/onflow/flow-cli/pkg/flowcli/project" "github.com/onflow/flow-cli/tests" - "github.com/onflow/flow-go-sdk/crypto" ) func TestTransactions(t *testing.T) { From fba01be79ecac0742c4965f35b9702baf2495529 Mon Sep 17 00:00:00 2001 From: Gregor Gololicic Date: Mon, 12 Apr 2021 15:40:47 +0200 Subject: [PATCH 066/137] headers --- internal/transactions/sign.go | 18 ++++++++++++++++++ pkg/flowcli/output/prompt.go | 18 ++++++++++++++++++ pkg/flowcli/project/transaction.go | 18 ++++++++++++++++++ 3 files changed, 54 insertions(+) diff --git a/internal/transactions/sign.go b/internal/transactions/sign.go index 9f926ee98..351384fe4 100644 --- a/internal/transactions/sign.go +++ b/internal/transactions/sign.go @@ -1,3 +1,21 @@ +/* + * Flow CLI + * + * Copyright 2019-2021 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 transactions import ( diff --git a/pkg/flowcli/output/prompt.go b/pkg/flowcli/output/prompt.go index 34089ff89..efe94623e 100644 --- a/pkg/flowcli/output/prompt.go +++ b/pkg/flowcli/output/prompt.go @@ -1,3 +1,21 @@ +/* + * Flow CLI + * + * Copyright 2019-2021 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 output import ( diff --git a/pkg/flowcli/project/transaction.go b/pkg/flowcli/project/transaction.go index aac7802e0..2cec2b4ea 100644 --- a/pkg/flowcli/project/transaction.go +++ b/pkg/flowcli/project/transaction.go @@ -1,3 +1,21 @@ +/* + * Flow CLI + * + * Copyright 2019-2021 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 project import ( From 5f52f5047c1c334e68a02775a86ee3060ea06931 Mon Sep 17 00:00:00 2001 From: Greg <75445744+sideninja@users.noreply.github.com> Date: Tue, 13 Apr 2021 10:27:50 +0200 Subject: [PATCH 067/137] Update internal/command/command.go Co-authored-by: Peter Siemens --- internal/command/command.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/internal/command/command.go b/internal/command/command.go index 426bb856e..bce85d615 100644 --- a/internal/command/command.go +++ b/internal/command/command.go @@ -206,7 +206,7 @@ func resolveHost(proj *project.Project, hostFlag string, networkFlag string) (st if networkFlag != "" && proj != nil { check := proj.NetworkByName(networkFlag) if check == nil { - return "", fmt.Errorf("provided network with name %s doesn't exists in condiguration", networkFlag) + return "", fmt.Errorf("network with name %s does not exist in configuration", networkFlag) } return proj.NetworkByName(networkFlag).Host, nil From 9e84ee9505a123e252f9cc57973b8d10908a565f Mon Sep 17 00:00:00 2001 From: Gregor Gololicic Date: Tue, 13 Apr 2021 10:42:47 +0200 Subject: [PATCH 068/137] implemented all pr feedback --- pkg/flowcli/arguments.go | 14 ++-- pkg/flowcli/contracts/resolver.go | 16 ++--- pkg/flowcli/contracts/resolver_test.go | 8 +-- pkg/flowcli/services/scripts.go | 8 ++- pkg/flowcli/services/transactions.go | 5 +- tests/release/checklist_test.go | 88 ++++++++++++++++++++++++++ 6 files changed, 118 insertions(+), 21 deletions(-) create mode 100644 tests/release/checklist_test.go diff --git a/pkg/flowcli/arguments.go b/pkg/flowcli/arguments.go index e52d46cbe..ced0d14f8 100644 --- a/pkg/flowcli/arguments.go +++ b/pkg/flowcli/arguments.go @@ -75,10 +75,7 @@ func ParseArgumentsCommaSplit(input []string) ([]cadence.Value, error) { ) } - // if we are passing address check and handle without 0x prefix as else it wont work and error is not descriptive - if argInput[0] == "Address" && !strings.Contains(argInput[1], "0x") { - argInput[1] = fmt.Sprintf("0x%s", argInput[1]) - } + argInput = sanitizeAddressArg(argInput) args = append(args, map[string]string{ "value": argInput[1], @@ -91,6 +88,15 @@ func ParseArgumentsCommaSplit(input []string) ([]cadence.Value, error) { return cadenceArgs, err } +// sanitizeAddressArg sanitize address and make sure it has 0x prefix +func sanitizeAddressArg(argInput []string) []string { + if argInput[0] == "Address" && !strings.Contains(argInput[1], "0x") { + argInput[1] = fmt.Sprintf("0x%s", argInput[1]) + } + + return argInput +} + func ParseArguments(args []string, argsJSON string) (scriptArgs []cadence.Value, err error) { if argsJSON != "" { scriptArgs, err = ParseArgumentsJSON(argsJSON) diff --git a/pkg/flowcli/contracts/resolver.go b/pkg/flowcli/contracts/resolver.go index b30a5c3bf..43071b290 100644 --- a/pkg/flowcli/contracts/resolver.go +++ b/pkg/flowcli/contracts/resolver.go @@ -42,7 +42,7 @@ func (r *Resolver) ResolveImports( contracts []project.Contract, aliases project.Aliases, ) ([]byte, error) { - imports := r.parseImports() + imports := r.getFileImports() sourceTarget := r.getSourceTarget(contracts, aliases) for _, imp := range imports { @@ -84,18 +84,18 @@ func (r *Resolver) getSourceTarget( return sourceTarget } -// ImportExists checks if there is an import statement present in Cadence code -func (r *Resolver) ImportExists() bool { - return len(r.parseImports()) > 0 +// HasFileImports checks if there is a file import statement present in Cadence code +func (r *Resolver) HasFileImports() bool { + return len(r.getFileImports()) > 0 } -// parseImports returns all imports from Cadence code as an array -func (r *Resolver) parseImports() []string { +// getFileImports returns all cadence file imports from Cadence code as an array +func (r *Resolver) getFileImports() []string { imports := make([]string, 0) for _, importDeclaration := range r.program.ImportDeclarations() { - location, ok := importDeclaration.Location.(common.StringLocation) - if ok && flow.HexToAddress(location.String()) == flow.EmptyAddress { + location, ok := importDeclaration.Location.(common.AddressLocation) + if !ok { imports = append(imports, location.String()) } } diff --git a/pkg/flowcli/contracts/resolver_test.go b/pkg/flowcli/contracts/resolver_test.go index d144a778e..369365679 100644 --- a/pkg/flowcli/contracts/resolver_test.go +++ b/pkg/flowcli/contracts/resolver_test.go @@ -75,7 +75,7 @@ func TestResolver(t *testing.T) { pub fun main() {} `)) assert.NoError(t, err) - assert.True(t, resolver.ImportExists()) + assert.True(t, resolver.HasFileImports()) }) t.Run("Import doesn't exists", func(t *testing.T) { @@ -83,20 +83,20 @@ func TestResolver(t *testing.T) { pub fun main() {} `)) assert.NoError(t, err) - assert.False(t, resolver.ImportExists()) + assert.False(t, resolver.HasFileImports()) resolver, err = NewResolver([]byte(` import Foo from 0xf8d6e0586b0a20c7 pub fun main() {} `)) assert.NoError(t, err) - assert.False(t, resolver.ImportExists()) + assert.False(t, resolver.HasFileImports()) }) t.Run("Parse imports", func(t *testing.T) { resolver, err := NewResolver(scripts[0]) assert.NoError(t, err) - assert.Equal(t, resolver.parseImports(), []string{ + assert.Equal(t, resolver.getFileImports(), []string{ "./Kibble.cdc", "./FT.cdc", }) }) diff --git a/pkg/flowcli/services/scripts.go b/pkg/flowcli/services/scripts.go index e6e7410b6..96f1a16e7 100644 --- a/pkg/flowcli/services/scripts.go +++ b/pkg/flowcli/services/scripts.go @@ -77,12 +77,14 @@ func (s *Scripts) execute(code []byte, args []string, argsJSON string, scriptPat return nil, err } - if resolver.ImportExists() { + if resolver.HasFileImports() { if s.project == nil { return nil, fmt.Errorf("missing configuration, initialize it: flow init") - } else if network == "" { + } + if network == "" { return nil, fmt.Errorf("missing network, specify which network to use to resolve imports in script code") - } else if scriptPath == "" { // when used as lib with code we don't support imports + } + if scriptPath == "" { // when used as lib with code we don't support imports return nil, fmt.Errorf("resolving imports in scripts not supported") } diff --git a/pkg/flowcli/services/transactions.go b/pkg/flowcli/services/transactions.go index 6afb51f92..69585d88d 100644 --- a/pkg/flowcli/services/transactions.go +++ b/pkg/flowcli/services/transactions.go @@ -142,10 +142,11 @@ func (t *Transactions) send( return nil, nil, err } - if resolver.ImportExists() { + if resolver.HasFileImports() { if network == "" { return nil, nil, fmt.Errorf("missing network, specify which network to use to resolve imports in transaction code") - } else if codePath == "" { // when used as lib with code we don't support imports + } + if codePath == "" { // when used as lib with code we don't support imports return nil, nil, fmt.Errorf("resolving imports in transactions not supported") } diff --git a/tests/release/checklist_test.go b/tests/release/checklist_test.go new file mode 100644 index 000000000..a2f58ae47 --- /dev/null +++ b/tests/release/checklist_test.go @@ -0,0 +1,88 @@ +/* + * Flow CLI + * + * Copyright 2019-2021 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 release + +import ( + "bytes" + "fmt" + "io/ioutil" + "testing" + + "github.com/onflow/flow-cli/internal/accounts" + "github.com/onflow/flow-cli/internal/cadence" + "github.com/onflow/flow-cli/internal/collections" + "github.com/onflow/flow-cli/internal/command" + "github.com/onflow/flow-cli/internal/config" + "github.com/onflow/flow-cli/internal/emulator" + "github.com/onflow/flow-cli/internal/events" + "github.com/onflow/flow-cli/internal/keys" + "github.com/onflow/flow-cli/internal/project" + "github.com/onflow/flow-cli/internal/scripts" + "github.com/onflow/flow-cli/internal/transactions" + "github.com/onflow/flow-cli/internal/version" + "github.com/spf13/cobra" + + "github.com/onflow/flow-cli/internal/blocks" +) + +func TestChecklist(t *testing.T) { + + var cmd = &cobra.Command{ + Use: "flow", + TraverseChildren: true, + } + + // hot commands + config.InitCommand.AddToParent(cmd) + + // structured commands + cmd.AddCommand(cadence.Cmd) + cmd.AddCommand(version.Cmd) + cmd.AddCommand(emulator.Cmd) + cmd.AddCommand(accounts.Cmd) + cmd.AddCommand(scripts.Cmd) + cmd.AddCommand(transactions.Cmd) + cmd.AddCommand(keys.Cmd) + cmd.AddCommand(events.Cmd) + cmd.AddCommand(blocks.Cmd) + cmd.AddCommand(collections.Cmd) + cmd.AddCommand(project.Cmd) + + command.InitFlags(cmd) + + for _, c := range cmd.Commands() { + fmt.Println(c.Name()) + } + +} + +func checkCommand(c cobra.Command) { + b := bytes.NewBufferString("") + + c.SetArgs([]string{"get", "1"}) + c.SetOut(b) + c.SetErr(b) + + //err := c.Execute() + //assert.NoError(t, err) + + out, _ := ioutil.ReadAll(b) + + fmt.Println(string(out)) +} From 7e1f22a59d0f39a1513a2756b30366f9a1a115d2 Mon Sep 17 00:00:00 2001 From: Gregor Gololicic Date: Tue, 13 Apr 2021 10:59:24 +0200 Subject: [PATCH 069/137] merging fixes --- pkg/flowcli/project/transaction.go | 9 ------ pkg/flowcli/services/transactions.go | 48 +++++++++++++++++++++++----- 2 files changed, 40 insertions(+), 17 deletions(-) diff --git a/pkg/flowcli/project/transaction.go b/pkg/flowcli/project/transaction.go index 2cec2b4ea..ba6f83736 100644 --- a/pkg/flowcli/project/transaction.go +++ b/pkg/flowcli/project/transaction.go @@ -188,15 +188,6 @@ func (t *Transaction) FlowTransaction() *flow.Transaction { return t.tx } -func (t *Transaction) SetScriptWithArgsFromFile(filepath string, args []string, argsJSON string) error { - script, err := util.LoadFile(filepath) - if err != nil { - return err - } - - return t.SetScriptWithArgs(script, args, argsJSON) -} - func (t *Transaction) SetScriptWithArgs(script []byte, args []string, argsJSON string) error { t.tx.SetScript(script) return t.AddRawArguments(args, argsJSON) diff --git a/pkg/flowcli/services/transactions.go b/pkg/flowcli/services/transactions.go index e2cac0d7a..ffef51f12 100644 --- a/pkg/flowcli/services/transactions.go +++ b/pkg/flowcli/services/transactions.go @@ -23,6 +23,7 @@ import ( "strings" "github.com/onflow/flow-cli/pkg/flowcli/contracts" + "github.com/onflow/flow-cli/pkg/flowcli/util" "github.com/onflow/flow-go-sdk" "github.com/onflow/flow-go-sdk/crypto" @@ -86,11 +87,12 @@ func (t *Transactions) Sign( payerAddress string, additionalAuthorizers []string, role string, - scriptFilename string, + codeFilename string, payloadFilename string, args []string, argsJSON string, approveSigning bool, + network string, ) (*project.Transaction, error) { if t.project == nil { return nil, fmt.Errorf("missing configuration, initialize it: flow project init") @@ -102,10 +104,10 @@ func (t *Transactions) Sign( return nil, fmt.Errorf("signer account: [%s] doesn't exists in configuration", signerName) } - if payloadFilename != "" && scriptFilename != "" { + if payloadFilename != "" && codeFilename != "" { return nil, fmt.Errorf("can not use both a transaction payload and Cadence code file") - } - if payloadFilename == "" && scriptFilename == "" { + } + if payloadFilename == "" && codeFilename == "" { return nil, fmt.Errorf("provide either a transaction payload or Cadence code file") } @@ -114,13 +116,13 @@ func (t *Transactions) Sign( if payerAddress != "" { return nil, fmt.Errorf("setting a payer is not permissible when using transaction payload") } - if proposerName != "" { + if proposerName != "" { return nil, fmt.Errorf("setting a proposer is not possible when using transaction payload") } - if len(args) > 0 || argsJSON != "" { + if len(args) > 0 || argsJSON != "" { return nil, fmt.Errorf("setting arguments is not possible when using transaction payload") } - if len(additionalAuthorizers) > 0 { + if len(additionalAuthorizers) > 0 { return nil, fmt.Errorf("setting additional authorizers is not possible when using transaction payload") } @@ -173,7 +175,35 @@ func (t *Transactions) Sign( tx.SetPayer(signerAccount.Address()) } - err = tx.SetScriptWithArgsFromFile(scriptFilename, args, argsJSON) + code, err := util.LoadFile(codeFilename) + if err != nil { + return nil, err + } + + resolver, err := contracts.NewResolver(code) + if err != nil { + return nil, err + } + + if resolver.HasFileImports() { + if network == "" { + return nil, fmt.Errorf("missing network, specify which network to use to resolve imports in transaction code") + } + if codeFilename == "" { // when used as lib with code we don't support imports + return nil, fmt.Errorf("resolving imports in transactions not supported") + } + + code, err = resolver.ResolveImports( + codeFilename, + t.project.ContractsByNetwork(network), + t.project.AliasesForNetwork(network), + ) + if err != nil { + return nil, err + } + } + + err = tx.SetScriptWithArgs(code, args, argsJSON) if err != nil { return nil, err } @@ -198,6 +228,7 @@ func (t *Transactions) Send( signerName string, args []string, argsJSON string, + network string, ) (*flow.Transaction, *flow.TransactionResult, error) { signed, err := t.Sign( @@ -211,6 +242,7 @@ func (t *Transactions) Send( args, argsJSON, true, + network, ) if err != nil { return nil, nil, err From e0f2b7baa6659ddc6b75b819a082b8119508b574 Mon Sep 17 00:00:00 2001 From: Gregor Gololicic Date: Tue, 13 Apr 2021 11:25:04 +0200 Subject: [PATCH 070/137] default flag values fix --- internal/command/command.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/internal/command/command.go b/internal/command/command.go index 2fafd3aa0..d025ddb2f 100644 --- a/internal/command/command.go +++ b/internal/command/command.go @@ -80,7 +80,7 @@ var flags = GlobalFlags{ Format: formatText, Save: "", Host: "", - Network: project.DefaultEmulatorNetworkName, + Network: config.DefaultMainnetNetwork().Name, Log: logLevelInfo, Yes: false, ConfigPath: project.DefaultConfigPaths, @@ -222,7 +222,7 @@ func resolveHost(proj *project.Project, hostFlag string, networkFlag string) (st return proj.NetworkByName(networkFlag).Host, nil } // default to emulator host - return project.DefaultEmulatorHost, nil + return config.DefaultEmulatorNetwork().Host, nil } // create logger utility From 512ab5475e6db298b400a62902886d0eca845d4a Mon Sep 17 00:00:00 2001 From: Gregor Gololicic Date: Tue, 13 Apr 2021 11:36:59 +0200 Subject: [PATCH 071/137] fix resolver address detection --- pkg/flowcli/contracts/resolver.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pkg/flowcli/contracts/resolver.go b/pkg/flowcli/contracts/resolver.go index 43071b290..e468bd2e3 100644 --- a/pkg/flowcli/contracts/resolver.go +++ b/pkg/flowcli/contracts/resolver.go @@ -94,9 +94,9 @@ func (r *Resolver) getFileImports() []string { imports := make([]string, 0) for _, importDeclaration := range r.program.ImportDeclarations() { - location, ok := importDeclaration.Location.(common.AddressLocation) + _, ok := importDeclaration.Location.(common.AddressLocation) if !ok { - imports = append(imports, location.String()) + imports = append(imports, importDeclaration.Location.String()) } } From 394b8b8906f9f9bd5877ce85308f35274ce1d3d8 Mon Sep 17 00:00:00 2001 From: Gregor Gololicic Date: Tue, 13 Apr 2021 11:37:10 +0200 Subject: [PATCH 072/137] fix tests --- internal/transactions/sign.go | 1 + pkg/flowcli/services/transactions_test.go | 4 ++++ tests/e2e_test.go | 25 ++++++++++++++++++++--- 3 files changed, 27 insertions(+), 3 deletions(-) diff --git a/internal/transactions/sign.go b/internal/transactions/sign.go index 351384fe4..d3c00e27f 100644 --- a/internal/transactions/sign.go +++ b/internal/transactions/sign.go @@ -69,6 +69,7 @@ var SignCommand = &command.Command{ signFlags.Args, signFlags.ArgsJSON, globalFlags.Yes, + globalFlags.Network, ) if err != nil { return nil, err diff --git a/pkg/flowcli/services/transactions_test.go b/pkg/flowcli/services/transactions_test.go index f105069e2..04b9c339a 100644 --- a/pkg/flowcli/services/transactions_test.go +++ b/pkg/flowcli/services/transactions_test.go @@ -93,6 +93,7 @@ func TestTransactions(t *testing.T) { serviceName, []string{"String:Bar"}, "", + "", ) assert.NoError(t, err) @@ -134,6 +135,7 @@ func TestTransactions(t *testing.T) { serviceName, []string{"Bar"}, "", + "", ) assert.Equal(t, err.Error(), "argument not passed in correct format, correct format is: Type:Value, got Bar") }) @@ -145,6 +147,7 @@ func TestTransactions(t *testing.T) { serviceName, []string{"Bar"}, "", + "", ) assert.Equal(t, err.Error(), "Failed to load file: nooo.cdc") }) @@ -156,6 +159,7 @@ func TestTransactions(t *testing.T) { serviceName, nil, "[{\"Bar\":\"No\"}]", + "", ) assert.Equal(t, err.Error(), "failed to decode value: invalid JSON Cadence structure") }) diff --git a/tests/e2e_test.go b/tests/e2e_test.go index 37d92dea2..2393cd63c 100644 --- a/tests/e2e_test.go +++ b/tests/e2e_test.go @@ -214,7 +214,12 @@ func TestScripts(t *testing.T) { }) t.Run("Test Script JSON args", func(t *testing.T) { - val, err := scripts.Execute("./script.cdc", []string{}, "[{\"type\": \"String\", \"value\": \"Mr G\"}]", "") + val, err := scripts.Execute( + "./script.cdc", + []string{}, + "[{\"type\": \"String\", \"value\": \"Mr G\"}]", + "", + ) assert.NoError(t, err) assert.Equal(t, val.String(), `"Hello Mr G"`) @@ -236,7 +241,14 @@ func TestTransactions(t *testing.T) { var txID1 flow.Identifier t.Run("Test Transactions", func(t *testing.T) { - tx, tr, err := transactions.Send("./transaction.cdc", "", emulatorAccount, []string{"String:Hello"}, "") + tx, tr, err := transactions.Send( + "./transaction.cdc", + "", + emulatorAccount, + []string{"String:Hello"}, + "", + "", + ) txID1 = tx.ID() assert.NoError(t, tr.Error) @@ -246,7 +258,14 @@ func TestTransactions(t *testing.T) { }) t.Run("Test Failed Transactions", func(t *testing.T) { - tx, tr, err := transactions.Send("./transactionErr.cdc", "", emulatorAccount, []string{}, "") + tx, tr, err := transactions.Send( + "./transactionErr.cdc", + "", + emulatorAccount, + []string{}, + "", + "", + ) assert.NoError(t, err) assert.NotNil(t, tr.Error) From b40cc2d7585147c8c209ba2e87f3f21de55785a8 Mon Sep 17 00:00:00 2001 From: Gregor Gololicic Date: Tue, 13 Apr 2021 11:40:54 +0200 Subject: [PATCH 073/137] typo --- internal/command/command.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/internal/command/command.go b/internal/command/command.go index d025ddb2f..6372ee15b 100644 --- a/internal/command/command.go +++ b/internal/command/command.go @@ -80,7 +80,7 @@ var flags = GlobalFlags{ Format: formatText, Save: "", Host: "", - Network: config.DefaultMainnetNetwork().Name, + Network: config.DefaultEmulatorNetwork().Name, Log: logLevelInfo, Yes: false, ConfigPath: project.DefaultConfigPaths, From 77a51c5bae1a7c7ec84602fc8ab0368c932cecab Mon Sep 17 00:00:00 2001 From: Gregor Gololicic Date: Tue, 13 Apr 2021 11:55:57 +0200 Subject: [PATCH 074/137] improved get account output --- internal/accounts/accounts.go | 2 ++ 1 file changed, 2 insertions(+) diff --git a/internal/accounts/accounts.go b/internal/accounts/accounts.go index 2ff688c42..e3ebffff2 100644 --- a/internal/accounts/accounts.go +++ b/internal/accounts/accounts.go @@ -96,6 +96,8 @@ func (r *AccountResult) String() string { fmt.Fprintf(writer, "\tSignature Algorithm\t %s\n", key.SigAlgo) fmt.Fprintf(writer, "\tHash Algorithm\t %s\n", key.HashAlgo) fmt.Fprintf(writer, "\tRevoked \t %t\n", key.Revoked) + fmt.Fprintf(writer, "\tSequence Number \t %d\n", key.SequenceNumber) + fmt.Fprintf(writer, "\tIndex \t %d\n", key.Index) fmt.Fprintf(writer, "\n") } From e477391d660708bf54b0bf4cb09cc35f9c43d16b Mon Sep 17 00:00:00 2001 From: Gregor Gololicic Date: Tue, 13 Apr 2021 11:58:17 +0200 Subject: [PATCH 075/137] docs updates --- docs/account-add-contract.md | 5 ++++- docs/account-remove-contract.md | 11 +++++++---- docs/account-update-contract.md | 5 ++++- docs/get-accounts.md | 7 +++++-- 4 files changed, 20 insertions(+), 8 deletions(-) diff --git a/docs/account-add-contract.md b/docs/account-add-contract.md index ccdfaa8ce..2766ce355 100644 --- a/docs/account-add-contract.md +++ b/docs/account-add-contract.md @@ -17,13 +17,16 @@ flow accounts add-contract Contract 'FungibleToken' deployed to the account 0xf8d6e0586b0a20c7 Address 0xf8d6e0586b0a20c7 -Balance 9999999999970000000 +Balance 99999999999.70000000 Keys 1 Key 0 Public Key 640a5a359bf3536d15192f18d872d57c98a96cb871b92b70cecb0739c2d5c37b4be12548d3526933c2cda9b0b9c69412f45ffb6b85b6840d8569d969fe84e5b7 Weight 1000 Signature Algorithm ECDSA_P256 Hash Algorithm SHA3_256 + Revoked false + Sequence Number 6 + Index 0 Contracts Deployed: 1 Contract: 'FungibleToken' diff --git a/docs/account-remove-contract.md b/docs/account-remove-contract.md index 0d3b68fb7..6ee929680 100644 --- a/docs/account-remove-contract.md +++ b/docs/account-remove-contract.md @@ -17,13 +17,16 @@ flow accounts remove-contract Contract 'FungibleToken' removed from account '0xf8d6e0586b0a20c7' Address 0xf8d6e0586b0a20c7 -Balance 0 +Balance 99999999999.70000000 Keys 1 Key 0 Public Key 640a5a359bf3536d15192f18d872d57c98a96cb871b92b70cecb0739c2d5c37b4be12548d3526933c2cda9b0b9c69412f45ffb6b85b6840d8569d969fe84e5b7 -Weight 1000 -Signature Algorithm ECDSA_P256 -Hash Algorithm SHA3_256 + Weight 1000 + Signature Algorithm ECDSA_P256 + Hash Algorithm SHA3_256 + Revoked false + Sequence Number 6 + Index 0 Contracts Deployed: 0 ``` diff --git a/docs/account-update-contract.md b/docs/account-update-contract.md index 4b7d780b4..d9004b535 100644 --- a/docs/account-update-contract.md +++ b/docs/account-update-contract.md @@ -17,13 +17,16 @@ flow accounts update-contract Contract 'FungibleToken' updated on account '0xf8d6e0586b0a20c7' Address 0xf8d6e0586b0a20c7 -Balance 9999999999970000000 +Balance 99999999999.70000000 Keys 1 Key 0 Public Key 640a5a359bf3536d15192f18d872d57c98a96cb871b92b70cecb0739c2d5c37b4be12548d3526933c2cda9b0b9c69412f45ffb6b85b6840d8569d969fe84e5b7 Weight 1000 Signature Algorithm ECDSA_P256 Hash Algorithm SHA3_256 + Revoked false + Sequence Number 6 + Index 0 Contracts Deployed: 1 Contract: 'FungibleToken' diff --git a/docs/get-accounts.md b/docs/get-accounts.md index afbd6a71a..bbe2140f7 100644 --- a/docs/get-accounts.md +++ b/docs/get-accounts.md @@ -19,13 +19,16 @@ flow accounts get 0xf8d6e0586b0a20c7 ### Example response ```shell Address 0xf8d6e0586b0a20c7 -Balance 9999999999970000000 +Balance 99999999999.70000000 Keys 1 -Key 0 Public Key 858a7d978b25d61f348841a343f79131f4b9fab341dd8a476a6f4367c25510570bf69b795fc9c3d2b7191327d869bcf848508526a3c1cafd1af34f71c7765117 +Key 0 Public Key 640a5a359bf3536d15192f18d872d57c98a96cb871b92b70cecb0739c2d5c37b4be12548d3526933c2cda9b0b9c69412f45ffb6b85b6840d8569d969fe84e5b7 Weight 1000 Signature Algorithm ECDSA_P256 Hash Algorithm SHA3_256 + Revoked false + Sequence Number 6 + Index 0 Contracts Deployed: 2 Contract: 'FlowServiceAccount' From 89e34ca403963331b67a2f2c0edff410ae4c0c3d Mon Sep 17 00:00:00 2001 From: Gregor Gololicic Date: Tue, 13 Apr 2021 12:29:12 +0200 Subject: [PATCH 076/137] clean up wrong tests --- tests/release/checklist_test.go | 88 --------------------------------- 1 file changed, 88 deletions(-) delete mode 100644 tests/release/checklist_test.go diff --git a/tests/release/checklist_test.go b/tests/release/checklist_test.go deleted file mode 100644 index a2f58ae47..000000000 --- a/tests/release/checklist_test.go +++ /dev/null @@ -1,88 +0,0 @@ -/* - * Flow CLI - * - * Copyright 2019-2021 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 release - -import ( - "bytes" - "fmt" - "io/ioutil" - "testing" - - "github.com/onflow/flow-cli/internal/accounts" - "github.com/onflow/flow-cli/internal/cadence" - "github.com/onflow/flow-cli/internal/collections" - "github.com/onflow/flow-cli/internal/command" - "github.com/onflow/flow-cli/internal/config" - "github.com/onflow/flow-cli/internal/emulator" - "github.com/onflow/flow-cli/internal/events" - "github.com/onflow/flow-cli/internal/keys" - "github.com/onflow/flow-cli/internal/project" - "github.com/onflow/flow-cli/internal/scripts" - "github.com/onflow/flow-cli/internal/transactions" - "github.com/onflow/flow-cli/internal/version" - "github.com/spf13/cobra" - - "github.com/onflow/flow-cli/internal/blocks" -) - -func TestChecklist(t *testing.T) { - - var cmd = &cobra.Command{ - Use: "flow", - TraverseChildren: true, - } - - // hot commands - config.InitCommand.AddToParent(cmd) - - // structured commands - cmd.AddCommand(cadence.Cmd) - cmd.AddCommand(version.Cmd) - cmd.AddCommand(emulator.Cmd) - cmd.AddCommand(accounts.Cmd) - cmd.AddCommand(scripts.Cmd) - cmd.AddCommand(transactions.Cmd) - cmd.AddCommand(keys.Cmd) - cmd.AddCommand(events.Cmd) - cmd.AddCommand(blocks.Cmd) - cmd.AddCommand(collections.Cmd) - cmd.AddCommand(project.Cmd) - - command.InitFlags(cmd) - - for _, c := range cmd.Commands() { - fmt.Println(c.Name()) - } - -} - -func checkCommand(c cobra.Command) { - b := bytes.NewBufferString("") - - c.SetArgs([]string{"get", "1"}) - c.SetOut(b) - c.SetErr(b) - - //err := c.Execute() - //assert.NoError(t, err) - - out, _ := ioutil.ReadAll(b) - - fmt.Println(string(out)) -} From 90ed0fe50a3b15c7836818baded21f711c61b7c0 Mon Sep 17 00:00:00 2001 From: Gregor Gololicic Date: Wed, 14 Apr 2021 20:10:47 +0200 Subject: [PATCH 077/137] add key weight to create --- internal/accounts/create.go | 2 ++ pkg/flowcli/services/accounts.go | 17 ++++++++++++++++- 2 files changed, 18 insertions(+), 1 deletion(-) diff --git a/internal/accounts/create.go b/internal/accounts/create.go index 54c5ae75f..feb5ecfb7 100644 --- a/internal/accounts/create.go +++ b/internal/accounts/create.go @@ -30,6 +30,7 @@ import ( type flagsCreate struct { Signer string `default:"emulator-account" flag:"signer" info:"Account name from configuration used to sign the transaction"` Keys []string `flag:"key" info:"Public keys to attach to account"` + Weights []int `flag:"key-weight" info:"Weight for the key"` SigAlgo string `default:"ECDSA_P256" flag:"sig-algo" info:"Signature algorithm used to generate the keys"` HashAlgo string `default:"SHA3_256" flag:"hash-algo" info:"Hash used for the digest"` Contracts []string `flag:"contract" info:"Contract to be deployed during account creation. "` @@ -58,6 +59,7 @@ var CreateCommand = &command.Command{ account, err := services.Accounts.Create( createFlags.Signer, createFlags.Keys, + createFlags.Weights, createFlags.SigAlgo, createFlags.HashAlgo, createFlags.Contracts, diff --git a/pkg/flowcli/services/accounts.go b/pkg/flowcli/services/accounts.go index 632f643c9..a3ac9c380 100644 --- a/pkg/flowcli/services/accounts.go +++ b/pkg/flowcli/services/accounts.go @@ -206,6 +206,7 @@ func (a *Accounts) StakingInfo(accountAddress string) (*cadence.Value, *cadence. func (a *Accounts) Create( signerName string, keys []string, + keyWeights []int, signatureAlgorithm string, hashingAlgorithm string, contracts []string, @@ -214,6 +215,11 @@ func (a *Accounts) Create( return nil, fmt.Errorf("missing configuration, initialize it: flow init") } + // if more than one key is provided and at least one weight is specified, make sure there isn't a missmatch + if len(keys) > 1 && len(keyWeights) > 0 && len(keys) != len(keyWeights) { + return nil, fmt.Errorf("number of keys and weights provided must match, provided keys %s") + } + signer := a.project.AccountByName(signerName) if signer == nil { return nil, fmt.Errorf("signer account: [%s] doesn't exists in configuration", signerName) @@ -241,11 +247,20 @@ func (a *Accounts) Create( ) } + weight := flow.AccountKeyWeightThreshold + if len(keyWeights) > i { + weight = keyWeights[i] + + if weight > flow.AccountKeyWeightThreshold || weight <= 0 { + return nil, fmt.Errorf("invalid key weight, valid range (0 - 1000)") + } + } + accountKeys[i] = &flow.AccountKey{ PublicKey: publicKey, SigAlgo: sigAlgo, HashAlgo: hashAlgo, - Weight: flow.AccountKeyWeightThreshold, + Weight: weight, } } From 811085f17017b9a3dbd6678bd53dd0cabcd9d917 Mon Sep 17 00:00:00 2001 From: Gregor Gololicic Date: Wed, 14 Apr 2021 20:13:59 +0200 Subject: [PATCH 078/137] added docs --- docs/create-accounts.md | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/docs/create-accounts.md b/docs/create-accounts.md index 71b618175..dab110df0 100644 --- a/docs/create-accounts.md +++ b/docs/create-accounts.md @@ -47,7 +47,7 @@ In the above example, the `flow.json` file would look something like this: } ``` -## Options +## Flags ### Public Key @@ -57,6 +57,15 @@ In the above example, the `flow.json` file would look something like this: Specify the public key that will be added to the new account upon creation. +### Key Weight + +- Flag: `--key-weight` +- Valid inputs: number between 0 and 1000 +- Default: 1000 + +Specify the weight of the key. When key weight is provided it must +match the number of keys. Specify key weight flag for each key flag. + ### Public Key Signature Algorithm - Flag: `--sig-algo` From 867dfe1697deb2197afc3593a39017c9551a13de Mon Sep 17 00:00:00 2001 From: Gregor Gololicic Date: Thu, 15 Apr 2021 16:57:05 +0200 Subject: [PATCH 079/137] test fixes --- pkg/flowcli/services/transactions_test.go | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/pkg/flowcli/services/transactions_test.go b/pkg/flowcli/services/transactions_test.go index d35487e48..138844dcd 100644 --- a/pkg/flowcli/services/transactions_test.go +++ b/pkg/flowcli/services/transactions_test.go @@ -87,9 +87,16 @@ func TestTransactions(t *testing.T) { return tests.NewTransaction(), nil } + mock.GetLatestBlockMock = func() (*flow.Block, error) { + return tests.NewBlock(), nil + } + + mock.GetAccountMock = func(address flow.Address) (*flow.Account, error) { + return tests.NewAccountWithAddress(address.String()), nil + } + _, _, err := transactions.Send( "../../../tests/transaction.cdc", - "", serviceName, []string{"String:Bar"}, "", @@ -116,7 +123,6 @@ func TestTransactions(t *testing.T) { _, _, err := transactions.Send( "../../../tests/transaction.cdc", - "", serviceName, nil, "[{\"type\": \"String\", \"value\": \"Bar\"}]", @@ -129,7 +135,6 @@ func TestTransactions(t *testing.T) { t.Run("Send Transaction Fails wrong args", func(t *testing.T) { _, _, err := transactions.Send( "../../../tests/transaction.cdc", - "", serviceName, []string{"Bar"}, "", @@ -140,7 +145,6 @@ func TestTransactions(t *testing.T) { t.Run("Send Transaction Fails wrong filename", func(t *testing.T) { _, _, err := transactions.Send( "nooo.cdc", - "", serviceName, []string{"Bar"}, "", @@ -151,7 +155,6 @@ func TestTransactions(t *testing.T) { t.Run("Send Transaction Fails wrong args", func(t *testing.T) { _, _, err := transactions.Send( "../../../tests/transaction.cdc", - "", serviceName, nil, "[{\"Bar\":\"No\"}]", From 77917cc703926aa8c80e203a37d96afce743cc67 Mon Sep 17 00:00:00 2001 From: Gregor Gololicic Date: Thu, 15 Apr 2021 16:57:13 +0200 Subject: [PATCH 080/137] add build command --- internal/transactions/build.go | 71 ++++++++++++++++++++++++++++++++++ 1 file changed, 71 insertions(+) create mode 100644 internal/transactions/build.go diff --git a/internal/transactions/build.go b/internal/transactions/build.go new file mode 100644 index 000000000..75ac599a1 --- /dev/null +++ b/internal/transactions/build.go @@ -0,0 +1,71 @@ +/* + * Flow CLI + * + * Copyright 2019-2021 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 transactions + +import ( + "github.com/onflow/flow-cli/internal/command" + "github.com/onflow/flow-cli/pkg/flowcli/services" + "github.com/spf13/cobra" +) + +type flagsBuild struct { + ArgsJSON string `default:"" flag:"args-json" info:"arguments in JSON-Cadence format"` + Args []string `default:"" flag:"arg" info:"argument in Type:Value format"` + Proposer string `default:"emulator-account" flag:"proposer" info:"transaction proposer"` + ProposerKeyIndex int `default:"0" flag:"proposer-key-index" info:"proposer key index"` + Payer string `default:"emulator-account" flag:"payer" info:"transaction payer"` + Authorizer []string `default:"emulator-account" flag:"authorizer" info:"transaction authorizer"` +} + +var buildFlags = flagsBuild{} + +var BuildCommand = &command.Command{ + Cmd: &cobra.Command{ + Use: "build ", + Short: "Build a transaction for later signing", + Example: "flow transactions build ./transaction.cdc --proposer alice --authorizer alice --payer bob", + Args: cobra.ExactArgs(1), + }, + Flags: &buildFlags, + Run: func( + cmd *cobra.Command, + args []string, + globalFlags command.GlobalFlags, + services *services.Services, + ) (command.Result, error) { + + // proposer key index? + + build, err := services.Transactions.Build( + buildFlags.Proposer, + buildFlags.Authorizer, + buildFlags.Payer, + buildFlags.ProposerKeyIndex, + args[0], // code filename + buildFlags.Args, + buildFlags.ArgsJSON, + ) + if err != nil { + return nil, err + } + + return &TransactionResult{ + tx: build.FlowTransaction(), + }, nil + }, +} From 5337c976d594a3866243e4cc9b805b653143aff8 Mon Sep 17 00:00:00 2001 From: Gregor Gololicic Date: Thu, 15 Apr 2021 16:57:21 +0200 Subject: [PATCH 081/137] add send signed command --- internal/transactions/send-signed.go | 59 ++++++++++++++++++++++++++++ 1 file changed, 59 insertions(+) create mode 100644 internal/transactions/send-signed.go diff --git a/internal/transactions/send-signed.go b/internal/transactions/send-signed.go new file mode 100644 index 000000000..9129caaa2 --- /dev/null +++ b/internal/transactions/send-signed.go @@ -0,0 +1,59 @@ +/* + * Flow CLI + * + * Copyright 2019-2021 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 transactions + +import ( + "github.com/onflow/flow-cli/internal/command" + "github.com/onflow/flow-cli/pkg/flowcli/services" + "github.com/spf13/cobra" +) + +type flagsSendSigned struct { +} + +var sendSignedFlags = flagsSendSigned{} + +var SendSignedCommand = &command.Command{ + Cmd: &cobra.Command{ + Use: "send-signed ", + Short: "Send signed transaction", + Args: cobra.ExactArgs(1), + Example: `flow transactions send-signed signed.rlp`, + }, + Flags: &sendSignedFlags, + Run: func( + cmd *cobra.Command, + args []string, + globalFlags command.GlobalFlags, + services *services.Services, + ) (command.Result, error) { + + tx, result, err := services.Transactions.SendSigned( + args[0], // signed filename + ) + if err != nil { + return nil, err + } + + return &TransactionResult{ + result: result, + tx: tx, + }, nil + }, +} From 4e6c2554dc8a4b9850c8b1e25286e1af76dcbeaf Mon Sep 17 00:00:00 2001 From: Gregor Gololicic Date: Thu, 15 Apr 2021 16:57:32 +0200 Subject: [PATCH 082/137] update send command --- internal/transactions/send.go | 4 ---- 1 file changed, 4 deletions(-) diff --git a/internal/transactions/send.go b/internal/transactions/send.go index ba529ce8b..f52b8e5ff 100644 --- a/internal/transactions/send.go +++ b/internal/transactions/send.go @@ -34,7 +34,6 @@ type flagsSend struct { Code string `default:"" flag:"code" info:"⚠️ Deprecated: use filename argument"` Results bool `default:"" flag:"results" info:"⚠️ Deprecated: all transactions will provide result"` Args string `default:"" flag:"args" info:"⚠️ Deprecated: use arg or args-json flag"` - Payload string `flag:"payload" info:"path to the transaction payload file"` } var sendFlags = flagsSend{} @@ -71,13 +70,10 @@ var SendCommand = &command.Command{ } else if sendFlags.Code != "" { fmt.Println("⚠️ DEPRECATION WARNING: use filename as a command argument ") filename = sendFlags.Code - } else if sendFlags.Payload == "" { - return nil, fmt.Errorf("provide a valid filename command argument") } tx, result, err := services.Transactions.Send( filename, - sendFlags.Payload, sendFlags.Signer, sendFlags.Arg, sendFlags.ArgsJSON, From 34f5a89b1fd5327b7a81b410e33d5e4b3c13c1ce Mon Sep 17 00:00:00 2001 From: Gregor Gololicic Date: Thu, 15 Apr 2021 16:57:39 +0200 Subject: [PATCH 083/137] refactor sign command --- internal/transactions/sign.go | 31 ++++++------------------------- 1 file changed, 6 insertions(+), 25 deletions(-) diff --git a/internal/transactions/sign.go b/internal/transactions/sign.go index 351384fe4..2d4931c29 100644 --- a/internal/transactions/sign.go +++ b/internal/transactions/sign.go @@ -26,24 +26,17 @@ import ( ) type flagsSign struct { - ArgsJSON string `default:"" flag:"args-json" info:"arguments in JSON-Cadence format"` - Args []string `default:"" flag:"arg" info:"argument in Type:Value format"` - Signer string `default:"emulator-account" flag:"signer" info:"name of the account used to sign"` - Payload string `flag:"payload" info:"path to the transaction payload file"` - Proposer string `default:"" flag:"proposer" info:"name of the account that is proposing the transaction"` - Role string `default:"authorizer" flag:"role" info:"Specify a role of the signer, values: proposer, payer, authorizer"` - AdditionalAuthorizers []string `flag:"add-authorizer" info:"Additional authorizer addresses to add to the transaction"` - PayerAddress string `flag:"payer-address" info:"Specify payer of the transaction. Defaults to first signer."` + Signer string `default:"emulator-account" flag:"signer" info:"name of the account used to sign"` } var signFlags = flagsSign{} var SignCommand = &command.Command{ Cmd: &cobra.Command{ - Use: "sign ", - Short: "Sign a transaction", - Example: "flow transactions sign", - Args: cobra.MaximumNArgs(1), + Use: "sign ", + Short: "Sign built transaction", + Example: "flow transactions sign ./built.rlp --signer alice", + Args: cobra.ExactArgs(1), }, Flags: &signFlags, Run: func( @@ -53,21 +46,9 @@ var SignCommand = &command.Command{ services *services.Services, ) (command.Result, error) { - codeFilename := "" - if len(args) > 0 { - codeFilename = args[0] - } - signed, err := services.Transactions.Sign( + args[0], // transaction payload signFlags.Signer, - signFlags.Proposer, - signFlags.PayerAddress, - signFlags.AdditionalAuthorizers, - signFlags.Role, - codeFilename, - signFlags.Payload, - signFlags.Args, - signFlags.ArgsJSON, globalFlags.Yes, ) if err != nil { From dbb6d55150dd985ddfbe66b06dc2e198ae7bf269 Mon Sep 17 00:00:00 2001 From: Gregor Gololicic Date: Thu, 15 Apr 2021 16:58:24 +0200 Subject: [PATCH 084/137] added new commands --- internal/transactions/transactions.go | 2 ++ 1 file changed, 2 insertions(+) diff --git a/internal/transactions/transactions.go b/internal/transactions/transactions.go index 0ac16d8aa..299ea8d69 100644 --- a/internal/transactions/transactions.go +++ b/internal/transactions/transactions.go @@ -39,6 +39,8 @@ func init() { GetCommand.AddToParent(Cmd) SendCommand.AddToParent(Cmd) SignCommand.AddToParent(Cmd) + BuildCommand.AddToParent(Cmd) + SendSignedCommand.AddToParent(Cmd) } // TransactionResult represent result from all account commands From b19246f79fdde6387a5426acc01096eea0e9cd55 Mon Sep 17 00:00:00 2001 From: Gregor Gololicic Date: Thu, 15 Apr 2021 16:58:48 +0200 Subject: [PATCH 085/137] refactor send, sign and implement build --- pkg/flowcli/services/transactions.go | 191 ++++++++++++++++----------- 1 file changed, 112 insertions(+), 79 deletions(-) diff --git a/pkg/flowcli/services/transactions.go b/pkg/flowcli/services/transactions.go index a5f892b62..99741f1d6 100644 --- a/pkg/flowcli/services/transactions.go +++ b/pkg/flowcli/services/transactions.go @@ -22,6 +22,8 @@ import ( "fmt" "strings" + "github.com/onflow/flow-cli/pkg/flowcli/util" + "github.com/onflow/flow-go-sdk" "github.com/onflow/flow-go-sdk/crypto" @@ -77,153 +79,170 @@ func (t *Transactions) GetStatus( return tx, result, err } -// Sign transaction -func (t *Transactions) Sign( - signerName string, - proposerName string, - payerAddress string, - additionalAuthorizers []string, - role string, +func (t *Transactions) Build( + proposer string, + authorizer []string, + payer string, + proposerKeyIndex int, scriptFilename string, - payloadFilename string, args []string, argsJSON string, - approveSigning bool, ) (*project.Transaction, error) { - if t.project == nil { - return nil, fmt.Errorf("missing configuration, initialize it: flow project init") - } - - // get the signer account - signerAccount := t.project.AccountByName(signerName) - if signerAccount == nil { - return nil, fmt.Errorf("signer account: [%s] doesn't exists in configuration", signerName) + proposerAddress, err := getAddressFromStringOrConfig(proposer, t.project) + if err != nil { + return nil, err } - if payloadFilename != "" && scriptFilename != "" { - return nil, fmt.Errorf("can not use both a transaction payload and Cadence code file") - } else if payloadFilename == "" && scriptFilename == "" { - return nil, fmt.Errorf("provide either a transaction payload or Cadence code file") + payerAddress, err := getAddressFromStringOrConfig(payer, t.project) + if err != nil { + return nil, err } - // if we received already created transaction payload, create from payload and return signed - if payloadFilename != "" { - if payerAddress != "" { - return nil, fmt.Errorf("setting a payer is not permissible when using transaction payload") - } else if proposerName != "" { - return nil, fmt.Errorf("setting a proposer is not possible when using transaction payload") - } else if len(args) > 0 || argsJSON != "" { - return nil, fmt.Errorf("setting arguments is not possible when using transaction payload") - } else if len(additionalAuthorizers) > 0 { - return nil, fmt.Errorf("setting additional authorizers is not possible when using transaction payload") - } - - tx, err := project.NewTransactionFromPayload(signerAccount, payloadFilename, role) + authorizerAddresses := make([]flow.Address, 0) + for _, a := range authorizer { + authorizerAddress, err := getAddressFromStringOrConfig(a, t.project) if err != nil { return nil, err } - - if approveSigning { - return tx.Sign() - } - - if output.ApproveTransactionPrompt(tx) { - return tx.Sign() - } else { - return nil, fmt.Errorf("transaction was not approved for signing") - } + authorizerAddresses = append(authorizerAddresses, authorizerAddress) } - // we are creating a new transaction - tx := project.NewTransaction() + latestBlock, err := t.gateway.GetLatestBlock() + if err != nil { + return nil, fmt.Errorf("failed to get latest sealed block: %w", err) + } - err := tx.SetSigner(signerAccount) + proposerAccount, err := t.gateway.GetAccount(proposerAddress) if err != nil { return nil, err } - err = tx.SetSignerRole(role) + tx := project.NewTransaction(). + SetPayer(payerAddress). + SetProposer(proposerAccount, proposerKeyIndex). + AddAuthorizers(authorizerAddresses). + SetDefaultGasLimit(). + SetBlockReference(latestBlock) + + err = tx.SetScriptWithArgsFromFile(scriptFilename, args, argsJSON) if err != nil { return nil, err } - // if proposer is specified and exists assign it - if proposerName != "" { - proposerAccount := t.project.AccountByName(proposerName) - if proposerAccount == nil { - return nil, fmt.Errorf("proposer account: [%s] doesn't exists in configuration", signerName) - } + return tx, nil +} - err = tx.SetProposer(proposerAccount) - if err != nil { - return nil, err - } +// Sign transaction +func (t *Transactions) Sign( + payloadFilename string, + signerName string, + approveSigning bool, +) (*project.Transaction, error) { + if t.project == nil { + return nil, fmt.Errorf("missing configuration, initialize it: flow project init") } - // set payer if specified, else set current signer as payer if tx doesn't have one yet associated - if payerAddress != "" { - tx.SetPayer(flow.HexToAddress(payerAddress)) - } else if !tx.HasPayer() { - tx.SetPayer(signerAccount.Address()) + // get the signer account + signerAccount := t.project.AccountByName(signerName) + if signerAccount == nil { + return nil, fmt.Errorf("signer account: [%s] doesn't exists in configuration", signerName) } - err = tx.SetScriptWithArgsFromFile(scriptFilename, args, argsJSON) + tx, err := project.NewTransactionFromPayload(payloadFilename) if err != nil { return nil, err } - err = tx.AddAuthorizers(additionalAuthorizers) + err = tx.SetSigner(signerAccount) if err != nil { return nil, err } - tx, err = t.gateway.PrepareTransactionPayload(tx) - if err != nil { - return nil, err + if approveSigning { + return tx.Sign() + } + + if !output.ApproveTransactionPrompt(tx) { + return nil, fmt.Errorf("transaction was not approved for signing") } return tx.Sign() } +func (t *Transactions) SendSigned( + signedFilename string, +) (*flow.Transaction, *flow.TransactionResult, error) { + tx, err := project.NewTransactionFromPayload(signedFilename) + if err != nil { + return nil, nil, err + } + + sentTx, err := t.gateway.SendSignedTransaction(tx) + if err != nil { + return nil, nil, err + } + + res, err := t.gateway.GetTransactionResult(sentTx, true) + if err != nil { + return nil, nil, err + } + + return sentTx, res, nil +} + // Send sends a transaction from a file. func (t *Transactions) Send( transactionFilename string, - payloadFilename string, signerName string, args []string, argsJSON string, ) (*flow.Transaction, *flow.TransactionResult, error) { + if t.project == nil { + return nil, nil, fmt.Errorf("missing configuration, initialize it: flow project init") + } - signed, err := t.Sign( + signerAccount := t.project.AccountByName(signerName) + if signerAccount == nil { + return nil, nil, fmt.Errorf("signer account: [%s] doesn't exists in configuration", signerName) + } + + tx, err := t.Build( + signerName, + []string{signerName}, signerName, - "", - "", - []string{}, - "", + 0, // default 0 key transactionFilename, - payloadFilename, args, argsJSON, - true, ) if err != nil { return nil, nil, err } + err = tx.SetSigner(signerAccount) + if err != nil { + return nil, nil, err + } + + signed, err := tx.Sign() + if err != nil { + return nil, nil, err + } + t.logger.StartProgress("Sending Transaction...") - tx, err := t.gateway.SendSignedTransaction(signed) + sentTx, err := t.gateway.SendSignedTransaction(signed) if err != nil { return nil, nil, err } t.logger.StartProgress("Waiting for transaction to be sealed...") - res, err := t.gateway.GetTransactionResult(tx, true) + res, err := t.gateway.GetTransactionResult(sentTx, true) t.logger.StopProgress() - return tx, res, err + return sentTx, res, err } // SendForAddressWithCode send transaction for address and private key specified with code @@ -273,3 +292,17 @@ func (t *Transactions) SendForAddressWithCode( t.logger.StopProgress() return sentTx, res, err } + +func getAddressFromStringOrConfig(value string, project *project.Project) (flow.Address, error) { + if util.ValidAddress(value) { + return flow.HexToAddress(value), nil + } else if project != nil { + account := project.AccountByName(value) + if account == nil { + return flow.EmptyAddress, fmt.Errorf("account could not be found") + } + return account.Address(), nil + } else { + return flow.EmptyAddress, fmt.Errorf("could not parse address or account name from config, missing configuration") + } +} From ace07afb1c639efa84f8d2d39f319d80f656c933 Mon Sep 17 00:00:00 2001 From: Gregor Gololicic Date: Thu, 15 Apr 2021 16:59:03 +0200 Subject: [PATCH 086/137] utils tests --- pkg/flowcli/util/utilities.go | 9 +++++++++ tests/e2e_test.go | 4 ++-- 2 files changed, 11 insertions(+), 2 deletions(-) diff --git a/pkg/flowcli/util/utilities.go b/pkg/flowcli/util/utilities.go index f2626a862..0c257787e 100644 --- a/pkg/flowcli/util/utilities.go +++ b/pkg/flowcli/util/utilities.go @@ -113,3 +113,12 @@ func ContainsString(s []string, e string) bool { } return false } + +func ValidAddress(value string) bool { + address := flow.HexToAddress(value) + + // valid on any chain + return address.IsValid(flow.Mainnet) || + address.IsValid(flow.Testnet) || + address.IsValid(flow.Emulator) +} diff --git a/tests/e2e_test.go b/tests/e2e_test.go index 1c5708cb7..e74e52199 100644 --- a/tests/e2e_test.go +++ b/tests/e2e_test.go @@ -236,7 +236,7 @@ func TestTransactions(t *testing.T) { var txID1 flow.Identifier t.Run("Test Transactions", func(t *testing.T) { - tx, tr, err := transactions.Send("./transaction.cdc", "", emulatorAccount, []string{"String:Hello"}, "") + tx, tr, err := transactions.Send("./transaction.cdc", emulatorAccount, []string{"String:Hello"}, "") txID1 = tx.ID() assert.NoError(t, tr.Error) @@ -246,7 +246,7 @@ func TestTransactions(t *testing.T) { }) t.Run("Test Failed Transactions", func(t *testing.T) { - tx, tr, err := transactions.Send("./transactionErr.cdc", "", emulatorAccount, []string{}, "") + tx, tr, err := transactions.Send("./transactionErr.cdc", emulatorAccount, []string{}, "") assert.NoError(t, err) assert.NotNil(t, tr.Error) From e7cc4e5743920bd35ffbd22bb431810d3011e25d Mon Sep 17 00:00:00 2001 From: Gregor Gololicic Date: Thu, 15 Apr 2021 16:59:13 +0200 Subject: [PATCH 087/137] refactor tx model --- pkg/flowcli/project/transaction.go | 121 +++++++++++++---------------- 1 file changed, 52 insertions(+), 69 deletions(-) diff --git a/pkg/flowcli/project/transaction.go b/pkg/flowcli/project/transaction.go index 2cec2b4ea..f38c7e874 100644 --- a/pkg/flowcli/project/transaction.go +++ b/pkg/flowcli/project/transaction.go @@ -38,9 +38,7 @@ import ( type signerRole string const ( - SignerRoleAuthorizer signerRole = "authorizer" - SignerRoleProposer signerRole = "proposer" - SignerRolePayer signerRole = "payer" + defaultGasLimit = 1000 ) func NewTransaction() *Transaction { @@ -49,7 +47,7 @@ func NewTransaction() *Transaction { } } -func NewTransactionFromPayload(signer *Account, filename string, role string) (*Transaction, error) { +func NewTransactionFromPayload(filename string) (*Transaction, error) { partialTxHex, err := ioutil.ReadFile(filename) if err != nil { return nil, fmt.Errorf("failed to read partial transaction from %s: %v", filename, err) @@ -69,13 +67,6 @@ func NewTransactionFromPayload(signer *Account, filename string, role string) (* tx: decodedTx, } - err = tx.SetSigner(signer) - if err != nil { - return nil, err - } - // we need to set the role here for signing purpose, so we know what to sign envelope or payload - tx.signerRole = signerRole(role) - return tx, nil } @@ -142,16 +133,14 @@ func NewCreateAccountTransaction( if len(contractFlagContent) != 2 { return nil, fmt.Errorf("wrong format for contract. Correct format is name:path, but got: %s", contract) } - contractName := contractFlagContent[0] - contractPath := contractFlagContent[1] - contractSource, err := util.LoadFile(contractPath) + contractSource, err := util.LoadFile(contractFlagContent[1]) if err != nil { return nil, err } contracts = append(contracts, templates.Contract{ - Name: contractName, + Name: contractFlagContent[0], Source: string(contractSource), }) } @@ -172,7 +161,7 @@ func NewCreateAccountTransaction( type Transaction struct { signer *Account signerRole signerRole - proposer *Account + proposer *flow.Account tx *flow.Transaction } @@ -180,7 +169,7 @@ func (t *Transaction) Signer() *Account { return t.signer } -func (t *Transaction) Proposer() *Account { +func (t *Transaction) Proposer() *flow.Account { return t.proposer } @@ -212,22 +201,32 @@ func (t *Transaction) SetSigner(account *Account) error { return nil } -func (t *Transaction) SetProposer(account *Account) error { - err := account.DefaultKey().Validate() - if err != nil { - return err - } +func (t *Transaction) SetProposer(proposer *flow.Account, keyIndex int) *Transaction { + t.proposer = proposer + proposerKey := proposer.Keys[keyIndex] - t.proposer = account - return nil + t.tx.SetProposalKey( + proposer.Address, + proposerKey.Index, + proposerKey.SequenceNumber, + ) + + return t } -func (t *Transaction) SetPayer(address flow.Address) { +func (t *Transaction) SetPayer(address flow.Address) *Transaction { t.tx.SetPayer(address) + return t +} + +func (t *Transaction) SetBlockReference(block *flow.Block) *Transaction { + t.tx.SetReferenceBlockID(block.ID) + return t } -func (t *Transaction) HasPayer() bool { - return t.tx.Payer != flow.EmptyAddress +func (t *Transaction) SetDefaultGasLimit() *Transaction { + t.tx.SetGasLimit(defaultGasLimit) + return t } func (t *Transaction) AddRawArguments(args []string, argsJSON string) error { @@ -254,63 +253,28 @@ func (t *Transaction) AddArgument(arg cadence.Value) error { return t.tx.AddArgument(arg) } -func (t *Transaction) AddAuthorizers(addresses []string) error { - for _, address := range addresses { - err := t.AddAuthorizer(address) - if err != nil { // return error even if one breaks - return err - } - } - - return nil -} - -func (t *Transaction) AddAuthorizer(address string) error { - authorizerAddress := flow.HexToAddress(address) - if authorizerAddress == flow.EmptyAddress { - return fmt.Errorf("invalid authorizer address provided %s", address) - } - - t.tx.AddAuthorizer(authorizerAddress) - return nil -} - -func (t *Transaction) SetSignerRole(role string) error { - t.signerRole = signerRole(role) - - if t.signerRole == SignerRoleAuthorizer { - err := t.AddAuthorizer(t.signer.Address().String()) - if err != nil { - return err - } - } - if t.signerRole == SignerRolePayer && t.tx.Payer != t.signer.Address() { - return fmt.Errorf("role specified as Payer, but Payer address also provided, and different: %s != %s", t.tx.Payer, t.signer.Address()) +func (t *Transaction) AddAuthorizers(authorizers []flow.Address) *Transaction { + for _, authorizer := range authorizers { + t.tx.AddAuthorizer(authorizer) } - return nil + return t } func (t *Transaction) Sign() (*Transaction, error) { keyIndex := t.signer.DefaultKey().Index() - signerAddress := t.signer.Address() signer, err := t.signer.DefaultKey().Signer(context.Background()) if err != nil { return nil, err } - if t.signerRole == SignerRoleAuthorizer || t.signerRole == SignerRoleProposer { - err := t.tx.SignPayload(signerAddress, keyIndex, signer) + if t.shouldSignEnvelope() { + err = t.tx.SignEnvelope(t.signer.address, keyIndex, signer) if err != nil { return nil, fmt.Errorf("failed to sign transaction: %s", err) } } else { - // make sure we have at least signer as authorizer else add self - if len(t.tx.Authorizers) == 0 { - t.tx.AddAuthorizer(t.signer.Address()) - } - - err := t.tx.SignEnvelope(signerAddress, keyIndex, signer) + err = t.tx.SignPayload(t.signer.address, keyIndex, signer) if err != nil { return nil, fmt.Errorf("failed to sign transaction: %s", err) } @@ -318,3 +282,22 @@ func (t *Transaction) Sign() (*Transaction, error) { return t, nil } + +func (t *Transaction) shouldSignEnvelope() bool { + // if signer is payer + if t.signer.address == t.tx.Payer { + return true + /* + // and either authorizer or proposer - special case + if len(t.tx.Authorizers) == 1 && t.tx.Authorizers[0] == t.signer.address { + return true + } else if t.signer.address == t.tx.ProposalKey.Address { + return true + } else { + // ? + } + */ + } + + return false +} From 4793c1f4a318d4588c8d60d00290841766234fc4 Mon Sep 17 00:00:00 2001 From: Gregor Gololicic Date: Thu, 15 Apr 2021 17:06:00 +0200 Subject: [PATCH 088/137] comments --- pkg/flowcli/project/transaction.go | 23 +++++++++++++++++++++++ 1 file changed, 23 insertions(+) diff --git a/pkg/flowcli/project/transaction.go b/pkg/flowcli/project/transaction.go index f38c7e874..877046b44 100644 --- a/pkg/flowcli/project/transaction.go +++ b/pkg/flowcli/project/transaction.go @@ -41,12 +41,14 @@ const ( defaultGasLimit = 1000 ) +// NewTransaction create new instance of transaction func NewTransaction() *Transaction { return &Transaction{ tx: flow.NewTransaction(), } } +// NewTransactionFromPayload build transaction from payload func NewTransactionFromPayload(filename string) (*Transaction, error) { partialTxHex, err := ioutil.ReadFile(filename) if err != nil { @@ -70,6 +72,7 @@ func NewTransactionFromPayload(filename string) (*Transaction, error) { return tx, nil } +// NewUpdateAccountContractTransaction update account contract func NewUpdateAccountContractTransaction(signer *Account, name string, source string) (*Transaction, error) { contract := templates.Contract{ Name: name, @@ -89,6 +92,7 @@ func NewUpdateAccountContractTransaction(signer *Account, name string, source st return tx, nil } +// NewAddAccountContractTransaction add new contract to the account func NewAddAccountContractTransaction(signer *Account, name string, source string) (*Transaction, error) { contract := templates.Contract{ Name: name, @@ -108,6 +112,7 @@ func NewAddAccountContractTransaction(signer *Account, name string, source strin return tx, nil } +// NewRemoveAccountContractTransaction creates new transaction to remove contract func NewRemoveAccountContractTransaction(signer *Account, name string) (*Transaction, error) { tx := &Transaction{ tx: templates.RemoveAccountContract(signer.Address(), name), @@ -121,6 +126,7 @@ func NewRemoveAccountContractTransaction(signer *Account, name string) (*Transac return tx, nil } +// NewCreateAccountTransaction creates new transaction for account func NewCreateAccountTransaction( signer *Account, keys []*flow.AccountKey, @@ -158,6 +164,7 @@ func NewCreateAccountTransaction( return tx, nil } +// Transaction builder of flow transactions type Transaction struct { signer *Account signerRole signerRole @@ -165,18 +172,22 @@ type Transaction struct { tx *flow.Transaction } +// Signer get signer func (t *Transaction) Signer() *Account { return t.signer } +// Proposer get proposer func (t *Transaction) Proposer() *flow.Account { return t.proposer } +// FlowTransaction get flow transaction func (t *Transaction) FlowTransaction() *flow.Transaction { return t.tx } +// SetScriptWithArgsFromFile set scripts for transaction by loading it from file and setting args func (t *Transaction) SetScriptWithArgsFromFile(filepath string, args []string, argsJSON string) error { script, err := util.LoadFile(filepath) if err != nil { @@ -186,11 +197,13 @@ func (t *Transaction) SetScriptWithArgsFromFile(filepath string, args []string, return t.SetScriptWithArgs(script, args, argsJSON) } +// SetScriptWithArgs set script for transaction and set arguments for script func (t *Transaction) SetScriptWithArgs(script []byte, args []string, argsJSON string) error { t.tx.SetScript(script) return t.AddRawArguments(args, argsJSON) } +// SetSigner sets the signer for transaction func (t *Transaction) SetSigner(account *Account) error { err := account.DefaultKey().Validate() if err != nil { @@ -201,6 +214,7 @@ func (t *Transaction) SetSigner(account *Account) error { return nil } +// SetProposer sets the proposer for transaction func (t *Transaction) SetProposer(proposer *flow.Account, keyIndex int) *Transaction { t.proposer = proposer proposerKey := proposer.Keys[keyIndex] @@ -214,21 +228,25 @@ func (t *Transaction) SetProposer(proposer *flow.Account, keyIndex int) *Transac return t } +// SetPayer sets the payer for transaction func (t *Transaction) SetPayer(address flow.Address) *Transaction { t.tx.SetPayer(address) return t } +// SetBlockReference sets block reference for transaction func (t *Transaction) SetBlockReference(block *flow.Block) *Transaction { t.tx.SetReferenceBlockID(block.ID) return t } +// SetDefaultGasLimit set the default gas limit for transaction func (t *Transaction) SetDefaultGasLimit() *Transaction { t.tx.SetGasLimit(defaultGasLimit) return t } +// AddRawArguments add raw arguments to tx func (t *Transaction) AddRawArguments(args []string, argsJSON string) error { txArguments, err := flowcli.ParseArguments(args, argsJSON) if err != nil { @@ -238,6 +256,7 @@ func (t *Transaction) AddRawArguments(args []string, argsJSON string) error { return t.AddArguments(txArguments) } +// AddArguments add array of cadence arguments func (t *Transaction) AddArguments(args []cadence.Value) error { for _, arg := range args { err := t.AddArgument(arg) @@ -249,10 +268,12 @@ func (t *Transaction) AddArguments(args []cadence.Value) error { return nil } +// AddArgument add cadence typed argument func (t *Transaction) AddArgument(arg cadence.Value) error { return t.tx.AddArgument(arg) } +// AddAuthorizers add group of authorizers func (t *Transaction) AddAuthorizers(authorizers []flow.Address) *Transaction { for _, authorizer := range authorizers { t.tx.AddAuthorizer(authorizer) @@ -261,6 +282,7 @@ func (t *Transaction) AddAuthorizers(authorizers []flow.Address) *Transaction { return t } +// Sign signs transaction using signer account func (t *Transaction) Sign() (*Transaction, error) { keyIndex := t.signer.DefaultKey().Index() signer, err := t.signer.DefaultKey().Signer(context.Background()) @@ -283,6 +305,7 @@ func (t *Transaction) Sign() (*Transaction, error) { return t, nil } +// shouldSignEnvelope checks if signer should sign envelope or payload func (t *Transaction) shouldSignEnvelope() bool { // if signer is payer if t.signer.address == t.tx.Payer { From 6714d38806ad72d9867b96d4f6a5c0d42b66e645 Mon Sep 17 00:00:00 2001 From: Gregor Gololicic Date: Thu, 15 Apr 2021 17:20:46 +0200 Subject: [PATCH 089/137] transaction refactor --- pkg/flowcli/project/transaction.go | 55 +++++++++++------------------- 1 file changed, 20 insertions(+), 35 deletions(-) diff --git a/pkg/flowcli/project/transaction.go b/pkg/flowcli/project/transaction.go index 877046b44..a861b40d4 100644 --- a/pkg/flowcli/project/transaction.go +++ b/pkg/flowcli/project/transaction.go @@ -79,17 +79,10 @@ func NewUpdateAccountContractTransaction(signer *Account, name string, source st Source: source, } - tx := &Transaction{ - tx: templates.UpdateAccountContract(signer.Address(), contract), - } - - err := tx.SetSigner(signer) - if err != nil { - return nil, err - } - tx.SetPayer(signer.Address()) - - return tx, nil + return newTransactionFromTemplate( + templates.UpdateAccountContract(signer.Address(), contract), + signer, + ) } // NewAddAccountContractTransaction add new contract to the account @@ -99,31 +92,18 @@ func NewAddAccountContractTransaction(signer *Account, name string, source strin Source: source, } - tx := &Transaction{ - tx: templates.AddAccountContract(signer.Address(), contract), - } - - err := tx.SetSigner(signer) - if err != nil { - return nil, err - } - tx.SetPayer(signer.Address()) - - return tx, nil + return newTransactionFromTemplate( + templates.AddAccountContract(signer.Address(), contract), + signer, + ) } // NewRemoveAccountContractTransaction creates new transaction to remove contract func NewRemoveAccountContractTransaction(signer *Account, name string) (*Transaction, error) { - tx := &Transaction{ - tx: templates.RemoveAccountContract(signer.Address(), name), - } - - err := tx.SetSigner(signer) - if err != nil { - return nil, err - } - - return tx, nil + return newTransactionFromTemplate( + templates.RemoveAccountContract(signer.Address(), name), + signer, + ) } // NewCreateAccountTransaction creates new transaction for account @@ -151,9 +131,14 @@ func NewCreateAccountTransaction( }) } - tx := &Transaction{ - tx: templates.CreateAccount(keys, contracts, signer.Address()), - } + return newTransactionFromTemplate( + templates.CreateAccount(keys, contracts, signer.Address()), + signer, + ) +} + +func newTransactionFromTemplate(templateTx *flow.Transaction, signer *Account) (*Transaction, error) { + tx := &Transaction{tx: templateTx} err := tx.SetSigner(signer) if err != nil { From 5aac252ac8d07473989c724d0cfd272fd25ba0a7 Mon Sep 17 00:00:00 2001 From: Gregor Gololicic Date: Thu, 15 Apr 2021 17:45:54 +0200 Subject: [PATCH 090/137] comments --- pkg/flowcli/services/transactions.go | 3 +++ 1 file changed, 3 insertions(+) diff --git a/pkg/flowcli/services/transactions.go b/pkg/flowcli/services/transactions.go index 99741f1d6..5f1a9e118 100644 --- a/pkg/flowcli/services/transactions.go +++ b/pkg/flowcli/services/transactions.go @@ -79,6 +79,7 @@ func (t *Transactions) GetStatus( return tx, result, err } +// Build builds a transaction with specified payer, proposer and authorizer func (t *Transactions) Build( proposer string, authorizer []string, @@ -169,6 +170,7 @@ func (t *Transactions) Sign( return tx.Sign() } +// SendSigned sends the transaction that is already signed func (t *Transactions) SendSigned( signedFilename string, ) (*flow.Transaction, *flow.TransactionResult, error) { @@ -293,6 +295,7 @@ func (t *Transactions) SendForAddressWithCode( return sentTx, res, err } +// getAddressFromStringOrConfig try to parse value as address or as an account from the config func getAddressFromStringOrConfig(value string, project *project.Project) (flow.Address, error) { if util.ValidAddress(value) { return flow.HexToAddress(value), nil From 1645e45ba274cfdd354297549f9af5143a7f0ead Mon Sep 17 00:00:00 2001 From: Gregor Gololicic Date: Thu, 15 Apr 2021 17:59:41 +0200 Subject: [PATCH 091/137] refactor prepare, remove unused code --- pkg/flowcli/services/accounts.go | 141 ++++++++++--------------------- 1 file changed, 45 insertions(+), 96 deletions(-) diff --git a/pkg/flowcli/services/accounts.go b/pkg/flowcli/services/accounts.go index da76b852a..d44120215 100644 --- a/pkg/flowcli/services/accounts.go +++ b/pkg/flowcli/services/accounts.go @@ -19,12 +19,10 @@ package services import ( - "context" "fmt" "strings" "github.com/onflow/flow-cli/pkg/flowcli" - "github.com/onflow/flow-cli/pkg/flowcli/config" "github.com/onflow/flow-cli/pkg/flowcli/gateway" "github.com/onflow/flow-cli/pkg/flowcli/output" "github.com/onflow/flow-cli/pkg/flowcli/project" @@ -68,97 +66,6 @@ func (a *Accounts) Get(address string) (*flow.Account, error) { return account, err } -// Add account to the configuration -func (a *Accounts) Add( - name string, - accountAddress string, - signatureAlgorithm string, - hashingAlgorithm string, - keyIndex int, - keyHex string, - overwrite bool, - path []string, -) (*project.Account, error) { - if a.project == nil { - return nil, fmt.Errorf("missing configuration, initialize it: flow init") - } - - existingAccount := a.project.AccountByName(name) - if existingAccount != nil && !overwrite { - return nil, fmt.Errorf("account with name [%s] already exists in the config, use `overwrite` if you want to overwrite it", name) - } - - sigAlgo, hashAlgo, err := util.ConvertSigAndHashAlgo(signatureAlgorithm, hashingAlgorithm) - if err != nil { - return nil, err - } - - if keyIndex < 0 { - return nil, fmt.Errorf("key index must be positive number") - } - - address := flow.HexToAddress(accountAddress) - chainID, err := util.GetAddressNetwork(address) - if err != nil { - return nil, err - } - - confAccount := config.Account{ - Name: name, - Address: address, - ChainID: chainID, - } - - accountKey := config.AccountKey{ - Index: keyIndex, - SigAlgo: sigAlgo, - HashAlgo: hashAlgo, - } - - // TODO: discuss refactor to accounts - if keyHex != "" { - _, err := crypto.DecodePrivateKeyHex(sigAlgo, keyHex) - if err != nil { - return nil, fmt.Errorf("key hex could not be parsed") - } - - accountKey.Type = config.KeyTypeHex - accountKey.Context = make(map[string]string) - accountKey.Context[config.PrivateKeyField] = keyHex - - } else { - return nil, fmt.Errorf("private key must be provided") - } - - confAccount.Keys = []config.AccountKey{accountKey} - - account, err := project.AccountFromConfig(confAccount) - if err != nil { - return nil, err - } - // TODO: refactor context - sig, err := account.DefaultKey().Signer(context.Background()) - if err != nil { - return nil, err - } - - _, err = sig.Sign([]byte("test")) - if err != nil { - return nil, fmt.Errorf("could not sign with the new key") - } - - a.project.AddOrUpdateAccount(account) - - err = a.project.Save(path[0]) // only allow saving to one config for now - if err != nil { - return nil, err - } - - a.logger.Info("Account added to configuration\n") - - return account, nil -} - // StakingInfo returns the staking information for an account. func (a *Accounts) StakingInfo(accountAddress string) (*cadence.Value, *cadence.Value, error) { a.logger.StartProgress(fmt.Sprintf("Fetching info for %s...", accountAddress)) @@ -254,7 +161,12 @@ func (a *Accounts) Create( return nil, err } - sentTx, err := a.gateway.SendTransaction(tx) + tx, err = a.prepareTransaction(tx, signer) + if err != nil { + return nil, err + } + + sentTx, err := a.gateway.SendSignedTransaction(tx) if err != nil { return nil, err } @@ -378,8 +290,13 @@ func (a *Accounts) addContract( } } + tx, err = a.prepareTransaction(tx, account) + if err != nil { + return nil, err + } + // send transaction with contract - sentTx, err := a.gateway.SendTransaction(tx) + sentTx, err := a.gateway.SendSignedTransaction(tx) if err != nil { return nil, err } @@ -435,7 +352,12 @@ func (a *Accounts) RemoveContract( return nil, err } - sentTx, err := a.gateway.SendTransaction(tx) + tx, err = a.prepareTransaction(tx, account) + if err != nil { + return nil, err + } + + sentTx, err := a.gateway.SendSignedTransaction(tx) if err != nil { return nil, err } @@ -455,6 +377,33 @@ func (a *Accounts) RemoveContract( return a.gateway.GetAccount(account.Address()) } +// prepareTransaction prepares transaction for sending with data from network +func (a *Accounts) prepareTransaction( + tx *project.Transaction, + account *project.Account, +) (*project.Transaction, error) { + + block, err := a.gateway.GetLatestBlock() + if err != nil { + return nil, err + } + + proposer, err := a.gateway.GetAccount(account.Address()) + if err != nil { + return nil, err + } + + tx.SetBlockReference(block). + SetProposer(proposer, 0) + + tx, err = tx.Sign() + if err != nil { + return nil, err + } + + return tx, nil +} + // AccountFromAddressAndKey get account from address and private key func accountFromAddressAndKey(address string, accountPrivateKey string) (*project.Account, error) { privateKey, err := crypto.DecodePrivateKeyHex(crypto.ECDSA_P256, accountPrivateKey) From 6a3d84610e7a8f07eec7d91cf48d1834fd3866d0 Mon Sep 17 00:00:00 2001 From: Gregor Gololicic Date: Thu, 15 Apr 2021 17:59:55 +0200 Subject: [PATCH 092/137] removed prepare and unused code --- pkg/flowcli/gateway/grpc.go | 38 +++---------------------------------- 1 file changed, 3 insertions(+), 35 deletions(-) diff --git a/pkg/flowcli/gateway/grpc.go b/pkg/flowcli/gateway/grpc.go index 13b79fc2a..688d03e7d 100644 --- a/pkg/flowcli/gateway/grpc.go +++ b/pkg/flowcli/gateway/grpc.go @@ -66,41 +66,9 @@ func (g *GrpcGateway) GetAccount(address flow.Address) (*flow.Account, error) { return account, nil } -// PrepareTransactionPayload prepares the payload for the transaction from the network -func (g *GrpcGateway) PrepareTransactionPayload(tx *project.Transaction) (*project.Transaction, error) { - proposalAddress := tx.Signer().Address() - if tx.Proposer() != nil { // default proposer is signer - proposalAddress = tx.Proposer().Address() - } - - proposer, err := g.GetAccount(proposalAddress) - if err != nil { - return nil, err - } - - proposerKey := proposer.Keys[tx.Signer().DefaultKey().Index()] - - sealed, err := g.client.GetLatestBlockHeader(g.ctx, true) - if err != nil { - return nil, fmt.Errorf("failed to get latest sealed block: %w", err) - } - - tx.FlowTransaction(). - SetReferenceBlockID(sealed.ID). - SetGasLimit(defaultGasLimit). - SetProposalKey(proposalAddress, proposerKey.Index, proposerKey.SequenceNumber) - - return tx, nil -} - -// SendTransaction prepares, signs and sends the transaction to the network -func (g *GrpcGateway) SendTransaction(transaction *project.Transaction) (*flow.Transaction, error) { - tx, err := g.PrepareTransactionPayload(transaction) - if err != nil { - return nil, err - } - - tx, err = tx.Sign() +// SendTransaction signs and sends the transaction to the network +func (g *GrpcGateway) SendTransaction(tx *project.Transaction) (*flow.Transaction, error) { + tx, err := tx.Sign() if err != nil { return nil, fmt.Errorf("failed to sign transaction: %w", err) } From 93b47b5912df71dc6ade7bba81704f1dabda25d6 Mon Sep 17 00:00:00 2001 From: Gregor Gololicic Date: Thu, 15 Apr 2021 18:01:57 +0200 Subject: [PATCH 093/137] remove unused code --- pkg/flowcli/gateway/gateway.go | 2 -- pkg/flowcli/gateway/grpc.go | 10 ---------- 2 files changed, 12 deletions(-) diff --git a/pkg/flowcli/gateway/gateway.go b/pkg/flowcli/gateway/gateway.go index ddd800511..e26ea793c 100644 --- a/pkg/flowcli/gateway/gateway.go +++ b/pkg/flowcli/gateway/gateway.go @@ -28,9 +28,7 @@ import ( type Gateway interface { GetAccount(flow.Address) (*flow.Account, error) - SendTransaction(*project.Transaction) (*flow.Transaction, error) SendSignedTransaction(*project.Transaction) (*flow.Transaction, error) - PrepareTransactionPayload(*project.Transaction) (*project.Transaction, error) GetTransactionResult(*flow.Transaction, bool) (*flow.TransactionResult, error) GetTransaction(flow.Identifier) (*flow.Transaction, error) ExecuteScript([]byte, []cadence.Value) (cadence.Value, error) diff --git a/pkg/flowcli/gateway/grpc.go b/pkg/flowcli/gateway/grpc.go index 688d03e7d..633b82710 100644 --- a/pkg/flowcli/gateway/grpc.go +++ b/pkg/flowcli/gateway/grpc.go @@ -66,16 +66,6 @@ func (g *GrpcGateway) GetAccount(address flow.Address) (*flow.Account, error) { return account, nil } -// SendTransaction signs and sends the transaction to the network -func (g *GrpcGateway) SendTransaction(tx *project.Transaction) (*flow.Transaction, error) { - tx, err := tx.Sign() - if err != nil { - return nil, fmt.Errorf("failed to sign transaction: %w", err) - } - - return g.SendSignedTransaction(tx) -} - // SendSignedTransaction sends a transaction to flow that is already prepared and signed func (g *GrpcGateway) SendSignedTransaction(transaction *project.Transaction) (*flow.Transaction, error) { tx := transaction.FlowTransaction() From dc0022d13039b5aa22728a83a4dfb1b5e278c87d Mon Sep 17 00:00:00 2001 From: Gregor Gololicic Date: Thu, 15 Apr 2021 18:06:15 +0200 Subject: [PATCH 094/137] refactor project for tx prepare and improved performance --- pkg/flowcli/services/project.go | 15 ++++++++++++++- 1 file changed, 14 insertions(+), 1 deletion(-) diff --git a/pkg/flowcli/services/project.go b/pkg/flowcli/services/project.go index 07fd2ffe2..632f95a1b 100644 --- a/pkg/flowcli/services/project.go +++ b/pkg/flowcli/services/project.go @@ -136,6 +136,11 @@ func (p *Project) Deploy(network string, update bool) ([]*contracts.Contract, er strings.Join(p.project.AccountNamesForNetwork(network), ","), )) + block, err := p.gateway.GetLatestBlock() + if err != nil { + return nil, err + } + deployErr := false for _, contract := range orderedContracts { targetAccount := p.project.AccountByAddress(contract.Target().String()) @@ -172,7 +177,15 @@ func (p *Project) Deploy(network string, update bool) ([]*contracts.Contract, er } } - sentTx, err := p.gateway.SendTransaction(tx) + tx.SetBlockReference(block). + SetProposer(targetAccountInfo, 0) + + tx, err = tx.Sign() + if err != nil { + return nil, err + } + + sentTx, err := p.gateway.SendSignedTransaction(tx) if err != nil { p.logger.Error(err.Error()) deployErr = true From 6fe699e3c550eaf83f0c6da94fb714e025aefa97 Mon Sep 17 00:00:00 2001 From: Gregor Gololicic Date: Thu, 15 Apr 2021 18:24:22 +0200 Subject: [PATCH 095/137] test fixes --- pkg/flowcli/services/accounts_test.go | 60 +++++++++-------------- pkg/flowcli/services/transactions_test.go | 21 +++----- tests/mockGateway.go | 8 --- 3 files changed, 30 insertions(+), 59 deletions(-) diff --git a/pkg/flowcli/services/accounts_test.go b/pkg/flowcli/services/accounts_test.go index 406a7eb4e..38dc5fba0 100644 --- a/pkg/flowcli/services/accounts_test.go +++ b/pkg/flowcli/services/accounts_test.go @@ -43,16 +43,24 @@ func TestAccounts(t *testing.T) { mock := &tests.MockGateway{} + mock.GetLatestBlockMock = func() (*flow.Block, error) { + return tests.NewBlock(), nil + } + + mock.GetTransactionResultMock = func(tx *flow.Transaction) (*flow.TransactionResult, error) { + return tests.NewTransactionResult(nil), nil + } + + mock.GetAccountMock = func(address flow.Address) (*flow.Account, error) { + return tests.NewAccountWithAddress(address.String()), nil + } + proj, err := project.Init(crypto.ECDSA_P256, crypto.SHA3_256) assert.NoError(t, err) accounts := NewAccounts(mock, proj, output.NewStdoutLogger(output.NoneLog)) t.Run("Get an Account", func(t *testing.T) { - mock.GetAccountMock = func(address flow.Address) (*flow.Account, error) { - return tests.NewAccountWithAddress(address.String()), nil - } - account, err := accounts.Get(serviceAddress) assert.NoError(t, err) @@ -62,7 +70,7 @@ func TestAccounts(t *testing.T) { t.Run("Create an Account", func(t *testing.T) { newAddress := "192440c99cb17282" - mock.SendTransactionMock = func(tx *project.Transaction) (*flow.Transaction, error) { + mock.SendSignedTransactionMock = func(tx *project.Transaction) (*flow.Transaction, error) { assert.Equal(t, tx.FlowTransaction().Authorizers[0].String(), serviceAddress) assert.Equal(t, tx.Signer().Address().String(), serviceAddress) @@ -73,10 +81,12 @@ func TestAccounts(t *testing.T) { return tests.NewAccountCreateResult(newAddress), nil } + compareAddress := serviceAddress mock.GetAccountMock = func(address flow.Address) (*flow.Account, error) { - assert.Equal(t, address.String(), newAddress) + assert.Equal(t, address.String(), compareAddress) + compareAddress = newAddress - return tests.NewAccountWithAddress(newAddress), nil + return tests.NewAccountWithAddress(address.String()), nil } a, err := accounts.Create(serviceName, []string{pubKey}, sigAlgo, hashAlgo, nil) @@ -89,7 +99,7 @@ func TestAccounts(t *testing.T) { t.Run("Create an Account with Contract", func(t *testing.T) { newAddress := "192440c99cb17282" - mock.SendTransactionMock = func(tx *project.Transaction) (*flow.Transaction, error) { + mock.SendSignedTransactionMock = func(tx *project.Transaction) (*flow.Transaction, error) { assert.Equal(t, tx.FlowTransaction().Authorizers[0].String(), serviceAddress) assert.Equal(t, tx.Signer().Address().String(), serviceAddress) assert.True(t, strings.Contains(string(tx.FlowTransaction().Script), "acct.contracts.add")) @@ -102,9 +112,7 @@ func TestAccounts(t *testing.T) { } mock.GetAccountMock = func(address flow.Address) (*flow.Account, error) { - assert.Equal(t, address.String(), newAddress) - - return tests.NewAccountWithAddress(newAddress), nil + return tests.NewAccountWithAddress(address.String()), nil } a, err := accounts.Create(serviceName, []string{pubKey}, sigAlgo, hashAlgo, []string{"Hello:../../../tests/Hello.cdc"}) @@ -115,7 +123,7 @@ func TestAccounts(t *testing.T) { }) t.Run("Contract Add for Account", func(t *testing.T) { - mock.SendTransactionMock = func(tx *project.Transaction) (*flow.Transaction, error) { + mock.SendSignedTransactionMock = func(tx *project.Transaction) (*flow.Transaction, error) { assert.Equal(t, tx.FlowTransaction().Authorizers[0].String(), serviceAddress) assert.Equal(t, tx.Signer().Address().String(), serviceAddress) assert.True(t, strings.Contains(string(tx.FlowTransaction().Script), "signer.contracts.add")) @@ -123,14 +131,6 @@ func TestAccounts(t *testing.T) { return tests.NewTransaction(), nil } - mock.GetTransactionResultMock = func(tx *flow.Transaction) (*flow.TransactionResult, error) { - return tests.NewTransactionResult(nil), nil - } - - mock.GetAccountMock = func(address flow.Address) (*flow.Account, error) { - return tests.NewAccountWithAddress(address.String()), nil - } - a, err := accounts.AddContract(serviceName, "Hello", "../../../tests/Hello.cdc", false) assert.NotNil(t, a) @@ -139,7 +139,7 @@ func TestAccounts(t *testing.T) { }) t.Run("Contract Update for Account", func(t *testing.T) { - mock.SendTransactionMock = func(tx *project.Transaction) (*flow.Transaction, error) { + mock.SendSignedTransactionMock = func(tx *project.Transaction) (*flow.Transaction, error) { assert.Equal(t, tx.FlowTransaction().Authorizers[0].String(), serviceAddress) assert.Equal(t, tx.Signer().Address().String(), serviceAddress) assert.True(t, strings.Contains(string(tx.FlowTransaction().Script), "signer.contracts.update__experimental")) @@ -147,14 +147,6 @@ func TestAccounts(t *testing.T) { return tests.NewTransaction(), nil } - mock.GetTransactionResultMock = func(tx *flow.Transaction) (*flow.TransactionResult, error) { - return tests.NewTransactionResult(nil), nil - } - - mock.GetAccountMock = func(address flow.Address) (*flow.Account, error) { - return tests.NewAccountWithAddress(address.String()), nil - } - account, err := accounts.AddContract(serviceName, "Hello", "../../../tests/Hello.cdc", true) assert.NotNil(t, account) @@ -163,7 +155,7 @@ func TestAccounts(t *testing.T) { }) t.Run("Contract Remove for Account", func(t *testing.T) { - mock.SendTransactionMock = func(tx *project.Transaction) (*flow.Transaction, error) { + mock.SendSignedTransactionMock = func(tx *project.Transaction) (*flow.Transaction, error) { assert.Equal(t, tx.FlowTransaction().Authorizers[0].String(), serviceAddress) assert.Equal(t, tx.Signer().Address().String(), serviceAddress) assert.True(t, strings.Contains(string(tx.FlowTransaction().Script), "signer.contracts.remove")) @@ -171,14 +163,6 @@ func TestAccounts(t *testing.T) { return tests.NewTransaction(), nil } - mock.GetTransactionResultMock = func(tx *flow.Transaction) (*flow.TransactionResult, error) { - return tests.NewTransactionResult(nil), nil - } - - mock.GetAccountMock = func(address flow.Address) (*flow.Account, error) { - return tests.NewAccountWithAddress(address.String()), nil - } - account, err := accounts.RemoveContract("Hello", serviceName) assert.NotNil(t, account) diff --git a/pkg/flowcli/services/transactions_test.go b/pkg/flowcli/services/transactions_test.go index 138844dcd..4fe82a1f9 100644 --- a/pkg/flowcli/services/transactions_test.go +++ b/pkg/flowcli/services/transactions_test.go @@ -33,15 +33,18 @@ import ( func TestTransactions(t *testing.T) { mock := &tests.MockGateway{} - // default implementations - mock.PrepareTransactionPayloadMock = func(tx *project.Transaction) (*project.Transaction, error) { - return tx, nil - } - mock.SendSignedTransactionMock = func(tx *project.Transaction) (*flow.Transaction, error) { return tx.FlowTransaction(), nil } + mock.GetLatestBlockMock = func() (*flow.Block, error) { + return tests.NewBlock(), nil + } + + mock.GetAccountMock = func(address flow.Address) (*flow.Account, error) { + return tests.NewAccountWithAddress(address.String()), nil + } + proj, err := project.Init(crypto.ECDSA_P256, crypto.SHA3_256) assert.NoError(t, err) @@ -87,14 +90,6 @@ func TestTransactions(t *testing.T) { return tests.NewTransaction(), nil } - mock.GetLatestBlockMock = func() (*flow.Block, error) { - return tests.NewBlock(), nil - } - - mock.GetAccountMock = func(address flow.Address) (*flow.Account, error) { - return tests.NewAccountWithAddress(address.String()), nil - } - _, _, err := transactions.Send( "../../../tests/transaction.cdc", serviceName, diff --git a/tests/mockGateway.go b/tests/mockGateway.go index c05f8e6f5..a1b4ff012 100644 --- a/tests/mockGateway.go +++ b/tests/mockGateway.go @@ -50,18 +50,10 @@ func (g *MockGateway) GetAccount(address flow.Address) (*flow.Account, error) { return g.GetAccountMock(address) } -func (g *MockGateway) SendTransaction(tx *project.Transaction) (*flow.Transaction, error) { - return g.SendTransactionMock(tx) -} - func (g *MockGateway) SendSignedTransaction(tx *project.Transaction) (*flow.Transaction, error) { return g.SendSignedTransactionMock(tx) } -func (g *MockGateway) PrepareTransactionPayload(tx *project.Transaction) (*project.Transaction, error) { - return g.PrepareTransactionPayloadMock(tx) -} - func (g *MockGateway) GetTransactionResult(tx *flow.Transaction, waitSeal bool) (*flow.TransactionResult, error) { return g.GetTransactionResultMock(tx) } From e49d33c99c31ffac906997df51da78fc9e864cc9 Mon Sep 17 00:00:00 2001 From: Gregor Gololicic Date: Thu, 15 Apr 2021 18:28:22 +0200 Subject: [PATCH 096/137] linted --- internal/transactions/build.go | 3 ++- internal/transactions/send-signed.go | 3 ++- pkg/flowcli/gateway/grpc.go | 4 ---- pkg/flowcli/project/transaction.go | 25 ++++--------------------- 4 files changed, 8 insertions(+), 27 deletions(-) diff --git a/internal/transactions/build.go b/internal/transactions/build.go index 75ac599a1..327c7dbc1 100644 --- a/internal/transactions/build.go +++ b/internal/transactions/build.go @@ -18,9 +18,10 @@ package transactions import ( + "github.com/spf13/cobra" + "github.com/onflow/flow-cli/internal/command" "github.com/onflow/flow-cli/pkg/flowcli/services" - "github.com/spf13/cobra" ) type flagsBuild struct { diff --git a/internal/transactions/send-signed.go b/internal/transactions/send-signed.go index 9129caaa2..0dbac74df 100644 --- a/internal/transactions/send-signed.go +++ b/internal/transactions/send-signed.go @@ -19,9 +19,10 @@ package transactions import ( + "github.com/spf13/cobra" + "github.com/onflow/flow-cli/internal/command" "github.com/onflow/flow-cli/pkg/flowcli/services" - "github.com/spf13/cobra" ) type flagsSendSigned struct { diff --git a/pkg/flowcli/gateway/grpc.go b/pkg/flowcli/gateway/grpc.go index 633b82710..a73838b2b 100644 --- a/pkg/flowcli/gateway/grpc.go +++ b/pkg/flowcli/gateway/grpc.go @@ -31,10 +31,6 @@ import ( "github.com/onflow/flow-cli/pkg/flowcli/project" ) -const ( - defaultGasLimit = 1000 -) - // GrpcGateway is a gateway implementation that uses the Flow Access gRPC API. type GrpcGateway struct { client *client.Client diff --git a/pkg/flowcli/project/transaction.go b/pkg/flowcli/project/transaction.go index a861b40d4..f1cfbdfc0 100644 --- a/pkg/flowcli/project/transaction.go +++ b/pkg/flowcli/project/transaction.go @@ -35,8 +35,6 @@ import ( "github.com/onflow/flow-cli/pkg/flowcli/util" ) -type signerRole string - const ( defaultGasLimit = 1000 ) @@ -151,10 +149,9 @@ func newTransactionFromTemplate(templateTx *flow.Transaction, signer *Account) ( // Transaction builder of flow transactions type Transaction struct { - signer *Account - signerRole signerRole - proposer *flow.Account - tx *flow.Transaction + signer *Account + proposer *flow.Account + tx *flow.Transaction } // Signer get signer @@ -293,19 +290,5 @@ func (t *Transaction) Sign() (*Transaction, error) { // shouldSignEnvelope checks if signer should sign envelope or payload func (t *Transaction) shouldSignEnvelope() bool { // if signer is payer - if t.signer.address == t.tx.Payer { - return true - /* - // and either authorizer or proposer - special case - if len(t.tx.Authorizers) == 1 && t.tx.Authorizers[0] == t.signer.address { - return true - } else if t.signer.address == t.tx.ProposalKey.Address { - return true - } else { - // ? - } - */ - } - - return false + return t.signer.address == t.tx.Payer // todo discuss } From bbe8fb62424d5b067f3c8d21d3dd7807fd3d5fcb Mon Sep 17 00:00:00 2001 From: Gregor Gololicic Date: Thu, 15 Apr 2021 19:47:51 +0200 Subject: [PATCH 097/137] updated docs --- docs/build-transactions.md | 175 ++++++++++++++++++++++++++ docs/send-signed-transactions.md | 141 +++++++++++++++++++++ docs/send-transactions.md | 63 +++++++--- docs/sign-transaction.md | 208 +++---------------------------- internal/transactions/send.go | 2 +- internal/transactions/sign.go | 2 +- 6 files changed, 380 insertions(+), 211 deletions(-) create mode 100644 docs/build-transactions.md create mode 100644 docs/send-signed-transactions.md diff --git a/docs/build-transactions.md b/docs/build-transactions.md new file mode 100644 index 000000000..8aa8a6aee --- /dev/null +++ b/docs/build-transactions.md @@ -0,0 +1,175 @@ +--- +title: Build a Transaction with the Flow CLI +sidebar_title: Build a Transaction +description: How to build a Flow transaction from the command line +--- + +The Flow CLI provides a command to build a transactions with options to specify +authorizer accounts, payer account and proposer account. + +Build command don't produce any signatures and +should be used with the `sign` and `send-signed` commands. + +Use this functionality in the following order: +1. Use this command to build the transaction +2. Use the sign command to sign with all accounts specified in the build process +3. Use send signed command to submit the signed transaction to the network. + +```shell +flow transactions build +``` + +## Example Usage + +```shell +> flow transactions build ./transaction.cdc --signer alice --proposer bob --payer charlie --arg "String:Meow" + +ID e8c0a69952fbe50a66703985e220307c8d44b8fa36c76cbca03f8c43d0167847 +Payer e03daebed8ca0615 +Authorizers [f3fcd2c1a78f5eee] + +Proposal Key: + Address 179b6b1cb6755e31 + Index 0 + Sequence 1 + +No Payload Signatures + +No Envelope Signatures + + +Arguments (1): + - Argument 0: {"type":"String","value":"Meow"} + + +Code + +transaction(greeting: String) { + let guest: Address + + prepare(authorizer: AuthAccount) { + self.guest = authorizer.address + } + + execute { + log(greeting.concat(",").concat(self.guest.toString())) + } +} + + +Payload: +f9013df90138b8d17472616e...73616374696f6e286eeec0c0 +``` + +## Arguments + +### Code Filename + +- Name: `filename` +- Valid inputs: Any filename and path valid on the system. + +The first argument is a path to a Cadence file containing the +transaction to be executed. + + +## Flags + + +### Payer + +- Flag: `--payer` +- Valid Inputs: Flow address or account name from configuration. +- Default: service account + +Specify account address that will be paying for the transaction. +Read more about payers [here](https://docs.onflow.org/concepts/accounts-and-keys/). + +### Proposer + +- Flag: `--proposer` +- Valid inputs: Flow address or account name from configuration. +- Default: service account + +Specify a name of the account that is proposing the transaction. +Account must be defined in flow configuration. + +### Proposer Key Index + +- Flag: `--proposer-key-index` +- Valid inputs: number of existing key index +- Default: 0 + +Specify key index for the proposer account. + +### Authorizer + +- Flag: `--authorizer` +- Valid Inputs: Flow address or account name from configuration. +- Default: service account + +Additional authorizer addresses to add to the transaction. +Read more about authorizers [here](https://docs.onflow.org/concepts/accounts-and-keys/). + +### Host + +- Flag: `--host` +- Valid inputs: an IP address or hostname. +- Default: `127.0.0.1:3569` (Flow Emulator) + +Specify the hostname of the Access API that will be +used to execute the commands. + +### Network + +- Flag: `--network` +- Short Flag: `-n` +- Valid inputs: the name of a network defined in the configuration (`flow.json`) + +Specify which network you want the command to use for execution. + +### Filter + +- Flag: `--filter` +- Short Flag: `-x` +- Valid inputs: case-sensitive name of the result property. + +Specify any property name from the result you want to return as the only value. + +### Output + +- Flag: `--output` +- Short Flag: `-o` +- Valid inputs: `json`, `inline` + +Specify in which format you want to display the result. + +### Save + +- Flag: `--save` +- Short Flag: `-s` +- Valid inputs: valid filename + +Specify the filename where you want the result to be saved. + +### Log + +- Flag: `--log` +- Short Flag: `-l` +- Valid inputs: `none`, `error`, `debug` +- Default: `info` + +Specify the log level. Control how much output you want to see while command execution. + +### Configuration + +- Flag: `--config-path` +- Short Flag: `-f` +- Valid inputs: valid filename + +Specify a filename for the configuration files, you can provide multiple configuration +files by using `-f` flag multiple times. + + + + + diff --git a/docs/send-signed-transactions.md b/docs/send-signed-transactions.md new file mode 100644 index 000000000..81819b329 --- /dev/null +++ b/docs/send-signed-transactions.md @@ -0,0 +1,141 @@ +--- +title: Send Signed Transaction with the Flow CLI +sidebar_title: Send Signed Transaction +description: How to send signed Flow transaction from the command line +--- + +The Flow CLI provides a command to send signed transactions to +any Flow Access API. + +Use this functionality in the following order: +1. Use this command to build the transaction +2. Use the sign command to sign with all accounts specified in the build process +3. Use send signed command to submit the signed transaction to the network. + +```shell +flow transactions send-signed +``` + +## Example Usage + +```shell +> flow transactions send-signed ./signed.rlp + +Status ✅ SEALED +ID b6430b35ba23849a8acb4fa1a4a1d5cce3ed4589111ecbb3984de1b6bd1ba39e +Payer a2c4941b5f3c7151 +Authorizers [a2c4941b5f3c7151] + +Proposal Key: + Address a2c4941b5f3c7151 + Index 0 + Sequence 9 + +No Payload Signatures + +Envelope Signature 0: + Address a2c4941b5f3c7151 + Signature 5391a6fed0fe...2742048166f9d5c925a8dcb78a6d8c710921d67 + Key Index 0 + + +Events: None + + +Arguments (1): + - Argument 0: {"type":"String","value":"Meow"} + + +Code + +transaction(greeting: String) { + let guest: Address + + prepare(authorizer: AuthAccount) { + self.guest = authorizer.address + } + + execute { + log(greeting.concat(",").concat(self.guest.toString())) + } +} + + +Payload: +f90184f90138...8a9462751237da2742048166f9d5c925a8dcb78a6d8c710921d67 + +``` + + +## Arguments + +### Signed Code Filename +- Name: `signed transaction filename` +- Valid inputs: Any filename and path valid on the system. + +The first argument is a path to a Cadence file containing the +transaction to be executed. + +## Flags + +### Host + +- Flag: `--host` +- Valid inputs: an IP address or hostname. +- Default: `127.0.0.1:3569` (Flow Emulator) + +Specify the hostname of the Access API that will be +used to execute the command. This flag overrides +any host defined by the `--network` flag. + +### Network + +- Flag: `--network` +- Short Flag: `-n` +- Valid inputs: the name of a network defined in the configuration (`flow.json`) + +Specify which network you want the command to use for execution. + +### Filter + +- Flag: `--filter` +- Short Flag: `-x` +- Valid inputs: a case-sensitive name of the result property. + +Specify any property name from the result you want to return as the only value. + +### Output + +- Flag: `--output` +- Short Flag: `-o` +- Valid inputs: `json`, `inline` + +Specify the format of the command results. + +### Save + +- Flag: `--save` +- Short Flag: `-s` +- Valid inputs: a path in the current filesystem. + +Specify the filename where you want the result to be saved + +### Log + +- Flag: `--log` +- Short Flag: `-l` +- Valid inputs: `none`, `error`, `debug` +- Default: `info` + +Specify the log level. Control how much output you want to see during command execution. + +### Configuration + +- Flag: `--config-path` +- Short Flag: `-f` +- Valid inputs: a path in the current filesystem. +- Default: `flow.json` + +Specify the path to the `flow.json` configuration file. +You can use the `-f` flag multiple times to merge +several configuration files. diff --git a/docs/send-transactions.md b/docs/send-transactions.md index fc2848411..8dced1570 100644 --- a/docs/send-transactions.md +++ b/docs/send-transactions.md @@ -8,20 +8,59 @@ The Flow CLI provides a command to sign and send transactions to any Flow Access API. ```shell -flow transactions send +flow transactions send ``` ## Example Usage ```shell -> flow transactions send +> flow transactions send --signer my-testnet-account \ --host access.testnet.nodes.onflow.org:9000 -ID f23582ba17322405608c0d3da79312617f8d16e118afe63e764b5e68edc5f211 -Status SEALED -Payer a2c4941b5f3c7151 -Events +Status ✅ SEALED +ID b6430b35ba23849a8acb4fa1a4a1d5cce3ed4589111ecbb3984de1b6bd1ba39e +Payer a2c4941b5f3c7151 +Authorizers [a2c4941b5f3c7151] + +Proposal Key: + Address a2c4941b5f3c7151 + Index 0 + Sequence 9 + +No Payload Signatures + +Envelope Signature 0: + Address a2c4941b5f3c7151 + Signature 5391a6fed0fe...2742048166f9d5c925a8dcb78a6d8c710921d67 + Key Index 0 + + +Events: None + + +Arguments (1): + - Argument 0: {"type":"String","value":"Meow"} + + +Code + +transaction(greeting: String) { + let guest: Address + + prepare(authorizer: AuthAccount) { + self.guest = authorizer.address + } + + execute { + log(greeting.concat(",").concat(self.guest.toString())) + } +} + + +Payload: +f90184f90138...8a9462751237da2742048166f9d5c925a8dcb78a6d8c710921d67 + ``` In the above example, the `flow.json` file would look something like this: @@ -39,8 +78,8 @@ In the above example, the `flow.json` file would look something like this: ## Arguments -### Filename -- Name: `filename` +### Code Filename +- Name: `code filename` - Valid inputs: Any filename and path valid on the system. The first argument is a path to a Cadence file containing the @@ -84,14 +123,6 @@ Arguments passed to the Cadence transaction in `Type:Value` format. The `Type` must be the same type as the corresponding parameter in the Cadence transaction code. -### Payload - -- Flag: `--payload` -- Valid inputs: any filename and path valid on the system. - -Specify the filename containing valid transaction payload that will be used for signing. -To be used with the `flow transaction sign` command. - ### Host - Flag: `--host` diff --git a/docs/sign-transaction.md b/docs/sign-transaction.md index 11f5b36ef..76a52dc02 100644 --- a/docs/sign-transaction.md +++ b/docs/sign-transaction.md @@ -4,15 +4,22 @@ sidebar_title: Sign a Transaction description: How to sign a Flow transaction from the command line --- -The Flow CLI provides a command to sign transactions with options to specify -authorizator accounts, payer accounts and proposer accounts. +The Flow CLI provides a command to sign transactions with options to specify +authorizer accounts, payer accounts and proposer accounts. -`flow transctions sign` +Use this functionality in the following order: +1. Use this command to build the transaction +2. Use the sign command to sign with all accounts specified in the build process +3. Use send signed command to submit the signed transaction to the network. + +```shell +flow transactions sign +``` ## Example Usage ```shell -> flow transactions sign ./tests/transaction.cdc --arg String:"Meow" +> flow transactions sign ./built.rlp --signer alice Hash b03b18a8d9d30ff7c9f0fdaa80fcaab242c2f36eedb687dd9b368326311fe376 Payer f8d6e0586b0a20c7 @@ -54,143 +61,14 @@ Payload: f90184f...a199bfd9b837a11a0885f9104b54014750f5e3e5bfe4a5795968b0df86769dd54c0 ``` - -### Example Sign and Send - -```shell - -> flow transactions sign ./tests/transaction.cdc --arg String:"Meow" --filter Payload --save payload1 -💾 result saved to: payload1 - - -> flow transactions send --payload payload1 - -Status ✅ SEALED -Hash 9a38fb25c9fedc20b008aaed7a5ff00169a178411238573d6a6a55982a645129 -Payer f8d6e0586b0a20c7 -Authorizers [f8d6e0586b0a20c7] - -Proposal Key: - Address f8d6e0586b0a20c7 - Index 0 - Sequence 6 - -Payload Signature 0: - Address f8d6e0586b0a20c7 - Signature c7ede88cfd45c7c01b2...097e4d5040f730f640c1d4ac - Key Index 0 - -Envelope Signature 0: - Address f8d6e0586b0a20c7 - Signature fb8226d6c61ddd58a2b...798e7a9be084eb622cf40f4f - Key Index 0 - - -Events: None - - -Arguments (1): - - Argument 0: {"type":"String","value":"Meow"} - - -Code - -transaction(greeting: String) { - let guest: Address - - prepare(authorizer: AuthAccount) { - self.guest = authorizer.address - } - - execute { - log(greeting.concat(",").concat(self.guest.toString())) - } -} - - -Payload: -f901cbf90138b......4649a4088797523c02d53f0c798e7a9be084eb622cf40f4f - - -``` - -### Example Different Payer and Signer - -```shell -> flow transactions sign ./tests/transaction.cdc --arg String:"Meow" --payer-address 179b6b1cb6755e31 --filter Payload --save payload1 -💾 result saved to: payload1 - - -> flow transactions sign --payload payload1 --role payer --signer alice --filter Payload --save payload2 -💾 result saved to: payload2 - - -> transactions send --payload payload2 - -Status ✅ SEALED -Hash 379ccb941b956c760f19307bbc961cc1e6bcdd7334b5941e9f55ab2151f52d43 -Payer 179b6b1cb6755e31 -Authorizers [f8d6e0586b0a20c7] - -Proposal Key: - Address f8d6e0586b0a20c7 - Index 0 - Sequence 7 - -Payload Signature 0: - Address f8d6e0586b0a20c7 - Signature f940766ce...3d2001e0b4b795e4f35345a18a04abc87466f6d0f1617b949b - Key Index 0 - -Envelope Signature 0: - Address f8d6e0586b0a20c7 - Signature 000621...6ff9cdef2d62fb5e98ebbc7a7bacdb505ab799522c76f1d6e5aa3 - Key Index 0 - -Envelope Signature 1: - Address 179b6b1cb6755e31 - Signature c423ebae6...a855564dc927dcd3f764b81c67048d7936af131abe1952dc80 - Key Index 0 - - -Events: None - - -Arguments (1): - - Argument 0: {"type":"String","value":"Meow"} - - -Code - -transaction(greeting: String) { - let guest: Address - - prepare(authorizer: AuthAccount) { - self.guest = authorizer.address - } - - execute { - log(greeting.concat(",").concat(self.guest.toString())) - } -} - - -Payload: -f90211f901...7a6520417574684163636f756e7429207b0a2020202073656c662e67756573 - -``` - - ## Arguments -### Filename (optional) -- Name: `filename` +### Built Transaction Filename +- Name: `built transaction filename` - Valid inputs: Any filename and path valid on the system. -The first argument is a path to a Cadence file containing the -transaction to be executed. This argument is optional as we can -use `--payload` flag if we already have created a transaction and -we would just like to sign it. +Specify the filename containing valid transaction payload that will be used for signing. +To be used with the `flow transaction build` command. ## Flags @@ -201,62 +79,6 @@ we would just like to sign it. Specify the name of the account that will be used to sign the transaction. -### Payload - -- Flag: `--payload` -- Valid inputs: any filename and path valid on the system. - -Specify the filename containing valid transaction payload that will be used for signing. - -### Proposer - -- Flag: `--proposer` -- Valid inputs: account from configuration. - -Specify a name of the account that is proposing the transaction. -Account must be defined in flow configuration. - -### Role - -- Flag: `--role` -- Valid inputs: authorizer, proposer, payer. - -Specify a role of the signer. -Read more about signer roles [here](https://docs.onflow.org/concepts/accounts-and-keys/). - -### Add Authorizers - -- Flag: `--add-authorizer` -- Valid Input: Flow account address. - -Additional authorizer addresses to add to the transaction. -Read more about authorizers [here](https://docs.onflow.org/concepts/accounts-and-keys/). - -### Payer Address - -- Flag: `--payer-address` -- Valid Input: Flow account address. - -Specify account address that will be paying for the transaction. -Read more about payers [here](https://docs.onflow.org/concepts/accounts-and-keys/). - -### Arguments - -- Flag: `--arg` -- Valid inputs: argument in `Type:Value` format. - -Arguments passed to the Cadence transaction in `Type:Value` format. -The `Type` must be the same as type in the transaction source code for that argument. - -### Arguments JSON - -- Flag: `--argsJSON` -- Valid inputs: arguments in JSON-Cadence form. - -Arguments passed to the Cadence transaction in `Type:Value` format. -The `Type` must be the same type as the corresponding parameter -in the Cadence transaction code. - ### Host - Flag: `--host` - Valid inputs: an IP address or hostname. diff --git a/internal/transactions/send.go b/internal/transactions/send.go index f52b8e5ff..b4c0fd825 100644 --- a/internal/transactions/send.go +++ b/internal/transactions/send.go @@ -40,7 +40,7 @@ var sendFlags = flagsSend{} var SendCommand = &command.Command{ Cmd: &cobra.Command{ - Use: "send ", + Use: "send ", Short: "Send a transaction", Args: cobra.MaximumNArgs(1), Example: `flow transactions send tx.cdc --arg String:"Hello world"`, diff --git a/internal/transactions/sign.go b/internal/transactions/sign.go index 2d4931c29..407ccc77a 100644 --- a/internal/transactions/sign.go +++ b/internal/transactions/sign.go @@ -33,7 +33,7 @@ var signFlags = flagsSign{} var SignCommand = &command.Command{ Cmd: &cobra.Command{ - Use: "sign ", + Use: "sign ", Short: "Sign built transaction", Example: "flow transactions sign ./built.rlp --signer alice", Args: cobra.ExactArgs(1), From 1bda56969ce444834453e1ba091a7786723abb49 Mon Sep 17 00:00:00 2001 From: Gregor Gololicic Date: Thu, 15 Apr 2021 19:50:09 +0200 Subject: [PATCH 098/137] fixed tests --- pkg/flowcli/services/accounts_test.go | 4 ++-- tests/e2e_test.go | 1 + 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/pkg/flowcli/services/accounts_test.go b/pkg/flowcli/services/accounts_test.go index 2a7f0b141..84a6e6003 100644 --- a/pkg/flowcli/services/accounts_test.go +++ b/pkg/flowcli/services/accounts_test.go @@ -79,7 +79,7 @@ func TestAccounts(t *testing.T) { return tests.NewAccountWithAddress(newAddress), nil } - a, err := accounts.Create(serviceName, []string{pubKey}, sigAlgo, hashAlgo, nil) + a, err := accounts.Create(serviceName, []string{pubKey}, []int{1000}, sigAlgo, hashAlgo, nil) assert.NotNil(t, a) assert.NoError(t, err) @@ -107,7 +107,7 @@ func TestAccounts(t *testing.T) { return tests.NewAccountWithAddress(newAddress), nil } - a, err := accounts.Create(serviceName, []string{pubKey}, sigAlgo, hashAlgo, []string{"Hello:../../../tests/Hello.cdc"}) + a, err := accounts.Create(serviceName, []string{pubKey}, []int{1000}, sigAlgo, hashAlgo, []string{"Hello:../../../tests/Hello.cdc"}) assert.NotNil(t, a) assert.NoError(t, err) diff --git a/tests/e2e_test.go b/tests/e2e_test.go index ed0d6db39..f808c2a38 100644 --- a/tests/e2e_test.go +++ b/tests/e2e_test.go @@ -71,6 +71,7 @@ func TestAccount(t *testing.T) { account, err := accounts.Create( emulatorAccount, keys, + []int{1000}, "ECDSA_P256", "SHA3_256", []string{}, From c0739874e2abc5020b8e41034394d757416f95b3 Mon Sep 17 00:00:00 2001 From: Gregor Gololicic Date: Thu, 15 Apr 2021 19:51:33 +0200 Subject: [PATCH 099/137] fixed error --- pkg/flowcli/services/accounts.go | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/pkg/flowcli/services/accounts.go b/pkg/flowcli/services/accounts.go index a3ac9c380..045ada9b2 100644 --- a/pkg/flowcli/services/accounts.go +++ b/pkg/flowcli/services/accounts.go @@ -217,7 +217,11 @@ func (a *Accounts) Create( // if more than one key is provided and at least one weight is specified, make sure there isn't a missmatch if len(keys) > 1 && len(keyWeights) > 0 && len(keys) != len(keyWeights) { - return nil, fmt.Errorf("number of keys and weights provided must match, provided keys %s") + return nil, fmt.Errorf( + "number of keys and weights provided must match, number of provided keys: %d, number of provided key weights: %d", + len(keys), + len(keyWeights), + ) } signer := a.project.AccountByName(signerName) From 0a443026f873c9b567e62b296d059f743cb0a1ee Mon Sep 17 00:00:00 2001 From: Gregor Gololicic Date: Thu, 15 Apr 2021 20:38:56 +0200 Subject: [PATCH 100/137] add exception for init command on config check --- internal/command/command.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/internal/command/command.go b/internal/command/command.go index 2cf4cf64f..9c6171a00 100644 --- a/internal/command/command.go +++ b/internal/command/command.go @@ -152,7 +152,7 @@ func (c Command) AddToParent(parent *cobra.Command) { // initialize project but ignore error since config can be missing proj, err := project.Load(flags.ConfigPath) // here we ignore if config does not exist as some commands don't require it - if !errors.Is(err, config.ErrDoesNotExist) { + if !errors.Is(err, config.ErrDoesNotExist) && cmd.CommandPath() != "flow init" { // ignore configs errors if we are doing init config handleError("Config Error", err) } From 498221dddc2d77d65dd1ab40cbea0c43a599aac0 Mon Sep 17 00:00:00 2001 From: Gregor Gololicic Date: Fri, 16 Apr 2021 14:10:39 +0200 Subject: [PATCH 101/137] comment remove --- internal/transactions/build.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/internal/transactions/build.go b/internal/transactions/build.go index 327c7dbc1..6704ae8f6 100644 --- a/internal/transactions/build.go +++ b/internal/transactions/build.go @@ -50,7 +50,7 @@ var BuildCommand = &command.Command{ services *services.Services, ) (command.Result, error) { - // proposer key index? + globalFlags.Filter = "payload" build, err := services.Transactions.Build( buildFlags.Proposer, From dcc8a64b5ab8c48d1a0895243b2e160a7dd57e80 Mon Sep 17 00:00:00 2001 From: Gregor Gololicic Date: Fri, 16 Apr 2021 14:39:54 +0200 Subject: [PATCH 102/137] make global flags exported and use config path in emulator --- internal/command/command.go | 42 ++++++++++++++++++------------------- internal/emulator/start.go | 4 +++- 2 files changed, 24 insertions(+), 22 deletions(-) diff --git a/internal/command/command.go b/internal/command/command.go index 2cf4cf64f..1dca5db10 100644 --- a/internal/command/command.go +++ b/internal/command/command.go @@ -74,7 +74,7 @@ const ( logLevelNone = "none" ) -var flags = GlobalFlags{ +var Flags = GlobalFlags{ Filter: "", Format: formatText, Save: "", @@ -87,58 +87,58 @@ var flags = GlobalFlags{ // InitFlags init all the global persistent flags func InitFlags(cmd *cobra.Command) { cmd.PersistentFlags().StringVarP( - &flags.Filter, + &Flags.Filter, "filter", "x", - flags.Filter, + Flags.Filter, "Filter result values by property name", ) cmd.PersistentFlags().StringVarP( - &flags.Host, + &Flags.Host, "host", "", - flags.Host, + Flags.Host, "Flow Access API host address", ) cmd.PersistentFlags().StringVarP( - &flags.Format, + &Flags.Format, "output", "o", - flags.Format, + Flags.Format, "Output format, options: \"text\", \"json\", \"inline\"", ) cmd.PersistentFlags().StringVarP( - &flags.Save, + &Flags.Save, "save", "s", - flags.Save, + Flags.Save, "Save result to a filename", ) cmd.PersistentFlags().StringVarP( - &flags.Log, + &Flags.Log, "log", "l", - flags.Log, + Flags.Log, "Log level, options: \"debug\", \"info\", \"error\", \"none\"", ) cmd.PersistentFlags().StringSliceVarP( - &flags.ConfigPath, + &Flags.ConfigPath, "config-path", "f", - flags.ConfigPath, + Flags.ConfigPath, "Path to flow configuration file", ) cmd.PersistentFlags().StringVarP( - &flags.Network, + &Flags.Network, "network", "n", - flags.Network, + Flags.Network, "Network from configuration file", ) } @@ -150,32 +150,32 @@ func InitFlags(cmd *cobra.Command) { func (c Command) AddToParent(parent *cobra.Command) { c.Cmd.Run = func(cmd *cobra.Command, args []string) { // initialize project but ignore error since config can be missing - proj, err := project.Load(flags.ConfigPath) + proj, err := project.Load(Flags.ConfigPath) // here we ignore if config does not exist as some commands don't require it if !errors.Is(err, config.ErrDoesNotExist) { handleError("Config Error", err) } - host, err := resolveHost(proj, flags.Host, flags.Network) + host, err := resolveHost(proj, Flags.Host, Flags.Network) handleError("Host Error", err) clientGateway, err := createGateway(host) handleError("Gateway Error", err) - logger := createLogger(flags.Log, flags.Format) + logger := createLogger(Flags.Log, Flags.Format) service := services.NewServices(clientGateway, proj, logger) // run command - result, err := c.Run(cmd, args, flags, service) + result, err := c.Run(cmd, args, Flags, service) handleError("Command Error", err) // format output result - formattedResult, err := formatResult(result, flags.Filter, flags.Format) + formattedResult, err := formatResult(result, Flags.Filter, Flags.Format) handleError("Result", err) // output result - err = outputResult(formattedResult, flags.Save) + err = outputResult(formattedResult, Flags.Save) handleError("Output Error", err) } diff --git a/internal/emulator/start.go b/internal/emulator/start.go index 86990d524..b574a090b 100644 --- a/internal/emulator/start.go +++ b/internal/emulator/start.go @@ -21,6 +21,8 @@ package emulator import ( "errors" + "github.com/onflow/flow-cli/internal/command" + emulator "github.com/onflow/flow-emulator" "github.com/onflow/flow-emulator/cmd/emulator/start" @@ -65,7 +67,7 @@ func ConfiguredServiceKey( } } } else { - proj, err = project.Load(project.DefaultConfigPaths) + proj, err = project.Load(command.Flags.ConfigPath) if err != nil { if errors.Is(err, config.ErrDoesNotExist) { util.Exitf(1, "🙏 Configuration is missing, initialize it with: 'flow project init' and then rerun this command.") From 4ff1b18487b99276102f4df3ded5578fed0c6d30 Mon Sep 17 00:00:00 2001 From: Gregor Gololicic Date: Fri, 16 Apr 2021 15:10:33 +0200 Subject: [PATCH 103/137] conflict resolution --- internal/transactions/build.go | 1 + pkg/flowcli/services/transactions.go | 40 +++++++++++++++++++++++++--- 2 files changed, 37 insertions(+), 4 deletions(-) diff --git a/internal/transactions/build.go b/internal/transactions/build.go index 6704ae8f6..7e0cc66f3 100644 --- a/internal/transactions/build.go +++ b/internal/transactions/build.go @@ -60,6 +60,7 @@ var BuildCommand = &command.Command{ args[0], // code filename buildFlags.Args, buildFlags.ArgsJSON, + globalFlags.Network, ) if err != nil { return nil, err diff --git a/pkg/flowcli/services/transactions.go b/pkg/flowcli/services/transactions.go index de8e98e96..3740038fa 100644 --- a/pkg/flowcli/services/transactions.go +++ b/pkg/flowcli/services/transactions.go @@ -22,14 +22,15 @@ import ( "fmt" "strings" + "github.com/onflow/flow-cli/pkg/flowcli/contracts" + "github.com/onflow/flow-go-sdk" "github.com/onflow/flow-go-sdk/crypto" - "github.com/onflow/flow-cli/pkg/flowcli/util" - "github.com/onflow/flow-cli/pkg/flowcli/contracts" "github.com/onflow/flow-cli/pkg/flowcli/gateway" "github.com/onflow/flow-cli/pkg/flowcli/output" "github.com/onflow/flow-cli/pkg/flowcli/project" + "github.com/onflow/flow-cli/pkg/flowcli/util" ) // Transactions is a service that handles all transaction-related interactions. @@ -85,9 +86,10 @@ func (t *Transactions) Build( authorizer []string, payer string, proposerKeyIndex int, - scriptFilename string, + codeFilename string, args []string, argsJSON string, + network string, ) (*project.Transaction, error) { proposerAddress, err := getAddressFromStringOrConfig(proposer, t.project) if err != nil { @@ -125,7 +127,35 @@ func (t *Transactions) Build( SetDefaultGasLimit(). SetBlockReference(latestBlock) - err = tx.SetScriptWithArgsFromFile(scriptFilename, args, argsJSON) + code, err := util.LoadFile(codeFilename) + if err != nil { + return nil, err + } + + resolver, err := contracts.NewResolver(code) + if err != nil { + return nil, err + } + + if resolver.HasFileImports() { + if network == "" { + return nil, fmt.Errorf("missing network, specify which network to use to resolve imports in transaction code") + } + if codeFilename == "" { // when used as lib with code we don't support imports + return nil, fmt.Errorf("resolving imports in transactions not supported") + } + + code, err = resolver.ResolveImports( + codeFilename, + t.project.ContractsByNetwork(network), + t.project.AliasesForNetwork(network), + ) + if err != nil { + return nil, err + } + } + + err = tx.SetScriptWithArgs(code, args, argsJSON) if err != nil { return nil, err } @@ -198,6 +228,7 @@ func (t *Transactions) Send( signerName string, args []string, argsJSON string, + network string, ) (*flow.Transaction, *flow.TransactionResult, error) { if t.project == nil { return nil, nil, fmt.Errorf("missing configuration, initialize it: flow project init") @@ -216,6 +247,7 @@ func (t *Transactions) Send( transactionFilename, args, argsJSON, + network, ) if err != nil { return nil, nil, err From b3deedf815ef57b2e9cd2bc3d6545fde84e62890 Mon Sep 17 00:00:00 2001 From: Gregor Gololicic Date: Fri, 16 Apr 2021 15:19:07 +0200 Subject: [PATCH 104/137] conflict resolution --- internal/command/command.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/internal/command/command.go b/internal/command/command.go index 154ca4ace..30d4bdb5b 100644 --- a/internal/command/command.go +++ b/internal/command/command.go @@ -185,7 +185,7 @@ func (c Command) AddToParent(parent *cobra.Command) { handleError("Result", err) // output result - err = outputResult(formattedResult, Flags.Save, flags.Format, flags.Filter) + err = outputResult(formattedResult, Flags.Save, Flags.Format, Flags.Filter) handleError("Output Error", err) } From c3329f616396ac983fc24eda2c93d395bef8e7b9 Mon Sep 17 00:00:00 2001 From: Gregor Gololicic Date: Fri, 16 Apr 2021 15:21:50 +0200 Subject: [PATCH 105/137] conflict resolution --- internal/command/command.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/internal/command/command.go b/internal/command/command.go index b23d892ea..5e4d4a447 100644 --- a/internal/command/command.go +++ b/internal/command/command.go @@ -27,13 +27,13 @@ import ( "os" "strings" + "github.com/onflow/flow-cli/build" "github.com/onflow/flow-cli/pkg/flowcli/config" "github.com/onflow/flow-cli/pkg/flowcli/gateway" "github.com/onflow/flow-cli/pkg/flowcli/output" "github.com/onflow/flow-cli/pkg/flowcli/project" "github.com/onflow/flow-cli/pkg/flowcli/services" "github.com/onflow/flow-cli/pkg/flowcli/util" - "github.com/onflow/flow-cli/build" "github.com/onflow/flow-go-sdk/client" "github.com/psiemens/sconfig" From 4691dbcaf0cdb7045111559866b49de1b7e81ef0 Mon Sep 17 00:00:00 2001 From: Gregor Gololicic Date: Fri, 16 Apr 2021 17:05:54 +0200 Subject: [PATCH 106/137] conflicts, linted --- internal/transactions/sign.go | 1 - pkg/flowcli/contracts/resolver.go | 6 +++--- pkg/flowcli/contracts/resolver_test.go | 4 ++-- pkg/flowcli/services/scripts.go | 2 +- 4 files changed, 6 insertions(+), 7 deletions(-) diff --git a/internal/transactions/sign.go b/internal/transactions/sign.go index 515b43f50..407ccc77a 100644 --- a/internal/transactions/sign.go +++ b/internal/transactions/sign.go @@ -50,7 +50,6 @@ var SignCommand = &command.Command{ args[0], // transaction payload signFlags.Signer, globalFlags.Yes, - globalFlags.Network, ) if err != nil { return nil, err diff --git a/pkg/flowcli/contracts/resolver.go b/pkg/flowcli/contracts/resolver.go index e468bd2e3..53c8a8765 100644 --- a/pkg/flowcli/contracts/resolver.go +++ b/pkg/flowcli/contracts/resolver.go @@ -5,11 +5,11 @@ import ( "path" "strings" - "github.com/onflow/flow-go-sdk" - "github.com/onflow/cadence/runtime/ast" "github.com/onflow/cadence/runtime/common" "github.com/onflow/cadence/runtime/parser2" + "github.com/onflow/flow-go-sdk" + "github.com/onflow/flow-cli/pkg/flowcli/project" ) @@ -72,7 +72,7 @@ func (r *Resolver) getSourceTarget( contracts []project.Contract, aliases project.Aliases, ) map[string]string { - sourceTarget := make(map[string]string, 0) + sourceTarget := make(map[string]string) for _, contract := range contracts { sourceTarget[path.Clean(contract.Source)] = contract.Target.String() } diff --git a/pkg/flowcli/contracts/resolver_test.go b/pkg/flowcli/contracts/resolver_test.go index 369365679..5be635d76 100644 --- a/pkg/flowcli/contracts/resolver_test.go +++ b/pkg/flowcli/contracts/resolver_test.go @@ -4,10 +4,10 @@ import ( "regexp" "testing" - "github.com/onflow/flow-cli/pkg/flowcli/project" "github.com/onflow/flow-go-sdk" - "github.com/stretchr/testify/assert" + + "github.com/onflow/flow-cli/pkg/flowcli/project" ) func cleanCode(code []byte) string { diff --git a/pkg/flowcli/services/scripts.go b/pkg/flowcli/services/scripts.go index 96f1a16e7..b2dd97216 100644 --- a/pkg/flowcli/services/scripts.go +++ b/pkg/flowcli/services/scripts.go @@ -22,9 +22,9 @@ import ( "fmt" "github.com/onflow/cadence" - "github.com/onflow/flow-cli/pkg/flowcli/contracts" "github.com/onflow/flow-cli/pkg/flowcli" + "github.com/onflow/flow-cli/pkg/flowcli/contracts" "github.com/onflow/flow-cli/pkg/flowcli/gateway" "github.com/onflow/flow-cli/pkg/flowcli/output" "github.com/onflow/flow-cli/pkg/flowcli/project" From e5894cf1f13069cded8709f3ad4d1b0c727eeb79 Mon Sep 17 00:00:00 2001 From: Gregor Gololicic Date: Fri, 16 Apr 2021 17:14:04 +0200 Subject: [PATCH 107/137] headers added --- pkg/flowcli/contracts/resolver.go | 18 ++++++++++++++++++ pkg/flowcli/contracts/resolver_test.go | 18 ++++++++++++++++++ 2 files changed, 36 insertions(+) diff --git a/pkg/flowcli/contracts/resolver.go b/pkg/flowcli/contracts/resolver.go index 53c8a8765..3963e6114 100644 --- a/pkg/flowcli/contracts/resolver.go +++ b/pkg/flowcli/contracts/resolver.go @@ -1,3 +1,21 @@ +/* + * Flow CLI + * + * Copyright 2019-2021 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 contracts import ( diff --git a/pkg/flowcli/contracts/resolver_test.go b/pkg/flowcli/contracts/resolver_test.go index 5be635d76..d769d5721 100644 --- a/pkg/flowcli/contracts/resolver_test.go +++ b/pkg/flowcli/contracts/resolver_test.go @@ -1,3 +1,21 @@ +/* + * Flow CLI + * + * Copyright 2019-2021 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 contracts import ( From 511375352b3d0743419d1833fa7045e41d4bf475 Mon Sep 17 00:00:00 2001 From: Gregor Gololicic Date: Fri, 16 Apr 2021 19:08:47 +0200 Subject: [PATCH 108/137] log id of new transaction --- pkg/flowcli/services/transactions.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pkg/flowcli/services/transactions.go b/pkg/flowcli/services/transactions.go index 3740038fa..2cc7f1aae 100644 --- a/pkg/flowcli/services/transactions.go +++ b/pkg/flowcli/services/transactions.go @@ -263,7 +263,7 @@ func (t *Transactions) Send( return nil, nil, err } - t.logger.StartProgress("Sending Transaction...") + t.logger.StartProgress(fmt.Sprintf("Sending Transaction with ID: %s", signed.FlowTransaction().ID())) sentTx, err := t.gateway.SendSignedTransaction(signed) if err != nil { From 027c95bef4bea9376f4104be2e5ea82c3f2599e1 Mon Sep 17 00:00:00 2001 From: Gregor Gololicic Date: Mon, 19 Apr 2021 13:38:21 +0200 Subject: [PATCH 109/137] change bold color to cyan --- pkg/flowcli/util/utilities.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pkg/flowcli/util/utilities.go b/pkg/flowcli/util/utilities.go index 0c257787e..1f01e2c03 100644 --- a/pkg/flowcli/util/utilities.go +++ b/pkg/flowcli/util/utilities.go @@ -30,7 +30,7 @@ import ( var Green = color.New(color.FgGreen, color.Bold).SprintfFunc() var Red = color.New(color.FgRed, color.Bold).SprintfFunc() -var Bold = color.New(color.Bold).SprintfFunc() +var Bold = color.New(color.FgCyan).SprintfFunc() // LoadFile loads a file by filename. func LoadFile(filename string) ([]byte, error) { From 81ed17dbd45214a643a392c3983e10944cd068ca Mon Sep 17 00:00:00 2001 From: Gregor Gololicic Date: Mon, 19 Apr 2021 13:44:58 +0200 Subject: [PATCH 110/137] fix error --- internal/emulator/start.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/internal/emulator/start.go b/internal/emulator/start.go index b574a090b..c2795b7db 100644 --- a/internal/emulator/start.go +++ b/internal/emulator/start.go @@ -70,7 +70,7 @@ func ConfiguredServiceKey( proj, err = project.Load(command.Flags.ConfigPath) if err != nil { if errors.Is(err, config.ErrDoesNotExist) { - util.Exitf(1, "🙏 Configuration is missing, initialize it with: 'flow project init' and then rerun this command.") + util.Exitf(1, "🙏 Configuration is missing, initialize it with: 'flow init' and then rerun this command.") } else { util.Exitf(1, err.Error()) } From b29092e5c1f2d7d308639a099bc12615c7d2bdf0 Mon Sep 17 00:00:00 2001 From: Gregor Gololicic Date: Mon, 19 Apr 2021 13:53:48 +0200 Subject: [PATCH 111/137] release notes --- docs/developer-updates/release-notes-v18.md | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) create mode 100644 docs/developer-updates/release-notes-v18.md diff --git a/docs/developer-updates/release-notes-v18.md b/docs/developer-updates/release-notes-v18.md new file mode 100644 index 000000000..52309140e --- /dev/null +++ b/docs/developer-updates/release-notes-v18.md @@ -0,0 +1,21 @@ +## ⬆️ Install or Upgrade + +Follow the [Flow CLI installation guide](https://docs.onflow.org/flow-cli/install/) for instructions on how to install or upgrade the CLI. + +## 💥 Breaking Changes + +### Updated: +### Removed: + +## ⚠️ Deprecation Warnings + +## ⭐ Features + +## 🎉 Improvements + +### Account Response Improved +Account response includes two new fields in key section: `Sequence Number` and `Index`. + +### + +## 🐞 Bug Fixes From c45abb5c3f6a6a322b5aeae42b139061a4485a42 Mon Sep 17 00:00:00 2001 From: Gregor Gololicic Date: Mon, 19 Apr 2021 14:04:45 +0200 Subject: [PATCH 112/137] race condition simple fix --- pkg/flowcli/output/spinner.go | 1 + 1 file changed, 1 insertion(+) diff --git a/pkg/flowcli/output/spinner.go b/pkg/flowcli/output/spinner.go index d26e6db6a..700f511d2 100644 --- a/pkg/flowcli/output/spinner.go +++ b/pkg/flowcli/output/spinner.go @@ -75,4 +75,5 @@ func (s *Spinner) run() { func (s *Spinner) Stop() { s.done <- "" + time.Sleep(50 * time.Millisecond) } From 901fee27202e192cb26d832eaa1a5f0b64b49c5d Mon Sep 17 00:00:00 2001 From: Gregor Gololicic Date: Mon, 19 Apr 2021 14:10:01 +0200 Subject: [PATCH 113/137] stop progress before return err --- pkg/flowcli/services/blocks.go | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/pkg/flowcli/services/blocks.go b/pkg/flowcli/services/blocks.go index b18f18bb9..5afb008f9 100644 --- a/pkg/flowcli/services/blocks.go +++ b/pkg/flowcli/services/blocks.go @@ -75,10 +75,12 @@ func (e *Blocks) GetBlock( } if err != nil { + e.logger.StopProgress() return nil, nil, nil, fmt.Errorf("error fetching block: %s", err.Error()) } if block == nil { + e.logger.StopProgress() return nil, nil, nil, fmt.Errorf("block not found") } @@ -87,6 +89,7 @@ func (e *Blocks) GetBlock( if eventType != "" { events, err = e.gateway.GetEvents(eventType, block.Height, block.Height) if err != nil { + e.logger.StopProgress() return nil, nil, nil, err } } @@ -97,6 +100,7 @@ func (e *Blocks) GetBlock( for _, guarantee := range block.CollectionGuarantees { collection, err := e.gateway.GetCollection(guarantee.CollectionID) if err != nil { + e.logger.StopProgress() return nil, nil, nil, err } collections = append(collections, collection) From e27b6422157a7fa911aa3f9178469c75dec0c590 Mon Sep 17 00:00:00 2001 From: Gregor Gololicic Date: Mon, 19 Apr 2021 14:18:32 +0200 Subject: [PATCH 114/137] defer stop spinner due to possible errors --- pkg/flowcli/services/accounts.go | 4 ++++ pkg/flowcli/services/blocks.go | 5 +---- pkg/flowcli/services/events.go | 1 + pkg/flowcli/services/project.go | 1 + pkg/flowcli/services/transactions.go | 2 ++ 5 files changed, 9 insertions(+), 4 deletions(-) diff --git a/pkg/flowcli/services/accounts.go b/pkg/flowcli/services/accounts.go index 6dbd105c1..5c1a6a5bc 100644 --- a/pkg/flowcli/services/accounts.go +++ b/pkg/flowcli/services/accounts.go @@ -69,6 +69,7 @@ func (a *Accounts) Get(address string) (*flow.Account, error) { // StakingInfo returns the staking information for an account. func (a *Accounts) StakingInfo(accountAddress string) (*cadence.Value, *cadence.Value, error) { a.logger.StartProgress(fmt.Sprintf("Fetching info for %s...", accountAddress)) + defer a.logger.StopProgress() address := flow.HexToAddress(accountAddress) @@ -137,6 +138,7 @@ func (a *Accounts) Create( } a.logger.StartProgress("Creating account...") + defer a.logger.StopProgress() accountKeys := make([]*flow.AccountKey, len(keys)) @@ -287,6 +289,7 @@ func (a *Accounts) addContract( account.Address(), ), ) + defer a.logger.StopProgress() tx, err := project.NewAddAccountContractTransaction( account, @@ -365,6 +368,7 @@ func (a *Accounts) RemoveContract( a.logger.StartProgress( fmt.Sprintf("Removing Contract %s from %s...", contractName, account.Address()), ) + defer a.logger.StopProgress() tx, err := project.NewRemoveAccountContractTransaction(account, contractName) if err != nil { diff --git a/pkg/flowcli/services/blocks.go b/pkg/flowcli/services/blocks.go index 5afb008f9..01dda6054 100644 --- a/pkg/flowcli/services/blocks.go +++ b/pkg/flowcli/services/blocks.go @@ -62,6 +62,7 @@ func (e *Blocks) GetBlock( verbose bool, ) (*flow.Block, []client.BlockEvents, []*flow.Collection, error) { e.logger.StartProgress("Fetching Block...") + defer e.logger.StopProgress() // smart parsing of query var err error @@ -75,12 +76,10 @@ func (e *Blocks) GetBlock( } if err != nil { - e.logger.StopProgress() return nil, nil, nil, fmt.Errorf("error fetching block: %s", err.Error()) } if block == nil { - e.logger.StopProgress() return nil, nil, nil, fmt.Errorf("block not found") } @@ -89,7 +88,6 @@ func (e *Blocks) GetBlock( if eventType != "" { events, err = e.gateway.GetEvents(eventType, block.Height, block.Height) if err != nil { - e.logger.StopProgress() return nil, nil, nil, err } } @@ -100,7 +98,6 @@ func (e *Blocks) GetBlock( for _, guarantee := range block.CollectionGuarantees { collection, err := e.gateway.GetCollection(guarantee.CollectionID) if err != nil { - e.logger.StopProgress() return nil, nil, nil, err } collections = append(collections, collection) diff --git a/pkg/flowcli/services/events.go b/pkg/flowcli/services/events.go index 696ae253e..7e49eec8e 100644 --- a/pkg/flowcli/services/events.go +++ b/pkg/flowcli/services/events.go @@ -61,6 +61,7 @@ func (e *Events) Get(name string, start string, end string) ([]client.BlockEvent } e.logger.StartProgress("Fetching Events...") + defer e.logger.StopProgress() var endHeight uint64 if end == "" { diff --git a/pkg/flowcli/services/project.go b/pkg/flowcli/services/project.go index 632f95a1b..54cfc71dd 100644 --- a/pkg/flowcli/services/project.go +++ b/pkg/flowcli/services/project.go @@ -135,6 +135,7 @@ func (p *Project) Deploy(network string, update bool) ([]*contracts.Contract, er len(orderedContracts), strings.Join(p.project.AccountNamesForNetwork(network), ","), )) + defer p.logger.StopProgress() block, err := p.gateway.GetLatestBlock() if err != nil { diff --git a/pkg/flowcli/services/transactions.go b/pkg/flowcli/services/transactions.go index 3740038fa..5897c03ad 100644 --- a/pkg/flowcli/services/transactions.go +++ b/pkg/flowcli/services/transactions.go @@ -264,6 +264,7 @@ func (t *Transactions) Send( } t.logger.StartProgress("Sending Transaction...") + defer t.logger.StopProgress() sentTx, err := t.gateway.SendSignedTransaction(signed) if err != nil { @@ -313,6 +314,7 @@ func (t *Transactions) SendForAddressWithCode( } t.logger.StartProgress("Sending transaction...") + defer t.logger.StopProgress() sentTx, err := t.gateway.SendSignedTransaction(tx) if err != nil { From 4bad7a1b3878ae25e7a061bc91cefb2fd4608a76 Mon Sep 17 00:00:00 2001 From: Gregor Gololicic Date: Mon, 19 Apr 2021 14:29:08 +0200 Subject: [PATCH 115/137] account balance fixed --- internal/accounts/accounts.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/internal/accounts/accounts.go b/internal/accounts/accounts.go index e3ebffff2..361840fcd 100644 --- a/internal/accounts/accounts.go +++ b/internal/accounts/accounts.go @@ -53,7 +53,7 @@ type AccountResult struct { func (r *AccountResult) JSON() interface{} { result := make(map[string]interface{}) result["address"] = r.Address - result["balance"] = r.Balance + result["balance"] = fmt.Sprintf("%s", cadence.UFix64(r.Balance)) keys := make([]string, 0) for _, key := range r.Keys { @@ -125,5 +125,5 @@ func (r *AccountResult) Oneliner() string { keys = append(keys, key.PublicKey.String()) } - return fmt.Sprintf("Address: 0x%s, Balance: %v, Public Keys: %s", r.Address, r.Balance, keys) + return fmt.Sprintf("Address: 0x%s, Balance: %s, Public Keys: %s", r.Address, cadence.UFix64(r.Balance), keys) } From 8c098f54f276210ba63a7b39c8fa8d8514bd3c27 Mon Sep 17 00:00:00 2001 From: Gregor Gololicic Date: Mon, 19 Apr 2021 14:32:44 +0200 Subject: [PATCH 116/137] network default value in compare --- internal/command/command.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/internal/command/command.go b/internal/command/command.go index 5e4d4a447..5f814c682 100644 --- a/internal/command/command.go +++ b/internal/command/command.go @@ -209,7 +209,7 @@ func createGateway(host string) (gateway.Gateway, error) { // resolveHost from the flags provided func resolveHost(proj *project.Project, hostFlag string, networkFlag string) (string, error) { // don't allow both network and host flag as the host might be different - if networkFlag != "" && hostFlag != "" { + if networkFlag != config.DefaultEmulatorNetwork().Name && hostFlag != "" { return "", fmt.Errorf("shouldn't use both host and network flags, better to use network flag") } From 3a4436d021366631ef979978cca5a8dec99e15a8 Mon Sep 17 00:00:00 2001 From: Gregor Gololicic Date: Mon, 19 Apr 2021 14:43:58 +0200 Subject: [PATCH 117/137] release notes wip --- docs/developer-updates/release-notes-v18.md | 75 ++++++++++++++++++++- 1 file changed, 74 insertions(+), 1 deletion(-) diff --git a/docs/developer-updates/release-notes-v18.md b/docs/developer-updates/release-notes-v18.md index 52309140e..a0d79e0d7 100644 --- a/docs/developer-updates/release-notes-v18.md +++ b/docs/developer-updates/release-notes-v18.md @@ -16,6 +16,79 @@ Follow the [Flow CLI installation guide](https://docs.onflow.org/flow-cli/instal ### Account Response Improved Account response includes two new fields in key section: `Sequence Number` and `Index`. -### +### Transaction Result Improved +Transaction result displays more information about the transaction. New format example: + +``` +Status ✅ SEALED +ID b6430b35ba23849a8acb4fa1a4a1d5cce3ed4589111ecbb3984de1b6bd1ba39e +Payer a2c4941b5f3c7151 +Authorizers [a2c4941b5f3c7151] + +Proposal Key: + Address a2c4941b5f3c7151 + Index 0 + Sequence 9 + +No Payload Signatures + +Envelope Signature 0: + Address a2c4941b5f3c7151 + Signature 5391a6fed0fe...2742048166f9d5c925a8dcb78a6d8c710921d67 + Key Index 0 + + +Events: None + + +Arguments (1): + - Argument 0: {"type":"String","value":"Meow"} + + +Code + +transaction(greeting: String) { + let guest: Address + + prepare(authorizer: AuthAccount) { + self.guest = authorizer.address + } + + execute { + log(greeting.concat(",").concat(self.guest.toString())) + } +} + + +Payload: +f90184f90138...8a9462751237da2742048166f9d5c925a8dcb78a6d8c710921d67 +``` + +Transaction error is now shown at the top of the result. +``` +Transaction 0dd6294a7614bc0fbeb39b44a6e9f68e821225caa4baf4104a17dc1193d4f011 sealed + +Status: SEALED +Execution Error: Execution failed: +error: invalid move operation for non-resource + --> 0dd6294a7614bc0fbeb39b44a6e9f68e821225caa4baf4104a17dc1193d4f011:15:15 + | +15 | useRes(<-result) + | ^^^ unexpected `<-` + +error: mismatched types + --> 0dd6294a7614bc0fbeb39b44a6e9f68e821225caa4baf4104a17dc1193d4f011:15:15 + | +15 | useRes(<-result) + | ^^^^^^^^ expected `AnyResource`, got `&AnyResource` + +Events: + None +``` ## 🐞 Bug Fixes + +### New Transaction ID Log +While sending transaction was in progress output displayed wrong transaction ID. + +### \ No newline at end of file From 55f4f957e938c4952f0c2e3292d3428694e55bb2 Mon Sep 17 00:00:00 2001 From: Gregor Gololicic Date: Mon, 19 Apr 2021 16:04:02 +0200 Subject: [PATCH 118/137] release notes written --- docs/developer-updates/release-notes-v18.md | 107 +++++++++++++++++++- 1 file changed, 104 insertions(+), 3 deletions(-) diff --git a/docs/developer-updates/release-notes-v18.md b/docs/developer-updates/release-notes-v18.md index a0d79e0d7..2e1a2291b 100644 --- a/docs/developer-updates/release-notes-v18.md +++ b/docs/developer-updates/release-notes-v18.md @@ -7,10 +7,103 @@ Follow the [Flow CLI installation guide](https://docs.onflow.org/flow-cli/instal ### Updated: ### Removed: -## ⚠️ Deprecation Warnings - ## ⭐ Features +### Resolve Contract Imports in Scripts and Transactions +A new feature that allows you to send transactions and scripts that reference +contract deployed using the project deploy command. Imports are resolved +the same way as project deploy are. Example: + +Example script: `get_supply.cdc` +``` +import Kibble from "../../contracts/Kibble.cdc" + +pub fun main(): UFix64 { + let supply = Kibble.totalSupply + return supply +} + +``` + +Example command: +``` +flow scripts execute ./get_supply.cdc +``` + +Note: Please make sure you first deploy the contract using `flow project deploy` +command and that contracts are correctly added to the flow configuration. + + +### Build, Sign and Send Transactions +New functionality allows you to build a transaction, sign it +and send signed to the network in separated steps. + +#### Build Transaction +Build new transaction and specify who will be the proposer, signer and payer account +or address. Example: + +``` +flow transactions build ./transaction.cdc --proposer alice --payer bob --authorizer bob --filter payload --save payload1.rlp +``` + +Check more about [this functionality in docs](https://docs.onflow.org/flow-cli/build-transactions/). + +#### Sign Transaction +After using build command and saving payload to a file you should sign the transaction +with each account. Example: + +``` +flow transactions sign ./payload1.rlp --signer alice --filter payload --save payload2.rlp +``` + +#### Send Signed Transaction +When authorizer, payer and proposer sign the transaction it is ready to be +sent to the network. Anyone can execute the `send-signed` command. Example: + +``` +flow transactions send-signed ./payload3.rlp +``` + +### Version Check +Automatically checks if a new version exists and outputs a warning in case there +is a newer version. Example: +``` +⚠️ Version Warning: New version v0.18.0 of Flow CLI is available. +Follow the Flow CLI installation guide for instructions on how to install or upgrade the CLI: https://docs.onflow.org/flow-cli/install +``` + + +### Create Account With Multiple Keys and Weights +Account creation can be done using multiple keys (`--key`) and new `--key-weight` +flag. Flag enables you to set key weight for each of the keys. Command example: +``` +accounts create \ + --key ca8cc7...76f67 --key-weight 500 \ + --key da8123...043ce --key-weight 500 + +Address 0x179b6b1cb6755e31 +Balance 0.10000000 +Keys 2 + +Key 0 Public Key ca8cc7...76f67 + Weight 500 + Signature Algorithm ECDSA_P256 + Hash Algorithm SHA3_256 + Revoked false + Sequence Number 0 + Index 0 + + +Key 1 Public Key da8123...043ce + Weight 500 + Signature Algorithm ECDSA_P256 + Hash Algorithm SHA3_256 + Revoked false + Sequence Number 0 + Index 1 + +``` + ## 🎉 Improvements ### Account Response Improved @@ -91,4 +184,12 @@ Events: ### New Transaction ID Log While sending transaction was in progress output displayed wrong transaction ID. -### \ No newline at end of file +### Init Reset Fix +Old configuration format caused an error saying to reset the +configuration using reset flag, but when ran it produced the same error again. +This bug was fixed. + +### Emulator Config Path +When running emulator command `flow emulator` config flag `-f` was ignored. +This has been fixed, so you can provide a custom path to the config while running +the start emulator command. \ No newline at end of file From 30e14cdd03f98940b217e3e3c58bfe320c8f4732 Mon Sep 17 00:00:00 2001 From: Gregor Gololicic Date: Mon, 19 Apr 2021 16:08:03 +0200 Subject: [PATCH 119/137] release notes fix --- docs/developer-updates/release-notes-v18.md | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/docs/developer-updates/release-notes-v18.md b/docs/developer-updates/release-notes-v18.md index 2e1a2291b..68e5b0f24 100644 --- a/docs/developer-updates/release-notes-v18.md +++ b/docs/developer-updates/release-notes-v18.md @@ -3,9 +3,7 @@ Follow the [Flow CLI installation guide](https://docs.onflow.org/flow-cli/install/) for instructions on how to install or upgrade the CLI. ## 💥 Breaking Changes - -### Updated: -### Removed: +/ ## ⭐ Features From bd4ccd7fc85c395feeadf193efe5173cc3176434 Mon Sep 17 00:00:00 2001 From: Gregor Gololicic Date: Mon, 19 Apr 2021 17:32:29 +0200 Subject: [PATCH 120/137] added default value for network --- docs/account-add-contract.md | 1 + docs/account-remove-contract.md | 1 + docs/account-staking-info.md | 1 + docs/account-update-contract.md | 1 + docs/build-transactions.md | 1 + docs/create-accounts.md | 1 + docs/deploy-project-contracts.md | 1 + docs/execute-scripts.md | 1 + docs/get-accounts.md | 1 + docs/get-blocks.md | 1 + docs/get-collections.md | 1 + docs/get-events.md | 1 + docs/get-transactions.md | 1 + docs/send-signed-transactions.md | 1 + docs/send-transactions.md | 1 + docs/sign-transaction.md | 364 +------------------------------ docs/template.md | 1 + 17 files changed, 17 insertions(+), 363 deletions(-) diff --git a/docs/account-add-contract.md b/docs/account-add-contract.md index 2766ce355..e8065cbd7 100644 --- a/docs/account-add-contract.md +++ b/docs/account-add-contract.md @@ -72,6 +72,7 @@ any host defined by the `--network` flag. - Flag: `--network` - Short Flag: `-n` - Valid inputs: the name of a network defined in the configuration (`flow.json`). +- Default: `emulator` Specify which network you want the command to use for execution. diff --git a/docs/account-remove-contract.md b/docs/account-remove-contract.md index 6ee929680..b38bc9d17 100644 --- a/docs/account-remove-contract.md +++ b/docs/account-remove-contract.md @@ -64,6 +64,7 @@ any host defined by the `--network` flag. - Flag: `--network` - Short Flag: `-n` - Valid inputs: the name of a network defined in the configuration (`flow.json`) +- Default: `emulator` Specify which network you want the command to use for execution. diff --git a/docs/account-staking-info.md b/docs/account-staking-info.md index 226fdad52..c5109aec4 100644 --- a/docs/account-staking-info.md +++ b/docs/account-staking-info.md @@ -68,6 +68,7 @@ any host defined by the `--network` flag. - Flag: `--network` - Short Flag: `-n` - Valid inputs: the name of a network defined in the configuration (`flow.json`) +- Default: `emulator` Specify which network you want the command to use for execution. diff --git a/docs/account-update-contract.md b/docs/account-update-contract.md index d9004b535..850706ef4 100644 --- a/docs/account-update-contract.md +++ b/docs/account-update-contract.md @@ -70,6 +70,7 @@ any host defined by the `--network` flag. - Flag: `--network` - Short Flag: `-n` - Valid inputs: the name of a network defined in the configuration (`flow.json`) +- Default: `emulator` Specify which network you want the command to use for execution. diff --git a/docs/build-transactions.md b/docs/build-transactions.md index 8aa8a6aee..2ab1e687b 100644 --- a/docs/build-transactions.md +++ b/docs/build-transactions.md @@ -124,6 +124,7 @@ used to execute the commands. - Flag: `--network` - Short Flag: `-n` - Valid inputs: the name of a network defined in the configuration (`flow.json`) +- Default: `emulator` Specify which network you want the command to use for execution. diff --git a/docs/create-accounts.md b/docs/create-accounts.md index dab110df0..41c825c55 100644 --- a/docs/create-accounts.md +++ b/docs/create-accounts.md @@ -118,6 +118,7 @@ any host defined by the `--network` flag. - Flag: `--network` - Short Flag: `-n` - Valid inputs: the name of a network defined in the configuration (`flow.json`) +- Default: `emulator` Specify which network you want the command to use for execution. diff --git a/docs/deploy-project-contracts.md b/docs/deploy-project-contracts.md index 497c26153..2e0aff747 100644 --- a/docs/deploy-project-contracts.md +++ b/docs/deploy-project-contracts.md @@ -121,6 +121,7 @@ any host defined by the `--network` flag. - Flag: `--network` - Short Flag: `-n` - Valid inputs: the name of a network defined in the configuration (`flow.json`) +- Default: `emulator` Specify which network you want the command to use for execution. diff --git a/docs/execute-scripts.md b/docs/execute-scripts.md index 7f7e08bda..0e27d26e5 100644 --- a/docs/execute-scripts.md +++ b/docs/execute-scripts.md @@ -70,6 +70,7 @@ any host defined by the `--network` flag. - Flag: `--network` - Short Flag: `-n` - Valid inputs: the name of a network defined in the configuration (`flow.json`) +- Default: `emulator` Specify which network you want the command to use for execution. diff --git a/docs/get-accounts.md b/docs/get-accounts.md index 6ddd09a95..67c83ae17 100644 --- a/docs/get-accounts.md +++ b/docs/get-accounts.md @@ -73,6 +73,7 @@ any host defined by the `--network` flag. - Flag: `--network` - Short Flag: `-n` - Valid inputs: the name of a network defined in the configuration (`flow.json`) +- Default: `emulator` Specify which network you want the command to use for execution. diff --git a/docs/get-blocks.md b/docs/get-blocks.md index 55f770526..f80856091 100644 --- a/docs/get-blocks.md +++ b/docs/get-blocks.md @@ -103,6 +103,7 @@ any host defined by the `--network` flag. - Flag: `--network` - Short Flag: `-n` - Valid inputs: the name of a network defined in the configuration (`flow.json`) +- Default: `emulator` Specify which network you want the command to use for execution. diff --git a/docs/get-collections.md b/docs/get-collections.md index 8ca29bb0d..4ef0f8094 100644 --- a/docs/get-collections.md +++ b/docs/get-collections.md @@ -55,6 +55,7 @@ any host defined by the `--network` flag. - Flag: `--network` - Short Flag: `-n` - Valid inputs: the name of a network defined in the configuration (`flow.json`) +- Default: `emulator` Specify which network you want the command to use for execution. diff --git a/docs/get-events.md b/docs/get-events.md index 9040c214e..63df08a5e 100644 --- a/docs/get-events.md +++ b/docs/get-events.md @@ -88,6 +88,7 @@ any host defined by the `--network` flag. - Flag: `--network` - Short Flag: `-n` - Valid inputs: the name of a network defined in the configuration (`flow.json`) +- Default: `emulator` Specify which network you want the command to use for execution. diff --git a/docs/get-transactions.md b/docs/get-transactions.md index 0cfe9a111..7cd04c9ae 100644 --- a/docs/get-transactions.md +++ b/docs/get-transactions.md @@ -75,6 +75,7 @@ any host defined by the `--network` flag. - Flag: `--network` - Short Flag: `-n` - Valid inputs: the name of a network defined in the configuration (`flow.json`) +- Default: `emulator` Specify which network you want the command to use for execution. diff --git a/docs/send-signed-transactions.md b/docs/send-signed-transactions.md index 81819b329..5f86af41e 100644 --- a/docs/send-signed-transactions.md +++ b/docs/send-signed-transactions.md @@ -93,6 +93,7 @@ any host defined by the `--network` flag. - Flag: `--network` - Short Flag: `-n` - Valid inputs: the name of a network defined in the configuration (`flow.json`) +- Default: `emulator` Specify which network you want the command to use for execution. diff --git a/docs/send-transactions.md b/docs/send-transactions.md index 8dced1570..d06801dc8 100644 --- a/docs/send-transactions.md +++ b/docs/send-transactions.md @@ -138,6 +138,7 @@ any host defined by the `--network` flag. - Flag: `--network` - Short Flag: `-n` - Valid inputs: the name of a network defined in the configuration (`flow.json`) +- Default: `emulator` Specify which network you want the command to use for execution. diff --git a/docs/sign-transaction.md b/docs/sign-transaction.md index 76a52dc02..61f646f39 100644 --- a/docs/sign-transaction.md +++ b/docs/sign-transaction.md @@ -92,6 +92,7 @@ used to execute the commands. - Flag: `--network` - Short Flag: `-n` - Valid inputs: the name of a network defined in the configuration (`flow.json`) +- Default: `emulator` Specify which network you want the command to use for execution. @@ -136,366 +137,3 @@ Specify the log level. Control how much output you want to see while command exe Specify a filename for the configuration files, you can provide multiple configuration files by using `-f` flag multiple times. - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -```bash -Authorizers [f8d6e0586b0a20c7] - -Proposal Key: - Address f8d6e0586b0a20c7 - Index 0 - Sequence 16 - -Payload Signature 0: - Address f8d6e0586b0a20c7...e888b1a5840e8881caa78208a45ac1ce9f77d98cb85ac982c4c8ca6b3510 - Key Index 0 - - -Transaction Payload: -f90183f90137b8d17472616e73616374696f6e286772656574696e673a20537472696e6729207b0a20206c657420677 -56573743a20416464726573730a0a20207072657061726528617574686f72697a65723a20417574684163636f756e74 -29207b0a2020202073656c662e6775657374203d20617574686f72697a65722e616464726573730a20207d0a0a20206 -5786563757465207b0a202020206c6f67286772656574696e672e636f6e63617428222c22292e636f6e636174287365 -6c662e67756573742e746f537472696e67282929290a20207d0a7de1a07b2274797065223a22537472696e67222c227 - - -``` - - -Example: - -Simple two step sign send -``` -> transactions sign ./tests/transaction.cdc --arg String:"Foo" - -Authorizers [f8d6e0586b0a20c7] -Payer f8d6e0586b0a20c7 - -Proposal Key: - Address f8d6e0586b0a20c7 - Index 0 - Sequence 4 - -Payload Signature 0: - Address f8d6e0586b0a20c7 - Signature bccac2e89d0407300a1a24f900757cdf15a49ef5e9ca92cc6cc54ea56ddda841bc8f47b803e5a97768f155d105376d62d40c2dbeaa822944289b92ad7eb33b9b - Key Index 0 - - -Transaction Payload: -f90183f90137b8d17472616e73616374696f6e286772656574696e673a20537472696e6729207b0a20206c65742067756573743a20416464726573730a0a20207072657061726528617574686f72697a65723a20417574684163636f756e7429207b0a2020202073656c662e6775657374203d20617574686f72697a65722e616464726573730a20207d0a0a202065786563757465207b0a202020206c6f67286772656574696e672e636f6e63617428222c22292e636f6e6361742873656c662e67756573742e746f537472696e67282929290a20207d0a7de1a07b2274797065223a22537472696e67222c2276616c7565223a22466f6f227d0aa076a251f4028186c2a934efa598e2cd41a6a33700893ae7098475cd05cc6c37fb8203e888f8d6e0586b0a20c7800488f8d6e0586b0a20c7c988f8d6e0586b0a20c7f846f8448080b840bccac2e89d0407300a1a24f900757cdf15a49ef5e9ca92cc6cc54ea56ddda841bc8f47b803e5a97768f155d105376d62d40c2dbeaa822944289b92ad7eb33b9bc0 - - -> transactions send --payload payload1 - -Hash 3130447e195587ef7a01ad40effd281680a02e7411b204391c837d451e246d42 -Status SEALED -Payer f8d6e0586b0a20c7 -Events - - -``` - - -Different Payer: -``` -> keys generate -🔴️ Store Private Key safely and don't share with anyone! -Private Key 8fea7a92c85aa1b653eb5fe407842886b76a2c009b800e82c570767cf010f384 -Public Key ad26f02fbdd3f372e2fbcf94bf0374c9502e6fdf2446a3009772642195b811be528143217139d8111dda7a7b30f7a57ec798cc12d86d2e850f5e0cccbb195da2 - -> accounts create --key ad26f02fbdd3f372e2fbcf94bf0374c9502e6fdf2446a3009772642195b811be528143217139d8111dda7a7b30f7a57ec798cc12d86d2e850f5e0cccbb195da2 -Address 0x179b6b1cb6755e31 -Balance 10000000 -Keys 1 - -Key 0 Public Key ad26f02fbdd3f372e2fbcf94bf0374c9502e6fdf2446a3009772642195b811be528143217139d8111dda7a7b30f7a57ec798cc12d86d2e850f5e0cccbb195da2 - Weight 1000 - Signature Algorithm ECDSA_P256 - Hash Algorithm SHA3_256 - -Contracts Deployed: 0 - - -> transactions sign ./tests/transaction.cdc --arg String:"Foo" --payer-address 0x179b6b1cb6755e31 --filter Payload --save payload2 - -> cmd/flow/main.go transactions sign --payload payload2 --role payer --signer payer-account - -Authorizers [f8d6e0586b0a20c7] -Payer 179b6b1cb6755e31 - -Proposal Key: - Address f8d6e0586b0a20c7 - Index 0 - Sequence 3 - -Payload Signature 0: - Address f8d6e0586b0a20c7 - Signature ce858a8bd8a58d29f2cf37e4de1aad2d6c577b342ef285e02762cf224614d90bac8de3fe0ea742e0c5d78e4dc981c0e84ba1d208fc4ec4554bd9e732290567ee - Key Index 0 - -Envelope Signature 0: - Address 179b6b1cb6755e31 - Signature 4ba3a88be452a684f54b29a9ddc72469a98f3863992d173ed0ab3c52efe7f0c0c0a4fc03d343c971086929f097e5c1032655b61efc3a5e87ea3ab22755aad409 - Key Index 0 - - -Transaction Payload: -f901caf90137b8d17472616e73616374696f6e286772656574696e673a20537472696e6729207b0a20206c65742067756573743a20416464726573730a0a20207072657061726528617574686f72697a65723a20417574684163636f756e7429207b0a2020202073656c662e6775657374203d20617574686f72697a65722e616464726573730a20207d0a0a202065786563757465207b0a202020206c6f67286772656574696e672e636f6e63617428222c22292e636f6e6361742873656c662e67756573742e746f537472696e67282929290a20207d0a7de1a07b2274797065223a22537472696e67222c2276616c7565223a22466f6f227d0aa0baaeb14e65391f51236b203665764aae224171aefc60bbfd1c2899a56e604c128203e888f8d6e0586b0a20c7800388179b6b1cb6755e31c988f8d6e0586b0a20c7f846f8448080b840ce858a8bd8a58d29f2cf37e4de1aad2d6c577b342ef285e02762cf224614d90bac8de3fe0ea742e0c5d78e4dc981c0e84ba1d208fc4ec4554bd9e732290567eef846f8440180b8404ba3a88be452a684f54b29a9ddc72469a98f3863992d173ed0ab3c52efe7f0c0c0a4fc03d343c971086929f097e5c1032655b61efc3a5e87ea3ab22755aad409 - - - - - -> go run cmd/flow/main.go transactions send --payload payload3 - -Hash 047b9fab1ff28fd7fed35672c611dcef40ace745ed535417dae714062497dec4 -Status SEALED -Payer 179b6b1cb6755e31 -Events - -``` - -Different Authorizer - -``` - -> transactions sign ./tests/transaction.cdc --arg String:"Foo" --add-authorizer 179b6b1cb6755e31 - -Authorizers [f8d6e0586b0a20c7 179b6b1cb6755e31] -Payer 0000000000000000 - -Proposal Key: - Address f8d6e0586b0a20c7 - Index 0 - Sequence 4 - -Payload Signature 0: - Address f8d6e0586b0a20c7 - Signature 64c0a6cb39c55364cff5c6d73622d22165efa994deb9a5b8b53ff80f0931db74380311ff9765bafcbce666d9b407638d9b0e26ad97b7a9dad963337d623b0de3 - Key Index 0 - - -Transaction Payload: -f9018cf90140b8d17472616e73616374696f6e286772656574696e673a20537472696e6729207b0a20206c65742067756573743a20416464726573730a0a20207072657061726528617574686f72697a65723a20417574684163636f756e7429207b0a2020202073656c662e6775657374203d20617574686f72697a65722e616464726573730a20207d0a0a202065786563757465207b0a202020206c6f67286772656574696e672e636f6e63617428222c22292e636f6e6361742873656c662e67756573742e746f537472696e67282929290a20207d0a7de1a07b2274797065223a22537472696e67222c2276616c7565223a22466f6f227d0aa076a251f4028186c2a934efa598e2cd41a6a33700893ae7098475cd05cc6c37fb8203e888f8d6e0586b0a20c78004880000000000000000d288f8d6e0586b0a20c788179b6b1cb6755e31f846f8448080b84064c0a6cb39c55364cff5c6d73622d22165efa994deb9a5b8b53ff80f0931db74380311ff9765bafcbce666d9b407638d9b0e26ad97b7a9dad963337d623b0de3c0 - -// saved to payload 1 - -> transactions sign --payload payload1 --signer payer-account - -Hash 9f6b7f270c1471991890935f3eb82d9913e9ad172e0bb5f0d445a8a511e5e4df -Payer f8d6e0586b0a20c7 -Authorizers [f8d6e0586b0a20c7 179b6b1cb6755e31] - -Proposal Key: - Address f8d6e0586b0a20c7 - Index 0 - Sequence 5 - -Payload Signature 0: - Address f8d6e0586b0a20c7 - Signature 5c56f2e465b13f289f341733a95b8673aeb9bfa8e3ed9021ca6d51a0b59a4ed278ef95491efdfb7c30e6d599d52358b4b698431782096e7e38a499130dfaeb1e - Key Index 0 - -Payload Signature 1: - Address 179b6b1cb6755e31 - Signature ca04dafea2a5438ba6d5ac7811bc2656035a23001eee3c96ddf581d015683006c42943b8475d3c61e6131578cc3fe80470ae8706e489b186bc2b333ff12f7282 - Key Index 0 - - -Payload: -f901d2f90140b8d17472616e73616374696f6e286772656574696e673a20537472696e6729207b0a20206c65742067756573743a20416464726573730a0a20207072657061726528617574686f72697a65723a20417574684163636f756e7429207b0a2020202073656c662e6775657374203d20617574686f72697a65722e616464726573730a20207d0a0a202065786563757465207b0a202020206c6f67286772656574696e672e636f6e63617428222c22292e636f6e6361742873656c662e67756573742e746f537472696e67282929290a20207d0a7de1a07b2274797065223a22537472696e67222c2276616c7565223a22466f6f227d0aa0ff25bc88a84e5989cafda9da5e55baa9308e511a12fd4d2788c0c359c3f1e6738203e888f8d6e0586b0a20c7800588f8d6e0586b0a20c7d288f8d6e0586b0a20c788179b6b1cb6755e31f88cf8448080b8405c56f2e465b13f289f341733a95b8673aeb9bfa8e3ed9021ca6d51a0b59a4ed278ef95491efdfb7c30e6d599d52358b4b698431782096e7e38a499130dfaeb1ef8440180b840ca04dafea2a5438ba6d5ac7811bc2656035a23001eee3c96ddf581d015683006c42943b8475d3c61e6131578cc3fe80470ae8706e489b186bc2b333ff12f7282c0 - -// saved to payload 2 - -> transactions send --payload payload2 - -❌ Transaction Error -execution error code 100: Execution failed: -error: authorizer count mismatch for transaction: expected 1, got 2 ---> 5fde5868a7f23b64335fea2c92eee97272bdc3d6bd5389a26ba25c496fe141e8 - - - -Status ✅ SEALED -Hash 5fde5868a7f23b64335fea2c92eee97272bdc3d6bd5389a26ba25c496fe141e8 -Payer f8d6e0586b0a20c7 -Authorizers [f8d6e0586b0a20c7 179b6b1cb6755e31] - -Proposal Key: - Address f8d6e0586b0a20c7 - Index 0 - Sequence 5 - -Payload Signature 0: - Address f8d6e0586b0a20c7 - Signature 5c56f2e465b13f289f341733a95b8673aeb9bfa8e3ed9021ca6d51a0b59a4ed278ef95491efdfb7c30e6d599d52358b4b698431782096e7e38a499130dfaeb1e - Key Index 0 - -Payload Signature 1: - Address 179b6b1cb6755e31 - Signature d02d792d0157ce357b87a1a8381e7a8a599386782d5ac0ae0738d2c1f1e96d495aad6fc058f0f81b6dfecc0c72b2358c55cfe6f68aaf13882cf177f48d44c337 - Key Index 0 - -Envelope Signature 0: - Address f8d6e0586b0a20c7 - Signature 2fce0b37e3cc7c44b0e709c7d2a8f145bf9af9aab8be7b1e4e76e20a1e6abc67958dd1be5c4a19f2283c9cddc9ace243688a3c2198858a502551dfd70b32790a - Key Index 0 - - -Events: - None - -Payload: -f90219f90140b8d17472616e73616374696f6e286772656574696e673a20537472696e6729207b0a20206c65742067756573743a20416464726573730a0a20207072657061726528617574686f72697a65723a20417574684163636f756e7429207b0a2020202073656c662e6775657374203d20617574686f72697a65722e616464726573730a20207d0a0a202065786563757465207b0a202020206c6f67286772656574696e672e636f6e63617428222c22292e636f6e6361742873656c662e67756573742e746f537472696e67282929290a20207d0a7de1a07b2274797065223a22537472696e67222c2276616c7565223a22466f6f227d0aa0ff25bc88a84e5989cafda9da5e55baa9308e511a12fd4d2788c0c359c3f1e6738203e888f8d6e0586b0a20c7800588f8d6e0586b0a20c7d288f8d6e0586b0a20c788179b6b1cb6755e31f88cf8448080b8405c56f2e465b13f289f341733a95b8673aeb9bfa8e3ed9021ca6d51a0b59a4ed278ef95491efdfb7c30e6d599d52358b4b698431782096e7e38a499130dfaeb1ef8440180b840d02d792d0157ce357b87a1a8381e7a8a599386782d5ac0ae0738d2c1f1e96d495aad6fc058f0f81b6dfecc0c72b2358c55cfe6f68aaf13882cf177f48d44c337f846f8448080b8402fce0b37e3cc7c44b0e709c7d2a8f145bf9af9aab8be7b1e4e76e20a1e6abc67958dd1be5c4a19f2283c9cddc9ace243688a3c2198858a502551dfd70b32790a - - -``` - - - - - -Kan Implementation - Multiple authorizers - -``` -go run cmd/flow/main.go transactions sign --payload payload11 --role authorizer --signer payer-account -^C -MacBook-Pro:flow-cli Dapper$ go run cmd/flow/main.go transactions sign --payload payload11 --role authorizer --signer payer-account --output payload12 -⚠️ You are using a new experimental configuration format. Support for this format is not yet available across all CLI commands. -⚠️ You are using a new experimental configuration format. Support for this format is not yet available across all CLI commands. -Authorizers (2): - Authorizer 0: f8d6e0586b0a20c7 - Authorizer 1: 179b6b1cb6755e31 - -Arguments (1): - Argument 0: {"type":"String","value":"Hello"} - - -Script: -transaction(greeting: String) { - let guest: Address - - prepare(authorizer: AuthAccount) { - self.guest = authorizer.address - } - - execute { - log(greeting.concat(",").concat(self.guest.toString())) - } -} -=== -Proposer Address: f8d6e0586b0a20c7 -Proposer Key Index: 0 -Payer Address: f8d6e0586b0a20c7 -=== -Payload Signatures (1): - Signature 0 Signer Address: f8d6e0586b0a20c7 - Signature 0 Signer Key Index: 0 -=== -Does this look correct? (y/n) -> y -Payload contents verified -hexrlp encoded transaction written to payload12 -MacBook-Pro:flow-cli Dapper$ cat payload12 -f901d2f90140b8d17472616e73616374696f6e286772656574696e673a20537472696e6729207b0a20206c65742067756573743a20416464726573730a0a20207072657061726528617574686f72697a65723a20417574684163636f756e7429207b0a2020202073656c662e6775657374203d20617574686f72697a65722e616464726573730a20207d0a0a202065786563757465207b0a202020206c6f67286772656574696e672e636f6e63617428222c22292e636f6e6361742873656c662e67756573742e746f537472696e67282929290a20207d0a7de3a27b2274797065223a22537472696e67222c2276616c7565223a2248656c6c6f227d0aa085710ebc28deba306bba85d19cf09aa525f1d4badd37843acc677f01fbcfc1f18088f8d6e0586b0a20c7800588f8d6e0586b0a20c7d288f8d6e0586b0a20c788179b6b1cb6755e31f88cf8448080b840ad1ea2b2ea309d875f4a54c49449bd891b45d76eaf3aafa0597d8e9b9e9822b8f86885c23d4eacc99ca3e4f4b0b321a375aebe972e6404d906fa77c0e674daa4f8440180b840267801d484a57a9be7136786807ef2f27059c4635f8412bb594e49b08b8b1af458ec93804d98ae24163987443ffb7847b57e188762aa483dc792ce902df67459c0MacBook-Pro:flow-cli Dapper$ -MacBook-Pro:flow-cli Dapper$ -MacBook-Pro:flow-cli Dapper$ -MacBook-Pro:flow-cli Dapper$ go run cmd/flow/main.go transactions send --payload payload12 --signer emulator-account --results -⚠️ You are using a new experimental configuration format. Support for this format is not yet available across all CLI commands. -⚠️ You are using a new experimental configuration format. Support for this format is not yet available across all CLI commands. -Authorizers (2): - Authorizer 0: f8d6e0586b0a20c7 - Authorizer 1: 179b6b1cb6755e31 - -Arguments (1): - Argument 0: {"type":"String","value":"Hello"} - - -Script: -transaction(greeting: String) { - let guest: Address - - prepare(authorizer: AuthAccount) { - self.guest = authorizer.address - } - - execute { - log(greeting.concat(",").concat(self.guest.toString())) - } -} -=== -Proposer Address: f8d6e0586b0a20c7 -Proposer Key Index: 0 -Payer Address: f8d6e0586b0a20c7 -=== -Payload Signatures (2): - Signature 0 Signer Address: f8d6e0586b0a20c7 - Signature 0 Signer Key Index: 0 - Signature 1 Signer Address: 179b6b1cb6755e31 - Signature 1 Signer Key Index: 0 -=== -Does this look correct? (y/n) -> y -Payload contents verified -Submitting transaction with ID b0aea61a31b3e872c2dac826d37a9667f252bc82f3e1d2be98f25485a0c09bd7 ... -Successfully submitted transaction with ID b0aea61a31b3e872c2dac826d37a9667f252bc82f3e1d2be98f25485a0c09bd7 -Waiting for transaction b0aea61a31b3e872c2dac826d37a9667f252bc82f3e1d2be98f25485a0c09bd7 to be sealed... - -Transaction b0aea61a31b3e872c2dac826d37a9667f252bc82f3e1d2be98f25485a0c09bd7 sealed - -Status: SEALED -Execution Error: execution error code 100: Execution failed: -error: authorizer count mismatch for transaction: expected 1, got 2 ---> b0aea61a31b3e872c2dac826d37a9667f252bc82f3e1d2be98f25485a0c09bd7 - -Code: -transaction(greeting: String) { - let guest: Address - - prepare(authorizer: AuthAccount) { - self.guest = authorizer.address - } - - execute { - log(greeting.concat(",").concat(self.guest.toString())) - } -} -Events: - None - -``` \ No newline at end of file diff --git a/docs/template.md b/docs/template.md index 07b5f4d89..525a1c8af 100644 --- a/docs/template.md +++ b/docs/template.md @@ -64,6 +64,7 @@ used to execute the commands. - Flag: `--network` - Short Flag: `-n` - Valid inputs: the name of a network defined in the configuration (`flow.json`) +- Default: `emulator` Specify which network you want the command to use for execution. From f00282da9309654290c616d5e21b12afb82293fd Mon Sep 17 00:00:00 2001 From: Gregor Gololicic Date: Mon, 19 Apr 2021 17:36:19 +0200 Subject: [PATCH 121/137] added missing examples --- internal/accounts/get.go | 7 ++++--- internal/accounts/staking-info.go | 7 ++++--- internal/blocks/get.go | 7 ++++--- internal/collections/get.go | 7 ++++--- internal/project/deploy.go | 5 +++-- internal/project/init.go | 5 +++-- internal/transactions/get.go | 1 + 7 files changed, 23 insertions(+), 16 deletions(-) diff --git a/internal/accounts/get.go b/internal/accounts/get.go index 7a9309b3f..26433c52a 100644 --- a/internal/accounts/get.go +++ b/internal/accounts/get.go @@ -36,9 +36,10 @@ var getFlags = flagsGet{} var GetCommand = &command.Command{ Cmd: &cobra.Command{ - Use: "get
", - Short: "Gets an account by address", - Args: cobra.ExactArgs(1), + Use: "get
", + Short: "Gets an account by address", + Example: "flow accounts get f8d6e0586b0a20c7", + Args: cobra.ExactArgs(1), }, Flags: &getFlags, Run: func( diff --git a/internal/accounts/staking-info.go b/internal/accounts/staking-info.go index 88e008788..08487a443 100644 --- a/internal/accounts/staking-info.go +++ b/internal/accounts/staking-info.go @@ -37,9 +37,10 @@ var stakingFlags = flagsStakingInfo{} var StakingCommand = &command.Command{ Cmd: &cobra.Command{ - Use: "staking-info
", - Short: "Get account staking info", - Args: cobra.ExactArgs(1), + Use: "staking-info
", + Short: "Get account staking info", + Example: "flow accounts staking-info f8d6e0586b0a20c7", + Args: cobra.ExactArgs(1), }, Flags: &stakingFlags, Run: func( diff --git a/internal/blocks/get.go b/internal/blocks/get.go index ffe3aa869..f11e99575 100644 --- a/internal/blocks/get.go +++ b/internal/blocks/get.go @@ -39,9 +39,10 @@ var blockFlags = flagsBlocks{} var GetCommand = &command.Command{ Cmd: &cobra.Command{ - Use: "get ", - Short: "Get block info", - Args: cobra.ExactArgs(1), + Use: "get ", + Short: "Get block info", + Example: "flow blocks get latest --network testnet", + Args: cobra.ExactArgs(1), }, Flags: &blockFlags, Run: func( diff --git a/internal/collections/get.go b/internal/collections/get.go index 1bbbb3922..ce2d18b34 100644 --- a/internal/collections/get.go +++ b/internal/collections/get.go @@ -31,9 +31,10 @@ var collectionFlags = flagsCollections{} var GetCommand = &command.Command{ Cmd: &cobra.Command{ - Use: "get ", - Short: "Get collection info", - Args: cobra.ExactArgs(1), + Use: "get ", + Short: "Get collection info", + Example: "flow collections get 270d...9c31e", + Args: cobra.ExactArgs(1), }, Flags: &collectionFlags, Run: func( diff --git a/internal/project/deploy.go b/internal/project/deploy.go index 87a8034b4..a3ef04da9 100644 --- a/internal/project/deploy.go +++ b/internal/project/deploy.go @@ -34,8 +34,9 @@ var deployFlags = flagsDeploy{} var DeployCommand = &command.Command{ Cmd: &cobra.Command{ - Use: "deploy", - Short: "Deploy Cadence contracts", + Use: "deploy", + Short: "Deploy Cadence contracts", + Example: "flow project deploy --network testnet", }, Flags: &deployFlags, Run: func( diff --git a/internal/project/init.go b/internal/project/init.go index 1cf28f441..33d6d710a 100644 --- a/internal/project/init.go +++ b/internal/project/init.go @@ -32,8 +32,9 @@ var initFlag = config.FlagsInit{} var InitCommand = &command.Command{ Cmd: &cobra.Command{ - Use: "init", - Short: "Initialize a new configuration", + Use: "init", + Short: "Initialize a new configuration", + Example: "flow project init", }, Flags: &initFlag, Run: func( diff --git a/internal/transactions/get.go b/internal/transactions/get.go index 4563651e3..60dc5b4f9 100644 --- a/internal/transactions/get.go +++ b/internal/transactions/get.go @@ -39,6 +39,7 @@ var GetCommand = &command.Command{ Use: "get ", Aliases: []string{"status"}, Short: "Get the transaction by ID", + Example: "flow transactions get 07a8...b433", Args: cobra.ExactArgs(1), }, Flags: &getFlags, From 661e7f1b9500cd094679057f2a5ab8cc6a1ac378 Mon Sep 17 00:00:00 2001 From: Gregor Gololicic Date: Mon, 19 Apr 2021 18:52:57 +0200 Subject: [PATCH 122/137] bugfix --- internal/keys/keys.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/internal/keys/keys.go b/internal/keys/keys.go index 8c271934c..43016dc9c 100644 --- a/internal/keys/keys.go +++ b/internal/keys/keys.go @@ -49,8 +49,8 @@ type KeyResult struct { // JSON convert result to JSON func (k *KeyResult) JSON() interface{} { result := make(map[string]string) - result["private"] = hex.EncodeToString(k.privateKey.PublicKey().Encode()) - result["public"] = hex.EncodeToString(k.privateKey.Encode()) + result["public"] = hex.EncodeToString(k.privateKey.PublicKey().Encode()) + result["private"] = hex.EncodeToString(k.privateKey.Encode()) return result } From d887ff36713b8fadd674596449ce76fbc3aeafdc Mon Sep 17 00:00:00 2001 From: Greg <75445744+sideninja@users.noreply.github.com> Date: Mon, 19 Apr 2021 18:57:25 +0200 Subject: [PATCH 123/137] Update docs/build-transactions.md Co-authored-by: Peter Siemens --- docs/build-transactions.md | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/docs/build-transactions.md b/docs/build-transactions.md index 8aa8a6aee..7bf056cbb 100644 --- a/docs/build-transactions.md +++ b/docs/build-transactions.md @@ -7,8 +7,8 @@ description: How to build a Flow transaction from the command line The Flow CLI provides a command to build a transactions with options to specify authorizer accounts, payer account and proposer account. -Build command don't produce any signatures and -should be used with the `sign` and `send-signed` commands. +The `build` command doesn't produce any signatures and instead +is designed to be used with the `sign` and `send-signed` commands. Use this functionality in the following order: 1. Use this command to build the transaction @@ -172,4 +172,3 @@ files by using `-f` flag multiple times. - From 2e75934cb824ed7978f9a9dcbecedd8e37068ab1 Mon Sep 17 00:00:00 2001 From: Greg <75445744+sideninja@users.noreply.github.com> Date: Mon, 19 Apr 2021 19:08:08 +0200 Subject: [PATCH 124/137] Update docs/create-accounts.md Co-authored-by: Peter Siemens --- docs/create-accounts.md | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/docs/create-accounts.md b/docs/create-accounts.md index dab110df0..096965521 100644 --- a/docs/create-accounts.md +++ b/docs/create-accounts.md @@ -63,8 +63,9 @@ upon creation. - Valid inputs: number between 0 and 1000 - Default: 1000 -Specify the weight of the key. When key weight is provided it must -match the number of keys. Specify key weight flag for each key flag. +Specify the weight of the public key being added to the new account. + +When opting to use this flag, you must specify a `--key-weight` flag for each public `--key` flag provided. ### Public Key Signature Algorithm From 289a7ad43c2f4a89d27fc141201c7e568d87b2c7 Mon Sep 17 00:00:00 2001 From: Greg <75445744+sideninja@users.noreply.github.com> Date: Mon, 19 Apr 2021 19:08:35 +0200 Subject: [PATCH 125/137] Update internal/command/command.go Co-authored-by: Peter Siemens --- internal/command/command.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/internal/command/command.go b/internal/command/command.go index 807677067..bf26abb4a 100644 --- a/internal/command/command.go +++ b/internal/command/command.go @@ -358,7 +358,7 @@ func checkVersion(logger output.Logger) { if string(latestVersion) != build.Semver() { logger.Info(fmt.Sprintf( - "\n⚠️ Version Warning: New version %s of Flow CLI is available.\n"+ + "\n⚠️ Version warning: a new version of Flow CLI is available (%s).\n"+ "Follow the Flow CLI installation guide for instructions on how to install or upgrade the CLI: https://docs.onflow.org/flow-cli/install", strings.ReplaceAll(string(latestVersion), "\n", ""), )) From 5c8fed2511cd74adabf076444181d37e9e502320 Mon Sep 17 00:00:00 2001 From: Greg <75445744+sideninja@users.noreply.github.com> Date: Mon, 19 Apr 2021 19:08:51 +0200 Subject: [PATCH 126/137] Update internal/command/command.go Co-authored-by: Peter Siemens --- internal/command/command.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/internal/command/command.go b/internal/command/command.go index bf26abb4a..b03fc884a 100644 --- a/internal/command/command.go +++ b/internal/command/command.go @@ -359,7 +359,7 @@ func checkVersion(logger output.Logger) { if string(latestVersion) != build.Semver() { logger.Info(fmt.Sprintf( "\n⚠️ Version warning: a new version of Flow CLI is available (%s).\n"+ - "Follow the Flow CLI installation guide for instructions on how to install or upgrade the CLI: https://docs.onflow.org/flow-cli/install", + "Read the installation guide for upgrade instructions: https://docs.onflow.org/flow-cli/install", strings.ReplaceAll(string(latestVersion), "\n", ""), )) } From 3f6593fe3884fa6333063d4354474c8dd545bf39 Mon Sep 17 00:00:00 2001 From: Greg <75445744+sideninja@users.noreply.github.com> Date: Mon, 19 Apr 2021 19:13:24 +0200 Subject: [PATCH 127/137] Docs improvements Co-authored-by: Peter Siemens --- docs/build-transactions.md | 7 +++---- docs/send-signed-transactions.md | 2 +- internal/transactions/build.go | 2 +- 3 files changed, 5 insertions(+), 6 deletions(-) diff --git a/docs/build-transactions.md b/docs/build-transactions.md index 7bf056cbb..0523b3f45 100644 --- a/docs/build-transactions.md +++ b/docs/build-transactions.md @@ -11,9 +11,9 @@ The `build` command doesn't produce any signatures and instead is designed to be used with the `sign` and `send-signed` commands. Use this functionality in the following order: -1. Use this command to build the transaction -2. Use the sign command to sign with all accounts specified in the build process -3. Use send signed command to submit the signed transaction to the network. +1. Use this command (`build`) to build the transaction. +2. Use the `sign` command to sign with all accounts specified in the build process. +3. Use `send-signed` command to submit the signed transaction to the Flow network. ```shell flow transactions build @@ -171,4 +171,3 @@ files by using `-f` flag multiple times. - diff --git a/docs/send-signed-transactions.md b/docs/send-signed-transactions.md index 81819b329..3b14f9aa0 100644 --- a/docs/send-signed-transactions.md +++ b/docs/send-signed-transactions.md @@ -1,7 +1,7 @@ --- title: Send Signed Transaction with the Flow CLI sidebar_title: Send Signed Transaction -description: How to send signed Flow transaction from the command line +description: How to send a signed Flow transaction from the command line --- The Flow CLI provides a command to send signed transactions to diff --git a/internal/transactions/build.go b/internal/transactions/build.go index 6704ae8f6..1a07a5f5c 100644 --- a/internal/transactions/build.go +++ b/internal/transactions/build.go @@ -38,7 +38,7 @@ var buildFlags = flagsBuild{} var BuildCommand = &command.Command{ Cmd: &cobra.Command{ Use: "build ", - Short: "Build a transaction for later signing", + Short: "Build an unsigned transaction", Example: "flow transactions build ./transaction.cdc --proposer alice --authorizer alice --payer bob", Args: cobra.ExactArgs(1), }, From 2c8816274b94b36f80b8cab06c21a63661c7bde6 Mon Sep 17 00:00:00 2001 From: Gregor Gololicic Date: Mon, 19 Apr 2021 19:18:08 +0200 Subject: [PATCH 128/137] docs fixes --- docs/build-transactions.md | 7 ++++++- docs/send-signed-transactions.md | 6 +++--- docs/sign-transaction.md | 9 +++++---- 3 files changed, 14 insertions(+), 8 deletions(-) diff --git a/docs/build-transactions.md b/docs/build-transactions.md index 0523b3f45..90e845fc9 100644 --- a/docs/build-transactions.md +++ b/docs/build-transactions.md @@ -22,7 +22,12 @@ flow transactions build ## Example Usage ```shell -> flow transactions build ./transaction.cdc --signer alice --proposer bob --payer charlie --arg "String:Meow" +> flow transactions build ./transaction.cdc \ + --signer alice \ + --proposer bob \ + --payer charlie \ + --arg "String:Meow" \ + --filter payload --save built.rlp ID e8c0a69952fbe50a66703985e220307c8d44b8fa36c76cbca03f8c43d0167847 Payer e03daebed8ca0615 diff --git a/docs/send-signed-transactions.md b/docs/send-signed-transactions.md index 3b14f9aa0..cf0c9df05 100644 --- a/docs/send-signed-transactions.md +++ b/docs/send-signed-transactions.md @@ -8,9 +8,9 @@ The Flow CLI provides a command to send signed transactions to any Flow Access API. Use this functionality in the following order: -1. Use this command to build the transaction -2. Use the sign command to sign with all accounts specified in the build process -3. Use send signed command to submit the signed transaction to the network. +1. Use this command (`build`) to build the transaction. +2. Use the `sign` command to sign with all accounts specified in the build process. +3. Use `send-signed` command to submit the signed transaction to the Flow network. ```shell flow transactions send-signed diff --git a/docs/sign-transaction.md b/docs/sign-transaction.md index 76a52dc02..6d3174f1c 100644 --- a/docs/sign-transaction.md +++ b/docs/sign-transaction.md @@ -8,9 +8,9 @@ The Flow CLI provides a command to sign transactions with options to specify authorizer accounts, payer accounts and proposer accounts. Use this functionality in the following order: -1. Use this command to build the transaction -2. Use the sign command to sign with all accounts specified in the build process -3. Use send signed command to submit the signed transaction to the network. +1. Use this command (`build`) to build the transaction. +2. Use the `sign` command to sign with all accounts specified in the build process. +3. Use `send-signed` command to submit the signed transaction to the Flow network. ```shell flow transactions sign @@ -19,7 +19,8 @@ flow transactions sign ## Example Usage ```shell -> flow transactions sign ./built.rlp --signer alice +> flow transactions sign ./built.rlp --signer alice \ + --filter payload --save signed.rlp Hash b03b18a8d9d30ff7c9f0fdaa80fcaab242c2f36eedb687dd9b368326311fe376 Payer f8d6e0586b0a20c7 From 189f417fb7e684cdab3538af8467c3ea39d159b7 Mon Sep 17 00:00:00 2001 From: Gregor Gololicic Date: Mon, 19 Apr 2021 19:23:30 +0200 Subject: [PATCH 129/137] refactor parse address --- pkg/flowcli/services/transactions.go | 6 ++++-- pkg/flowcli/util/utilities.go | 4 ++-- 2 files changed, 6 insertions(+), 4 deletions(-) diff --git a/pkg/flowcli/services/transactions.go b/pkg/flowcli/services/transactions.go index 5f1a9e118..49d583b8b 100644 --- a/pkg/flowcli/services/transactions.go +++ b/pkg/flowcli/services/transactions.go @@ -297,8 +297,10 @@ func (t *Transactions) SendForAddressWithCode( // getAddressFromStringOrConfig try to parse value as address or as an account from the config func getAddressFromStringOrConfig(value string, project *project.Project) (flow.Address, error) { - if util.ValidAddress(value) { - return flow.HexToAddress(value), nil + address, isValid := util.ParseAddress(value) + + if isValid { + return address, nil } else if project != nil { account := project.AccountByName(value) if account == nil { diff --git a/pkg/flowcli/util/utilities.go b/pkg/flowcli/util/utilities.go index 0c257787e..b24c66931 100644 --- a/pkg/flowcli/util/utilities.go +++ b/pkg/flowcli/util/utilities.go @@ -114,11 +114,11 @@ func ContainsString(s []string, e string) bool { return false } -func ValidAddress(value string) bool { +func ParseAddress(value string) (flow.Address, bool) { address := flow.HexToAddress(value) // valid on any chain - return address.IsValid(flow.Mainnet) || + return address, address.IsValid(flow.Mainnet) || address.IsValid(flow.Testnet) || address.IsValid(flow.Emulator) } From 2e9d2c875a5369884ead63e223a717a9209fed73 Mon Sep 17 00:00:00 2001 From: Gregor Gololicic Date: Mon, 19 Apr 2021 19:30:54 +0200 Subject: [PATCH 130/137] sanitize version text --- internal/command/command.go | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/internal/command/command.go b/internal/command/command.go index b03fc884a..16c6b51b8 100644 --- a/internal/command/command.go +++ b/internal/command/command.go @@ -354,9 +354,10 @@ func checkVersion(logger output.Logger) { } defer resp.Body.Close() - latestVersion, _ := ioutil.ReadAll(resp.Body) + body, _ := ioutil.ReadAll(resp.Body) + latestVersion := strings.TrimSpace(string(body)) - if string(latestVersion) != build.Semver() { + if latestVersion != build.Semver() { logger.Info(fmt.Sprintf( "\n⚠️ Version warning: a new version of Flow CLI is available (%s).\n"+ "Read the installation guide for upgrade instructions: https://docs.onflow.org/flow-cli/install", From 7cb8f6d3a00ec766b327d8c29a057766eca79ddc Mon Sep 17 00:00:00 2001 From: Gregor Gololicic Date: Mon, 19 Apr 2021 19:53:32 +0200 Subject: [PATCH 131/137] check for deploy accounts and contracts --- pkg/flowcli/config/config.go | 9 ++++++--- pkg/flowcli/project/project.go | 15 ++++++++++++--- pkg/flowcli/services/project.go | 9 +++++++-- pkg/flowcli/services/scripts.go | 7 ++++++- pkg/flowcli/services/transactions.go | 7 ++++++- 5 files changed, 37 insertions(+), 10 deletions(-) diff --git a/pkg/flowcli/config/config.go b/pkg/flowcli/config/config.go index 07ed99a94..9b92e4424 100644 --- a/pkg/flowcli/config/config.go +++ b/pkg/flowcli/config/config.go @@ -163,7 +163,7 @@ func (c *Contract) IsAlias() bool { } // GetByNameAndNetwork get contract array for account and network -func (c *Contracts) GetByNameAndNetwork(name string, network string) Contract { +func (c *Contracts) GetByNameAndNetwork(name string, network string) *Contract { contracts := make(Contracts, 0) for _, contract := range *c { @@ -176,15 +176,18 @@ func (c *Contracts) GetByNameAndNetwork(name string, network string) Contract { // and replace only name and source with existing if len(contracts) == 0 { cName := c.GetByName(name) + if cName == nil { + return nil + } - return Contract{ + return &Contract{ Name: cName.Name, Network: network, Source: cName.Source, } } - return contracts[0] + return &contracts[0] } // TODO: this filtering can cause error if not found, better to refactor to returning diff --git a/pkg/flowcli/project/project.go b/pkg/flowcli/project/project.go index f741a443e..b569acfe3 100644 --- a/pkg/flowcli/project/project.go +++ b/pkg/flowcli/project/project.go @@ -131,7 +131,10 @@ func newProject(conf *config.Config, composer *config.Loader) (*Project, error) // The CLI currently does not allow the same contract to be deployed to multiple // accounts in the same network. func (p *Project) ContractConflictExists(network string) bool { - contracts := p.ContractsByNetwork(network) + contracts, error := p.ContractsByNetwork(network) + if error != nil { + return false + } uniq := funk.Uniq( funk.Map(contracts, func(c Contract) string { @@ -171,16 +174,22 @@ func (p *Project) SetEmulatorServiceKey(privateKey crypto.PrivateKey) { } // ContractsByNetwork returns all contracts for a network. -func (p *Project) ContractsByNetwork(network string) []Contract { +func (p *Project) ContractsByNetwork(network string) ([]Contract, error) { contracts := make([]Contract, 0) // get deployments for the specified network for _, deploy := range p.conf.Deployments.GetByNetwork(network) { account := p.AccountByName(deploy.Account) + if account == nil { + return nil, fmt.Errorf("could not find account with name %s in the configuration", deploy.Account) + } // go through each contract in this deployment for _, contractName := range deploy.Contracts { c := p.conf.Contracts.GetByNameAndNetwork(contractName, network) + if c == nil { + return nil, fmt.Errorf("could not find contract with name name %s in the configuration", contractName) + } contract := Contract{ Name: c.Name, @@ -192,7 +201,7 @@ func (p *Project) ContractsByNetwork(network string) []Contract { } } - return contracts + return contracts, nil } // AccountNamesForNetwork returns all configured account names for a network. diff --git a/pkg/flowcli/services/project.go b/pkg/flowcli/services/project.go index 632f95a1b..5fb656d95 100644 --- a/pkg/flowcli/services/project.go +++ b/pkg/flowcli/services/project.go @@ -109,7 +109,12 @@ func (p *Project) Deploy(network string, update bool) ([]*contracts.Contract, er p.project.AliasesForNetwork(network), ) - for _, contract := range p.project.ContractsByNetwork(network) { + contractsNetwork, err := p.project.ContractsByNetwork(network) + if err != nil { + return nil, err + } + + for _, contract := range contractsNetwork { err := processor.AddContractSource( contract.Name, contract.Source, @@ -120,7 +125,7 @@ func (p *Project) Deploy(network string, update bool) ([]*contracts.Contract, er } } - err := processor.ResolveImports() + err = processor.ResolveImports() if err != nil { return nil, err } diff --git a/pkg/flowcli/services/scripts.go b/pkg/flowcli/services/scripts.go index b2dd97216..9aa72d5c3 100644 --- a/pkg/flowcli/services/scripts.go +++ b/pkg/flowcli/services/scripts.go @@ -88,9 +88,14 @@ func (s *Scripts) execute(code []byte, args []string, argsJSON string, scriptPat return nil, fmt.Errorf("resolving imports in scripts not supported") } + contractsNetwork, err := s.project.ContractsByNetwork(network) + if err != nil { + return nil, err + } + code, err = resolver.ResolveImports( scriptPath, - s.project.ContractsByNetwork(network), + contractsNetwork, s.project.AliasesForNetwork(network), ) if err != nil { diff --git a/pkg/flowcli/services/transactions.go b/pkg/flowcli/services/transactions.go index 3740038fa..4803c9cfa 100644 --- a/pkg/flowcli/services/transactions.go +++ b/pkg/flowcli/services/transactions.go @@ -145,9 +145,14 @@ func (t *Transactions) Build( return nil, fmt.Errorf("resolving imports in transactions not supported") } + contractsNetwork, err := t.project.ContractsByNetwork(network) + if err != nil { + return nil, err + } + code, err = resolver.ResolveImports( codeFilename, - t.project.ContractsByNetwork(network), + contractsNetwork, t.project.AliasesForNetwork(network), ) if err != nil { From 93cd575af36d52ba976255f8bc356d60b0ae8386 Mon Sep 17 00:00:00 2001 From: Gregor Gololicic Date: Mon, 19 Apr 2021 19:54:58 +0200 Subject: [PATCH 132/137] fixed tests --- pkg/flowcli/project/project_test.go | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/pkg/flowcli/project/project_test.go b/pkg/flowcli/project/project_test.go index a89af259c..5b6f401cb 100644 --- a/pkg/flowcli/project/project_test.go +++ b/pkg/flowcli/project/project_test.go @@ -318,7 +318,7 @@ Project Tests func Test_GetContractsByNameSimple(t *testing.T) { p := generateSimpleProject() - contracts := p.ContractsByNetwork("emulator") + contracts, _ := p.ContractsByNetwork("emulator") assert.Len(t, contracts, 1) assert.Equal(t, contracts[0].Name, "NonFungibleToken") @@ -360,7 +360,7 @@ func Test_HostSimple(t *testing.T) { func Test_GetContractsByNameComplex(t *testing.T) { p := generateComplexProject() - contracts := p.ContractsByNetwork("emulator") + contracts, _ := p.ContractsByNetwork("emulator") assert.Equal(t, 7, len(contracts)) @@ -452,7 +452,7 @@ func Test_GetAliases(t *testing.T) { p := generateAliasesProject() aliases := p.AliasesForNetwork("emulator") - contracts := p.ContractsByNetwork("emulator") + contracts, _ := p.ContractsByNetwork("emulator") assert.Len(t, aliases, 1) assert.Equal(t, aliases["../hungry-kitties/cadence/contracts/FungibleToken.cdc"], "ee82856bf20e2aa6") @@ -464,10 +464,10 @@ func Test_GetAliasesComplex(t *testing.T) { p := generateAliasesComplexProject() aEmulator := p.AliasesForNetwork("emulator") - cEmulator := p.ContractsByNetwork("emulator") + cEmulator, _ := p.ContractsByNetwork("emulator") aTestnet := p.AliasesForNetwork("testnet") - cTestnet := p.ContractsByNetwork("testnet") + cTestnet, _ := p.ContractsByNetwork("testnet") assert.Len(t, cEmulator, 1) assert.Equal(t, cEmulator[0].Name, "NonFungibleToken") From 51f2b4972f1746682e4518932d75c829213735a8 Mon Sep 17 00:00:00 2001 From: Greg <75445744+sideninja@users.noreply.github.com> Date: Tue, 20 Apr 2021 12:24:49 +0200 Subject: [PATCH 133/137] Update docs/developer-updates/release-notes-v18.md Co-authored-by: Peter Siemens --- docs/developer-updates/release-notes-v18.md | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/docs/developer-updates/release-notes-v18.md b/docs/developer-updates/release-notes-v18.md index 68e5b0f24..844e3d7e8 100644 --- a/docs/developer-updates/release-notes-v18.md +++ b/docs/developer-updates/release-notes-v18.md @@ -2,9 +2,6 @@ Follow the [Flow CLI installation guide](https://docs.onflow.org/flow-cli/install/) for instructions on how to install or upgrade the CLI. -## 💥 Breaking Changes -/ - ## ⭐ Features ### Resolve Contract Imports in Scripts and Transactions @@ -190,4 +187,4 @@ This bug was fixed. ### Emulator Config Path When running emulator command `flow emulator` config flag `-f` was ignored. This has been fixed, so you can provide a custom path to the config while running -the start emulator command. \ No newline at end of file +the start emulator command. From bd9e724215427934aa049578f4b0a0d610d98b3d Mon Sep 17 00:00:00 2001 From: Greg <75445744+sideninja@users.noreply.github.com> Date: Tue, 20 Apr 2021 12:24:57 +0200 Subject: [PATCH 134/137] Update docs/developer-updates/release-notes-v18.md Co-authored-by: Peter Siemens --- docs/developer-updates/release-notes-v18.md | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/docs/developer-updates/release-notes-v18.md b/docs/developer-updates/release-notes-v18.md index 844e3d7e8..54b778a89 100644 --- a/docs/developer-updates/release-notes-v18.md +++ b/docs/developer-updates/release-notes-v18.md @@ -5,9 +5,11 @@ Follow the [Flow CLI installation guide](https://docs.onflow.org/flow-cli/instal ## ⭐ Features ### Resolve Contract Imports in Scripts and Transactions -A new feature that allows you to send transactions and scripts that reference -contract deployed using the project deploy command. Imports are resolved -the same way as project deploy are. Example: +This is a new feature that allows you to send transactions and scripts that reference +contracts deployed using the `project deploy` command. Imports are resolved +by matching contract source paths to their declarations in `flow.json`. + +For example: Example script: `get_supply.cdc` ``` From 0e07d082ab4c2555bb4697f344b5ecefaad001e3 Mon Sep 17 00:00:00 2001 From: Greg <75445744+sideninja@users.noreply.github.com> Date: Tue, 20 Apr 2021 12:28:00 +0200 Subject: [PATCH 135/137] Update pkg/flowcli/project/project.go Co-authored-by: Peter Siemens --- pkg/flowcli/project/project.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pkg/flowcli/project/project.go b/pkg/flowcli/project/project.go index b569acfe3..582f67517 100644 --- a/pkg/flowcli/project/project.go +++ b/pkg/flowcli/project/project.go @@ -131,8 +131,8 @@ func newProject(conf *config.Config, composer *config.Loader) (*Project, error) // The CLI currently does not allow the same contract to be deployed to multiple // accounts in the same network. func (p *Project) ContractConflictExists(network string) bool { - contracts, error := p.ContractsByNetwork(network) - if error != nil { + contracts, err := p.ContractsByNetwork(network) + if err != nil { return false } From d4fb2b046a03a3838f83dbce3b1fff604170c283 Mon Sep 17 00:00:00 2001 From: Gregor Gololicic Date: Tue, 20 Apr 2021 12:38:42 +0200 Subject: [PATCH 136/137] linted --- internal/accounts/accounts.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/internal/accounts/accounts.go b/internal/accounts/accounts.go index 361840fcd..e98c6a33f 100644 --- a/internal/accounts/accounts.go +++ b/internal/accounts/accounts.go @@ -53,7 +53,7 @@ type AccountResult struct { func (r *AccountResult) JSON() interface{} { result := make(map[string]interface{}) result["address"] = r.Address - result["balance"] = fmt.Sprintf("%s", cadence.UFix64(r.Balance)) + result["balance"] = cadence.UFix64(r.Balance).String() keys := make([]string, 0) for _, key := range r.Keys { From a4d880cdeae70b178d94740cefe78af0f1db7855 Mon Sep 17 00:00:00 2001 From: Gregor Gololicic Date: Tue, 20 Apr 2021 16:32:12 +0200 Subject: [PATCH 137/137] quick fix default network flag is not empty string anymore but has default value --- internal/command/command.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/internal/command/command.go b/internal/command/command.go index fe56982e2..fb2cd2d40 100644 --- a/internal/command/command.go +++ b/internal/command/command.go @@ -218,7 +218,7 @@ func resolveHost(proj *project.Project, hostFlag string, networkFlag string) (st return hostFlag, nil } // network flag with project initialized is next - if networkFlag != "" && proj != nil { + if proj != nil { check := proj.NetworkByName(networkFlag) if check == nil { return "", fmt.Errorf("network with name %s does not exist in configuration", networkFlag)