parent
dca38d1d32
commit
a38b34ae49
|
@ -106,7 +106,7 @@ func (b *StatusNode) initServices(config *params.NodeConfig, mediaServer *server
|
|||
// Community collectibles.
|
||||
// Messenger needs the CollectiblesManager to get the list of collectibles owned
|
||||
// by a certain account and check community entry permissions.
|
||||
// We handle circular dependency between the two by delaying ininitalization of the CollectibleMetadataProvider
|
||||
// We handle circular dependency between the two by delaying ininitalization of the CommunityCollectibleInfoProvider
|
||||
// in the CollectiblesManager.
|
||||
if config.WakuConfig.Enabled {
|
||||
wakuService, err := b.wakuService(&config.WakuConfig, &config.ClusterConfig)
|
||||
|
@ -125,7 +125,6 @@ func (b *StatusNode) initServices(config *params.NodeConfig, mediaServer *server
|
|||
|
||||
services = append(services, wakuext)
|
||||
|
||||
b.SetWalletCollectibleMetadataProvider(wakuext)
|
||||
b.SetWalletCollectibleCommunityInfoProvider(wakuext)
|
||||
}
|
||||
|
||||
|
@ -153,7 +152,6 @@ func (b *StatusNode) initServices(config *params.NodeConfig, mediaServer *server
|
|||
|
||||
services = append(services, wakuext)
|
||||
|
||||
b.SetWalletCollectibleMetadataProvider(wakuext)
|
||||
b.SetWalletCollectibleCommunityInfoProvider(wakuext)
|
||||
}
|
||||
|
||||
|
@ -514,12 +512,6 @@ func (b *StatusNode) WalletService() *wallet.Service {
|
|||
return b.walletSrvc
|
||||
}
|
||||
|
||||
func (b *StatusNode) SetWalletCollectibleMetadataProvider(provider thirdparty.CollectibleMetadataProvider) {
|
||||
if b.walletSrvc != nil {
|
||||
b.walletSrvc.SetCollectibleMetadataProvider(provider)
|
||||
}
|
||||
}
|
||||
|
||||
func (b *StatusNode) SetWalletCollectibleCommunityInfoProvider(provider thirdparty.CollectibleCommunityInfoProvider) {
|
||||
if b.walletSrvc != nil {
|
||||
b.walletSrvc.SetCollectibleCommunityInfoProvider(provider)
|
||||
|
|
|
@ -555,64 +555,80 @@ func tokenURIToCommunityID(tokenURI string) string {
|
|||
return communityID
|
||||
}
|
||||
|
||||
func (s *Service) CanProvideCollectibleMetadata(id thirdparty.CollectibleUniqueID, tokenURI string) (bool, error) {
|
||||
ret := tokenURI != "" && tokenURIToCommunityID(tokenURI) != ""
|
||||
return ret, nil
|
||||
func (s *Service) GetCommunityID(tokenURI string) string {
|
||||
if tokenURI != "" {
|
||||
return tokenURIToCommunityID(tokenURI)
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
func (s *Service) FetchCollectibleMetadata(id thirdparty.CollectibleUniqueID, tokenURI string) (*thirdparty.FullCollectibleData, error) {
|
||||
func (s *Service) FillCollectibleMetadata(collectible *thirdparty.FullCollectibleData) error {
|
||||
if s.messenger == nil {
|
||||
return nil, fmt.Errorf("messenger not ready")
|
||||
return fmt.Errorf("messenger not ready")
|
||||
}
|
||||
|
||||
communityID := tokenURIToCommunityID(tokenURI)
|
||||
if collectible == nil {
|
||||
return fmt.Errorf("empty collectible")
|
||||
}
|
||||
|
||||
id := collectible.CollectibleData.ID
|
||||
communityID := collectible.CollectibleData.CommunityID
|
||||
|
||||
if communityID == "" {
|
||||
return nil, fmt.Errorf("invalid tokenURI")
|
||||
return fmt.Errorf("invalid communityID")
|
||||
}
|
||||
|
||||
community, err := s.fetchCommunity(communityID)
|
||||
|
||||
if err != nil {
|
||||
return nil, err
|
||||
return err
|
||||
}
|
||||
|
||||
if community == nil {
|
||||
return nil, nil
|
||||
return nil
|
||||
}
|
||||
|
||||
tokenMetadata, err := s.fetchCommunityCollectibleMetadata(community, id.ContractID)
|
||||
|
||||
if err != nil {
|
||||
return nil, err
|
||||
return err
|
||||
}
|
||||
|
||||
if tokenMetadata == nil {
|
||||
return nil, nil
|
||||
return nil
|
||||
}
|
||||
|
||||
token, err := s.fetchCommunityToken(communityID, id.ContractID)
|
||||
communityToken, err := s.fetchCommunityToken(communityID, id.ContractID)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
return err
|
||||
}
|
||||
|
||||
return &thirdparty.FullCollectibleData{
|
||||
CollectibleData: thirdparty.CollectibleData{
|
||||
ID: id,
|
||||
CommunityID: communityID,
|
||||
Name: tokenMetadata.GetName(),
|
||||
Description: tokenMetadata.GetDescription(),
|
||||
ImageURL: tokenMetadata.GetImage(),
|
||||
TokenURI: tokenURI,
|
||||
Traits: getCollectibleCommunityTraits(token),
|
||||
},
|
||||
CollectionData: &thirdparty.CollectionData{
|
||||
permission := fetchCommunityCollectiblePermission(community, id)
|
||||
|
||||
privilegesLevel := token.CommunityLevel
|
||||
if permission != nil {
|
||||
privilegesLevel = permissionTypeToPrivilegesLevel(permission.GetType())
|
||||
}
|
||||
|
||||
collectible.CollectibleData.Name = tokenMetadata.GetName()
|
||||
collectible.CollectibleData.Description = tokenMetadata.GetDescription()
|
||||
collectible.CollectibleData.ImageURL = tokenMetadata.GetImage()
|
||||
collectible.CollectibleData.Traits = getCollectibleCommunityTraits(communityToken)
|
||||
|
||||
if collectible.CollectionData == nil {
|
||||
collectible.CollectionData = &thirdparty.CollectionData{
|
||||
ID: id.ContractID,
|
||||
CommunityID: communityID,
|
||||
Name: tokenMetadata.GetName(),
|
||||
ImageURL: tokenMetadata.GetImage(),
|
||||
},
|
||||
}, nil
|
||||
}
|
||||
}
|
||||
collectible.CollectionData.Name = tokenMetadata.GetName()
|
||||
collectible.CollectionData.ImageURL = tokenMetadata.GetImage()
|
||||
|
||||
collectible.CommunityInfo = &thirdparty.CollectibleCommunityInfo{
|
||||
PrivilegesLevel: privilegesLevel,
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func permissionTypeToPrivilegesLevel(permissionType protobuf.CommunityTokenPermission_Type) token.PrivilegesLevel {
|
||||
|
@ -626,7 +642,7 @@ func permissionTypeToPrivilegesLevel(permissionType protobuf.CommunityTokenPermi
|
|||
}
|
||||
}
|
||||
|
||||
func (s *Service) FetchCollectibleCommunityInfo(communityID string, id thirdparty.CollectibleUniqueID) (*thirdparty.CollectiblesCommunityInfo, error) {
|
||||
func (s *Service) FetchCommunityInfo(communityID string) (*thirdparty.CommunityInfo, error) {
|
||||
community, err := s.fetchCommunity(communityID)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
|
@ -635,37 +651,13 @@ func (s *Service) FetchCollectibleCommunityInfo(communityID string, id thirdpart
|
|||
return nil, nil
|
||||
}
|
||||
|
||||
metadata, err := s.fetchCommunityCollectibleMetadata(community, id.ContractID)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if metadata == nil {
|
||||
return nil, nil
|
||||
communityInfo := &thirdparty.CommunityInfo{
|
||||
CommunityName: community.Name(),
|
||||
CommunityColor: community.Color(),
|
||||
CommunityImage: fetchCommunityImage(community),
|
||||
}
|
||||
|
||||
permission := fetchCommunityCollectiblePermission(community, id)
|
||||
|
||||
privilegesLevel := token.CommunityLevel
|
||||
if permission != nil {
|
||||
privilegesLevel = permissionTypeToPrivilegesLevel(permission.GetType())
|
||||
}
|
||||
|
||||
return &thirdparty.CollectiblesCommunityInfo{
|
||||
CommunityID: communityID,
|
||||
CommunityName: community.Name(),
|
||||
CommunityColor: community.Color(),
|
||||
CommunityImage: fetchCommunityImage(community),
|
||||
PrivilegesLevel: privilegesLevel,
|
||||
}, nil
|
||||
}
|
||||
|
||||
func (s *Service) FetchCollectibleCommunityTraits(communityID string, id thirdparty.CollectibleUniqueID) ([]thirdparty.CollectibleTrait, error) {
|
||||
token, err := s.fetchCommunityToken(communityID, id.ContractID)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return getCollectibleCommunityTraits(token), nil
|
||||
return communityInfo, nil
|
||||
}
|
||||
|
||||
func (s *Service) fetchCommunity(communityID string) (*communities.Community, error) {
|
||||
|
|
|
@ -5,6 +5,7 @@ import (
|
|||
"fmt"
|
||||
"math/big"
|
||||
|
||||
"github.com/status-im/status-go/protocol/communities/token"
|
||||
"github.com/status-im/status-go/services/wallet/bigint"
|
||||
"github.com/status-im/status-go/services/wallet/thirdparty"
|
||||
"github.com/status-im/status-go/sqlite"
|
||||
|
@ -21,6 +22,7 @@ func NewCollectibleDataDB(sqlDb *sql.DB) *CollectibleDataDB {
|
|||
}
|
||||
|
||||
const collectibleDataColumns = "chain_id, contract_address, token_id, provider, name, description, permalink, image_url, animation_url, animation_media_type, background_color, token_uri, community_id"
|
||||
const collectibleCommunityDataColumns = "community_privileges_level"
|
||||
const collectibleTraitsColumns = "chain_id, contract_address, token_id, trait_type, trait_value, display_type, max_value"
|
||||
const selectCollectibleTraitsColumns = "trait_type, trait_value, display_type, max_value"
|
||||
|
||||
|
@ -252,3 +254,70 @@ func (o *CollectibleDataDB) GetData(ids []thirdparty.CollectibleUniqueID) (map[s
|
|||
}
|
||||
return ret, nil
|
||||
}
|
||||
|
||||
func (o *CollectibleDataDB) SetCommunityInfo(id thirdparty.CollectibleUniqueID, communityInfo thirdparty.CollectibleCommunityInfo) (err error) {
|
||||
tx, err := o.db.Begin()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer func() {
|
||||
if err == nil {
|
||||
err = tx.Commit()
|
||||
return
|
||||
}
|
||||
_ = tx.Rollback()
|
||||
}()
|
||||
|
||||
update, err := tx.Prepare(`UPDATE collectible_data_cache
|
||||
SET community_privileges_level=?
|
||||
WHERE chain_id=? AND contract_address=? AND token_id=?`)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
_, err = update.Exec(
|
||||
communityInfo.PrivilegesLevel,
|
||||
id.ContractID.ChainID,
|
||||
id.ContractID.Address,
|
||||
(*bigint.SQLBigIntBytes)(id.TokenID.Int),
|
||||
)
|
||||
|
||||
return err
|
||||
}
|
||||
|
||||
func (o *CollectibleDataDB) GetCommunityInfo(id thirdparty.CollectibleUniqueID) (*thirdparty.CollectibleCommunityInfo, error) {
|
||||
ret := thirdparty.CollectibleCommunityInfo{
|
||||
PrivilegesLevel: token.CommunityLevel,
|
||||
}
|
||||
|
||||
getData, err := o.db.Prepare(fmt.Sprintf(`SELECT %s
|
||||
FROM collectible_data_cache
|
||||
WHERE chain_id=? AND contract_address=? AND token_id=?`, collectibleCommunityDataColumns))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
row := getData.QueryRow(
|
||||
id.ContractID.ChainID,
|
||||
id.ContractID.Address,
|
||||
(*bigint.SQLBigIntBytes)(id.TokenID.Int),
|
||||
)
|
||||
|
||||
var dbPrivilegesLevel sql.NullByte
|
||||
|
||||
err = row.Scan(
|
||||
&dbPrivilegesLevel,
|
||||
)
|
||||
|
||||
if err == sql.ErrNoRows {
|
||||
return nil, nil
|
||||
} else if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if dbPrivilegesLevel.Valid {
|
||||
ret.PrivilegesLevel = token.PrivilegesLevel(dbPrivilegesLevel.Byte)
|
||||
}
|
||||
|
||||
return &ret, nil
|
||||
}
|
||||
|
|
|
@ -7,6 +7,7 @@ import (
|
|||
|
||||
"github.com/ethereum/go-ethereum/common"
|
||||
|
||||
"github.com/status-im/status-go/protocol/communities/token"
|
||||
"github.com/status-im/status-go/services/wallet/bigint"
|
||||
w_common "github.com/status-im/status-go/services/wallet/common"
|
||||
"github.com/status-im/status-go/services/wallet/thirdparty"
|
||||
|
@ -72,6 +73,17 @@ func generateTestCollectiblesData(count int) (result []thirdparty.CollectibleDat
|
|||
return result
|
||||
}
|
||||
|
||||
func generateTestCommunityData(count int) []thirdparty.CollectibleCommunityInfo {
|
||||
result := make([]thirdparty.CollectibleCommunityInfo, 0, count)
|
||||
for i := 0; i < count; i++ {
|
||||
newCommunityInfo := thirdparty.CollectibleCommunityInfo{
|
||||
PrivilegesLevel: token.PrivilegesLevel(i),
|
||||
}
|
||||
result = append(result, newCommunityInfo)
|
||||
}
|
||||
return result
|
||||
}
|
||||
|
||||
func TestUpdateCollectiblesData(t *testing.T) {
|
||||
db, cleanDB := setupCollectibleDataDBTest(t)
|
||||
defer cleanDB()
|
||||
|
@ -146,3 +158,28 @@ func TestUpdateCollectiblesData(t *testing.T) {
|
|||
require.Equal(t, c0, loadedMap[c0.ID.HashKey()])
|
||||
require.Equal(t, c1, loadedMap[c1.ID.HashKey()])
|
||||
}
|
||||
|
||||
func TestUpdateCommunityData(t *testing.T) {
|
||||
db, cleanDB := setupCollectibleDataDBTest(t)
|
||||
defer cleanDB()
|
||||
|
||||
const nData = 50
|
||||
data := generateTestCollectiblesData(nData)
|
||||
communityData := generateTestCommunityData(nData)
|
||||
|
||||
var err error
|
||||
|
||||
err = db.SetData(data)
|
||||
require.NoError(t, err)
|
||||
|
||||
for i := 0; i < nData; i++ {
|
||||
err = db.SetCommunityInfo(data[i].ID, communityData[i])
|
||||
require.NoError(t, err)
|
||||
}
|
||||
|
||||
for i := 0; i < nData; i++ {
|
||||
loadedCommunityData, err := db.GetCommunityInfo(data[i].ID)
|
||||
require.NoError(t, err)
|
||||
require.Equal(t, communityData[i], *loadedCommunityData)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -214,7 +214,7 @@ func (c *loadOwnedCollectiblesCommand) Run(parent context.Context) (err error) {
|
|||
break
|
||||
}
|
||||
|
||||
log.Debug("partial loadOwnedCollectiblesCommand", "chain", c.chainID, "account", c.account, "page", pageNr, "in", time.Since(pageStart), "found", len(partialOwnership.Items), "collectibles")
|
||||
log.Debug("partial loadOwnedCollectiblesCommand", "chain", c.chainID, "account", c.account, "page", pageNr, "in", time.Since(pageStart), "found", len(partialOwnership.Items))
|
||||
|
||||
c.partialOwnership = append(c.partialOwnership, partialOwnership.Items...)
|
||||
|
||||
|
|
|
@ -18,6 +18,7 @@ import (
|
|||
"github.com/status-im/status-go/services/accounts/settingsevent"
|
||||
"github.com/status-im/status-go/services/wallet/async"
|
||||
walletCommon "github.com/status-im/status-go/services/wallet/common"
|
||||
"github.com/status-im/status-go/services/wallet/community"
|
||||
"github.com/status-im/status-go/services/wallet/transfer"
|
||||
"github.com/status-im/status-go/services/wallet/walletevent"
|
||||
)
|
||||
|
@ -35,6 +36,7 @@ type timerPerAddressAndChainID = map[common.Address]timerPerChainID
|
|||
type Controller struct {
|
||||
manager *Manager
|
||||
ownershipDB *OwnershipDB
|
||||
communityDB *community.DataDB
|
||||
walletFeed *event.Feed
|
||||
accountsDB *accounts.Database
|
||||
accountsFeed *event.Feed
|
||||
|
@ -64,6 +66,7 @@ func NewController(
|
|||
return &Controller{
|
||||
manager: manager,
|
||||
ownershipDB: NewOwnershipDB(db),
|
||||
communityDB: community.NewDataDB(db),
|
||||
walletFeed: walletFeed,
|
||||
accountsDB: accountsDB,
|
||||
accountsFeed: accountsFeed,
|
||||
|
@ -412,7 +415,8 @@ func (c *Controller) notifyCommunityCollectiblesReceived(ownedCollectibles Owned
|
|||
continue
|
||||
}
|
||||
|
||||
communityInfo, err := c.manager.FetchCollectibleCommunityInfo(communityID, collectibleID)
|
||||
communityInfo, err := c.communityDB.GetCommunityInfo(communityID)
|
||||
|
||||
if err != nil {
|
||||
log.Error("Error fetching community info", "error", err)
|
||||
continue
|
||||
|
@ -421,7 +425,7 @@ func (c *Controller) notifyCommunityCollectiblesReceived(ownedCollectibles Owned
|
|||
header := CommunityCollectibleHeader{
|
||||
ID: collectibleID,
|
||||
Name: collectibleData.CollectibleData.Name,
|
||||
CommunityHeader: communityInfoToHeader(*communityInfo),
|
||||
CommunityHeader: communityInfoToHeader(communityID, communityInfo, collectibleData.CommunityInfo),
|
||||
}
|
||||
|
||||
communityCollectibles = append(communityCollectibles, header)
|
||||
|
|
|
@ -4,7 +4,6 @@ import (
|
|||
"context"
|
||||
"database/sql"
|
||||
"errors"
|
||||
"fmt"
|
||||
"math/big"
|
||||
"net/http"
|
||||
"strings"
|
||||
|
@ -20,6 +19,7 @@ import (
|
|||
"github.com/status-im/status-go/rpc"
|
||||
"github.com/status-im/status-go/services/wallet/bigint"
|
||||
walletCommon "github.com/status-im/status-go/services/wallet/common"
|
||||
"github.com/status-im/status-go/services/wallet/community"
|
||||
"github.com/status-im/status-go/services/wallet/connection"
|
||||
"github.com/status-im/status-go/services/wallet/thirdparty"
|
||||
"github.com/status-im/status-go/services/wallet/walletevent"
|
||||
|
@ -54,13 +54,13 @@ type Manager struct {
|
|||
collectibleDataProviders []thirdparty.CollectibleDataProvider
|
||||
collectionDataProviders []thirdparty.CollectionDataProvider
|
||||
collectibleProviders []thirdparty.CollectibleProvider
|
||||
metadataProvider thirdparty.CollectibleMetadataProvider
|
||||
communityInfoProvider thirdparty.CollectibleCommunityInfoProvider
|
||||
|
||||
httpClient *http.Client
|
||||
|
||||
collectiblesDataDB *CollectibleDataDB
|
||||
collectionsDataDB *CollectionDataDB
|
||||
communityDataDB *community.DataDB
|
||||
|
||||
statuses map[string]*connection.Status
|
||||
statusNotifier *connection.StatusNotifier
|
||||
|
@ -134,6 +134,7 @@ func NewManager(
|
|||
},
|
||||
collectiblesDataDB: NewCollectibleDataDB(db),
|
||||
collectionsDataDB: NewCollectionDataDB(db),
|
||||
communityDataDB: community.NewDataDB(db),
|
||||
statuses: statuses,
|
||||
statusNotifier: statusNotifier,
|
||||
}
|
||||
|
@ -196,10 +197,6 @@ func (o *Manager) doContentTypeRequest(url string) (string, error) {
|
|||
}
|
||||
|
||||
// Used to break circular dependency, call once as soon as possible after initialization
|
||||
func (o *Manager) SetMetadataProvider(metadataProvider thirdparty.CollectibleMetadataProvider) {
|
||||
o.metadataProvider = metadataProvider
|
||||
}
|
||||
|
||||
func (o *Manager) SetCommunityInfoProvider(communityInfoProvider thirdparty.CollectibleCommunityInfoProvider) {
|
||||
o.communityInfoProvider = communityInfoProvider
|
||||
}
|
||||
|
@ -489,62 +486,72 @@ func (o *Manager) fetchTokenURI(id thirdparty.CollectibleUniqueID) (string, erro
|
|||
}
|
||||
|
||||
func (o *Manager) processFullCollectibleData(assets []thirdparty.FullCollectibleData) error {
|
||||
fullyFetchedAssets := make(map[string]*thirdparty.FullCollectibleData)
|
||||
communityCollectibles := make(map[string][]*thirdparty.FullCollectibleData)
|
||||
|
||||
// Start with all assets, remove if any of the fetch steps fail
|
||||
for idx := range assets {
|
||||
asset := &assets[idx]
|
||||
id := asset.CollectibleData.ID
|
||||
fullyFetchedAssets[id.HashKey()] = asset
|
||||
}
|
||||
|
||||
for _, asset := range fullyFetchedAssets {
|
||||
// Only check community ownership if metadata is empty
|
||||
if isMetadataEmpty(asset.CollectibleData) {
|
||||
err := o.fillTokenURI(asset)
|
||||
if err != nil {
|
||||
log.Error("fillTokenURI failed", "err", err)
|
||||
delete(fullyFetchedAssets, asset.CollectibleData.ID.HashKey())
|
||||
continue
|
||||
}
|
||||
err = o.fillCommunityID(asset)
|
||||
if err != nil {
|
||||
log.Error("fillCommunityID failed", "err", err)
|
||||
delete(fullyFetchedAssets, asset.CollectibleData.ID.HashKey())
|
||||
continue
|
||||
}
|
||||
|
||||
communityID := asset.CollectibleData.CommunityID
|
||||
if communityID != "" {
|
||||
if _, ok := communityCollectibles[communityID]; !ok {
|
||||
communityCollectibles[communityID] = make([]*thirdparty.FullCollectibleData, 0)
|
||||
}
|
||||
communityCollectibles[communityID] = append(communityCollectibles[communityID], asset)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Community collectibles are grouped by community ID
|
||||
// If fetching data for one community fails (for example, owner node is down),
|
||||
// skip and continue with the other communities.
|
||||
for communityID, communityAssets := range communityCollectibles {
|
||||
err := o.fillCommunityInfo(communityID, communityAssets)
|
||||
if err != nil {
|
||||
log.Error("fillCommunityInfo failed", "communityID", communityID, "err", err)
|
||||
for _, communityAsset := range communityAssets {
|
||||
delete(fullyFetchedAssets, communityAsset.CollectibleData.ID.HashKey())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for _, asset := range fullyFetchedAssets {
|
||||
err := o.fillAnimationMediatype(asset)
|
||||
if err != nil {
|
||||
log.Error("fillAnimationMediatype failed", "err", err)
|
||||
delete(fullyFetchedAssets, asset.CollectibleData.ID.HashKey())
|
||||
continue
|
||||
}
|
||||
}
|
||||
|
||||
// Save successfully fetched data to DB
|
||||
collectiblesData := make([]thirdparty.CollectibleData, 0, len(assets))
|
||||
collectionsData := make([]thirdparty.CollectionData, 0, len(assets))
|
||||
missingCollectionIDs := make([]thirdparty.ContractID, 0)
|
||||
|
||||
for _, asset := range assets {
|
||||
for _, asset := range fullyFetchedAssets {
|
||||
id := asset.CollectibleData.ID
|
||||
|
||||
// Get Metadata from alternate source if empty
|
||||
if isMetadataEmpty(asset.CollectibleData) {
|
||||
if o.metadataProvider == nil {
|
||||
return fmt.Errorf("CollectibleMetadataProvider not available")
|
||||
}
|
||||
|
||||
tokenURI := asset.CollectibleData.TokenURI
|
||||
var err error
|
||||
|
||||
if tokenURI == "" {
|
||||
tokenURI, err = o.fetchTokenURI(id)
|
||||
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
asset.CollectibleData.TokenURI = tokenURI
|
||||
}
|
||||
|
||||
canProvide, err := o.metadataProvider.CanProvideCollectibleMetadata(id, tokenURI)
|
||||
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if canProvide {
|
||||
metadata, err := o.metadataProvider.FetchCollectibleMetadata(id, tokenURI)
|
||||
if err != nil {
|
||||
// Metadata is available but fetching failed.
|
||||
// Ideally we would retry, but for now we just skip it.
|
||||
log.Error("Failed to fetch collectible metadata", "err", err)
|
||||
continue
|
||||
}
|
||||
|
||||
if metadata != nil {
|
||||
asset = *metadata
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Get Animation MediaType
|
||||
if len(asset.CollectibleData.AnimationURL) > 0 {
|
||||
contentType, err := o.doContentTypeRequest(asset.CollectibleData.AnimationURL)
|
||||
if err != nil {
|
||||
asset.CollectibleData.AnimationURL = ""
|
||||
}
|
||||
asset.CollectibleData.AnimationMediaType = contentType
|
||||
}
|
||||
|
||||
collectiblesData = append(collectiblesData, asset.CollectibleData)
|
||||
if asset.CollectionData != nil {
|
||||
collectionsData = append(collectionsData, *asset.CollectionData)
|
||||
|
@ -558,6 +565,15 @@ func (o *Manager) processFullCollectibleData(assets []thirdparty.FullCollectible
|
|||
return err
|
||||
}
|
||||
|
||||
for _, asset := range assets {
|
||||
if asset.CommunityInfo != nil {
|
||||
err = o.collectiblesDataDB.SetCommunityInfo(asset.CollectibleData.ID, *asset.CommunityInfo)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
err = o.collectionsDataDB.SetData(collectionsData)
|
||||
if err != nil {
|
||||
return err
|
||||
|
@ -574,6 +590,69 @@ func (o *Manager) processFullCollectibleData(assets []thirdparty.FullCollectible
|
|||
return nil
|
||||
}
|
||||
|
||||
func (o *Manager) fillTokenURI(asset *thirdparty.FullCollectibleData) error {
|
||||
id := asset.CollectibleData.ID
|
||||
|
||||
tokenURI := asset.CollectibleData.TokenURI
|
||||
// Only need to fetch it from contract if it was empty
|
||||
if tokenURI == "" {
|
||||
tokenURI, err := o.fetchTokenURI(id)
|
||||
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
asset.CollectibleData.TokenURI = tokenURI
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (o *Manager) fillCommunityID(asset *thirdparty.FullCollectibleData) error {
|
||||
tokenURI := asset.CollectibleData.TokenURI
|
||||
|
||||
communityID := ""
|
||||
if tokenURI != "" {
|
||||
communityID = o.communityInfoProvider.GetCommunityID(tokenURI)
|
||||
}
|
||||
|
||||
asset.CollectibleData.CommunityID = communityID
|
||||
return nil
|
||||
}
|
||||
|
||||
func (o *Manager) fillCommunityInfo(communityID string, communityAssets []*thirdparty.FullCollectibleData) error {
|
||||
communityInfo, err := o.communityInfoProvider.FetchCommunityInfo(communityID)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if communityInfo != nil {
|
||||
err := o.communityDataDB.SetCommunityInfo(communityID, *communityInfo)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
for _, communityAsset := range communityAssets {
|
||||
err := o.communityInfoProvider.FillCollectibleMetadata(communityAsset)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (o *Manager) fillAnimationMediatype(asset *thirdparty.FullCollectibleData) error {
|
||||
if len(asset.CollectibleData.AnimationURL) > 0 {
|
||||
contentType, err := o.doContentTypeRequest(asset.CollectibleData.AnimationURL)
|
||||
if err != nil {
|
||||
asset.CollectibleData.AnimationURL = ""
|
||||
}
|
||||
asset.CollectibleData.AnimationMediaType = contentType
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (o *Manager) processCollectionData(collections []thirdparty.CollectionData) error {
|
||||
return o.collectionsDataDB.SetData(collections)
|
||||
}
|
||||
|
@ -623,43 +702,6 @@ func (o *Manager) getCacheFullCollectibleData(uniqueIDs []thirdparty.Collectible
|
|||
return ret, nil
|
||||
}
|
||||
|
||||
func (o *Manager) FetchCollectibleCommunityInfo(communityID string, id thirdparty.CollectibleUniqueID) (*thirdparty.CollectiblesCommunityInfo, error) {
|
||||
if o.communityInfoProvider == nil {
|
||||
return nil, fmt.Errorf("CollectibleCommunityInfoProvider not available")
|
||||
}
|
||||
|
||||
return o.communityInfoProvider.FetchCollectibleCommunityInfo(communityID, id)
|
||||
}
|
||||
|
||||
func (o *Manager) FetchCollectibleCommunityTraits(communityID string, id thirdparty.CollectibleUniqueID) ([]thirdparty.CollectibleTrait, error) {
|
||||
if o.communityInfoProvider == nil {
|
||||
return nil, fmt.Errorf("CollectibleCommunityInfoProvider not available")
|
||||
}
|
||||
|
||||
traits, err := o.communityInfoProvider.FetchCollectibleCommunityTraits(communityID, id)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
collectibleIDs := []thirdparty.CollectibleUniqueID{id}
|
||||
|
||||
collectiblesData, err := o.collectiblesDataDB.GetData(collectibleIDs)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if collectible, ok := collectiblesData[id.HashKey()]; ok {
|
||||
collectible.Traits = traits
|
||||
collectiblesData[id.HashKey()] = collectible
|
||||
err = o.collectiblesDataDB.SetData(mapToList(collectiblesData))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
|
||||
return traits, nil
|
||||
}
|
||||
|
||||
// Reset connection status to trigger notifications
|
||||
// on the next status update
|
||||
func (o *Manager) ResetConnectionStatus() {
|
||||
|
|
|
@ -16,6 +16,7 @@ import (
|
|||
|
||||
"github.com/status-im/status-go/services/wallet/async"
|
||||
walletCommon "github.com/status-im/status-go/services/wallet/common"
|
||||
"github.com/status-im/status-go/services/wallet/community"
|
||||
"github.com/status-im/status-go/services/wallet/thirdparty"
|
||||
"github.com/status-im/status-go/services/wallet/walletevent"
|
||||
)
|
||||
|
@ -47,6 +48,7 @@ type Service struct {
|
|||
manager *Manager
|
||||
controller *Controller
|
||||
ownershipDB *OwnershipDB
|
||||
communityDB *community.DataDB
|
||||
walletFeed *event.Feed
|
||||
scheduler *async.MultiClientScheduler
|
||||
}
|
||||
|
@ -63,6 +65,7 @@ func NewService(
|
|||
manager: manager,
|
||||
controller: NewController(db, walletFeed, accountsDB, accountsFeed, settingsFeed, networkManager, manager),
|
||||
ownershipDB: NewOwnershipDB(db),
|
||||
communityDB: community.NewDataDB(db),
|
||||
walletFeed: walletFeed,
|
||||
scheduler: async.NewMultiClientScheduler(),
|
||||
}
|
||||
|
@ -254,12 +257,12 @@ func (s *Service) fullCollectiblesDataToHeaders(data []thirdparty.FullCollectibl
|
|||
header := fullCollectibleDataToHeader(c)
|
||||
|
||||
if c.CollectibleData.CommunityID != "" {
|
||||
communityInfo, err := s.manager.FetchCollectibleCommunityInfo(c.CollectibleData.CommunityID, c.CollectibleData.ID)
|
||||
communityInfo, err := s.communityDB.GetCommunityInfo(c.CollectibleData.CommunityID)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
communityHeader := communityInfoToHeader(*communityInfo)
|
||||
communityHeader := communityInfoToHeader(c.CollectibleData.CommunityID, communityInfo, c.CommunityInfo)
|
||||
header.CommunityHeader = &communityHeader
|
||||
}
|
||||
|
||||
|
@ -276,18 +279,13 @@ func (s *Service) fullCollectiblesDataToDetails(data []thirdparty.FullCollectibl
|
|||
details := fullCollectibleDataToDetails(c)
|
||||
|
||||
if c.CollectibleData.CommunityID != "" {
|
||||
traits, err := s.manager.FetchCollectibleCommunityTraits(c.CollectibleData.CommunityID, c.CollectibleData.ID)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
details.Traits = traits
|
||||
|
||||
communityInfo, err := s.manager.FetchCollectibleCommunityInfo(c.CollectibleData.CommunityID, c.CollectibleData.ID)
|
||||
communityInfo, err := s.communityDB.GetCommunityInfo(c.CollectibleData.CommunityID)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
details.CommunityInfo = communityInfo
|
||||
communityDetails := communityInfoToDetails(c.CollectibleData.CommunityID, communityInfo, c.CommunityInfo)
|
||||
details.CommunityInfo = &communityDetails
|
||||
}
|
||||
|
||||
res = append(res, details)
|
||||
|
|
|
@ -7,18 +7,18 @@ import (
|
|||
|
||||
// Combined Collection+Collectible info, used to display a detailed view of a collectible
|
||||
type CollectibleDetails struct {
|
||||
ID thirdparty.CollectibleUniqueID `json:"id"`
|
||||
Name string `json:"name"`
|
||||
Description string `json:"description"`
|
||||
ImageURL string `json:"image_url"`
|
||||
AnimationURL string `json:"animation_url"`
|
||||
AnimationMediaType string `json:"animation_media_type"`
|
||||
Traits []thirdparty.CollectibleTrait `json:"traits"`
|
||||
BackgroundColor string `json:"background_color"`
|
||||
CollectionName string `json:"collection_name"`
|
||||
CollectionSlug string `json:"collection_slug"`
|
||||
CollectionImageURL string `json:"collection_image_url"`
|
||||
CommunityInfo *thirdparty.CollectiblesCommunityInfo `json:"community_info,omitempty"`
|
||||
ID thirdparty.CollectibleUniqueID `json:"id"`
|
||||
Name string `json:"name"`
|
||||
Description string `json:"description"`
|
||||
ImageURL string `json:"image_url"`
|
||||
AnimationURL string `json:"animation_url"`
|
||||
AnimationMediaType string `json:"animation_media_type"`
|
||||
Traits []thirdparty.CollectibleTrait `json:"traits"`
|
||||
BackgroundColor string `json:"background_color"`
|
||||
CollectionName string `json:"collection_name"`
|
||||
CollectionSlug string `json:"collection_slug"`
|
||||
CollectionImageURL string `json:"collection_image_url"`
|
||||
CommunityInfo *CommunityDetails `json:"community_info,omitempty"`
|
||||
}
|
||||
|
||||
// Combined Collection+Collectible info, used to display a basic view of a collectible in a list
|
||||
|
@ -35,6 +35,14 @@ type CollectibleHeader struct {
|
|||
CommunityHeader *CommunityHeader `json:"community_header,omitempty"`
|
||||
}
|
||||
|
||||
type CommunityDetails struct {
|
||||
CommunityID string `json:"community_id"`
|
||||
CommunityName string `json:"community_name"`
|
||||
CommunityColor string `json:"community_color"`
|
||||
CommunityImage string `json:"community_image"`
|
||||
PrivilegesLevel token.PrivilegesLevel `json:"privileges_level"`
|
||||
}
|
||||
|
||||
type CommunityHeader struct {
|
||||
CommunityID string `json:"community_id"`
|
||||
CommunityName string `json:"community_name"`
|
||||
|
@ -84,11 +92,37 @@ func fullCollectibleDataToDetails(c thirdparty.FullCollectibleData) CollectibleD
|
|||
return ret
|
||||
}
|
||||
|
||||
func communityInfoToHeader(c thirdparty.CollectiblesCommunityInfo) CommunityHeader {
|
||||
return CommunityHeader{
|
||||
CommunityID: c.CommunityID,
|
||||
CommunityName: c.CommunityName,
|
||||
CommunityColor: c.CommunityColor,
|
||||
PrivilegesLevel: c.PrivilegesLevel,
|
||||
func communityInfoToHeader(communityID string, community *thirdparty.CommunityInfo, communityCollectible *thirdparty.CollectibleCommunityInfo) CommunityHeader {
|
||||
ret := CommunityHeader{
|
||||
CommunityID: communityID,
|
||||
}
|
||||
|
||||
if community != nil {
|
||||
ret.CommunityName = community.CommunityName
|
||||
ret.CommunityColor = community.CommunityColor
|
||||
}
|
||||
|
||||
if communityCollectible != nil {
|
||||
ret.PrivilegesLevel = communityCollectible.PrivilegesLevel
|
||||
}
|
||||
|
||||
return ret
|
||||
}
|
||||
|
||||
func communityInfoToDetails(communityID string, community *thirdparty.CommunityInfo, communityCollectible *thirdparty.CollectibleCommunityInfo) CommunityDetails {
|
||||
ret := CommunityDetails{
|
||||
CommunityID: communityID,
|
||||
}
|
||||
|
||||
if community != nil {
|
||||
ret.CommunityName = community.CommunityName
|
||||
ret.CommunityColor = community.CommunityColor
|
||||
ret.CommunityImage = community.CommunityImage
|
||||
}
|
||||
|
||||
if communityCollectible != nil {
|
||||
ret.PrivilegesLevel = communityCollectible.PrivilegesLevel
|
||||
}
|
||||
|
||||
return ret
|
||||
}
|
||||
|
|
|
@ -0,0 +1,77 @@
|
|||
package community
|
||||
|
||||
import (
|
||||
"database/sql"
|
||||
"fmt"
|
||||
|
||||
"github.com/status-im/status-go/services/wallet/thirdparty"
|
||||
)
|
||||
|
||||
type DataDB struct {
|
||||
db *sql.DB
|
||||
}
|
||||
|
||||
func NewDataDB(sqlDb *sql.DB) *DataDB {
|
||||
return &DataDB{
|
||||
db: sqlDb,
|
||||
}
|
||||
}
|
||||
|
||||
const communityDataColumns = "id, name, color, image"
|
||||
const selectCommunityDataColumns = "name, color, image"
|
||||
|
||||
func (o *DataDB) SetCommunityInfo(id string, c thirdparty.CommunityInfo) (err error) {
|
||||
tx, err := o.db.Begin()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer func() {
|
||||
if err == nil {
|
||||
err = tx.Commit()
|
||||
return
|
||||
}
|
||||
_ = tx.Rollback()
|
||||
}()
|
||||
|
||||
update, err := tx.Prepare(fmt.Sprintf(`INSERT OR REPLACE INTO community_data_cache (%s)
|
||||
VALUES (?, ?, ?, ?)`, communityDataColumns))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
_, err = update.Exec(
|
||||
id,
|
||||
c.CommunityName,
|
||||
c.CommunityColor,
|
||||
c.CommunityImage,
|
||||
)
|
||||
|
||||
return err
|
||||
}
|
||||
|
||||
func (o *DataDB) GetCommunityInfo(id string) (*thirdparty.CommunityInfo, error) {
|
||||
var ret thirdparty.CommunityInfo
|
||||
|
||||
getData, err := o.db.Prepare(fmt.Sprintf(`SELECT %s
|
||||
FROM community_data_cache
|
||||
WHERE id=?`, selectCommunityDataColumns))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
row := getData.QueryRow(id)
|
||||
|
||||
err = row.Scan(
|
||||
&ret.CommunityName,
|
||||
&ret.CommunityColor,
|
||||
&ret.CommunityImage,
|
||||
)
|
||||
|
||||
if err == sql.ErrNoRows {
|
||||
return nil, nil
|
||||
} else if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return &ret, nil
|
||||
}
|
|
@ -0,0 +1,52 @@
|
|||
package community
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"testing"
|
||||
|
||||
"github.com/status-im/status-go/services/wallet/thirdparty"
|
||||
"github.com/status-im/status-go/t/helpers"
|
||||
"github.com/status-im/status-go/walletdatabase"
|
||||
|
||||
"github.com/stretchr/testify/require"
|
||||
)
|
||||
|
||||
func setupCommunityDataDBTest(t *testing.T) (*DataDB, func()) {
|
||||
db, err := helpers.SetupTestMemorySQLDB(walletdatabase.DbInitializer{})
|
||||
require.NoError(t, err)
|
||||
return NewDataDB(db), func() {
|
||||
require.NoError(t, db.Close())
|
||||
}
|
||||
}
|
||||
|
||||
func generateTestCommunityInfo(count int) map[string]thirdparty.CommunityInfo {
|
||||
result := make(map[string]thirdparty.CommunityInfo)
|
||||
for i := 0; i < count; i++ {
|
||||
communityID := fmt.Sprintf("communityid-%d", i)
|
||||
newCommunity := thirdparty.CommunityInfo{
|
||||
CommunityName: fmt.Sprintf("communityname-%d", i),
|
||||
CommunityColor: fmt.Sprintf("communitycolor-%d", i),
|
||||
CommunityImage: fmt.Sprintf("communityimage-%d", i),
|
||||
}
|
||||
result[communityID] = newCommunity
|
||||
}
|
||||
|
||||
return result
|
||||
}
|
||||
|
||||
func TestUpdateCommunityInfo(t *testing.T) {
|
||||
db, cleanup := setupCommunityDataDBTest(t)
|
||||
defer cleanup()
|
||||
|
||||
communityData := generateTestCommunityInfo(10)
|
||||
for communityID, communityInfo := range communityData {
|
||||
err := db.SetCommunityInfo(communityID, communityInfo)
|
||||
require.NoError(t, err)
|
||||
}
|
||||
|
||||
for communityID, communityInfo := range communityData {
|
||||
communityInfoFromDB, err := db.GetCommunityInfo(communityID)
|
||||
require.NoError(t, err)
|
||||
require.Equal(t, communityInfo, *communityInfoFromDB)
|
||||
}
|
||||
}
|
|
@ -209,11 +209,6 @@ func (s *Service) Start() error {
|
|||
return err
|
||||
}
|
||||
|
||||
// Set external Collectibles metadata provider
|
||||
func (s *Service) SetCollectibleMetadataProvider(provider thirdparty.CollectibleMetadataProvider) {
|
||||
s.collectiblesManager.SetMetadataProvider(provider)
|
||||
}
|
||||
|
||||
// Set external Collectibles community info provider
|
||||
func (s *Service) SetCollectibleCommunityInfoProvider(provider thirdparty.CollectibleCommunityInfoProvider) {
|
||||
s.collectiblesManager.SetCommunityInfoProvider(provider)
|
||||
|
|
|
@ -134,11 +134,17 @@ type CollectibleData struct {
|
|||
TokenURI string `json:"token_uri"`
|
||||
}
|
||||
|
||||
// Community-related collectible info. Present only for collectibles minted in a community.
|
||||
type CollectibleCommunityInfo struct {
|
||||
PrivilegesLevel token.PrivilegesLevel `json:"privileges_level"`
|
||||
}
|
||||
|
||||
// Combined Collection+Collectible info returned by the CollectibleProvider
|
||||
// Some providers may not return the CollectionData in the same API call, so it's optional
|
||||
type FullCollectibleData struct {
|
||||
CollectibleData CollectibleData
|
||||
CollectionData *CollectionData
|
||||
CommunityInfo *CollectibleCommunityInfo
|
||||
}
|
||||
|
||||
type CollectiblesContainer[T any] struct {
|
||||
|
@ -171,28 +177,6 @@ func (c *FullCollectibleDataContainer) ToOwnershipContainer() CollectibleOwnersh
|
|||
}
|
||||
}
|
||||
|
||||
// Community-related info. Present only for collectibles minted in a community.
|
||||
// This info is directly fetched every time upon request since a change in community
|
||||
// settings could affect it.
|
||||
|
||||
type CollectiblesCommunityInfo struct {
|
||||
CommunityID string `json:"community_id"`
|
||||
CommunityName string `json:"community_name"`
|
||||
CommunityColor string `json:"community_color"`
|
||||
CommunityImage string `json:"community_image"`
|
||||
PrivilegesLevel token.PrivilegesLevel `json:"privileges_level"`
|
||||
}
|
||||
|
||||
type CollectibleMetadataProvider interface {
|
||||
CanProvideCollectibleMetadata(id CollectibleUniqueID, tokenURI string) (bool, error)
|
||||
FetchCollectibleMetadata(id CollectibleUniqueID, tokenURI string) (*FullCollectibleData, error)
|
||||
}
|
||||
|
||||
type CollectibleCommunityInfoProvider interface {
|
||||
FetchCollectibleCommunityInfo(communityID string, id CollectibleUniqueID) (*CollectiblesCommunityInfo, error)
|
||||
FetchCollectibleCommunityTraits(communityID string, id CollectibleUniqueID) ([]CollectibleTrait, error)
|
||||
}
|
||||
|
||||
type TokenBalance struct {
|
||||
TokenID *bigint.BigInt `json:"tokenId"`
|
||||
Balance *bigint.BigInt `json:"balance"`
|
||||
|
@ -230,3 +214,8 @@ type CollectionDataProvider interface {
|
|||
CollectibleProvider
|
||||
FetchCollectionsDataByContractID(ids []ContractID) ([]CollectionData, error)
|
||||
}
|
||||
|
||||
type CollectibleCommunityInfoProvider interface {
|
||||
CommunityInfoProvider
|
||||
FillCollectibleMetadata(collectible *FullCollectibleData) error
|
||||
}
|
||||
|
|
|
@ -0,0 +1,13 @@
|
|||
package thirdparty
|
||||
|
||||
// Community-related info used by the wallet, cached in the wallet db.
|
||||
type CommunityInfo struct {
|
||||
CommunityName string `json:"community_name"`
|
||||
CommunityColor string `json:"community_color"`
|
||||
CommunityImage string `json:"community_image"`
|
||||
}
|
||||
|
||||
type CommunityInfoProvider interface {
|
||||
GetCommunityID(tokenURI string) string
|
||||
FetchCommunityInfo(communityID string) (*CommunityInfo, error)
|
||||
}
|
|
@ -9,6 +9,7 @@
|
|||
// 1695932536_balance_history_v2.up.sql (653B)
|
||||
// 1696853635_input_data.up.sql (23.14kB)
|
||||
// 1698117918_add_community_id_to_tokens.up.sql (61B)
|
||||
// 1698257443_add_community_metadata_to_wallet_db.up.sql (323B)
|
||||
// doc.go (74B)
|
||||
|
||||
package migrations
|
||||
|
@ -19,7 +20,6 @@ import (
|
|||
"crypto/sha256"
|
||||
"fmt"
|
||||
"io"
|
||||
"io/ioutil"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
|
@ -29,7 +29,7 @@ import (
|
|||
func bindataRead(data []byte, name string) ([]byte, error) {
|
||||
gz, err := gzip.NewReader(bytes.NewBuffer(data))
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("read %q: %v", name, err)
|
||||
return nil, fmt.Errorf("read %q: %w", name, err)
|
||||
}
|
||||
|
||||
var buf bytes.Buffer
|
||||
|
@ -37,7 +37,7 @@ func bindataRead(data []byte, name string) ([]byte, error) {
|
|||
clErr := gz.Close()
|
||||
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("read %q: %v", name, err)
|
||||
return nil, fmt.Errorf("read %q: %w", name, err)
|
||||
}
|
||||
if clErr != nil {
|
||||
return nil, err
|
||||
|
@ -93,7 +93,7 @@ func _1691753758_initialUpSql() (*asset, error) {
|
|||
return nil, err
|
||||
}
|
||||
|
||||
info := bindataFileInfo{name: "1691753758_initial.up.sql", size: 5738, mode: os.FileMode(0644), modTime: time.Unix(1697447579, 0)}
|
||||
info := bindataFileInfo{name: "1691753758_initial.up.sql", size: 5738, mode: os.FileMode(0644), modTime: time.Unix(1698249648, 0)}
|
||||
a := &asset{bytes: bytes, info: info, digest: [32]uint8{0x6b, 0x25, 0x31, 0xc8, 0x27, 0x3, 0x6b, 0x9f, 0x15, 0x42, 0x2f, 0x85, 0xfb, 0xe3, 0x6, 0xea, 0xf7, 0x97, 0x12, 0x56, 0x3c, 0x9a, 0x5b, 0x1a, 0xca, 0xb1, 0x23, 0xfa, 0xcd, 0x57, 0x25, 0x5c}}
|
||||
return a, nil
|
||||
}
|
||||
|
@ -113,7 +113,7 @@ func _1692701329_add_collectibles_and_collections_data_cacheUpSql() (*asset, err
|
|||
return nil, err
|
||||
}
|
||||
|
||||
info := bindataFileInfo{name: "1692701329_add_collectibles_and_collections_data_cache.up.sql", size: 1808, mode: os.FileMode(0644), modTime: time.Unix(1697447579, 0)}
|
||||
info := bindataFileInfo{name: "1692701329_add_collectibles_and_collections_data_cache.up.sql", size: 1808, mode: os.FileMode(0644), modTime: time.Unix(1698249648, 0)}
|
||||
a := &asset{bytes: bytes, info: info, digest: [32]uint8{0x1, 0x51, 0xf4, 0x2b, 0x92, 0xde, 0x59, 0x65, 0xd8, 0x9b, 0x57, 0xe0, 0xfd, 0x7b, 0x12, 0xb, 0x29, 0x6e, 0x9d, 0xb5, 0x90, 0xe, 0xfa, 0x12, 0x97, 0xd, 0x61, 0x60, 0x7f, 0x32, 0x1d, 0xc3}}
|
||||
return a, nil
|
||||
}
|
||||
|
@ -133,7 +133,7 @@ func _1692701339_add_scope_to_pendingUpSql() (*asset, error) {
|
|||
return nil, err
|
||||
}
|
||||
|
||||
info := bindataFileInfo{name: "1692701339_add_scope_to_pending.up.sql", size: 576, mode: os.FileMode(0644), modTime: time.Unix(1697447579, 0)}
|
||||
info := bindataFileInfo{name: "1692701339_add_scope_to_pending.up.sql", size: 576, mode: os.FileMode(0644), modTime: time.Unix(1698249648, 0)}
|
||||
a := &asset{bytes: bytes, info: info, digest: [32]uint8{0x36, 0x8a, 0x5e, 0xe2, 0x63, 0x15, 0x37, 0xba, 0x55, 0x18, 0xf3, 0xcc, 0xe0, 0x5, 0x84, 0xe1, 0x5b, 0xe8, 0x1, 0x32, 0x6b, 0x9f, 0x7d, 0x9f, 0xd9, 0x23, 0x6c, 0xa9, 0xb5, 0xdc, 0xf4, 0x93}}
|
||||
return a, nil
|
||||
}
|
||||
|
@ -153,7 +153,7 @@ func _1694540071_add_collectibles_ownership_update_timestampUpSql() (*asset, err
|
|||
return nil, err
|
||||
}
|
||||
|
||||
info := bindataFileInfo{name: "1694540071_add_collectibles_ownership_update_timestamp.up.sql", size: 349, mode: os.FileMode(0644), modTime: time.Unix(1697447579, 0)}
|
||||
info := bindataFileInfo{name: "1694540071_add_collectibles_ownership_update_timestamp.up.sql", size: 349, mode: os.FileMode(0644), modTime: time.Unix(1698249648, 0)}
|
||||
a := &asset{bytes: bytes, info: info, digest: [32]uint8{0x7f, 0x45, 0xc7, 0xce, 0x79, 0x63, 0xbc, 0x6f, 0x83, 0x5f, 0xe2, 0x3, 0x56, 0xcc, 0x5, 0x2f, 0x85, 0xda, 0x7e, 0xea, 0xf5, 0xd2, 0xac, 0x19, 0xd4, 0xd8, 0x5e, 0xdd, 0xed, 0xe2, 0xa9, 0x97}}
|
||||
return a, nil
|
||||
}
|
||||
|
@ -173,7 +173,7 @@ func _1694692748_add_raw_balance_to_token_balancesUpSql() (*asset, error) {
|
|||
return nil, err
|
||||
}
|
||||
|
||||
info := bindataFileInfo{name: "1694692748_add_raw_balance_to_token_balances.up.sql", size: 165, mode: os.FileMode(0644), modTime: time.Unix(1697447579, 0)}
|
||||
info := bindataFileInfo{name: "1694692748_add_raw_balance_to_token_balances.up.sql", size: 165, mode: os.FileMode(0644), modTime: time.Unix(1698249648, 0)}
|
||||
a := &asset{bytes: bytes, info: info, digest: [32]uint8{0xd4, 0xe0, 0x5b, 0x42, 0xf0, 0x96, 0xa5, 0xf5, 0xed, 0xc0, 0x97, 0x88, 0xb0, 0x6d, 0xfe, 0x7d, 0x97, 0x2e, 0x17, 0xd2, 0x16, 0xbc, 0x2a, 0xf2, 0xcc, 0x67, 0x9e, 0xc5, 0x47, 0xf6, 0x69, 0x1}}
|
||||
return a, nil
|
||||
}
|
||||
|
@ -193,7 +193,7 @@ func _1695133989_add_community_id_to_collectibles_and_collections_data_cacheUpSq
|
|||
return nil, err
|
||||
}
|
||||
|
||||
info := bindataFileInfo{name: "1695133989_add_community_id_to_collectibles_and_collections_data_cache.up.sql", size: 275, mode: os.FileMode(0644), modTime: time.Unix(1697447579, 0)}
|
||||
info := bindataFileInfo{name: "1695133989_add_community_id_to_collectibles_and_collections_data_cache.up.sql", size: 275, mode: os.FileMode(0644), modTime: time.Unix(1698249648, 0)}
|
||||
a := &asset{bytes: bytes, info: info, digest: [32]uint8{0xfa, 0x2, 0xa, 0x7f, 0x4b, 0xd1, 0x3, 0xd0, 0x3, 0x29, 0x84, 0x31, 0xed, 0x49, 0x4f, 0xb1, 0x2d, 0xd7, 0x80, 0x41, 0x5b, 0xfa, 0x6, 0xae, 0xb4, 0xf6, 0x6b, 0x49, 0xee, 0x57, 0x33, 0x76}}
|
||||
return a, nil
|
||||
}
|
||||
|
@ -213,7 +213,7 @@ func _1695932536_balance_history_v2UpSql() (*asset, error) {
|
|||
return nil, err
|
||||
}
|
||||
|
||||
info := bindataFileInfo{name: "1695932536_balance_history_v2.up.sql", size: 653, mode: os.FileMode(0644), modTime: time.Unix(1697447579, 0)}
|
||||
info := bindataFileInfo{name: "1695932536_balance_history_v2.up.sql", size: 653, mode: os.FileMode(0644), modTime: time.Unix(1698249648, 0)}
|
||||
a := &asset{bytes: bytes, info: info, digest: [32]uint8{0x37, 0xf4, 0x14, 0x91, 0xf6, 0x5f, 0xc4, 0x9b, 0xb7, 0x83, 0x32, 0x72, 0xbe, 0x82, 0x42, 0x39, 0xa4, 0x3b, 0xc9, 0x78, 0x3d, 0xca, 0xd4, 0xbf, 0xfc, 0x7a, 0x33, 0x1e, 0xcd, 0x9e, 0xe4, 0x85}}
|
||||
return a, nil
|
||||
}
|
||||
|
@ -233,7 +233,7 @@ func _1696853635_input_dataUpSql() (*asset, error) {
|
|||
return nil, err
|
||||
}
|
||||
|
||||
info := bindataFileInfo{name: "1696853635_input_data.up.sql", size: 23140, mode: os.FileMode(0644), modTime: time.Unix(1697447579, 0)}
|
||||
info := bindataFileInfo{name: "1696853635_input_data.up.sql", size: 23140, mode: os.FileMode(0644), modTime: time.Unix(1698249648, 0)}
|
||||
a := &asset{bytes: bytes, info: info, digest: [32]uint8{0x89, 0x30, 0x33, 0x33, 0x55, 0xc5, 0x57, 0x2b, 0xaf, 0xef, 0x3d, 0x8d, 0x2a, 0xaa, 0x5c, 0x32, 0xd1, 0xf4, 0xd, 0x4a, 0xd0, 0x33, 0x4a, 0xe8, 0xf6, 0x8, 0x6b, 0x65, 0xcc, 0xba, 0xed, 0x42}}
|
||||
return a, nil
|
||||
}
|
||||
|
@ -253,11 +253,31 @@ func _1698117918_add_community_id_to_tokensUpSql() (*asset, error) {
|
|||
return nil, err
|
||||
}
|
||||
|
||||
info := bindataFileInfo{name: "1698117918_add_community_id_to_tokens.up.sql", size: 61, mode: os.FileMode(0644), modTime: time.Unix(1698290254, 0)}
|
||||
info := bindataFileInfo{name: "1698117918_add_community_id_to_tokens.up.sql", size: 61, mode: os.FileMode(0644), modTime: time.Unix(1698257400, 0)}
|
||||
a := &asset{bytes: bytes, info: info, digest: [32]uint8{0xb3, 0x82, 0xdb, 0xde, 0x3, 0x3, 0xc, 0x67, 0xf3, 0x54, 0xc4, 0xad, 0xd6, 0xce, 0x56, 0xfb, 0xc1, 0x87, 0xd7, 0xda, 0xab, 0xec, 0x1, 0xe1, 0x7d, 0xb3, 0x63, 0xd6, 0xe5, 0x5d, 0x1c, 0x15}}
|
||||
return a, nil
|
||||
}
|
||||
|
||||
var __1698257443_add_community_metadata_to_wallet_dbUpSql = []byte("\x1f\x8b\x08\x00\x00\x00\x00\x00\x00\xff\x6c\x8e\xc1\x4e\xc3\x30\x10\x44\xef\xfe\x8a\x39\x82\x44\xbe\xa0\xa7\xd0\x18\x88\x48\x1d\x94\x38\x52\x7b\xb2\x8c\xbd\x14\x4b\xeb\x38\x6a\xdc\x4a\xf9\x7b\x44\xa9\x44\x41\xbd\xee\xce\x9b\x37\x45\x81\x76\xe4\x05\x53\x9a\x8e\x6c\x33\x79\x84\x0f\xb8\x14\xe3\x71\xcc\x8b\x09\x1e\x61\xc6\x98\x32\x28\x4e\x79\x11\x65\xa3\x65\x07\x5d\x3e\x36\x12\x2e\x31\x93\xcb\xe1\x9d\xc9\x78\x9b\xad\x71\xd6\x7d\x12\xca\xaa\xc2\xba\x6d\x86\x8d\xba\xd4\x84\xbc\x98\xe9\x10\x4e\x81\x69\x4f\xb3\x61\x3a\x11\x63\x50\x7d\xfd\xac\x64\x85\x5a\xe9\x95\x10\x45\x81\x97\xc4\x7e\xfe\x45\x80\x48\xd9\x7e\xf7\x8a\x75\x27\x4b\x2d\x2f\xd6\xfa\x09\xaa\xd5\x90\xdb\xba\xd7\xfd\x95\xe1\x6a\xc1\x9d\x00\x80\xe0\xa1\xe5\x56\xe3\xad\xab\x37\x65\xb7\xc3\xab\xdc\x9d\x49\x35\x34\xcd\xc3\x39\x31\xda\x48\x3f\x99\xbf\x77\x97\x38\x1d\x6e\x3d\x42\xb4\xfb\x7f\x84\xb8\x5f\x89\xaf\x00\x00\x00\xff\xff\x54\x75\x5f\xc6\x43\x01\x00\x00")
|
||||
|
||||
func _1698257443_add_community_metadata_to_wallet_dbUpSqlBytes() ([]byte, error) {
|
||||
return bindataRead(
|
||||
__1698257443_add_community_metadata_to_wallet_dbUpSql,
|
||||
"1698257443_add_community_metadata_to_wallet_db.up.sql",
|
||||
)
|
||||
}
|
||||
|
||||
func _1698257443_add_community_metadata_to_wallet_dbUpSql() (*asset, error) {
|
||||
bytes, err := _1698257443_add_community_metadata_to_wallet_dbUpSqlBytes()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
info := bindataFileInfo{name: "1698257443_add_community_metadata_to_wallet_db.up.sql", size: 323, mode: os.FileMode(0644), modTime: time.Unix(1698301583, 0)}
|
||||
a := &asset{bytes: bytes, info: info, digest: [32]uint8{0x22, 0xd3, 0x4, 0x25, 0xfa, 0x23, 0x1, 0x48, 0x83, 0x26, 0x20, 0xf2, 0x3d, 0xbc, 0xc1, 0xa7, 0x7c, 0x27, 0x7c, 0x1d, 0x63, 0x3, 0xa, 0xd0, 0xce, 0x47, 0x86, 0xdc, 0xa1, 0x3c, 0x2, 0x1c}}
|
||||
return a, nil
|
||||
}
|
||||
|
||||
var _docGo = []byte("\x1f\x8b\x08\x00\x00\x00\x00\x00\x00\xff\x2c\xc9\xb1\x0d\xc4\x20\x0c\x05\xd0\x9e\x29\xfe\x02\xd8\xfd\x6d\xe3\x4b\xac\x2f\x44\x82\x09\x78\x7f\xa5\x49\xfd\xa6\x1d\xdd\xe8\xd8\xcf\x55\x8a\x2a\xe3\x47\x1f\xbe\x2c\x1d\x8c\xfa\x6f\xe3\xb4\x34\xd4\xd9\x89\xbb\x71\x59\xb6\x18\x1b\x35\x20\xa2\x9f\x0a\x03\xa2\xe5\x0d\x00\x00\xff\xff\x60\xcd\x06\xbe\x4a\x00\x00\x00")
|
||||
|
||||
func docGoBytes() ([]byte, error) {
|
||||
|
@ -273,7 +293,7 @@ func docGo() (*asset, error) {
|
|||
return nil, err
|
||||
}
|
||||
|
||||
info := bindataFileInfo{name: "doc.go", size: 74, mode: os.FileMode(0644), modTime: time.Unix(1697447579, 0)}
|
||||
info := bindataFileInfo{name: "doc.go", size: 74, mode: os.FileMode(0644), modTime: time.Unix(1698249648, 0)}
|
||||
a := &asset{bytes: bytes, info: info, digest: [32]uint8{0xde, 0x7c, 0x28, 0xcd, 0x47, 0xf2, 0xfa, 0x7c, 0x51, 0x2d, 0xd8, 0x38, 0xb, 0xb0, 0x34, 0x9d, 0x4c, 0x62, 0xa, 0x9e, 0x28, 0xc3, 0x31, 0x23, 0xd9, 0xbb, 0x89, 0x9f, 0xa0, 0x89, 0x1f, 0xe8}}
|
||||
return a, nil
|
||||
}
|
||||
|
@ -369,36 +389,33 @@ func AssetNames() []string {
|
|||
|
||||
// _bindata is a table, holding each asset generator, mapped to its name.
|
||||
var _bindata = map[string]func() (*asset, error){
|
||||
"1691753758_initial.up.sql": _1691753758_initialUpSql,
|
||||
|
||||
"1692701329_add_collectibles_and_collections_data_cache.up.sql": _1692701329_add_collectibles_and_collections_data_cacheUpSql,
|
||||
|
||||
"1692701339_add_scope_to_pending.up.sql": _1692701339_add_scope_to_pendingUpSql,
|
||||
|
||||
"1694540071_add_collectibles_ownership_update_timestamp.up.sql": _1694540071_add_collectibles_ownership_update_timestampUpSql,
|
||||
|
||||
"1694692748_add_raw_balance_to_token_balances.up.sql": _1694692748_add_raw_balance_to_token_balancesUpSql,
|
||||
|
||||
"1691753758_initial.up.sql": _1691753758_initialUpSql,
|
||||
"1692701329_add_collectibles_and_collections_data_cache.up.sql": _1692701329_add_collectibles_and_collections_data_cacheUpSql,
|
||||
"1692701339_add_scope_to_pending.up.sql": _1692701339_add_scope_to_pendingUpSql,
|
||||
"1694540071_add_collectibles_ownership_update_timestamp.up.sql": _1694540071_add_collectibles_ownership_update_timestampUpSql,
|
||||
"1694692748_add_raw_balance_to_token_balances.up.sql": _1694692748_add_raw_balance_to_token_balancesUpSql,
|
||||
"1695133989_add_community_id_to_collectibles_and_collections_data_cache.up.sql": _1695133989_add_community_id_to_collectibles_and_collections_data_cacheUpSql,
|
||||
|
||||
"1695932536_balance_history_v2.up.sql": _1695932536_balance_history_v2UpSql,
|
||||
|
||||
"1696853635_input_data.up.sql": _1696853635_input_dataUpSql,
|
||||
|
||||
"1698117918_add_community_id_to_tokens.up.sql": _1698117918_add_community_id_to_tokensUpSql,
|
||||
|
||||
"1695932536_balance_history_v2.up.sql": _1695932536_balance_history_v2UpSql,
|
||||
"1696853635_input_data.up.sql": _1696853635_input_dataUpSql,
|
||||
"1698117918_add_community_id_to_tokens.up.sql": _1698117918_add_community_id_to_tokensUpSql,
|
||||
"1698257443_add_community_metadata_to_wallet_db.up.sql": _1698257443_add_community_metadata_to_wallet_dbUpSql,
|
||||
"doc.go": docGo,
|
||||
}
|
||||
|
||||
// AssetDebug is true if the assets were built with the debug flag enabled.
|
||||
const AssetDebug = false
|
||||
|
||||
// AssetDir returns the file names below a certain
|
||||
// directory embedded in the file by go-bindata.
|
||||
// For example if you run go-bindata on data/... and data contains the
|
||||
// following hierarchy:
|
||||
// data/
|
||||
// foo.txt
|
||||
// img/
|
||||
// a.png
|
||||
// b.png
|
||||
//
|
||||
// data/
|
||||
// foo.txt
|
||||
// img/
|
||||
// a.png
|
||||
// b.png
|
||||
//
|
||||
// then AssetDir("data") would return []string{"foo.txt", "img"},
|
||||
// AssetDir("data/img") would return []string{"a.png", "b.png"},
|
||||
// AssetDir("foo.txt") and AssetDir("notexist") would return an error, and
|
||||
|
@ -431,16 +448,17 @@ type bintree struct {
|
|||
}
|
||||
|
||||
var _bintree = &bintree{nil, map[string]*bintree{
|
||||
"1691753758_initial.up.sql": &bintree{_1691753758_initialUpSql, map[string]*bintree{}},
|
||||
"1692701329_add_collectibles_and_collections_data_cache.up.sql": &bintree{_1692701329_add_collectibles_and_collections_data_cacheUpSql, map[string]*bintree{}},
|
||||
"1692701339_add_scope_to_pending.up.sql": &bintree{_1692701339_add_scope_to_pendingUpSql, map[string]*bintree{}},
|
||||
"1694540071_add_collectibles_ownership_update_timestamp.up.sql": &bintree{_1694540071_add_collectibles_ownership_update_timestampUpSql, map[string]*bintree{}},
|
||||
"1694692748_add_raw_balance_to_token_balances.up.sql": &bintree{_1694692748_add_raw_balance_to_token_balancesUpSql, map[string]*bintree{}},
|
||||
"1695133989_add_community_id_to_collectibles_and_collections_data_cache.up.sql": &bintree{_1695133989_add_community_id_to_collectibles_and_collections_data_cacheUpSql, map[string]*bintree{}},
|
||||
"1695932536_balance_history_v2.up.sql": &bintree{_1695932536_balance_history_v2UpSql, map[string]*bintree{}},
|
||||
"1696853635_input_data.up.sql": &bintree{_1696853635_input_dataUpSql, map[string]*bintree{}},
|
||||
"1698117918_add_community_id_to_tokens.up.sql": &bintree{_1698117918_add_community_id_to_tokensUpSql, map[string]*bintree{}},
|
||||
"doc.go": &bintree{docGo, map[string]*bintree{}},
|
||||
"1691753758_initial.up.sql": {_1691753758_initialUpSql, map[string]*bintree{}},
|
||||
"1692701329_add_collectibles_and_collections_data_cache.up.sql": {_1692701329_add_collectibles_and_collections_data_cacheUpSql, map[string]*bintree{}},
|
||||
"1692701339_add_scope_to_pending.up.sql": {_1692701339_add_scope_to_pendingUpSql, map[string]*bintree{}},
|
||||
"1694540071_add_collectibles_ownership_update_timestamp.up.sql": {_1694540071_add_collectibles_ownership_update_timestampUpSql, map[string]*bintree{}},
|
||||
"1694692748_add_raw_balance_to_token_balances.up.sql": {_1694692748_add_raw_balance_to_token_balancesUpSql, map[string]*bintree{}},
|
||||
"1695133989_add_community_id_to_collectibles_and_collections_data_cache.up.sql": {_1695133989_add_community_id_to_collectibles_and_collections_data_cacheUpSql, map[string]*bintree{}},
|
||||
"1695932536_balance_history_v2.up.sql": {_1695932536_balance_history_v2UpSql, map[string]*bintree{}},
|
||||
"1696853635_input_data.up.sql": {_1696853635_input_dataUpSql, map[string]*bintree{}},
|
||||
"1698117918_add_community_id_to_tokens.up.sql": {_1698117918_add_community_id_to_tokensUpSql, map[string]*bintree{}},
|
||||
"1698257443_add_community_metadata_to_wallet_db.up.sql": {_1698257443_add_community_metadata_to_wallet_dbUpSql, map[string]*bintree{}},
|
||||
"doc.go": {docGo, map[string]*bintree{}},
|
||||
}}
|
||||
|
||||
// RestoreAsset restores an asset under the given directory.
|
||||
|
@ -457,7 +475,7 @@ func RestoreAsset(dir, name string) error {
|
|||
if err != nil {
|
||||
return err
|
||||
}
|
||||
err = ioutil.WriteFile(_filePath(dir, name), data, info.Mode())
|
||||
err = os.WriteFile(_filePath(dir, name), data, info.Mode())
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
|
|
@ -0,0 +1,10 @@
|
|||
-- Only populated if communty_id is not empty
|
||||
ALTER TABLE collectible_data_cache ADD COLUMN community_privileges_level UNSIGNED INT;
|
||||
|
||||
-- Holds community metadata
|
||||
CREATE TABLE IF NOT EXISTS community_data_cache (
|
||||
id TEXT PRIMARY KEY NOT NULL,
|
||||
name TEXT NOT NULL,
|
||||
color TEXT NOT NULL,
|
||||
image TEXT NOT NULL
|
||||
);
|
Loading…
Reference in New Issue