Skip to content

Commit 6bf366f

Browse files
committed
Merge branch 'bitflow-scraper-update'
2 parents 8de3458 + 3e7788b commit 6bf366f

File tree

9 files changed

+532
-105
lines changed

9 files changed

+532
-105
lines changed

pkg/dia/helpers/bitflowhelper/client.go

Lines changed: 41 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -12,15 +12,48 @@ import (
1212
"github.com/sirupsen/logrus"
1313
)
1414

15-
const DeployerAddress = "SPQC38PW542EQJ5M11CR25P7BS1CA6QT4TBXGB3M"
15+
var StableSwapContracts = [...]SwapContract{
16+
{
17+
DeployerAddress: "SPQC38PW542EQJ5M11CR25P7BS1CA6QT4TBXGB3M",
18+
ContractRegistry: "stableswap-stx-ststx-v-1-2",
19+
ContractType: 0,
20+
},
21+
{
22+
DeployerAddress: "SPQC38PW542EQJ5M11CR25P7BS1CA6QT4TBXGB3M",
23+
ContractRegistry: "stableswap-usda-susdt-v-1-2",
24+
ContractType: 0,
25+
},
26+
{
27+
DeployerAddress: "SPQC38PW542EQJ5M11CR25P7BS1CA6QT4TBXGB3M",
28+
ContractRegistry: "stableswap-aeusdc-susdt-v-1-2",
29+
ContractType: 0,
30+
},
31+
{
32+
DeployerAddress: "SPQC38PW542EQJ5M11CR25P7BS1CA6QT4TBXGB3M",
33+
ContractRegistry: "stableswap-usda-aeusdc-v-1-2",
34+
ContractType: 0,
35+
},
36+
{
37+
DeployerAddress: "SPQC38PW542EQJ5M11CR25P7BS1CA6QT4TBXGB3M",
38+
ContractRegistry: "stableswap-usda-aeusdc-v-1-4",
39+
ContractType: 0,
40+
},
41+
{
42+
DeployerAddress: "SPQC38PW542EQJ5M11CR25P7BS1CA6QT4TBXGB3M",
43+
ContractRegistry: "stableswap-abtc-xbtc-v-1-2",
44+
ContractType: 0,
45+
},
46+
{
47+
DeployerAddress: "SM1793C4R5PZ4NS4VQ4WMP7SKKYVH8JZEWSZ9HCCR",
48+
ContractRegistry: "xyk-core-v-1-2",
49+
ContractType: 1,
50+
},
51+
}
1652

