chore: implement collectibles data db cache

This commit is contained in:
Dario Gabriel Lipicar 2023-08-07 15:02:32 -03:00 committed by dlipicar
parent 4fd94c2345
commit 33c116f7b1
16 changed files with 1118 additions and 361 deletions

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,51 @@
CREATE TABLE IF NOT EXISTS collectible_data_cache (
chain_id UNSIGNED BIGINT NOT NULL,
contract_address VARCHAR NOT NULL,
token_id BLOB NOT NULL,
provider VARCHAR NOT NULL,
name VARCHAR NOT NULL,
description VARCHAR NOT NULL,
permalink VARCHAR NOT NULL,
image_url VARCHAR NOT NULL,
animation_url VARCHAR NOT NULL,
animation_media_type VARCHAR NOT NULL,
background_color VARCHAR NOT NULL,
token_uri VARCHAR NOT NULL
);
CREATE UNIQUE INDEX IF NOT EXISTS collectible_data_identify_entry ON collectible_data_cache (chain_id, contract_address, token_id);
CREATE TABLE IF NOT EXISTS collectible_traits_cache (
chain_id UNSIGNED BIGINT NOT NULL,
contract_address VARCHAR NOT NULL,
token_id BLOB NOT NULL,
trait_type VARCHAR NOT NULL,
trait_value VARCHAR NOT NULL,
display_type VARCHAR NOT NULL,
max_value VARCHAR NOT NULL,
FOREIGN KEY(chain_id, contract_address, token_id) REFERENCES collectible_data_cache(chain_id, contract_address, token_id)
ON UPDATE CASCADE
ON DELETE CASCADE
);
CREATE TABLE IF NOT EXISTS collection_data_cache (
chain_id UNSIGNED BIGINT NOT NULL,
contract_address VARCHAR NOT NULL,
provider VARCHAR NOT NULL,
name VARCHAR NOT NULL,
slug VARCHAR NOT NULL,
image_url VARCHAR NOT NULL
);
CREATE UNIQUE INDEX IF NOT EXISTS collection_data_identify_entry ON collection_data_cache (chain_id, contract_address);
CREATE TABLE IF NOT EXISTS collection_traits_cache (
chain_id UNSIGNED BIGINT NOT NULL,
contract_address VARCHAR NOT NULL,
trait_type VARCHAR NOT NULL,
min REAL NOT NULL,
max REAL NOT NULL,
FOREIGN KEY(chain_id, contract_address) REFERENCES collection_data_cache(chain_id, contract_address)
ON UPDATE CASCADE
ON DELETE CASCADE
);

View file

