cosmos-sdk/client/v2/offchain/sign.go
2024-12-03 12:34:43 +00:00

126 lines
3.1 KiB
Go

package offchain
import (
"context"
"fmt"
gogogrpc "github.com/cosmos/gogoproto/grpc"
apisigning "cosmossdk.io/api/cosmos/tx/signing/v1beta1"
clientcontext "cosmossdk.io/client/v2/context"
"cosmossdk.io/client/v2/internal/account"
"cosmossdk.io/client/v2/internal/offchain"
clitx "cosmossdk.io/client/v2/tx"
"github.com/cosmos/cosmos-sdk/version"
)
const (
// ExpectedChainID defines the chain id an off-chain message must have
ExpectedChainID = ""
// ExpectedAccountNumber defines the account number an off-chain message must have
ExpectedAccountNumber = 0
// ExpectedSequence defines the sequence number an off-chain message must have
ExpectedSequence = 0
)
var enabledSignModes = []apisigning.SignMode{
apisigning.SignMode_SIGN_MODE_DIRECT,
apisigning.SignMode_SIGN_MODE_LEGACY_AMINO_JSON,
}
// Sign signs given bytes using the specified encoder and SignMode.
func Sign(
ctx clientcontext.Context,
rawBytes []byte,
conn gogogrpc.ClientConn,
fromName, encoding, signMode, output string,
) (string, error) {
digest, err := encodeDigest(encoding, rawBytes)
if err != nil {
return "", err
}
txConfig, err := clitx.NewTxConfig(clitx.ConfigOptions{
AddressCodec: ctx.AddressCodec,
Cdc: ctx.Cdc,
ValidatorAddressCodec: ctx.ValidatorAddressCodec,
EnabledSignModes: enabledSignModes,
})
if err != nil {
return "", err
}
accRetriever := account.NewAccountRetriever(ctx.AddressCodec, conn, ctx.Cdc.InterfaceRegistry())
sm, err := getSignMode(signMode)
if err != nil {
return "", err
}
params := clitx.TxParameters{
ChainID: ExpectedChainID,
SignMode: sm,
AccountConfig: clitx.AccountConfig{
AccountNumber: ExpectedAccountNumber,
Sequence: ExpectedSequence,
FromName: fromName,
},
}
txf, err := clitx.NewFactory(ctx.Keyring, ctx.Cdc, accRetriever, txConfig, ctx.AddressCodec, conn, params)
if err != nil {
return "", err
}
pubKey, err := ctx.Keyring.GetPubKey(fromName)
if err != nil {
return "", err
}
addr, err := ctx.AddressCodec.BytesToString(pubKey.Address())
if err != nil {
return "", err
}
msg := &offchain.MsgSignArbitraryData{
AppDomain: version.AppName,
Signer: addr,
Data: digest,
}
signedTx, err := txf.BuildsSignedTx(context.Background(), msg)
if err != nil {
return "", err
}
bz, err := encode(output, signedTx, txConfig)
if err != nil {
return "", err
}
return string(bz), nil
}
func encode(output string, tx clitx.Tx, config clitx.TxConfig) ([]byte, error) {
switch output {
case "json":
return config.TxJSONEncoder()(tx)
case "text":
return config.TxTextEncoder()(tx)
default:
return nil, fmt.Errorf("unsupported output type: %s", output)
}
}
// getSignMode returns the corresponding apisigning.SignMode based on the provided mode string.
func getSignMode(mode string) (apisigning.SignMode, error) {
switch mode {
case "direct":
return apisigning.SignMode_SIGN_MODE_DIRECT, nil
case "amino-json":
return apisigning.SignMode_SIGN_MODE_LEGACY_AMINO_JSON, nil
}
return apisigning.SignMode_SIGN_MODE_UNSPECIFIED, fmt.Errorf("unsupported sign mode: %s", mode)
}