signer/core: handle gnosis safe problem with missing chain id (#26309)

This PR adds a check that the safetxhash that we sign corresponds to the one that is expected by the input. If it differs, it tries again with the configured chainid.
pull/26360/head
Martin Holst Swende 2 years ago committed by GitHub
parent fa97788c75
commit 502fa829a6
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
  1. 21
      signer/core/api.go
  2. 22
      signer/core/signed_data_test.go

@ -17,6 +17,7 @@
package core
import (
"bytes"
"context"
"encoding/json"
"errors"
@ -31,6 +32,7 @@ import (
"github.com/ethereum/go-ethereum/accounts/usbwallet"
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/common/hexutil"
"github.com/ethereum/go-ethereum/common/math"
"github.com/ethereum/go-ethereum/internal/ethapi"
"github.com/ethereum/go-ethereum/log"
"github.com/ethereum/go-ethereum/rpc"
@ -627,7 +629,26 @@ func (api *SignerAPI) SignGnosisSafeTx(ctx context.Context, signerAddress common
}
}
typedData := gnosisTx.ToTypedData()
// might aswell error early.
// we are expected to sign. If our calculated hash does not match what they want,
// The gnosis safetx input contains a 'safeTxHash' which is the expected safeTxHash that
sighash, _, err := apitypes.TypedDataAndHash(typedData)
if err != nil {
return nil, err
}
if !bytes.Equal(sighash, gnosisTx.InputExpHash.Bytes()) {
// It might be the case that the json is missing chain id.
if gnosisTx.ChainId == nil {
gnosisTx.ChainId = (*math.HexOrDecimal256)(api.chainID)
typedData = gnosisTx.ToTypedData()
sighash, _, _ = apitypes.TypedDataAndHash(typedData)
if !bytes.Equal(sighash, gnosisTx.InputExpHash.Bytes()) {
return nil, fmt.Errorf("mismatched safeTxHash; have %#x want %#x", sighash, gnosisTx.InputExpHash[:])
}
}
}
signature, preimage, err := api.signTypedData(ctx, signerAddress, typedData, msgs)
if err != nil {
return nil, err
}

@ -21,6 +21,7 @@ import (
"context"
"encoding/json"
"fmt"
"math/big"
"os"
"path"
"strings"
@ -826,3 +827,24 @@ func TestComplexTypedData(t *testing.T) {
t.Fatalf("Error, got %x, wanted %x", sighash, expSigHash)
}
}
func TestGnosisSafe(t *testing.T) {
// json missing chain id
js := "{\n \"safe\": \"0x899FcB1437DE65DC6315f5a69C017dd3F2837557\",\n \"to\": \"0x899FcB1437DE65DC6315f5a69C017dd3F2837557\",\n \"value\": \"0\",\n \"data\": \"0x0d582f13000000000000000000000000d3ed2b8756b942c98c851722f3bd507a17b4745f0000000000000000000000000000000000000000000000000000000000000005\",\n \"operation\": 0,\n \"gasToken\": \"0x0000000000000000000000000000000000000000\",\n \"safeTxGas\": 0,\n \"baseGas\": 0,\n \"gasPrice\": \"0\",\n \"refundReceiver\": \"0x0000000000000000000000000000000000000000\",\n \"nonce\": 0,\n \"executionDate\": null,\n \"submissionDate\": \"2022-02-23T14:09:00.018475Z\",\n \"modified\": \"2022-12-01T15:52:21.214357Z\",\n \"blockNumber\": null,\n \"transactionHash\": null,\n \"safeTxHash\": \"0x6f0f5cffee69087c9d2471e477a63cab2ae171cf433e754315d558d8836274f4\",\n \"executor\": null,\n \"isExecuted\": false,\n \"isSuccessful\": null,\n \"ethGasPrice\": null,\n \"maxFeePerGas\": null,\n \"maxPriorityFeePerGas\": null,\n \"gasUsed\": null,\n \"fee\": null,\n \"origin\": \"https://gnosis-safe.io\",\n \"dataDecoded\": {\n \"method\": \"addOwnerWithThreshold\",\n \"parameters\": [\n {\n \"name\": \"owner\",\n \"type\": \"address\",\n \"value\": \"0xD3Ed2b8756b942c98c851722F3bd507a17B4745F\"\n },\n {\n \"name\": \"_threshold\",\n \"type\": \"uint256\",\n \"value\": \"5\"\n }\n ]\n },\n \"confirmationsRequired\": 4,\n \"confirmations\": [\n {\n \"owner\": \"0x30B714E065B879F5c042A75Bb40a220A0BE27966\",\n \"submissionDate\": \"2022-03-01T14:56:22Z\",\n \"transactionHash\": \"0x6d0a9c83ac7578ef3be1f2afce089fb83b619583dfa779b82f4422fd64ff3ee9\",\n \"signature\": \"0x00000000000000000000000030b714e065b879f5c042a75bb40a220a0be27966000000000000000000000000000000000000000000000000000000000000000001\",\n \"signatureType\": \"APPROVED_HASH\"\n },\n {\n \"owner\": \"0x8300dFEa25Da0eb744fC0D98c23283F86AB8c10C\",\n \"submissionDate\": \"2022-12-01T15:52:21.214357Z\",\n \"transactionHash\": null,\n \"signature\": \"0xbce73de4cc6ee208e933a93c794dcb8ba1810f9848d1eec416b7be4dae9854c07dbf1720e60bbd310d2159197a380c941cfdb55b3ce58f9dd69efd395d7bef881b\",\n \"signatureType\": \"EOA\"\n }\n ],\n \"trusted\": true,\n \"signatures\": null\n}\n"
var gnosisTx core.GnosisSafeTx
if err := json.Unmarshal([]byte(js), &gnosisTx); err != nil {
t.Fatal(err)
}
sighash, _, err := apitypes.TypedDataAndHash(gnosisTx.ToTypedData())
if err != nil {
t.Fatal(err)
}
if bytes.Equal(sighash, gnosisTx.InputExpHash.Bytes()) {
t.Fatal("expected inequality")
}
gnosisTx.ChainId = (*math.HexOrDecimal256)(big.NewInt(1))
sighash, _, _ = apitypes.TypedDataAndHash(gnosisTx.ToTypedData())
if !bytes.Equal(sighash, gnosisTx.InputExpHash.Bytes()) {
t.Fatal("expected equality")
}
}

Loading…
Cancel
Save