17-
var StableSwapContracts = [...]string{
18-
"stableswap-stx-ststx-v-1-2",
19-
"stableswap-usda-susdt-v-1-2",
20-
"stableswap-aeusdc-susdt-v-1-2",
21-
"stableswap-usda-aeusdc-v-1-2",
22-
"stableswap-usda-aeusdc-v-1-4",
23-
"stableswap-abtc-xbtc-v-1-2",
53+
type SwapContract struct {
54+
DeployerAddress string
55+
ContractRegistry string
56+
ContractType int
2457
}
2558

2659
type BitflowClient struct {

pkg/dia/helpers/bitflowhelper/model.go

Lines changed: 11 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,18 @@
11
package bitflowhelper
22

3-
type TokenMetadata struct {
4-
TokenID string `json:"token-id"`
5-
Name string `json:"name"`
6-
Symbol string `json:"symbol"`
3+
type WrapToken struct {
74
TokenDecimals uint `json:"tokenDecimals"`
85
TokenContract string `json:"tokenContract"`
6+
Name string `json:"tokenName"`
7+
}
8+
9+
type TokenMetadata struct {
10+
TokenID string `json:"token-id"`
11+
Name string `json:"name"`
12+
Symbol string `json:"symbol"`
13+
TokenDecimals uint `json:"tokenDecimals"`
14+
TokenContract string `json:"tokenContract"`
15+
WrapTokens map[string]WrapToken `json:"wrapTokens"`
916
}
1017

1118
type GetAllTokensResponse struct {

pkg/dia/helpers/stackshelper/c32.go

Lines changed: 120 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,120 @@
1+
package stackshelper
2+
3+
import (
4+
"crypto/sha256"
5+
"encoding/hex"
6+
"errors"
7+
"fmt"
8+
"regexp"
9+
"strings"
10+
)
11+
12+
const c32table = "0123456789ABCDEFGHJKMNPQRSTVWXYZ"
13+
const hextable = "0123456789abcdef"
14+
15+
func c32address(version int, hash160hex string) (string, error) {
16+
match, err := regexp.MatchString("^[0-9a-fA-F]{40}$", hash160hex)
17+
if err != nil {
18+
return "", err
19+
}
20+
if !match {
21+
return "", errors.New("not a hash160 hex string")
22+
}
23+
24+
c32str, err := c32checkEncode(version, hash160hex)
25+
if err != nil {
26+
return "", err
27+
}
28+
return "S" + c32str, nil
29+
}
30+
31+
func c32checkEncode(version int, data string) (string, error) {
32+
if version < 0 || version >= 32 {
33+
return "", errors.New("invalid version (must be between 0 and 31)")
34+
}
35+
36+
data = strings.ToLower(data)
37+
if len(data)%2 != 0 {
38+
data = "0" + data
39+
}
40+
versionHex := fmt.Sprintf("%02x", version)
41+
42+
checksum, err := c32checksum(versionHex + data)
43+
if err != nil {
44+
return "", err
45+
}
46+
47+
c32str, err := c32encode(data + checksum)
48+
if err != nil {
49+
return "", err
50+
}
51+
return string(c32table[version]) + c32str, nil
52+
}
53+
54+
func c32checksum(dataHex string) (string, error) {
55+
bytes, err := hex.DecodeString(dataHex)
56+
if err != nil {
57+
return "", err
58+
}
59+
60+
inner := sha256.Sum256(bytes)
61+
checksum := sha256.Sum256(inner[:])
62+
return hex.EncodeToString(checksum[0:4]), nil
63+
}
64+
65+
func c32encode(inputHex string) (string, error) {
66+
if len(inputHex)%2 != 0 {
67+
inputHex = "0" + inputHex
68+
}
69+
inputHex = strings.ToLower(inputHex)
70+
71+
inputBytes, err := hex.DecodeString(inputHex)
72+
if err != nil {
73+
return "", err
74+
}
75+
76+
res := make([]byte, 0)
77+
carry := 0
78+
79+
for i := len(inputHex) - 1; i >= 0; i-- {
80+
if carry < 4 {
81+
currentCode := strings.IndexByte(hextable, inputHex[i]) >> carry
82+
nextCode := 0
83+
if i != 0 {
84+
nextCode = strings.IndexByte(hextable, inputHex[i-1])
85+
}
86+
87+
nextBits := 1 + carry
88+
nextLowBits := nextCode % (1 << nextBits) << (5 - nextBits)
89+
curC32Digit := c32table[currentCode+nextLowBits]
90+
91+
res = append([]byte{curC32Digit}, res...)
92+
carry = nextBits
93+
} else {
94+
carry = 0
95+
}
96+
}
97+
98+
c32LeadingZeros := 0
99+
for _, d := range res {
100+
if d != '0' {
101+
break
102+
} else {
103+
c32LeadingZeros++
104+
}
105+
}
106+
res = res[c32LeadingZeros:]
107+
108+
numLeadingZeroBytesInHex := 0
109+
for _, b := range inputBytes {
110+
if b != 0 {
111+
break
112+
}
113+
numLeadingZeroBytesInHex++
114+
}
115+
116+
for i := 0; i < numLeadingZeroBytesInHex; i++ {
117+
res = append([]byte{c32table[0]}, res...)
118+
}
119+
return string(res), nil
120+
}

pkg/dia/helpers/stackshelper/clarity.go

Lines changed: 40 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ package stackshelper
22

33
import (
44
"encoding/binary"
5+
"encoding/hex"
56
"errors"
67
"math/big"
78
"sort"
@@ -18,10 +19,13 @@ const (
1819
boolFalseCV = 0x04
1920
principalStandard = 0x05
2021
principalContract = 0x06
22+
responseOkCV = 0x07
23+
responseErrCV = 0x08
2124
optionNoneCV = 0x09
2225
optionSomeCV = 0x0a
2326
tupleCV = 0x0c
2427
stringASCII = 0x0d
28+
stringUTF8 = 0x0e
2529
)
2630

2731
type CVTuple map[string][]byte
@@ -47,6 +51,35 @@ func DeserializeCVUint(src []byte) (*big.Int, error) {
4751
return value, nil
4852
}
4953

54+
func DeserializeCVPrincipal(src []byte) (string, error) {
55+
switch src[0] {
56+
case principalStandard:
57+
version, hash160 := deserializeAddress(src[1:])
58+
return c32address(version, hash160)
59+
case principalContract:
60+
version, hash160 := deserializeAddress(src[1:])
61+
cAddress, err := c32address(version, hash160)
62+
if err != nil {
63+
return "", err
64+
}
65+
contractName, _ := deserializeLPString(src[clarityPrincipalByteSize+2:])
66+
return cAddress + "." + contractName, nil
67+
default:
68+
return "", errors.New("value is not a CV principal")
69+
}
70+
}
71+
72+
func DeserializeCVResponse(src []byte) ([]byte, bool) {
73+
switch src[0] {
74+
case responseOkCV:
75+
return src[1:], true
76+
case responseErrCV:
77+
return src[1:], false
78+
default:
79+
return nil, false
80+
}
81+
}
82+
5083
// SerializeCVTuple converts a clarity value tuple into its binary representation
5184
// that can be used to call stacks smart contract functions.
5285
func SerializeCVTuple(tuple CVTuple) []byte {
@@ -112,7 +145,7 @@ func DeserializeCVTuple(src []byte) (CVTuple, error) {
112145
entrySize := len(serializeLPString(k)) + len(v)
113146
valueSize += entrySize
114147
}
115-
case stringASCII:
148+
case stringASCII, stringUTF8:
116149
size := readClarityTypeSize(src[offset+1:])
117150
valueSize += 4 + int(size)
118151
default:
@@ -147,6 +180,12 @@ func deserializeLPString(val []byte) (string, int) {
147180
return string(val[1 : size+1]), size
148181
}
149182

183+
func deserializeAddress(src []byte) (int, string) {
184+
version := int(src[0])
185+
hash160 := hex.EncodeToString(src[1 : clarityPrincipalByteSize+1])
186+
return version, hash160
187+
}
188+
150189
func readClarityTypeSize(src []byte) uint32 {
151190
return binary.BigEndian.Uint32(src[0:4])
152191
}

pkg/dia/helpers/stackshelper/client.go

Lines changed: 44 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -63,7 +63,7 @@ func (c *StacksClient) GetLatestBlock() (Block, error) {
6363
var block Block
6464

6565
url := fmt.Sprintf("%s/extended/v2/blocks/latest", StacksURL)
66-
req, _ := http.NewRequest("GET", url, http.NoBody)
66+
req, _ := http.NewRequest(http.MethodGet, url, http.NoBody)
6767

6868
err := c.callStacksAPI(req, &block)
6969
if err != nil {
@@ -76,7 +76,7 @@ func (c *StacksClient) GetTransactionAt(txID string) (Transaction, error) {
7676
var transaction Transaction
7777

7878
url := fmt.Sprintf("%s/extended/v1/tx/%s", StacksURL, txID)
79-
req, _ := http.NewRequest("GET", url, http.NoBody)
79+
req, _ := http.NewRequest(http.MethodGet, url, http.NoBody)
8080

8181
err := c.callStacksAPI(req, &transaction)
8282
if err != nil {
@@ -95,7 +95,7 @@ func (c *StacksClient) GetAllBlockTransactions(height int) ([]Transaction, error
9595

9696
for offset := 0; offset < total; offset += MaxPageLimit {
9797
url := fmt.Sprintf("%s?limit=%d&offset=%d", baseURL, MaxPageLimit, offset)
98-
req, _ := http.NewRequest("GET", url, http.NoBody)
98+
req, _ := http.NewRequest(http.MethodGet, url, http.NoBody)
9999

100100
err := c.callStacksAPI(req, &resp)
101101
if err != nil {
@@ -123,26 +123,25 @@ func (c *StacksClient) GetAddressTransactions(address string, limit, offset int)
123123
offset,
124124
)
125125

126-
req, _ := http.NewRequest("GET", url, http.NoBody)
126+
req, _ := http.NewRequest(http.MethodGet, url, http.NoBody)
127127
err := c.callStacksAPI(req, &resp)
128128
if err != nil {
129129
return resp, err
130130
}
131131
return resp, nil
132132
}
133133

134-
func (c *StacksClient) GetDataMapEntry(contractId, mapName, key string) ([]byte, error) {
135-
address := strings.Split(contractId, ".")
134+
func (c *StacksClient) GetDataMapEntry(contractID, mapName, key string) ([]byte, error) {
135+
address := strings.Split(contractID, ".")
136136

137137
url := fmt.Sprintf("%s/v2/map_entry/%s/%s/%s", StacksURL, address[0], address[1], mapName)
138138
body := []byte(fmt.Sprintf(`"%s"`, key))
139139

140-
req, _ := http.NewRequest("POST", url, bytes.NewBuffer(body))
140+
req, _ := http.NewRequest(http.MethodPost, url, bytes.NewBuffer(body))
141141
req.Header.Set("Content-Type", "application/json")
142142

143-
var entry DataMapEntry
144-
err := c.callStacksAPI(req, &entry)
145-
if err != nil {
143+
var entry ContractValue
144+
if err := c.callStacksAPI(req, &entry); err != nil {
146145
return nil, err
147146
}
148147

@@ -160,6 +159,41 @@ func (c *StacksClient) GetDataMapEntry(contractId, mapName, key string) ([]byte,
160159
return result, nil
161160
}
162161

162+
func (c *StacksClient) GetDataVar(contractAddress, contractName, dataVar string) ([]byte, error) {
163+
url := fmt.Sprintf("%s/v2/data_var/%s/%s/%s", StacksURL, contractAddress, contractName, dataVar)
164+
req, _ := http.NewRequest(http.MethodGet, url, http.NoBody)
165+
166+
var result ContractValue
167+
if err := c.callStacksAPI(req, &result); err != nil {
168+
return nil, err
169+
}
170+
return hex.DecodeString(result.Data[2:])
171+
}
172+
173+
func (c *StacksClient) CallContractFunction(contractAddress, contractName, functionName string, args ContractCallArgs) ([]byte, error) {
174+
url := fmt.Sprintf("%s/v2/contracts/call-read/%s/%s/%s", StacksURL, contractAddress, contractName, functionName)
175+
body, err := json.Marshal(args)
176+
if err != nil {
177+
return nil, err
178+
}
179+
180+
req, _ := http.NewRequest(http.MethodPost, url, bytes.NewBuffer(body))
181+
req.Header.Set("Content-Type", "application/json")
182+
183+
var resp ContractCallResult
184+
if err := c.callStacksAPI(req, &resp); err != nil {
185+
return nil, err
186+
}
187+
188+
if !resp.Okay {
189+
err = errors.New(resp.Cause)
190+
c.logger.WithError(err).Error("failed to call a read-only function")
191+
return nil, err
192+
}
193+
194+
return hex.DecodeString(resp.Result[2:])
195+
}
196+
163197
func (c *StacksClient) callStacksAPI(request *http.Request, target interface{}) error {
164198
if len(c.apiKey) > 0 {
165199
request.Header.Add("X-API-Key", c.apiKey)

0 commit comments

Comments
 (0)