signed_data_test.go 19 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774
  1. // Copyright 2018 The go-ethereum Authors
  2. // This file is part of go-ethereum.
  3. //
  4. // go-ethereum is free software: you can redistribute it and/or modify
  5. // it under the terms of the GNU 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. // go-ethereum 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 General Public License for more details.
  13. //
  14. // You should have received a copy of the GNU General Public License
  15. // along with go-ethereum. If not, see <http://www.gnu.org/licenses/>.
  16. //
  17. package core
  18. import (
  19. "context"
  20. "encoding/json"
  21. "fmt"
  22. "math/big"
  23. "testing"
  24. "github.com/ethereum/go-ethereum/accounts/keystore"
  25. "github.com/ethereum/go-ethereum/common"
  26. "github.com/ethereum/go-ethereum/common/hexutil"
  27. )
  28. var typesStandard = Types{
  29. "EIP712Domain": {
  30. {
  31. Name: "name",
  32. Type: "string",
  33. },
  34. {
  35. Name: "version",
  36. Type: "string",
  37. },
  38. {
  39. Name: "chainId",
  40. Type: "uint256",
  41. },
  42. {
  43. Name: "verifyingContract",
  44. Type: "address",
  45. },
  46. },
  47. "Person": {
  48. {
  49. Name: "name",
  50. Type: "string",
  51. },
  52. {
  53. Name: "wallet",
  54. Type: "address",
  55. },
  56. },
  57. "Mail": {
  58. {
  59. Name: "from",
  60. Type: "Person",
  61. },
  62. {
  63. Name: "to",
  64. Type: "Person",
  65. },
  66. {
  67. Name: "contents",
  68. Type: "string",
  69. },
  70. },
  71. }
  72. var jsonTypedData = `
  73. {
  74. "types": {
  75. "EIP712Domain": [
  76. {
  77. "name": "name",
  78. "type": "string"
  79. },
  80. {
  81. "name": "version",
  82. "type": "string"
  83. },
  84. {
  85. "name": "chainId",
  86. "type": "uint256"
  87. },
  88. {
  89. "name": "verifyingContract",
  90. "type": "address"
  91. }
  92. ],
  93. "Person": [
  94. {
  95. "name": "name",
  96. "type": "string"
  97. },
  98. {
  99. "name": "test",
  100. "type": "uint8"
  101. },
  102. {
  103. "name": "wallet",
  104. "type": "address"
  105. }
  106. ],
  107. "Mail": [
  108. {
  109. "name": "from",
  110. "type": "Person"
  111. },
  112. {
  113. "name": "to",
  114. "type": "Person"
  115. },
  116. {
  117. "name": "contents",
  118. "type": "string"
  119. }
  120. ]
  121. },
  122. "primaryType": "Mail",
  123. "domain": {
  124. "name": "Ether Mail",
  125. "version": "1",
  126. "chainId": 1,
  127. "verifyingContract": "0xCCCcccccCCCCcCCCCCCcCcCccCcCCCcCcccccccC"
  128. },
  129. "message": {
  130. "from": {
  131. "name": "Cow",
  132. "test": 3,
  133. "wallet": "0xcD2a3d9F938E13CD947Ec05AbC7FE734Df8DD826"
  134. },
  135. "to": {
  136. "name": "Bob",
  137. "wallet": "0xbBbBBBBbbBBBbbbBbbBbbbbBBbBbbbbBbBbbBBbB"
  138. },
  139. "contents": "Hello, Bob!"
  140. }
  141. }
  142. `
  143. const primaryType = "Mail"
  144. var domainStandard = TypedDataDomain{
  145. "Ether Mail",
  146. "1",
  147. big.NewInt(1),
  148. "0xCcCCccccCCCCcCCCCCCcCcCccCcCCCcCcccccccC",
  149. "",
  150. }
  151. var messageStandard = map[string]interface{}{
  152. "from": map[string]interface{}{
  153. "name": "Cow",
  154. "wallet": "0xCD2a3d9F938E13CD947Ec05AbC7FE734Df8DD826",
  155. },
  156. "to": map[string]interface{}{
  157. "name": "Bob",
  158. "wallet": "0xbBbBBBBbbBBBbbbBbbBbbbbBBbBbbbbBbBbbBBbB",
  159. },
  160. "contents": "Hello, Bob!",
  161. }
  162. var typedData = TypedData{
  163. Types: typesStandard,
  164. PrimaryType: primaryType,
  165. Domain: domainStandard,
  166. Message: messageStandard,
  167. }
  168. func TestSignData(t *testing.T) {
  169. api, control := setup(t)
  170. //Create two accounts
  171. createAccount(control, api, t)
  172. createAccount(control, api, t)
  173. control <- "1"
  174. list, err := api.List(context.Background())
  175. if err != nil {
  176. t.Fatal(err)
  177. }
  178. a := common.NewMixedcaseAddress(list[0])
  179. control <- "Y"
  180. control <- "wrongpassword"
  181. signature, err := api.SignData(context.Background(), TextPlain.Mime, a, hexutil.Encode([]byte("EHLO world")))
  182. if signature != nil {
  183. t.Errorf("Expected nil-data, got %x", signature)
  184. }
  185. if err != keystore.ErrDecrypt {
  186. t.Errorf("Expected ErrLocked! '%v'", err)
  187. }
  188. control <- "No way"
  189. signature, err = api.SignData(context.Background(), TextPlain.Mime, a, hexutil.Encode([]byte("EHLO world")))
  190. if signature != nil {
  191. t.Errorf("Expected nil-data, got %x", signature)
  192. }
  193. if err != ErrRequestDenied {
  194. t.Errorf("Expected ErrRequestDenied! '%v'", err)
  195. }
  196. // text/plain
  197. control <- "Y"
  198. control <- "a_long_password"
  199. signature, err = api.SignData(context.Background(), TextPlain.Mime, a, hexutil.Encode([]byte("EHLO world")))
  200. if err != nil {
  201. t.Fatal(err)
  202. }
  203. if signature == nil || len(signature) != 65 {
  204. t.Errorf("Expected 65 byte signature (got %d bytes)", len(signature))
  205. }
  206. // data/typed
  207. control <- "Y"
  208. control <- "a_long_password"
  209. signature, err = api.SignTypedData(context.Background(), a, typedData)
  210. if err != nil {
  211. t.Fatal(err)
  212. }
  213. if signature == nil || len(signature) != 65 {
  214. t.Errorf("Expected 65 byte signature (got %d bytes)", len(signature))
  215. }
  216. }
  217. func TestHashStruct(t *testing.T) {
  218. hash, err := typedData.HashStruct(typedData.PrimaryType, typedData.Message)
  219. if err != nil {
  220. t.Fatal(err)
  221. }
  222. mainHash := fmt.Sprintf("0x%s", common.Bytes2Hex(hash))
  223. if mainHash != "0xc52c0ee5d84264471806290a3f2c4cecfc5490626bf912d01f240d7a274b371e" {
  224. t.Errorf("Expected different hashStruct result (got %s)", mainHash)
  225. }
  226. hash, err = typedData.HashStruct("EIP712Domain", typedData.Domain.Map())
  227. if err != nil {
  228. t.Error(err)
  229. }
  230. domainHash := fmt.Sprintf("0x%s", common.Bytes2Hex(hash))
  231. if domainHash != "0xf2cee375fa42b42143804025fc449deafd50cc031ca257e0b194a650a912090f" {
  232. t.Errorf("Expected different domain hashStruct result (got %s)", domainHash)
  233. }
  234. }
  235. func TestEncodeType(t *testing.T) {
  236. domainTypeEncoding := string(typedData.EncodeType("EIP712Domain"))
  237. if domainTypeEncoding != "EIP712Domain(string name,string version,uint256 chainId,address verifyingContract)" {
  238. t.Errorf("Expected different encodeType result (got %s)", domainTypeEncoding)
  239. }
  240. mailTypeEncoding := string(typedData.EncodeType(typedData.PrimaryType))
  241. if mailTypeEncoding != "Mail(Person from,Person to,string contents)Person(string name,address wallet)" {
  242. t.Errorf("Expected different encodeType result (got %s)", mailTypeEncoding)
  243. }
  244. }
  245. func TestTypeHash(t *testing.T) {
  246. mailTypeHash := fmt.Sprintf("0x%s", common.Bytes2Hex(typedData.TypeHash(typedData.PrimaryType)))
  247. if mailTypeHash != "0xa0cedeb2dc280ba39b857546d74f5549c3a1d7bdc2dd96bf881f76108e23dac2" {
  248. t.Errorf("Expected different typeHash result (got %s)", mailTypeHash)
  249. }
  250. }
  251. func TestEncodeData(t *testing.T) {
  252. hash, err := typedData.EncodeData(typedData.PrimaryType, typedData.Message, 0)
  253. if err != nil {
  254. t.Fatal(err)
  255. }
  256. dataEncoding := fmt.Sprintf("0x%s", common.Bytes2Hex(hash))
  257. if dataEncoding != "0xa0cedeb2dc280ba39b857546d74f5549c3a1d7bdc2dd96bf881f76108e23dac2fc71e5fa27ff56c350aa531bc129ebdf613b772b6604664f5d8dbe21b85eb0c8cd54f074a4af31b4411ff6a60c9719dbd559c221c8ac3492d9d872b041d703d1b5aadf3154a261abdd9086fc627b61efca26ae5702701d05cd2305f7c52a2fc8" {
  258. t.Errorf("Expected different encodeData result (got %s)", dataEncoding)
  259. }
  260. }
  261. func TestMalformedDomainkeys(t *testing.T) {
  262. // Verifies that malformed domain keys are properly caught:
  263. //{
  264. // "name": "Ether Mail",
  265. // "version": "1",
  266. // "chainId": 1,
  267. // "vxerifyingContract": "0xCcCCccccCCCCcCCCCCCcCcCccCcCCCcCcccccccC"
  268. //}
  269. jsonTypedData := `
  270. {
  271. "types": {
  272. "EIP712Domain": [
  273. {
  274. "name": "name",
  275. "type": "string"
  276. },
  277. {
  278. "name": "version",
  279. "type": "string"
  280. },
  281. {
  282. "name": "chainId",
  283. "type": "uint256"
  284. },
  285. {
  286. "name": "verifyingContract",
  287. "type": "address"
  288. }
  289. ],
  290. "Person": [
  291. {
  292. "name": "name",
  293. "type": "string"
  294. },
  295. {
  296. "name": "wallet",
  297. "type": "address"
  298. }
  299. ],
  300. "Mail": [
  301. {
  302. "name": "from",
  303. "type": "Person"
  304. },
  305. {
  306. "name": "to",
  307. "type": "Person"
  308. },
  309. {
  310. "name": "contents",
  311. "type": "string"
  312. }
  313. ]
  314. },
  315. "primaryType": "Mail",
  316. "domain": {
  317. "name": "Ether Mail",
  318. "version": "1",
  319. "chainId": 1,
  320. "vxerifyingContract": "0xCcCCccccCCCCcCCCCCCcCcCccCcCCCcCcccccccC"
  321. },
  322. "message": {
  323. "from": {
  324. "name": "Cow",
  325. "wallet": "0xCD2a3d9F938E13CD947Ec05AbC7FE734Df8DD826"
  326. },
  327. "to": {
  328. "name": "Bob",
  329. "wallet": "0xbBbBBBBbbBBBbbbBbbBbbbbBBbBbbbbBbBbbBBbB"
  330. },
  331. "contents": "Hello, Bob!"
  332. }
  333. }
  334. `
  335. var malformedDomainTypedData TypedData
  336. err := json.Unmarshal([]byte(jsonTypedData), &malformedDomainTypedData)
  337. if err != nil {
  338. t.Fatalf("unmarshalling failed '%v'", err)
  339. }
  340. _, err = malformedDomainTypedData.HashStruct("EIP712Domain", malformedDomainTypedData.Domain.Map())
  341. if err == nil || err.Error() != "provided data '<nil>' doesn't match type 'address'" {
  342. t.Errorf("Expected `provided data '<nil>' doesn't match type 'address'`, got '%v'", err)
  343. }
  344. }
  345. func TestMalformedTypesAndExtradata(t *testing.T) {
  346. // Verifies several quirks
  347. // 1. Using dynamic types and only validating the prefix:
  348. //{
  349. // "name": "chainId",
  350. // "type": "uint256 ... and now for something completely different"
  351. //}
  352. // 2. Extra data in message:
  353. //{
  354. // "blahonga": "zonk bonk"
  355. //}
  356. jsonTypedData := `
  357. {
  358. "types": {
  359. "EIP712Domain": [
  360. {
  361. "name": "name",
  362. "type": "string"
  363. },
  364. {
  365. "name": "version",
  366. "type": "string"
  367. },
  368. {
  369. "name": "chainId",
  370. "type": "uint256 ... and now for something completely different"
  371. },
  372. {
  373. "name": "verifyingContract",
  374. "type": "address"
  375. }
  376. ],
  377. "Person": [
  378. {
  379. "name": "name",
  380. "type": "string"
  381. },
  382. {
  383. "name": "wallet",
  384. "type": "address"
  385. }
  386. ],
  387. "Mail": [
  388. {
  389. "name": "from",
  390. "type": "Person"
  391. },
  392. {
  393. "name": "to",
  394. "type": "Person"
  395. },
  396. {
  397. "name": "contents",
  398. "type": "string"
  399. }
  400. ]
  401. },
  402. "primaryType": "Mail",
  403. "domain": {
  404. "name": "Ether Mail",
  405. "version": "1",
  406. "chainId": 1,
  407. "verifyingContract": "0xCCCcccccCCCCcCCCCCCcCcCccCcCCCcCcccccccC"
  408. },
  409. "message": {
  410. "from": {
  411. "name": "Cow",
  412. "wallet": "0xcD2a3d9F938E13CD947Ec05AbC7FE734Df8DD826"
  413. },
  414. "to": {
  415. "name": "Bob",
  416. "wallet": "0xbBbBBBBbbBBBbbbBbbBbbbbBBbBbbbbBbBbbBBbB"
  417. },
  418. "contents": "Hello, Bob!"
  419. }
  420. }
  421. `
  422. var malformedTypedData TypedData
  423. err := json.Unmarshal([]byte(jsonTypedData), &malformedTypedData)
  424. if err != nil {
  425. t.Fatalf("unmarshalling failed '%v'", err)
  426. }
  427. malformedTypedData.Types["EIP712Domain"][2].Type = "uint256"
  428. malformedTypedData.Message["blahonga"] = "zonk bonk"
  429. _, err = malformedTypedData.HashStruct(malformedTypedData.PrimaryType, malformedTypedData.Message)
  430. if err == nil || err.Error() != "there is extra data provided in the message" {
  431. t.Errorf("Expected `there is extra data provided in the message`, got '%v'", err)
  432. }
  433. }
  434. func TestTypeMismatch(t *testing.T) {
  435. // Verifies that:
  436. // 1. Mismatches between the given type and data, i.e. `Person` and
  437. // the data item is a string, are properly caught:
  438. //{
  439. // "name": "contents",
  440. // "type": "Person"
  441. //},
  442. //{
  443. // "contents": "Hello, Bob!" <-- string not "Person"
  444. //}
  445. // 2. Nonexistent types are properly caught:
  446. //{
  447. // "name": "contents",
  448. // "type": "Blahonga"
  449. //}
  450. jsonTypedData := `
  451. {
  452. "types": {
  453. "EIP712Domain": [
  454. {
  455. "name": "name",
  456. "type": "string"
  457. },
  458. {
  459. "name": "version",
  460. "type": "string"
  461. },
  462. {
  463. "name": "chainId",
  464. "type": "uint256"
  465. },
  466. {
  467. "name": "verifyingContract",
  468. "type": "address"
  469. }
  470. ],
  471. "Person": [
  472. {
  473. "name": "name",
  474. "type": "string"
  475. },
  476. {
  477. "name": "wallet",
  478. "type": "address"
  479. }
  480. ],
  481. "Mail": [
  482. {
  483. "name": "from",
  484. "type": "Person"
  485. },
  486. {
  487. "name": "to",
  488. "type": "Person"
  489. },
  490. {
  491. "name": "contents",
  492. "type": "Person"
  493. }
  494. ]
  495. },
  496. "primaryType": "Mail",
  497. "domain": {
  498. "name": "Ether Mail",
  499. "version": "1",
  500. "chainId": 1,
  501. "verifyingContract": "0xCcCCccccCCCCcCCCCCCcCcCccCcCCCcCcccccccC"
  502. },
  503. "message": {
  504. "from": {
  505. "name": "Cow",
  506. "wallet": "0xCD2a3d9F938E13CD947Ec05AbC7FE734Df8DD826"
  507. },
  508. "to": {
  509. "name": "Bob",
  510. "wallet": "0xbBbBBBBbbBBBbbbBbbBbbbbBBbBbbbbBbBbbBBbB"
  511. },
  512. "contents": "Hello, Bob!"
  513. }
  514. }
  515. `
  516. var mismatchTypedData TypedData
  517. err := json.Unmarshal([]byte(jsonTypedData), &mismatchTypedData)
  518. if err != nil {
  519. t.Fatalf("unmarshalling failed '%v'", err)
  520. }
  521. _, err = mismatchTypedData.HashStruct(mismatchTypedData.PrimaryType, mismatchTypedData.Message)
  522. if err.Error() != "provided data 'Hello, Bob!' doesn't match type 'Person'" {
  523. t.Errorf("Expected `provided data 'Hello, Bob!' doesn't match type 'Person'`, got '%v'", err)
  524. }
  525. mismatchTypedData.Types["Mail"][2].Type = "Blahonga"
  526. _, err = mismatchTypedData.HashStruct(mismatchTypedData.PrimaryType, mismatchTypedData.Message)
  527. if err == nil || err.Error() != "reference type 'Blahonga' is undefined" {
  528. t.Fatalf("Expected `reference type 'Blahonga' is undefined`, got '%v'", err)
  529. }
  530. }
  531. func TestTypeOverflow(t *testing.T) {
  532. // Verifies data that doesn't fit into it:
  533. //{
  534. // "test": 65536 <-- test defined as uint8
  535. //}
  536. var overflowTypedData TypedData
  537. err := json.Unmarshal([]byte(jsonTypedData), &overflowTypedData)
  538. if err != nil {
  539. t.Fatalf("unmarshalling failed '%v'", err)
  540. }
  541. // Set test to something outside uint8
  542. (overflowTypedData.Message["from"]).(map[string]interface{})["test"] = big.NewInt(65536)
  543. _, err = overflowTypedData.HashStruct(overflowTypedData.PrimaryType, overflowTypedData.Message)
  544. if err == nil || err.Error() != "integer larger than 'uint8'" {
  545. t.Fatalf("Expected `integer larger than 'uint8'`, got '%v'", err)
  546. }
  547. (overflowTypedData.Message["from"]).(map[string]interface{})["test"] = big.NewInt(3)
  548. (overflowTypedData.Message["to"]).(map[string]interface{})["test"] = big.NewInt(4)
  549. _, err = overflowTypedData.HashStruct(overflowTypedData.PrimaryType, overflowTypedData.Message)
  550. if err != nil {
  551. t.Fatalf("Expected no err, got '%v'", err)
  552. }
  553. }
  554. func TestArray(t *testing.T) {
  555. // Makes sure that arrays work fine
  556. //{
  557. // "type": "address[]"
  558. //},
  559. //{
  560. // "type": "string[]"
  561. //},
  562. //{
  563. // "type": "uint16[]",
  564. //}
  565. jsonTypedData := `
  566. {
  567. "types": {
  568. "EIP712Domain": [
  569. {
  570. "name": "name",
  571. "type": "string"
  572. },
  573. {
  574. "name": "version",
  575. "type": "string"
  576. },
  577. {
  578. "name": "chainId",
  579. "type": "uint256"
  580. },
  581. {
  582. "name": "verifyingContract",
  583. "type": "address"
  584. }
  585. ],
  586. "Foo": [
  587. {
  588. "name": "bar",
  589. "type": "address[]"
  590. }
  591. ]
  592. },
  593. "primaryType": "Foo",
  594. "domain": {
  595. "name": "Lorem",
  596. "version": "1",
  597. "chainId": 1,
  598. "verifyingContract": "0xCcCCccccCCCCcCCCCCCcCcCccCcCCCcCcccccccC"
  599. },
  600. "message": {
  601. "bar": [
  602. "0x0000000000000000000000000000000000000001",
  603. "0x0000000000000000000000000000000000000002",
  604. "0x0000000000000000000000000000000000000003"
  605. ]
  606. }
  607. }
  608. `
  609. var arrayTypedData TypedData
  610. err := json.Unmarshal([]byte(jsonTypedData), &arrayTypedData)
  611. if err != nil {
  612. t.Fatalf("unmarshalling failed '%v'", err)
  613. }
  614. _, err = arrayTypedData.HashStruct(arrayTypedData.PrimaryType, arrayTypedData.Message)
  615. if err != nil {
  616. t.Fatalf("Expected no err, got '%v'", err)
  617. }
  618. // Change array to string
  619. arrayTypedData.Types["Foo"][0].Type = "string[]"
  620. arrayTypedData.Message["bar"] = []interface{}{
  621. "lorem",
  622. "ipsum",
  623. "dolores",
  624. }
  625. _, err = arrayTypedData.HashStruct(arrayTypedData.PrimaryType, arrayTypedData.Message)
  626. if err != nil {
  627. t.Fatalf("Expected no err, got '%v'", err)
  628. }
  629. // Change array to uint
  630. arrayTypedData.Types["Foo"][0].Type = "uint[]"
  631. arrayTypedData.Message["bar"] = []interface{}{
  632. big.NewInt(1955),
  633. big.NewInt(108),
  634. big.NewInt(44010),
  635. }
  636. _, err = arrayTypedData.HashStruct(arrayTypedData.PrimaryType, arrayTypedData.Message)
  637. if err != nil {
  638. t.Fatalf("Expected no err, got '%v'", err)
  639. }
  640. // Should not work with fixed-size arrays
  641. arrayTypedData.Types["Foo"][0].Type = "uint[3]"
  642. _, err = arrayTypedData.HashStruct(arrayTypedData.PrimaryType, arrayTypedData.Message)
  643. if err == nil || err.Error() != "unknown type 'uint[3]'" {
  644. t.Fatalf("Expected `unknown type 'uint[3]'`, got '%v'", err)
  645. }
  646. }
  647. func TestCustomTypeAsArray(t *testing.T) {
  648. var jsonTypedData = `
  649. {
  650. "types": {
  651. "EIP712Domain": [
  652. {
  653. "name": "name",
  654. "type": "string"
  655. },
  656. {
  657. "name": "version",
  658. "type": "string"
  659. },
  660. {
  661. "name": "chainId",
  662. "type": "uint256"
  663. },
  664. {
  665. "name": "verifyingContract",
  666. "type": "address"
  667. }
  668. ],
  669. "Person": [
  670. {
  671. "name": "name",
  672. "type": "string"
  673. },
  674. {
  675. "name": "wallet",
  676. "type": "address"
  677. }
  678. ],
  679. "Person[]": [
  680. {
  681. "name": "baz",
  682. "type": "string"
  683. }
  684. ],
  685. "Mail": [
  686. {
  687. "name": "from",
  688. "type": "Person"
  689. },
  690. {
  691. "name": "to",
  692. "type": "Person[]"
  693. },
  694. {
  695. "name": "contents",
  696. "type": "string"
  697. }
  698. ]
  699. },
  700. "primaryType": "Mail",
  701. "domain": {
  702. "name": "Ether Mail",
  703. "version": "1",
  704. "chainId": 1,
  705. "verifyingContract": "0xCcCCccccCCCCcCCCCCCcCcCccCcCCCcCcccccccC"
  706. },
  707. "message": {
  708. "from": {
  709. "name": "Cow",
  710. "wallet": "0xCD2a3d9F938E13CD947Ec05AbC7FE734Df8DD826"
  711. },
  712. "to": {"baz": "foo"},
  713. "contents": "Hello, Bob!"
  714. }
  715. }
  716. `
  717. var malformedTypedData TypedData
  718. err := json.Unmarshal([]byte(jsonTypedData), &malformedTypedData)
  719. if err != nil {
  720. t.Fatalf("unmarshalling failed '%v'", err)
  721. }
  722. _, err = malformedTypedData.HashStruct("EIP712Domain", malformedTypedData.Domain.Map())
  723. if err != nil {
  724. t.Errorf("Expected no error, got '%v'", err)
  725. }
  726. }
  727. func TestFormatter(t *testing.T) {
  728. var d TypedData
  729. err := json.Unmarshal([]byte(jsonTypedData), &d)
  730. if err != nil {
  731. t.Fatalf("unmarshalling failed '%v'", err)
  732. }
  733. formatted := d.Format()
  734. for _, item := range formatted {
  735. fmt.Printf("'%v'\n", item.Pprint(0))
  736. }
  737. j, _ := json.Marshal(formatted)
  738. fmt.Printf("'%v'\n", string(j))
  739. }