diff --git a/cmd/api/handlers/responses.go b/cmd/api/handlers/responses.go index d6c72887a..7220d4c1b 100644 --- a/cmd/api/handlers/responses.go +++ b/cmd/api/handlers/responses.go @@ -661,7 +661,7 @@ type TokenMetadata struct { Symbol string `json:"symbol,omitempty" extensions:"x-nullable"` Name string `json:"name,omitempty" extensions:"x-nullable"` Decimals *int64 `json:"decimals,omitempty" extensions:"x-nullable"` - Extras map[string]interface{} `json:"extras,omitempty" extensions:"x-nullable"` + TokenInfo map[string]interface{} `json:"token_info,omitempty" extensions:"x-nullable"` Volume24Hours *float64 `json:"volume_24_hours,omitempty" extensions:"x-nullable"` } @@ -674,7 +674,7 @@ func TokenMetadataFromElasticModel(model tokenmetadata.TokenMetadata) (tm TokenM tm.Contract = model.Contract tm.Level = model.Level tm.Network = model.Network - tm.Extras = model.Extras + tm.TokenInfo = model.Extras return } diff --git a/internal/models/interface.go b/internal/models/interface.go index cde977a2c..80b4c6c2a 100644 --- a/internal/models/interface.go +++ b/internal/models/interface.go @@ -16,7 +16,7 @@ type GeneralRepository interface { GetByNetwork(string, interface{}) error GetByNetworkWithSort(string, string, string, interface{}) error UpdateDoc(model Model) (err error) - UpdateFields(string, string, interface{}, ...string) error + UpdateFields(index, id string, data interface{}, fields ...string) error GetEvents([]SubscriptionRequest, int64, int64) ([]Event, error) SearchByText(string, int64, []string, map[string]interface{}, bool) (Result, error) CreateAWSRepository(string, string, string) error diff --git a/internal/parsers/tzip/tokens/metadata.go b/internal/parsers/tzip/tokens/metadata.go index 16cc849f5..87745afcb 100644 --- a/internal/parsers/tzip/tokens/metadata.go +++ b/internal/parsers/tzip/tokens/metadata.go @@ -7,6 +7,7 @@ import ( "time" "github.com/baking-bad/bcdhub/internal/contractparser/consts" + "github.com/baking-bad/bcdhub/internal/logger" "github.com/baking-bad/bcdhub/internal/models/tokenmetadata" "github.com/tidwall/gjson" ) @@ -140,8 +141,21 @@ func (m *TokenMetadata) UnmarshalJSON(data []byte) error { delete(res, keySymbol) } if val, ok := res[keyDecimals]; ok { - if decimals, ok := val.(int64); ok { + switch decimals := val.(type) { + case float64: + int64Val := int64(decimals) + m.Decimals = &int64Val + case int64: m.Decimals = &decimals + case string: + int64Val, err := strconv.ParseInt(decimals, 10, 64) + if err != nil { + logger.Errorf("TokenMetadata decimal Unmarshal error with string. Got %##v %T", res[keyDecimals], val) + } else { + m.Decimals = &int64Val + } + default: + logger.Errorf("TokenMetadata decimal Unmarshal error. Wanted float64, int64 or (>_<) string, got %##v %T", res[keyDecimals], val) } delete(res, keyDecimals) } diff --git a/internal/parsers/tzip/tokens/metadata_test.go b/internal/parsers/tzip/tokens/metadata_test.go index ab7fe142b..2babdc005 100644 --- a/internal/parsers/tzip/tokens/metadata_test.go +++ b/internal/parsers/tzip/tokens/metadata_test.go @@ -183,3 +183,56 @@ func TestTokenMetadata_Merge(t *testing.T) { }) } } + +func TestTokenMetadata_UnmarshalJSON(t *testing.T) { + tests := []struct { + name string + tm TokenMetadata + data []byte + }{ + { + name: "test ipfs", + tm: TokenMetadata{ + Symbol: "SIMMAW", + Name: "Mystery Map Award", + Decimals: int64Ptr(0), + Extras: map[string]interface{}{ + "description": "A most mysterious map has been discovered. Where it leads is uncertain, but an adventure lies ahead.", + "nonTransferable": false, + "symbolPreference": false, + "booleanAmount": false, + "displayUri": "https://gateway.pinata.cloud/ipfs/QmPkJBaRnb2JwqA1S2sUQayTV9xT3x8MBnsmq7ForBWKuU", + "defaultPresentation": "large", + "actionLabel": "Send", + }, + }, + data: []byte(`{ + "name": "Mystery Map Award", + "symbol": "SIMMAW", + "decimals": 0, + "description": "A most mysterious map has been discovered. Where it leads is uncertain, but an adventure lies ahead.", + "nonTransferable": false, + "symbolPreference": false, + "booleanAmount": false, + "displayUri": "https://gateway.pinata.cloud/ipfs/QmPkJBaRnb2JwqA1S2sUQayTV9xT3x8MBnsmq7ForBWKuU", + "defaultPresentation": "large", + "actionLabel": "Send" + }`), + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + m := new(TokenMetadata) + if err := m.UnmarshalJSON(tt.data); err != nil { + t.Errorf("TokenMetadata.UnmarshalJSON() error = %v", err) + return + } + + assert.Equal(t, tt.tm, *m) + }) + } +} + +func int64Ptr(val int64) *int64 { + return &val +} diff --git a/scripts/migration/main.go b/scripts/migration/main.go index cd217f2c1..2b4a15804 100644 --- a/scripts/migration/main.go +++ b/scripts/migration/main.go @@ -28,6 +28,7 @@ var migrationsList = []migrations.Migration{ &migrations.ExtendedStorageEvents{}, &migrations.ParameterEvents{}, &migrations.TokenBalanceRecalc{}, + &migrations.TokenMetadataSetDecimals{}, } func main() { diff --git a/scripts/migration/migrations/token_metadata_set_decimals.go b/scripts/migration/migrations/token_metadata_set_decimals.go new file mode 100644 index 000000000..141622857 --- /dev/null +++ b/scripts/migration/migrations/token_metadata_set_decimals.go @@ -0,0 +1,75 @@ +package migrations + +import ( + "github.com/baking-bad/bcdhub/internal/config" + "github.com/baking-bad/bcdhub/internal/logger" + "github.com/baking-bad/bcdhub/internal/models" + "github.com/baking-bad/bcdhub/internal/models/tokenmetadata" + "github.com/baking-bad/bcdhub/internal/parsers/tzip/tokens" +) + +// TokenMetadataSetDecimals - migration that set decimals in token metadata for all metadata with empty decimals +type TokenMetadataSetDecimals struct{} + +// Key - +func (m *TokenMetadataSetDecimals) Key() string { + return "token_metadata_set_decimals" +} + +// Description - +func (m *TokenMetadataSetDecimals) Description() string { + return "set decimals in token metadata for all metadata with empty decimals" +} + +// Do - migrate function +func (m *TokenMetadataSetDecimals) Do(ctx *config.Context) error { + var updates []models.Model + + for _, network := range ctx.Config.Scripts.Networks { + logger.Info("Work with %swork", network) + rpc, err := ctx.GetRPC(network) + if err != nil { + return err + } + + parser := tokens.NewParser(ctx.BigMapDiffs, ctx.Blocks, ctx.Protocols, ctx.Schema, ctx.Storage, rpc, ctx.SharePath, network, ctx.Config.IPFSGateways...) + + logger.Info("Receiving token metadata....") + tokenMetadata, err := ctx.TokenMetadata.Get(tokenmetadata.GetContext{ + TokenID: -1, + Network: network, + }) + if err != nil { + return err + } + + logger.Info("Received %d metadata....", len(tokenMetadata)) + + if len(tokenMetadata) == 0 { + continue + } + + for i, tm := range tokenMetadata { + if tm.Decimals != nil { + continue + } + + parsedTm, err := parser.Parse(tm.Contract, 0) + if err != nil { + return err + } + + for j, ptm := range parsedTm { + if ptm.Decimals != nil { + logger.Info("Found: contract=%s decimals=%v", ptm.Contract, *ptm.Decimals) + tokenMetadata[i].Decimals = parsedTm[j].Decimals + updates = append(updates, &tokenMetadata[i]) + } + } + } + } + + logger.Info("Total updates: %d", len(updates)) + + return ctx.Storage.BulkUpdate(updates) +}