diff --git a/address.go b/address.go index 2b7cb22..4ab34ad 100644 --- a/address.go +++ b/address.go @@ -16,14 +16,14 @@ type AddressInput struct { } type Address struct { - AddressId string `json:"address_id"` - AssetId string `json:"asset_id"` - Label string `json:"label"` - Destination string `json:"destination"` - Tag string `json:"tag"` - Fee string `json:"fee"` - Dust string `json:"dust"` - UpdatedAt string `json:"updated_at"` + AddressId string `json:"address_id"` + AssetId string `json:"asset_id"` + Label string `json:"label"` + Destination string `json:"destination"` + Tag string `json:"tag"` + Fee string `json:"fee"` + Dust string `json:"dust"` + UpdatedAt time.Time `json:"updated_at"` } type SimpleAddress struct { diff --git a/inscription.go b/inscription.go index 3800957..8e0da6a 100644 --- a/inscription.go +++ b/inscription.go @@ -1,5 +1,12 @@ package bot +import ( + "context" + "encoding/json" + "fmt" + "time" +) + const ( InscriptionModeInstant = 1 InscriptionModeDone = 2 @@ -79,3 +86,106 @@ type InscriptionOccupy struct { // the integer sequence number of the NFT inscription Sequence uint64 `json:"sequence"` } + +// Collection represents the API response structure for collection data +type Collection struct { + AssetKey string `json:"asset_key"` + CollectionHash string `json:"collection_hash"` + KernelAssetID string `json:"kernel_asset_id"` + Name string `json:"name"` + Symbol string `json:"symbol"` + Description string `json:"description"` + IconURL string `json:"icon_url"` + Supply string `json:"supply"` + Unit string `json:"unit"` + MinimumPrice string `json:"minimum_price"` + Treasury map[string]interface{} `json:"treasury"` + Type string `json:"type"` + CreatedAt time.Time `json:"created_at"` + UpdatedAt time.Time `json:"updated_at"` +} + +// Inscription represents the API response structure for inscription data +type Inscription struct { + InscriptionHash string `json:"inscription_hash"` + CollectionHash string `json:"collection_hash"` + ContentType string `json:"content_type"` + ContentURL string `json:"content_url"` + CreatedAt time.Time `json:"created_at"` + OccupiedBy string `json:"occupied_by"` + Owner string `json:"owner"` + Recipient string `json:"recipient"` + Sequence int64 `json:"sequence"` + Type string `json:"type"` + UpdatedAt time.Time `json:"updated_at"` +} + +// ReadCollection reads collection information from Mixin API +func ReadCollection(ctx context.Context, collectionHash string) (*Collection, error) { + body, err := Request(ctx, "GET", "/safe/inscriptions/collections/"+collectionHash, nil, "") + if err != nil { + return nil, err + } + + var resp struct { + Data *Collection `json:"data"` + Error Error `json:"error"` + } + + err = json.Unmarshal(body, &resp) + if err != nil { + return nil, err + } + + if resp.Error.Code > 0 { + return nil, resp.Error + } + + return resp.Data, nil +} + +// ReadInscription reads inscription information from Mixin API +func ReadInscription(ctx context.Context, inscriptionHash string) (*Inscription, error) { + body, err := Request(ctx, "GET", "/safe/inscriptions/items/"+inscriptionHash, nil, "") + if err != nil { + return nil, err + } + + var resp struct { + Data *Inscription `json:"data"` + Error Error `json:"error"` + } + + err = json.Unmarshal(body, &resp) + if err != nil { + return nil, err + } + + if resp.Error.Code > 0 { + return nil, resp.Error + } + + return resp.Data, nil +} + +// ReadCollectionItems reads all items in a collection from Mixin API +func ReadCollectionItems(ctx context.Context, collectionHash string) ([]*Inscription, error) { + path := fmt.Sprintf("/safe/inscriptions/collections/%s/items", collectionHash) + body, err := Request(ctx, "GET", path, nil, "") + if err != nil { + return nil, err + } + + var resp struct { + Data []*Inscription `json:"data"` + Error Error `json:"error"` + } + if err := json.Unmarshal(body, &resp); err != nil { + return nil, err + } + if resp.Error.Code > 0 { + return nil, resp.Error + } + + return resp.Data, nil +} diff --git a/inscription_test.go b/inscription_test.go new file mode 100644 index 0000000..ce48664 --- /dev/null +++ b/inscription_test.go @@ -0,0 +1,87 @@ +package bot + +import ( + "context" + "testing" + + "github.com/stretchr/testify/assert" +) + +func TestReadCollection(t *testing.T) { + assert := assert.New(t) + ctx := context.Background() + // Test collection hash provided by user + collectionHash := "d48af6bdd4ce12328583611debf2f75e0895a2c5522d23db70c912a6a34538a9" + + collection, err := ReadCollection(ctx, collectionHash) + if err != nil { + t.Fatalf("ReadCollection failed: %v", err) + } + + assert.NotNil(collection, "Collection should not be nil") + assert.Equal(collectionHash, collection.CollectionHash, "Collection hash should match") + assert.NotEmpty(collection.Name, "Collection name should not be empty") + + t.Logf("Collection Name: %s", collection.Name) + t.Logf("Collection Symbol: %s", collection.Symbol) + t.Logf("Collection Supply: %s", collection.Supply) +} + +func TestReadCollectionItems(t *testing.T) { + assert := assert.New(t) + ctx := context.Background() + // Test collection hash provided by user + collectionHash := "d48af6bdd4ce12328583611debf2f75e0895a2c5522d23db70c912a6a34538a9" + + items, err := ReadCollectionItems(ctx, collectionHash) + if err != nil { + t.Fatalf("ReadCollectionItems failed: %v", err) + } + + assert.NotNil(items, "Items should not be nil") + assert.Greater(len(items), 0, "Should have at least one item") + + t.Logf("Found %d items in collection", len(items)) + + // Verify first item structure + if len(items) > 0 { + firstItem := items[0] + assert.NotEmpty(firstItem.InscriptionHash, "Inscription hash should not be empty") + assert.Equal(collectionHash, firstItem.CollectionHash, "Collection hash should match") + + t.Logf("First item inscription hash: %s", firstItem.InscriptionHash) + t.Logf("First item content type: %s", firstItem.ContentType) + } +} + +func TestReadInscription(t *testing.T) { + assert := assert.New(t) + ctx := context.Background() + + // First get items from the collection to get a valid inscription hash + collectionHash := "d48af6bdd4ce12328583611debf2f75e0895a2c5522d23db70c912a6a34538a9" + items, err := ReadCollectionItems(ctx, collectionHash) + if err != nil { + t.Fatalf("ReadCollectionItems failed: %v", err) + } + + if len(items) == 0 { + t.Skip("No items in collection to test with") + } + + // Test with the first item's inscription hash + inscriptionHash := items[0].InscriptionHash + + inscription, err := ReadInscription(ctx, inscriptionHash) + if err != nil { + t.Fatalf("ReadInscription failed: %v", err) + } + + assert.NotNil(inscription, "Inscription should not be nil") + assert.Equal(inscriptionHash, inscription.InscriptionHash, "Inscription hash should match") + assert.Equal(collectionHash, inscription.CollectionHash, "Collection hash should match") + + t.Logf("Inscription hash: %s", inscription.InscriptionHash) + t.Logf("Content type: %s", inscription.ContentType) + t.Logf("Owner: %s", inscription.Owner) +} diff --git a/network.go b/network.go index ee575d1..921e4b8 100644 --- a/network.go +++ b/network.go @@ -3,38 +3,39 @@ package bot import ( "context" "encoding/json" + "time" ) type AssetNetwork struct { - AssetID string `json:"asset_id"` - ChainID string `json:"chain_id"` - FeeAssetID string `json:"fee_asset_id"` - DisplaySymbol string `json:"display_symbol"` - DisplayName string `json:"display_name"` - Symbol string `json:"symbol"` - Name string `json:"name"` - IconURL string `json:"icon_url"` - Balance string `json:"balance"` - Destination string `json:"destination"` - Tag string `json:"tag"` - PriceBTC string `json:"price_btc"` - PriceUSD string `json:"price_usd"` - ChangeBTC string `json:"change_btc"` - ChangeUSD string `json:"change_usd"` - AssetKey string `json:"asset_key"` - Precision int `json:"precision"` - MixinID string `json:"mixin_id"` - KernelAssetID string `json:"kernel_asset_id"` - Reserve string `json:"reserve"` - Dust string `json:"dust"` - Confirmations int64 `json:"confirmations"` - Capitalization float64 `json:"capitalization"` - Liquidity string `json:"liquidity"` - PriceUpdatedAt string `json:"price_updated_at"` - WithdrawalMemoPossibility string `json:"withdrawal_memo_possibility"` - PrimitiveAssetId string `json:"primitive_asset_id,omitempty"` - Level int64 `json:"level"` - CollectionHash string `json:"collection_hash,omitempty"` + AssetID string `json:"asset_id"` + ChainID string `json:"chain_id"` + FeeAssetID string `json:"fee_asset_id"` + DisplaySymbol string `json:"display_symbol"` + DisplayName string `json:"display_name"` + Symbol string `json:"symbol"` + Name string `json:"name"` + IconURL string `json:"icon_url"` + Balance string `json:"balance"` + Destination string `json:"destination"` + Tag string `json:"tag"` + PriceBTC string `json:"price_btc"` + PriceUSD string `json:"price_usd"` + ChangeBTC string `json:"change_btc"` + ChangeUSD string `json:"change_usd"` + AssetKey string `json:"asset_key"` + Precision int `json:"precision"` + MixinID string `json:"mixin_id"` + KernelAssetID string `json:"kernel_asset_id"` + Reserve string `json:"reserve"` + Dust string `json:"dust"` + Confirmations int64 `json:"confirmations"` + Capitalization float64 `json:"capitalization"` + Liquidity string `json:"liquidity"` + PriceUpdatedAt time.Time `json:"price_updated_at"` + WithdrawalMemoPossibility string `json:"withdrawal_memo_possibility"` + PrimitiveAssetId string `json:"primitive_asset_id,omitempty"` + Level int64 `json:"level"` + CollectionHash string `json:"collection_hash,omitempty"` } func ReadNetworkAssets(ctx context.Context) ([]*AssetNetwork, error) { diff --git a/safe_deposits.go b/safe_deposits.go index 7e53799..b122f26 100644 --- a/safe_deposits.go +++ b/safe_deposits.go @@ -3,28 +3,29 @@ package bot import ( "context" "encoding/json" + "time" ) type SafeDepositPending struct { - Amount string `json:"amount"` - AssetID string `json:"asset_id"` - AssetKey string `json:"asset_key"` - BlockHash string `json:"block_hash"` - BlockNumber int `json:"block_number"` - ChainID string `json:"chain_id"` - Confirmations int `json:"confirmations"` - CreatedAt string `json:"created_at"` - DepositID string `json:"deposit_id"` - Destination string `json:"destination"` - Extra string `json:"extra"` - KernelAssetID string `json:"kernel_asset_id"` - OutputIndex int `json:"output_index"` - Sender string `json:"sender"` - State string `json:"state"` - Tag string `json:"tag"` - Threshold int `json:"threshold"` - TransactionHash string `json:"transaction_hash"` - UpdatedAt string `json:"updated_at"` + Amount string `json:"amount"` + AssetID string `json:"asset_id"` + AssetKey string `json:"asset_key"` + BlockHash string `json:"block_hash"` + BlockNumber int `json:"block_number"` + ChainID string `json:"chain_id"` + Confirmations int `json:"confirmations"` + CreatedAt time.Time `json:"created_at"` + DepositID string `json:"deposit_id"` + Destination string `json:"destination"` + Extra string `json:"extra"` + KernelAssetID string `json:"kernel_asset_id"` + OutputIndex int `json:"output_index"` + Sender string `json:"sender"` + State string `json:"state"` + Tag string `json:"tag"` + Threshold int `json:"threshold"` + TransactionHash string `json:"transaction_hash"` + UpdatedAt time.Time `json:"updated_at"` } func FetchPendingSafeDeposits(ctx context.Context) ([]*SafeDepositPending, error) { diff --git a/user.go b/user.go index b1c5e97..2a6084c 100644 --- a/user.go +++ b/user.go @@ -14,23 +14,23 @@ import ( ) type User struct { - UserId string `json:"user_id"` - SessionId string `json:"session_id"` - PinToken string `json:"pin_token"` - PINTokenBase64 string `json:"pin_token_base64"` - IdentityNumber string `json:"identity_number"` - HasSafe bool `json:"has_safe"` - TIPKeyBase64 string `json:"tip_key_base64"` - Phone string `json:"phone"` - FullName string `json:"full_name"` - AvatarURL string `json:"avatar_url"` - DeviceStatus string `json:"device_status"` - CreatedAt string `json:"created_at"` - Memebership Memebership `json:"membership"` - AppId string `json:"app_id"` + UserId string `json:"user_id"` + SessionId string `json:"session_id"` + PinToken string `json:"pin_token"` + PINTokenBase64 string `json:"pin_token_base64"` + IdentityNumber string `json:"identity_number"` + HasSafe bool `json:"has_safe"` + TIPKeyBase64 string `json:"tip_key_base64"` + Phone string `json:"phone"` + FullName string `json:"full_name"` + AvatarURL string `json:"avatar_url"` + DeviceStatus string `json:"device_status"` + CreatedAt time.Time `json:"created_at"` + Membership Membership `json:"membership"` + AppId string `json:"app_id"` } -type Memebership struct { +type Membership struct { Plan string `json:"plan"` ExpiredAt time.Time `json:"expired_at"` }