chore: rework data structures to accomodate new providers
This commit is contained in:
parent
d535cd95f8
commit
c2ac108556
|
@ -550,7 +550,7 @@ func (s *Service) CanProvideCollectibleMetadata(id thirdparty.CollectibleUniqueI
|
|||
return ret, nil
|
||||
}
|
||||
|
||||
func (s *Service) FetchCollectibleMetadata(id thirdparty.CollectibleUniqueID, tokenURI string) (*thirdparty.CollectibleData, error) {
|
||||
func (s *Service) FetchCollectibleMetadata(id thirdparty.CollectibleUniqueID, tokenURI string) (*thirdparty.FullCollectibleData, error) {
|
||||
if s.messenger == nil {
|
||||
return nil, fmt.Errorf("messenger not ready")
|
||||
}
|
||||
|
@ -573,13 +573,17 @@ func (s *Service) FetchCollectibleMetadata(id thirdparty.CollectibleUniqueID, to
|
|||
|
||||
for _, tokenMetadata := range tokensMetadata {
|
||||
contractAddresses := tokenMetadata.GetContractAddresses()
|
||||
if contractAddresses[uint64(id.ChainID)] == id.ContractAddress.Hex() {
|
||||
return &thirdparty.CollectibleData{
|
||||
ID: id,
|
||||
Name: tokenMetadata.GetName(),
|
||||
Description: tokenMetadata.GetDescription(),
|
||||
ImageURL: tokenMetadata.GetImage(),
|
||||
CollectionData: thirdparty.CollectionData{
|
||||
if contractAddresses[uint64(id.ContractID.ChainID)] == id.ContractID.Address.Hex() {
|
||||
return &thirdparty.FullCollectibleData{
|
||||
CollectibleData: thirdparty.CollectibleData{
|
||||
ID: id,
|
||||
Name: tokenMetadata.GetName(),
|
||||
Description: tokenMetadata.GetDescription(),
|
||||
ImageURL: tokenMetadata.GetImage(),
|
||||
TokenURI: tokenURI,
|
||||
},
|
||||
CollectionData: &thirdparty.CollectionData{
|
||||
ID: id.ContractID,
|
||||
Name: tokenMetadata.GetName(),
|
||||
ImageURL: tokenMetadata.GetImage(),
|
||||
},
|
||||
|
|
|
@ -316,10 +316,10 @@ func (api *API) FilterOwnedCollectiblesAsync(ctx context.Context, chainIDs []wco
|
|||
return nil
|
||||
}
|
||||
|
||||
func (api *API) GetCollectiblesDataAsync(ctx context.Context, uniqueIDs []thirdparty.CollectibleUniqueID) error {
|
||||
func (api *API) GetCollectiblesDetailsAsync(ctx context.Context, uniqueIDs []thirdparty.CollectibleUniqueID) error {
|
||||
log.Debug("wallet.api.GetCollectiblesDetailsAsync")
|
||||
|
||||
api.s.collectibles.GetCollectiblesDataAsync(ctx, uniqueIDs)
|
||||
api.s.collectibles.GetCollectiblesDetailsAsync(ctx, uniqueIDs)
|
||||
return nil
|
||||
}
|
||||
|
||||
|
@ -342,22 +342,22 @@ func (api *API) GetOpenseaAssetsByOwnerAndCollection(ctx context.Context, chainI
|
|||
return container.Assets, nil
|
||||
}
|
||||
|
||||
func (api *API) GetCollectiblesByOwnerAndCollectionWithCursor(ctx context.Context, chainID wcommon.ChainID, owner common.Address, collectionSlug string, cursor string, limit int) (*thirdparty.CollectibleDataContainer, error) {
|
||||
func (api *API) GetCollectiblesByOwnerAndCollectionWithCursor(ctx context.Context, chainID wcommon.ChainID, owner common.Address, collectionSlug string, cursor string, limit int) (*thirdparty.FullCollectibleDataContainer, error) {
|
||||
log.Debug("call to GetCollectiblesByOwnerAndCollectionWithCursor")
|
||||
return api.s.collectiblesManager.FetchAllAssetsByOwnerAndCollection(chainID, owner, collectionSlug, cursor, limit)
|
||||
}
|
||||
|
||||
func (api *API) GetCollectiblesByOwnerWithCursor(ctx context.Context, chainID wcommon.ChainID, owner common.Address, cursor string, limit int) (*thirdparty.CollectibleDataContainer, error) {
|
||||
func (api *API) GetCollectiblesByOwnerWithCursor(ctx context.Context, chainID wcommon.ChainID, owner common.Address, cursor string, limit int) (*thirdparty.FullCollectibleDataContainer, error) {
|
||||
log.Debug("call to GetCollectiblesByOwnerWithCursor")
|
||||
return api.s.collectiblesManager.FetchAllAssetsByOwner(chainID, owner, cursor, limit)
|
||||
}
|
||||
|
||||
func (api *API) GetCollectiblesByOwnerAndContractAddressWithCursor(ctx context.Context, chainID wcommon.ChainID, owner common.Address, contractAddresses []common.Address, cursor string, limit int) (*thirdparty.CollectibleDataContainer, error) {
|
||||
func (api *API) GetCollectiblesByOwnerAndContractAddressWithCursor(ctx context.Context, chainID wcommon.ChainID, owner common.Address, contractAddresses []common.Address, cursor string, limit int) (*thirdparty.FullCollectibleDataContainer, error) {
|
||||
log.Debug("call to GetCollectiblesByOwnerAndContractAddressWithCursor")
|
||||
return api.s.collectiblesManager.FetchAllAssetsByOwnerAndContractAddress(chainID, owner, contractAddresses, cursor, limit)
|
||||
}
|
||||
|
||||
func (api *API) GetCollectiblesByUniqueID(ctx context.Context, uniqueIDs []thirdparty.CollectibleUniqueID) ([]thirdparty.CollectibleData, error) {
|
||||
func (api *API) GetCollectiblesByUniqueID(ctx context.Context, uniqueIDs []thirdparty.CollectibleUniqueID) ([]thirdparty.FullCollectibleData, error) {
|
||||
log.Debug("call to GetCollectiblesByUniqueID")
|
||||
return api.s.collectiblesManager.FetchAssetsByCollectibleUniqueID(uniqueIDs)
|
||||
}
|
||||
|
|
|
@ -40,8 +40,10 @@ type Manager struct {
|
|||
fallbackContractOwnershipProvider thirdparty.CollectibleContractOwnershipProvider
|
||||
metadataProvider thirdparty.CollectibleMetadataProvider
|
||||
opensea *opensea.Client
|
||||
nftCache map[walletCommon.ChainID]map[string]thirdparty.CollectibleData
|
||||
nftCacheLock sync.RWMutex
|
||||
collectiblesDataCache map[string]thirdparty.CollectibleData
|
||||
collectiblesDataCacheLock sync.RWMutex
|
||||
collectionsDataCache map[string]thirdparty.CollectionData
|
||||
collectionsDataCacheLock sync.RWMutex
|
||||
}
|
||||
|
||||
func NewManager(rpcClient *rpc.Client, mainContractOwnershipProvider thirdparty.CollectibleContractOwnershipProvider, fallbackContractOwnershipProvider thirdparty.CollectibleContractOwnershipProvider, opensea *opensea.Client) *Manager {
|
||||
|
@ -57,7 +59,8 @@ func NewManager(rpcClient *rpc.Client, mainContractOwnershipProvider thirdparty.
|
|||
mainContractOwnershipProvider: mainContractOwnershipProvider,
|
||||
fallbackContractOwnershipProvider: fallbackContractOwnershipProvider,
|
||||
opensea: opensea,
|
||||
nftCache: make(map[walletCommon.ChainID]map[string]thirdparty.CollectibleData),
|
||||
collectiblesDataCache: make(map[string]thirdparty.CollectibleData),
|
||||
collectionsDataCache: make(map[string]thirdparty.CollectionData),
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -103,13 +106,13 @@ func (o *Manager) FetchAllOpenseaAssetsByOwnerAndCollection(chainID walletCommon
|
|||
return o.opensea.FetchAllOpenseaAssetsByOwnerAndCollection(chainID, owner, collectionSlug, cursor, limit)
|
||||
}
|
||||
|
||||
func (o *Manager) FetchAllAssetsByOwnerAndCollection(chainID walletCommon.ChainID, owner common.Address, collectionSlug string, cursor string, limit int) (*thirdparty.CollectibleDataContainer, error) {
|
||||
func (o *Manager) FetchAllAssetsByOwnerAndCollection(chainID walletCommon.ChainID, owner common.Address, collectionSlug string, cursor string, limit int) (*thirdparty.FullCollectibleDataContainer, error) {
|
||||
assetContainer, err := o.opensea.FetchAllAssetsByOwnerAndCollection(chainID, owner, collectionSlug, cursor, limit)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
err = o.processAssets(assetContainer.Collectibles)
|
||||
err = o.processFullCollectibleData(assetContainer.Items)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
@ -127,7 +130,7 @@ func (o *Manager) FetchBalancesByOwnerAndContractAddress(chainID walletCommon.Ch
|
|||
|
||||
// Try with more direct endpoint first (OpenSea)
|
||||
assetsContainer, err := o.FetchAllAssetsByOwnerAndContractAddress(chainID, ownerAddress, contractAddresses, FetchFromStartCursor, FetchNoLimit)
|
||||
if err == opensea.ErrChainIDNotSupported {
|
||||
if err == thirdparty.ErrChainIDNotSupported {
|
||||
// Use contract ownership providers
|
||||
for _, contractAddress := range contractAddresses {
|
||||
ownership, err := o.FetchCollectibleOwnersByContractAddress(chainID, contractAddress)
|
||||
|
@ -143,10 +146,10 @@ func (o *Manager) FetchBalancesByOwnerAndContractAddress(chainID walletCommon.Ch
|
|||
}
|
||||
} else if err == nil {
|
||||
// OpenSea could provide
|
||||
for _, collectible := range assetsContainer.Collectibles {
|
||||
contractAddress := collectible.ID.ContractAddress
|
||||
for _, fullData := range assetsContainer.Items {
|
||||
contractAddress := fullData.CollectibleData.ID.ContractID.Address
|
||||
balance := thirdparty.TokenBalance{
|
||||
TokenID: collectible.ID.TokenID,
|
||||
TokenID: fullData.CollectibleData.ID.TokenID,
|
||||
Balance: &bigint.BigInt{Int: big.NewInt(1)},
|
||||
}
|
||||
ret[contractAddress] = append(ret[contractAddress], balance)
|
||||
|
@ -159,13 +162,13 @@ func (o *Manager) FetchBalancesByOwnerAndContractAddress(chainID walletCommon.Ch
|
|||
return ret, nil
|
||||
}
|
||||
|
||||
func (o *Manager) FetchAllAssetsByOwnerAndContractAddress(chainID walletCommon.ChainID, owner common.Address, contractAddresses []common.Address, cursor string, limit int) (*thirdparty.CollectibleDataContainer, error) {
|
||||
func (o *Manager) FetchAllAssetsByOwnerAndContractAddress(chainID walletCommon.ChainID, owner common.Address, contractAddresses []common.Address, cursor string, limit int) (*thirdparty.FullCollectibleDataContainer, error) {
|
||||
assetContainer, err := o.opensea.FetchAllAssetsByOwnerAndContractAddress(chainID, owner, contractAddresses, cursor, limit)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
err = o.processAssets(assetContainer.Collectibles)
|
||||
err = o.processFullCollectibleData(assetContainer.Items)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
@ -173,13 +176,13 @@ func (o *Manager) FetchAllAssetsByOwnerAndContractAddress(chainID walletCommon.C
|
|||
return assetContainer, nil
|
||||
}
|
||||
|
||||
func (o *Manager) FetchAllAssetsByOwner(chainID walletCommon.ChainID, owner common.Address, cursor string, limit int) (*thirdparty.CollectibleDataContainer, error) {
|
||||
func (o *Manager) FetchAllAssetsByOwner(chainID walletCommon.ChainID, owner common.Address, cursor string, limit int) (*thirdparty.FullCollectibleDataContainer, error) {
|
||||
assetContainer, err := o.opensea.FetchAllAssetsByOwner(chainID, owner, cursor, limit)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
err = o.processAssets(assetContainer.Collectibles)
|
||||
err = o.processFullCollectibleData(assetContainer.Items)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
@ -188,17 +191,18 @@ func (o *Manager) FetchAllAssetsByOwner(chainID walletCommon.ChainID, owner comm
|
|||
}
|
||||
|
||||
func (o *Manager) FetchCollectibleOwnershipByOwner(chainID walletCommon.ChainID, owner common.Address, cursor string, limit int) (*thirdparty.CollectibleOwnershipContainer, error) {
|
||||
// We don't yet have an API that will return only Ownership data
|
||||
// Use the full Ownership + Metadata endpoint and use the data we need
|
||||
assetContainer, err := o.FetchAllAssetsByOwner(chainID, owner, cursor, limit)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
ret := assetContainer.ToOwnershipContainer()
|
||||
|
||||
return &ret, nil
|
||||
}
|
||||
|
||||
func (o *Manager) FetchAssetsByCollectibleUniqueID(uniqueIDs []thirdparty.CollectibleUniqueID) ([]thirdparty.CollectibleData, error) {
|
||||
func (o *Manager) FetchAssetsByCollectibleUniqueID(uniqueIDs []thirdparty.CollectibleUniqueID) ([]thirdparty.FullCollectibleData, error) {
|
||||
idsToFetch := o.getIDsNotInCollectiblesDataCache(uniqueIDs)
|
||||
if len(idsToFetch) > 0 {
|
||||
fetchedAssets, err := o.opensea.FetchAssetsByCollectibleUniqueID(idsToFetch)
|
||||
|
@ -206,14 +210,13 @@ func (o *Manager) FetchAssetsByCollectibleUniqueID(uniqueIDs []thirdparty.Collec
|
|||
return nil, err
|
||||
}
|
||||
|
||||
err = o.processAssets(fetchedAssets)
|
||||
err = o.processFullCollectibleData(fetchedAssets)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
return o.getCacheCollectiblesData(uniqueIDs), nil
|
||||
return o.getCacheFullCollectibleData(uniqueIDs), nil
|
||||
}
|
||||
|
||||
func (o *Manager) FetchCollectibleOwnersByContractAddress(chainID walletCommon.ChainID, contractAddress common.Address) (*thirdparty.CollectibleContractOwnership, error) {
|
||||
|
@ -242,12 +245,12 @@ func isMetadataEmpty(asset thirdparty.CollectibleData) bool {
|
|||
}
|
||||
|
||||
func (o *Manager) fetchTokenURI(id thirdparty.CollectibleUniqueID) (string, error) {
|
||||
backend, err := o.rpcClient.EthClient(uint64(id.ChainID))
|
||||
backend, err := o.rpcClient.EthClient(uint64(id.ContractID.ChainID))
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
caller, err := collectibles.NewCollectiblesCaller(id.ContractAddress, backend)
|
||||
caller, err := collectibles.NewCollectiblesCaller(id.ContractID.Address, backend)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
@ -272,11 +275,11 @@ func (o *Manager) fetchTokenURI(id thirdparty.CollectibleUniqueID) (string, erro
|
|||
return tokenURI, err
|
||||
}
|
||||
|
||||
func (o *Manager) processAssets(assets []thirdparty.CollectibleData) error {
|
||||
func (o *Manager) processFullCollectibleData(assets []thirdparty.FullCollectibleData) error {
|
||||
for idx, asset := range assets {
|
||||
id := asset.ID
|
||||
id := asset.CollectibleData.ID
|
||||
|
||||
if isMetadataEmpty(asset) {
|
||||
if isMetadataEmpty(asset.CollectibleData) {
|
||||
if o.metadataProvider == nil {
|
||||
return fmt.Errorf("CollectibleMetadataProvider not available")
|
||||
}
|
||||
|
@ -286,7 +289,7 @@ func (o *Manager) processAssets(assets []thirdparty.CollectibleData) error {
|
|||
return err
|
||||
}
|
||||
|
||||
assets[idx].TokenURI = tokenURI
|
||||
assets[idx].CollectibleData.TokenURI = tokenURI
|
||||
|
||||
canProvide, err := o.metadataProvider.CanProvideCollectibleMetadata(id, tokenURI)
|
||||
|
||||
|
@ -306,21 +309,21 @@ func (o *Manager) processAssets(assets []thirdparty.CollectibleData) error {
|
|||
}
|
||||
}
|
||||
|
||||
o.setCacheCollectibleData(assets[idx])
|
||||
o.setCacheCollectibleData(assets[idx].CollectibleData)
|
||||
if assets[idx].CollectionData != nil {
|
||||
o.setCacheCollectionData(*assets[idx].CollectionData)
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (o *Manager) isIDInCollectiblesDataCache(id thirdparty.CollectibleUniqueID) bool {
|
||||
o.nftCacheLock.RLock()
|
||||
defer o.nftCacheLock.RUnlock()
|
||||
if _, ok := o.nftCache[id.ChainID]; ok {
|
||||
if _, ok := o.nftCache[id.ChainID][id.HashKey()]; ok {
|
||||
return true
|
||||
}
|
||||
o.collectiblesDataCacheLock.RLock()
|
||||
defer o.collectiblesDataCacheLock.RUnlock()
|
||||
if _, ok := o.collectiblesDataCache[id.HashKey()]; ok {
|
||||
return true
|
||||
}
|
||||
|
||||
return false
|
||||
}
|
||||
|
||||
|
@ -335,35 +338,94 @@ func (o *Manager) getIDsNotInCollectiblesDataCache(uniqueIDs []thirdparty.Collec
|
|||
return idsToFetch
|
||||
}
|
||||
|
||||
func (o *Manager) getCacheCollectiblesData(uniqueIDs []thirdparty.CollectibleUniqueID) []thirdparty.CollectibleData {
|
||||
o.nftCacheLock.RLock()
|
||||
defer o.nftCacheLock.RUnlock()
|
||||
func (o *Manager) getCacheCollectiblesData(uniqueIDs []thirdparty.CollectibleUniqueID) map[string]*thirdparty.CollectibleData {
|
||||
o.collectiblesDataCacheLock.RLock()
|
||||
defer o.collectiblesDataCacheLock.RUnlock()
|
||||
|
||||
assets := make([]thirdparty.CollectibleData, 0, len(uniqueIDs))
|
||||
collectibles := make(map[string]*thirdparty.CollectibleData)
|
||||
for _, id := range uniqueIDs {
|
||||
if _, ok := o.nftCache[id.ChainID]; ok {
|
||||
if asset, ok := o.nftCache[id.ChainID][id.HashKey()]; ok {
|
||||
assets = append(assets, asset)
|
||||
continue
|
||||
}
|
||||
if collectible, ok := o.collectiblesDataCache[id.HashKey()]; ok {
|
||||
collectibles[id.HashKey()] = &collectible
|
||||
continue
|
||||
}
|
||||
emptyAsset := thirdparty.CollectibleData{
|
||||
ID: id,
|
||||
}
|
||||
assets = append(assets, emptyAsset)
|
||||
}
|
||||
return assets
|
||||
return collectibles
|
||||
}
|
||||
|
||||
func (o *Manager) setCacheCollectibleData(data thirdparty.CollectibleData) {
|
||||
o.nftCacheLock.Lock()
|
||||
defer o.nftCacheLock.Unlock()
|
||||
o.collectiblesDataCacheLock.Lock()
|
||||
defer o.collectiblesDataCacheLock.Unlock()
|
||||
|
||||
id := data.ID
|
||||
o.collectiblesDataCache[data.ID.HashKey()] = data
|
||||
}
|
||||
|
||||
if _, ok := o.nftCache[id.ChainID]; !ok {
|
||||
o.nftCache[id.ChainID] = make(map[string]thirdparty.CollectibleData)
|
||||
func (o *Manager) isIDInContractDataCache(id thirdparty.ContractID) bool {
|
||||
o.collectionsDataCacheLock.RLock()
|
||||
defer o.collectionsDataCacheLock.RUnlock()
|
||||
if _, ok := o.collectionsDataCache[id.HashKey()]; ok {
|
||||
return true
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
func (o *Manager) getIDsNotInContractDataCache(ids []thirdparty.ContractID) []thirdparty.ContractID {
|
||||
idsToFetch := make([]thirdparty.ContractID, 0, len(ids))
|
||||
for _, id := range ids {
|
||||
if o.isIDInContractDataCache(id) {
|
||||
continue
|
||||
}
|
||||
idsToFetch = append(idsToFetch, id)
|
||||
}
|
||||
return idsToFetch
|
||||
}
|
||||
|
||||
func (o *Manager) getCacheCollectionData(ids []thirdparty.ContractID) map[string]*thirdparty.CollectionData {
|
||||
o.collectionsDataCacheLock.RLock()
|
||||
defer o.collectionsDataCacheLock.RUnlock()
|
||||
|
||||
collections := make(map[string]*thirdparty.CollectionData)
|
||||
for _, id := range ids {
|
||||
if collection, ok := o.collectionsDataCache[id.HashKey()]; ok {
|
||||
collections[id.HashKey()] = &collection
|
||||
continue
|
||||
}
|
||||
}
|
||||
return collections
|
||||
}
|
||||
|
||||
func (o *Manager) setCacheCollectionData(data thirdparty.CollectionData) {
|
||||
o.collectionsDataCacheLock.Lock()
|
||||
defer o.collectionsDataCacheLock.Unlock()
|
||||
|
||||
o.collectionsDataCache[data.ID.HashKey()] = data
|
||||
}
|
||||
|
||||
func (o *Manager) getCacheFullCollectibleData(uniqueIDs []thirdparty.CollectibleUniqueID) []thirdparty.FullCollectibleData {
|
||||
ret := make([]thirdparty.FullCollectibleData, 0, len(uniqueIDs))
|
||||
|
||||
collectiblesData := o.getCacheCollectiblesData(uniqueIDs)
|
||||
|
||||
contractIDs := make([]thirdparty.ContractID, 0, len(uniqueIDs))
|
||||
for _, id := range uniqueIDs {
|
||||
contractIDs = append(contractIDs, id.ContractID)
|
||||
}
|
||||
|
||||
o.nftCache[id.ChainID][id.HashKey()] = data
|
||||
collectionsData := o.getCacheCollectionData(contractIDs)
|
||||
|
||||
for _, id := range uniqueIDs {
|
||||
collectibleData := collectiblesData[id.HashKey()]
|
||||
if collectibleData == nil {
|
||||
// Use empty data, set only ID
|
||||
collectibleData = &thirdparty.CollectibleData{
|
||||
ID: id,
|
||||
}
|
||||
}
|
||||
|
||||
fullData := thirdparty.FullCollectibleData{
|
||||
CollectibleData: *collectibleData,
|
||||
CollectionData: collectionsData[id.ContractID.HashKey()],
|
||||
}
|
||||
ret = append(ret, fullData)
|
||||
}
|
||||
return ret
|
||||
}
|
||||
|
|
|
@ -154,9 +154,9 @@ func (c *loadOwnedCollectiblesCommand) Run(parent context.Context) (err error) {
|
|||
break
|
||||
}
|
||||
|
||||
log.Debug("partial loadOwnedCollectiblesCommand", "chain", c.chainID, "account", c.account, "page", pageNr, "found", len(partialOwnership.Collectibles), "collectibles")
|
||||
log.Debug("partial loadOwnedCollectiblesCommand", "chain", c.chainID, "account", c.account, "page", pageNr, "found", len(partialOwnership.Items), "collectibles")
|
||||
|
||||
c.partialOwnership = append(c.partialOwnership, partialOwnership.Collectibles...)
|
||||
c.partialOwnership = append(c.partialOwnership, partialOwnership.Items...)
|
||||
|
||||
pageNr++
|
||||
cursor = partialOwnership.NextCursor
|
||||
|
|
|
@ -54,7 +54,7 @@ func insertAddressOwnership(creator statementCreator, ownerAddress common.Addres
|
|||
}
|
||||
|
||||
for _, c := range collectibles {
|
||||
_, err = insertOwnership.Exec(c.ChainID, c.ContractAddress, (*bigint.SQLBigIntBytes)(c.TokenID.Int), ownerAddress)
|
||||
_, err = insertOwnership.Exec(c.ContractID.ChainID, c.ContractID.Address, (*bigint.SQLBigIntBytes)(c.TokenID.Int), ownerAddress)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
@ -101,8 +101,8 @@ func rowsToCollectibles(rows *sql.Rows) ([]thirdparty.CollectibleUniqueID, error
|
|||
TokenID: &bigint.BigInt{Int: big.NewInt(0)},
|
||||
}
|
||||
err := rows.Scan(
|
||||
&id.ChainID,
|
||||
&id.ContractAddress,
|
||||
&id.ContractID.ChainID,
|
||||
&id.ContractID.Address,
|
||||
(*bigint.SQLBigIntBytes)(id.TokenID.Int),
|
||||
)
|
||||
if err != nil {
|
||||
|
|
|
@ -27,9 +27,11 @@ func generateTestCollectibles(chainID w_common.ChainID, count int) (result []thi
|
|||
for i := 0; i < count; i++ {
|
||||
bigI := big.NewInt(int64(i))
|
||||
newCollectible := thirdparty.CollectibleUniqueID{
|
||||
ChainID: chainID,
|
||||
ContractAddress: common.BigToAddress(bigI),
|
||||
TokenID: &bigint.BigInt{Int: bigI},
|
||||
ContractID: thirdparty.ContractID{
|
||||
ChainID: chainID,
|
||||
Address: common.BigToAddress(bigI),
|
||||
},
|
||||
TokenID: &bigint.BigInt{Int: bigI},
|
||||
}
|
||||
result = append(result, newCollectible)
|
||||
}
|
||||
|
@ -98,9 +100,11 @@ func TestLargeTokenID(t *testing.T) {
|
|||
|
||||
ownedListChain := []thirdparty.CollectibleUniqueID{
|
||||
{
|
||||
ChainID: chainID,
|
||||
ContractAddress: common.HexToAddress("0x1234"),
|
||||
TokenID: &bigint.BigInt{Int: big.NewInt(0).SetBytes([]byte("0x1234567890123456789012345678901234567890"))},
|
||||
ContractID: thirdparty.ContractID{
|
||||
ChainID: chainID,
|
||||
Address: common.HexToAddress("0x1234"),
|
||||
},
|
||||
TokenID: &bigint.BigInt{Int: big.NewInt(0).SetBytes([]byte("0x1234567890123456789012345678901234567890"))},
|
||||
},
|
||||
}
|
||||
|
||||
|
|
|
@ -28,7 +28,7 @@ const (
|
|||
EventCollectiblesOwnershipUpdateFinishedWithError walletevent.EventType = "wallet-collectibles-ownership-update-finished-with-error"
|
||||
|
||||
EventOwnedCollectiblesFilteringDone walletevent.EventType = "wallet-owned-collectibles-filtering-done"
|
||||
EventGetCollectiblesDataDone walletevent.EventType = "wallet-get-collectibles-data-done"
|
||||
EventGetCollectiblesDetailsDone walletevent.EventType = "wallet-get-collectibles-details-done"
|
||||
)
|
||||
|
||||
var (
|
||||
|
@ -78,21 +78,21 @@ const (
|
|||
)
|
||||
|
||||
type FilterOwnedCollectiblesResponse struct {
|
||||
Collectibles []thirdparty.CollectibleHeader `json:"collectibles"`
|
||||
Offset int `json:"offset"`
|
||||
Collectibles []CollectibleHeader `json:"collectibles"`
|
||||
Offset int `json:"offset"`
|
||||
// Used to indicate that there might be more collectibles that were not returned
|
||||
// based on a simple heuristic
|
||||
HasMore bool `json:"hasMore"`
|
||||
ErrorCode ErrorCode `json:"errorCode"`
|
||||
}
|
||||
|
||||
type GetCollectiblesDataResponse struct {
|
||||
Collectibles []thirdparty.CollectibleData `json:"collectibles"`
|
||||
ErrorCode ErrorCode `json:"errorCode"`
|
||||
type GetCollectiblesDetailsResponse struct {
|
||||
Collectibles []CollectibleDetails `json:"collectibles"`
|
||||
ErrorCode ErrorCode `json:"errorCode"`
|
||||
}
|
||||
|
||||
type filterOwnedCollectiblesTaskReturnType struct {
|
||||
collectibles []thirdparty.CollectibleHeader
|
||||
collectibles []CollectibleHeader
|
||||
hasMore bool
|
||||
}
|
||||
|
||||
|
@ -111,7 +111,7 @@ func (s *Service) FilterOwnedCollectiblesAsync(ctx context.Context, chainIDs []w
|
|||
}
|
||||
|
||||
return filterOwnedCollectiblesTaskReturnType{
|
||||
collectibles: thirdparty.CollectiblesToHeaders(data),
|
||||
collectibles: fullCollectiblesDataToHeaders(data),
|
||||
hasMore: hasMore,
|
||||
}, err
|
||||
}, func(result interface{}, taskType async.TaskType, err error) {
|
||||
|
@ -133,24 +133,24 @@ func (s *Service) FilterOwnedCollectiblesAsync(ctx context.Context, chainIDs []w
|
|||
})
|
||||
}
|
||||
|
||||
func (s *Service) GetCollectiblesDataAsync(ctx context.Context, uniqueIDs []thirdparty.CollectibleUniqueID) {
|
||||
func (s *Service) GetCollectiblesDetailsAsync(ctx context.Context, uniqueIDs []thirdparty.CollectibleUniqueID) {
|
||||
s.scheduler.Enqueue(getCollectiblesDataTask, func(ctx context.Context) (interface{}, error) {
|
||||
collectibles, err := s.manager.FetchAssetsByCollectibleUniqueID(uniqueIDs)
|
||||
return collectibles, err
|
||||
}, func(result interface{}, taskType async.TaskType, err error) {
|
||||
res := GetCollectiblesDataResponse{
|
||||
res := GetCollectiblesDetailsResponse{
|
||||
ErrorCode: ErrorCodeFailed,
|
||||
}
|
||||
|
||||
if errors.Is(err, context.Canceled) || errors.Is(err, async.ErrTaskOverwritten) {
|
||||
res.ErrorCode = ErrorCodeTaskCanceled
|
||||
} else if err == nil {
|
||||
collectibles := result.([]thirdparty.CollectibleData)
|
||||
res.Collectibles = collectibles
|
||||
collectibles := result.([]thirdparty.FullCollectibleData)
|
||||
res.Collectibles = fullCollectiblesDataToDetails(collectibles)
|
||||
res.ErrorCode = ErrorCodeSuccess
|
||||
}
|
||||
|
||||
s.sendResponseEvent(EventGetCollectiblesDataDone, res, err)
|
||||
s.sendResponseEvent(EventGetCollectiblesDetailsDone, res, err)
|
||||
})
|
||||
}
|
||||
|
||||
|
|
|
@ -0,0 +1,83 @@
|
|||
package collectibles
|
||||
|
||||
import "github.com/status-im/status-go/services/wallet/thirdparty"
|
||||
|
||||
// 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"`
|
||||
}
|
||||
|
||||
// Combined Collection+Collectible info, used to display a basic view of a collectible in a list
|
||||
type CollectibleHeader struct {
|
||||
ID thirdparty.CollectibleUniqueID `json:"id"`
|
||||
Name string `json:"name"`
|
||||
ImageURL string `json:"image_url"`
|
||||
AnimationURL string `json:"animation_url"`
|
||||
AnimationMediaType string `json:"animation_media_type"`
|
||||
BackgroundColor string `json:"background_color"`
|
||||
CollectionName string `json:"collection_name"`
|
||||
}
|
||||
|
||||
func fullCollectibleDataToHeader(c thirdparty.FullCollectibleData) CollectibleHeader {
|
||||
ret := CollectibleHeader{
|
||||
ID: c.CollectibleData.ID,
|
||||
Name: c.CollectibleData.Name,
|
||||
ImageURL: c.CollectibleData.ImageURL,
|
||||
AnimationURL: c.CollectibleData.AnimationURL,
|
||||
AnimationMediaType: c.CollectibleData.AnimationMediaType,
|
||||
BackgroundColor: c.CollectibleData.BackgroundColor,
|
||||
}
|
||||
if c.CollectionData != nil {
|
||||
ret.CollectionName = c.CollectionData.Name
|
||||
}
|
||||
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 {
|
||||
ret := CollectibleDetails{
|
||||
ID: c.CollectibleData.ID,
|
||||
Name: c.CollectibleData.Name,
|
||||
Description: c.CollectibleData.Description,
|
||||
ImageURL: c.CollectibleData.ImageURL,
|
||||
AnimationURL: c.CollectibleData.AnimationURL,
|
||||
AnimationMediaType: c.CollectibleData.AnimationMediaType,
|
||||
BackgroundColor: c.CollectibleData.BackgroundColor,
|
||||
Traits: c.CollectibleData.Traits,
|
||||
}
|
||||
if c.CollectionData != nil {
|
||||
ret.CollectionName = c.CollectionData.Name
|
||||
ret.CollectionSlug = c.CollectionData.Slug
|
||||
ret.CollectionImageURL = c.CollectionData.ImageURL
|
||||
}
|
||||
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
|
||||
}
|
|
@ -33,7 +33,16 @@ func getBaseURL(chainID walletCommon.ChainID) (string, error) {
|
|||
return "https://arb-goerli.g.alchemy.com", nil
|
||||
}
|
||||
|
||||
return "", fmt.Errorf("chainID not supported: %d", chainID)
|
||||
return "", thirdparty.ErrChainIDNotSupported
|
||||
}
|
||||
|
||||
func (o *Client) ID() string {
|
||||
return "alchemy"
|
||||
}
|
||||
|
||||
func (o *Client) IsChainSupported(chainID walletCommon.ChainID) bool {
|
||||
_, err := getBaseURL(chainID)
|
||||
return err == nil
|
||||
}
|
||||
|
||||
func getAPIKeySubpath(apiKey string) string {
|
||||
|
@ -93,11 +102,6 @@ func (o *Client) doQuery(url string) (*http.Response, error) {
|
|||
return resp, nil
|
||||
}
|
||||
|
||||
func (o *Client) IsChainSupported(chainID walletCommon.ChainID) bool {
|
||||
_, err := getBaseURL(chainID)
|
||||
return err == nil
|
||||
}
|
||||
|
||||
func alchemyOwnershipToCommon(contractAddress common.Address, alchemyOwnership CollectibleContractOwnership) (*thirdparty.CollectibleContractOwnership, error) {
|
||||
owners := make([]thirdparty.CollectibleOwner, 0, len(alchemyOwnership.Owners))
|
||||
for _, alchemyOwner := range alchemyOwnership.Owners {
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
package thirdparty
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
|
||||
"github.com/ethereum/go-ethereum/common"
|
||||
|
@ -8,24 +9,41 @@ import (
|
|||
w_common "github.com/status-im/status-go/services/wallet/common"
|
||||
)
|
||||
|
||||
var (
|
||||
ErrChainIDNotSupported = errors.New("chainID not supported")
|
||||
)
|
||||
|
||||
type CollectibleProvider interface {
|
||||
ID() string
|
||||
IsChainSupported(chainID w_common.ChainID) bool
|
||||
}
|
||||
|
||||
type ContractID struct {
|
||||
ChainID w_common.ChainID `json:"chainID"`
|
||||
Address common.Address `json:"address"`
|
||||
}
|
||||
|
||||
func (k *ContractID) HashKey() string {
|
||||
return fmt.Sprintf("%d+%s", k.ChainID, k.Address.String())
|
||||
}
|
||||
|
||||
type CollectibleUniqueID struct {
|
||||
ChainID w_common.ChainID `json:"chainID"`
|
||||
ContractAddress common.Address `json:"contractAddress"`
|
||||
TokenID *bigint.BigInt `json:"tokenID"`
|
||||
ContractID ContractID `json:"contractID"`
|
||||
TokenID *bigint.BigInt `json:"tokenID"`
|
||||
}
|
||||
|
||||
func (k *CollectibleUniqueID) HashKey() string {
|
||||
return fmt.Sprintf("%d+%s+%s", k.ChainID, k.ContractAddress.String(), k.TokenID.String())
|
||||
return fmt.Sprintf("%s+%s", k.ContractID.HashKey(), k.TokenID.String())
|
||||
}
|
||||
|
||||
func GroupCollectibleUIDsByChainID(uids []CollectibleUniqueID) map[w_common.ChainID][]CollectibleUniqueID {
|
||||
ret := make(map[w_common.ChainID][]CollectibleUniqueID)
|
||||
|
||||
for _, uid := range uids {
|
||||
if _, ok := ret[uid.ChainID]; !ok {
|
||||
ret[uid.ChainID] = make([]CollectibleUniqueID, 0, len(uids))
|
||||
if _, ok := ret[uid.ContractID.ChainID]; !ok {
|
||||
ret[uid.ContractID.ChainID] = make([]CollectibleUniqueID, 0, len(uids))
|
||||
}
|
||||
ret[uid.ChainID] = append(ret[uid.ChainID], uid)
|
||||
ret[uid.ContractID.ChainID] = append(ret[uid.ContractID.ChainID], uid)
|
||||
}
|
||||
|
||||
return ret
|
||||
|
@ -36,7 +54,9 @@ type CollectionTrait struct {
|
|||
Max float64 `json:"max"`
|
||||
}
|
||||
|
||||
// Collection info
|
||||
type CollectionData struct {
|
||||
ID ContractID `json:"id"`
|
||||
Name string `json:"name"`
|
||||
Slug string `json:"slug"`
|
||||
ImageURL string `json:"image_url"`
|
||||
|
@ -50,6 +70,7 @@ type CollectibleTrait struct {
|
|||
MaxValue string `json:"max_value"`
|
||||
}
|
||||
|
||||
// Collectible info
|
||||
type CollectibleData struct {
|
||||
ID CollectibleUniqueID `json:"id"`
|
||||
Name string `json:"name"`
|
||||
|
@ -61,75 +82,46 @@ type CollectibleData struct {
|
|||
Traits []CollectibleTrait `json:"traits"`
|
||||
BackgroundColor string `json:"background_color"`
|
||||
TokenURI string `json:"token_uri"`
|
||||
CollectionData CollectionData `json:"collection_data"`
|
||||
}
|
||||
|
||||
type CollectibleHeader struct {
|
||||
ID CollectibleUniqueID `json:"id"`
|
||||
Name string `json:"name"`
|
||||
ImageURL string `json:"image_url"`
|
||||
AnimationURL string `json:"animation_url"`
|
||||
AnimationMediaType string `json:"animation_media_type"`
|
||||
BackgroundColor string `json:"background_color"`
|
||||
CollectionName string `json:"collection_name"`
|
||||
// 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
|
||||
}
|
||||
|
||||
type CollectibleOwnershipContainer struct {
|
||||
Collectibles []CollectibleUniqueID
|
||||
type CollectiblesContainer[T any] struct {
|
||||
Items []T
|
||||
NextCursor string
|
||||
PreviousCursor string
|
||||
}
|
||||
|
||||
type CollectibleDataContainer struct {
|
||||
Collectibles []CollectibleData
|
||||
NextCursor string
|
||||
PreviousCursor string
|
||||
}
|
||||
type CollectibleOwnershipContainer CollectiblesContainer[CollectibleUniqueID]
|
||||
type CollectionDataContainer CollectiblesContainer[CollectionData]
|
||||
type CollectibleDataContainer CollectiblesContainer[CollectibleData]
|
||||
type FullCollectibleDataContainer CollectiblesContainer[FullCollectibleData]
|
||||
|
||||
func (c *CollectibleDataContainer) ToOwnershipContainer() CollectibleOwnershipContainer {
|
||||
ret := CollectibleOwnershipContainer{
|
||||
Collectibles: make([]CollectibleUniqueID, 0, len(c.Collectibles)),
|
||||
NextCursor: c.NextCursor,
|
||||
PreviousCursor: c.PreviousCursor,
|
||||
// Tried to find a way to make this generic, but couldn't, so the code below is duplicated somewhere else
|
||||
func collectibleItemsToIDs(items []FullCollectibleData) []CollectibleUniqueID {
|
||||
ret := make([]CollectibleUniqueID, 0, len(items))
|
||||
for _, item := range items {
|
||||
ret = append(ret, item.CollectibleData.ID)
|
||||
}
|
||||
|
||||
for _, collectible := range c.Collectibles {
|
||||
ret.Collectibles = append(ret.Collectibles, collectible.ID)
|
||||
}
|
||||
|
||||
return ret
|
||||
}
|
||||
|
||||
func (c *CollectibleData) toHeader() CollectibleHeader {
|
||||
return CollectibleHeader{
|
||||
ID: c.ID,
|
||||
Name: c.Name,
|
||||
ImageURL: c.ImageURL,
|
||||
AnimationURL: c.AnimationURL,
|
||||
AnimationMediaType: c.AnimationMediaType,
|
||||
BackgroundColor: c.BackgroundColor,
|
||||
CollectionName: c.CollectionData.Name,
|
||||
func (c *FullCollectibleDataContainer) ToOwnershipContainer() CollectibleOwnershipContainer {
|
||||
return CollectibleOwnershipContainer{
|
||||
Items: collectibleItemsToIDs(c.Items),
|
||||
NextCursor: c.NextCursor,
|
||||
PreviousCursor: c.PreviousCursor,
|
||||
}
|
||||
}
|
||||
|
||||
func CollectiblesToHeaders(collectibles []CollectibleData) []CollectibleHeader {
|
||||
res := make([]CollectibleHeader, 0, len(collectibles))
|
||||
|
||||
for _, c := range collectibles {
|
||||
res = append(res, c.toHeader())
|
||||
}
|
||||
|
||||
return res
|
||||
}
|
||||
|
||||
type CollectibleOwnershipProvider interface {
|
||||
CanProvideAccountOwnership(chainID uint64) (bool, error)
|
||||
FetchAccountOwnership(chainID uint64, address common.Address) (*CollectibleData, error)
|
||||
}
|
||||
|
||||
type CollectibleMetadataProvider interface {
|
||||
CanProvideCollectibleMetadata(id CollectibleUniqueID, tokenURI string) (bool, error)
|
||||
FetchCollectibleMetadata(id CollectibleUniqueID, tokenURI string) (*CollectibleData, error)
|
||||
FetchCollectibleMetadata(id CollectibleUniqueID, tokenURI string) (*FullCollectibleData, error)
|
||||
}
|
||||
|
||||
type TokenBalance struct {
|
||||
|
|
|
@ -63,6 +63,10 @@ func (o *Client) doQuery(url string) (*http.Response, error) {
|
|||
return resp, nil
|
||||
}
|
||||
|
||||
func (o *Client) ID() string {
|
||||
return "infura"
|
||||
}
|
||||
|
||||
func (o *Client) IsChainSupported(chainID walletCommon.ChainID) bool {
|
||||
switch uint64(chainID) {
|
||||
case walletCommon.EthereumMainnet, walletCommon.EthereumGoerli, walletCommon.EthereumSepolia, walletCommon.ArbitrumMainnet:
|
||||
|
|
|
@ -2,7 +2,6 @@ package opensea
|
|||
|
||||
import (
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"net/http"
|
||||
|
@ -41,13 +40,9 @@ const ChainIDRequiringAPIKey = walletCommon.EthereumMainnet
|
|||
|
||||
const FetchNoLimit = 0
|
||||
|
||||
var (
|
||||
ErrChainIDNotSupported = errors.New("chainID not supported by opensea API")
|
||||
)
|
||||
|
||||
type urlGetter func(walletCommon.ChainID, string) (string, error)
|
||||
|
||||
func getbaseURL(chainID walletCommon.ChainID) (string, error) {
|
||||
func getBaseURL(chainID walletCommon.ChainID) (string, error) {
|
||||
// v1 Endpoints only support L1 chain
|
||||
switch uint64(chainID) {
|
||||
case walletCommon.EthereumMainnet:
|
||||
|
@ -56,11 +51,20 @@ func getbaseURL(chainID walletCommon.ChainID) (string, error) {
|
|||
return "https://testnets-api.opensea.io/api/v1", nil
|
||||
}
|
||||
|
||||
return "", ErrChainIDNotSupported
|
||||
return "", thirdparty.ErrChainIDNotSupported
|
||||
}
|
||||
|
||||
func (o *Client) ID() string {
|
||||
return "opensea"
|
||||
}
|
||||
|
||||
func (o *Client) IsChainSupported(chainID walletCommon.ChainID) bool {
|
||||
_, err := getBaseURL(chainID)
|
||||
return err == nil
|
||||
}
|
||||
|
||||
func getURL(chainID walletCommon.ChainID, path string) (string, error) {
|
||||
baseURL, err := getbaseURL(chainID)
|
||||
baseURL, err := getBaseURL(chainID)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
@ -182,9 +186,11 @@ type OwnedCollection struct {
|
|||
|
||||
func (c *Asset) id() thirdparty.CollectibleUniqueID {
|
||||
return thirdparty.CollectibleUniqueID{
|
||||
ChainID: chainStringToChainID(c.Contract.ChainIdentifier),
|
||||
ContractAddress: common.HexToAddress(c.Contract.Address),
|
||||
TokenID: c.TokenID,
|
||||
ContractID: thirdparty.ContractID{
|
||||
ChainID: chainStringToChainID(c.Contract.ChainIdentifier),
|
||||
Address: common.HexToAddress(c.Contract.Address),
|
||||
},
|
||||
TokenID: c.TokenID,
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -204,14 +210,15 @@ func openseaToCollectibleTraits(traits []Trait) []thirdparty.CollectibleTrait {
|
|||
return ret
|
||||
}
|
||||
|
||||
func (c *Collection) toCommon() thirdparty.CollectionData {
|
||||
func (c *Asset) toCollectionData() thirdparty.CollectionData {
|
||||
ret := thirdparty.CollectionData{
|
||||
Name: c.Name,
|
||||
Slug: c.Slug,
|
||||
ImageURL: c.ImageURL,
|
||||
ID: c.id().ContractID,
|
||||
Name: c.Collection.Name,
|
||||
Slug: c.Collection.Slug,
|
||||
ImageURL: c.Collection.ImageURL,
|
||||
Traits: make(map[string]thirdparty.CollectionTrait),
|
||||
}
|
||||
for traitType, trait := range c.Traits {
|
||||
for traitType, trait := range c.Collection.Traits {
|
||||
ret.Traits[traitType] = thirdparty.CollectionTrait{
|
||||
Min: trait.Min,
|
||||
Max: trait.Max,
|
||||
|
@ -220,7 +227,7 @@ func (c *Collection) toCommon() thirdparty.CollectionData {
|
|||
return ret
|
||||
}
|
||||
|
||||
func (c *Asset) toCommon() thirdparty.CollectibleData {
|
||||
func (c *Asset) toCollectiblesData() thirdparty.CollectibleData {
|
||||
return thirdparty.CollectibleData{
|
||||
ID: c.id(),
|
||||
Name: c.Name,
|
||||
|
@ -232,7 +239,14 @@ func (c *Asset) toCommon() thirdparty.CollectibleData {
|
|||
Traits: openseaToCollectibleTraits(c.Traits),
|
||||
BackgroundColor: c.BackgroundColor,
|
||||
TokenURI: c.TokenURI,
|
||||
CollectionData: c.Collection.toCommon(),
|
||||
}
|
||||
}
|
||||
|
||||
func (c *Asset) toCommon() thirdparty.FullCollectibleData {
|
||||
collection := c.toCollectionData()
|
||||
return thirdparty.FullCollectibleData{
|
||||
CollectibleData: c.toCollectiblesData(),
|
||||
CollectionData: &collection,
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -386,7 +400,7 @@ func (o *Client) FetchAllCollectionsByOwner(chainID walletCommon.ChainID, owner
|
|||
return collections, nil
|
||||
}
|
||||
|
||||
func (o *Client) FetchAllAssetsByOwnerAndCollection(chainID walletCommon.ChainID, owner common.Address, collectionSlug string, cursor string, limit int) (*thirdparty.CollectibleDataContainer, error) {
|
||||
func (o *Client) FetchAllAssetsByOwnerAndCollection(chainID walletCommon.ChainID, owner common.Address, collectionSlug string, cursor string, limit int) (*thirdparty.FullCollectibleDataContainer, error) {
|
||||
queryParams := url.Values{
|
||||
"owner": {owner.String()},
|
||||
"collection": {collectionSlug},
|
||||
|
@ -399,7 +413,7 @@ func (o *Client) FetchAllAssetsByOwnerAndCollection(chainID walletCommon.ChainID
|
|||
return o.fetchAssets(chainID, queryParams, limit)
|
||||
}
|
||||
|
||||
func (o *Client) FetchAllAssetsByOwnerAndContractAddress(chainID walletCommon.ChainID, owner common.Address, contractAddresses []common.Address, cursor string, limit int) (*thirdparty.CollectibleDataContainer, error) {
|
||||
func (o *Client) FetchAllAssetsByOwnerAndContractAddress(chainID walletCommon.ChainID, owner common.Address, contractAddresses []common.Address, cursor string, limit int) (*thirdparty.FullCollectibleDataContainer, error) {
|
||||
queryParams := url.Values{
|
||||
"owner": {owner.String()},
|
||||
}
|
||||
|
@ -415,7 +429,7 @@ func (o *Client) FetchAllAssetsByOwnerAndContractAddress(chainID walletCommon.Ch
|
|||
return o.fetchAssets(chainID, queryParams, limit)
|
||||
}
|
||||
|
||||
func (o *Client) FetchAllAssetsByOwner(chainID walletCommon.ChainID, owner common.Address, cursor string, limit int) (*thirdparty.CollectibleDataContainer, error) {
|
||||
func (o *Client) FetchAllAssetsByOwner(chainID walletCommon.ChainID, owner common.Address, cursor string, limit int) (*thirdparty.FullCollectibleDataContainer, error) {
|
||||
queryParams := url.Values{
|
||||
"owner": {owner.String()},
|
||||
}
|
||||
|
@ -427,16 +441,16 @@ func (o *Client) FetchAllAssetsByOwner(chainID walletCommon.ChainID, owner commo
|
|||
return o.fetchAssets(chainID, queryParams, limit)
|
||||
}
|
||||
|
||||
func (o *Client) FetchAssetsByCollectibleUniqueID(uniqueIDs []thirdparty.CollectibleUniqueID) ([]thirdparty.CollectibleData, error) {
|
||||
func (o *Client) FetchAssetsByCollectibleUniqueID(uniqueIDs []thirdparty.CollectibleUniqueID) ([]thirdparty.FullCollectibleData, error) {
|
||||
queryParams := url.Values{}
|
||||
|
||||
ret := make([]thirdparty.CollectibleData, 0, len(uniqueIDs))
|
||||
ret := make([]thirdparty.FullCollectibleData, 0, len(uniqueIDs))
|
||||
|
||||
idsPerChainID := thirdparty.GroupCollectibleUIDsByChainID(uniqueIDs)
|
||||
for chainID, ids := range idsPerChainID {
|
||||
for _, id := range ids {
|
||||
queryParams.Add("token_ids", id.TokenID.String())
|
||||
queryParams.Add("asset_contract_addresses", id.ContractAddress.String())
|
||||
queryParams.Add("asset_contract_addresses", id.ContractID.Address.String())
|
||||
}
|
||||
|
||||
data, err := o.fetchAssets(chainID, queryParams, FetchNoLimit)
|
||||
|
@ -444,14 +458,14 @@ func (o *Client) FetchAssetsByCollectibleUniqueID(uniqueIDs []thirdparty.Collect
|
|||
return nil, err
|
||||
}
|
||||
|
||||
ret = append(ret, data.Collectibles...)
|
||||
ret = append(ret, data.Items...)
|
||||
}
|
||||
|
||||
return ret, nil
|
||||
}
|
||||
|
||||
func (o *Client) fetchAssets(chainID walletCommon.ChainID, queryParams url.Values, limit int) (*thirdparty.CollectibleDataContainer, error) {
|
||||
assets := new(thirdparty.CollectibleDataContainer)
|
||||
func (o *Client) fetchAssets(chainID walletCommon.ChainID, queryParams url.Values, limit int) (*thirdparty.FullCollectibleDataContainer, error) {
|
||||
assets := new(thirdparty.FullCollectibleDataContainer)
|
||||
|
||||
if len(queryParams["cursor"]) > 0 {
|
||||
assets.PreviousCursor = queryParams["cursor"][0]
|
||||
|
@ -495,7 +509,7 @@ func (o *Client) fetchAssets(chainID walletCommon.ChainID, queryParams url.Value
|
|||
asset.AnimationURL = ""
|
||||
}
|
||||
}
|
||||
assets.Collectibles = append(assets.Collectibles, asset.toCommon())
|
||||
assets.Items = append(assets.Items, asset.toCommon())
|
||||
}
|
||||
assets.NextCursor = container.NextCursor
|
||||
|
||||
|
@ -505,7 +519,7 @@ func (o *Client) fetchAssets(chainID walletCommon.ChainID, queryParams url.Value
|
|||
|
||||
queryParams["cursor"] = []string{assets.NextCursor}
|
||||
|
||||
if limit > FetchNoLimit && len(assets.Collectibles) >= limit {
|
||||
if limit > FetchNoLimit && len(assets.Items) >= limit {
|
||||
break
|
||||
}
|
||||
}
|
||||
|
@ -539,7 +553,7 @@ func (o *Client) fetchOpenseaAssets(chainID walletCommon.ChainID, queryParams ur
|
|||
tmpLimit = limit
|
||||
}
|
||||
|
||||
baseURL, err := getbaseURL(chainID)
|
||||
baseURL, err := getBaseURL(chainID)
|
||||
|
||||
if err != nil {
|
||||
return nil, err
|
||||
|
|
|
@ -106,23 +106,33 @@ func TestFetchAllAssetsByOwnerAndCollection(t *testing.T) {
|
|||
NextCursor: "",
|
||||
PreviousCursor: "",
|
||||
}
|
||||
expectedCommon := thirdparty.CollectibleDataContainer{
|
||||
Collectibles: []thirdparty.CollectibleData{{
|
||||
ID: thirdparty.CollectibleUniqueID{
|
||||
ChainID: 1,
|
||||
ContractAddress: common.HexToAddress("0x1"),
|
||||
TokenID: &bigint.BigInt{Int: big.NewInt(1)},
|
||||
expectedCommon := thirdparty.FullCollectibleDataContainer{
|
||||
Items: []thirdparty.FullCollectibleData{
|
||||
thirdparty.FullCollectibleData{
|
||||
CollectibleData: thirdparty.CollectibleData{
|
||||
ID: thirdparty.CollectibleUniqueID{
|
||||
ContractID: thirdparty.ContractID{
|
||||
ChainID: 1,
|
||||
Address: common.HexToAddress("0x1"),
|
||||
},
|
||||
TokenID: &bigint.BigInt{Int: big.NewInt(1)},
|
||||
},
|
||||
Name: "Rocky",
|
||||
Description: "Rocky Balboa",
|
||||
Permalink: "permalink",
|
||||
ImageURL: "ImageUrl",
|
||||
Traits: []thirdparty.CollectibleTrait{},
|
||||
},
|
||||
CollectionData: &thirdparty.CollectionData{
|
||||
ID: thirdparty.ContractID{
|
||||
ChainID: 1,
|
||||
Address: common.HexToAddress("0x1"),
|
||||
},
|
||||
Name: "Rocky",
|
||||
Traits: map[string]thirdparty.CollectionTrait{},
|
||||
},
|
||||
},
|
||||
Name: "Rocky",
|
||||
Description: "Rocky Balboa",
|
||||
Permalink: "permalink",
|
||||
ImageURL: "ImageUrl",
|
||||
Traits: []thirdparty.CollectibleTrait{},
|
||||
CollectionData: thirdparty.CollectionData{
|
||||
Name: "Rocky",
|
||||
Traits: map[string]thirdparty.CollectionTrait{},
|
||||
},
|
||||
}},
|
||||
},
|
||||
NextCursor: "",
|
||||
PreviousCursor: "",
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue