Skip to content

Commit d0628fd

Browse files
authored
Add collection and inscription data structures with API read functions (#245)
* Add collection and inscription data structures with API read functions * Refactor timestamp fields to use time.Time type in multiple structs * Refactor struct field formatting for consistency in AssetNetwork and SafeDepositPending
1 parent 1710ffa commit d0628fd

File tree

6 files changed

+270
-71
lines changed

6 files changed

+270
-71
lines changed

address.go

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -16,14 +16,14 @@ type AddressInput struct {
1616
}
1717

1818
type Address struct {
19-
AddressId string `json:"address_id"`
20-
AssetId string `json:"asset_id"`
21-
Label string `json:"label"`
22-
Destination string `json:"destination"`
23-
Tag string `json:"tag"`
24-
Fee string `json:"fee"`
25-
Dust string `json:"dust"`
26-
UpdatedAt string `json:"updated_at"`
19+
AddressId string `json:"address_id"`
20+
AssetId string `json:"asset_id"`
21+
Label string `json:"label"`
22+
Destination string `json:"destination"`
23+
Tag string `json:"tag"`
24+
Fee string `json:"fee"`
25+
Dust string `json:"dust"`
26+
UpdatedAt time.Time `json:"updated_at"`
2727
}
2828

2929
type SimpleAddress struct {

inscription.go

Lines changed: 110 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,12 @@
11
package bot
22

3+
import (
4+
"context"
5+
"encoding/json"
6+
"fmt"
7+
"time"
8+
)
9+
310
const (
411
InscriptionModeInstant = 1
512
InscriptionModeDone = 2
@@ -79,3 +86,106 @@ type InscriptionOccupy struct {
7986
// the integer sequence number of the NFT inscription
8087
Sequence uint64 `json:"sequence"`
8188
}
89+
90+
// Collection represents the API response structure for collection data
91+
type Collection struct {
92+
AssetKey string `json:"asset_key"`
93+
CollectionHash string `json:"collection_hash"`
94+
KernelAssetID string `json:"kernel_asset_id"`
95+
Name string `json:"name"`
96+
Symbol string `json:"symbol"`
97+
Description string `json:"description"`
98+
IconURL string `json:"icon_url"`
99+
Supply string `json:"supply"`
100+
Unit string `json:"unit"`
101+
MinimumPrice string `json:"minimum_price"`
102+
Treasury map[string]interface{} `json:"treasury"`
103+
Type string `json:"type"`
104+
CreatedAt time.Time `json:"created_at"`
105+
UpdatedAt time.Time `json:"updated_at"`
106+
}
107+
108+
// Inscription represents the API response structure for inscription data
109+
type Inscription struct {
110+
InscriptionHash string `json:"inscription_hash"`
111+
CollectionHash string `json:"collection_hash"`
112+
ContentType string `json:"content_type"`
113+
ContentURL string `json:"content_url"`
114+
CreatedAt time.Time `json:"created_at"`
115+
OccupiedBy string `json:"occupied_by"`
116+
Owner string `json:"owner"`
117+
Recipient string `json:"recipient"`
118+
Sequence int64 `json:"sequence"`
119+
Type string `json:"type"`
120+
UpdatedAt time.Time `json:"updated_at"`
121+
}
122+
123+
// ReadCollection reads collection information from Mixin API
124+
func ReadCollection(ctx context.Context, collectionHash string) (*Collection, error) {
125+
body, err := Request(ctx, "GET", "/safe/inscriptions/collections/"+collectionHash, nil, "")
126+
if err != nil {
127+
return nil, err
128+
}
129+
130+
var resp struct {
131+
Data *Collection `json:"data"`
132+
Error Error `json:"error"`
133+
}
134+
135+
err = json.Unmarshal(body, &resp)
136+
if err != nil {
137+
return nil, err
138+
}
139+
140+
if resp.Error.Code > 0 {
141+
return nil, resp.Error
142+
}
143+
144+
return resp.Data, nil
145+
}
146+
147+
// ReadInscription reads inscription information from Mixin API
148+
func ReadInscription(ctx context.Context, inscriptionHash string) (*Inscription, error) {
149+
body, err := Request(ctx, "GET", "/safe/inscriptions/items/"+inscriptionHash, nil, "")
150+
if err != nil {
151+
return nil, err
152+
}
153+
154+
var resp struct {
155+
Data *Inscription `json:"data"`
156+
Error Error `json:"error"`
157+
}
158+
159+
err = json.Unmarshal(body, &resp)
160+
if err != nil {
161+
return nil, err
162+
}
163+
164+
if resp.Error.Code > 0 {
165+
return nil, resp.Error
166+
}
167+
168+
return resp.Data, nil
169+
}
170+
171+
// ReadCollectionItems reads all items in a collection from Mixin API
172+
func ReadCollectionItems(ctx context.Context, collectionHash string) ([]*Inscription, error) {
173+
path := fmt.Sprintf("/safe/inscriptions/collections/%s/items", collectionHash)
174+
body, err := Request(ctx, "GET", path, nil, "")
175+
if err != nil {
176+
return nil, err
177+
}
178+
179+
var resp struct {
180+
Data []*Inscription `json:"data"`
181+
Error Error `json:"error"`
182+
}
183+
if err := json.Unmarshal(body, &resp); err != nil {
184+
return nil, err
185+
}
186+
if resp.Error.Code > 0 {
187+
return nil, resp.Error
188+
}
189+
190+
return resp.Data, nil
191+
}

inscription_test.go

Lines changed: 87 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,87 @@
1+
package bot
2+
3+
import (
4+
"context"
5+
"testing"
6+
7+
"github.com/stretchr/testify/assert"
8+
)
9+
10+
func TestReadCollection(t *testing.T) {
11+
assert := assert.New(t)
12+
ctx := context.Background()
13+
// Test collection hash provided by user
14+
collectionHash := "d48af6bdd4ce12328583611debf2f75e0895a2c5522d23db70c912a6a34538a9"
15+
16+
collection, err := ReadCollection(ctx, collectionHash)
17+
if err != nil {
18+
t.Fatalf("ReadCollection failed: %v", err)
19+
}
20+
21+
assert.NotNil(collection, "Collection should not be nil")
22+
assert.Equal(collectionHash, collection.CollectionHash, "Collection hash should match")
23+
assert.NotEmpty(collection.Name, "Collection name should not be empty")
24+
25+
t.Logf("Collection Name: %s", collection.Name)
26+
t.Logf("Collection Symbol: %s", collection.Symbol)
27+
t.Logf("Collection Supply: %s", collection.Supply)
28+
}
29+
30+
func TestReadCollectionItems(t *testing.T) {
31+
assert := assert.New(t)
32+
ctx := context.Background()
33+
// Test collection hash provided by user
34+
collectionHash := "d48af6bdd4ce12328583611debf2f75e0895a2c5522d23db70c912a6a34538a9"
35+
36+
items, err := ReadCollectionItems(ctx, collectionHash)
37+
if err != nil {
38+
t.Fatalf("ReadCollectionItems failed: %v", err)
39+
}
40+
41+
assert.NotNil(items, "Items should not be nil")
42+
assert.Greater(len(items), 0, "Should have at least one item")
43+
44+
t.Logf("Found %d items in collection", len(items))
45+
46+
// Verify first item structure
47+
if len(items) > 0 {
48+
firstItem := items[0]
49+
assert.NotEmpty(firstItem.InscriptionHash, "Inscription hash should not be empty")
50+
assert.Equal(collectionHash, firstItem.CollectionHash, "Collection hash should match")
51+
52+
t.Logf("First item inscription hash: %s", firstItem.InscriptionHash)
53+
t.Logf("First item content type: %s", firstItem.ContentType)
54+
}
55+
}
56+
57+
func TestReadInscription(t *testing.T) {
58+
assert := assert.New(t)
59+
ctx := context.Background()
60+
61+
// First get items from the collection to get a valid inscription hash
62+
collectionHash := "d48af6bdd4ce12328583611debf2f75e0895a2c5522d23db70c912a6a34538a9"
63+
items, err := ReadCollectionItems(ctx, collectionHash)
64+
if err != nil {
65+
t.Fatalf("ReadCollectionItems failed: %v", err)
66+
}
67+
68+
if len(items) == 0 {
69+
t.Skip("No items in collection to test with")
70+
}
71+
72+
// Test with the first item's inscription hash
73+
inscriptionHash := items[0].InscriptionHash
74+
75+
inscription, err := ReadInscription(ctx, inscriptionHash)
76+
if err != nil {
77+
t.Fatalf("ReadInscription failed: %v", err)
78+
}
79+
80+
assert.NotNil(inscription, "Inscription should not be nil")
81+
assert.Equal(inscriptionHash, inscription.InscriptionHash, "Inscription hash should match")
82+
assert.Equal(collectionHash, inscription.CollectionHash, "Collection hash should match")
83+
84+
t.Logf("Inscription hash: %s", inscription.InscriptionHash)
85+
t.Logf("Content type: %s", inscription.ContentType)
86+
t.Logf("Owner: %s", inscription.Owner)
87+
}

network.go

Lines changed: 30 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -3,38 +3,39 @@ package bot
33
import (
44
"context"
55
"encoding/json"
6+
"time"
67
)
78

89
type AssetNetwork struct {
9-
AssetID string `json:"asset_id"`
10-
ChainID string `json:"chain_id"`
11-
FeeAssetID string `json:"fee_asset_id"`
12-
DisplaySymbol string `json:"display_symbol"`
13-
DisplayName string `json:"display_name"`
14-
Symbol string `json:"symbol"`
15-
Name string `json:"name"`
16-
IconURL string `json:"icon_url"`
17-
Balance string `json:"balance"`
18-
Destination string `json:"destination"`
19-
Tag string `json:"tag"`
20-
PriceBTC string `json:"price_btc"`
21-
PriceUSD string `json:"price_usd"`
22-
ChangeBTC string `json:"change_btc"`
23-
ChangeUSD string `json:"change_usd"`
24-
AssetKey string `json:"asset_key"`
25-
Precision int `json:"precision"`
26-
MixinID string `json:"mixin_id"`
27-
KernelAssetID string `json:"kernel_asset_id"`
28-
Reserve string `json:"reserve"`
29-
Dust string `json:"dust"`
30-
Confirmations int64 `json:"confirmations"`
31-
Capitalization float64 `json:"capitalization"`
32-
Liquidity string `json:"liquidity"`
33-
PriceUpdatedAt string `json:"price_updated_at"`
34-
WithdrawalMemoPossibility string `json:"withdrawal_memo_possibility"`
35-
PrimitiveAssetId string `json:"primitive_asset_id,omitempty"`
36-
Level int64 `json:"level"`
37-
CollectionHash string `json:"collection_hash,omitempty"`
10+
AssetID string `json:"asset_id"`
11+
ChainID string `json:"chain_id"`
12+
FeeAssetID string `json:"fee_asset_id"`
13+
DisplaySymbol string `json:"display_symbol"`
14+
DisplayName string `json:"display_name"`
15+
Symbol string `json:"symbol"`
16+
Name string `json:"name"`
17+
IconURL string `json:"icon_url"`
18+
Balance string `json:"balance"`
19+
Destination string `json:"destination"`
20+
Tag string `json:"tag"`
21+
PriceBTC string `json:"price_btc"`
22+
PriceUSD string `json:"price_usd"`
23+
ChangeBTC string `json:"change_btc"`
24+
ChangeUSD string `json:"change_usd"`
25+
AssetKey string `json:"asset_key"`
26+
Precision int `json:"precision"`
27+
MixinID string `json:"mixin_id"`
28+
KernelAssetID string `json:"kernel_asset_id"`
29+
Reserve string `json:"reserve"`
30+
Dust string `json:"dust"`
31+
Confirmations int64 `json:"confirmations"`
32+
Capitalization float64 `json:"capitalization"`
33+
Liquidity string `json:"liquidity"`
34+
PriceUpdatedAt time.Time `json:"price_updated_at"`
35+
WithdrawalMemoPossibility string `json:"withdrawal_memo_possibility"`
36+
PrimitiveAssetId string `json:"primitive_asset_id,omitempty"`
37+
Level int64 `json:"level"`
38+
CollectionHash string `json:"collection_hash,omitempty"`
3839
}
3940

4041
func ReadNetworkAssets(ctx context.Context) ([]*AssetNetwork, error) {

safe_deposits.go

Lines changed: 20 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -3,28 +3,29 @@ package bot
33
import (
44
"context"
55
"encoding/json"
6+
"time"
67
)
78

89
type SafeDepositPending struct {
9-
Amount string `json:"amount"`
10-
AssetID string `json:"asset_id"`
11-
AssetKey string `json:"asset_key"`
12-
BlockHash string `json:"block_hash"`
13-
BlockNumber int `json:"block_number"`
14-
ChainID string `json:"chain_id"`
15-
Confirmations int `json:"confirmations"`
16-
CreatedAt string `json:"created_at"`
17-
DepositID string `json:"deposit_id"`
18-
Destination string `json:"destination"`
19-
Extra string `json:"extra"`
20-
KernelAssetID string `json:"kernel_asset_id"`
21-
OutputIndex int `json:"output_index"`
22-
Sender string `json:"sender"`
23-
State string `json:"state"`
24-
Tag string `json:"tag"`
25-
Threshold int `json:"threshold"`
26-
TransactionHash string `json:"transaction_hash"`
27-
UpdatedAt string `json:"updated_at"`
10+
Amount string `json:"amount"`
11+
AssetID string `json:"asset_id"`
12+
AssetKey string `json:"asset_key"`
13+
BlockHash string `json:"block_hash"`
14+
BlockNumber int `json:"block_number"`
15+
ChainID string `json:"chain_id"`
16+
Confirmations int `json:"confirmations"`
17+
CreatedAt time.Time `json:"created_at"`
18+
DepositID string `json:"deposit_id"`
19+
Destination string `json:"destination"`
20+
Extra string `json:"extra"`
21+
KernelAssetID string `json:"kernel_asset_id"`
22+
OutputIndex int `json:"output_index"`
23+
Sender string `json:"sender"`
24+
State string `json:"state"`
25+
Tag string `json:"tag"`
26+
Threshold int `json:"threshold"`
27+
TransactionHash string `json:"transaction_hash"`
28+
UpdatedAt time.Time `json:"updated_at"`
2829
}
2930

3031
func FetchPendingSafeDeposits(ctx context.Context) ([]*SafeDepositPending, error) {

user.go

Lines changed: 15 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -14,23 +14,23 @@ import (
1414
)
1515

1616
type User struct {
17-
UserId string `json:"user_id"`
18-
SessionId string `json:"session_id"`
19-
PinToken string `json:"pin_token"`
20-
PINTokenBase64 string `json:"pin_token_base64"`
21-
IdentityNumber string `json:"identity_number"`
22-
HasSafe bool `json:"has_safe"`
23-
TIPKeyBase64 string `json:"tip_key_base64"`
24-
Phone string `json:"phone"`
25-
FullName string `json:"full_name"`
26-
AvatarURL string `json:"avatar_url"`
27-
DeviceStatus string `json:"device_status"`
28-
CreatedAt string `json:"created_at"`
29-
Memebership Memebership `json:"membership"`
30-
AppId string `json:"app_id"`
17+
UserId string `json:"user_id"`
18+
SessionId string `json:"session_id"`
19+
PinToken string `json:"pin_token"`
20+
PINTokenBase64 string `json:"pin_token_base64"`
21+
IdentityNumber string `json:"identity_number"`
22+
HasSafe bool `json:"has_safe"`
23+
TIPKeyBase64 string `json:"tip_key_base64"`
24+
Phone string `json:"phone"`
25+
FullName string `json:"full_name"`
26+
AvatarURL string `json:"avatar_url"`
27+
DeviceStatus string `json:"device_status"`
28+
CreatedAt time.Time `json:"created_at"`
29+
Membership Membership `json:"membership"`
30+
AppId string `json:"app_id"`
3131
}
3232

33-
type Memebership struct {
33+
type Membership struct {
3434
Plan string `json:"plan"`
3535
ExpiredAt time.Time `json:"expired_at"`
3636
}

0 commit comments

Comments
 (0)