@ -0,0 +1,252 @@
package collectibles
import (
"database/sql"
"fmt"
"math/big"
"github.com/status-im/status-go/services/wallet/bigint"
"github.com/status-im/status-go/services/wallet/thirdparty"
"github.com/status-im/status-go/sqlite"
)
type CollectibleDataDB struct {
db *sql.DB
}
func NewCollectibleDataDB(sqlDb *sql.DB) *CollectibleDataDB {
return &CollectibleDataDB{
db: sqlDb,
}
}
const collectibleDataColumns = "chain_id, contract_address, token_id, provider, name, description, permalink, image_url, animation_url, animation_media_type, background_color, token_uri"
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"
func rowsToCollectibleTraits(rows *sql.Rows) ([]thirdparty.CollectibleTrait, error) {
var traits []thirdparty.CollectibleTrait = make([]thirdparty.CollectibleTrait, 0)
for rows.Next() {
var trait thirdparty.CollectibleTrait
err := rows.Scan(
&trait.TraitType,
&trait.Value,
&trait.DisplayType,
&trait.MaxValue,
)
if err != nil {
return nil, err
}
traits = append(traits, trait)
}
return traits, nil
}
func getCollectibleTraits(creator sqlite.StatementCreator, id thirdparty.CollectibleUniqueID) ([]thirdparty.CollectibleTrait, error) {
// Get traits list
selectTraits, err := creator.Prepare(fmt.Sprintf(`SELECT %s
FROM collectible_traits_cache
WHERE chain_id = ? AND contract_address = ? AND token_id = ?`, selectCollectibleTraitsColumns))
if err != nil {
return nil, err
}
rows, err := selectTraits.Query(
id.ContractID.ChainID,
id.ContractID.Address,
(*bigint.SQLBigIntBytes)(id.TokenID.Int),
)
if err != nil {
return nil, err
}
return rowsToCollectibleTraits(rows)
}
func upsertCollectibleTraits(creator sqlite.StatementCreator, id thirdparty.CollectibleUniqueID, traits []thirdparty.CollectibleTrait) error {
// Remove old traits list
deleteTraits, err := creator.Prepare(`DELETE FROM collectible_traits_cache WHERE chain_id = ? AND contract_address = ? AND token_id = ?`)
if err != nil {
return err
}
_, err = deleteTraits.Exec(
id.ContractID.ChainID,
id.ContractID.Address,
(*bigint.SQLBigIntBytes)(id.TokenID.Int),
)
if err != nil {
return err
}
// Insert new traits list
insertTrait, err := creator.Prepare(fmt.Sprintf(`INSERT INTO collectible_traits_cache (%s)
VALUES (?, ?, ?, ?, ?, ?, ?)`, collectibleTraitsColumns))
if err != nil {
return err
}
for _, t := range traits {
_, err = insertTrait.Exec(
id.ContractID.ChainID,
id.ContractID.Address,
(*bigint.SQLBigIntBytes)(id.TokenID.Int),
t.TraitType,
t.Value,
t.DisplayType,
t.MaxValue,
)
if err != nil {
return err
}
}
return nil
}
func upsertCollectiblesData(creator sqlite.StatementCreator, collectibles []thirdparty.CollectibleData) error {
insertCollectible, err := creator.Prepare(fmt.Sprintf(`INSERT OR REPLACE INTO collectible_data_cache (%s)
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)`, collectibleDataColumns))
if err != nil {
return err
}
for _, c := range collectibles {
_, err = insertCollectible.Exec(
c.ID.ContractID.ChainID,
c.ID.ContractID.Address,
(*bigint.SQLBigIntBytes)(c.ID.TokenID.Int),
c.Provider,
c.Name,
c.Description,
c.Permalink,
c.ImageURL,
c.AnimationURL,
c.AnimationMediaType,
c.BackgroundColor,
c.TokenURI,
)
if err != nil {
return err
}
err = upsertCollectibleTraits(creator, c.ID, c.Traits)
if err != nil {
return err
}
}
return nil
}
func (o *CollectibleDataDB) SetData(collectibles []thirdparty.CollectibleData) (err error) {
tx, err := o.db.Begin()
if err != nil {
return err
}
defer func() {
if err == nil {
err = tx.Commit()
return
}
_ = tx.Rollback()
}()
// Insert new collectibles data
err = upsertCollectiblesData(tx, collectibles)
if err != nil {
return err
}
return
}
func scanCollectiblesDataRow(row *sql.Row) (*thirdparty.CollectibleData, error) {
c := thirdparty.CollectibleData{
ID: thirdparty.CollectibleUniqueID{
TokenID: &bigint.BigInt{Int: big.NewInt(0)},
},
Traits: make([]thirdparty.CollectibleTrait, 0),
}
err := row.Scan(
&c.ID.ContractID.ChainID,
&c.ID.ContractID.Address,
(*bigint.SQLBigIntBytes)(c.ID.TokenID.Int),
&c.Provider,
&c.Name,
&c.Description,
&c.Permalink,
&c.ImageURL,
&c.AnimationURL,
&c.AnimationMediaType,
&c.BackgroundColor,
&c.TokenURI,
)
if err != nil {
return nil, err
}
return &c, nil
}
func (o *CollectibleDataDB) GetIDsNotInDB(ids []thirdparty.CollectibleUniqueID) ([]thirdparty.CollectibleUniqueID, error) {
ret := make([]thirdparty.CollectibleUniqueID, 0, len(ids))
exists, err := o.db.Prepare(`SELECT EXISTS (
SELECT 1 FROM collectible_data_cache
WHERE chain_id=? AND contract_address=? AND token_id=?
)`)
if err != nil {
return nil, err
}
for _, id := range ids {
row := exists.QueryRow(
id.ContractID.ChainID,
id.ContractID.Address,
(*bigint.SQLBigIntBytes)(id.TokenID.Int),
)
var exists bool
err = row.Scan(&exists)
if err != nil {
return nil, err
}
if !exists {
ret = append(ret, id)
}
}
return ret, nil
}
func (o *CollectibleDataDB) GetData(ids []thirdparty.CollectibleUniqueID) (map[string]thirdparty.CollectibleData, error) {
ret := make(map[string]thirdparty.CollectibleData)
getData, err := o.db.Prepare(fmt.Sprintf(`SELECT %s
FROM collectible_data_cache
WHERE chain_id=? AND contract_address=? AND token_id=?`, collectibleDataColumns))
if err != nil {
return nil, err
}
for _, id := range ids {
row := getData.QueryRow(
id.ContractID.ChainID,
id.ContractID.Address,
(*bigint.SQLBigIntBytes)(id.TokenID.Int),
)
c, err := scanCollectiblesDataRow(row)
if err == sql.ErrNoRows {
continue
} else if err != nil {
return nil, err
} else {
// Get traits from different table
c.Traits, err = getCollectibleTraits(o.db, c.ID)
if err != nil {
return nil, err
}
ret[c.ID.HashKey()] = *c
}
}
return ret, nil
}

