|
1 | 1 | package ethutils |
2 | 2 |
|
3 | 3 | import ( |
| 4 | + "bytes" |
| 5 | + "context" |
4 | 6 | "encoding/hex" |
| 7 | + "encoding/json" |
| 8 | + "errors" |
| 9 | + "fmt" |
| 10 | + "io" |
5 | 11 | "math/big" |
| 12 | + "net/http" |
6 | 13 |
|
7 | 14 | "github.com/ethereum/go-ethereum/common" |
8 | 15 | ) |
9 | 16 |
|
| 17 | +type SubmitBody struct { |
| 18 | + TxHash string `json:"txHash"` |
| 19 | + ChainID int64 `json:"chainId"` |
| 20 | +} |
| 21 | + |
10 | 22 | const ( |
11 | 23 | divviMagicPrefix = "6decb85d" |
12 | 24 | knownEmptyAddressArrayEncoding = "00000000000000000000000000000000000000000000000000000000000000600000000000000000000000000000000000000000000000000000000000000000" |
| 25 | + |
| 26 | + divviAPIEndpoint = "https://api.divvi.xyz/submitReferral" |
| 27 | + userAgent = "ethutils/v1.x.x" |
| 28 | + contentType = "application/json" |
13 | 29 | ) |
14 | 30 |
|
15 | | -var referalTagFormat1Byte = []byte{0x01} |
| 31 | +var ( |
| 32 | + referalTagFormat1Byte = []byte{0x01} |
| 33 | + |
| 34 | + ErrDivviClientNotInitialized = errors.New("divvi client not initialized") |
| 35 | +) |
16 | 36 |
|
17 | 37 | func (p *Provider) GetReferalTag(user common.Address) []byte { |
18 | | - encodedBytes := concatBytes(encodeAddress(user), encodeAddress(p.DivviConsumerAddress), encodeAddressArrayEmpty()) |
| 38 | + encodedBytes := ConcatBytes(encodeAddress(user), encodeAddress(p.DivviConsumerAddress), encodeAddressArrayEmpty()) |
19 | 39 | payloadLen := []byte{byte(len(encodedBytes) >> 8), byte(len(encodedBytes))} |
20 | 40 | magicPrefix, _ := hex.DecodeString(divviMagicPrefix) |
21 | | - payload := concatBytes(magicPrefix, referalTagFormat1Byte, payloadLen, encodedBytes) |
| 41 | + payload := ConcatBytes(magicPrefix, referalTagFormat1Byte, payloadLen, encodedBytes) |
22 | 42 | return payload |
23 | 43 | } |
24 | 44 |
|
| 45 | +func (p *Provider) SubmitReferral(ctx context.Context, txHash common.Hash) error { |
| 46 | + if p.DivviClient == nil { |
| 47 | + return ErrDivviClientNotInitialized |
| 48 | + } |
| 49 | + body := SubmitBody{ |
| 50 | + TxHash: txHash.Hex(), |
| 51 | + ChainID: CeloMainnet, |
| 52 | + } |
| 53 | + |
| 54 | + b, err := json.Marshal(&body) |
| 55 | + if err != nil { |
| 56 | + return err |
| 57 | + } |
| 58 | + |
| 59 | + resp, err := p.requestWithCtx(ctx, http.MethodPost, divviAPIEndpoint, bytes.NewBuffer(b)) |
| 60 | + if err != nil { |
| 61 | + return err |
| 62 | + } |
| 63 | + |
| 64 | + if err := parseResponse(resp); err != nil { |
| 65 | + return err |
| 66 | + } |
| 67 | + |
| 68 | + return nil |
| 69 | +} |
| 70 | + |
| 71 | +func (p *Provider) requestWithCtx(ctx context.Context, method string, url string, body io.Reader) (*http.Response, error) { |
| 72 | + req, err := http.NewRequestWithContext(ctx, method, url, body) |
| 73 | + if err != nil { |
| 74 | + return nil, err |
| 75 | + } |
| 76 | + return p.do(req) |
| 77 | +} |
| 78 | + |
| 79 | +func (p *Provider) do(req *http.Request) (*http.Response, error) { |
| 80 | + builtRequest, err := setHeaders(req) |
| 81 | + if err != nil { |
| 82 | + return nil, err |
| 83 | + } |
| 84 | + |
| 85 | + return p.DivviClient.Do(builtRequest) |
| 86 | +} |
| 87 | + |
| 88 | +func setHeaders(req *http.Request) (*http.Request, error) { |
| 89 | + req.Header.Set("User-Agent", userAgent) |
| 90 | + req.Header.Set("Accept", contentType) |
| 91 | + req.Header.Set("Content-Type", contentType) |
| 92 | + |
| 93 | + return req, nil |
| 94 | +} |
| 95 | + |
| 96 | +func parseResponse(resp *http.Response) error { |
| 97 | + defer resp.Body.Close() |
| 98 | + |
| 99 | + if resp.StatusCode >= http.StatusBadRequest { |
| 100 | + b, err := io.ReadAll(resp.Body) |
| 101 | + if err != nil { |
| 102 | + return fmt.Errorf("divvi api error: status=%s", resp.Status) |
| 103 | + } |
| 104 | + return fmt.Errorf("divvi api error: status=%s body=%s", resp.Status, string(b)) |
| 105 | + } |
| 106 | + |
| 107 | + return nil |
| 108 | +} |
| 109 | + |
25 | 110 | func encodeAddress(address common.Address) []byte { |
26 | 111 | return common.LeftPadBytes(address.Bytes(), 32) |
27 | 112 | } |
@@ -51,7 +136,7 @@ func encodeAddressArrayEmpty() []byte { |
51 | 136 | return emptyBytes |
52 | 137 | } |
53 | 138 |
|
54 | | -func concatBytes(slices ...[]byte) []byte { |
| 139 | +func ConcatBytes(slices ...[]byte) []byte { |
55 | 140 | var result []byte |
56 | 141 | for _, slice := range slices { |
57 | 142 | result = append(result, slice...) |
|
0 commit comments