signer, core: support chainId for GnosisSafeTx (#24231)

This commit is contained in:
Mikhail Mikheev 2022-01-18 13:31:25 +01:00 committed by GitHub
parent 51eb5f8ca8
commit 7dec26db2a
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
2 changed files with 139 additions and 1 deletions

@ -31,6 +31,7 @@ type GnosisSafeTx struct {
SafeTxGas big.Int `json:"safeTxGas"`
Nonce big.Int `json:"nonce"`
InputExpHash common.Hash `json:"safeTxHash"`
ChainId *math.HexOrDecimal256 `json:"chainId,omitempty"`
}
// ToTypedData converts the tx to a EIP-712 Typed Data structure for signing
@ -39,9 +40,14 @@ func (tx *GnosisSafeTx) ToTypedData() apitypes.TypedData {
if tx.Data != nil {
data = *tx.Data
}
var domainType = []apitypes.Type{{Name: "verifyingContract", Type: "address"}}
if tx.ChainId != nil {
domainType = append([]apitypes.Type{{Name: "chainId", Type: "uint256"}}, domainType[0])
}
gnosisTypedData := apitypes.TypedData{
Types: apitypes.Types{
"EIP712Domain": []apitypes.Type{{Name: "verifyingContract", Type: "address"}},
"EIP712Domain": domainType,
"SafeTx": []apitypes.Type{
{Name: "to", Type: "address"},
{Name: "value", Type: "uint256"},
@ -57,6 +63,7 @@ func (tx *GnosisSafeTx) ToTypedData() apitypes.TypedData {
},
Domain: apitypes.TypedDataDomain{
VerifyingContract: tx.Safe.Address().Hex(),
ChainId: tx.ChainId,
},
PrimaryType: "SafeTx",
Message: apitypes.TypedDataMessage{
@ -88,6 +95,7 @@ func (tx *GnosisSafeTx) ArgsForValidation() *apitypes.SendTxArgs {
Nonce: hexutil.Uint64(tx.Nonce.Uint64()),
Data: tx.Data,
Input: nil,
ChainID: (*hexutil.Big)(tx.ChainId),
}
return args
}

@ -532,3 +532,133 @@ func TestGnosisCustomData(t *testing.T) {
t.Fatalf("Error, got %x, wanted %x", sighash, expSigHash)
}
}
var gnosisTypedDataWithChainId = `
{
"types": {
"EIP712Domain": [
{ "type": "uint256", "name": "chainId" },
{ "type": "address", "name": "verifyingContract" }
],
"SafeTx": [
{ "type": "address", "name": "to" },
{ "type": "uint256", "name": "value" },
{ "type": "bytes", "name": "data" },
{ "type": "uint8", "name": "operation" },
{ "type": "uint256", "name": "safeTxGas" },
{ "type": "uint256", "name": "baseGas" },
{ "type": "uint256", "name": "gasPrice" },
{ "type": "address", "name": "gasToken" },
{ "type": "address", "name": "refundReceiver" },
{ "type": "uint256", "name": "nonce" }
]
},
"domain": {
"verifyingContract": "0x111dAE35D176A9607053e0c46e91F36AFbC1dc57",
"chainId": "4"
},
"primaryType": "SafeTx",
"message": {
"to": "0x5592EC0cfb4dbc12D3aB100b257153436a1f0FEa",
"value": "0",
"data": "0xa9059cbb00000000000000000000000099d580d3a7fe7bd183b2464517b2cd7ce5a8f15a0000000000000000000000000000000000000000000000000de0b6b3a7640000",
"operation": 0,
"safeTxGas": 0,
"baseGas": 0,
"gasPrice": "0",
"gasToken": "0x0000000000000000000000000000000000000000",
"refundReceiver": "0x0000000000000000000000000000000000000000",
"nonce": 15
}
}`
var gnosisTxWithChainId = `
{
"safe": "0x111dAE35D176A9607053e0c46e91F36AFbC1dc57",
"to": "0x5592EC0cfb4dbc12D3aB100b257153436a1f0FEa",
"value": "0",
"data": "0xa9059cbb00000000000000000000000099d580d3a7fe7bd183b2464517b2cd7ce5a8f15a0000000000000000000000000000000000000000000000000de0b6b3a7640000",
"operation": 0,
"gasToken": "0x0000000000000000000000000000000000000000",
"safeTxGas": 0,
"baseGas": 0,
"gasPrice": "0",
"refundReceiver": "0x0000000000000000000000000000000000000000",
"nonce": 15,
"executionDate": "2022-01-10T20:00:12Z",
"submissionDate": "2022-01-10T19:59:59.689989Z",
"modified": "2022-01-10T20:00:31.903635Z",
"blockNumber": 9968802,
"transactionHash": "0xc9fef30499ee8984974ab9dddd9d15c2a97c1a4393935dceed5efc3af9fc41a4",
"safeTxHash": "0x6619dab5401503f2735256e12b898e69eb701d6a7e0d07abf1be4bb8aebfba29",
"executor": "0xbc2BB26a6d821e69A38016f3858561a1D80d4182",
"isExecuted": true,
"isSuccessful": true,
"ethGasPrice": "2500000009",
"gasUsed": 82902,
"fee": "207255000746118",
"chainId": "4",
"origin": null,
"dataDecoded": {
"method": "transfer",
"parameters": [
{
"name": "to",
"type": "address",
"value": "0x99D580d3a7FE7BD183b2464517B2cD7ce5A8F15A"
},
{
"name": "value",
"type": "uint256",
"value": "1000000000000000000"
}
]
},
"confirmationsRequired": 1,
"confirmations": [
{
"owner": "0xbc2BB26a6d821e69A38016f3858561a1D80d4182",
"submissionDate": "2022-01-10T19:59:59.722500Z",
"transactionHash": null,
"signature": "0x5ca34641bcdee06e7b99143bfe34778195ca41022bd35837b96c204c7786be9d6dfa6dba43b53cd92da45ac728899e1561b232d28f38ba82df45f164caba38be1b",
"signatureType": "EOA"
}
],
"signatures": "0x5ca34641bcdee06e7b99143bfe34778195ca41022bd35837b96c204c7786be9d6dfa6dba43b53cd92da45ac728899e1561b232d28f38ba82df45f164caba38be1b"
}
`
func TestGnosisTypedDataWithChainId(t *testing.T) {
var td apitypes.TypedData
err := json.Unmarshal([]byte(gnosisTypedDataWithChainId), &td)
if err != nil {
t.Fatalf("unmarshalling failed '%v'", err)
}
_, sighash, err := sign(td)
if err != nil {
t.Fatal(err)
}
expSigHash := common.FromHex("0x6619dab5401503f2735256e12b898e69eb701d6a7e0d07abf1be4bb8aebfba29")
if !bytes.Equal(expSigHash, sighash) {
t.Fatalf("Error, got %x, wanted %x", sighash, expSigHash)
}
}
// TestGnosisCustomData tests the scenario where a user submits only the gnosis-safe
// specific data, and we fill the TypedData struct on our side
func TestGnosisCustomDataWithChainId(t *testing.T) {
var tx core.GnosisSafeTx
err := json.Unmarshal([]byte(gnosisTxWithChainId), &tx)
if err != nil {
t.Fatal(err)
}
var td = tx.ToTypedData()
_, sighash, err := sign(td)
if err != nil {
t.Fatal(err)
}
expSigHash := common.FromHex("0x6619dab5401503f2735256e12b898e69eb701d6a7e0d07abf1be4bb8aebfba29")
if !bytes.Equal(expSigHash, sighash) {
t.Fatalf("Error, got %x, wanted %x", sighash, expSigHash)
}
}