2024-02-06 12:55:59 +00:00
|
|
|
package communities
|
|
|
|
|
|
|
|
import (
|
2024-06-13 13:26:52 +00:00
|
|
|
"context"
|
|
|
|
"errors"
|
|
|
|
"fmt"
|
|
|
|
"math/big"
|
|
|
|
"strconv"
|
2024-02-06 12:55:59 +00:00
|
|
|
"testing"
|
|
|
|
|
|
|
|
"github.com/stretchr/testify/suite"
|
|
|
|
|
2024-06-13 13:26:52 +00:00
|
|
|
"github.com/status-im/status-go/protocol/protobuf"
|
|
|
|
"github.com/status-im/status-go/services/wallet/bigint"
|
|
|
|
"github.com/status-im/status-go/services/wallet/thirdparty"
|
|
|
|
|
2024-02-06 12:55:59 +00:00
|
|
|
gethcommon "github.com/ethereum/go-ethereum/common"
|
2024-06-13 13:26:52 +00:00
|
|
|
"github.com/ethereum/go-ethereum/common/hexutil"
|
2024-02-06 12:55:59 +00:00
|
|
|
)
|
|
|
|
|
|
|
|
func TestPermissionCheckerSuite(t *testing.T) {
|
|
|
|
suite.Run(t, new(PermissionCheckerSuite))
|
|
|
|
}
|
|
|
|
|
|
|
|
type PermissionCheckerSuite struct {
|
|
|
|
suite.Suite
|
|
|
|
}
|
|
|
|
|
|
|
|
func (s *PermissionCheckerSuite) TestMergeValidCombinations() {
|
|
|
|
|
|
|
|
permissionChecker := DefaultPermissionChecker{}
|
|
|
|
|
|
|
|
combination1 := &AccountChainIDsCombination{
|
|
|
|
Address: gethcommon.HexToAddress("0xA"),
|
|
|
|
ChainIDs: []uint64{1},
|
|
|
|
}
|
|
|
|
|
|
|
|
combination2 := &AccountChainIDsCombination{
|
|
|
|
Address: gethcommon.HexToAddress("0xB"),
|
|
|
|
ChainIDs: []uint64{5},
|
|
|
|
}
|
|
|
|
|
|
|
|
combination3 := &AccountChainIDsCombination{
|
|
|
|
Address: gethcommon.HexToAddress("0xA"),
|
|
|
|
ChainIDs: []uint64{5},
|
|
|
|
}
|
|
|
|
|
|
|
|
combination4 := &AccountChainIDsCombination{
|
|
|
|
Address: gethcommon.HexToAddress("0xB"),
|
|
|
|
ChainIDs: []uint64{5},
|
|
|
|
}
|
|
|
|
|
|
|
|
mergedCombination := permissionChecker.MergeValidCombinations([]*AccountChainIDsCombination{combination1, combination2},
|
|
|
|
[]*AccountChainIDsCombination{combination3, combination4})
|
|
|
|
|
|
|
|
s.Require().Len(mergedCombination, 2)
|
|
|
|
chains1 := mergedCombination[0].ChainIDs
|
|
|
|
chains2 := mergedCombination[1].ChainIDs
|
|
|
|
|
|
|
|
if len(chains1) == 2 {
|
|
|
|
s.Equal([]uint64{1, 5}, chains1)
|
|
|
|
s.Equal([]uint64{5}, chains2)
|
|
|
|
} else {
|
|
|
|
s.Equal([]uint64{1, 5}, chains2)
|
|
|
|
s.Equal([]uint64{5}, chains1)
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
2024-06-13 13:26:52 +00:00
|
|
|
|
|
|
|
func (s *PermissionCheckerSuite) TestCheckPermissions() {
|
|
|
|
testCases := []struct {
|
|
|
|
name string
|
|
|
|
amountInWei func(t protobuf.CommunityTokenType) string
|
|
|
|
requiredAmountInWei func(t protobuf.CommunityTokenType) string
|
|
|
|
shouldSatisfy bool
|
|
|
|
}{
|
|
|
|
{
|
|
|
|
name: "account does not meet criteria",
|
|
|
|
amountInWei: func(t protobuf.CommunityTokenType) string {
|
|
|
|
if t == protobuf.CommunityTokenType_ERC721 {
|
|
|
|
return "1"
|
|
|
|
}
|
|
|
|
return "1000000000000000000"
|
|
|
|
},
|
|
|
|
requiredAmountInWei: func(t protobuf.CommunityTokenType) string {
|
|
|
|
if t == protobuf.CommunityTokenType_ERC721 {
|
|
|
|
return "2"
|
|
|
|
}
|
|
|
|
return "2000000000000000000"
|
|
|
|
},
|
|
|
|
shouldSatisfy: false,
|
|
|
|
},
|
|
|
|
{
|
|
|
|
name: "account does exactly meet criteria",
|
|
|
|
amountInWei: func(t protobuf.CommunityTokenType) string {
|
|
|
|
if t == protobuf.CommunityTokenType_ERC721 {
|
|
|
|
return "2"
|
|
|
|
}
|
|
|
|
return "2000000000000000000"
|
|
|
|
},
|
|
|
|
requiredAmountInWei: func(t protobuf.CommunityTokenType) string {
|
|
|
|
if t == protobuf.CommunityTokenType_ERC721 {
|
|
|
|
return "2"
|
|
|
|
}
|
|
|
|
return "2000000000000000000"
|
|
|
|
},
|
|
|
|
shouldSatisfy: true,
|
|
|
|
},
|
|
|
|
{
|
|
|
|
name: "account does meet criteria",
|
|
|
|
amountInWei: func(t protobuf.CommunityTokenType) string {
|
|
|
|
if t == protobuf.CommunityTokenType_ERC721 {
|
|
|
|
return "3"
|
|
|
|
}
|
|
|
|
return "3000000000000000000"
|
|
|
|
},
|
|
|
|
requiredAmountInWei: func(t protobuf.CommunityTokenType) string {
|
|
|
|
if t == protobuf.CommunityTokenType_ERC721 {
|
|
|
|
return "2"
|
|
|
|
}
|
|
|
|
return "2000000000000000000"
|
|
|
|
},
|
|
|
|
shouldSatisfy: true,
|
|
|
|
},
|
|
|
|
}
|
|
|
|
|
|
|
|
permissionChecker := DefaultPermissionChecker{}
|
|
|
|
chainID := uint64(1)
|
|
|
|
contractAddress := gethcommon.HexToAddress("0x3d6afaa395c31fcd391fe3d562e75fe9e8ec7e6a")
|
|
|
|
walletAddress := gethcommon.HexToAddress("0xD6b912e09E797D291E8D0eA3D3D17F8000e01c32")
|
|
|
|
|
|
|
|
for _, tc := range testCases {
|
|
|
|
for _, tokenType := range [](protobuf.CommunityTokenType){protobuf.CommunityTokenType_ERC20, protobuf.CommunityTokenType_ERC721} {
|
|
|
|
s.Run(fmt.Sprintf("%s_%s", tc.name, tokenType.String()), func() {
|
|
|
|
decimals := uint64(0)
|
|
|
|
if tokenType == protobuf.CommunityTokenType_ERC20 {
|
|
|
|
decimals = 18
|
|
|
|
}
|
|
|
|
permissions := map[string]*CommunityTokenPermission{
|
|
|
|
"p1": {
|
|
|
|
CommunityTokenPermission: &protobuf.CommunityTokenPermission{
|
|
|
|
Id: "p1",
|
|
|
|
Type: protobuf.CommunityTokenPermission_BECOME_MEMBER,
|
|
|
|
TokenCriteria: []*protobuf.TokenCriteria{
|
|
|
|
{
|
|
|
|
ContractAddresses: map[uint64]string{
|
|
|
|
chainID: contractAddress.String(),
|
|
|
|
},
|
|
|
|
Type: tokenType,
|
|
|
|
Symbol: "STT",
|
|
|
|
TokenIds: []uint64{},
|
|
|
|
Decimals: decimals,
|
|
|
|
AmountInWei: tc.requiredAmountInWei(tokenType),
|
|
|
|
},
|
|
|
|
},
|
|
|
|
},
|
|
|
|
},
|
|
|
|
}
|
|
|
|
|
|
|
|
permissionsData, _ := PreParsePermissionsData(permissions)
|
|
|
|
accountsAndChainIDs := []*AccountChainIDsCombination{
|
|
|
|
{
|
|
|
|
Address: walletAddress,
|
|
|
|
ChainIDs: []uint64{chainID},
|
|
|
|
},
|
|
|
|
}
|
|
|
|
|
|
|
|
var getOwnedERC721Tokens ownedERC721TokensGetter = func(walletAddresses []gethcommon.Address, tokenRequirements map[uint64]map[string]*protobuf.TokenCriteria, chainIDs []uint64) (CollectiblesByChain, error) {
|
|
|
|
amount, err := strconv.ParseUint(tc.amountInWei(protobuf.CommunityTokenType_ERC721), 10, 64)
|
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
|
|
|
|
balances := []thirdparty.TokenBalance{}
|
|
|
|
for i := uint64(0); i < amount; i++ {
|
|
|
|
balances = append(balances, thirdparty.TokenBalance{
|
|
|
|
TokenID: &bigint.BigInt{
|
|
|
|
Int: new(big.Int).SetUint64(i + 1),
|
|
|
|
},
|
|
|
|
Balance: &bigint.BigInt{
|
|
|
|
Int: new(big.Int).SetUint64(1),
|
|
|
|
},
|
|
|
|
})
|
|
|
|
}
|
|
|
|
|
|
|
|
return CollectiblesByChain{
|
|
|
|
chainID: {
|
|
|
|
walletAddress: {
|
|
|
|
contractAddress: balances,
|
|
|
|
},
|
|
|
|
},
|
|
|
|
}, nil
|
|
|
|
}
|
|
|
|
|
|
|
|
var getBalancesByChain balancesByChainGetter = func(ctx context.Context, accounts, tokens []gethcommon.Address, chainIDs []uint64) (BalancesByChain, error) {
|
|
|
|
balance, ok := new(big.Int).SetString(tc.amountInWei(protobuf.CommunityTokenType_ERC20), 10)
|
|
|
|
if !ok {
|
|
|
|
return nil, errors.New("invalid conversion")
|
|
|
|
}
|
|
|
|
|
|
|
|
return BalancesByChain{
|
|
|
|
chainID: {
|
|
|
|
walletAddress: {
|
|
|
|
contractAddress: (*hexutil.Big)(balance),
|
|
|
|
},
|
|
|
|
},
|
|
|
|
}, nil
|
|
|
|
}
|
|
|
|
|
|
|
|
response, err := permissionChecker.checkPermissions(permissionsData[protobuf.CommunityTokenPermission_BECOME_MEMBER], accountsAndChainIDs, true, getOwnedERC721Tokens, getBalancesByChain)
|
|
|
|
s.Require().NoError(err)
|
|
|
|
s.Require().Equal(tc.shouldSatisfy, response.Satisfied)
|
|
|
|
})
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|