View file

@ -0,0 +1,146 @@
package collectibles
import (
"fmt"
"math/big"
"testing"
"github.com/ethereum/go-ethereum/common"
"github.com/status-im/status-go/appdatabase"
"github.com/status-im/status-go/services/wallet/bigint"
w_common "github.com/status-im/status-go/services/wallet/common"
"github.com/status-im/status-go/services/wallet/thirdparty"
"github.com/stretchr/testify/require"
)
func setupCollectibleDataDBTest(t *testing.T) (*CollectibleDataDB, func()) {
db, err := appdatabase.InitializeDB(":memory:", "wallet-collectibles-data-db-tests", 1)
require.NoError(t, err)
return NewCollectibleDataDB(db), func() {
require.NoError(t, db.Close())
}
}
func generateTestCollectiblesData(count int) (result []thirdparty.CollectibleData) {
result = make([]thirdparty.CollectibleData, 0, count)
for i := 0; i < count; i++ {
bigI := big.NewInt(int64(count))
newCollectible := thirdparty.CollectibleData{
ID: thirdparty.CollectibleUniqueID{
ContractID: thirdparty.ContractID{
ChainID: w_common.ChainID(i),
Address: common.BigToAddress(bigI),
},
TokenID: &bigint.BigInt{Int: bigI},
},
Provider: fmt.Sprintf("provider-%d", i),
Name: fmt.Sprintf("name-%d", i),
Description: fmt.Sprintf("description-%d", i),
Permalink: fmt.Sprintf("permalink-%d", i),
ImageURL: fmt.Sprintf("imageurl-%d", i),
AnimationURL: fmt.Sprintf("animationurl-%d", i),
AnimationMediaType: fmt.Sprintf("animationmediatype-%d", i),
Traits: []thirdparty.CollectibleTrait{
{
TraitType: fmt.Sprintf("traittype-%d", i),
Value: fmt.Sprintf("traitvalue-%d", i),
DisplayType: fmt.Sprintf("displaytype-%d", i),
MaxValue: fmt.Sprintf("maxvalue-%d", i),
},
{
TraitType: fmt.Sprintf("traittype-%d", i),
Value: fmt.Sprintf("traitvalue-%d", i),
DisplayType: fmt.Sprintf("displaytype-%d", i),
MaxValue: fmt.Sprintf("maxvalue-%d", i),
},
{
TraitType: fmt.Sprintf("traittype-%d", i),
Value: fmt.Sprintf("traitvalue-%d", i),
DisplayType: fmt.Sprintf("displaytype-%d", i),
MaxValue: fmt.Sprintf("maxvalue-%d", i),
},
},
BackgroundColor: fmt.Sprintf("backgroundcolor-%d", i),
TokenURI: fmt.Sprintf("tokenuri-%d", i),
}
result = append(result, newCollectible)
}
return result
}
func TestUpdateCollectiblesData(t *testing.T) {
db, cleanDB := setupCollectibleDataDBTest(t)
defer cleanDB()
data := generateTestCollectiblesData(50)
var err error
err = db.SetData(data)
require.NoError(t, err)
ids := make([]thirdparty.CollectibleUniqueID, 0, len(data))
for _, collectible := range data {
ids = append(ids, collectible.ID)
}
// Check for missing IDs
idsNotInDB, err := db.GetIDsNotInDB(ids)
require.NoError(t, err)
require.Empty(t, idsNotInDB)
extraID0 := thirdparty.CollectibleUniqueID{
ContractID: thirdparty.ContractID{
ChainID: w_common.ChainID(100),
Address: common.BigToAddress(big.NewInt(100)),
},
TokenID: &bigint.BigInt{Int: big.NewInt(100)},
}
extraID1 := thirdparty.CollectibleUniqueID{
ContractID: thirdparty.ContractID{
ChainID: w_common.ChainID(101),
Address: common.BigToAddress(big.NewInt(101)),
},
TokenID: &bigint.BigInt{Int: big.NewInt(101)},
}
extraIds := []thirdparty.CollectibleUniqueID{extraID0, extraID1}
idsNotInDB, err = db.GetIDsNotInDB(extraIds)
require.NoError(t, err)
require.Equal(t, extraIds, idsNotInDB)
combinedIds := append(ids, extraIds...)
idsNotInDB, err = db.GetIDsNotInDB(combinedIds)
require.NoError(t, err)
require.Equal(t, extraIds, idsNotInDB)
// Check for loaded data
loadedMap, err := db.GetData(ids)
require.NoError(t, err)
require.Equal(t, len(ids), len(loadedMap))
for _, origC := range data {
require.Equal(t, origC, loadedMap[origC.ID.HashKey()])
}
// update some collectibles, changing the provider
c0 := data[0]
c0.Name = "new collectible name 0"
c0.Provider = "new collectible provider 0"
c1 := data[1]
c1.Name = "new collectible name 1"
c1.Provider = "new collectible provider 1"
err = db.SetData([]thirdparty.CollectibleData{c0, c1})
require.NoError(t, err)
loadedMap, err = db.GetData([]thirdparty.CollectibleUniqueID{c0.ID, c1.ID})
require.NoError(t, err)
require.Equal(t, 2, len(loadedMap))
require.Equal(t, c0, loadedMap[c0.ID.HashKey()])
require.Equal(t, c1, loadedMap[c1.ID.HashKey()])
}

