Feat: Profile showcase validate collectible ownership (#4737)

* feat: profile showcase checks then presenting collectibles

* chore: more obvious CollectiblesManager configuration
This commit is contained in:
Mikhail Rogachev 2024-02-22 11:08:58 +03:00 committed by GitHub
parent 01b3f8ace4
commit eb5bad4868
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
13 changed files with 312 additions and 88 deletions

View File

@ -164,6 +164,7 @@ func (m *DefaultTokenManager) GetAllChainIDs() ([]uint64, error) {
type CollectiblesManager interface {
FetchBalancesByOwnerAndContractAddress(ctx context.Context, chainID walletcommon.ChainID, ownerAddress gethcommon.Address, contractAddresses []gethcommon.Address) (thirdparty.TokenBalancesPerContractAddress, error)
GetCollectibleOwnership(id thirdparty.CollectibleUniqueID) ([]thirdparty.AccountBalance, error)
}
func (m *DefaultTokenManager) GetBalancesByChain(ctx context.Context, accounts, tokenAddresses []gethcommon.Address, chainIDs []uint64) (BalancesByChain, error) {
@ -5162,6 +5163,11 @@ func (m *Manager) encryptCommunityDescriptionChannel(community *Community, chann
return m.encryptCommunityDescriptionImpl([]byte(community.IDString()+channelID), d)
}
// TODO: add collectiblesManager to messenger intance
func (m *Manager) GetCollectiblesManager() CollectiblesManager {
return m.collectiblesManager
}
type DecryptCommunityResponse struct {
Decrypted bool
Description *protobuf.CommunityDescription

View File

@ -3,6 +3,7 @@ package communities
import (
"bytes"
"context"
"errors"
"image"
"image/png"
"math"
@ -114,6 +115,10 @@ func (m *testCollectiblesManager) FetchBalancesByOwnerAndContractAddress(ctx con
return m.response[uint64(chainID)][ownerAddress], nil
}
func (m *testCollectiblesManager) GetCollectibleOwnership(id thirdparty.CollectibleUniqueID) ([]thirdparty.AccountBalance, error) {
return nil, errors.New("GetCollectibleOwnership is not implemented for testCollectiblesManager")
}
type testTokenManager struct {
response map[uint64]map[gethcommon.Address]map[gethcommon.Address]*hexutil.Big
}

View File

@ -3,8 +3,6 @@ package identity
import "errors"
var ErrorNoAccountProvidedWithTokenOrCollectible = errors.New("no account provided with tokens or collectible")
var ErrorDublicateAccountAddress = errors.New("duplicate account address")
var ErrorAccountVisibilityLowerThanCollectible = errors.New("account visibility lower than collectible")
type ProfileShowcaseVisibility int
@ -122,25 +120,5 @@ func Validate(preferences *ProfileShowcasePreferences) error {
return ErrorNoAccountProvidedWithTokenOrCollectible
}
accountsMap := make(map[string]*ProfileShowcaseAccountPreference)
for _, account := range preferences.Accounts {
if _, ok := accountsMap[account.Address]; ok {
return ErrorDublicateAccountAddress
}
accountsMap[account.Address] = account
}
for _, collectible := range preferences.Collectibles {
account, ok := accountsMap[collectible.AccountAddress]
if !ok {
return nil
// NOTE: with current wallet collectible implementation we don't know account on this stage
// return errorNoAccountAddressForCollectible
}
if account.ShowcaseVisibility < collectible.ShowcaseVisibility {
return ErrorAccountVisibilityLowerThanCollectible
}
}
return nil
}

View File

@ -451,17 +451,16 @@ func NewMessenger(
ensVerifier := ens.New(node, logger, transp, database, c.verifyENSURL, c.verifyENSContractAddress)
var walletAPI *wallet.API
if c.walletService != nil {
walletAPI = wallet.NewAPI(c.walletService)
}
managerOptions := []communities.ManagerOption{
communities.WithAccountManager(c.accountsManager),
}
if walletAPI != nil {
var walletAPI *wallet.API
if c.walletService != nil {
walletAPI = wallet.NewAPI(c.walletService)
managerOptions = append(managerOptions, communities.WithCollectiblesManager(walletAPI))
} else if c.collectiblesManager != nil {
managerOptions = append(managerOptions, communities.WithCollectiblesManager(c.collectiblesManager))
}
if c.tokenManager != nil {

View File

@ -159,7 +159,7 @@ func (s *MessengerBackupSuite) TestBackupProfile() {
})
s.Require().NoError(err)
profileShowcasePreferences := DummyProfileShowcasePreferences()
profileShowcasePreferences := DummyProfileShowcasePreferences(false)
err = bob1.SetProfileShowcasePreferences(profileShowcasePreferences, false)
s.Require().NoError(err)

View File

@ -92,6 +92,7 @@ type config struct {
httpServer *server.MediaServer
rpcClient *rpc.Client
tokenManager communities.TokenManager
collectiblesManager communities.CollectiblesManager
accountsManager account.Manager
verifyTransactionClient EthClient
@ -394,6 +395,13 @@ func WithTokenManager(tokenManager communities.TokenManager) Option {
}
}
func WithCollectiblesManager(collectiblesManager communities.CollectiblesManager) Option {
return func(c *config) error {
c.collectiblesManager = collectiblesManager
return nil
}
}
func WithAccountManager(accountManager account.Manager) Option {
return func(c *config) error {
c.accountsManager = accountManager

View File

@ -6,21 +6,98 @@ import (
"crypto/ecdsa"
crand "crypto/rand"
"errors"
"math/big"
"reflect"
"sort"
"github.com/golang/protobuf/proto"
"go.uber.org/zap"
eth_common "github.com/ethereum/go-ethereum/common"
"github.com/status-im/status-go/eth-node/crypto"
"github.com/status-im/status-go/multiaccounts/accounts"
"github.com/status-im/status-go/protocol/common"
"github.com/status-im/status-go/protocol/communities"
"github.com/status-im/status-go/protocol/identity"
"github.com/status-im/status-go/protocol/protobuf"
"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"
)
var errorDecryptingPayloadEncryptionKey = errors.New("decrypting the payload encryption key resulted in no error and a nil key")
var errorConvertCollectibleTokenIDToInt = errors.New("failed to convert collectible token id to bigint")
var errorNoAccountPresentedForCollectible = errors.New("account holding the collectible is not presented in the profile showcase")
var errorDublicateAccountAddress = errors.New("duplicate account address")
var errorAccountVisibilityLowerThanCollectible = errors.New("account visibility lower than collectible")
func toCollectibleUniqueID(contractAddress string, tokenID string, chainID uint64) (thirdparty.CollectibleUniqueID, error) {
tokenIDInt := new(big.Int)
tokenIDInt, isTokenIDOk := tokenIDInt.SetString(tokenID, 10)
if !isTokenIDOk {
return thirdparty.CollectibleUniqueID{}, errorConvertCollectibleTokenIDToInt
}
return thirdparty.CollectibleUniqueID{
ContractID: thirdparty.ContractID{
ChainID: w_common.ChainID(chainID),
Address: eth_common.HexToAddress(contractAddress),
},
TokenID: &bigint.BigInt{Int: tokenIDInt},
}, nil
}
func (m *Messenger) fetchCollectibleOwner(contractAddress string, tokenID string, chainID uint64) ([]thirdparty.AccountBalance, error) {
collectibleID, err := toCollectibleUniqueID(contractAddress, tokenID, chainID)
if err != nil {
return nil, err
}
balance, err := m.communitiesManager.GetCollectiblesManager().GetCollectibleOwnership(collectibleID)
if err != nil {
return nil, err
}
return balance, nil
}
func (m *Messenger) validateCollectiblesOwnership(accounts []*identity.ProfileShowcaseAccountPreference,
collectibles []*identity.ProfileShowcaseCollectiblePreference) error {
accountsMap := make(map[string]identity.ProfileShowcaseVisibility)
for _, accountProfile := range accounts {
if _, ok := accountsMap[accountProfile.Address]; ok {
return errorDublicateAccountAddress
}
accountsMap[accountProfile.Address] = accountProfile.ShowcaseVisibility
}
for _, collectibleProfile := range collectibles {
balances, err := m.fetchCollectibleOwner(collectibleProfile.ContractAddress, collectibleProfile.TokenID,
collectibleProfile.ChainID)
if err != nil {
return err
}
// NOTE: ERC721 tokens can have only a single holder
// but ERC1155 which can be supported later can have more than one holder and balances > 1
found := false
for _, balance := range balances {
if accountShowcaseVisibility, ok := accountsMap[balance.Address.String()]; ok {
if accountShowcaseVisibility < collectibleProfile.ShowcaseVisibility {
return errorAccountVisibilityLowerThanCollectible
}
found = true
break
}
}
if !found {
return errorNoAccountPresentedForCollectible
}
}
return nil
}
func (m *Messenger) toProfileShowcaseCommunityProto(preferences []*identity.ProfileShowcaseCommunityPreference, visibility identity.ProfileShowcaseVisibility) []*protobuf.ProfileShowcaseCommunity {
entries := []*protobuf.ProfileShowcaseCommunity{}
@ -182,15 +259,16 @@ func (m *Messenger) fromProfileShowcaseAccountProto(messages []*protobuf.Profile
func (m *Messenger) fromProfileShowcaseCollectibleProto(messages []*protobuf.ProfileShowcaseCollectible) []*identity.ProfileShowcaseCollectible {
entries := []*identity.ProfileShowcaseCollectible{}
for _, entry := range messages {
entries = append(entries, &identity.ProfileShowcaseCollectible{
ContractAddress: entry.ContractAddress,
ChainID: entry.ChainId,
TokenID: entry.TokenId,
CommunityID: entry.CommunityId,
AccountAddress: entry.AccountAddress,
Order: int(entry.Order),
})
for _, message := range messages {
entry := &identity.ProfileShowcaseCollectible{
ContractAddress: message.ContractAddress,
ChainID: message.ChainId,
TokenID: message.TokenId,
CommunityID: message.CommunityId,
AccountAddress: message.AccountAddress,
Order: int(message.Order),
}
entries = append(entries, entry)
}
return entries
}
@ -230,6 +308,11 @@ func (m *Messenger) setProfileShowcasePreferences(preferences *identity.ProfileS
return err
}
err = m.validateCollectiblesOwnership(preferences.Accounts, preferences.Collectibles)
if err != nil {
return err
}
err = m.persistence.SaveProfileShowcasePreferences(preferences)
if err != nil {
return err

View File

@ -2,10 +2,17 @@ package protocol
import (
"context"
"crypto/ecdsa"
"errors"
"math/big"
"testing"
"github.com/stretchr/testify/suite"
"go.uber.org/zap"
gethcommon "github.com/ethereum/go-ethereum/common"
"github.com/status-im/status-go/appdatabase"
gethbridge "github.com/status-im/status-go/eth-node/bridge/geth"
"github.com/status-im/status-go/eth-node/crypto"
"github.com/status-im/status-go/eth-node/types"
"github.com/status-im/status-go/multiaccounts/accounts"
@ -13,14 +20,97 @@ import (
"github.com/status-im/status-go/protocol/identity"
"github.com/status-im/status-go/protocol/protobuf"
"github.com/status-im/status-go/protocol/requests"
"github.com/status-im/status-go/protocol/sqlite"
"github.com/status-im/status-go/protocol/tt"
"github.com/status-im/status-go/services/wallet/bigint"
walletCommon "github.com/status-im/status-go/services/wallet/common"
"github.com/status-im/status-go/services/wallet/thirdparty"
"github.com/status-im/status-go/t/helpers"
"github.com/status-im/status-go/waku"
)
type CollectiblesManagerMock struct {
response map[thirdparty.CollectibleUniqueID][]thirdparty.AccountBalance
}
func (m *CollectiblesManagerMock) FetchBalancesByOwnerAndContractAddress(ctx context.Context, chainID walletCommon.ChainID,
ownerAddress gethcommon.Address, contractAddresses []gethcommon.Address) (thirdparty.TokenBalancesPerContractAddress, error) {
return nil, errors.New("FetchBalancesByOwnerAndContractAddress is not implemented for testCollectiblesManager")
}
func (m *CollectiblesManagerMock) GetCollectibleOwnership(requestedID thirdparty.CollectibleUniqueID) ([]thirdparty.AccountBalance, error) {
// NOTE: TokenID inside of thirdparty.CollectibleUniqueID is a pointer so m.response[id] is now working
for id, balances := range m.response {
if id.ContractID.Address == requestedID.ContractID.Address &&
id.ContractID.ChainID == requestedID.ContractID.ChainID {
return balances, nil
}
}
return []thirdparty.AccountBalance{}, nil
}
func (m *CollectiblesManagerMock) SetResponse(id thirdparty.CollectibleUniqueID, balances []thirdparty.AccountBalance) {
if m.response == nil {
m.response = map[thirdparty.CollectibleUniqueID][]thirdparty.AccountBalance{}
}
m.response[id] = balances
}
func TestMessengerProfileShowcaseSuite(t *testing.T) { // nolint: deadcode,unused
suite.Run(t, new(TestMessengerProfileShowcase))
}
type TestMessengerProfileShowcase struct {
MessengerBaseTestSuite
suite.Suite
m *Messenger // main instance of Messenger
privateKey *ecdsa.PrivateKey // private key for the main instance of Messenger
// If one wants to send messages between different instances of Messenger,
// a single waku service should be shared.
shh types.Waku
logger *zap.Logger
collectiblesMock *CollectiblesManagerMock
}
func (s *TestMessengerProfileShowcase) SetupTest() {
s.logger = tt.MustCreateTestLogger()
config := waku.DefaultConfig
config.MinimumAcceptedPoW = 0
shh := waku.New(&config, s.logger)
s.shh = gethbridge.NewGethWakuWrapper(shh)
s.Require().NoError(shh.Start())
s.m = s.newMessengerForProfileShowcase()
s.privateKey = s.m.identity
}
func (s *TestMessengerProfileShowcase) TearDownTest() {
TearDownMessenger(&s.Suite, s.m)
_ = s.logger.Sync()
}
func (s *TestMessengerProfileShowcase) newMessengerForProfileShowcase() *Messenger {
db, err := helpers.SetupTestMemorySQLDB(appdatabase.DbInitializer{})
s.NoError(err, "creating sqlite db instance")
err = sqlite.Migrate(db)
s.NoError(err, "protocol migrate")
privateKey, err := crypto.GenerateKey()
s.Require().NoError(err)
s.collectiblesMock = &CollectiblesManagerMock{}
options := []Option{
WithCollectiblesManager(s.collectiblesMock),
}
m, err := newMessengerWithKey(s.shh, privateKey, s.logger, options)
s.Require().NoError(err)
_, err = m.Start()
s.Require().NoError(err)
return m
}
func (s *TestMessengerProfileShowcase) mutualContact(theirMessenger *Messenger) {
@ -113,8 +203,22 @@ func (s *TestMessengerProfileShowcase) verifiedContact(theirMessenger *Messenger
}
func (s *TestMessengerProfileShowcase) TestSaveAndGetProfileShowcasePreferences() {
request := DummyProfileShowcasePreferences()
err := s.m.SetProfileShowcasePreferences(request, false)
request := DummyProfileShowcasePreferences(true)
// Provide collectible balances test response
collectible := request.Collectibles[0]
collectibleID, err := toCollectibleUniqueID(collectible.ContractAddress, collectible.TokenID, collectible.ChainID)
s.Require().NoError(err)
balances := []thirdparty.AccountBalance{
thirdparty.AccountBalance{
Address: gethcommon.HexToAddress(request.Accounts[0].Address),
Balance: &bigint.BigInt{Int: big.NewInt(5)},
TxTimestamp: 0,
},
}
s.collectiblesMock.SetResponse(collectibleID, balances)
err = s.m.SetProfileShowcasePreferences(request, false)
s.Require().NoError(err)
// Restored preferences shoulf be same as stored
@ -149,7 +253,7 @@ func (s *TestMessengerProfileShowcase) TestSaveAndGetProfileShowcasePreferences(
func (s *TestMessengerProfileShowcase) TestFailToSaveProfileShowcasePreferencesWithWrongVisibility() {
accountEntry := &identity.ProfileShowcaseAccountPreference{
Address: "0x32433445133424",
Address: "0x0000000000000000000000000032433445133424",
Name: "Status Account",
ColorID: "blue",
Emoji: ">:-]",
@ -159,10 +263,9 @@ func (s *TestMessengerProfileShowcase) TestFailToSaveProfileShowcasePreferencesW
collectibleEntry := &identity.ProfileShowcaseCollectiblePreference{
ContractAddress: "0x12378534257568678487683576",
ChainID: 8,
TokenID: "0x12321389592999f903",
ChainID: 11155111,
TokenID: "12321389592999903",
CommunityID: "0x01312357798976535",
AccountAddress: "0x32433445133424",
ShowcaseVisibility: identity.ProfileShowcaseVisibilityContacts,
Order: 17,
}
@ -172,13 +275,26 @@ func (s *TestMessengerProfileShowcase) TestFailToSaveProfileShowcasePreferencesW
Collectibles: []*identity.ProfileShowcaseCollectiblePreference{collectibleEntry},
}
err := s.m.SetProfileShowcasePreferences(request, false)
s.Require().Equal(identity.ErrorAccountVisibilityLowerThanCollectible, err)
// Provide collectible balances test response
collectible := request.Collectibles[0]
collectibleID, err := toCollectibleUniqueID(collectible.ContractAddress, collectible.TokenID, collectible.ChainID)
s.Require().NoError(err)
balances := []thirdparty.AccountBalance{
thirdparty.AccountBalance{
Address: gethcommon.HexToAddress(request.Accounts[0].Address),
Balance: &bigint.BigInt{Int: big.NewInt(5)},
TxTimestamp: 0,
},
}
s.collectiblesMock.SetResponse(collectibleID, balances)
err = s.m.SetProfileShowcasePreferences(request, false)
s.Require().Equal(errorAccountVisibilityLowerThanCollectible, err)
}
func (s *TestMessengerProfileShowcase) TestEncryptAndDecryptProfileShowcaseEntries() {
// Add mutual contact
theirMessenger := s.newMessenger()
theirMessenger := s.newMessengerForProfileShowcase()
_, err := theirMessenger.Start()
s.Require().NoError(err)
defer TearDownMessenger(&s.Suite, theirMessenger)
@ -208,8 +324,8 @@ func (s *TestMessengerProfileShowcase) TestEncryptAndDecryptProfileShowcaseEntri
Collectibles: []*protobuf.ProfileShowcaseCollectible{
&protobuf.ProfileShowcaseCollectible{
ContractAddress: "0x12378534257568678487683576",
ChainId: 7,
TokenId: "0x12321389592999f903",
ChainId: 1,
TokenId: "12321389592999903",
AccountAddress: "0x32433445133424",
CommunityId: "0x12378534257568678487683576",
Order: 0,
@ -232,12 +348,12 @@ func (s *TestMessengerProfileShowcase) TestEncryptAndDecryptProfileShowcaseEntri
UnverifiedTokens: []*protobuf.ProfileShowcaseUnverifiedToken{
&protobuf.ProfileShowcaseUnverifiedToken{
ContractAddress: "0x454525452023452",
ChainId: 3,
ChainId: 11155111,
Order: 0,
},
&protobuf.ProfileShowcaseUnverifiedToken{
ContractAddress: "0x12312323323233",
ChainId: 2,
ChainId: 1,
Order: 1,
},
},
@ -302,7 +418,7 @@ func (s *TestMessengerProfileShowcase) TestShareShowcasePreferences() {
s.Require().NoError(err)
// Add mutual contact
mutualContact := s.newMessenger()
mutualContact := s.newMessengerForProfileShowcase()
_, err = mutualContact.Start()
s.Require().NoError(err)
defer TearDownMessenger(&s.Suite, mutualContact)
@ -310,7 +426,7 @@ func (s *TestMessengerProfileShowcase) TestShareShowcasePreferences() {
s.mutualContact(mutualContact)
// Add identity verified contact
verifiedContact := s.newMessenger()
verifiedContact := s.newMessengerForProfileShowcase()
_, err = verifiedContact.Start()
s.Require().NoError(err)
defer TearDownMessenger(&s.Suite, verifiedContact)
@ -319,7 +435,21 @@ func (s *TestMessengerProfileShowcase) TestShareShowcasePreferences() {
s.verifiedContact(verifiedContact)
// Save preferences to dispatch changes
request := DummyProfileShowcasePreferences()
request := DummyProfileShowcasePreferences(true)
// Provide collectible balances test response
collectible := request.Collectibles[0]
collectibleID, err := toCollectibleUniqueID(collectible.ContractAddress, collectible.TokenID, collectible.ChainID)
s.Require().NoError(err)
balances := []thirdparty.AccountBalance{
thirdparty.AccountBalance{
Address: gethcommon.HexToAddress(request.Accounts[0].Address),
Balance: &bigint.BigInt{Int: big.NewInt(1)},
TxTimestamp: 32443424,
},
}
s.collectiblesMock.SetResponse(collectibleID, balances)
err = s.m.SetProfileShowcasePreferences(request, false)
s.Require().NoError(err)
@ -433,7 +563,7 @@ func (s *TestMessengerProfileShowcase) TestProfileShowcaseProofOfMembershipUnenc
s.Require().NoError(err)
// Add bob as a mutual contact
bob := s.newMessenger()
bob := s.newMessengerForProfileShowcase()
_, err = bob.Start()
s.Require().NoError(err)
defer TearDownMessenger(&s.Suite, bob)
@ -500,7 +630,7 @@ func (s *TestMessengerProfileShowcase) TestProfileShowcaseProofOfMembershipEncry
s.Require().NoError(err)
// Add bob as a mutual contact
bob := s.newMessenger()
bob := s.newMessengerForProfileShowcase()
_, err = bob.Start()
s.Require().NoError(err)
defer TearDownMessenger(&s.Suite, bob)

View File

@ -414,12 +414,12 @@ func RandomBytes(length int) []byte {
return out
}
func DummyProfileShowcasePreferences() *identity.ProfileShowcasePreferences {
return &identity.ProfileShowcasePreferences{
func DummyProfileShowcasePreferences(withCollectibles bool) *identity.ProfileShowcasePreferences {
preferences := &identity.ProfileShowcasePreferences{
Communities: []*identity.ProfileShowcaseCommunityPreference{}, // empty to avoid fetching
Accounts: []*identity.ProfileShowcaseAccountPreference{
{
Address: "0x32433445133424",
Address: "0x0000000000000000000000000033433445133423",
Name: "Status Account",
ColorID: "blue",
Emoji: "-_-",
@ -427,7 +427,7 @@ func DummyProfileShowcasePreferences() *identity.ProfileShowcasePreferences {
Order: 0,
},
{
Address: "0x3845354643324",
Address: "0x0000000000000000000000000032433445133424",
Name: "Money Box",
ColorID: "red",
Emoji: ":o)",
@ -435,17 +435,6 @@ func DummyProfileShowcasePreferences() *identity.ProfileShowcasePreferences {
Order: 1,
},
},
Collectibles: []*identity.ProfileShowcaseCollectiblePreference{
{
ContractAddress: "0x12378534257568678487683576",
ChainID: 1,
TokenID: "0x12321389592999f903",
CommunityID: "0x01312357798976535",
AccountAddress: "0x32433445133424",
ShowcaseVisibility: identity.ProfileShowcaseVisibilityEveryone,
Order: 0,
},
},
VerifiedTokens: []*identity.ProfileShowcaseVerifiedTokenPreference{
{
Symbol: "ETH",
@ -466,16 +455,34 @@ func DummyProfileShowcasePreferences() *identity.ProfileShowcasePreferences {
UnverifiedTokens: []*identity.ProfileShowcaseUnverifiedTokenPreference{
{
ContractAddress: "0x454525452023452",
ChainID: 3,
ChainID: 11155111,
ShowcaseVisibility: identity.ProfileShowcaseVisibilityEveryone,
Order: 0,
},
{
ContractAddress: "0x12312323323233",
ChainID: 6,
ChainID: 1,
ShowcaseVisibility: identity.ProfileShowcaseVisibilityContacts,
Order: 1,
},
},
}
if withCollectibles {
preferences.Collectibles = []*identity.ProfileShowcaseCollectiblePreference{
{
ContractAddress: "0x12378534257568678487683576",
ChainID: 1,
TokenID: "12321389592999903",
CommunityID: "0x01312357798976535",
AccountAddress: "0x32433445133424",
ShowcaseVisibility: identity.ProfileShowcaseVisibilityEveryone,
Order: 0,
},
}
} else {
preferences.Collectibles = []*identity.ProfileShowcaseCollectiblePreference{}
}
return preferences
}

View File

@ -31,7 +31,7 @@ func (s *TestProfileShowcasePersistence) TestProfileShowcasePreferences() {
},
Accounts: []*identity.ProfileShowcaseAccountPreference{
&identity.ProfileShowcaseAccountPreference{
Address: "0x32433445133424",
Address: "0x0000000000000000000000000032433445133422",
Name: "Status Account",
ColorID: "blue",
Emoji: "-_-",
@ -39,7 +39,7 @@ func (s *TestProfileShowcasePersistence) TestProfileShowcasePreferences() {
Order: 0,
},
&identity.ProfileShowcaseAccountPreference{
Address: "0x3845354643324",
Address: "0x0000000000000000000000000032433445133424",
Name: "Money Box",
ColorID: "red",
Emoji: ":o)",
@ -50,8 +50,8 @@ func (s *TestProfileShowcasePersistence) TestProfileShowcasePreferences() {
Collectibles: []*identity.ProfileShowcaseCollectiblePreference{
&identity.ProfileShowcaseCollectiblePreference{
ContractAddress: "0x12378534257568678487683576",
ChainID: 3,
TokenID: "0x12321389592999f903",
ChainID: 11155111,
TokenID: "123213895929994903",
CommunityID: "0x01312357798976535",
AccountAddress: "0x32433445133424",
ShowcaseVisibility: identity.ProfileShowcaseVisibilityEveryone,
@ -85,7 +85,7 @@ func (s *TestProfileShowcasePersistence) TestProfileShowcasePreferences() {
},
&identity.ProfileShowcaseUnverifiedTokenPreference{
ContractAddress: "0x12312323323233",
ChainID: 2,
ChainID: 11155111,
CommunityID: "",
ShowcaseVisibility: identity.ProfileShowcaseVisibilityContacts,
Order: 1,
@ -153,7 +153,7 @@ func (s *TestProfileShowcasePersistence) TestProfileShowcaseContacts() {
},
&identity.ProfileShowcaseAccount{
ContactID: "contact_1",
Address: "0x3845354643324",
Address: "0x0000000000000000000000000032433445133424",
Name: "Money Box",
ColorID: "red",
Emoji: ":o)",
@ -163,8 +163,8 @@ func (s *TestProfileShowcasePersistence) TestProfileShowcaseContacts() {
Collectibles: []*identity.ProfileShowcaseCollectible{
&identity.ProfileShowcaseCollectible{
ContractAddress: "0x12378534257568678487683576",
ChainID: 2,
TokenID: "0x12321389592999f903",
ChainID: 1,
TokenID: "123213895929994903",
CommunityID: "0x01312357798976535",
Order: 0,
},
@ -192,7 +192,7 @@ func (s *TestProfileShowcasePersistence) TestProfileShowcaseContacts() {
},
&identity.ProfileShowcaseUnverifiedToken{
ContractAddress: "0x12312323323233",
ChainID: 2,
ChainID: 11155111,
CommunityID: "0x32433445133424",
Order: 1,
},
@ -216,8 +216,8 @@ func (s *TestProfileShowcasePersistence) TestProfileShowcaseContacts() {
Collectibles: []*identity.ProfileShowcaseCollectible{
&identity.ProfileShowcaseCollectible{
ContractAddress: "0x12378534257568678487683576",
ChainID: 2,
TokenID: "0x12321389592999f903",
ChainID: 1,
TokenID: "123213895929994903",
CommunityID: "0x01312357798976535",
Order: 1,
},
@ -382,8 +382,8 @@ func (s *TestProfileShowcasePersistence) TestUpdateProfileShowcaseAccountOnWalle
s.Require().NoError(err)
persistence := newSQLitePersistence(db)
deleteAccountAddress := "0x3243344513424"
updateAccountAddress := "0x3845354643324"
deleteAccountAddress := "0x0000000000000000000000000033433445133423"
updateAccountAddress := "0x0000000000000000000000000032433445133424"
preferences := &identity.ProfileShowcasePreferences{
Accounts: []*identity.ProfileShowcaseAccountPreference{

View File

@ -329,7 +329,7 @@ func (s *SyncDeviceSuite) TestPairingSyncDeviceClientAsSender() {
err = clientBackend.StatusNode().EnsService().API().Add(ctx, ensChainID, ensUsername)
require.NoError(s.T(), err)
// generate profile showcase preferences
profileShowcasePreferences := protocol.DummyProfileShowcasePreferences()
profileShowcasePreferences := protocol.DummyProfileShowcasePreferences(false)
err = clientBackend.Messenger().SetProfileShowcasePreferences(profileShowcasePreferences, false)
require.NoError(s.T(), err)

View File

@ -316,6 +316,10 @@ func (api *API) FetchBalancesByOwnerAndContractAddress(ctx context.Context, chai
return api.s.collectiblesManager.FetchBalancesByOwnerAndContractAddress(ctx, chainID, ownerAddress, contractAddresses)
}
func (api *API) GetCollectibleOwnership(id thirdparty.CollectibleUniqueID) ([]thirdparty.AccountBalance, error) {
return api.s.collectiblesManager.GetCollectibleOwnership(id)
}
func (api *API) RefetchOwnedCollectibles() error {
log.Debug("wallet.api.RefetchOwnedCollectibles")

View File

@ -417,6 +417,10 @@ func (o *Manager) FetchCollectionsDataByContractID(ctx context.Context, ids []th
return mapToList(data), nil
}
func (o *Manager) GetCollectibleOwnership(id thirdparty.CollectibleUniqueID) ([]thirdparty.AccountBalance, error) {
return o.ownershipDB.GetOwnership(id)
}
func (o *Manager) getContractOwnershipProviders(chainID walletCommon.ChainID) (mainProvider thirdparty.CollectibleContractOwnershipProvider, fallbackProvider thirdparty.CollectibleContractOwnershipProvider) {
mainProvider = nil
fallbackProvider = nil