github.com/palisadeinc/bor@v0.0.0-20230615125219-ab7196213d15/signer/core/signed_data_test.go (about) 1 // Copyright 2019 The go-ethereum Authors 2 // This file is part of the go-ethereum library. 3 // 4 // The go-ethereum library is free software: you can redistribute it and/or modify 5 // it under the terms of the GNU Lesser General Public License as published by 6 // the Free Software Foundation, either version 3 of the License, or 7 // (at your option) any later version. 8 // 9 // The go-ethereum library is distributed in the hope that it will be useful, 10 // but WITHOUT ANY WARRANTY; without even the implied warranty of 11 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 // GNU Lesser General Public License for more details. 13 // 14 // You should have received a copy of the GNU Lesser General Public License 15 // along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>. 16 17 package core_test 18 19 import ( 20 "bytes" 21 "context" 22 "encoding/json" 23 "fmt" 24 "io/ioutil" 25 "path" 26 "strings" 27 "testing" 28 29 "github.com/ethereum/go-ethereum/accounts/keystore" 30 "github.com/ethereum/go-ethereum/common" 31 "github.com/ethereum/go-ethereum/common/hexutil" 32 "github.com/ethereum/go-ethereum/common/math" 33 "github.com/ethereum/go-ethereum/crypto" 34 "github.com/ethereum/go-ethereum/signer/core" 35 "github.com/ethereum/go-ethereum/signer/core/apitypes" 36 ) 37 38 var typesStandard = apitypes.Types{ 39 "EIP712Domain": { 40 { 41 Name: "name", 42 Type: "string", 43 }, 44 { 45 Name: "version", 46 Type: "string", 47 }, 48 { 49 Name: "chainId", 50 Type: "uint256", 51 }, 52 { 53 Name: "verifyingContract", 54 Type: "address", 55 }, 56 }, 57 "Person": { 58 { 59 Name: "name", 60 Type: "string", 61 }, 62 { 63 Name: "wallet", 64 Type: "address", 65 }, 66 }, 67 "Mail": { 68 { 69 Name: "from", 70 Type: "Person", 71 }, 72 { 73 Name: "to", 74 Type: "Person", 75 }, 76 { 77 Name: "contents", 78 Type: "string", 79 }, 80 }, 81 } 82 83 var jsonTypedData = ` 84 { 85 "types": { 86 "EIP712Domain": [ 87 { 88 "name": "name", 89 "type": "string" 90 }, 91 { 92 "name": "version", 93 "type": "string" 94 }, 95 { 96 "name": "chainId", 97 "type": "uint256" 98 }, 99 { 100 "name": "verifyingContract", 101 "type": "address" 102 } 103 ], 104 "Person": [ 105 { 106 "name": "name", 107 "type": "string" 108 }, 109 { 110 "name": "test", 111 "type": "uint8" 112 }, 113 { 114 "name": "wallet", 115 "type": "address" 116 } 117 ], 118 "Mail": [ 119 { 120 "name": "from", 121 "type": "Person" 122 }, 123 { 124 "name": "to", 125 "type": "Person" 126 }, 127 { 128 "name": "contents", 129 "type": "string" 130 } 131 ] 132 }, 133 "primaryType": "Mail", 134 "domain": { 135 "name": "Ether Mail", 136 "version": "1", 137 "chainId": "1", 138 "verifyingContract": "0xCCCcccccCCCCcCCCCCCcCcCccCcCCCcCcccccccC" 139 }, 140 "message": { 141 "from": { 142 "name": "Cow", 143 "test": 3, 144 "wallet": "0xcD2a3d9F938E13CD947Ec05AbC7FE734Df8DD826" 145 }, 146 "to": { 147 "name": "Bob", 148 "wallet": "0xbBbBBBBbbBBBbbbBbbBbbbbBBbBbbbbBbBbbBBbB" 149 }, 150 "contents": "Hello, Bob!" 151 } 152 } 153 ` 154 155 const primaryType = "Mail" 156 157 var domainStandard = apitypes.TypedDataDomain{ 158 Name: "Ether Mail", 159 Version: "1", 160 ChainId: math.NewHexOrDecimal256(1), 161 VerifyingContract: "0xCcCCccccCCCCcCCCCCCcCcCccCcCCCcCcccccccC", 162 Salt: "", 163 } 164 165 var messageStandard = map[string]interface{}{ 166 "from": map[string]interface{}{ 167 "name": "Cow", 168 "wallet": "0xCD2a3d9F938E13CD947Ec05AbC7FE734Df8DD826", 169 }, 170 "to": map[string]interface{}{ 171 "name": "Bob", 172 "wallet": "0xbBbBBBBbbBBBbbbBbbBbbbbBBbBbbbbBbBbbBBbB", 173 }, 174 "contents": "Hello, Bob!", 175 } 176 177 var typedData = apitypes.TypedData{ 178 Types: typesStandard, 179 PrimaryType: primaryType, 180 Domain: domainStandard, 181 Message: messageStandard, 182 } 183 184 func TestSignData(t *testing.T) { 185 api, control := setup(t) 186 //Create two accounts 187 createAccount(control, api, t) 188 createAccount(control, api, t) 189 control.approveCh <- "1" 190 list, err := api.List(context.Background()) 191 if err != nil { 192 t.Fatal(err) 193 } 194 a := common.NewMixedcaseAddress(list[0]) 195 196 control.approveCh <- "Y" 197 control.inputCh <- "wrongpassword" 198 signature, err := api.SignData(context.Background(), apitypes.TextPlain.Mime, a, hexutil.Encode([]byte("EHLO world"))) 199 if signature != nil { 200 t.Errorf("Expected nil-data, got %x", signature) 201 } 202 if err != keystore.ErrDecrypt { 203 t.Errorf("Expected ErrLocked! '%v'", err) 204 } 205 control.approveCh <- "No way" 206 signature, err = api.SignData(context.Background(), apitypes.TextPlain.Mime, a, hexutil.Encode([]byte("EHLO world"))) 207 if signature != nil { 208 t.Errorf("Expected nil-data, got %x", signature) 209 } 210 if err != core.ErrRequestDenied { 211 t.Errorf("Expected ErrRequestDenied! '%v'", err) 212 } 213 // text/plain 214 control.approveCh <- "Y" 215 control.inputCh <- "a_long_password" 216 signature, err = api.SignData(context.Background(), apitypes.TextPlain.Mime, a, hexutil.Encode([]byte("EHLO world"))) 217 if err != nil { 218 t.Fatal(err) 219 } 220 if signature == nil || len(signature) != 65 { 221 t.Errorf("Expected 65 byte signature (got %d bytes)", len(signature)) 222 } 223 // data/typed 224 control.approveCh <- "Y" 225 control.inputCh <- "a_long_password" 226 signature, err = api.SignTypedData(context.Background(), a, typedData) 227 if err != nil { 228 t.Fatal(err) 229 } 230 if signature == nil || len(signature) != 65 { 231 t.Errorf("Expected 65 byte signature (got %d bytes)", len(signature)) 232 } 233 } 234 235 func TestDomainChainId(t *testing.T) { 236 withoutChainID := apitypes.TypedData{ 237 Types: apitypes.Types{ 238 "EIP712Domain": []apitypes.Type{ 239 {Name: "name", Type: "string"}, 240 }, 241 }, 242 Domain: apitypes.TypedDataDomain{ 243 Name: "test", 244 }, 245 } 246 247 if _, ok := withoutChainID.Domain.Map()["chainId"]; ok { 248 t.Errorf("Expected the chainId key to not be present in the domain map") 249 } 250 // should encode successfully 251 if _, err := withoutChainID.HashStruct("EIP712Domain", withoutChainID.Domain.Map()); err != nil { 252 t.Errorf("Expected the typedData to encode the domain successfully, got %v", err) 253 } 254 withChainID := apitypes.TypedData{ 255 Types: apitypes.Types{ 256 "EIP712Domain": []apitypes.Type{ 257 {Name: "name", Type: "string"}, 258 {Name: "chainId", Type: "uint256"}, 259 }, 260 }, 261 Domain: apitypes.TypedDataDomain{ 262 Name: "test", 263 ChainId: math.NewHexOrDecimal256(1), 264 }, 265 } 266 267 if _, ok := withChainID.Domain.Map()["chainId"]; !ok { 268 t.Errorf("Expected the chainId key be present in the domain map") 269 } 270 // should encode successfully 271 if _, err := withChainID.HashStruct("EIP712Domain", withChainID.Domain.Map()); err != nil { 272 t.Errorf("Expected the typedData to encode the domain successfully, got %v", err) 273 } 274 } 275 276 func TestHashStruct(t *testing.T) { 277 hash, err := typedData.HashStruct(typedData.PrimaryType, typedData.Message) 278 if err != nil { 279 t.Fatal(err) 280 } 281 mainHash := fmt.Sprintf("0x%s", common.Bytes2Hex(hash)) 282 if mainHash != "0xc52c0ee5d84264471806290a3f2c4cecfc5490626bf912d01f240d7a274b371e" { 283 t.Errorf("Expected different hashStruct result (got %s)", mainHash) 284 } 285 286 hash, err = typedData.HashStruct("EIP712Domain", typedData.Domain.Map()) 287 if err != nil { 288 t.Error(err) 289 } 290 domainHash := fmt.Sprintf("0x%s", common.Bytes2Hex(hash)) 291 if domainHash != "0xf2cee375fa42b42143804025fc449deafd50cc031ca257e0b194a650a912090f" { 292 t.Errorf("Expected different domain hashStruct result (got %s)", domainHash) 293 } 294 } 295 296 func TestEncodeType(t *testing.T) { 297 domainTypeEncoding := string(typedData.EncodeType("EIP712Domain")) 298 if domainTypeEncoding != "EIP712Domain(string name,string version,uint256 chainId,address verifyingContract)" { 299 t.Errorf("Expected different encodeType result (got %s)", domainTypeEncoding) 300 } 301 302 mailTypeEncoding := string(typedData.EncodeType(typedData.PrimaryType)) 303 if mailTypeEncoding != "Mail(Person from,Person to,string contents)Person(string name,address wallet)" { 304 t.Errorf("Expected different encodeType result (got %s)", mailTypeEncoding) 305 } 306 } 307 308 func TestTypeHash(t *testing.T) { 309 mailTypeHash := fmt.Sprintf("0x%s", common.Bytes2Hex(typedData.TypeHash(typedData.PrimaryType))) 310 if mailTypeHash != "0xa0cedeb2dc280ba39b857546d74f5549c3a1d7bdc2dd96bf881f76108e23dac2" { 311 t.Errorf("Expected different typeHash result (got %s)", mailTypeHash) 312 } 313 } 314 315 func TestEncodeData(t *testing.T) { 316 hash, err := typedData.EncodeData(typedData.PrimaryType, typedData.Message, 0) 317 if err != nil { 318 t.Fatal(err) 319 } 320 dataEncoding := fmt.Sprintf("0x%s", common.Bytes2Hex(hash)) 321 if dataEncoding != "0xa0cedeb2dc280ba39b857546d74f5549c3a1d7bdc2dd96bf881f76108e23dac2fc71e5fa27ff56c350aa531bc129ebdf613b772b6604664f5d8dbe21b85eb0c8cd54f074a4af31b4411ff6a60c9719dbd559c221c8ac3492d9d872b041d703d1b5aadf3154a261abdd9086fc627b61efca26ae5702701d05cd2305f7c52a2fc8" { 322 t.Errorf("Expected different encodeData result (got %s)", dataEncoding) 323 } 324 } 325 326 func TestFormatter(t *testing.T) { 327 var d apitypes.TypedData 328 err := json.Unmarshal([]byte(jsonTypedData), &d) 329 if err != nil { 330 t.Fatalf("unmarshalling failed '%v'", err) 331 } 332 formatted, _ := d.Format() 333 for _, item := range formatted { 334 t.Logf("'%v'\n", item.Pprint(0)) 335 } 336 337 j, _ := json.Marshal(formatted) 338 t.Logf("'%v'\n", string(j)) 339 } 340 341 func sign(typedData apitypes.TypedData) ([]byte, []byte, error) { 342 domainSeparator, err := typedData.HashStruct("EIP712Domain", typedData.Domain.Map()) 343 if err != nil { 344 return nil, nil, err 345 } 346 typedDataHash, err := typedData.HashStruct(typedData.PrimaryType, typedData.Message) 347 if err != nil { 348 return nil, nil, err 349 } 350 rawData := []byte(fmt.Sprintf("\x19\x01%s%s", string(domainSeparator), string(typedDataHash))) 351 sighash := crypto.Keccak256(rawData) 352 return typedDataHash, sighash, nil 353 } 354 355 func TestJsonFiles(t *testing.T) { 356 testfiles, err := ioutil.ReadDir("testdata/") 357 if err != nil { 358 t.Fatalf("failed reading files: %v", err) 359 } 360 for i, fInfo := range testfiles { 361 if !strings.HasSuffix(fInfo.Name(), "json") { 362 continue 363 } 364 expectedFailure := strings.HasPrefix(fInfo.Name(), "expfail") 365 data, err := ioutil.ReadFile(path.Join("testdata", fInfo.Name())) 366 if err != nil { 367 t.Errorf("Failed to read file %v: %v", fInfo.Name(), err) 368 continue 369 } 370 var typedData apitypes.TypedData 371 err = json.Unmarshal(data, &typedData) 372 if err != nil { 373 t.Errorf("Test %d, file %v, json unmarshalling failed: %v", i, fInfo.Name(), err) 374 continue 375 } 376 _, _, err = sign(typedData) 377 t.Logf("Error %v\n", err) 378 if err != nil && !expectedFailure { 379 t.Errorf("Test %d failed, file %v: %v", i, fInfo.Name(), err) 380 } 381 if expectedFailure && err == nil { 382 t.Errorf("Test %d succeeded (expected failure), file %v: %v", i, fInfo.Name(), err) 383 } 384 } 385 } 386 387 // TestFuzzerFiles tests some files that have been found by fuzzing to cause 388 // crashes or hangs. 389 func TestFuzzerFiles(t *testing.T) { 390 corpusdir := path.Join("testdata", "fuzzing") 391 testfiles, err := ioutil.ReadDir(corpusdir) 392 if err != nil { 393 t.Fatalf("failed reading files: %v", err) 394 } 395 verbose := false 396 for i, fInfo := range testfiles { 397 data, err := ioutil.ReadFile(path.Join(corpusdir, fInfo.Name())) 398 if err != nil { 399 t.Errorf("Failed to read file %v: %v", fInfo.Name(), err) 400 continue 401 } 402 var typedData apitypes.TypedData 403 err = json.Unmarshal(data, &typedData) 404 if err != nil { 405 t.Errorf("Test %d, file %v, json unmarshalling failed: %v", i, fInfo.Name(), err) 406 continue 407 } 408 _, err = typedData.EncodeData("EIP712Domain", typedData.Domain.Map(), 1) 409 if verbose && err != nil { 410 t.Logf("%d, EncodeData[1] err: %v\n", i, err) 411 } 412 _, err = typedData.EncodeData(typedData.PrimaryType, typedData.Message, 1) 413 if verbose && err != nil { 414 t.Logf("%d, EncodeData[2] err: %v\n", i, err) 415 } 416 typedData.Format() 417 } 418 } 419 420 var gnosisTypedData = ` 421 { 422 "types": { 423 "EIP712Domain": [ 424 { "type": "address", "name": "verifyingContract" } 425 ], 426 "SafeTx": [ 427 { "type": "address", "name": "to" }, 428 { "type": "uint256", "name": "value" }, 429 { "type": "bytes", "name": "data" }, 430 { "type": "uint8", "name": "operation" }, 431 { "type": "uint256", "name": "safeTxGas" }, 432 { "type": "uint256", "name": "baseGas" }, 433 { "type": "uint256", "name": "gasPrice" }, 434 { "type": "address", "name": "gasToken" }, 435 { "type": "address", "name": "refundReceiver" }, 436 { "type": "uint256", "name": "nonce" } 437 ] 438 }, 439 "domain": { 440 "verifyingContract": "0x25a6c4BBd32B2424A9c99aEB0584Ad12045382B3" 441 }, 442 "primaryType": "SafeTx", 443 "message": { 444 "to": "0x9eE457023bB3De16D51A003a247BaEaD7fce313D", 445 "value": "20000000000000000", 446 "data": "0x", 447 "operation": 0, 448 "safeTxGas": 27845, 449 "baseGas": 0, 450 "gasPrice": "0", 451 "gasToken": "0x0000000000000000000000000000000000000000", 452 "refundReceiver": "0x0000000000000000000000000000000000000000", 453 "nonce": 3 454 } 455 }` 456 457 var gnosisTx = ` 458 { 459 "safe": "0x25a6c4BBd32B2424A9c99aEB0584Ad12045382B3", 460 "to": "0x9eE457023bB3De16D51A003a247BaEaD7fce313D", 461 "value": "20000000000000000", 462 "data": null, 463 "operation": 0, 464 "gasToken": "0x0000000000000000000000000000000000000000", 465 "safeTxGas": 27845, 466 "baseGas": 0, 467 "gasPrice": "0", 468 "refundReceiver": "0x0000000000000000000000000000000000000000", 469 "nonce": 3, 470 "executionDate": null, 471 "submissionDate": "2020-09-15T21:59:23.815748Z", 472 "modified": "2020-09-15T21:59:23.815748Z", 473 "blockNumber": null, 474 "transactionHash": null, 475 "safeTxHash": "0x28bae2bd58d894a1d9b69e5e9fde3570c4b98a6fc5499aefb54fb830137e831f", 476 "executor": null, 477 "isExecuted": false, 478 "isSuccessful": null, 479 "ethGasPrice": null, 480 "gasUsed": null, 481 "fee": null, 482 "origin": null, 483 "dataDecoded": null, 484 "confirmationsRequired": null, 485 "confirmations": [ 486 { 487 "owner": "0xAd2e180019FCa9e55CADe76E4487F126Fd08DA34", 488 "submissionDate": "2020-09-15T21:59:28.281243Z", 489 "transactionHash": null, 490 "confirmationType": "CONFIRMATION", 491 "signature": "0x5e562065a0cb15d766dac0cd49eb6d196a41183af302c4ecad45f1a81958d7797753f04424a9b0aa1cb0448e4ec8e189540fbcdda7530ef9b9d95dfc2d36cb521b", 492 "signatureType": "EOA" 493 } 494 ], 495 "signatures": null 496 } 497 ` 498 499 // TestGnosisTypedData tests the scenario where a user submits a full EIP-712 500 // struct without using the gnosis-specific endpoint 501 func TestGnosisTypedData(t *testing.T) { 502 var td apitypes.TypedData 503 err := json.Unmarshal([]byte(gnosisTypedData), &td) 504 if err != nil { 505 t.Fatalf("unmarshalling failed '%v'", err) 506 } 507 _, sighash, err := sign(td) 508 if err != nil { 509 t.Fatal(err) 510 } 511 expSigHash := common.FromHex("0x28bae2bd58d894a1d9b69e5e9fde3570c4b98a6fc5499aefb54fb830137e831f") 512 if !bytes.Equal(expSigHash, sighash) { 513 t.Fatalf("Error, got %x, wanted %x", sighash, expSigHash) 514 } 515 } 516 517 // TestGnosisCustomData tests the scenario where a user submits only the gnosis-safe 518 // specific data, and we fill the TypedData struct on our side 519 func TestGnosisCustomData(t *testing.T) { 520 var tx core.GnosisSafeTx 521 err := json.Unmarshal([]byte(gnosisTx), &tx) 522 if err != nil { 523 t.Fatal(err) 524 } 525 var td = tx.ToTypedData() 526 _, sighash, err := sign(td) 527 if err != nil { 528 t.Fatal(err) 529 } 530 expSigHash := common.FromHex("0x28bae2bd58d894a1d9b69e5e9fde3570c4b98a6fc5499aefb54fb830137e831f") 531 if !bytes.Equal(expSigHash, sighash) { 532 t.Fatalf("Error, got %x, wanted %x", sighash, expSigHash) 533 } 534 } 535 536 var gnosisTypedDataWithChainId = ` 537 { 538 "types": { 539 "EIP712Domain": [ 540 { "type": "uint256", "name": "chainId" }, 541 { "type": "address", "name": "verifyingContract" } 542 ], 543 "SafeTx": [ 544 { "type": "address", "name": "to" }, 545 { "type": "uint256", "name": "value" }, 546 { "type": "bytes", "name": "data" }, 547 { "type": "uint8", "name": "operation" }, 548 { "type": "uint256", "name": "safeTxGas" }, 549 { "type": "uint256", "name": "baseGas" }, 550 { "type": "uint256", "name": "gasPrice" }, 551 { "type": "address", "name": "gasToken" }, 552 { "type": "address", "name": "refundReceiver" }, 553 { "type": "uint256", "name": "nonce" } 554 ] 555 }, 556 "domain": { 557 "verifyingContract": "0x111dAE35D176A9607053e0c46e91F36AFbC1dc57", 558 "chainId": "4" 559 }, 560 "primaryType": "SafeTx", 561 "message": { 562 "to": "0x5592EC0cfb4dbc12D3aB100b257153436a1f0FEa", 563 "value": "0", 564 "data": "0xa9059cbb00000000000000000000000099d580d3a7fe7bd183b2464517b2cd7ce5a8f15a0000000000000000000000000000000000000000000000000de0b6b3a7640000", 565 "operation": 0, 566 "safeTxGas": 0, 567 "baseGas": 0, 568 "gasPrice": "0", 569 "gasToken": "0x0000000000000000000000000000000000000000", 570 "refundReceiver": "0x0000000000000000000000000000000000000000", 571 "nonce": 15 572 } 573 }` 574 575 var gnosisTxWithChainId = ` 576 { 577 "safe": "0x111dAE35D176A9607053e0c46e91F36AFbC1dc57", 578 "to": "0x5592EC0cfb4dbc12D3aB100b257153436a1f0FEa", 579 "value": "0", 580 "data": "0xa9059cbb00000000000000000000000099d580d3a7fe7bd183b2464517b2cd7ce5a8f15a0000000000000000000000000000000000000000000000000de0b6b3a7640000", 581 "operation": 0, 582 "gasToken": "0x0000000000000000000000000000000000000000", 583 "safeTxGas": 0, 584 "baseGas": 0, 585 "gasPrice": "0", 586 "refundReceiver": "0x0000000000000000000000000000000000000000", 587 "nonce": 15, 588 "executionDate": "2022-01-10T20:00:12Z", 589 "submissionDate": "2022-01-10T19:59:59.689989Z", 590 "modified": "2022-01-10T20:00:31.903635Z", 591 "blockNumber": 9968802, 592 "transactionHash": "0xc9fef30499ee8984974ab9dddd9d15c2a97c1a4393935dceed5efc3af9fc41a4", 593 "safeTxHash": "0x6619dab5401503f2735256e12b898e69eb701d6a7e0d07abf1be4bb8aebfba29", 594 "executor": "0xbc2BB26a6d821e69A38016f3858561a1D80d4182", 595 "isExecuted": true, 596 "isSuccessful": true, 597 "ethGasPrice": "2500000009", 598 "gasUsed": 82902, 599 "fee": "207255000746118", 600 "chainId": "4", 601 "origin": null, 602 "dataDecoded": { 603 "method": "transfer", 604 "parameters": [ 605 { 606 "name": "to", 607 "type": "address", 608 "value": "0x99D580d3a7FE7BD183b2464517B2cD7ce5A8F15A" 609 }, 610 { 611 "name": "value", 612 "type": "uint256", 613 "value": "1000000000000000000" 614 } 615 ] 616 }, 617 "confirmationsRequired": 1, 618 "confirmations": [ 619 { 620 "owner": "0xbc2BB26a6d821e69A38016f3858561a1D80d4182", 621 "submissionDate": "2022-01-10T19:59:59.722500Z", 622 "transactionHash": null, 623 "signature": "0x5ca34641bcdee06e7b99143bfe34778195ca41022bd35837b96c204c7786be9d6dfa6dba43b53cd92da45ac728899e1561b232d28f38ba82df45f164caba38be1b", 624 "signatureType": "EOA" 625 } 626 ], 627 "signatures": "0x5ca34641bcdee06e7b99143bfe34778195ca41022bd35837b96c204c7786be9d6dfa6dba43b53cd92da45ac728899e1561b232d28f38ba82df45f164caba38be1b" 628 } 629 ` 630 631 func TestGnosisTypedDataWithChainId(t *testing.T) { 632 var td apitypes.TypedData 633 err := json.Unmarshal([]byte(gnosisTypedDataWithChainId), &td) 634 if err != nil { 635 t.Fatalf("unmarshalling failed '%v'", err) 636 } 637 _, sighash, err := sign(td) 638 if err != nil { 639 t.Fatal(err) 640 } 641 expSigHash := common.FromHex("0x6619dab5401503f2735256e12b898e69eb701d6a7e0d07abf1be4bb8aebfba29") 642 if !bytes.Equal(expSigHash, sighash) { 643 t.Fatalf("Error, got %x, wanted %x", sighash, expSigHash) 644 } 645 } 646 647 // TestGnosisCustomData tests the scenario where a user submits only the gnosis-safe 648 // specific data, and we fill the TypedData struct on our side 649 func TestGnosisCustomDataWithChainId(t *testing.T) { 650 var tx core.GnosisSafeTx 651 err := json.Unmarshal([]byte(gnosisTxWithChainId), &tx) 652 if err != nil { 653 t.Fatal(err) 654 } 655 var td = tx.ToTypedData() 656 _, sighash, err := sign(td) 657 if err != nil { 658 t.Fatal(err) 659 } 660 expSigHash := common.FromHex("0x6619dab5401503f2735256e12b898e69eb701d6a7e0d07abf1be4bb8aebfba29") 661 if !bytes.Equal(expSigHash, sighash) { 662 t.Fatalf("Error, got %x, wanted %x", sighash, expSigHash) 663 } 664 } 665 666 var complexTypedData = ` 667 { 668 "types": { 669 "EIP712Domain": [ 670 { 671 "name": "chainId", 672 "type": "uint256" 673 }, 674 { 675 "name": "name", 676 "type": "string" 677 }, 678 { 679 "name": "verifyingContract", 680 "type": "address" 681 }, 682 { 683 "name": "version", 684 "type": "string" 685 } 686 ], 687 "Action": [ 688 { 689 "name": "action", 690 "type": "string" 691 }, 692 { 693 "name": "params", 694 "type": "string" 695 } 696 ], 697 "Cell": [ 698 { 699 "name": "capacity", 700 "type": "string" 701 }, 702 { 703 "name": "lock", 704 "type": "string" 705 }, 706 { 707 "name": "type", 708 "type": "string" 709 }, 710 { 711 "name": "data", 712 "type": "string" 713 }, 714 { 715 "name": "extraData", 716 "type": "string" 717 } 718 ], 719 "Transaction": [ 720 { 721 "name": "DAS_MESSAGE", 722 "type": "string" 723 }, 724 { 725 "name": "inputsCapacity", 726 "type": "string" 727 }, 728 { 729 "name": "outputsCapacity", 730 "type": "string" 731 }, 732 { 733 "name": "fee", 734 "type": "string" 735 }, 736 { 737 "name": "action", 738 "type": "Action" 739 }, 740 { 741 "name": "inputs", 742 "type": "Cell[]" 743 }, 744 { 745 "name": "outputs", 746 "type": "Cell[]" 747 }, 748 { 749 "name": "digest", 750 "type": "bytes32" 751 } 752 ] 753 }, 754 "primaryType": "Transaction", 755 "domain": { 756 "chainId": "56", 757 "name": "da.systems", 758 "verifyingContract": "0x0000000000000000000000000000000020210722", 759 "version": "1" 760 }, 761 "message": { 762 "DAS_MESSAGE": "SELL mobcion.bit FOR 100000 CKB", 763 "inputsCapacity": "1216.9999 CKB", 764 "outputsCapacity": "1216.9998 CKB", 765 "fee": "0.0001 CKB", 766 "digest": "0x53a6c0f19ec281604607f5d6817e442082ad1882bef0df64d84d3810dae561eb", 767 "action": { 768 "action": "start_account_sale", 769 "params": "0x00" 770 }, 771 "inputs": [ 772 { 773 "capacity": "218 CKB", 774 "lock": "das-lock,0x01,0x051c152f77f8efa9c7c6d181cc97ee67c165c506...", 775 "type": "account-cell-type,0x01,0x", 776 "data": "{ account: mobcion.bit, expired_at: 1670913958 }", 777 "extraData": "{ status: 0, records_hash: 0x55478d76900611eb079b22088081124ed6c8bae21a05dd1a0d197efcc7c114ce }" 778 } 779 ], 780 "outputs": [ 781 { 782 "capacity": "218 CKB", 783 "lock": "das-lock,0x01,0x051c152f77f8efa9c7c6d181cc97ee67c165c506...", 784 "type": "account-cell-type,0x01,0x", 785 "data": "{ account: mobcion.bit, expired_at: 1670913958 }", 786 "extraData": "{ status: 1, records_hash: 0x55478d76900611eb079b22088081124ed6c8bae21a05dd1a0d197efcc7c114ce }" 787 }, 788 { 789 "capacity": "201 CKB", 790 "lock": "das-lock,0x01,0x051c152f77f8efa9c7c6d181cc97ee67c165c506...", 791 "type": "account-sale-cell-type,0x01,0x", 792 "data": "0x1209460ef3cb5f1c68ed2c43a3e020eec2d9de6e...", 793 "extraData": "" 794 } 795 ] 796 } 797 } 798 ` 799 800 func TestComplexTypedData(t *testing.T) { 801 var td apitypes.TypedData 802 err := json.Unmarshal([]byte(complexTypedData), &td) 803 if err != nil { 804 t.Fatalf("unmarshalling failed '%v'", err) 805 } 806 _, sighash, err := sign(td) 807 if err != nil { 808 t.Fatal(err) 809 } 810 expSigHash := common.FromHex("0x42b1aca82bb6900ff75e90a136de550a58f1a220a071704088eabd5e6ce20446") 811 if !bytes.Equal(expSigHash, sighash) { 812 t.Fatalf("Error, got %x, wanted %x", sighash, expSigHash) 813 } 814 }