fork
Configure Feed
Select the types of activity you want to include in your feed.
Live video on the AT Protocol
fork
Configure Feed
Select the types of activity you want to include in your feed.
1package schema
2
3import (
4 "encoding/json"
5 "fmt"
6 "reflect"
7
8 "github.com/ethereum/go-ethereum/signer/core/apitypes"
9)
10
11type Schema interface {
12 EIP712() (*EIP712SchemaStruct, error)
13}
14
15type SchemaStruct struct {
16 name string
17 version string
18 schema any
19}
20
21func MakeSchema(name, version string, schema any) (Schema, error) {
22 return &SchemaStruct{
23 name: name,
24 version: version,
25 schema: schema,
26 }, nil
27}
28
29type EIP712SchemaStruct struct {
30 Types apitypes.Types `json:"types"`
31 Domain *apitypes.TypedDataDomain `json:"domain"`
32 TypeToName map[reflect.Type]string
33 NameToType map[string]reflect.Type
34}
35
36func (schema *SchemaStruct) EIP712() (*EIP712SchemaStruct, error) {
37 var eip712Types = apitypes.Types{
38 "EIP712Domain": {
39 {
40 Name: "name",
41 Type: "string",
42 },
43 {
44 Name: "version",
45 Type: "string",
46 },
47 },
48 }
49
50 stype := reflect.TypeOf(schema.schema)
51 if stype.Kind() != reflect.Struct {
52 return nil, fmt.Errorf("schema parameter of MakeEIP712Signer is not a struct")
53 }
54 fields := reflect.VisibleFields(stype)
55 typeToName := map[reflect.Type]string{}
56 nameToType := map[string]reflect.Type{}
57 for _, field := range fields {
58 name := field.Name
59 eip712TypeName := fmt.Sprintf("%sData", name)
60 if field.Type.Kind() != reflect.Struct {
61 return nil, fmt.Errorf("field '%s' in provided schema is not a struct", name)
62 }
63 typeToName[field.Type] = name
64 nameToType[name] = field.Type
65 parentType := []apitypes.Type{
66 {
67 Name: "signer",
68 Type: "address",
69 },
70 {
71 Name: "time",
72 Type: "int64",
73 },
74 {
75 Name: "data",
76 Type: eip712TypeName,
77 },
78 }
79 typeSlice := []apitypes.Type{}
80
81 subfields := reflect.VisibleFields(field.Type)
82 for _, subfield := range subfields {
83 eipType, err := goToEIP712(subfield)
84 if err != nil {
85 return nil, fmt.Errorf("error handling type %s: %w", name, err)
86 }
87 typeSlice = append(typeSlice, eipType)
88 }
89 eip712Types[name] = parentType
90 eip712Types[eip712TypeName] = typeSlice
91 }
92 return &EIP712SchemaStruct{
93 Types: eip712Types,
94 Domain: &apitypes.TypedDataDomain{
95 Version: schema.version,
96 Name: schema.name,
97 },
98 TypeToName: typeToName,
99 NameToType: nameToType,
100 }, nil
101}
102
103func (eip *EIP712SchemaStruct) JSON() ([]byte, error) {
104 out := map[string]any{
105 "domain": eip.Domain,
106 "types": eip.Types,
107 }
108 bs, err := json.MarshalIndent(out, "", " ")
109 if err != nil {
110 return []byte{}, err
111 }
112 return bs, nil
113}
114
115// turns a go type into an eip712 type
116func goToEIP712(field reflect.StructField) (apitypes.Type, error) {
117 var typ string
118 kind := field.Type.Kind()
119 if kind == reflect.String {
120 typ = "string"
121 } else if kind == reflect.Int64 {
122 typ = "int64"
123 }
124 jsonTag := field.Tag.Get("json")
125 if jsonTag == "" {
126 return apitypes.Type{}, fmt.Errorf("could not find field name for %s", field.Name)
127 }
128 return apitypes.Type{
129 Name: jsonTag,
130 Type: typ,
131 }, nil
132}