-
Notifications
You must be signed in to change notification settings - Fork 1
/
methods_source.go
136 lines (119 loc) · 4.31 KB
/
methods_source.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
package sourcify
import (
"encoding/json"
"fmt"
"io"
"net/http"
"strings"
"github.com/ethereum/go-ethereum/common"
)
var (
// MethodSourceFilesFullOrPartialMatch represents the API endpoint for getting the source files with full or partial match in the Sourcify service.
// It includes the name, the HTTP method, the URI, and the parameters necessary for the request.
// Returns all verified sources from the repository for the desired contract address and chain, including metadata.json. Searches for full and partial matches.
// More information: https://docs.sourcify.dev/docs/api/server/get-source-files-all/
MethodSourceFilesFullOrPartialMatch = Method{
Name: "Get source files for the address full or partial match",
URI: "/files/any/:chain/:address",
MoreInfo: "https://docs.sourcify.dev/docs/api/server/get-source-files-all/",
Method: "GET",
ParamType: MethodParamTypeUri,
RequiredParams: []string{":chain", ":address"},
Params: []MethodParam{
{
Key: ":chain",
Value: "",
},
{
Key: ":address",
Value: "",
},
},
}
// MethodSourceFilesFullMatch represents the API endpoint for getting the source files with full match in the Sourcify service.
// It includes the name, the HTTP method, the URI, and the parameters necessary for the request.
// Returns all verified sources from the repository for the desired contract address and chain, including metadata.json. Searches only for full matches.
// More information: https://docs.sourcify.dev/docs/api/server/get-source-files-full/
MethodSourceFilesFullMatch = Method{
Name: "Get source files for the address full match",
URI: "/files/:chain/:address",
MoreInfo: "https://docs.sourcify.dev/docs/api/server/get-source-files-full/",
Method: "GET",
ParamType: MethodParamTypeUri,
RequiredParams: []string{":chain", ":address"},
Params: []MethodParam{
{
Key: ":chain",
Value: "",
},
{
Key: ":address",
Value: "",
},
},
}
)
// SourceCode represents the source code details for a file.
type SourceCode struct {
Name string `json:"name"`
Path string `json:"path"`
Content string `json:"content"`
}
// SourceCodes represents the source code details for multiple files.
type SourceCodes struct {
Status string `json:"status"`
Code []SourceCode `json:"files"`
}
// GetContractSourceCode retrieves the source code files for a contract with the given chain ID and address, based on the match type.
// It makes an API request to the Sourcify service and returns the source code details as a SourceCodes object.
func GetContractSourceCode(client *Client, chainId int, contract common.Address, matchType MethodMatchType) (*SourceCodes, error) {
var method Method
switch matchType {
case MethodMatchTypeFull:
method = MethodSourceFilesFullMatch
case MethodMatchTypePartial:
method = MethodSourceFilesFullOrPartialMatch
case MethodMatchTypeAny:
method = MethodSourceFilesFullOrPartialMatch
default:
return nil, fmt.Errorf("invalid match type: %s", matchType)
}
method.SetParams(
MethodParam{Key: ":chain", Value: chainId},
MethodParam{Key: ":address", Value: contract.Hex()},
)
if err := method.Verify(); err != nil {
return nil, err
}
response, statusCode, err := client.CallMethod(method)
if err != nil {
return nil, err
}
// Close the io.ReadCloser interface.
// This is important as CallMethod is NOT closing the response body!
// You'll have memory leaks if you don't do this!
defer response.Close()
body, readBodyErr := io.ReadAll(response)
if readBodyErr != nil {
return nil, fmt.Errorf("failure to read body: %s", readBodyErr)
}
if statusCode != http.StatusOK {
return nil, fmt.Errorf("unexpected status code: %d", statusCode)
}
toReturn := &SourceCodes{}
if err := json.Unmarshal(body, &toReturn); err != nil {
// Sometimes, response will not be a JSON object, but an array.
// In this case, we'll get an error, but we can still return the code.
// This is a workaround for the Sourcify API.
// Ugly, but it works.
if strings.Contains(err.Error(), "cannot unmarshal array into Go value") {
toReturn.Status = "unknown"
if err := json.Unmarshal(body, &toReturn.Code); err != nil {
return nil, err
}
return toReturn, nil
}
return nil, err
}
return toReturn, nil
}