mirror of https://github.com/status-im/op-geth.git
signer, core: support chainId for GnosisSafeTx (#24231)
This commit is contained in:
parent
51eb5f8ca8
commit
7dec26db2a
|
@ -31,6 +31,7 @@ type GnosisSafeTx struct {
|
||||||
SafeTxGas big.Int `json:"safeTxGas"`
|
SafeTxGas big.Int `json:"safeTxGas"`
|
||||||
Nonce big.Int `json:"nonce"`
|
Nonce big.Int `json:"nonce"`
|
||||||
InputExpHash common.Hash `json:"safeTxHash"`
|
InputExpHash common.Hash `json:"safeTxHash"`
|
||||||
|
ChainId *math.HexOrDecimal256 `json:"chainId,omitempty"`
|
||||||
}
|
}
|
||||||
|
|
||||||
// ToTypedData converts the tx to a EIP-712 Typed Data structure for signing
|
// 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 {
|
if tx.Data != nil {
|
||||||
data = *tx.Data
|
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{
|
gnosisTypedData := apitypes.TypedData{
|
||||||
Types: apitypes.Types{
|
Types: apitypes.Types{
|
||||||
"EIP712Domain": []apitypes.Type{{Name: "verifyingContract", Type: "address"}},
|
"EIP712Domain": domainType,
|
||||||
"SafeTx": []apitypes.Type{
|
"SafeTx": []apitypes.Type{
|
||||||
{Name: "to", Type: "address"},
|
{Name: "to", Type: "address"},
|
||||||
{Name: "value", Type: "uint256"},
|
{Name: "value", Type: "uint256"},
|
||||||
|
@ -57,6 +63,7 @@ func (tx *GnosisSafeTx) ToTypedData() apitypes.TypedData {
|
||||||
},
|
},
|
||||||
Domain: apitypes.TypedDataDomain{
|
Domain: apitypes.TypedDataDomain{
|
||||||
VerifyingContract: tx.Safe.Address().Hex(),
|
VerifyingContract: tx.Safe.Address().Hex(),
|
||||||
|
ChainId: tx.ChainId,
|
||||||
},
|
},
|
||||||
PrimaryType: "SafeTx",
|
PrimaryType: "SafeTx",
|
||||||
Message: apitypes.TypedDataMessage{
|
Message: apitypes.TypedDataMessage{
|
||||||
|
@ -88,6 +95,7 @@ func (tx *GnosisSafeTx) ArgsForValidation() *apitypes.SendTxArgs {
|
||||||
Nonce: hexutil.Uint64(tx.Nonce.Uint64()),
|
Nonce: hexutil.Uint64(tx.Nonce.Uint64()),
|
||||||
Data: tx.Data,
|
Data: tx.Data,
|
||||||
Input: nil,
|
Input: nil,
|
||||||
|
ChainID: (*hexutil.Big)(tx.ChainId),
|
||||||
}
|
}
|
||||||
return args
|
return args
|
||||||
}
|
}
|
||||||
|
|
|
@ -532,3 +532,133 @@ func TestGnosisCustomData(t *testing.T) {
|
||||||
t.Fatalf("Error, got %x, wanted %x", sighash, expSigHash)
|
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)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
Loading…
Reference in New Issue