github.com/status-im/status-go@v1.1.0/protocol/communities/permissioned_balances_test.go (about)

     1  package communities
     2  
     3  import (
     4  	"context"
     5  	"math/big"
     6  
     7  	gethcommon "github.com/ethereum/go-ethereum/common"
     8  	"github.com/ethereum/go-ethereum/common/hexutil"
     9  	"github.com/status-im/status-go/protocol/requests"
    10  	"github.com/status-im/status-go/services/wallet/bigint"
    11  	"github.com/status-im/status-go/services/wallet/thirdparty"
    12  
    13  	_ "github.com/mutecomm/go-sqlcipher/v4" // require go-sqlcipher that overrides default implementation
    14  
    15  	"github.com/status-im/status-go/protocol/protobuf"
    16  )
    17  
    18  func (s *ManagerSuite) Test_calculatePermissionedBalances() {
    19  	m, _, _ := s.setupManagerForTokenPermissions()
    20  
    21  	var mainnetID uint64 = 1
    22  	var arbitrumID uint64 = 42161
    23  	var gnosisID uint64 = 100
    24  	chainIDs := []uint64{mainnetID, arbitrumID}
    25  
    26  	mainnetSNTContractAddress := gethcommon.HexToAddress("0xC")
    27  	mainnetETHContractAddress := gethcommon.HexToAddress("0xA")
    28  	arbitrumETHContractAddress := gethcommon.HexToAddress("0xB")
    29  	mainnetTMasterAddress := gethcommon.HexToAddress("0x123")
    30  	mainnetOwnerAddress := gethcommon.HexToAddress("0x1234")
    31  	mainnetTMasterNoTokenIDsAddress := gethcommon.HexToAddress("0x456")
    32  
    33  	account1Address := gethcommon.HexToAddress("0x1")
    34  	account2Address := gethcommon.HexToAddress("0x2")
    35  	account3Address := gethcommon.HexToAddress("0x3")
    36  	accountAddresses := []gethcommon.Address{account1Address, account2Address, account3Address}
    37  
    38  	erc20Balances := make(BalancesByChain)
    39  	erc721Balances := make(CollectiblesByChain)
    40  
    41  	erc20Balances[mainnetID] = make(map[gethcommon.Address]map[gethcommon.Address]*hexutil.Big)
    42  	erc20Balances[arbitrumID] = make(map[gethcommon.Address]map[gethcommon.Address]*hexutil.Big)
    43  	erc20Balances[gnosisID] = make(map[gethcommon.Address]map[gethcommon.Address]*hexutil.Big)
    44  	erc721Balances[mainnetID] = make(map[gethcommon.Address]thirdparty.TokenBalancesPerContractAddress)
    45  
    46  	// Account 1 balances
    47  	erc20Balances[mainnetID][account1Address] = make(map[gethcommon.Address]*hexutil.Big)
    48  	erc20Balances[mainnetID][account1Address][mainnetETHContractAddress] = intToBig(10)
    49  	erc20Balances[arbitrumID][account1Address] = make(map[gethcommon.Address]*hexutil.Big)
    50  	erc20Balances[arbitrumID][account1Address][arbitrumETHContractAddress] = intToBig(25)
    51  
    52  	// Account 2 balances
    53  	erc20Balances[mainnetID][account2Address] = make(map[gethcommon.Address]*hexutil.Big)
    54  	erc20Balances[mainnetID][account2Address][mainnetSNTContractAddress] = intToBig(120)
    55  	erc721Balances[mainnetID][account2Address] = make(thirdparty.TokenBalancesPerContractAddress)
    56  	erc721Balances[mainnetID][account2Address][mainnetTMasterNoTokenIDsAddress] = []thirdparty.TokenBalance{
    57  		thirdparty.TokenBalance{
    58  			TokenID: uintToDecBig(1500),
    59  			Balance: uintToDecBig(3),
    60  		},
    61  	}
    62  	erc721Balances[mainnetID][account2Address][mainnetTMasterAddress] = []thirdparty.TokenBalance{
    63  		thirdparty.TokenBalance{
    64  			TokenID: uintToDecBig(456),
    65  			Balance: uintToDecBig(1),
    66  		},
    67  		thirdparty.TokenBalance{
    68  			TokenID: uintToDecBig(123),
    69  			Balance: uintToDecBig(2),
    70  		},
    71  	}
    72  	erc721Balances[mainnetID][account2Address][mainnetOwnerAddress] = []thirdparty.TokenBalance{
    73  		thirdparty.TokenBalance{
    74  			TokenID: uintToDecBig(100),
    75  			Balance: uintToDecBig(6),
    76  		},
    77  		thirdparty.TokenBalance{
    78  			TokenID: uintToDecBig(101),
    79  			Balance: uintToDecBig(1),
    80  		},
    81  	}
    82  
    83  	erc20Balances[arbitrumID][account2Address] = make(map[gethcommon.Address]*hexutil.Big)
    84  	erc20Balances[arbitrumID][account2Address][arbitrumETHContractAddress] = intToBig(2)
    85  
    86  	// Account 3 balances. This account is used to assert zeroed balances are
    87  	// removed from the final response.
    88  	erc20Balances[mainnetID][account3Address] = make(map[gethcommon.Address]*hexutil.Big)
    89  	erc20Balances[mainnetID][account3Address][mainnetETHContractAddress] = intToBig(0)
    90  
    91  	// A balance that should be ignored because the list of wallet addresses don't
    92  	// contain any wallet in the Gnosis chain.
    93  	erc20Balances[gnosisID][gethcommon.HexToAddress("0xF")] = make(map[gethcommon.Address]*hexutil.Big)
    94  	erc20Balances[gnosisID][gethcommon.HexToAddress("0xF")][gethcommon.HexToAddress("0x99")] = intToBig(5)
    95  
    96  	tokenPermissions := []*CommunityTokenPermission{
    97  		&CommunityTokenPermission{
    98  			CommunityTokenPermission: &protobuf.CommunityTokenPermission{
    99  				Type: protobuf.CommunityTokenPermission_BECOME_TOKEN_MASTER,
   100  				// A criteria without token IDs should be considered satisfied.
   101  				TokenCriteria: []*protobuf.TokenCriteria{
   102  					&protobuf.TokenCriteria{
   103  						Type:              protobuf.CommunityTokenType_ERC721,
   104  						Symbol:            "TM_NO_TOKEN_IDS",
   105  						Name:              "TMaster-NoTokenIDs",
   106  						AmountInWei:       "1",
   107  						ContractAddresses: map[uint64]string{mainnetID: mainnetTMasterNoTokenIDsAddress.Hex()},
   108  					},
   109  				},
   110  			},
   111  		},
   112  		&CommunityTokenPermission{
   113  			CommunityTokenPermission: &protobuf.CommunityTokenPermission{
   114  				Type: protobuf.CommunityTokenPermission_BECOME_TOKEN_MASTER,
   115  				TokenCriteria: []*protobuf.TokenCriteria{
   116  					&protobuf.TokenCriteria{
   117  						Type:              protobuf.CommunityTokenType_ERC721,
   118  						Symbol:            "TMTEST",
   119  						Name:              "TMaster-Test",
   120  						AmountInWei:       "1",
   121  						TokenIds:          []uint64{123, 456},
   122  						ContractAddresses: map[uint64]string{mainnetID: mainnetTMasterAddress.Hex()},
   123  					},
   124  				},
   125  			},
   126  		},
   127  		&CommunityTokenPermission{
   128  			CommunityTokenPermission: &protobuf.CommunityTokenPermission{
   129  				Type: protobuf.CommunityTokenPermission_BECOME_TOKEN_OWNER,
   130  				TokenCriteria: []*protobuf.TokenCriteria{
   131  					&protobuf.TokenCriteria{
   132  						Type:        protobuf.CommunityTokenType_ERC721,
   133  						Symbol:      "OWNTEST",
   134  						Name:        "Owner-Test",
   135  						AmountInWei: "5",
   136  						// No account has a positive balance for these token IDs, so we
   137  						// expect this collectible to not be present in the final result.
   138  						TokenIds:          []uint64{666},
   139  						ContractAddresses: map[uint64]string{mainnetID: mainnetOwnerAddress.Hex()},
   140  					},
   141  				},
   142  			},
   143  		},
   144  		&CommunityTokenPermission{
   145  			CommunityTokenPermission: &protobuf.CommunityTokenPermission{
   146  				Type: protobuf.CommunityTokenPermission_BECOME_ADMIN,
   147  				TokenCriteria: []*protobuf.TokenCriteria{
   148  					&protobuf.TokenCriteria{
   149  						Type:        protobuf.CommunityTokenType_ERC20,
   150  						Symbol:      "ETH",
   151  						Name:        "Ethereum",
   152  						AmountInWei: "20000000000000000000",
   153  						Decimals:    18,
   154  						ContractAddresses: map[uint64]string{
   155  							arbitrumID: arbitrumETHContractAddress.Hex(),
   156  							mainnetID:  mainnetETHContractAddress.Hex(),
   157  						},
   158  					},
   159  					&protobuf.TokenCriteria{
   160  						Type:              protobuf.CommunityTokenType_ERC20,
   161  						Symbol:            "ETH",
   162  						Name:              "Ethereum",
   163  						AmountInWei:       "4000000000000000000",
   164  						Decimals:          18,
   165  						ContractAddresses: map[uint64]string{arbitrumID: arbitrumETHContractAddress.Hex()},
   166  					},
   167  				},
   168  			},
   169  		},
   170  		&CommunityTokenPermission{
   171  			CommunityTokenPermission: &protobuf.CommunityTokenPermission{
   172  				Type: protobuf.CommunityTokenPermission_BECOME_MEMBER,
   173  				TokenCriteria: []*protobuf.TokenCriteria{
   174  					&protobuf.TokenCriteria{
   175  						Type:              protobuf.CommunityTokenType_ERC20,
   176  						Symbol:            "SNT",
   177  						Name:              "Status",
   178  						AmountInWei:       "10000000000000000000",
   179  						Decimals:          16,
   180  						ContractAddresses: map[uint64]string{mainnetID: mainnetSNTContractAddress.Hex()},
   181  					},
   182  				},
   183  			},
   184  		},
   185  		&CommunityTokenPermission{
   186  			CommunityTokenPermission: &protobuf.CommunityTokenPermission{
   187  				// Unknown permission should be ignored.
   188  				Type: protobuf.CommunityTokenPermission_UNKNOWN_TOKEN_PERMISSION,
   189  				TokenCriteria: []*protobuf.TokenCriteria{
   190  					&protobuf.TokenCriteria{
   191  						Type:              protobuf.CommunityTokenType_ERC20,
   192  						Symbol:            "DAI",
   193  						Name:              "Dai",
   194  						AmountInWei:       "7000000000000",
   195  						Decimals:          12,
   196  						ContractAddresses: map[uint64]string{mainnetID: "0x1234567"},
   197  					},
   198  				},
   199  			},
   200  		},
   201  	}
   202  
   203  	actual := m.calculatePermissionedBalances(
   204  		chainIDs,
   205  		accountAddresses,
   206  		erc20Balances,
   207  		erc721Balances,
   208  		tokenPermissions,
   209  	)
   210  
   211  	expected := make(map[gethcommon.Address][]PermissionedBalance)
   212  	expected[account1Address] = []PermissionedBalance{
   213  		PermissionedBalance{
   214  			Type:     protobuf.CommunityTokenType_ERC20,
   215  			Symbol:   "ETH",
   216  			Name:     "Ethereum",
   217  			Decimals: 18,
   218  			Amount:   &bigint.BigInt{Int: big.NewInt(35)},
   219  		},
   220  	}
   221  	expected[account2Address] = []PermissionedBalance{
   222  		PermissionedBalance{
   223  			Type:     protobuf.CommunityTokenType_ERC20,
   224  			Symbol:   "ETH",
   225  			Name:     "Ethereum",
   226  			Decimals: 18,
   227  			Amount:   &bigint.BigInt{Int: big.NewInt(2)},
   228  		},
   229  		PermissionedBalance{
   230  			Type:     protobuf.CommunityTokenType_ERC20,
   231  			Symbol:   "SNT",
   232  			Name:     "Status",
   233  			Decimals: 16,
   234  			Amount:   &bigint.BigInt{Int: big.NewInt(120)},
   235  		},
   236  		PermissionedBalance{
   237  			Type:   protobuf.CommunityTokenType_ERC721,
   238  			Symbol: "TM_NO_TOKEN_IDS",
   239  			Name:   "TMaster-NoTokenIDs",
   240  			Amount: &bigint.BigInt{Int: big.NewInt(1)},
   241  		},
   242  		PermissionedBalance{
   243  			Type:   protobuf.CommunityTokenType_ERC721,
   244  			Symbol: "TMTEST",
   245  			Name:   "TMaster-Test",
   246  			Amount: &bigint.BigInt{Int: big.NewInt(1)},
   247  		},
   248  	}
   249  
   250  	_, ok := actual[account1Address]
   251  	s.Require().True(ok, "not found account1Address='%s'", account1Address)
   252  	_, ok = actual[account1Address]
   253  	s.Require().True(ok, "not found account2Address='%s'", account2Address)
   254  
   255  	for accountAddress, permissionedTokens := range actual {
   256  		s.Require().ElementsMatch(expected[accountAddress], permissionedTokens, "accountAddress='%s'", accountAddress)
   257  	}
   258  }
   259  
   260  func (s *ManagerSuite) Test_GetPermissionedBalances() {
   261  	m, collectiblesManager, tokenManager := s.setupManagerForTokenPermissions()
   262  	s.Require().NotNil(m)
   263  	s.Require().NotNil(collectiblesManager)
   264  
   265  	request := &requests.CreateCommunity{
   266  		Membership: protobuf.CommunityPermissions_AUTO_ACCEPT,
   267  	}
   268  	community, err := m.CreateCommunity(request, true)
   269  	s.Require().NoError(err)
   270  	s.Require().NotNil(community)
   271  
   272  	accountAddress := gethcommon.HexToAddress("0x1")
   273  	accountAddresses := []gethcommon.Address{accountAddress}
   274  
   275  	var chainID uint64 = 5
   276  	erc20ETHAddress := gethcommon.HexToAddress("0xA")
   277  	erc721Address := gethcommon.HexToAddress("0x123")
   278  
   279  	permissionRequest := &requests.CreateCommunityTokenPermission{
   280  		CommunityID: community.ID(),
   281  		Type:        protobuf.CommunityTokenPermission_BECOME_MEMBER,
   282  		TokenCriteria: []*protobuf.TokenCriteria{
   283  			&protobuf.TokenCriteria{
   284  				Type:              protobuf.CommunityTokenType_ERC20,
   285  				Symbol:            "ETH",
   286  				Name:              "Ethereum",
   287  				AmountInWei:       "3000000000000000000",
   288  				Decimals:          18,
   289  				ContractAddresses: map[uint64]string{chainID: erc20ETHAddress.Hex()},
   290  			},
   291  		},
   292  	}
   293  	_, changes, err := m.CreateCommunityTokenPermission(permissionRequest)
   294  	s.Require().NoError(err)
   295  	s.Require().Len(changes.TokenPermissionsAdded, 1)
   296  
   297  	permissionRequest = &requests.CreateCommunityTokenPermission{
   298  		CommunityID: community.ID(),
   299  		Type:        protobuf.CommunityTokenPermission_BECOME_TOKEN_MASTER,
   300  		TokenCriteria: []*protobuf.TokenCriteria{
   301  			&protobuf.TokenCriteria{
   302  				Type:              protobuf.CommunityTokenType_ERC721,
   303  				Symbol:            "TMTEST",
   304  				Name:              "TMaster-Test",
   305  				AmountInWei:       "1",
   306  				TokenIds:          []uint64{666},
   307  				ContractAddresses: map[uint64]string{chainID: erc721Address.Hex()},
   308  			},
   309  		},
   310  	}
   311  	_, changes, err = m.CreateCommunityTokenPermission(permissionRequest)
   312  	s.Require().NoError(err)
   313  	s.Require().Len(changes.TokenPermissionsAdded, 1)
   314  
   315  	tokenManager.setResponse(chainID, accountAddress, erc20ETHAddress, 42)
   316  	collectiblesManager.setResponse(chainID, accountAddress, erc721Address, []thirdparty.TokenBalance{
   317  		thirdparty.TokenBalance{
   318  			TokenID: uintToDecBig(666),
   319  			Balance: uintToDecBig(15),
   320  		},
   321  	})
   322  
   323  	actual, err := m.GetPermissionedBalances(context.Background(), community.ID(), accountAddresses)
   324  	s.Require().NoError(err)
   325  
   326  	expected := make(map[gethcommon.Address][]PermissionedBalance)
   327  	expected[accountAddress] = []PermissionedBalance{
   328  		PermissionedBalance{
   329  			Type:     protobuf.CommunityTokenType_ERC20,
   330  			Symbol:   "ETH",
   331  			Name:     "Ethereum",
   332  			Decimals: 18,
   333  			Amount:   &bigint.BigInt{Int: big.NewInt(42)},
   334  		},
   335  		PermissionedBalance{
   336  			Type:   protobuf.CommunityTokenType_ERC721,
   337  			Symbol: "TMTEST",
   338  			Name:   "TMaster-Test",
   339  			Amount: &bigint.BigInt{Int: big.NewInt(1)},
   340  		},
   341  	}
   342  
   343  	_, ok := actual[accountAddress]
   344  	s.Require().True(ok, "not found accountAddress='%s'", accountAddress)
   345  
   346  	for address, permissionedBalances := range actual {
   347  		s.Require().ElementsMatch(expected[address], permissionedBalances)
   348  	}
   349  }