diff --git a/go.mod b/go.mod index ea1afa724..8824d9dbc 100644 --- a/go.mod +++ b/go.mod @@ -22,8 +22,8 @@ require ( github.com/onflow/flow-emulator v1.7.0 github.com/onflow/flow-evm-gateway v1.3.0 github.com/onflow/flow-go v0.43.0-dev-pebble.1.0.20250910132853-12699a150fd9 - github.com/onflow/flow-go-sdk v1.8.1 - github.com/onflow/flowkit/v2 v2.5.0 + github.com/onflow/flow-go-sdk v1.8.3-0.20250917204435-cd9d4cf5f6af + github.com/onflow/flowkit/v2 v2.5.1 github.com/onflowser/flowser/v3 v3.2.1-0.20240131200229-7d4d22715f48 github.com/pkg/browser v0.0.0-20240102092130-5ac0b6a4141c github.com/pkg/errors v0.9.1 @@ -291,7 +291,7 @@ require ( google.golang.org/genproto v0.0.0-20250603155806-513f23925822 // indirect google.golang.org/genproto/googleapis/api v0.0.0-20250707201910-8d1bb00bc6a7 // indirect google.golang.org/genproto/googleapis/rpc v0.0.0-20250804133106-a7a43d27e69b // indirect - google.golang.org/protobuf v1.36.7 // indirect + google.golang.org/protobuf v1.36.9 // indirect gopkg.in/yaml.v2 v2.4.0 // indirect gopkg.in/yaml.v3 v3.0.1 // indirect lukechampine.com/blake3 v1.4.1 // indirect diff --git a/go.sum b/go.sum index 75a0d5072..92962a440 100644 --- a/go.sum +++ b/go.sum @@ -72,20 +72,20 @@ github.com/atotto/clipboard v0.1.4/go.mod h1:ZY9tmq7sm5xIbd9bOK4onWV4S6X0u6GY7Vn github.com/aws/aws-lambda-go v1.13.3/go.mod h1:4UKl9IzQMoD+QF79YdCuzCwp8VbmG4VAQwij/eHl5CU= github.com/aws/aws-sdk-go v1.27.0/go.mod h1:KmX6BPdI08NWTb3/sm4ZGu5ShLoqVDhKgpiN924inxo= github.com/aws/aws-sdk-go-v2 v0.18.0/go.mod h1:JWVYvqSMppoMJC0x5wdwiImzgXTI9FuZwxzkQq9wy+g= -github.com/aws/aws-sdk-go-v2 v1.38.1 h1:j7sc33amE74Rz0M/PoCpsZQ6OunLqys/m5antM0J+Z8= -github.com/aws/aws-sdk-go-v2 v1.38.1/go.mod h1:9Q0OoGQoboYIAJyslFyF1f5K1Ryddop8gqMhWx/n4Wg= +github.com/aws/aws-sdk-go-v2 v1.39.0 h1:xm5WV/2L4emMRmMjHFykqiA4M/ra0DJVSWUkDyBjbg4= +github.com/aws/aws-sdk-go-v2 v1.39.0/go.mod h1:sDioUELIUO9Znk23YVmIk86/9DOpkbyyVb1i/gUNFXY= github.com/aws/aws-sdk-go-v2/feature/s3/manager v1.5.1 h1:VGkV9KmhGqOQWnHyi4gLG98kE6OecT42fdrCGFWxJsc= github.com/aws/aws-sdk-go-v2/feature/s3/manager v1.5.1/go.mod h1:PLlnMiki//sGnCJiW+aVpvP/C8Kcm8mEj/IVm9+9qk4= -github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.13.0 h1:6+lZi2JeGKtCraAj1rpoZfKqnQ9SptseRZioejfUOLM= -github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.13.0/go.mod h1:eb3gfbVIxIoGgJsi9pGne19dhCBpK6opTYpQqAmdy44= -github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.13.4 h1:ueB2Te0NacDMnaC+68za9jLwkjzxGWm0KB5HTUHjLTI= -github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.13.4/go.mod h1:nLEfLnVMmLvyIG58/6gsSA03F1voKGaCfHV7+lR8S7s= +github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.13.1 h1:oegbebPEMA/1Jny7kvwejowCaHz1FWZAQ94WXFNCyTM= +github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.13.1/go.mod h1:kemo5Myr9ac0U9JfSjMo9yHLtw+pECEHsFtJ9tqCEI8= +github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.13.7 h1:mLgc5QIgOy26qyh5bvW+nDoAppxgn3J2WV3m9ewq7+8= +github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.13.7/go.mod h1:wXb/eQnqt8mDQIQTTmcw58B5mYGxzLGZGK8PWNFZ0BA= github.com/aws/aws-sdk-go-v2/service/internal/s3shared v1.7.0 h1:HWsM0YQWX76V6MOp07YuTYacm8k7h69ObJuw7Nck+og= github.com/aws/aws-sdk-go-v2/service/internal/s3shared v1.7.0/go.mod h1:LKb3cKNQIMh+itGnEpKGcnL/6OIjPZqrtYah1w5f+3o= github.com/aws/aws-sdk-go-v2/service/s3 v1.15.0 h1:nPLfLPfglacc29Y949sDxpr3X/blaY40s3B85WT2yZU= github.com/aws/aws-sdk-go-v2/service/s3 v1.15.0/go.mod h1:Iv2aJVtVSm/D22rFoX99cLG4q4uB7tppuCsulGe98k4= -github.com/aws/smithy-go v1.22.5 h1:P9ATCXPMb2mPjYBgueqJNCA5S9UfktsW0tTxi+a7eqw= -github.com/aws/smithy-go v1.22.5/go.mod h1:t1ufH5HMublsJYulve2RKmHDC15xu1f26kHCp/HgceI= +github.com/aws/smithy-go v1.23.0 h1:8n6I3gXzWJB2DxBDnfxgBaSX6oe0d/t10qGz7OKqMCE= +github.com/aws/smithy-go v1.23.0/go.mod h1:t1ufH5HMublsJYulve2RKmHDC15xu1f26kHCp/HgceI= github.com/aymanbagabas/go-osc52/v2 v2.0.1 h1:HwpRHbFMcZLEVr42D4p7XBqjyuxQH5SMiErDT4WkJ2k= github.com/aymanbagabas/go-osc52/v2 v2.0.1/go.mod h1:uYgXzlJ7ZpABp8OJ+exZzJJhRNQ2ASbcXHWsFqH8hp8= github.com/aymanbagabas/go-udiff v0.2.0 h1:TK0fH4MteXUDspT88n8CKzvK0X9O2xu9yQjWpi6yML8= @@ -801,16 +801,20 @@ github.com/onflow/flow-ft/lib/go/templates v1.0.1 h1:FDYKAiGowABtoMNusLuRCILIZDt github.com/onflow/flow-ft/lib/go/templates v1.0.1/go.mod h1:uQ8XFqmMK2jxyBSVrmyuwdWjTEb+6zGjRYotfDJ5pAE= github.com/onflow/flow-go v0.43.0-dev-pebble.1.0.20250910132853-12699a150fd9 h1:LzgHQI7A8rINyfzKEF6x2gsrzx7zGBQpmgdHJjJtQqM= github.com/onflow/flow-go v0.43.0-dev-pebble.1.0.20250910132853-12699a150fd9/go.mod h1:VkvpX4p4imUpPR+FhL0Qw7Qx32zQ/QOQRz2Vl2uu50Y= -github.com/onflow/flow-go-sdk v1.8.1 h1:BPp7p10RrpOdezQ3RJ+nheOqpalHlTB9bRocVkLsGNU= -github.com/onflow/flow-go-sdk v1.8.1/go.mod h1:w6bxCznDhJJCDybn1jCUAz3rEO4/7XY9EgWRFrj0zoo= +github.com/onflow/flow-go-sdk v1.8.2 h1:Jkoh0LdH4kIADFdHoHK31qHcH0QnCkAL+ybjAkBEbqc= +github.com/onflow/flow-go-sdk v1.8.2/go.mod h1:/5g1t+xgk1nFXz8ifk8O3aT4DqLwq5p3k2BhiW4ZX+U= +github.com/onflow/flow-go-sdk v1.8.3-0.20250917001858-5aa1f787eb8e h1:A4EVQWNo8bTlGV7O1e7AzKJ4WXVOTPryY2SHsCqVR3I= +github.com/onflow/flow-go-sdk v1.8.3-0.20250917001858-5aa1f787eb8e/go.mod h1:/5g1t+xgk1nFXz8ifk8O3aT4DqLwq5p3k2BhiW4ZX+U= +github.com/onflow/flow-go-sdk v1.8.3-0.20250917204435-cd9d4cf5f6af h1:C7pJVDcTEFqm65oW27WgpRhONOvPu4lFFWx9kGZKLgg= +github.com/onflow/flow-go-sdk v1.8.3-0.20250917204435-cd9d4cf5f6af/go.mod h1:/5g1t+xgk1nFXz8ifk8O3aT4DqLwq5p3k2BhiW4ZX+U= github.com/onflow/flow-nft/lib/go/contracts v1.2.4 h1:gWJgSSgIGo0qWOqr90+khQ69VoYF9vNlqzF+Yh6YYy4= github.com/onflow/flow-nft/lib/go/contracts v1.2.4/go.mod h1:eZ9VMMNfCq0ho6kV25xJn1kXeCfxnkhj3MwF3ed08gY= github.com/onflow/flow-nft/lib/go/templates v1.2.1 h1:SAALMZPDw9Eb9p5kSLnmnFxjyig1MLiT4JUlLp0/bSE= github.com/onflow/flow-nft/lib/go/templates v1.2.1/go.mod h1:W6hOWU0xltPqNpv9gQX8Pj8Jtf0OmRxc1XX2V0kzJaI= github.com/onflow/flow/protobuf/go/flow v0.4.12 h1:nMJHVuz2iRQnzEwvmruCaMrQvm/dfdWtbKroi3o/42M= github.com/onflow/flow/protobuf/go/flow v0.4.12/go.mod h1:NA2pX2nw8zuaxfKphhKsk00kWLwfd+tv8mS23YXO4Sk= -github.com/onflow/flowkit/v2 v2.5.0 h1:Y5eFuFHem8a4gNaZl+47Jr7qyBFkU0X+opUVUD72CcE= -github.com/onflow/flowkit/v2 v2.5.0/go.mod h1:wfWK0O8VxdCbAREo1Snnagt1l9GuqFdmyAQXeymzpiY= +github.com/onflow/flowkit/v2 v2.5.1 h1:02Y91zpwGDUhbGu+E4RVQ90ltaVcP6GLpNTBOEI5vaM= +github.com/onflow/flowkit/v2 v2.5.1/go.mod h1:59aJa3S+1MtDbb13wQF1igw7Nsvw5kQSUa0vBDGELmI= github.com/onflow/go-ethereum v1.15.10 h1:blZBeOLJDOVWqKuhkkMh6S2PKQAJvdgbvOL9ZNggFcU= github.com/onflow/go-ethereum v1.15.10/go.mod h1:t2nZJtwruVjA5u5yEK8InFzjImFLHrF7ak2bw3E4LDM= github.com/onflow/nft-storefront/lib/go/contracts v1.0.0 h1:sxyWLqGm/p4EKT6DUlQESDG1ZNMN9GjPCm1gTq7NGfc= @@ -1461,8 +1465,8 @@ google.golang.org/protobuf v1.24.0/go.mod h1:r/3tXBNzIEhYS9I1OUVjXDlt8tc493IdKGj google.golang.org/protobuf v1.25.0/go.mod h1:9JNX74DMeImyA3h4bdi1ymwjUzf21/xIlbajtzgsN7c= google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw= google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc= -google.golang.org/protobuf v1.36.7 h1:IgrO7UwFQGJdRNXH/sQux4R1Dj1WAKcLElzeeRaXV2A= -google.golang.org/protobuf v1.36.7/go.mod h1:jduwjTPXsFjZGTmRluh+L6NjiWu7pchiJ2/5YcXBHnY= +google.golang.org/protobuf v1.36.9 h1:w2gp2mA27hUeUzj9Ex9FBjsBm40zfaDtEWow293U7Iw= +google.golang.org/protobuf v1.36.9/go.mod h1:fuxRtAxBytpl4zzqUh6/eyUujkJdNiuEkXntxiD/uRU= gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= diff --git a/internal/prompt/prompt.go b/internal/prompt/prompt.go index 376a20a25..19a8689b8 100644 --- a/internal/prompt/prompt.go +++ b/internal/prompt/prompt.go @@ -75,16 +75,26 @@ func ApproveTransactionPrompt(tx *flow.Transaction, promptMsg string) bool { 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) + _, _ = fmt.Fprintf(writer, " Address\t\t%s\n", e.Address) + _, _ = fmt.Fprintf(writer, " Signature\t\t%x\n", e.Signature) + _, _ = fmt.Fprintf(writer, " Key Index\t\t%d\n", e.KeyIndex) + if len(e.ExtensionData) > 0 { + _, _ = fmt.Fprintf(writer, " Extension Data\t%x\n", e.ExtensionData) + } else { + _, _ = fmt.Fprintf(writer, " Extension Data\t None\n") + } } 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) + _, _ = fmt.Fprintf(writer, " Address\t\t%s\n", e.Address) + _, _ = fmt.Fprintf(writer, " Signature\t\t%x\n", e.Signature) + _, _ = fmt.Fprintf(writer, " Key Index\t\t%d\n", e.KeyIndex) + if len(e.ExtensionData) > 0 { + _, _ = fmt.Fprintf(writer, " Extension Data\t%x\n", e.ExtensionData) + } else { + _, _ = fmt.Fprintf(writer, " Extension Data\t None\n") + } } if tx.Script != nil { diff --git a/internal/transactions/sign.go b/internal/transactions/sign.go index 689e157ec..a918e5dad 100644 --- a/internal/transactions/sign.go +++ b/internal/transactions/sign.go @@ -24,11 +24,16 @@ import ( "encoding/hex" "fmt" "io" + "math" "net/http" "sort" + "strconv" + "strings" "github.com/onflow/flow-cli/internal/prompt" + "github.com/onflow/flow-go-sdk/crypto" + "github.com/onflow/flowkit/v2/config" "github.com/onflow/flowkit/v2/transactions" "github.com/onflow/flowkit/v2/accounts" @@ -46,6 +51,7 @@ type flagsSign struct { Signer []string `default:"emulator-account" flag:"signer" info:"name of a single or multiple comma-separated accounts used to sign"` Include []string `default:"" flag:"include" info:"Fields to include in the output. Valid values: signatures, code, payload."` FromRemoteUrl string `default:"" flag:"from-remote-url" info:"server URL where RLP can be fetched, signed RLP will be posted back to remote URL."` + RawSig []string `default:"" flag:"raw-sig" info:"Raw hex-encoded signature to add to the transaction, instead of signing with a private key from an account in the config."` } var signFlags = flagsSign{} @@ -101,12 +107,29 @@ func sign( return nil, err } + // Use raw signatures if provided, and if the number of signatures matches the number of signers + useRawSig := len(signFlags.RawSig) == len(signFlags.Signer) + // validate all signers - for _, signerName := range signFlags.Signer { + for i, signerName := range signFlags.Signer { signer, err := state.Accounts().ByName(signerName) if err != nil { return nil, fmt.Errorf("signer account: [%s] doesn't exists in configuration", signerName) } + if useRawSig { + sig, err := hex.DecodeString(strings.ReplaceAll(signFlags.RawSig[i], "0x", "")) + if err != nil { + return nil, fmt.Errorf("invalid message signature: %w", err) + } + // If a raw signature is provided, use a dummy key that returns the signature instead of signing + signer.Key = &sigAddKey{ + index: signer.Key.Index(), + signer: crypto.NewAddSignatureSigner(sig, nil), + sigAlgo: signer.Key.SigAlgo(), + hashAlgo: signer.Key.HashAlgo(), + keyType: signer.Key.Type(), + } + } signers = append(signers, signer) } @@ -181,3 +204,70 @@ func postRLPTransaction(rlpUrl string, tx *flowsdk.Transaction) error { return nil } + +type sigAddKey struct { + keyType config.KeyType + index uint32 + sigAlgo crypto.SignatureAlgorithm + hashAlgo crypto.HashAlgorithm + signer crypto.Signer +} + +var _ accounts.Key = &sigAddKey{} + +func (a *sigAddKey) Type() config.KeyType { + return a.keyType +} + +func (a *sigAddKey) SigAlgo() crypto.SignatureAlgorithm { + if a.sigAlgo == crypto.UnknownSignatureAlgorithm { + return crypto.ECDSA_P256 // default value + } + return a.sigAlgo +} + +func (a *sigAddKey) HashAlgo() crypto.HashAlgorithm { + if a.hashAlgo == crypto.UnknownHashAlgorithm { + return crypto.SHA3_256 // default value + } + return a.hashAlgo +} + +func (a *sigAddKey) Index() uint32 { + return a.index // default to 0 +} + +func (a *sigAddKey) Validate() error { + return nil +} +func (a *sigAddKey) Signer(ctx context.Context) (crypto.Signer, error) { + return a.signer, nil +} +func (a *sigAddKey) ToConfig() config.AccountKey { + return config.AccountKey{ + Type: a.keyType, + Index: a.index, + SigAlgo: a.sigAlgo, + HashAlgo: a.hashAlgo, + Mnemonic: "", + DerivationPath: "", + } +} +func (a *sigAddKey) PrivateKey() (*crypto.PrivateKey, error) { + return nil, fmt.Errorf("This key type does not support private key retrieval") +} + +func parseKeyIndex(value string) (uint32, error) { + v, err := strconv.Atoi(value) + if err != nil { + return 0, fmt.Errorf("invalid index, must be a number") + } + if v < 0 { + return 0, fmt.Errorf("invalid index, must be positive") + } + if v > math.MaxUint32 { + return 0, fmt.Errorf("invalid index, must be less than %d", math.MaxUint32) + } + + return uint32(v), nil +} diff --git a/internal/transactions/transactions.go b/internal/transactions/transactions.go index 54624408b..307677d4e 100644 --- a/internal/transactions/transactions.go +++ b/internal/transactions/transactions.go @@ -171,6 +171,9 @@ func (r *transactionResult) String() string { _, _ = 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 len(e.ExtensionData) > 0 { + _, _ = fmt.Fprintf(writer, " Extension Data\t%x\n", e.ExtensionData) + } } else { _, _ = fmt.Fprintf(writer, "\nPayload Signature %v: %s", i, e.Address) } @@ -182,6 +185,9 @@ func (r *transactionResult) String() string { _, _ = 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 len(e.ExtensionData) > 0 { + _, _ = fmt.Fprintf(writer, " Extension Data\t%x\n", e.ExtensionData) + } } else { _, _ = fmt.Fprintf(writer, "\nEnvelope Signature %v: %s", i, e.Address) }