From eb5bad48686ed21617e5f5a45f5a20a2b8952884 Mon Sep 17 00:00:00 2001 From: Mikhail Rogachev Date: Thu, 22 Feb 2024 11:08:58 +0300 Subject: [PATCH] Feat: Profile showcase validate collectible ownership (#4737) * feat: profile showcase checks then presenting collectibles * chore: more obvious CollectiblesManager configuration --- protocol/communities/manager.go | 6 + protocol/communities/manager_test.go | 5 + protocol/identity/profile_showcase.go | 22 --- protocol/messenger.go | 11 +- protocol/messenger_backup_test.go | 2 +- protocol/messenger_config.go | 8 + protocol/messenger_profile_showcase.go | 101 ++++++++++- protocol/messenger_profile_showcase_test.go | 168 ++++++++++++++++-- protocol/messenger_testing_utils.go | 41 +++-- protocol/persistence_profile_showcase_test.go | 26 +-- server/pairing/sync_device_test.go | 2 +- services/wallet/api.go | 4 + services/wallet/collectibles/manager.go | 4 + 13 files changed, 312 insertions(+), 88 deletions(-) diff --git a/protocol/communities/manager.go b/protocol/communities/manager.go index 8c570b008..64c80e8a7 100644 --- a/protocol/communities/manager.go +++ b/protocol/communities/manager.go @@ -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 diff --git a/protocol/communities/manager_test.go b/protocol/communities/manager_test.go index 65f4913a0..8e9d5085e 100644 --- a/protocol/communities/manager_test.go +++ b/protocol/communities/manager_test.go @@ -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 } diff --git a/protocol/identity/profile_showcase.go b/protocol/identity/profile_showcase.go index 173ef16b0..abb1daec9 100644 --- a/protocol/identity/profile_showcase.go +++ b/protocol/identity/profile_showcase.go @@ -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 } diff --git a/protocol/messenger.go b/protocol/messenger.go index bfaf13cf4..961802d8f 100644 --- a/protocol/messenger.go +++ b/protocol/messenger.go @@ -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 { diff --git a/protocol/messenger_backup_test.go b/protocol/messenger_backup_test.go index faa630b9a..db0b61cf7 100644 --- a/protocol/messenger_backup_test.go +++ b/protocol/messenger_backup_test.go @@ -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) diff --git a/protocol/messenger_config.go b/protocol/messenger_config.go index 75cb52a32..79fe2c9ed 100644 --- a/protocol/messenger_config.go +++ b/protocol/messenger_config.go @@ -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 diff --git a/protocol/messenger_profile_showcase.go b/protocol/messenger_profile_showcase.go index 7c1ea0184..fd43da1e8 100644 --- a/protocol/messenger_profile_showcase.go +++ b/protocol/messenger_profile_showcase.go @@ -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 diff --git a/protocol/messenger_profile_showcase_test.go b/protocol/messenger_profile_showcase_test.go index cb94428d3..e9beec425 100644 --- a/protocol/messenger_profile_showcase_test.go +++ b/protocol/messenger_profile_showcase_test.go @@ -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) diff --git a/protocol/messenger_testing_utils.go b/protocol/messenger_testing_utils.go index 7ad0f782c..3c221b41a 100644 --- a/protocol/messenger_testing_utils.go +++ b/protocol/messenger_testing_utils.go @@ -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 } diff --git a/protocol/persistence_profile_showcase_test.go b/protocol/persistence_profile_showcase_test.go index 9705feeaa..2ddefaf58 100644 --- a/protocol/persistence_profile_showcase_test.go +++ b/protocol/persistence_profile_showcase_test.go @@ -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{ diff --git a/server/pairing/sync_device_test.go b/server/pairing/sync_device_test.go index f23bb2885..ea13fd41b 100644 --- a/server/pairing/sync_device_test.go +++ b/server/pairing/sync_device_test.go @@ -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) diff --git a/services/wallet/api.go b/services/wallet/api.go index 2c7871cc7..1a073c232 100644 --- a/services/wallet/api.go +++ b/services/wallet/api.go @@ -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") diff --git a/services/wallet/collectibles/manager.go b/services/wallet/collectibles/manager.go index d05dcad7a..a9e6c7718 100644 --- a/services/wallet/collectibles/manager.go +++ b/services/wallet/collectibles/manager.go @@ -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