feat(wallet): add community info to collectibles
This commit is contained in:
parent
2b53d71708
commit
ba5cd9c1a4
|
@ -122,6 +122,7 @@ func (b *StatusNode) initServices(config *params.NodeConfig, mediaServer *server
|
||||||
services = append(services, wakuext)
|
services = append(services, wakuext)
|
||||||
|
|
||||||
b.SetWalletCollectibleMetadataProvider(wakuext)
|
b.SetWalletCollectibleMetadataProvider(wakuext)
|
||||||
|
b.SetWalletCollectibleCommunityInfoProvider(wakuext)
|
||||||
}
|
}
|
||||||
|
|
||||||
if config.WakuV2Config.Enabled {
|
if config.WakuV2Config.Enabled {
|
||||||
|
@ -149,6 +150,7 @@ func (b *StatusNode) initServices(config *params.NodeConfig, mediaServer *server
|
||||||
services = append(services, wakuext)
|
services = append(services, wakuext)
|
||||||
|
|
||||||
b.SetWalletCollectibleMetadataProvider(wakuext)
|
b.SetWalletCollectibleMetadataProvider(wakuext)
|
||||||
|
b.SetWalletCollectibleCommunityInfoProvider(wakuext)
|
||||||
}
|
}
|
||||||
|
|
||||||
// We ignore for now local notifications flag as users who are upgrading have no mean to enable it
|
// We ignore for now local notifications flag as users who are upgrading have no mean to enable it
|
||||||
|
@ -503,6 +505,12 @@ func (b *StatusNode) SetWalletCollectibleMetadataProvider(provider thirdparty.Co
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (b *StatusNode) SetWalletCollectibleCommunityInfoProvider(provider thirdparty.CollectibleCommunityInfoProvider) {
|
||||||
|
if b.walletSrvc != nil {
|
||||||
|
b.walletSrvc.SetCollectibleCommunityInfoProvider(provider)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func (b *StatusNode) walletService(accountsDB *accounts.Database, accountsFeed *event.Feed, walletFeed *event.Feed) *wallet.Service {
|
func (b *StatusNode) walletService(accountsDB *accounts.Database, accountsFeed *event.Feed, walletFeed *event.Feed) *wallet.Service {
|
||||||
if b.walletSrvc == nil {
|
if b.walletSrvc == nil {
|
||||||
b.walletSrvc = wallet.NewService(
|
b.walletSrvc = wallet.NewService(
|
||||||
|
|
|
@ -4601,55 +4601,64 @@ func (m *Manager) HandleCommunityTokensMetadata(community *Community) error {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
if !exists {
|
if !exists {
|
||||||
communityToken := &community_token.CommunityToken{
|
// Fetch community token to make sure it's stored in the DB, discard result
|
||||||
CommunityID: communityID,
|
communityToken, err := m.FetchCommunityToken(community, tokenMetadata, chainID, address)
|
||||||
Address: address,
|
|
||||||
TokenType: tokenMetadata.TokenType,
|
|
||||||
Name: tokenMetadata.Name,
|
|
||||||
Symbol: tokenMetadata.Symbol,
|
|
||||||
Description: tokenMetadata.Description,
|
|
||||||
Transferable: true,
|
|
||||||
RemoteSelfDestruct: false,
|
|
||||||
ChainID: int(chainID),
|
|
||||||
DeployState: community_token.Deployed,
|
|
||||||
Base64Image: tokenMetadata.Image,
|
|
||||||
Decimals: int(tokenMetadata.Decimals),
|
|
||||||
}
|
|
||||||
|
|
||||||
switch tokenMetadata.TokenType {
|
|
||||||
case protobuf.CommunityTokenType_ERC721:
|
|
||||||
contractData, err := m.communityTokensService.GetCollectibleContractData(chainID, address)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
communityToken.Supply = contractData.TotalSupply
|
|
||||||
communityToken.Transferable = contractData.Transferable
|
|
||||||
communityToken.RemoteSelfDestruct = contractData.RemoteBurnable
|
|
||||||
communityToken.InfiniteSupply = contractData.InfiniteSupply
|
|
||||||
|
|
||||||
case protobuf.CommunityTokenType_ERC20:
|
|
||||||
contractData, err := m.communityTokensService.GetAssetContractData(chainID, address)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
communityToken.Supply = contractData.TotalSupply
|
|
||||||
communityToken.InfiniteSupply = contractData.InfiniteSupply
|
|
||||||
}
|
|
||||||
|
|
||||||
communityToken.PrivilegesLevel = getPrivilegesLevel(chainID, address, community.TokenPermissions())
|
|
||||||
|
|
||||||
err = m.persistence.AddCommunityToken(communityToken)
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return m.persistence.AddCommunityToken(communityToken)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (m *Manager) FetchCommunityToken(community *Community, tokenMetadata *protobuf.CommunityTokenMetadata, chainID uint64, contractAddress string) (*community_token.CommunityToken, error) {
|
||||||
|
communityID := community.IDString()
|
||||||
|
|
||||||
|
communityToken := &community_token.CommunityToken{
|
||||||
|
CommunityID: communityID,
|
||||||
|
Address: contractAddress,
|
||||||
|
TokenType: tokenMetadata.TokenType,
|
||||||
|
Name: tokenMetadata.Name,
|
||||||
|
Symbol: tokenMetadata.Symbol,
|
||||||
|
Description: tokenMetadata.Description,
|
||||||
|
Transferable: true,
|
||||||
|
RemoteSelfDestruct: false,
|
||||||
|
ChainID: int(chainID),
|
||||||
|
DeployState: community_token.Deployed,
|
||||||
|
Base64Image: tokenMetadata.Image,
|
||||||
|
Decimals: int(tokenMetadata.Decimals),
|
||||||
|
}
|
||||||
|
|
||||||
|
switch tokenMetadata.TokenType {
|
||||||
|
case protobuf.CommunityTokenType_ERC721:
|
||||||
|
contractData, err := m.communityTokensService.GetCollectibleContractData(chainID, contractAddress)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
communityToken.Supply = contractData.TotalSupply
|
||||||
|
communityToken.Transferable = contractData.Transferable
|
||||||
|
communityToken.RemoteSelfDestruct = contractData.RemoteBurnable
|
||||||
|
communityToken.InfiniteSupply = contractData.InfiniteSupply
|
||||||
|
|
||||||
|
case protobuf.CommunityTokenType_ERC20:
|
||||||
|
contractData, err := m.communityTokensService.GetAssetContractData(chainID, contractAddress)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
communityToken.Supply = contractData.TotalSupply
|
||||||
|
communityToken.InfiniteSupply = contractData.InfiniteSupply
|
||||||
|
}
|
||||||
|
|
||||||
|
communityToken.PrivilegesLevel = getPrivilegesLevel(chainID, contractAddress, community.TokenPermissions())
|
||||||
|
|
||||||
|
return communityToken, nil
|
||||||
|
}
|
||||||
|
|
||||||
func getPrivilegesLevel(chainID uint64, tokenAddress string, tokenPermissions map[string]*CommunityTokenPermission) community_token.PrivilegesLevel {
|
func getPrivilegesLevel(chainID uint64, tokenAddress string, tokenPermissions map[string]*CommunityTokenPermission) community_token.PrivilegesLevel {
|
||||||
for _, permission := range tokenPermissions {
|
for _, permission := range tokenPermissions {
|
||||||
if permission.Type == protobuf.CommunityTokenPermission_BECOME_TOKEN_MASTER || permission.Type == protobuf.CommunityTokenPermission_BECOME_TOKEN_OWNER {
|
if permission.Type == protobuf.CommunityTokenPermission_BECOME_TOKEN_MASTER || permission.Type == protobuf.CommunityTokenPermission_BECOME_TOKEN_OWNER {
|
||||||
|
|
|
@ -4492,6 +4492,10 @@ func (m *Messenger) chatMessagesToWakuMessages(chatMessages []*common.Message, c
|
||||||
return wakuMessages, nil
|
return wakuMessages, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (m *Messenger) GetCommunityToken(communityID string, chainID int, address string) (*token.CommunityToken, error) {
|
||||||
|
return m.communitiesManager.GetCommunityToken(communityID, chainID, address)
|
||||||
|
}
|
||||||
|
|
||||||
func (m *Messenger) GetCommunityTokens(communityID string) ([]*token.CommunityToken, error) {
|
func (m *Messenger) GetCommunityTokens(communityID string) ([]*token.CommunityToken, error) {
|
||||||
return m.communitiesManager.GetCommunityTokens(communityID)
|
return m.communitiesManager.GetCommunityTokens(communityID)
|
||||||
}
|
}
|
||||||
|
|
|
@ -32,12 +32,16 @@ import (
|
||||||
coretypes "github.com/status-im/status-go/eth-node/core/types"
|
coretypes "github.com/status-im/status-go/eth-node/core/types"
|
||||||
"github.com/status-im/status-go/eth-node/crypto"
|
"github.com/status-im/status-go/eth-node/crypto"
|
||||||
"github.com/status-im/status-go/eth-node/types"
|
"github.com/status-im/status-go/eth-node/types"
|
||||||
|
"github.com/status-im/status-go/images"
|
||||||
"github.com/status-im/status-go/multiaccounts"
|
"github.com/status-im/status-go/multiaccounts"
|
||||||
"github.com/status-im/status-go/multiaccounts/accounts"
|
"github.com/status-im/status-go/multiaccounts/accounts"
|
||||||
"github.com/status-im/status-go/params"
|
"github.com/status-im/status-go/params"
|
||||||
"github.com/status-im/status-go/protocol"
|
"github.com/status-im/status-go/protocol"
|
||||||
"github.com/status-im/status-go/protocol/anonmetrics"
|
"github.com/status-im/status-go/protocol/anonmetrics"
|
||||||
"github.com/status-im/status-go/protocol/common"
|
"github.com/status-im/status-go/protocol/common"
|
||||||
|
"github.com/status-im/status-go/protocol/communities"
|
||||||
|
"github.com/status-im/status-go/protocol/communities/token"
|
||||||
|
"github.com/status-im/status-go/protocol/protobuf"
|
||||||
"github.com/status-im/status-go/protocol/pushnotificationclient"
|
"github.com/status-im/status-go/protocol/pushnotificationclient"
|
||||||
"github.com/status-im/status-go/protocol/pushnotificationserver"
|
"github.com/status-im/status-go/protocol/pushnotificationserver"
|
||||||
"github.com/status-im/status-go/protocol/transport"
|
"github.com/status-im/status-go/protocol/transport"
|
||||||
|
@ -53,6 +57,8 @@ import (
|
||||||
"github.com/status-im/status-go/services/wallet/thirdparty"
|
"github.com/status-im/status-go/services/wallet/thirdparty"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
const infinityString = "∞"
|
||||||
|
|
||||||
// EnvelopeEventsHandler used for two different event types.
|
// EnvelopeEventsHandler used for two different event types.
|
||||||
type EnvelopeEventsHandler interface {
|
type EnvelopeEventsHandler interface {
|
||||||
EnvelopeSent([][]byte)
|
EnvelopeSent([][]byte)
|
||||||
|
@ -63,7 +69,6 @@ type EnvelopeEventsHandler interface {
|
||||||
|
|
||||||
// Service is a service that provides some additional API to whisper-based protocols like Whisper or Waku.
|
// Service is a service that provides some additional API to whisper-based protocols like Whisper or Waku.
|
||||||
type Service struct {
|
type Service struct {
|
||||||
thirdparty.CollectibleMetadataProvider
|
|
||||||
messenger *protocol.Messenger
|
messenger *protocol.Messenger
|
||||||
identity *ecdsa.PrivateKey
|
identity *ecdsa.PrivateKey
|
||||||
cancelMessenger chan struct{}
|
cancelMessenger chan struct{}
|
||||||
|
@ -556,16 +561,114 @@ func (s *Service) CanProvideCollectibleMetadata(id thirdparty.CollectibleUniqueI
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *Service) FetchCollectibleMetadata(id thirdparty.CollectibleUniqueID, tokenURI string) (*thirdparty.FullCollectibleData, error) {
|
func (s *Service) FetchCollectibleMetadata(id thirdparty.CollectibleUniqueID, tokenURI string) (*thirdparty.FullCollectibleData, error) {
|
||||||
if s.messenger == nil {
|
|
||||||
return nil, fmt.Errorf("messenger not ready")
|
|
||||||
}
|
|
||||||
|
|
||||||
communityID := tokenURIToCommunityID(tokenURI)
|
communityID := tokenURIToCommunityID(tokenURI)
|
||||||
|
|
||||||
if communityID == "" {
|
if communityID == "" {
|
||||||
return nil, fmt.Errorf("invalid tokenURI")
|
return nil, fmt.Errorf("invalid tokenURI")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
community, err := s.fetchCommunity(communityID)
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
if community == nil {
|
||||||
|
return nil, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
tokenMetadata, err := s.fetchCommunityCollectibleMetadata(community, id.ContractID)
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
if tokenMetadata == nil {
|
||||||
|
return nil, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
token, err := s.fetchCommunityToken(communityID, id.ContractID)
|
||||||
|
if err != nil {
|
||||||
|
return nil, 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{
|
||||||
|
ID: id.ContractID,
|
||||||
|
CommunityID: communityID,
|
||||||
|
Name: tokenMetadata.GetName(),
|
||||||
|
ImageURL: tokenMetadata.GetImage(),
|
||||||
|
},
|
||||||
|
}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func permissionTypeToPrivilegesLevel(permissionType protobuf.CommunityTokenPermission_Type) token.PrivilegesLevel {
|
||||||
|
switch permissionType {
|
||||||
|
case protobuf.CommunityTokenPermission_BECOME_TOKEN_OWNER:
|
||||||
|
return token.OwnerLevel
|
||||||
|
case protobuf.CommunityTokenPermission_BECOME_TOKEN_MASTER:
|
||||||
|
return token.MasterLevel
|
||||||
|
default:
|
||||||
|
return token.CommunityLevel
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *Service) FetchCollectibleCommunityInfo(communityID string, id thirdparty.CollectibleUniqueID) (*thirdparty.CollectiblesCommunityInfo, error) {
|
||||||
|
community, err := s.fetchCommunity(communityID)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
if community == nil {
|
||||||
|
return nil, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
metadata, err := s.fetchCommunityCollectibleMetadata(community, id.ContractID)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
if metadata == nil {
|
||||||
|
return nil, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
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
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *Service) fetchCommunity(communityID string) (*communities.Community, error) {
|
||||||
|
if s.messenger == nil {
|
||||||
|
return nil, fmt.Errorf("messenger not ready")
|
||||||
|
}
|
||||||
|
|
||||||
// Try to fetch metadata from Messenger communities
|
// Try to fetch metadata from Messenger communities
|
||||||
community, err := s.messenger.RequestCommunityInfoFromMailserver(communityID, true)
|
community, err := s.messenger.RequestCommunityInfoFromMailserver(communityID, true)
|
||||||
|
|
||||||
|
@ -573,29 +676,155 @@ func (s *Service) FetchCollectibleMetadata(id thirdparty.CollectibleUniqueID, to
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
if community != nil {
|
return community, nil
|
||||||
tokensMetadata := community.CommunityTokensMetadata()
|
}
|
||||||
|
|
||||||
for _, tokenMetadata := range tokensMetadata {
|
func (s *Service) fetchCommunityToken(communityID string, contractID thirdparty.ContractID) (*token.CommunityToken, error) {
|
||||||
contractAddresses := tokenMetadata.GetContractAddresses()
|
if s.messenger == nil {
|
||||||
if contractAddresses[uint64(id.ContractID.ChainID)] == id.ContractID.Address.Hex() {
|
return nil, fmt.Errorf("messenger not ready")
|
||||||
return &thirdparty.FullCollectibleData{
|
}
|
||||||
CollectibleData: thirdparty.CollectibleData{
|
|
||||||
ID: id,
|
return s.messenger.GetCommunityToken(communityID, int(contractID.ChainID), contractID.Address.String())
|
||||||
Name: tokenMetadata.GetName(),
|
}
|
||||||
Description: tokenMetadata.GetDescription(),
|
|
||||||
ImageURL: tokenMetadata.GetImage(),
|
func (s *Service) fetchCommunityCollectibleMetadata(community *communities.Community, contractID thirdparty.ContractID) (*protobuf.CommunityTokenMetadata, error) {
|
||||||
TokenURI: tokenURI,
|
tokensMetadata := community.CommunityTokensMetadata()
|
||||||
},
|
|
||||||
CollectionData: &thirdparty.CollectionData{
|
for _, tokenMetadata := range tokensMetadata {
|
||||||
ID: id.ContractID,
|
contractAddresses := tokenMetadata.GetContractAddresses()
|
||||||
Name: tokenMetadata.GetName(),
|
if contractAddresses[uint64(contractID.ChainID)] == contractID.Address.Hex() {
|
||||||
ImageURL: tokenMetadata.GetImage(),
|
return tokenMetadata, nil
|
||||||
},
|
|
||||||
}, nil
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return nil, nil
|
return nil, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func tokenCriterionContainsCollectible(tokenCriterion *protobuf.TokenCriteria, id thirdparty.CollectibleUniqueID) bool {
|
||||||
|
// Check if token type matches
|
||||||
|
if tokenCriterion.Type != protobuf.CommunityTokenType_ERC721 {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
for chainID, contractAddressStr := range tokenCriterion.ContractAddresses {
|
||||||
|
if chainID != uint64(id.ContractID.ChainID) {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
contractAddress := commongethtypes.HexToAddress(contractAddressStr)
|
||||||
|
if contractAddress != id.ContractID.Address {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(tokenCriterion.TokenIds) == 0 {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, tokenID := range tokenCriterion.TokenIds {
|
||||||
|
tokenIDBigInt := new(big.Int).SetUint64(tokenID)
|
||||||
|
if id.TokenID.Cmp(tokenIDBigInt) == 0 {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
func permissionContainsCollectible(permission *communities.CommunityTokenPermission, id thirdparty.CollectibleUniqueID) bool {
|
||||||
|
// See if any token criterion contains the collectible we're looking for
|
||||||
|
for _, tokenCriterion := range permission.TokenCriteria {
|
||||||
|
if tokenCriterionContainsCollectible(tokenCriterion, id) {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
func fetchCommunityCollectiblePermission(community *communities.Community, id thirdparty.CollectibleUniqueID) *communities.CommunityTokenPermission {
|
||||||
|
// Permnission types of interest
|
||||||
|
permissionTypes := []protobuf.CommunityTokenPermission_Type{
|
||||||
|
protobuf.CommunityTokenPermission_BECOME_TOKEN_OWNER,
|
||||||
|
protobuf.CommunityTokenPermission_BECOME_TOKEN_MASTER,
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, permissionType := range permissionTypes {
|
||||||
|
permissions := community.TokenPermissionsByType(permissionType)
|
||||||
|
// See if any community permission matches the type we're looking for
|
||||||
|
for _, permission := range permissions {
|
||||||
|
if permissionContainsCollectible(permission, id) {
|
||||||
|
return permission
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func fetchCommunityImage(community *communities.Community) string {
|
||||||
|
imageTypes := []string{
|
||||||
|
images.LargeDimName,
|
||||||
|
images.SmallDimName,
|
||||||
|
}
|
||||||
|
|
||||||
|
communityImages := community.Images()
|
||||||
|
|
||||||
|
for _, imageType := range imageTypes {
|
||||||
|
if pbImage, ok := communityImages[imageType]; ok {
|
||||||
|
imageBase64, err := images.GetPayloadDataURI(pbImage.Payload)
|
||||||
|
if err == nil {
|
||||||
|
return imageBase64
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
|
||||||
|
func boolToString(value bool) string {
|
||||||
|
if value {
|
||||||
|
return "Yes"
|
||||||
|
}
|
||||||
|
return "No"
|
||||||
|
}
|
||||||
|
|
||||||
|
func getCollectibleCommunityTraits(token *token.CommunityToken) []thirdparty.CollectibleTrait {
|
||||||
|
if token == nil {
|
||||||
|
return make([]thirdparty.CollectibleTrait, 0)
|
||||||
|
}
|
||||||
|
|
||||||
|
totalStr := infinityString
|
||||||
|
availableStr := infinityString
|
||||||
|
if !token.InfiniteSupply {
|
||||||
|
totalStr = token.Supply.String()
|
||||||
|
// TODO: calculate available supply. See services/communitytokens/api.go
|
||||||
|
availableStr = totalStr
|
||||||
|
}
|
||||||
|
|
||||||
|
transferableStr := boolToString(token.Transferable)
|
||||||
|
|
||||||
|
destructibleStr := boolToString(token.RemoteSelfDestruct)
|
||||||
|
|
||||||
|
return []thirdparty.CollectibleTrait{
|
||||||
|
{
|
||||||
|
TraitType: "Symbol",
|
||||||
|
Value: token.Symbol,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
TraitType: "Total",
|
||||||
|
Value: totalStr,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
TraitType: "Available",
|
||||||
|
Value: availableStr,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
TraitType: "Transferable",
|
||||||
|
Value: transferableStr,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
TraitType: "Destructible",
|
||||||
|
Value: destructibleStr,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -20,7 +20,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"
|
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 collectibleTraitsColumns = "chain_id, contract_address, token_id, trait_type, trait_value, display_type, max_value"
|
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"
|
const selectCollectibleTraitsColumns = "trait_type, trait_value, display_type, max_value"
|
||||||
|
|
||||||
|
@ -106,7 +106,7 @@ func upsertCollectibleTraits(creator sqlite.StatementCreator, id thirdparty.Coll
|
||||||
|
|
||||||
func upsertCollectiblesData(creator sqlite.StatementCreator, collectibles []thirdparty.CollectibleData) error {
|
func upsertCollectiblesData(creator sqlite.StatementCreator, collectibles []thirdparty.CollectibleData) error {
|
||||||
insertCollectible, err := creator.Prepare(fmt.Sprintf(`INSERT OR REPLACE INTO collectible_data_cache (%s)
|
insertCollectible, err := creator.Prepare(fmt.Sprintf(`INSERT OR REPLACE INTO collectible_data_cache (%s)
|
||||||
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)`, collectibleDataColumns))
|
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)`, collectibleDataColumns))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
@ -125,6 +125,7 @@ func upsertCollectiblesData(creator sqlite.StatementCreator, collectibles []thir
|
||||||
c.AnimationMediaType,
|
c.AnimationMediaType,
|
||||||
c.BackgroundColor,
|
c.BackgroundColor,
|
||||||
c.TokenURI,
|
c.TokenURI,
|
||||||
|
c.CommunityID,
|
||||||
)
|
)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
|
@ -181,6 +182,7 @@ func scanCollectiblesDataRow(row *sql.Row) (*thirdparty.CollectibleData, error)
|
||||||
&c.AnimationMediaType,
|
&c.AnimationMediaType,
|
||||||
&c.BackgroundColor,
|
&c.BackgroundColor,
|
||||||
&c.TokenURI,
|
&c.TokenURI,
|
||||||
|
&c.CommunityID,
|
||||||
)
|
)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
|
|
|
@ -7,16 +7,17 @@ import (
|
||||||
|
|
||||||
"github.com/ethereum/go-ethereum/common"
|
"github.com/ethereum/go-ethereum/common"
|
||||||
|
|
||||||
"github.com/status-im/status-go/appdatabase"
|
|
||||||
"github.com/status-im/status-go/services/wallet/bigint"
|
"github.com/status-im/status-go/services/wallet/bigint"
|
||||||
w_common "github.com/status-im/status-go/services/wallet/common"
|
w_common "github.com/status-im/status-go/services/wallet/common"
|
||||||
"github.com/status-im/status-go/services/wallet/thirdparty"
|
"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"
|
"github.com/stretchr/testify/require"
|
||||||
)
|
)
|
||||||
|
|
||||||
func setupCollectibleDataDBTest(t *testing.T) (*CollectibleDataDB, func()) {
|
func setupCollectibleDataDBTest(t *testing.T) (*CollectibleDataDB, func()) {
|
||||||
db, err := appdatabase.InitializeDB(":memory:", "wallet-collectibles-data-db-tests", 1)
|
db, err := helpers.SetupTestMemorySQLDB(walletdatabase.DbInitializer{})
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
return NewCollectibleDataDB(db), func() {
|
return NewCollectibleDataDB(db), func() {
|
||||||
require.NoError(t, db.Close())
|
require.NoError(t, db.Close())
|
||||||
|
@ -64,6 +65,7 @@ func generateTestCollectiblesData(count int) (result []thirdparty.CollectibleDat
|
||||||
},
|
},
|
||||||
BackgroundColor: fmt.Sprintf("backgroundcolor-%d", i),
|
BackgroundColor: fmt.Sprintf("backgroundcolor-%d", i),
|
||||||
TokenURI: fmt.Sprintf("tokenuri-%d", i),
|
TokenURI: fmt.Sprintf("tokenuri-%d", i),
|
||||||
|
CommunityID: fmt.Sprintf("communityid-%d", i),
|
||||||
}
|
}
|
||||||
result = append(result, newCollectible)
|
result = append(result, newCollectible)
|
||||||
}
|
}
|
||||||
|
|
|
@ -18,7 +18,7 @@ func NewCollectionDataDB(sqlDb *sql.DB) *CollectionDataDB {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const collectionDataColumns = "chain_id, contract_address, provider, name, slug, image_url"
|
const collectionDataColumns = "chain_id, contract_address, provider, name, slug, image_url, community_id"
|
||||||
const collectionTraitsColumns = "chain_id, contract_address, trait_type, min, max"
|
const collectionTraitsColumns = "chain_id, contract_address, trait_type, min, max"
|
||||||
const selectCollectionTraitsColumns = "trait_type, min, max"
|
const selectCollectionTraitsColumns = "trait_type, min, max"
|
||||||
|
|
||||||
|
@ -100,7 +100,7 @@ func upsertCollectionTraits(creator sqlite.StatementCreator, id thirdparty.Contr
|
||||||
|
|
||||||
func upsertCollectionsData(creator sqlite.StatementCreator, collections []thirdparty.CollectionData) error {
|
func upsertCollectionsData(creator sqlite.StatementCreator, collections []thirdparty.CollectionData) error {
|
||||||
insertCollection, err := creator.Prepare(fmt.Sprintf(`INSERT OR REPLACE INTO collection_data_cache (%s)
|
insertCollection, err := creator.Prepare(fmt.Sprintf(`INSERT OR REPLACE INTO collection_data_cache (%s)
|
||||||
VALUES (?, ?, ?, ?, ?, ?)`, collectionDataColumns))
|
VALUES (?, ?, ?, ?, ?, ?, ?)`, collectionDataColumns))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
@ -113,6 +113,7 @@ func upsertCollectionsData(creator sqlite.StatementCreator, collections []thirdp
|
||||||
c.Name,
|
c.Name,
|
||||||
c.Slug,
|
c.Slug,
|
||||||
c.ImageURL,
|
c.ImageURL,
|
||||||
|
c.CommunityID,
|
||||||
)
|
)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
|
@ -160,6 +161,7 @@ func scanCollectionsDataRow(row *sql.Row) (*thirdparty.CollectionData, error) {
|
||||||
&c.Name,
|
&c.Name,
|
||||||
&c.Slug,
|
&c.Slug,
|
||||||
&c.ImageURL,
|
&c.ImageURL,
|
||||||
|
&c.CommunityID,
|
||||||
)
|
)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
|
|
|
@ -7,15 +7,16 @@ import (
|
||||||
|
|
||||||
"github.com/ethereum/go-ethereum/common"
|
"github.com/ethereum/go-ethereum/common"
|
||||||
|
|
||||||
"github.com/status-im/status-go/appdatabase"
|
|
||||||
w_common "github.com/status-im/status-go/services/wallet/common"
|
w_common "github.com/status-im/status-go/services/wallet/common"
|
||||||
"github.com/status-im/status-go/services/wallet/thirdparty"
|
"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"
|
"github.com/stretchr/testify/require"
|
||||||
)
|
)
|
||||||
|
|
||||||
func setupCollectionDataDBTest(t *testing.T) (*CollectionDataDB, func()) {
|
func setupCollectionDataDBTest(t *testing.T) (*CollectionDataDB, func()) {
|
||||||
db, err := appdatabase.InitializeDB(":memory:", "wallet-collections-data-db-tests", 1)
|
db, err := helpers.SetupTestMemorySQLDB(walletdatabase.DbInitializer{})
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
return NewCollectionDataDB(db), func() {
|
return NewCollectionDataDB(db), func() {
|
||||||
require.NoError(t, db.Close())
|
require.NoError(t, db.Close())
|
||||||
|
@ -39,11 +40,12 @@ func generateTestCollectionsData(count int) (result []thirdparty.CollectionData)
|
||||||
ChainID: w_common.ChainID(i),
|
ChainID: w_common.ChainID(i),
|
||||||
Address: common.BigToAddress(bigI),
|
Address: common.BigToAddress(bigI),
|
||||||
},
|
},
|
||||||
Provider: fmt.Sprintf("provider-%d", i),
|
Provider: fmt.Sprintf("provider-%d", i),
|
||||||
Name: fmt.Sprintf("name-%d", i),
|
Name: fmt.Sprintf("name-%d", i),
|
||||||
Slug: fmt.Sprintf("slug-%d", i),
|
Slug: fmt.Sprintf("slug-%d", i),
|
||||||
ImageURL: fmt.Sprintf("imageurl-%d", i),
|
ImageURL: fmt.Sprintf("imageurl-%d", i),
|
||||||
Traits: traits,
|
Traits: traits,
|
||||||
|
CommunityID: fmt.Sprintf("community-%d", i),
|
||||||
}
|
}
|
||||||
result = append(result, newCollection)
|
result = append(result, newCollection)
|
||||||
}
|
}
|
||||||
|
|
|
@ -49,13 +49,21 @@ type Manager struct {
|
||||||
collectibleDataProviders []thirdparty.CollectibleDataProvider
|
collectibleDataProviders []thirdparty.CollectibleDataProvider
|
||||||
collectionDataProviders []thirdparty.CollectionDataProvider
|
collectionDataProviders []thirdparty.CollectionDataProvider
|
||||||
metadataProvider thirdparty.CollectibleMetadataProvider
|
metadataProvider thirdparty.CollectibleMetadataProvider
|
||||||
|
communityInfoProvider thirdparty.CollectibleCommunityInfoProvider
|
||||||
opensea *opensea.Client
|
opensea *opensea.Client
|
||||||
httpClient *http.Client
|
httpClient *http.Client
|
||||||
collectiblesDataDB *CollectibleDataDB
|
collectiblesDataDB *CollectibleDataDB
|
||||||
collectionsDataDB *CollectionDataDB
|
collectionsDataDB *CollectionDataDB
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewManager(db *sql.DB, rpcClient *rpc.Client, contractOwnershipProviders []thirdparty.CollectibleContractOwnershipProvider, accountOwnershipProviders []thirdparty.CollectibleAccountOwnershipProvider, collectibleDataProviders []thirdparty.CollectibleDataProvider, collectionDataProviders []thirdparty.CollectionDataProvider, opensea *opensea.Client) *Manager {
|
func NewManager(
|
||||||
|
db *sql.DB,
|
||||||
|
rpcClient *rpc.Client,
|
||||||
|
contractOwnershipProviders []thirdparty.CollectibleContractOwnershipProvider,
|
||||||
|
accountOwnershipProviders []thirdparty.CollectibleAccountOwnershipProvider,
|
||||||
|
collectibleDataProviders []thirdparty.CollectibleDataProvider,
|
||||||
|
collectionDataProviders []thirdparty.CollectionDataProvider,
|
||||||
|
opensea *opensea.Client) *Manager {
|
||||||
hystrix.ConfigureCommand(hystrixContractOwnershipClientName, hystrix.CommandConfig{
|
hystrix.ConfigureCommand(hystrixContractOwnershipClientName, hystrix.CommandConfig{
|
||||||
Timeout: 10000,
|
Timeout: 10000,
|
||||||
MaxConcurrentRequests: 100,
|
MaxConcurrentRequests: 100,
|
||||||
|
@ -139,6 +147,10 @@ func (o *Manager) SetMetadataProvider(metadataProvider thirdparty.CollectibleMet
|
||||||
o.metadataProvider = metadataProvider
|
o.metadataProvider = metadataProvider
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (o *Manager) SetCommunityInfoProvider(communityInfoProvider thirdparty.CollectibleCommunityInfoProvider) {
|
||||||
|
o.communityInfoProvider = communityInfoProvider
|
||||||
|
}
|
||||||
|
|
||||||
func (o *Manager) FetchAllCollectionsByOwner(chainID walletCommon.ChainID, owner common.Address) ([]opensea.OwnedCollection, error) {
|
func (o *Manager) FetchAllCollectionsByOwner(chainID walletCommon.ChainID, owner common.Address) ([]opensea.OwnedCollection, error) {
|
||||||
return o.opensea.FetchAllCollectionsByOwner(chainID, owner)
|
return o.opensea.FetchAllCollectionsByOwner(chainID, owner)
|
||||||
}
|
}
|
||||||
|
@ -375,8 +387,7 @@ func (o *Manager) FetchCollectibleOwnersByContractAddress(chainID walletCommon.C
|
||||||
func isMetadataEmpty(asset thirdparty.CollectibleData) bool {
|
func isMetadataEmpty(asset thirdparty.CollectibleData) bool {
|
||||||
return asset.Name == "" &&
|
return asset.Name == "" &&
|
||||||
asset.Description == "" &&
|
asset.Description == "" &&
|
||||||
asset.ImageURL == "" &&
|
asset.ImageURL == ""
|
||||||
asset.TokenURI == ""
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (o *Manager) fetchTokenURI(id thirdparty.CollectibleUniqueID) (string, error) {
|
func (o *Manager) fetchTokenURI(id thirdparty.CollectibleUniqueID) (string, error) {
|
||||||
|
@ -426,14 +437,20 @@ func (o *Manager) processFullCollectibleData(assets []thirdparty.FullCollectible
|
||||||
if o.metadataProvider == nil {
|
if o.metadataProvider == nil {
|
||||||
return fmt.Errorf("CollectibleMetadataProvider not available")
|
return fmt.Errorf("CollectibleMetadataProvider not available")
|
||||||
}
|
}
|
||||||
tokenURI, err := o.fetchTokenURI(id)
|
|
||||||
|
|
||||||
if err != nil {
|
tokenURI := asset.CollectibleData.TokenURI
|
||||||
return err
|
var err error
|
||||||
|
|
||||||
|
if tokenURI == "" {
|
||||||
|
tokenURI, err = o.fetchTokenURI(id)
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
asset.CollectibleData.TokenURI = tokenURI
|
||||||
}
|
}
|
||||||
|
|
||||||
asset.CollectibleData.TokenURI = tokenURI
|
|
||||||
|
|
||||||
canProvide, err := o.metadataProvider.CanProvideCollectibleMetadata(id, tokenURI)
|
canProvide, err := o.metadataProvider.CanProvideCollectibleMetadata(id, tokenURI)
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -538,3 +555,40 @@ func (o *Manager) getCacheFullCollectibleData(uniqueIDs []thirdparty.Collectible
|
||||||
|
|
||||||
return ret, nil
|
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
|
||||||
|
}
|
||||||
|
|
|
@ -116,7 +116,7 @@ type GetCollectiblesDetailsResponse struct {
|
||||||
}
|
}
|
||||||
|
|
||||||
type filterOwnedCollectiblesTaskReturnType struct {
|
type filterOwnedCollectiblesTaskReturnType struct {
|
||||||
collectibles []CollectibleHeader
|
headers []CollectibleHeader
|
||||||
hasMore bool
|
hasMore bool
|
||||||
ownershipStatus OwnershipStatusPerAddressAndChainID
|
ownershipStatus OwnershipStatusPerAddressAndChainID
|
||||||
}
|
}
|
||||||
|
@ -138,9 +138,10 @@ func (s *Service) FilterOwnedCollectiblesAsync(requestID int32, chainIDs []walle
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
headers, err := s.fullCollectiblesDataToHeaders(data)
|
||||||
|
|
||||||
return filterOwnedCollectiblesTaskReturnType{
|
return filterOwnedCollectiblesTaskReturnType{
|
||||||
collectibles: fullCollectiblesDataToHeaders(data),
|
headers: headers,
|
||||||
hasMore: hasMore,
|
hasMore: hasMore,
|
||||||
ownershipStatus: ownershipStatus,
|
ownershipStatus: ownershipStatus,
|
||||||
}, err
|
}, err
|
||||||
|
@ -153,7 +154,7 @@ func (s *Service) FilterOwnedCollectiblesAsync(requestID int32, chainIDs []walle
|
||||||
res.ErrorCode = ErrorCodeTaskCanceled
|
res.ErrorCode = ErrorCodeTaskCanceled
|
||||||
} else if err == nil {
|
} else if err == nil {
|
||||||
fnRet := result.(filterOwnedCollectiblesTaskReturnType)
|
fnRet := result.(filterOwnedCollectiblesTaskReturnType)
|
||||||
res.Collectibles = fnRet.collectibles
|
res.Collectibles = fnRet.headers
|
||||||
res.Offset = offset
|
res.Offset = offset
|
||||||
res.HasMore = fnRet.hasMore
|
res.HasMore = fnRet.hasMore
|
||||||
res.OwnershipStatus = fnRet.ownershipStatus
|
res.OwnershipStatus = fnRet.ownershipStatus
|
||||||
|
@ -167,7 +168,10 @@ func (s *Service) FilterOwnedCollectiblesAsync(requestID int32, chainIDs []walle
|
||||||
func (s *Service) GetCollectiblesDetailsAsync(requestID int32, uniqueIDs []thirdparty.CollectibleUniqueID) {
|
func (s *Service) GetCollectiblesDetailsAsync(requestID int32, uniqueIDs []thirdparty.CollectibleUniqueID) {
|
||||||
s.scheduler.Enqueue(requestID, getCollectiblesDataTask, func(ctx context.Context) (interface{}, error) {
|
s.scheduler.Enqueue(requestID, getCollectiblesDataTask, func(ctx context.Context) (interface{}, error) {
|
||||||
collectibles, err := s.manager.FetchAssetsByCollectibleUniqueID(uniqueIDs)
|
collectibles, err := s.manager.FetchAssetsByCollectibleUniqueID(uniqueIDs)
|
||||||
return collectibles, err
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return s.fullCollectiblesDataToDetails(collectibles)
|
||||||
}, func(result interface{}, taskType async.TaskType, err error) {
|
}, func(result interface{}, taskType async.TaskType, err error) {
|
||||||
res := GetCollectiblesDetailsResponse{
|
res := GetCollectiblesDetailsResponse{
|
||||||
ErrorCode: ErrorCodeFailed,
|
ErrorCode: ErrorCodeFailed,
|
||||||
|
@ -176,8 +180,7 @@ func (s *Service) GetCollectiblesDetailsAsync(requestID int32, uniqueIDs []third
|
||||||
if errors.Is(err, context.Canceled) || errors.Is(err, async.ErrTaskOverwritten) {
|
if errors.Is(err, context.Canceled) || errors.Is(err, async.ErrTaskOverwritten) {
|
||||||
res.ErrorCode = ErrorCodeTaskCanceled
|
res.ErrorCode = ErrorCodeTaskCanceled
|
||||||
} else if err == nil {
|
} else if err == nil {
|
||||||
collectibles := result.([]thirdparty.FullCollectibleData)
|
res.Collectibles = result.([]CollectibleDetails)
|
||||||
res.Collectibles = fullCollectiblesDataToDetails(collectibles)
|
|
||||||
res.ErrorCode = ErrorCodeSuccess
|
res.ErrorCode = ErrorCodeSuccess
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -402,3 +405,56 @@ func (s *Service) GetOwnershipStatus(chainIDs []walletCommon.ChainID, owners []c
|
||||||
|
|
||||||
return ret, nil
|
return ret, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (s *Service) fullCollectiblesDataToHeaders(data []thirdparty.FullCollectibleData) ([]CollectibleHeader, error) {
|
||||||
|
res := make([]CollectibleHeader, 0, len(data))
|
||||||
|
|
||||||
|
for _, c := range data {
|
||||||
|
header := fullCollectibleDataToHeader(c)
|
||||||
|
|
||||||
|
if c.CollectibleData.CommunityID != "" {
|
||||||
|
communityInfo, err := s.manager.FetchCollectibleCommunityInfo(c.CollectibleData.CommunityID, c.CollectibleData.ID)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
header.CommunityHeader = &CommunityHeader{
|
||||||
|
CommunityID: communityInfo.CommunityID,
|
||||||
|
CommunityName: communityInfo.CommunityName,
|
||||||
|
CommunityColor: communityInfo.CommunityColor,
|
||||||
|
PrivilegesLevel: communityInfo.PrivilegesLevel,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
res = append(res, header)
|
||||||
|
}
|
||||||
|
|
||||||
|
return res, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *Service) fullCollectiblesDataToDetails(data []thirdparty.FullCollectibleData) ([]CollectibleDetails, error) {
|
||||||
|
res := make([]CollectibleDetails, 0, len(data))
|
||||||
|
|
||||||
|
for _, c := range data {
|
||||||
|
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)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
details.CommunityInfo = communityInfo
|
||||||
|
}
|
||||||
|
|
||||||
|
res = append(res, details)
|
||||||
|
}
|
||||||
|
|
||||||
|
return res, nil
|
||||||
|
}
|
||||||
|
|
|
@ -1,20 +1,24 @@
|
||||||
package collectibles
|
package collectibles
|
||||||
|
|
||||||
import "github.com/status-im/status-go/services/wallet/thirdparty"
|
import (
|
||||||
|
"github.com/status-im/status-go/protocol/communities/token"
|
||||||
|
"github.com/status-im/status-go/services/wallet/thirdparty"
|
||||||
|
)
|
||||||
|
|
||||||
// Combined Collection+Collectible info, used to display a detailed view of a collectible
|
// Combined Collection+Collectible info, used to display a detailed view of a collectible
|
||||||
type CollectibleDetails struct {
|
type CollectibleDetails struct {
|
||||||
ID thirdparty.CollectibleUniqueID `json:"id"`
|
ID thirdparty.CollectibleUniqueID `json:"id"`
|
||||||
Name string `json:"name"`
|
Name string `json:"name"`
|
||||||
Description string `json:"description"`
|
Description string `json:"description"`
|
||||||
ImageURL string `json:"image_url"`
|
ImageURL string `json:"image_url"`
|
||||||
AnimationURL string `json:"animation_url"`
|
AnimationURL string `json:"animation_url"`
|
||||||
AnimationMediaType string `json:"animation_media_type"`
|
AnimationMediaType string `json:"animation_media_type"`
|
||||||
Traits []thirdparty.CollectibleTrait `json:"traits"`
|
Traits []thirdparty.CollectibleTrait `json:"traits"`
|
||||||
BackgroundColor string `json:"background_color"`
|
BackgroundColor string `json:"background_color"`
|
||||||
CollectionName string `json:"collection_name"`
|
CollectionName string `json:"collection_name"`
|
||||||
CollectionSlug string `json:"collection_slug"`
|
CollectionSlug string `json:"collection_slug"`
|
||||||
CollectionImageURL string `json:"collection_image_url"`
|
CollectionImageURL string `json:"collection_image_url"`
|
||||||
|
CommunityInfo *thirdparty.CollectiblesCommunityInfo `json:"community_info,omitempty"`
|
||||||
}
|
}
|
||||||
|
|
||||||
// Combined Collection+Collectible info, used to display a basic view of a collectible in a list
|
// Combined Collection+Collectible info, used to display a basic view of a collectible in a list
|
||||||
|
@ -28,6 +32,14 @@ type CollectibleHeader struct {
|
||||||
CollectionName string `json:"collection_name"`
|
CollectionName string `json:"collection_name"`
|
||||||
CollectionSlug string `json:"collection_slug"`
|
CollectionSlug string `json:"collection_slug"`
|
||||||
CollectionImageURL string `json:"collection_image_url"`
|
CollectionImageURL string `json:"collection_image_url"`
|
||||||
|
CommunityHeader *CommunityHeader `json:"community_header,omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type CommunityHeader struct {
|
||||||
|
CommunityID string `json:"community_id"`
|
||||||
|
CommunityName string `json:"community_name"`
|
||||||
|
CommunityColor string `json:"community_color"`
|
||||||
|
PrivilegesLevel token.PrivilegesLevel `json:"privileges_level"`
|
||||||
}
|
}
|
||||||
|
|
||||||
func fullCollectibleDataToHeader(c thirdparty.FullCollectibleData) CollectibleHeader {
|
func fullCollectibleDataToHeader(c thirdparty.FullCollectibleData) CollectibleHeader {
|
||||||
|
@ -47,16 +59,6 @@ func fullCollectibleDataToHeader(c thirdparty.FullCollectibleData) CollectibleHe
|
||||||
return ret
|
return ret
|
||||||
}
|
}
|
||||||
|
|
||||||
func fullCollectiblesDataToHeaders(data []thirdparty.FullCollectibleData) []CollectibleHeader {
|
|
||||||
res := make([]CollectibleHeader, 0, len(data))
|
|
||||||
|
|
||||||
for _, c := range data {
|
|
||||||
res = append(res, fullCollectibleDataToHeader(c))
|
|
||||||
}
|
|
||||||
|
|
||||||
return res
|
|
||||||
}
|
|
||||||
|
|
||||||
func fullCollectibleDataToDetails(c thirdparty.FullCollectibleData) CollectibleDetails {
|
func fullCollectibleDataToDetails(c thirdparty.FullCollectibleData) CollectibleDetails {
|
||||||
ret := CollectibleDetails{
|
ret := CollectibleDetails{
|
||||||
ID: c.CollectibleData.ID,
|
ID: c.CollectibleData.ID,
|
||||||
|
@ -75,13 +77,3 @@ func fullCollectibleDataToDetails(c thirdparty.FullCollectibleData) CollectibleD
|
||||||
}
|
}
|
||||||
return ret
|
return ret
|
||||||
}
|
}
|
||||||
|
|
||||||
func fullCollectiblesDataToDetails(data []thirdparty.FullCollectibleData) []CollectibleDetails {
|
|
||||||
res := make([]CollectibleDetails, 0, len(data))
|
|
||||||
|
|
||||||
for _, c := range data {
|
|
||||||
res = append(res, fullCollectibleDataToDetails(c))
|
|
||||||
}
|
|
||||||
|
|
||||||
return res
|
|
||||||
}
|
|
||||||
|
|
|
@ -223,6 +223,11 @@ func (s *Service) SetCollectibleMetadataProvider(provider thirdparty.Collectible
|
||||||
s.collectiblesManager.SetMetadataProvider(provider)
|
s.collectiblesManager.SetMetadataProvider(provider)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Set external Collectibles community info provider
|
||||||
|
func (s *Service) SetCollectibleCommunityInfoProvider(provider thirdparty.CollectibleCommunityInfoProvider) {
|
||||||
|
s.collectiblesManager.SetCommunityInfoProvider(provider)
|
||||||
|
}
|
||||||
|
|
||||||
// Stop reactor and close db.
|
// Stop reactor and close db.
|
||||||
func (s *Service) Stop() error {
|
func (s *Service) Stop() error {
|
||||||
log.Info("wallet will be stopped")
|
log.Info("wallet will be stopped")
|
||||||
|
|
|
@ -5,6 +5,7 @@ import (
|
||||||
"fmt"
|
"fmt"
|
||||||
|
|
||||||
"github.com/ethereum/go-ethereum/common"
|
"github.com/ethereum/go-ethereum/common"
|
||||||
|
"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/bigint"
|
||||||
w_common "github.com/status-im/status-go/services/wallet/common"
|
w_common "github.com/status-im/status-go/services/wallet/common"
|
||||||
)
|
)
|
||||||
|
@ -76,12 +77,13 @@ type CollectionTrait struct {
|
||||||
|
|
||||||
// Collection info
|
// Collection info
|
||||||
type CollectionData struct {
|
type CollectionData struct {
|
||||||
ID ContractID `json:"id"`
|
ID ContractID `json:"id"`
|
||||||
Provider string `json:"provider"`
|
CommunityID string `json:"community_id"`
|
||||||
Name string `json:"name"`
|
Provider string `json:"provider"`
|
||||||
Slug string `json:"slug"`
|
Name string `json:"name"`
|
||||||
ImageURL string `json:"image_url"`
|
Slug string `json:"slug"`
|
||||||
Traits map[string]CollectionTrait `json:"traits"`
|
ImageURL string `json:"image_url"`
|
||||||
|
Traits map[string]CollectionTrait `json:"traits"`
|
||||||
}
|
}
|
||||||
|
|
||||||
type CollectibleTrait struct {
|
type CollectibleTrait struct {
|
||||||
|
@ -94,6 +96,7 @@ type CollectibleTrait struct {
|
||||||
// Collectible info
|
// Collectible info
|
||||||
type CollectibleData struct {
|
type CollectibleData struct {
|
||||||
ID CollectibleUniqueID `json:"id"`
|
ID CollectibleUniqueID `json:"id"`
|
||||||
|
CommunityID string `json:"community_id"`
|
||||||
Provider string `json:"provider"`
|
Provider string `json:"provider"`
|
||||||
Name string `json:"name"`
|
Name string `json:"name"`
|
||||||
Description string `json:"description"`
|
Description string `json:"description"`
|
||||||
|
@ -141,11 +144,28 @@ 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 {
|
type CollectibleMetadataProvider interface {
|
||||||
CanProvideCollectibleMetadata(id CollectibleUniqueID, tokenURI string) (bool, error)
|
CanProvideCollectibleMetadata(id CollectibleUniqueID, tokenURI string) (bool, error)
|
||||||
FetchCollectibleMetadata(id CollectibleUniqueID, tokenURI string) (*FullCollectibleData, 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 {
|
type TokenBalance struct {
|
||||||
TokenID *bigint.BigInt `json:"tokenId"`
|
TokenID *bigint.BigInt `json:"tokenId"`
|
||||||
Balance *bigint.BigInt `json:"balance"`
|
Balance *bigint.BigInt `json:"balance"`
|
||||||
|
|
|
@ -5,6 +5,7 @@
|
||||||
// 1692701339_add_scope_to_pending.up.sql (576B)
|
// 1692701339_add_scope_to_pending.up.sql (576B)
|
||||||
// 1694540071_add_collectibles_ownership_update_timestamp.up.sql (349B)
|
// 1694540071_add_collectibles_ownership_update_timestamp.up.sql (349B)
|
||||||
// 1694692748_add_raw_balance_to_token_balances.up.sql (165B)
|
// 1694692748_add_raw_balance_to_token_balances.up.sql (165B)
|
||||||
|
// 1695133989_add_community_id_to_collectibles_and_collections_data_cache.up.sql (275B)
|
||||||
// doc.go (74B)
|
// doc.go (74B)
|
||||||
|
|
||||||
package migrations
|
package migrations
|
||||||
|
@ -15,7 +16,6 @@ import (
|
||||||
"crypto/sha256"
|
"crypto/sha256"
|
||||||
"fmt"
|
"fmt"
|
||||||
"io"
|
"io"
|
||||||
"io/ioutil"
|
|
||||||
"os"
|
"os"
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
"strings"
|
"strings"
|
||||||
|
@ -25,7 +25,7 @@ import (
|
||||||
func bindataRead(data []byte, name string) ([]byte, error) {
|
func bindataRead(data []byte, name string) ([]byte, error) {
|
||||||
gz, err := gzip.NewReader(bytes.NewBuffer(data))
|
gz, err := gzip.NewReader(bytes.NewBuffer(data))
|
||||||
if err != nil {
|
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
|
var buf bytes.Buffer
|
||||||
|
@ -33,7 +33,7 @@ func bindataRead(data []byte, name string) ([]byte, error) {
|
||||||
clErr := gz.Close()
|
clErr := gz.Close()
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, fmt.Errorf("read %q: %v", name, err)
|
return nil, fmt.Errorf("read %q: %w", name, err)
|
||||||
}
|
}
|
||||||
if clErr != nil {
|
if clErr != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
|
@ -89,7 +89,7 @@ func _1691753758_initialUpSql() (*asset, error) {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
info := bindataFileInfo{name: "1691753758_initial.up.sql", size: 5738, mode: os.FileMode(0664), modTime: time.Unix(1694793410, 0)}
|
info := bindataFileInfo{name: "1691753758_initial.up.sql", size: 5738, mode: os.FileMode(0644), modTime: time.Unix(1695161107, 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}}
|
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
|
return a, nil
|
||||||
}
|
}
|
||||||
|
@ -109,7 +109,7 @@ func _1692701329_add_collectibles_and_collections_data_cacheUpSql() (*asset, err
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
info := bindataFileInfo{name: "1692701329_add_collectibles_and_collections_data_cache.up.sql", size: 1808, mode: os.FileMode(0664), modTime: time.Unix(1694793410, 0)}
|
info := bindataFileInfo{name: "1692701329_add_collectibles_and_collections_data_cache.up.sql", size: 1808, mode: os.FileMode(0644), modTime: time.Unix(1695161107, 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}}
|
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
|
return a, nil
|
||||||
}
|
}
|
||||||
|
@ -129,7 +129,7 @@ func _1692701339_add_scope_to_pendingUpSql() (*asset, error) {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
info := bindataFileInfo{name: "1692701339_add_scope_to_pending.up.sql", size: 576, mode: os.FileMode(0664), modTime: time.Unix(1694793410, 0)}
|
info := bindataFileInfo{name: "1692701339_add_scope_to_pending.up.sql", size: 576, mode: os.FileMode(0644), modTime: time.Unix(1695161107, 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}}
|
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
|
return a, nil
|
||||||
}
|
}
|
||||||
|
@ -149,7 +149,7 @@ func _1694540071_add_collectibles_ownership_update_timestampUpSql() (*asset, err
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
info := bindataFileInfo{name: "1694540071_add_collectibles_ownership_update_timestamp.up.sql", size: 349, mode: os.FileMode(0664), modTime: time.Unix(1695198641, 0)}
|
info := bindataFileInfo{name: "1694540071_add_collectibles_ownership_update_timestamp.up.sql", size: 349, mode: os.FileMode(0644), modTime: time.Unix(1695161107, 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}}
|
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
|
return a, nil
|
||||||
}
|
}
|
||||||
|
@ -169,11 +169,31 @@ func _1694692748_add_raw_balance_to_token_balancesUpSql() (*asset, error) {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
info := bindataFileInfo{name: "1694692748_add_raw_balance_to_token_balances.up.sql", size: 165, mode: os.FileMode(0664), modTime: time.Unix(1695203924, 0)}
|
info := bindataFileInfo{name: "1694692748_add_raw_balance_to_token_balances.up.sql", size: 165, mode: os.FileMode(0644), modTime: time.Unix(1695211597, 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}}
|
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
|
return a, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var __1695133989_add_community_id_to_collectibles_and_collections_data_cacheUpSql = []byte("\x1f\x8b\x08\x00\x00\x00\x00\x00\x00\xff\x72\xf4\x09\x71\x0d\x52\x08\x71\x74\xf2\x71\x55\x48\xce\xcf\xc9\x49\x4d\x2e\xc9\x4c\xca\x49\x8d\x4f\x49\x2c\x49\x8c\x4f\x4e\x4c\xce\x48\x55\x70\x74\x71\x51\x70\xf6\xf7\x09\xf5\xf5\x53\x48\xce\xcf\xcd\x2d\xcd\xcb\x2c\xa9\x8c\xcf\x4c\x51\x08\x71\x8d\x08\x51\xf0\xf3\x0f\x51\xf0\x0b\xf5\xf1\x51\x70\x71\x75\x73\x0c\xf5\x09\x51\x50\x52\xb2\xe6\x0a\x0d\x70\x71\x0c\xc1\x69\x5e\xb0\x6b\x08\xaa\x41\xb6\x60\x4d\x5c\xd8\x9c\x92\x9f\x47\x55\x97\xa0\x1a\x87\xc3\x21\x80\x00\x00\x00\xff\xff\x2e\x30\x6f\xa7\x13\x01\x00\x00")
|
||||||
|
|
||||||
|
func _1695133989_add_community_id_to_collectibles_and_collections_data_cacheUpSqlBytes() ([]byte, error) {
|
||||||
|
return bindataRead(
|
||||||
|
__1695133989_add_community_id_to_collectibles_and_collections_data_cacheUpSql,
|
||||||
|
"1695133989_add_community_id_to_collectibles_and_collections_data_cache.up.sql",
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
func _1695133989_add_community_id_to_collectibles_and_collections_data_cacheUpSql() (*asset, error) {
|
||||||
|
bytes, err := _1695133989_add_community_id_to_collectibles_and_collections_data_cacheUpSqlBytes()
|
||||||
|
if err != nil {
|
||||||
|
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(1695211597, 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
|
||||||
|
}
|
||||||
|
|
||||||
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")
|
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) {
|
func docGoBytes() ([]byte, error) {
|
||||||
|
@ -189,7 +209,7 @@ func docGo() (*asset, error) {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
info := bindataFileInfo{name: "doc.go", size: 74, mode: os.FileMode(0664), modTime: time.Unix(1694793410, 0)}
|
info := bindataFileInfo{name: "doc.go", size: 74, mode: os.FileMode(0644), modTime: time.Unix(1695161107, 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}}
|
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
|
return a, nil
|
||||||
}
|
}
|
||||||
|
@ -285,28 +305,29 @@ func AssetNames() []string {
|
||||||
|
|
||||||
// _bindata is a table, holding each asset generator, mapped to its name.
|
// _bindata is a table, holding each asset generator, mapped to its name.
|
||||||
var _bindata = map[string]func() (*asset, error){
|
var _bindata = map[string]func() (*asset, error){
|
||||||
"1691753758_initial.up.sql": _1691753758_initialUpSql,
|
"1691753758_initial.up.sql": _1691753758_initialUpSql,
|
||||||
|
"1692701329_add_collectibles_and_collections_data_cache.up.sql": _1692701329_add_collectibles_and_collections_data_cacheUpSql,
|
||||||
"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,
|
||||||
"1692701339_add_scope_to_pending.up.sql": _1692701339_add_scope_to_pendingUpSql,
|
"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,
|
||||||
"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,
|
|
||||||
|
|
||||||
"doc.go": docGo,
|
"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
|
// AssetDir returns the file names below a certain
|
||||||
// directory embedded in the file by go-bindata.
|
// directory embedded in the file by go-bindata.
|
||||||
// For example if you run go-bindata on data/... and data contains the
|
// For example if you run go-bindata on data/... and data contains the
|
||||||
// following hierarchy:
|
// following hierarchy:
|
||||||
// data/
|
//
|
||||||
// foo.txt
|
// data/
|
||||||
// img/
|
// foo.txt
|
||||||
// a.png
|
// img/
|
||||||
// b.png
|
// a.png
|
||||||
|
// b.png
|
||||||
|
//
|
||||||
// then AssetDir("data") would return []string{"foo.txt", "img"},
|
// then AssetDir("data") would return []string{"foo.txt", "img"},
|
||||||
// AssetDir("data/img") would return []string{"a.png", "b.png"},
|
// AssetDir("data/img") would return []string{"a.png", "b.png"},
|
||||||
// AssetDir("foo.txt") and AssetDir("notexist") would return an error, and
|
// AssetDir("foo.txt") and AssetDir("notexist") would return an error, and
|
||||||
|
@ -339,12 +360,13 @@ type bintree struct {
|
||||||
}
|
}
|
||||||
|
|
||||||
var _bintree = &bintree{nil, map[string]*bintree{
|
var _bintree = &bintree{nil, map[string]*bintree{
|
||||||
"1691753758_initial.up.sql": &bintree{_1691753758_initialUpSql, map[string]*bintree{}},
|
"1691753758_initial.up.sql": {_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{}},
|
"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": &bintree{_1692701339_add_scope_to_pendingUpSql, 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": &bintree{_1694540071_add_collectibles_ownership_update_timestampUpSql, 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": &bintree{_1694692748_add_raw_balance_to_token_balancesUpSql, map[string]*bintree{}},
|
"1694692748_add_raw_balance_to_token_balances.up.sql": {_1694692748_add_raw_balance_to_token_balancesUpSql, map[string]*bintree{}},
|
||||||
"doc.go": &bintree{docGo, 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{}},
|
||||||
|
"doc.go": {docGo, map[string]*bintree{}},
|
||||||
}}
|
}}
|
||||||
|
|
||||||
// RestoreAsset restores an asset under the given directory.
|
// RestoreAsset restores an asset under the given directory.
|
||||||
|
@ -361,7 +383,7 @@ func RestoreAsset(dir, name string) error {
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
err = ioutil.WriteFile(_filePath(dir, name), data, info.Mode())
|
err = os.WriteFile(_filePath(dir, name), data, info.Mode())
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,5 @@
|
||||||
|
ALTER TABLE collectible_data_cache ADD COLUMN community_id TEXT NOT NULL DEFAULT "";
|
||||||
|
UPDATE collectible_data_cache SET community_id = "";
|
||||||
|
|
||||||
|
ALTER TABLE collection_data_cache ADD COLUMN community_id TEXT NOT NULL DEFAULT "";
|
||||||
|
UPDATE collection_data_cache SET community_id = "";
|
Loading…
Reference in New Issue