package protocol import ( "math/big" "testing" "time" "github.com/stretchr/testify/suite" "go.uber.org/zap" gethcommon "github.com/ethereum/go-ethereum/common" hexutil "github.com/ethereum/go-ethereum/common/hexutil" 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/protocol/common" "github.com/status-im/status-go/protocol/communities" "github.com/status-im/status-go/protocol/protobuf" "github.com/status-im/status-go/protocol/requests" "github.com/status-im/status-go/protocol/tt" ) func TestMessengerCommunitiesSharedMemberAddressSuite(t *testing.T) { suite.Run(t, new(MessengerCommunitiesSharedMemberAddressSuite)) } type MessengerCommunitiesSharedMemberAddressSuite struct { suite.Suite owner *Messenger bob *Messenger alice *Messenger ownerWaku types.Waku bobWaku types.Waku aliceWaku types.Waku logger *zap.Logger mockedBalances map[uint64]map[gethcommon.Address]map[gethcommon.Address]*hexutil.Big // chainID, account, token, balance collectiblesServiceMock *CollectiblesServiceMock } func (s *MessengerCommunitiesSharedMemberAddressSuite) SetupTest() { // Initialize with nil to avoid panics in TearDownTest s.owner = nil s.bob = nil s.alice = nil s.ownerWaku = nil s.bobWaku = nil s.aliceWaku = nil communities.SetValidateInterval(300 * time.Millisecond) s.collectiblesServiceMock = &CollectiblesServiceMock{} s.resetMockedBalances() s.logger = tt.MustCreateTestLogger() wakuNodes := CreateWakuV2Network(&s.Suite, s.logger, false, []string{"owner", "bob", "alice"}) s.ownerWaku = wakuNodes[0] s.owner = s.newMessenger(ownerPassword, []string{ownerAddress}, s.ownerWaku, "owner", []Option{}) s.bobWaku = wakuNodes[1] s.bob = s.newMessenger(bobPassword, []string{bobAddress}, s.bobWaku, "bob", []Option{}) s.bob.EnableBackedupMessagesProcessing() s.aliceWaku = wakuNodes[2] s.alice = s.newMessenger(alicePassword, []string{aliceAddress1, aliceAddress2}, s.aliceWaku, "alice", []Option{}) _, err := s.owner.Start() s.Require().NoError(err) _, err = s.bob.Start() s.Require().NoError(err) _, err = s.alice.Start() s.Require().NoError(err) } func (s *MessengerCommunitiesSharedMemberAddressSuite) TearDownTest() { TearDownMessenger(&s.Suite, s.owner) TearDownMessenger(&s.Suite, s.bob) TearDownMessenger(&s.Suite, s.alice) if s.ownerWaku != nil { s.Require().NoError(gethbridge.GetGethWakuV2From(s.ownerWaku).Stop()) } if s.bobWaku != nil { s.Require().NoError(gethbridge.GetGethWakuV2From(s.bobWaku).Stop()) } if s.aliceWaku != nil { s.Require().NoError(gethbridge.GetGethWakuV2From(s.aliceWaku).Stop()) } _ = s.logger.Sync() } func (s *MessengerCommunitiesSharedMemberAddressSuite) newMessenger(password string, walletAddresses []string, waku types.Waku, name string, extraOptions []Option) *Messenger { communityManagerOptions := []communities.ManagerOption{ communities.WithAllowForcingCommunityMembersReevaluation(true), } extraOptions = append(extraOptions, WithCommunityManagerOptions(communityManagerOptions)) return newTestCommunitiesMessenger(&s.Suite, waku, testCommunitiesMessengerConfig{ testMessengerConfig: testMessengerConfig{ logger: s.logger.Named(name), extraOptions: extraOptions, }, password: password, walletAddresses: walletAddresses, mockedBalances: &s.mockedBalances, collectiblesService: s.collectiblesServiceMock, }) } func (s *MessengerCommunitiesSharedMemberAddressSuite) joinCommunity(community *communities.Community, user *Messenger, password string, addresses []string) { s.joinCommunityWithAirdropAddress(community, user, password, addresses, "") } func (s *MessengerCommunitiesSharedMemberAddressSuite) joinCommunityWithAirdropAddress(community *communities.Community, user *Messenger, password string, addresses []string, airdropAddress string) { passwdHash := types.EncodeHex(crypto.Keccak256([]byte(password))) if airdropAddress == "" && len(addresses) > 0 { airdropAddress = addresses[0] } request := &requests.RequestToJoinCommunity{CommunityID: community.ID(), AddressesToReveal: addresses, AirdropAddress: airdropAddress} joinCommunity(&s.Suite, community, s.owner, user, request, passwdHash) } func (s *MessengerCommunitiesSharedMemberAddressSuite) checkRevealedAccounts(communityID types.HexBytes, user *Messenger, expectedAccounts []*protobuf.RevealedAccount) { revealedAccounts, err := user.communitiesManager.GetRevealedAddresses(communityID, s.alice.IdentityPublicKeyString()) s.Require().NoError(err) s.Require().Equal(revealedAccounts, expectedAccounts) } func (s *MessengerCommunitiesSharedMemberAddressSuite) makeAddressSatisfyTheCriteria(chainID uint64, address string, criteria *protobuf.TokenCriteria) { walletAddress := gethcommon.HexToAddress(address) contractAddress := gethcommon.HexToAddress(criteria.ContractAddresses[chainID]) balance, ok := new(big.Int).SetString(criteria.AmountInWei, 10) s.Require().True(ok) s.mockedBalances[chainID][walletAddress][contractAddress] = (*hexutil.Big)(balance) } func (s *MessengerCommunitiesSharedMemberAddressSuite) resetMockedBalances() { s.mockedBalances = make(map[uint64]map[gethcommon.Address]map[gethcommon.Address]*hexutil.Big) s.mockedBalances[testChainID1] = make(map[gethcommon.Address]map[gethcommon.Address]*hexutil.Big) s.mockedBalances[testChainID1][gethcommon.HexToAddress(aliceAddress1)] = make(map[gethcommon.Address]*hexutil.Big) s.mockedBalances[testChainID1][gethcommon.HexToAddress(aliceAddress2)] = make(map[gethcommon.Address]*hexutil.Big) s.mockedBalances[testChainID1][gethcommon.HexToAddress(bobAddress)] = make(map[gethcommon.Address]*hexutil.Big) } func createTokenMasterTokenCriteria() *protobuf.TokenCriteria { return &protobuf.TokenCriteria{ ContractAddresses: map[uint64]string{testChainID1: "0x123"}, Type: protobuf.CommunityTokenType_ERC20, Symbol: "STT", Name: "Status Test Token", AmountInWei: "10000000000000000000", Decimals: 18, } } func (s *MessengerCommunitiesSharedMemberAddressSuite) createEditSharedAddressesRequest(communityID types.HexBytes) *requests.EditSharedAddresses { request := &requests.EditSharedAddresses{CommunityID: communityID, AddressesToReveal: []string{aliceAddress2}, AirdropAddress: aliceAddress2} signingParams, err := s.alice.GenerateJoiningCommunityRequestsForSigning(common.PubkeyToHex(&s.alice.identity.PublicKey), communityID, request.AddressesToReveal) s.Require().NoError(err) passwdHash := types.EncodeHex(crypto.Keccak256([]byte(alicePassword))) for i := range signingParams { signingParams[i].Password = passwdHash } signatures, err := s.alice.SignData(signingParams) s.Require().NoError(err) updateAddresses := len(request.AddressesToReveal) == 0 if updateAddresses { request.AddressesToReveal = make([]string, len(signingParams)) } for i := range signingParams { request.AddressesToReveal[i] = signingParams[i].Address request.Signatures = append(request.Signatures, types.FromHex(signatures[i])) } if updateAddresses { request.AirdropAddress = request.AddressesToReveal[0] } return request } func (s *MessengerCommunitiesSharedMemberAddressSuite) TestJoinedCommunityMembersSharedAddress() { community, _ := createCommunity(&s.Suite, s.owner) advertiseCommunityTo(&s.Suite, community, s.owner, s.alice) advertiseCommunityTo(&s.Suite, community, s.owner, s.bob) s.joinCommunity(community, s.alice, alicePassword, []string{}) s.joinCommunity(community, s.bob, bobPassword, []string{}) community, err := s.owner.GetCommunityByID(community.ID()) s.Require().NoError(err) s.Require().Equal(3, community.MembersCount()) // Check owner's DB for revealed accounts for pubKey := range community.Members() { if pubKey != common.PubkeyToHex(&s.owner.identity.PublicKey) { revealedAccounts, err := s.owner.communitiesManager.GetRevealedAddresses(community.ID(), pubKey) s.Require().NoError(err) switch pubKey { case common.PubkeyToHex(&s.alice.identity.PublicKey): s.Require().Len(revealedAccounts, 2) s.Require().Equal(revealedAccounts[0].Address, aliceAddress1) s.Require().Equal(revealedAccounts[1].Address, aliceAddress2) s.Require().Equal(true, revealedAccounts[0].IsAirdropAddress) case common.PubkeyToHex(&s.bob.identity.PublicKey): s.Require().Len(revealedAccounts, 1) s.Require().Equal(revealedAccounts[0].Address, bobAddress) s.Require().Equal(true, revealedAccounts[0].IsAirdropAddress) default: s.Require().Fail("pubKey does not match expected keys") } } } // Check Bob's DB for revealed accounts revealedAccountsInBobsDB, err := s.bob.communitiesManager.GetRevealedAddresses(community.ID(), common.PubkeyToHex(&s.bob.identity.PublicKey)) s.Require().NoError(err) s.Require().Len(revealedAccountsInBobsDB, 1) s.Require().Equal(revealedAccountsInBobsDB[0].Address, bobAddress) s.Require().Equal(true, revealedAccountsInBobsDB[0].IsAirdropAddress) // Check Alices's DB for revealed accounts revealedAccountsInAlicesDB, err := s.alice.communitiesManager.GetRevealedAddresses(community.ID(), common.PubkeyToHex(&s.alice.identity.PublicKey)) s.Require().NoError(err) s.Require().Len(revealedAccountsInAlicesDB, 2) s.Require().Equal(revealedAccountsInAlicesDB[0].Address, aliceAddress1) s.Require().Equal(revealedAccountsInAlicesDB[1].Address, aliceAddress2) s.Require().Equal(true, revealedAccountsInAlicesDB[0].IsAirdropAddress) } func (s *MessengerCommunitiesSharedMemberAddressSuite) TestJoinedCommunityMembersSelectedSharedAddress() { community, _ := createCommunity(&s.Suite, s.owner) advertiseCommunityTo(&s.Suite, community, s.owner, s.alice) s.joinCommunity(community, s.alice, alicePassword, []string{aliceAddress2}) community, err := s.owner.GetCommunityByID(community.ID()) s.Require().NoError(err) s.Require().Equal(2, community.MembersCount()) alicePubkey := common.PubkeyToHex(&s.alice.identity.PublicKey) // Check Alice's DB for revealed accounts revealedAccountsInAlicesDB, err := s.alice.communitiesManager.GetRevealedAddresses(community.ID(), alicePubkey) s.Require().NoError(err) s.Require().Len(revealedAccountsInAlicesDB, 1) s.Require().Equal(revealedAccountsInAlicesDB[0].Address, aliceAddress2) s.Require().Equal(true, revealedAccountsInAlicesDB[0].IsAirdropAddress) // Check owner's DB for revealed accounts s.checkRevealedAccounts(community.ID(), s.owner, revealedAccountsInAlicesDB) } func (s *MessengerCommunitiesSharedMemberAddressSuite) TestJoinedCommunityMembersMultipleSelectedSharedAddresses() { community, _ := createCommunity(&s.Suite, s.owner) advertiseCommunityTo(&s.Suite, community, s.owner, s.alice) s.joinCommunityWithAirdropAddress(community, s.alice, alicePassword, []string{aliceAddress1, aliceAddress2}, aliceAddress2) community, err := s.owner.GetCommunityByID(community.ID()) s.Require().NoError(err) s.Require().Equal(2, community.MembersCount()) alicePubkey := common.PubkeyToHex(&s.alice.identity.PublicKey) // Check Alice's DB for revealed accounts revealedAccountsInAlicesDB, err := s.alice.communitiesManager.GetRevealedAddresses(community.ID(), alicePubkey) s.Require().NoError(err) s.Require().Len(revealedAccountsInAlicesDB, 2) s.Require().Equal(revealedAccountsInAlicesDB[0].Address, aliceAddress1) s.Require().Equal(revealedAccountsInAlicesDB[1].Address, aliceAddress2) s.Require().Equal(true, revealedAccountsInAlicesDB[1].IsAirdropAddress) // Check owner's DB for revealed accounts s.checkRevealedAccounts(community.ID(), s.owner, revealedAccountsInAlicesDB) } func (s *MessengerCommunitiesSharedMemberAddressSuite) TestEditSharedAddresses() { community, _ := createCommunity(&s.Suite, s.owner) alicePubkey := common.PubkeyToHex(&s.alice.identity.PublicKey) advertiseCommunityTo(&s.Suite, community, s.owner, s.alice) s.joinCommunity(community, s.alice, alicePassword, []string{aliceAddress1}) community, err := s.owner.GetCommunityByID(community.ID()) s.Require().NoError(err) s.Require().Equal(2, community.MembersCount()) aliceExpectedRevealedAccounts, err := s.alice.communitiesManager.GetRevealedAddresses(community.ID(), alicePubkey) s.Require().NoError(err) s.Require().Len(aliceExpectedRevealedAccounts, 1) s.Require().Equal(aliceExpectedRevealedAccounts[0].Address, aliceAddress1) s.Require().Equal(true, aliceExpectedRevealedAccounts[0].IsAirdropAddress) s.checkRevealedAccounts(community.ID(), s.owner, aliceExpectedRevealedAccounts) request := s.createEditSharedAddressesRequest(community.ID()) response, err := s.alice.EditSharedAddressesForCommunity(request) s.Require().NoError(err) s.Require().NotNil(response) aliceExpectedRevealedAccounts, err = s.alice.communitiesManager.GetRevealedAddresses(community.ID(), alicePubkey) s.Require().NoError(err) s.Require().Len(aliceExpectedRevealedAccounts, 1) s.Require().Equal(aliceExpectedRevealedAccounts[0].Address, aliceAddress2) s.Require().Equal(true, aliceExpectedRevealedAccounts[0].IsAirdropAddress) // check that owner received revealed address _, err = WaitOnMessengerResponse(s.owner, func(r *MessengerResponse) bool { revealedAccounts, err := s.owner.communitiesManager.GetRevealedAddresses(community.ID(), s.alice.IdentityPublicKeyString()) s.Require().NoError(err) s.Require().Len(revealedAccounts, 1) return revealedAccounts[0].Address == aliceAddress2 }, "owned did not receive alice shared address") s.Require().NoError(err) s.checkRevealedAccounts(community.ID(), s.owner, aliceExpectedRevealedAccounts) // check that we filter out outdated edit shared addresses events community, err = s.owner.GetCommunityByID(community.ID()) s.Require().NoError(err) aliceClock := community.Description().Members[s.alice.IdentityPublicKeyString()].LastUpdateClock s.Require().Greater(aliceClock, uint64(1)) editMsg := &protobuf.CommunityEditSharedAddresses{ Clock: aliceClock - 1, CommunityId: community.ID(), RevealedAccounts: aliceExpectedRevealedAccounts, } state := &ReceivedMessageState{ CurrentMessageState: &CurrentMessageState{ PublicKey: s.alice.IdentityPublicKey(), }, } err = s.owner.HandleCommunityEditSharedAddresses(state, editMsg, nil) s.Require().Error(err, communities.ErrEditSharedAddressesRequestOutdated) } func (s *MessengerCommunitiesSharedMemberAddressSuite) TestTokenMasterReceivesEditedSharedAddresses() { community, _ := createCommunity(&s.Suite, s.owner) alicePubkey := s.alice.IdentityPublicKeyString() tokenCriteria := createTokenMasterTokenCriteria() _, err := s.owner.CreateCommunityTokenPermission(&requests.CreateCommunityTokenPermission{ CommunityID: community.ID(), Type: protobuf.CommunityTokenPermission_BECOME_TOKEN_MASTER, TokenCriteria: []*protobuf.TokenCriteria{tokenCriteria}, }) s.Require().NoError(err) advertiseCommunityTo(&s.Suite, community, s.owner, s.alice) s.joinCommunity(community, s.alice, alicePassword, []string{aliceAddress1}) community, err = s.owner.communitiesManager.GetByID(community.ID()) s.Require().NoError(err) // make bob satisfy the Token Master criteria s.makeAddressSatisfyTheCriteria(testChainID1, bobAddress, tokenCriteria) advertiseCommunityTo(&s.Suite, community, s.owner, s.bob) s.joinCommunity(community, s.bob, bobPassword, []string{bobAddress}) // check bob has TM role community, err = s.bob.communitiesManager.GetByID(community.ID()) s.Require().NoError(err) checkRoleBasedOnThePermissionType(protobuf.CommunityTokenPermission_BECOME_TOKEN_MASTER, &s.bob.identity.PublicKey, community) aliceRevealedAccounts, err := s.bob.GetRevealedAccounts(community.ID(), alicePubkey) s.Require().NoError(err) s.Require().Len(aliceRevealedAccounts, 1) request := s.createEditSharedAddressesRequest(community.ID()) response, err := s.alice.EditSharedAddressesForCommunity(request) s.Require().NoError(err) s.Require().NotNil(response) expectedAliceRevealedAccounts, err := s.alice.communitiesManager.GetRevealedAddresses(community.ID(), alicePubkey) s.Require().NoError(err) s.Require().Len(expectedAliceRevealedAccounts, 1) s.Require().Equal(expectedAliceRevealedAccounts[0].Address, aliceAddress2) s.Require().Equal(true, expectedAliceRevealedAccounts[0].IsAirdropAddress) // check that owner received revealed address _, err = WaitOnMessengerResponse(s.owner, func(r *MessengerResponse) bool { revealedAccounts, err := s.owner.communitiesManager.GetRevealedAddresses(community.ID(), s.alice.IdentityPublicKeyString()) s.Require().NoError(err) s.Require().Len(revealedAccounts, 1) return revealedAccounts[0].Address == aliceAddress2 }, "owned did not receive alice shared address") s.Require().NoError(err) s.checkRevealedAccounts(community.ID(), s.owner, expectedAliceRevealedAccounts) // check that bob as a token master received revealed address _, err = WaitOnMessengerResponse(s.bob, func(r *MessengerResponse) bool { revealedAccounts, err := s.bob.communitiesManager.GetRevealedAddresses(community.ID(), s.alice.IdentityPublicKeyString()) s.Require().NoError(err) s.Require().Len(revealedAccounts, 1) return revealedAccounts[0].Address == aliceAddress2 }, "user not accepted") s.Require().NoError(err) s.checkRevealedAccounts(community.ID(), s.bob, expectedAliceRevealedAccounts) } func (s *MessengerCommunitiesSharedMemberAddressSuite) TestSharedAddressesReturnsRevealedAccount() { community, _ := createCommunity(&s.Suite, s.owner) permissionRequest := requests.CreateCommunityTokenPermission{ CommunityID: community.ID(), Type: protobuf.CommunityTokenPermission_CAN_VIEW_AND_POST_CHANNEL, TokenCriteria: []*protobuf.TokenCriteria{ &protobuf.TokenCriteria{ Type: protobuf.CommunityTokenType_ERC20, ContractAddresses: map[uint64]string{testChainID1: "0x123"}, Symbol: "TEST", AmountInWei: "100000000000000000000", Decimals: uint64(18), }, }, } response, err := s.owner.CreateCommunityTokenPermission(&permissionRequest) s.Require().NoError(err) s.Require().Len(response.Communities(), 1) advertiseCommunityTo(&s.Suite, community, s.owner, s.alice) s.joinCommunity(community, s.alice, alicePassword, []string{}) revealedAccounts, err := s.alice.GetRevealedAccounts(community.ID(), common.PubkeyToHex(&s.alice.identity.PublicKey)) s.Require().NoError(err) revealedAddressesMap := make(map[string]struct{}, len(revealedAccounts)) for _, acc := range revealedAccounts { revealedAddressesMap[acc.Address] = struct{}{} } s.Require().Len(revealedAddressesMap, 2) s.Require().Contains(revealedAddressesMap, aliceAddress1) s.Require().Contains(revealedAddressesMap, aliceAddress2) sharedAddresses, err := s.alice.getSharedAddresses(community.ID(), []string{}) s.Require().NoError(err) s.Require().Len(sharedAddresses, 2) sharedAddressesMap := make(map[string]struct{}, len(sharedAddresses)) for _, acc := range sharedAddresses { sharedAddressesMap[acc.String()] = struct{}{} } s.Require().Len(sharedAddressesMap, 2) s.Require().Contains(sharedAddressesMap, aliceAddress1) s.Require().Contains(sharedAddressesMap, aliceAddress2) } func (s *MessengerCommunitiesSharedMemberAddressSuite) TestResendSharedAddressesOnBackupRestore() { community, _ := createCommunity(&s.Suite, s.owner) // bob joins the community advertiseCommunityTo(&s.Suite, community, s.owner, s.bob) s.joinCommunity(community, s.bob, bobPassword, []string{bobAddress}) currentBobSharedAddresses, err := s.bob.GetRevealedAccounts(community.ID(), s.bob.IdentityPublicKeyString()) s.Require().NoError(err) s.Require().Len(currentBobSharedAddresses, 1) requestID := communities.CalculateRequestID(s.bob.IdentityPublicKeyString(), community.ID()) err = s.bob.communitiesManager.RemoveRequestToJoinRevealedAddresses(requestID) s.Require().NoError(err) emptySharedAddresses, err := s.bob.GetRevealedAccounts(community.ID(), s.bob.IdentityPublicKeyString()) s.Require().NoError(err) s.Require().Len(emptySharedAddresses, 0) // Simulate backup creation and handling backup message // As a result, bob sends request to resend encryption keys to the owner clock, _ := s.bob.getLastClockWithRelatedChat() community, err = s.owner.communitiesManager.GetByID(community.ID()) s.Require().NoError(err) backupMessage, err := s.bob.backupCommunity(community, clock) s.Require().NoError(err) err = s.bob.HandleBackup(s.bob.buildMessageState(), backupMessage, nil) s.Require().NoError(err) // Owner will receive the request for addresses and send them back to Bob response, err := WaitOnMessengerResponse( s.bob, func(r *MessengerResponse) bool { _, _ = s.owner.RetrieveAll() return len(r.requestsToJoinCommunity) > 0 }, "request to join not received", ) s.Require().NoError(err) requestToJoin, ok := response.requestsToJoinCommunity[requestID.String()] s.Require().Equal(true, ok) s.Require().Equal(currentBobSharedAddresses, requestToJoin.RevealedAccounts) currentBobSharedAddresses, err = s.bob.GetRevealedAccounts(community.ID(), s.bob.IdentityPublicKeyString()) s.Require().NoError(err) s.Require().Len(currentBobSharedAddresses, 1) } func (s *MessengerCommunitiesSharedMemberAddressSuite) TestTokenMasterReceivesMembersSharedAddressesOnBackupRestore() { community, _ := createCommunity(&s.Suite, s.owner) tokenCriteria := createTokenMasterTokenCriteria() _, err := s.owner.CreateCommunityTokenPermission(&requests.CreateCommunityTokenPermission{ CommunityID: community.ID(), Type: protobuf.CommunityTokenPermission_BECOME_TOKEN_MASTER, TokenCriteria: []*protobuf.TokenCriteria{tokenCriteria}, }) s.Require().NoError(err) advertiseCommunityTo(&s.Suite, community, s.owner, s.alice) s.joinCommunity(community, s.alice, alicePassword, []string{aliceAddress1}) expectedAliceRevealedAccounts, err := s.alice.GetRevealedAccounts(community.ID(), s.alice.IdentityPublicKeyString()) s.Require().NoError(err) s.Require().Len(expectedAliceRevealedAccounts, 1) s.Require().Equal(expectedAliceRevealedAccounts[0].Address, aliceAddress1) community, err = s.owner.communitiesManager.GetByID(community.ID()) s.Require().NoError(err) // make bob satisfy the Token Master criteria s.makeAddressSatisfyTheCriteria(testChainID1, bobAddress, tokenCriteria) advertiseCommunityTo(&s.Suite, community, s.owner, s.bob) s.joinCommunity(community, s.bob, bobPassword, []string{bobAddress}) // check bob has TM role community, err = s.bob.communitiesManager.GetByID(community.ID()) s.Require().NoError(err) checkRoleBasedOnThePermissionType(protobuf.CommunityTokenPermission_BECOME_TOKEN_MASTER, &s.bob.identity.PublicKey, community) s.checkRevealedAccounts(community.ID(), s.bob, expectedAliceRevealedAccounts) // remove alice revealed addresses aliceRequestID := communities.CalculateRequestID(s.alice.IdentityPublicKeyString(), community.ID()) err = s.bob.communitiesManager.RemoveRequestToJoinRevealedAddresses(aliceRequestID) s.Require().NoError(err) emptySharedAddresses, err := s.bob.GetRevealedAccounts(community.ID(), s.alice.IdentityPublicKeyString()) s.Require().NoError(err) s.Require().Len(emptySharedAddresses, 0) s.Require().NotEqual(emptySharedAddresses, expectedAliceRevealedAccounts) // Simulate backup creation and handling backup message // As a result, bob sends request to resend encryption keys to the owner clock, _ := s.bob.getLastClockWithRelatedChat() community, err = s.owner.communitiesManager.GetByID(community.ID()) s.Require().NoError(err) backupMessage, err := s.bob.backupCommunity(community, clock) s.Require().NoError(err) err = s.bob.HandleBackup(s.bob.buildMessageState(), backupMessage, nil) s.Require().NoError(err) // Owner will receive the request for addresses and send requests to join with revealed // addresses to token master _, err = WaitOnMessengerResponse( s.bob, func(r *MessengerResponse) bool { _, _ = s.owner.RetrieveAll() if len(r.requestsToJoinCommunity) == 0 { return false } for _, requestToJoin := range r.requestsToJoinCommunity { if requestToJoin.PublicKey == s.alice.IdentityPublicKeyString() { return true } } return false }, "alice request to join with revealed addresses not received", ) s.Require().NoError(err) s.checkRevealedAccounts(community.ID(), s.bob, expectedAliceRevealedAccounts) } func (s *MessengerCommunitiesSharedMemberAddressSuite) TestTokenMasterReceivedRevealedAddressesFromJoinedMember() { community, _ := createCommunity(&s.Suite, s.owner) tokenCriteria := createTokenMasterTokenCriteria() _, err := s.owner.CreateCommunityTokenPermission(&requests.CreateCommunityTokenPermission{ CommunityID: community.ID(), Type: protobuf.CommunityTokenPermission_BECOME_TOKEN_MASTER, TokenCriteria: []*protobuf.TokenCriteria{tokenCriteria}, }) s.Require().NoError(err) community, err = s.owner.communitiesManager.GetByID(community.ID()) s.Require().NoError(err) s.Require().Len(community.TokenPermissions(), 1) // make bob satisfy the Token Master criteria s.makeAddressSatisfyTheCriteria(testChainID1, bobAddress, tokenCriteria) advertiseCommunityTo(&s.Suite, community, s.owner, s.bob) s.joinCommunity(community, s.bob, bobPassword, []string{bobAddress}) // check bob has TM role community, err = s.bob.communitiesManager.GetByID(community.ID()) s.Require().NoError(err) checkRoleBasedOnThePermissionType(protobuf.CommunityTokenPermission_BECOME_TOKEN_MASTER, &s.bob.identity.PublicKey, community) community, err = s.owner.communitiesManager.GetByID(community.ID()) s.Require().NoError(err) advertiseCommunityTo(&s.Suite, community, s.owner, s.alice) s.joinCommunity(community, s.alice, alicePassword, []string{aliceAddress1}) // check that bob received revealed address _, err = WaitOnMessengerResponse(s.bob, func(r *MessengerResponse) bool { return len(r.RequestsToJoinCommunity()) == 1 && r.RequestsToJoinCommunity()[0].PublicKey == s.alice.IdentityPublicKeyString() }, "user not accepted") s.Require().NoError(err) expectedAliceRevealedAccounts, err := s.alice.communitiesManager.GetRevealedAddresses(community.ID(), s.alice.IdentityPublicKeyString()) s.Require().NoError(err) s.Require().Len(expectedAliceRevealedAccounts, 1) s.Require().Equal(expectedAliceRevealedAccounts[0].Address, aliceAddress1) s.Require().Equal(true, expectedAliceRevealedAccounts[0].IsAirdropAddress) s.checkRevealedAccounts(community.ID(), s.bob, expectedAliceRevealedAccounts) } func (s *MessengerCommunitiesSharedMemberAddressSuite) TestTokenMasterJoinedToCommunityAndReceivedRevealedAddresses() { community, _ := createCommunity(&s.Suite, s.owner) tokenCriteria := createTokenMasterTokenCriteria() _, err := s.owner.CreateCommunityTokenPermission(&requests.CreateCommunityTokenPermission{ CommunityID: community.ID(), Type: protobuf.CommunityTokenPermission_BECOME_TOKEN_MASTER, TokenCriteria: []*protobuf.TokenCriteria{tokenCriteria}, }) s.Require().NoError(err) community, err = s.owner.communitiesManager.GetByID(community.ID()) s.Require().NoError(err) s.Require().Len(community.TokenPermissions(), 1) advertiseCommunityTo(&s.Suite, community, s.owner, s.alice) s.joinCommunity(community, s.alice, alicePassword, []string{aliceAddress1}) community, err = s.owner.communitiesManager.GetByID(community.ID()) s.Require().NoError(err) // make bob satisfy the Token Master criteria s.makeAddressSatisfyTheCriteria(testChainID1, bobAddress, tokenCriteria) advertiseCommunityTo(&s.Suite, community, s.owner, s.bob) s.joinCommunity(community, s.bob, bobPassword, []string{bobAddress}) community, err = s.bob.communitiesManager.GetByID(community.ID()) s.Require().NoError(err) checkRoleBasedOnThePermissionType(protobuf.CommunityTokenPermission_BECOME_TOKEN_MASTER, &s.bob.identity.PublicKey, community) expectedAliceRevealedAccounts, err := s.alice.communitiesManager.GetRevealedAddresses(community.ID(), s.alice.IdentityPublicKeyString()) s.Require().NoError(err) s.Require().Len(expectedAliceRevealedAccounts, 1) s.Require().Equal(expectedAliceRevealedAccounts[0].Address, aliceAddress1) s.Require().Equal(true, expectedAliceRevealedAccounts[0].IsAirdropAddress) s.checkRevealedAccounts(community.ID(), s.bob, expectedAliceRevealedAccounts) } func (s *MessengerCommunitiesSharedMemberAddressSuite) TestMemberReceivedSharedAddressOnGettingTokenMasterRole() { community, _ := createCommunity(&s.Suite, s.owner) community, err := s.owner.communitiesManager.GetByID(community.ID()) s.Require().NoError(err) s.Require().Len(community.TokenPermissions(), 0) advertiseCommunityTo(&s.Suite, community, s.owner, s.alice) s.joinCommunity(community, s.alice, alicePassword, []string{aliceAddress1}) advertiseCommunityTo(&s.Suite, community, s.owner, s.bob) s.joinCommunity(community, s.bob, bobPassword, []string{bobAddress}) tokenCriteria := createTokenMasterTokenCriteria() // make bob satisfy the Token Master criteria s.makeAddressSatisfyTheCriteria(testChainID1, bobAddress, tokenCriteria) // wait for owner to send sync message for bob, who got a TM role waitOnOwnerSendSyncMessage := waitOnCommunitiesEvent(s.owner, func(sub *communities.Subscription) bool { return sub.CommunityPrivilegedMemberSyncMessage != nil && sub.CommunityPrivilegedMemberSyncMessage.CommunityPrivilegedUserSyncMessage.Type == protobuf.CommunityPrivilegedUserSyncMessage_CONTROL_NODE_ALL_SYNC_REQUESTS_TO_JOIN && len(sub.CommunityPrivilegedMemberSyncMessage.Receivers) == 1 && sub.CommunityPrivilegedMemberSyncMessage.Receivers[0].Equal(&s.bob.identity.PublicKey) }) _, err = s.owner.CreateCommunityTokenPermission(&requests.CreateCommunityTokenPermission{ CommunityID: community.ID(), Type: protobuf.CommunityTokenPermission_BECOME_TOKEN_MASTER, TokenCriteria: []*protobuf.TokenCriteria{tokenCriteria}, }) s.Require().NoError(err) err = <-waitOnOwnerSendSyncMessage s.Require().NoError(err) _, err = WaitOnMessengerResponse(s.bob, func(r *MessengerResponse) bool { return len(r.Communities()) == 1 && r.Communities()[0].IsTokenMaster() }, "bob didn't receive token master role") s.Require().NoError(err) expectedAliceRevealedAccounts, err := s.alice.communitiesManager.GetRevealedAddresses(community.ID(), s.alice.IdentityPublicKeyString()) s.Require().NoError(err) s.Require().Len(expectedAliceRevealedAccounts, 1) s.Require().Equal(expectedAliceRevealedAccounts[0].Address, aliceAddress1) s.Require().Equal(true, expectedAliceRevealedAccounts[0].IsAirdropAddress) s.checkRevealedAccounts(community.ID(), s.bob, expectedAliceRevealedAccounts) } func (s *MessengerCommunitiesSharedMemberAddressSuite) TestTokenMasterReceivesAccountsAfterPendingRequestToJoinApproval() { community, _ := createOnRequestCommunity(&s.Suite, s.owner) tokenCriteria := createTokenMasterTokenCriteria() // make bob satisfy the Token Master criteria s.makeAddressSatisfyTheCriteria(testChainID1, bobAddress, tokenCriteria) _, err := s.owner.CreateCommunityTokenPermission(&requests.CreateCommunityTokenPermission{ CommunityID: community.ID(), Type: protobuf.CommunityTokenPermission_BECOME_TOKEN_MASTER, TokenCriteria: []*protobuf.TokenCriteria{tokenCriteria}, }) s.Require().NoError(err) community, err = s.owner.communitiesManager.GetByID(community.ID()) s.Require().NoError(err) s.Require().Len(community.TokenPermissions(), 1) advertiseCommunityTo(&s.Suite, community, s.owner, s.alice) advertiseCommunityTo(&s.Suite, community, s.owner, s.bob) aliceArray64Bytes := common.HashPublicKey(&s.alice.identity.PublicKey) aliceSignature := append([]byte{0}, aliceArray64Bytes...) aliceRequest := &requests.RequestToJoinCommunity{ CommunityID: community.ID(), AddressesToReveal: []string{aliceAddress1}, AirdropAddress: aliceAddress1, Signatures: []types.HexBytes{aliceSignature}, } aliceRequestToJoinID := requestToJoinCommunity(&s.Suite, s.owner, s.alice, aliceRequest) bobArray64Bytes := common.HashPublicKey(&s.bob.identity.PublicKey) bobSignature := append([]byte{0}, bobArray64Bytes...) bobRequest := &requests.RequestToJoinCommunity{ CommunityID: community.ID(), AddressesToReveal: []string{bobAddress}, AirdropAddress: bobAddress, Signatures: []types.HexBytes{bobSignature}, } joinOnRequestCommunity(&s.Suite, community, s.owner, s.bob, bobRequest) community, err = s.owner.communitiesManager.GetByID(community.ID()) s.Require().NoError(err) s.Require().True(community.IsMemberTokenMaster(&s.bob.identity.PublicKey)) _, err = s.owner.AcceptRequestToJoinCommunity(&requests.AcceptRequestToJoinCommunity{ID: aliceRequestToJoinID}) s.Require().NoError(err) _, err = WaitOnMessengerResponse(s.bob, func(r *MessengerResponse) bool { if r.RequestsToJoinCommunity() != nil { for _, request := range r.RequestsToJoinCommunity() { if request.PublicKey == s.alice.IdentityPublicKeyString() && request.State == communities.RequestToJoinStateAccepted { return true } } } return false }, "bob didn't receive accepted Alice request to join") s.Require().NoError(err) expectedAliceRevealedAccounts, err := s.alice.communitiesManager.GetRevealedAddresses(community.ID(), s.alice.IdentityPublicKeyString()) s.Require().NoError(err) s.Require().Len(expectedAliceRevealedAccounts, 1) s.Require().Equal(expectedAliceRevealedAccounts[0].Address, aliceAddress1) s.Require().Equal(true, expectedAliceRevealedAccounts[0].IsAirdropAddress) s.checkRevealedAccounts(community.ID(), s.bob, expectedAliceRevealedAccounts) } func (s *MessengerCommunitiesSharedMemberAddressSuite) TestMemberReceivesPendingRequestToJoinAfterAfterGettingTokenMasterRole() { community, _ := createOnRequestCommunity(&s.Suite, s.owner) advertiseCommunityTo(&s.Suite, community, s.owner, s.alice) advertiseCommunityTo(&s.Suite, community, s.owner, s.bob) aliceArray64Bytes := common.HashPublicKey(&s.alice.identity.PublicKey) aliceSignature := append([]byte{0}, aliceArray64Bytes...) aliceRequest := &requests.RequestToJoinCommunity{ CommunityID: community.ID(), AddressesToReveal: []string{aliceAddress1}, AirdropAddress: aliceAddress1, Signatures: []types.HexBytes{aliceSignature}, } aliceRequestToJoinID := requestToJoinCommunity(&s.Suite, s.owner, s.alice, aliceRequest) bobArray64Bytes := common.HashPublicKey(&s.bob.identity.PublicKey) bobSignature := append([]byte{0}, bobArray64Bytes...) bobRequest := &requests.RequestToJoinCommunity{ CommunityID: community.ID(), AddressesToReveal: []string{bobAddress}, AirdropAddress: bobAddress, Signatures: []types.HexBytes{bobSignature}, } joinOnRequestCommunity(&s.Suite, community, s.owner, s.bob, bobRequest) tokenCriteria := createTokenMasterTokenCriteria() // make bob satisfy the Token Master criteria s.makeAddressSatisfyTheCriteria(testChainID1, bobAddress, tokenCriteria) // wait for owner to send sync message for bob, who got a TM role waitOnOwnerSendSyncMessage := waitOnCommunitiesEvent(s.owner, func(sub *communities.Subscription) bool { return sub.CommunityPrivilegedMemberSyncMessage != nil && sub.CommunityPrivilegedMemberSyncMessage.CommunityPrivilegedUserSyncMessage.Type == protobuf.CommunityPrivilegedUserSyncMessage_CONTROL_NODE_ALL_SYNC_REQUESTS_TO_JOIN && len(sub.CommunityPrivilegedMemberSyncMessage.Receivers) == 1 && sub.CommunityPrivilegedMemberSyncMessage.Receivers[0].Equal(&s.bob.identity.PublicKey) }) _, err := s.owner.CreateCommunityTokenPermission(&requests.CreateCommunityTokenPermission{ CommunityID: community.ID(), Type: protobuf.CommunityTokenPermission_BECOME_TOKEN_MASTER, TokenCriteria: []*protobuf.TokenCriteria{tokenCriteria}, }) s.Require().NoError(err) err = <-waitOnOwnerSendSyncMessage s.Require().NoError(err) _, err = WaitOnMessengerResponse(s.bob, func(r *MessengerResponse) bool { return len(r.Communities()) == 1 && r.Communities()[0].IsTokenMaster() }, "bob didn't receive token master role") s.Require().NoError(err) _, err = s.owner.AcceptRequestToJoinCommunity(&requests.AcceptRequestToJoinCommunity{ID: aliceRequestToJoinID}) s.Require().NoError(err) _, err = WaitOnMessengerResponse(s.bob, func(r *MessengerResponse) bool { return len(r.RequestsToJoinCommunity()) > 0 && r.RequestsToJoinCommunity()[0].PublicKey == s.alice.IdentityPublicKeyString() && r.RequestsToJoinCommunity()[0].State == communities.RequestToJoinStateAccepted }, "bob didn't receive accepted Alice request to join") s.Require().NoError(err) expectedAliceRevealedAccounts, err := s.alice.communitiesManager.GetRevealedAddresses(community.ID(), s.alice.IdentityPublicKeyString()) s.Require().NoError(err) s.Require().Len(expectedAliceRevealedAccounts, 1) s.Require().Equal(expectedAliceRevealedAccounts[0].Address, aliceAddress1) s.Require().Equal(true, expectedAliceRevealedAccounts[0].IsAirdropAddress) s.checkRevealedAccounts(community.ID(), s.bob, expectedAliceRevealedAccounts) } func (s *MessengerCommunitiesSharedMemberAddressSuite) TestHandlingOutdatedPrivilegedUserSyncMessages() { community, _ := createCommunity(&s.Suite, s.owner) tokenCriteria := createTokenMasterTokenCriteria() _, err := s.owner.CreateCommunityTokenPermission(&requests.CreateCommunityTokenPermission{ CommunityID: community.ID(), Type: protobuf.CommunityTokenPermission_BECOME_TOKEN_MASTER, TokenCriteria: []*protobuf.TokenCriteria{tokenCriteria}, }) s.Require().NoError(err) community, err = s.owner.communitiesManager.GetByID(community.ID()) s.Require().NoError(err) s.Require().Len(community.TokenPermissions(), 1) // make bob satisfy the Token Master criteria s.makeAddressSatisfyTheCriteria(testChainID1, bobAddress, tokenCriteria) advertiseCommunityTo(&s.Suite, community, s.owner, s.bob) s.joinCommunity(community, s.bob, bobPassword, []string{bobAddress}) // check bob has TM role community, err = s.bob.communitiesManager.GetByID(community.ID()) s.Require().NoError(err) checkRoleBasedOnThePermissionType(protobuf.CommunityTokenPermission_BECOME_TOKEN_MASTER, &s.bob.identity.PublicKey, community) community, err = s.owner.communitiesManager.GetByID(community.ID()) s.Require().NoError(err) advertiseCommunityTo(&s.Suite, community, s.owner, s.alice) s.joinCommunity(community, s.alice, alicePassword, []string{aliceAddress1}) // check that bob received revealed address _, err = WaitOnMessengerResponse(s.bob, func(r *MessengerResponse) bool { return len(r.RequestsToJoinCommunity()) == 1 && r.RequestsToJoinCommunity()[0].PublicKey == s.alice.IdentityPublicKeyString() }, "user not accepted") s.Require().NoError(err) // handle outdated CommunityPrivilegedUserSyncMessage_CONTROL_NODE_ALL_SYNC_REQUESTS_TO_JOIN msg expectedAliceRequestToJoin, err := s.bob.communitiesManager.GetRequestToJoinByPkAndCommunityID(s.alice.IdentityPublicKey(), community.ID()) s.Require().NoError(err) s.Require().NotNil(expectedAliceRequestToJoin) bobRequestToJoin, err := s.bob.communitiesManager.GetRequestToJoinByPkAndCommunityID(s.bob.IdentityPublicKey(), community.ID()) s.Require().NoError(err) s.Require().NotNil(bobRequestToJoin) invalidAliceSyncRtj := expectedAliceRequestToJoin.ToSyncProtobuf() invalidAliceSyncRtj.RevealedAccounts = bobRequestToJoin.RevealedAccounts invalidAliceSyncRtj.EnsName = "corrupted" invalidAliceSyncRtj.State = uint64(communities.RequestToJoinStatePending) syncMsg := &protobuf.CommunityPrivilegedUserSyncMessage{ Type: protobuf.CommunityPrivilegedUserSyncMessage_CONTROL_NODE_ALL_SYNC_REQUESTS_TO_JOIN, CommunityId: community.ID(), SyncRequestsToJoin: []*protobuf.SyncCommunityRequestsToJoin{invalidAliceSyncRtj}, } state := &ReceivedMessageState{ CurrentMessageState: &CurrentMessageState{ PublicKey: community.PublicKey(), }, } err = s.bob.HandleCommunityPrivilegedUserSyncMessage(state, syncMsg, nil) s.Require().NoError(err) aliceRtj, err := s.bob.communitiesManager.GetRequestToJoinByPkAndCommunityID(s.alice.IdentityPublicKey(), community.ID()) s.Require().NoError(err) s.Require().Equal(aliceRtj, expectedAliceRequestToJoin) // handle outdated CommunityPrivilegedUserSyncMessage_CONTROL_NODE_ACCEPT_REQUEST_TO_JOIN msg invalidAliceCommunityRtj := aliceRtj.ToCommunityRequestToJoinProtobuf() invalidAliceCommunityRtj.RevealedAccounts = bobRequestToJoin.RevealedAccounts invalidAliceCommunityRtj.EnsName = "corrupted" syncMsg.Type = protobuf.CommunityPrivilegedUserSyncMessage_CONTROL_NODE_ACCEPT_REQUEST_TO_JOIN syncMsg.RequestToJoin = map[string]*protobuf.CommunityRequestToJoin{ s.alice.IdentityPublicKeyString(): invalidAliceCommunityRtj, } err = s.bob.HandleCommunityPrivilegedUserSyncMessage(state, syncMsg, nil) s.Require().NoError(err) aliceRtj, err = s.bob.communitiesManager.GetRequestToJoinByPkAndCommunityID(s.alice.IdentityPublicKey(), community.ID()) s.Require().NoError(err) s.Require().Equal(aliceRtj, expectedAliceRequestToJoin) } func (s *MessengerCommunitiesSharedMemberAddressSuite) TestMemberReceivedEditedSharedAddressOnGettingTokenMasterRole() { community, _ := createCommunity(&s.Suite, s.owner) alicePubkey := s.alice.IdentityPublicKeyString() advertiseCommunityTo(&s.Suite, community, s.owner, s.alice) s.joinCommunity(community, s.alice, alicePassword, []string{aliceAddress1}) request := s.createEditSharedAddressesRequest(community.ID()) response, err := s.alice.EditSharedAddressesForCommunity(request) s.Require().NoError(err) s.Require().NotNil(response) expectedAliceRevealedAccounts, err := s.alice.communitiesManager.GetRevealedAddresses(community.ID(), alicePubkey) s.Require().NoError(err) s.Require().Len(expectedAliceRevealedAccounts, 1) s.Require().Equal(expectedAliceRevealedAccounts[0].Address, aliceAddress2) s.Require().Equal(true, expectedAliceRevealedAccounts[0].IsAirdropAddress) // check that owner received edited shared adresses _, err = WaitOnMessengerResponse(s.owner, func(r *MessengerResponse) bool { revealedAccounts, err := s.owner.communitiesManager.GetRevealedAddresses(community.ID(), alicePubkey) s.Require().NoError(err) s.Require().Len(revealedAccounts, 1) return revealedAccounts[0].Address == aliceAddress2 }, "owned did not receive alice shared address") s.Require().NoError(err) s.checkRevealedAccounts(community.ID(), s.owner, expectedAliceRevealedAccounts) advertiseCommunityTo(&s.Suite, community, s.owner, s.bob) s.joinCommunity(community, s.bob, bobPassword, []string{bobAddress}) tokenCriteria := createTokenMasterTokenCriteria() // make bob satisfy the Token Master criteria s.makeAddressSatisfyTheCriteria(testChainID1, bobAddress, tokenCriteria) // wait for owner to send sync message for bob, who got a TM role waitOnOwnerSendSyncMessage := waitOnCommunitiesEvent(s.owner, func(sub *communities.Subscription) bool { return sub.CommunityPrivilegedMemberSyncMessage != nil && sub.CommunityPrivilegedMemberSyncMessage.CommunityPrivilegedUserSyncMessage.Type == protobuf.CommunityPrivilegedUserSyncMessage_CONTROL_NODE_ALL_SYNC_REQUESTS_TO_JOIN && len(sub.CommunityPrivilegedMemberSyncMessage.Receivers) == 1 && sub.CommunityPrivilegedMemberSyncMessage.Receivers[0].Equal(&s.bob.identity.PublicKey) }) _, err = s.owner.CreateCommunityTokenPermission(&requests.CreateCommunityTokenPermission{ CommunityID: community.ID(), Type: protobuf.CommunityTokenPermission_BECOME_TOKEN_MASTER, TokenCriteria: []*protobuf.TokenCriteria{tokenCriteria}, }) s.Require().NoError(err) err = <-waitOnOwnerSendSyncMessage s.Require().NoError(err) _, err = WaitOnMessengerResponse(s.bob, func(r *MessengerResponse) bool { return len(r.Communities()) == 1 && r.Communities()[0].IsTokenMaster() }, "bob didn't receive token master role") s.Require().NoError(err) s.checkRevealedAccounts(community.ID(), s.bob, expectedAliceRevealedAccounts) } func (s *MessengerCommunitiesSharedMemberAddressSuite) TestMemberReceivesAccountsOnRoleChangeFromAdminToTokenMaster() { community, _ := createCommunity(&s.Suite, s.owner) alicePublicKey := s.alice.IdentityPublicKeyString() adminTokenCriteria := &protobuf.TokenCriteria{ ContractAddresses: map[uint64]string{testChainID1: "0x125"}, Type: protobuf.CommunityTokenType_ERC20, Symbol: "STT", Name: "Status Test Token", AmountInWei: "10000000000000000000", Decimals: 18, } tokenMasterTokenCriteria := createTokenMasterTokenCriteria() _, err := s.owner.CreateCommunityTokenPermission(&requests.CreateCommunityTokenPermission{ CommunityID: community.ID(), Type: protobuf.CommunityTokenPermission_BECOME_TOKEN_MASTER, TokenCriteria: []*protobuf.TokenCriteria{tokenMasterTokenCriteria}, }) s.Require().NoError(err) _, err = s.owner.CreateCommunityTokenPermission(&requests.CreateCommunityTokenPermission{ CommunityID: community.ID(), Type: protobuf.CommunityTokenPermission_BECOME_ADMIN, TokenCriteria: []*protobuf.TokenCriteria{adminTokenCriteria}, }) s.Require().NoError(err) community, err = s.owner.communitiesManager.GetByID(community.ID()) s.Require().NoError(err) s.Require().Len(community.TokenPermissions(), 2) // make bob satisfy the admin criteria s.makeAddressSatisfyTheCriteria(testChainID1, bobAddress, adminTokenCriteria) advertiseCommunityTo(&s.Suite, community, s.owner, s.bob) s.joinCommunity(community, s.bob, bobPassword, []string{bobAddress}) // check bob has admin role community, err = s.bob.communitiesManager.GetByID(community.ID()) s.Require().NoError(err) checkRoleBasedOnThePermissionType(protobuf.CommunityTokenPermission_BECOME_ADMIN, &s.bob.identity.PublicKey, community) community, err = s.owner.communitiesManager.GetByID(community.ID()) s.Require().NoError(err) advertiseCommunityTo(&s.Suite, community, s.owner, s.alice) s.joinCommunity(community, s.alice, alicePassword, []string{aliceAddress1}) expectedAliceRevealedAccounts, err := s.alice.communitiesManager.GetRevealedAddresses(community.ID(), alicePublicKey) s.Require().NoError(err) s.Require().Len(expectedAliceRevealedAccounts, 1) s.Require().Equal(expectedAliceRevealedAccounts[0].Address, aliceAddress1) s.Require().Equal(true, expectedAliceRevealedAccounts[0].IsAirdropAddress) // check that bob received alice request to join without revealed accounts _, err = WaitOnMessengerResponse(s.bob, func(r *MessengerResponse) bool { return len(r.RequestsToJoinCommunity()) == 1 && r.RequestsToJoinCommunity()[0].PublicKey == s.alice.IdentityPublicKeyString() && len(r.RequestsToJoinCommunity()[0].RevealedAccounts) == 0 }, "alice request to join was not delivered to admin bob") s.Require().NoError(err) emptyAliceAccounts, err := s.bob.communitiesManager.GetRevealedAddresses(community.ID(), s.alice.IdentityPublicKeyString()) s.Require().NoError(err) s.Require().Len(emptyAliceAccounts, 0) // make bob satisfy TokenMaster criteria s.makeAddressSatisfyTheCriteria(testChainID1, bobAddress, tokenMasterTokenCriteria) // wait for owner to send sync message for bob, who got a TM role waitOnOwnerSendSyncMessage := waitOnCommunitiesEvent(s.owner, func(sub *communities.Subscription) bool { return sub.CommunityPrivilegedMemberSyncMessage != nil && sub.CommunityPrivilegedMemberSyncMessage.CommunityPrivilegedUserSyncMessage.Type == protobuf.CommunityPrivilegedUserSyncMessage_CONTROL_NODE_ALL_SYNC_REQUESTS_TO_JOIN && len(sub.CommunityPrivilegedMemberSyncMessage.Receivers) == 1 && sub.CommunityPrivilegedMemberSyncMessage.Receivers[0].Equal(&s.bob.identity.PublicKey) }) err = s.owner.communitiesManager.ForceMembersReevaluation(community.ID()) s.Require().NoError(err) err = <-waitOnOwnerSendSyncMessage s.Require().NoError(err) // check that bob received alice request to join with revealed accounts _, err = WaitOnMessengerResponse(s.bob, func(r *MessengerResponse) bool { revealedAccounts, err := s.bob.communitiesManager.GetRevealedAddresses(community.ID(), alicePublicKey) s.Require().NoError(err) return len(revealedAccounts) > 0 }, "alice request to join was not delivered to token master bob") s.Require().NoError(err) s.checkRevealedAccounts(community.ID(), s.bob, expectedAliceRevealedAccounts) } func (s *MessengerCommunitiesSharedMemberAddressSuite) TestOwnerRejectAndAcceptAliceRequestToJoin() { community, _ := createOnRequestCommunity(&s.Suite, s.owner) s.Require().False(community.AutoAccept()) tokenCriteria := createTokenMasterTokenCriteria() // make bob satisfy the Token Master criteria s.makeAddressSatisfyTheCriteria(testChainID1, bobAddress, tokenCriteria) _, err := s.owner.CreateCommunityTokenPermission(&requests.CreateCommunityTokenPermission{ CommunityID: community.ID(), Type: protobuf.CommunityTokenPermission_BECOME_TOKEN_MASTER, TokenCriteria: []*protobuf.TokenCriteria{tokenCriteria}, }) s.Require().NoError(err) community, err = s.owner.communitiesManager.GetByID(community.ID()) s.Require().NoError(err) s.Require().Len(community.TokenPermissions(), 1) advertiseCommunityTo(&s.Suite, community, s.owner, s.bob) aliceArray64Bytes := common.HashPublicKey(&s.alice.identity.PublicKey) aliceSignature := append([]byte{0}, aliceArray64Bytes...) aliceRequest := &requests.RequestToJoinCommunity{ CommunityID: community.ID(), AddressesToReveal: []string{aliceAddress1}, AirdropAddress: aliceAddress1, Signatures: []types.HexBytes{aliceSignature}, } bobArray64Bytes := common.HashPublicKey(&s.bob.identity.PublicKey) bobSignature := append([]byte{0}, bobArray64Bytes...) bobRequest := &requests.RequestToJoinCommunity{ CommunityID: community.ID(), AddressesToReveal: []string{bobAddress}, AirdropAddress: bobAddress, Signatures: []types.HexBytes{bobSignature}, } joinOnRequestCommunity(&s.Suite, community, s.owner, s.bob, bobRequest) community, err = s.owner.communitiesManager.GetByID(community.ID()) s.Require().NoError(err) s.Require().True(community.IsMemberTokenMaster(&s.bob.identity.PublicKey)) advertiseCommunityTo(&s.Suite, community, s.owner, s.alice) aliceRequestToJoinID := requestToJoinCommunity(&s.Suite, s.owner, s.alice, aliceRequest) // check that bob received alice request to join without revealed accounts due to pending state _, err = WaitOnMessengerResponse(s.bob, func(r *MessengerResponse) bool { return len(r.RequestsToJoinCommunity()) == 1 && r.RequestsToJoinCommunity()[0].State == communities.RequestToJoinStatePending && r.RequestsToJoinCommunity()[0].PublicKey == s.alice.IdentityPublicKeyString() }, "alice pending request to join was not delivered to token master bob") s.Require().NoError(err) // request to join was not approved, bob should not have alice revealed addresses aliceRevealedAccounts, err := s.bob.communitiesManager.GetRevealedAddresses(community.ID(), s.alice.IdentityPublicKeyString()) s.Require().NoError(err) s.Require().Len(aliceRevealedAccounts, 0) _, err = s.owner.DeclineRequestToJoinCommunity(&requests.DeclineRequestToJoinCommunity{ID: aliceRequestToJoinID}) s.Require().NoError(err) // check that bob received owner decline sync msg _, err = WaitOnMessengerResponse(s.bob, func(r *MessengerResponse) bool { return len(r.RequestsToJoinCommunity()) == 1 && r.RequestsToJoinCommunity()[0].State == communities.RequestToJoinStateDeclined && r.RequestsToJoinCommunity()[0].PublicKey == s.alice.IdentityPublicKeyString() }, "alice declined request to join was not delivered to token master bob") s.Require().NoError(err) // request to join was declined, bob should not have alice revealed addresses aliceRevealedAccounts, err = s.bob.communitiesManager.GetRevealedAddresses(community.ID(), s.alice.IdentityPublicKeyString()) s.Require().NoError(err) s.Require().Len(aliceRevealedAccounts, 0) _, err = s.owner.AcceptRequestToJoinCommunity(&requests.AcceptRequestToJoinCommunity{ID: aliceRequestToJoinID}) s.Require().NoError(err) _, err = WaitOnMessengerResponse(s.bob, func(r *MessengerResponse) bool { return len(r.RequestsToJoinCommunity()) == 1 && r.RequestsToJoinCommunity()[0].State == communities.RequestToJoinStateAccepted && r.RequestsToJoinCommunity()[0].PublicKey == s.alice.IdentityPublicKeyString() }, "bob didn't receive accepted Alice request to join") s.Require().NoError(err) // request to join was accepted, bob should have alice revealed addresses aliceRevealedAccounts, err = s.bob.communitiesManager.GetRevealedAddresses(community.ID(), s.alice.IdentityPublicKeyString()) s.Require().NoError(err) s.Require().Len(aliceRevealedAccounts, 1) }