View file

@ -0,0 +1,229 @@
package collectibles
import (
"database/sql"
"fmt"
"github.com/status-im/status-go/services/wallet/thirdparty"
"github.com/status-im/status-go/sqlite"
)
type CollectionDataDB struct {
db *sql.DB
}
func NewCollectionDataDB(sqlDb *sql.DB) *CollectionDataDB {
return &CollectionDataDB{
db: sqlDb,
}
}
const collectionDataColumns = "chain_id, contract_address, provider, name, slug, image_url"
const collectionTraitsColumns = "chain_id, contract_address, trait_type, min, max"
const selectCollectionTraitsColumns = "trait_type, min, max"
func rowsToCollectionTraits(rows *sql.Rows) (map[string]thirdparty.CollectionTrait, error) {
traits := make(map[string]thirdparty.CollectionTrait)
for rows.Next() {
var traitType string
var trait thirdparty.CollectionTrait
err := rows.Scan(
&traitType,
&trait.Min,
&trait.Max,
)
if err != nil {
return nil, err
}
traits[traitType] = trait
}
return traits, nil
}
func getCollectionTraits(creator sqlite.StatementCreator, id thirdparty.ContractID) (map[string]thirdparty.CollectionTrait, error) {
// Get traits list
selectTraits, err := creator.Prepare(fmt.Sprintf(`SELECT %s
FROM collection_traits_cache
WHERE chain_id = ? AND contract_address = ?`, selectCollectionTraitsColumns))
if err != nil {
return nil, err
}
rows, err := selectTraits.Query(
id.ChainID,
id.Address,
)
if err != nil {
return nil, err
}
return rowsToCollectionTraits(rows)
}
func upsertCollectionTraits(creator sqlite.StatementCreator, id thirdparty.ContractID, traits map[string]thirdparty.CollectionTrait) error {
// Rremove old traits list
deleteTraits, err := creator.Prepare(`DELETE FROM collection_traits_cache WHERE chain_id = ? AND contract_address = ?`)
if err != nil {
return err
}
_, err = deleteTraits.Exec(
id.ChainID,
id.Address,
)
if err != nil {
return err
}
// Insert new traits list
insertTrait, err := creator.Prepare(fmt.Sprintf(`INSERT OR REPLACE INTO collection_traits_cache (%s)
VALUES (?, ?, ?, ?, ?)`, collectionTraitsColumns))
if err != nil {
return err
}
for traitType, trait := range traits {
_, err = insertTrait.Exec(
id.ChainID,
id.Address,
traitType,
trait.Min,
trait.Max,
)
if err != nil {
return err
}
}
return nil
}
func upsertCollectionsData(creator sqlite.StatementCreator, collections []thirdparty.CollectionData) error {
insertCollection, err := creator.Prepare(fmt.Sprintf(`INSERT OR REPLACE INTO collection_data_cache (%s)
VALUES (?, ?, ?, ?, ?, ?)`, collectionDataColumns))
if err != nil {
return err
}
for _, c := range collections {
_, err = insertCollection.Exec(
c.ID.ChainID,
c.ID.Address,
c.Provider,
c.Name,
c.Slug,
c.ImageURL,
)
if err != nil {
return err
}
err = upsertCollectionTraits(creator, c.ID, c.Traits)
if err != nil {
return err
}
}
return nil
}
func (o *CollectionDataDB) SetData(collections []thirdparty.CollectionData) (err error) {
tx, err := o.db.Begin()
if err != nil {
return err
}
defer func() {
if err == nil {
err = tx.Commit()
return
}
_ = tx.Rollback()
}()
// Insert new collections data
err = upsertCollectionsData(tx, collections)
if err != nil {
return err
}
return
}
func scanCollectionsDataRow(row *sql.Row) (*thirdparty.CollectionData, error) {
c := thirdparty.CollectionData{
Traits: make(map[string]thirdparty.CollectionTrait),
}
err := row.Scan(
&c.ID.ChainID,
&c.ID.Address,
&c.Provider,
&c.Name,
&c.Slug,
&c.ImageURL,
)
if err != nil {
return nil, err
}
return &c, nil
}
func (o *CollectionDataDB) GetIDsNotInDB(ids []thirdparty.ContractID) ([]thirdparty.ContractID, error) {
ret := make([]thirdparty.ContractID, 0, len(ids))
exists, err := o.db.Prepare(`SELECT EXISTS (
SELECT 1 FROM collection_data_cache
WHERE chain_id=? AND contract_address=?
)`)
if err != nil {
return nil, err
}
for _, id := range ids {
row := exists.QueryRow(
id.ChainID,
id.Address,
)
var exists bool
err = row.Scan(&exists)
if err != nil {
return nil, err
}
if !exists {
ret = append(ret, id)
}
}
return ret, nil
}
func (o *CollectionDataDB) GetData(ids []thirdparty.ContractID) (map[string]thirdparty.CollectionData, error) {
ret := make(map[string]thirdparty.CollectionData)
getData, err := o.db.Prepare(fmt.Sprintf(`SELECT %s
FROM collection_data_cache
WHERE chain_id=? AND contract_address=?`, collectionDataColumns))
if err != nil {
return nil, err
}
for _, id := range ids {
row := getData.QueryRow(
id.ChainID,
id.Address,
)
c, err := scanCollectionsDataRow(row)
if err == sql.ErrNoRows {
continue
} else if err != nil {
return nil, err
} else {
// Get traits from different table
c.Traits, err = getCollectionTraits(o.db, c.ID)
if err != nil {
return nil, err
}
ret[c.ID.HashKey()] = *c
}
}
return ret, nil
}

