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

     1  package communities
     2  
     3  import (
     4  	"context"
     5  	"errors"
     6  	"fmt"
     7  	"math/big"
     8  	"strconv"
     9  	"testing"
    10  
    11  	"github.com/stretchr/testify/suite"
    12  
    13  	"github.com/status-im/status-go/protocol/protobuf"
    14  	"github.com/status-im/status-go/services/wallet/bigint"
    15  	"github.com/status-im/status-go/services/wallet/thirdparty"
    16  
    17  	gethcommon "github.com/ethereum/go-ethereum/common"
    18  	"github.com/ethereum/go-ethereum/common/hexutil"
    19  )
    20  
    21  func TestPermissionCheckerSuite(t *testing.T) {
    22  	suite.Run(t, new(PermissionCheckerSuite))
    23  }
    24  
    25  type PermissionCheckerSuite struct {
    26  	suite.Suite
    27  }
    28  
    29  func (s *PermissionCheckerSuite) TestMergeValidCombinations() {
    30  
    31  	permissionChecker := DefaultPermissionChecker{}
    32  
    33  	combination1 := &AccountChainIDsCombination{
    34  		Address:  gethcommon.HexToAddress("0xA"),
    35  		ChainIDs: []uint64{1},
    36  	}
    37  
    38  	combination2 := &AccountChainIDsCombination{
    39  		Address:  gethcommon.HexToAddress("0xB"),
    40  		ChainIDs: []uint64{5},
    41  	}
    42  
    43  	combination3 := &AccountChainIDsCombination{
    44  		Address:  gethcommon.HexToAddress("0xA"),
    45  		ChainIDs: []uint64{5},
    46  	}
    47  
    48  	combination4 := &AccountChainIDsCombination{
    49  		Address:  gethcommon.HexToAddress("0xB"),
    50  		ChainIDs: []uint64{5},
    51  	}
    52  
    53  	mergedCombination := permissionChecker.MergeValidCombinations([]*AccountChainIDsCombination{combination1, combination2},
    54  		[]*AccountChainIDsCombination{combination3, combination4})
    55  
    56  	s.Require().Len(mergedCombination, 2)
    57  	chains1 := mergedCombination[0].ChainIDs
    58  	chains2 := mergedCombination[1].ChainIDs
    59  
    60  	if len(chains1) == 2 {
    61  		s.Equal([]uint64{1, 5}, chains1)
    62  		s.Equal([]uint64{5}, chains2)
    63  	} else {
    64  		s.Equal([]uint64{1, 5}, chains2)
    65  		s.Equal([]uint64{5}, chains1)
    66  	}
    67  
    68  }
    69  
    70  func (s *PermissionCheckerSuite) TestCheckPermissions() {
    71  	testCases := []struct {
    72  		name                string
    73  		amountInWei         func(t protobuf.CommunityTokenType) string
    74  		requiredAmountInWei func(t protobuf.CommunityTokenType) string
    75  		shouldSatisfy       bool
    76  	}{
    77  		{
    78  			name: "account does not meet criteria",
    79  			amountInWei: func(t protobuf.CommunityTokenType) string {
    80  				if t == protobuf.CommunityTokenType_ERC721 {
    81  					return "1"
    82  				}
    83  				return "1000000000000000000"
    84  			},
    85  			requiredAmountInWei: func(t protobuf.CommunityTokenType) string {
    86  				if t == protobuf.CommunityTokenType_ERC721 {
    87  					return "2"
    88  				}
    89  				return "2000000000000000000"
    90  			},
    91  			shouldSatisfy: false,
    92  		},
    93  		{
    94  			name: "account does exactly meet criteria",
    95  			amountInWei: func(t protobuf.CommunityTokenType) string {
    96  				if t == protobuf.CommunityTokenType_ERC721 {
    97  					return "2"
    98  				}
    99  				return "2000000000000000000"
   100  			},
   101  			requiredAmountInWei: func(t protobuf.CommunityTokenType) string {
   102  				if t == protobuf.CommunityTokenType_ERC721 {
   103  					return "2"
   104  				}
   105  				return "2000000000000000000"
   106  			},
   107  			shouldSatisfy: true,
   108  		},
   109  		{
   110  			name: "account does meet criteria",
   111  			amountInWei: func(t protobuf.CommunityTokenType) string {
   112  				if t == protobuf.CommunityTokenType_ERC721 {
   113  					return "3"
   114  				}
   115  				return "3000000000000000000"
   116  			},
   117  			requiredAmountInWei: func(t protobuf.CommunityTokenType) string {
   118  				if t == protobuf.CommunityTokenType_ERC721 {
   119  					return "2"
   120  				}
   121  				return "2000000000000000000"
   122  			},
   123  			shouldSatisfy: true,
   124  		},
   125  	}
   126  
   127  	permissionChecker := DefaultPermissionChecker{}
   128  	chainID := uint64(1)
   129  	contractAddress := gethcommon.HexToAddress("0x3d6afaa395c31fcd391fe3d562e75fe9e8ec7e6a")
   130  	walletAddress := gethcommon.HexToAddress("0xD6b912e09E797D291E8D0eA3D3D17F8000e01c32")
   131  
   132  	for _, tc := range testCases {
   133  		for _, tokenType := range [](protobuf.CommunityTokenType){protobuf.CommunityTokenType_ERC20, protobuf.CommunityTokenType_ERC721} {
   134  			s.Run(fmt.Sprintf("%s_%s", tc.name, tokenType.String()), func() {
   135  				decimals := uint64(0)
   136  				if tokenType == protobuf.CommunityTokenType_ERC20 {
   137  					decimals = 18
   138  				}
   139  				permissions := map[string]*CommunityTokenPermission{
   140  					"p1": {
   141  						CommunityTokenPermission: &protobuf.CommunityTokenPermission{
   142  							Id:   "p1",
   143  							Type: protobuf.CommunityTokenPermission_BECOME_MEMBER,
   144  							TokenCriteria: []*protobuf.TokenCriteria{
   145  								{
   146  									ContractAddresses: map[uint64]string{
   147  										chainID: contractAddress.String(),
   148  									},
   149  									Type:        tokenType,
   150  									Symbol:      "STT",
   151  									TokenIds:    []uint64{},
   152  									Decimals:    decimals,
   153  									AmountInWei: tc.requiredAmountInWei(tokenType),
   154  								},
   155  							},
   156  						},
   157  					},
   158  				}
   159  
   160  				permissionsData, _ := PreParsePermissionsData(permissions)
   161  				accountsAndChainIDs := []*AccountChainIDsCombination{
   162  					{
   163  						Address:  walletAddress,
   164  						ChainIDs: []uint64{chainID},
   165  					},
   166  				}
   167  
   168  				var getOwnedERC721Tokens ownedERC721TokensGetter = func(walletAddresses []gethcommon.Address, tokenRequirements map[uint64]map[string]*protobuf.TokenCriteria, chainIDs []uint64) (CollectiblesByChain, error) {
   169  					amount, err := strconv.ParseUint(tc.amountInWei(protobuf.CommunityTokenType_ERC721), 10, 64)
   170  					if err != nil {
   171  						return nil, err
   172  					}
   173  
   174  					balances := []thirdparty.TokenBalance{}
   175  					for i := uint64(0); i < amount; i++ {
   176  						balances = append(balances, thirdparty.TokenBalance{
   177  							TokenID: &bigint.BigInt{
   178  								Int: new(big.Int).SetUint64(i + 1),
   179  							},
   180  							Balance: &bigint.BigInt{
   181  								Int: new(big.Int).SetUint64(1),
   182  							},
   183  						})
   184  					}
   185  
   186  					return CollectiblesByChain{
   187  						chainID: {
   188  							walletAddress: {
   189  								contractAddress: balances,
   190  							},
   191  						},
   192  					}, nil
   193  				}
   194  
   195  				var getBalancesByChain balancesByChainGetter = func(ctx context.Context, accounts, tokens []gethcommon.Address, chainIDs []uint64) (BalancesByChain, error) {
   196  					balance, ok := new(big.Int).SetString(tc.amountInWei(protobuf.CommunityTokenType_ERC20), 10)
   197  					if !ok {
   198  						return nil, errors.New("invalid conversion")
   199  					}
   200  
   201  					return BalancesByChain{
   202  						chainID: {
   203  							walletAddress: {
   204  								contractAddress: (*hexutil.Big)(balance),
   205  							},
   206  						},
   207  					}, nil
   208  				}
   209  
   210  				response, err := permissionChecker.checkPermissions(permissionsData[protobuf.CommunityTokenPermission_BECOME_MEMBER], accountsAndChainIDs, true, getOwnedERC721Tokens, getBalancesByChain)
   211  				s.Require().NoError(err)
   212  				s.Require().Equal(tc.shouldSatisfy, response.Satisfied)
   213  			})
   214  		}
   215  	}
   216  }