2022-12-16 09:48:38 +00:00
|
|
|
// Copyright 2021 Evmos Foundation
|
|
|
|
// This file is part of Evmos' Ethermint library.
|
|
|
|
//
|
|
|
|
// The Ethermint library is free software: you can redistribute it and/or modify
|
|
|
|
// it under the terms of the GNU Lesser General Public License as published by
|
|
|
|
// the Free Software Foundation, either version 3 of the License, or
|
|
|
|
// (at your option) any later version.
|
|
|
|
//
|
|
|
|
// The Ethermint library is distributed in the hope that it will be useful,
|
|
|
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
|
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
|
|
// GNU Lesser General Public License for more details.
|
|
|
|
//
|
|
|
|
// You should have received a copy of the GNU Lesser General Public License
|
|
|
|
// along with the Ethermint library. If not, see https://github.com/evmos/ethermint/blob/main/LICENSE
|
2022-09-13 14:56:35 +00:00
|
|
|
package eip712
|
|
|
|
|
|
|
|
import (
|
|
|
|
"fmt"
|
|
|
|
|
|
|
|
"github.com/cosmos/cosmos-sdk/client"
|
|
|
|
codectypes "github.com/cosmos/cosmos-sdk/codec/types"
|
|
|
|
cosmoskr "github.com/cosmos/cosmos-sdk/crypto/keyring"
|
|
|
|
"github.com/cosmos/cosmos-sdk/types/tx/signing"
|
|
|
|
authtx "github.com/cosmos/cosmos-sdk/x/auth/tx"
|
|
|
|
"github.com/evmos/ethermint/types"
|
|
|
|
)
|
|
|
|
|
|
|
|
// PreprocessLedgerTx reformats Ledger-signed Cosmos transactions to match the fork expected by Ethermint
|
|
|
|
// by including the signature in a Web3Tx extension and sending a blank signature in the body.
|
|
|
|
func PreprocessLedgerTx(chainID string, keyType cosmoskr.KeyType, txBuilder client.TxBuilder) error {
|
|
|
|
// Only process Ledger transactions
|
|
|
|
if keyType != cosmoskr.TypeLedger {
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
|
|
|
// Init extension builder to set Web3 extension
|
|
|
|
extensionBuilder, ok := txBuilder.(authtx.ExtensionOptionsTxBuilder)
|
|
|
|
if !ok {
|
|
|
|
return fmt.Errorf("cannot cast TxBuilder to ExtensionOptionsTxBuilder")
|
|
|
|
}
|
|
|
|
|
|
|
|
// Get signatures from TxBuilder
|
|
|
|
sigs, err := txBuilder.GetTx().GetSignaturesV2()
|
|
|
|
if err != nil {
|
|
|
|
return fmt.Errorf("could not get signatures: %w", err)
|
|
|
|
}
|
|
|
|
|
|
|
|
// Verify single-signer
|
|
|
|
if len(sigs) != 1 {
|
|
|
|
return fmt.Errorf("invalid number of signatures, expected 1 and got %v", len(sigs))
|
|
|
|
}
|
|
|
|
|
|
|
|
signature := sigs[0]
|
|
|
|
sigData, ok := signature.Data.(*signing.SingleSignatureData)
|
|
|
|
if !ok {
|
|
|
|
return fmt.Errorf("unexpected signature type, expected SingleSignatureData")
|
|
|
|
}
|
|
|
|
sigBytes := sigData.Signature
|
|
|
|
|
|
|
|
// Parse Chain ID as big.Int
|
|
|
|
chainIDInt, err := types.ParseChainID(chainID)
|
|
|
|
if err != nil {
|
|
|
|
return fmt.Errorf("could not parse chain id: %w", err)
|
|
|
|
}
|
|
|
|
|
|
|
|
// Add ExtensionOptionsWeb3Tx extension with signature
|
|
|
|
var option *codectypes.Any
|
|
|
|
option, err = codectypes.NewAnyWithValue(&types.ExtensionOptionsWeb3Tx{
|
|
|
|
FeePayer: txBuilder.GetTx().FeePayer().String(),
|
|
|
|
TypedDataChainID: chainIDInt.Uint64(),
|
|
|
|
FeePayerSig: sigBytes,
|
|
|
|
})
|
|
|
|
if err != nil {
|
|
|
|
return fmt.Errorf("could not set extension as any: %w", err)
|
|
|
|
}
|
|
|
|
|
|
|
|
extensionBuilder.SetExtensionOptions(option)
|
|
|
|
|
|
|
|
// Set blank signature with Amino Sign Type
|
|
|
|
// (Regardless of input signMode, Evmos requires Amino signature type for Ledger)
|
|
|
|
blankSig := signing.SingleSignatureData{
|
|
|
|
SignMode: signing.SignMode_SIGN_MODE_LEGACY_AMINO_JSON,
|
|
|
|
Signature: nil,
|
|
|
|
}
|
|
|
|
sig := signing.SignatureV2{
|
|
|
|
PubKey: signature.PubKey,
|
|
|
|
Data: &blankSig,
|
|
|
|
Sequence: signature.Sequence,
|
|
|
|
}
|
|
|
|
|
|
|
|
err = txBuilder.SetSignatures(sig)
|
|
|
|
if err != nil {
|
|
|
|
return fmt.Errorf("unable to set signatures on payload: %w", err)
|
|
|
|
}
|
|
|
|
|
|
|
|
return nil
|
|
|
|
}
|