View file

@ -0,0 +1,120 @@
package collectibles
import (
"fmt"
"math/big"
"testing"
"github.com/ethereum/go-ethereum/common"
"github.com/status-im/status-go/appdatabase"
w_common "github.com/status-im/status-go/services/wallet/common"
"github.com/status-im/status-go/services/wallet/thirdparty"
"github.com/stretchr/testify/require"
)
func setupCollectionDataDBTest(t *testing.T) (*CollectionDataDB, func()) {
db, err := appdatabase.InitializeDB(":memory:", "wallet-collections-data-db-tests", 1)
require.NoError(t, err)
return NewCollectionDataDB(db), func() {
require.NoError(t, db.Close())
}
}
func generateTestCollectionsData(count int) (result []thirdparty.CollectionData) {
result = make([]thirdparty.CollectionData, 0, count)
for i := 0; i < count; i++ {
bigI := big.NewInt(int64(count))
traits := make(map[string]thirdparty.CollectionTrait)
for j := 0; j < 3; j++ {
traits[fmt.Sprintf("traittype-%d", j)] = thirdparty.CollectionTrait{
Min: float64(i+j) / 2,
Max: float64(i+j) * 2,
}
}
newCollection := thirdparty.CollectionData{
ID: thirdparty.ContractID{
ChainID: w_common.ChainID(i),
Address: common.BigToAddress(bigI),
},
Provider: fmt.Sprintf("provider-%d", i),
Name: fmt.Sprintf("name-%d", i),
Slug: fmt.Sprintf("slug-%d", i),
ImageURL: fmt.Sprintf("imageurl-%d", i),
Traits: traits,
}
result = append(result, newCollection)
}
return result
}
func TestUpdateCollectionsData(t *testing.T) {
db, cleanDB := setupCollectionDataDBTest(t)
defer cleanDB()
data := generateTestCollectionsData(50)
var err error
err = db.SetData(data)
require.NoError(t, err)
ids := make([]thirdparty.ContractID, 0, len(data))
for _, collection := range data {
ids = append(ids, collection.ID)
}
// Check for missing IDs
idsNotInDB, err := db.GetIDsNotInDB(ids)
require.NoError(t, err)
require.Empty(t, idsNotInDB)
extraID0 := thirdparty.ContractID{
ChainID: w_common.ChainID(100),
Address: common.BigToAddress(big.NewInt(100)),
}
extraID1 := thirdparty.ContractID{
ChainID: w_common.ChainID(101),
Address: common.BigToAddress(big.NewInt(101)),
}
extraIds := []thirdparty.ContractID{extraID0, extraID1}
idsNotInDB, err = db.GetIDsNotInDB(extraIds)
require.NoError(t, err)
require.Equal(t, extraIds, idsNotInDB)
combinedIds := append(ids, extraIds...)
idsNotInDB, err = db.GetIDsNotInDB(combinedIds)
require.NoError(t, err)
require.Equal(t, extraIds, idsNotInDB)
// Check for loaded data
loadedMap, err := db.GetData(ids)
require.NoError(t, err)
require.Equal(t, len(ids), len(loadedMap))
for _, origC := range data {
require.Equal(t, origC, loadedMap[origC.ID.HashKey()])
}
// update some collections, changing the provider
c0 := data[0]
c0.Name = "new collection name 0"
c0.Provider = "new collection provider 0"
c1 := data[1]
c1.Name = "new collection name 1"
c1.Provider = "new collection provider 1"
err = db.SetData([]thirdparty.CollectionData{c0, c1})
require.NoError(t, err)
loadedMap, err = db.GetData([]thirdparty.ContractID{c0.ID, c1.ID})
require.NoError(t, err)
require.Equal(t, 2, len(loadedMap))
require.Equal(t, c0, loadedMap[c0.ID.HashKey()])
require.Equal(t, c1, loadedMap[c1.ID.HashKey()])
}

View file

@ -12,6 +12,7 @@ import (
"github.com/status-im/status-go/services/wallet/bigint"
w_common "github.com/status-im/status-go/services/wallet/common"
"github.com/status-im/status-go/services/wallet/thirdparty"
"github.com/status-im/status-go/sqlite"
)
type OwnershipDB struct {
@ -27,12 +28,7 @@ func NewOwnershipDB(sqlDb *sql.DB) *OwnershipDB {
const ownershipColumns = "chain_id, contract_address, token_id, owner_address"
const selectOwnershipColumns = "chain_id, contract_address, token_id"
// statementCreator allows to pass transaction or database to use in consumer.
type statementCreator interface {
Prepare(query string) (*sql.Stmt, error)
}
func removeAddressOwnership(creator statementCreator, chainID w_common.ChainID, ownerAddress common.Address) error {
func removeAddressOwnership(creator sqlite.StatementCreator, chainID w_common.ChainID, ownerAddress common.Address) error {
deleteOwnership, err := creator.Prepare("DELETE FROM collectibles_ownership_cache WHERE chain_id = ? AND owner_address = ?")
if err != nil {
return err
@ -46,7 +42,7 @@ func removeAddressOwnership(creator statementCreator, chainID w_common.ChainID,
return nil
}
func insertAddressOwnership(creator statementCreator, ownerAddress common.Address, collectibles []thirdparty.CollectibleUniqueID) error {
func insertAddressOwnership(creator sqlite.StatementCreator, ownerAddress common.Address, collectibles []thirdparty.CollectibleUniqueID) error {
insertOwnership, err := creator.Prepare(fmt.Sprintf(`INSERT INTO collectibles_ownership_cache (%s)
VALUES (?, ?, ?, ?)`, ownershipColumns))
if err != nil {

View file

@ -15,7 +15,6 @@ import (
"github.com/status-im/status-go/services/wallet/thirdparty"
)
const AlchemyID = "alchemy"
const nftMetadataBatchLimit = 100
const contractMetadataBatchLimit = 100

View file

@ -15,6 +15,8 @@ import (
"golang.org/x/text/language"
)
const AlchemyID = "alchemy"
type TokenBalance struct {
TokenID *bigint.BigInt `json:"tokenId"`
Balance *bigint.BigInt `json:"balance"`
@ -155,6 +157,7 @@ func alchemyToCollectibleTraits(attributes []Attribute) []thirdparty.Collectible
func (c *Contract) toCollectionData(id thirdparty.ContractID) thirdparty.CollectionData {
ret := thirdparty.CollectionData{
ID: id,
Provider: AlchemyID,
Name: c.Name,
ImageURL: c.OpenSeaMetadata.ImageURL,
}
@ -164,6 +167,7 @@ func (c *Contract) toCollectionData(id thirdparty.ContractID) thirdparty.Collect
func (c *Asset) toCollectiblesData(id thirdparty.CollectibleUniqueID) thirdparty.CollectibleData {
return thirdparty.CollectibleData{
ID: id,
Provider: AlchemyID,
Name: c.Name,
Description: c.Description,
ImageURL: c.Image.ImageURL,

View file

@ -73,6 +73,7 @@ type CollectionTrait struct {
// Collection info
type CollectionData struct {
ID ContractID `json:"id"`
Provider string `json:"provider"`
Name string `json:"name"`
Slug string `json:"slug"`
ImageURL string `json:"image_url"`
@ -89,6 +90,7 @@ type CollectibleTrait struct {
// Collectible info
type CollectibleData struct {
ID CollectibleUniqueID `json:"id"`
Provider string `json:"provider"`
Name string `json:"name"`
Description string `json:"description"`
Permalink string `json:"permalink"`

View file

@ -15,7 +15,6 @@ import (
)
const baseURL = "https://nft.api.infura.io"
const InfuraID = "infura"
type Client struct {
thirdparty.CollectibleContractOwnershipProvider

View file

@ -15,6 +15,8 @@ import (
"golang.org/x/text/language"
)
const InfuraID = "infura"
func chainStringToChainID(chainString string) walletCommon.ChainID {
chainID := walletCommon.UnknownChainID
switch chainString {
@ -129,6 +131,7 @@ type NFTList struct {
func (c *Asset) toCollectiblesData(id thirdparty.CollectibleUniqueID) thirdparty.CollectibleData {
return thirdparty.CollectibleData{
ID: id,
Provider: InfuraID,
Name: c.Metadata.Name,
Description: c.Metadata.Description,
Permalink: c.Metadata.Permalink,
@ -177,7 +180,8 @@ func infuraToCollectibleTraits(attributes []Attribute) []thirdparty.CollectibleT
func (c *ContractMetadata) toCommon(id thirdparty.ContractID) thirdparty.CollectionData {
return thirdparty.CollectionData{
ID: id,
Name: c.Name,
ID: id,
Provider: InfuraID,
Name: c.Name,
}
}

View file

@ -21,8 +21,6 @@ const (
EventCollectibleStatusChanged walletevent.EventType = "wallet-collectible-opensea-v1-status-changed"
)
const OpenseaV1ID = "openseaV1"
const AssetLimit = 200
const CollectionLimit = 300

View file

@ -117,6 +117,7 @@ func TestFetchAllAssetsByOwnerAndCollection(t *testing.T) {
},
TokenID: &bigint.BigInt{Int: big.NewInt(1)},
},
Provider: "openseaV1",
Name: "Rocky",
Description: "Rocky Balboa",
Permalink: "permalink",
@ -128,8 +129,9 @@ func TestFetchAllAssetsByOwnerAndCollection(t *testing.T) {
ChainID: 1,
Address: common.HexToAddress("0x1"),
},
Name: "Rocky",
Traits: map[string]thirdparty.CollectionTrait{},
Provider: "openseaV1",
Name: "Rocky",
Traits: map[string]thirdparty.CollectionTrait{},
},
},
},

View file

@ -15,6 +15,8 @@ import (
"golang.org/x/text/language"
)
const OpenseaV1ID = "openseaV1"
func chainStringToChainID(chainString string) walletCommon.ChainID {
chainID := walletCommon.UnknownChainID
switch chainString {
@ -159,6 +161,7 @@ func openseaToCollectibleTraits(traits []Trait) []thirdparty.CollectibleTrait {
func (c *Collection) toCollectionData(id thirdparty.ContractID) thirdparty.CollectionData {
ret := thirdparty.CollectionData{
ID: id,
Provider: OpenseaV1ID,
Name: c.Name,
Slug: c.Slug,
ImageURL: c.ImageURL,
@ -176,6 +179,7 @@ func (c *Collection) toCollectionData(id thirdparty.ContractID) thirdparty.Colle
func (c *Asset) toCollectiblesData() thirdparty.CollectibleData {
return thirdparty.CollectibleData{
ID: c.id(),
Provider: OpenseaV1ID,
Name: c.Name,
Description: c.Description,
Permalink: c.Permalink,

8
sqlite/driver.go Normal file
View file

@ -0,0 +1,8 @@
package sqlite
import "database/sql"
// statementCreator allows to pass transaction or database to use in consumer.
type StatementCreator interface {
Prepare(query string) (*sql.Stmt, error)
}