350 lines
12 KiB
Go
350 lines
12 KiB
Go
package communities
|
|
|
|
import (
|
|
"context"
|
|
"math/big"
|
|
|
|
gethcommon "github.com/ethereum/go-ethereum/common"
|
|
"github.com/ethereum/go-ethereum/common/hexutil"
|
|
"github.com/status-im/status-go/protocol/requests"
|
|
"github.com/status-im/status-go/services/wallet/bigint"
|
|
"github.com/status-im/status-go/services/wallet/thirdparty"
|
|
|
|
_ "github.com/mutecomm/go-sqlcipher/v4" // require go-sqlcipher that overrides default implementation
|
|
|
|
"github.com/status-im/status-go/protocol/protobuf"
|
|
)
|
|
|
|
func (s *ManagerSuite) Test_calculatePermissionedBalances() {
|
|
m, _, _ := s.setupManagerForTokenPermissions()
|
|
|
|
var mainnetID uint64 = 1
|
|
var arbitrumID uint64 = 42161
|
|
var gnosisID uint64 = 100
|
|
chainIDs := []uint64{mainnetID, arbitrumID}
|
|
|
|
mainnetSNTContractAddress := gethcommon.HexToAddress("0xC")
|
|
mainnetETHContractAddress := gethcommon.HexToAddress("0xA")
|
|
arbitrumETHContractAddress := gethcommon.HexToAddress("0xB")
|
|
mainnetTMasterAddress := gethcommon.HexToAddress("0x123")
|
|
mainnetOwnerAddress := gethcommon.HexToAddress("0x1234")
|
|
mainnetTMasterNoTokenIDsAddress := gethcommon.HexToAddress("0x456")
|
|
|
|
account1Address := gethcommon.HexToAddress("0x1")
|
|
account2Address := gethcommon.HexToAddress("0x2")
|
|
account3Address := gethcommon.HexToAddress("0x3")
|
|
accountAddresses := []gethcommon.Address{account1Address, account2Address, account3Address}
|
|
|
|
erc20Balances := make(BalancesByChain)
|
|
erc721Balances := make(CollectiblesByChain)
|
|
|
|
erc20Balances[mainnetID] = make(map[gethcommon.Address]map[gethcommon.Address]*hexutil.Big)
|
|
erc20Balances[arbitrumID] = make(map[gethcommon.Address]map[gethcommon.Address]*hexutil.Big)
|
|
erc20Balances[gnosisID] = make(map[gethcommon.Address]map[gethcommon.Address]*hexutil.Big)
|
|
erc721Balances[mainnetID] = make(map[gethcommon.Address]thirdparty.TokenBalancesPerContractAddress)
|
|
|
|
// Account 1 balances
|
|
erc20Balances[mainnetID][account1Address] = make(map[gethcommon.Address]*hexutil.Big)
|
|
erc20Balances[mainnetID][account1Address][mainnetETHContractAddress] = intToBig(10)
|
|
erc20Balances[arbitrumID][account1Address] = make(map[gethcommon.Address]*hexutil.Big)
|
|
erc20Balances[arbitrumID][account1Address][arbitrumETHContractAddress] = intToBig(25)
|
|
|
|
// Account 2 balances
|
|
erc20Balances[mainnetID][account2Address] = make(map[gethcommon.Address]*hexutil.Big)
|
|
erc20Balances[mainnetID][account2Address][mainnetSNTContractAddress] = intToBig(120)
|
|
erc721Balances[mainnetID][account2Address] = make(thirdparty.TokenBalancesPerContractAddress)
|
|
erc721Balances[mainnetID][account2Address][mainnetTMasterNoTokenIDsAddress] = []thirdparty.TokenBalance{
|
|
thirdparty.TokenBalance{
|
|
TokenID: uintToDecBig(1500),
|
|
Balance: uintToDecBig(3),
|
|
},
|
|
}
|
|
erc721Balances[mainnetID][account2Address][mainnetTMasterAddress] = []thirdparty.TokenBalance{
|
|
thirdparty.TokenBalance{
|
|
TokenID: uintToDecBig(456),
|
|
Balance: uintToDecBig(1),
|
|
},
|
|
thirdparty.TokenBalance{
|
|
TokenID: uintToDecBig(123),
|
|
Balance: uintToDecBig(2),
|
|
},
|
|
}
|
|
erc721Balances[mainnetID][account2Address][mainnetOwnerAddress] = []thirdparty.TokenBalance{
|
|
thirdparty.TokenBalance{
|
|
TokenID: uintToDecBig(100),
|
|
Balance: uintToDecBig(6),
|
|
},
|
|
thirdparty.TokenBalance{
|
|
TokenID: uintToDecBig(101),
|
|
Balance: uintToDecBig(1),
|
|
},
|
|
}
|
|
|
|
erc20Balances[arbitrumID][account2Address] = make(map[gethcommon.Address]*hexutil.Big)
|
|
erc20Balances[arbitrumID][account2Address][arbitrumETHContractAddress] = intToBig(2)
|
|
|
|
// Account 3 balances. This account is used to assert zeroed balances are
|
|
// removed from the final response.
|
|
erc20Balances[mainnetID][account3Address] = make(map[gethcommon.Address]*hexutil.Big)
|
|
erc20Balances[mainnetID][account3Address][mainnetETHContractAddress] = intToBig(0)
|
|
|
|
// A balance that should be ignored because the list of wallet addresses don't
|
|
// contain any wallet in the Gnosis chain.
|
|
erc20Balances[gnosisID][gethcommon.HexToAddress("0xF")] = make(map[gethcommon.Address]*hexutil.Big)
|
|
erc20Balances[gnosisID][gethcommon.HexToAddress("0xF")][gethcommon.HexToAddress("0x99")] = intToBig(5)
|
|
|
|
tokenPermissions := []*CommunityTokenPermission{
|
|
&CommunityTokenPermission{
|
|
CommunityTokenPermission: &protobuf.CommunityTokenPermission{
|
|
Type: protobuf.CommunityTokenPermission_BECOME_TOKEN_MASTER,
|
|
// A criteria without token IDs should be considered satisfied.
|
|
TokenCriteria: []*protobuf.TokenCriteria{
|
|
&protobuf.TokenCriteria{
|
|
Type: protobuf.CommunityTokenType_ERC721,
|
|
Symbol: "TM_NO_TOKEN_IDS",
|
|
Name: "TMaster-NoTokenIDs",
|
|
Amount: "1",
|
|
ContractAddresses: map[uint64]string{mainnetID: mainnetTMasterNoTokenIDsAddress.Hex()},
|
|
},
|
|
},
|
|
},
|
|
},
|
|
&CommunityTokenPermission{
|
|
CommunityTokenPermission: &protobuf.CommunityTokenPermission{
|
|
Type: protobuf.CommunityTokenPermission_BECOME_TOKEN_MASTER,
|
|
TokenCriteria: []*protobuf.TokenCriteria{
|
|
&protobuf.TokenCriteria{
|
|
Type: protobuf.CommunityTokenType_ERC721,
|
|
Symbol: "TMTEST",
|
|
Name: "TMaster-Test",
|
|
Amount: "1",
|
|
TokenIds: []uint64{123, 456},
|
|
ContractAddresses: map[uint64]string{mainnetID: mainnetTMasterAddress.Hex()},
|
|
},
|
|
},
|
|
},
|
|
},
|
|
&CommunityTokenPermission{
|
|
CommunityTokenPermission: &protobuf.CommunityTokenPermission{
|
|
Type: protobuf.CommunityTokenPermission_BECOME_TOKEN_OWNER,
|
|
TokenCriteria: []*protobuf.TokenCriteria{
|
|
&protobuf.TokenCriteria{
|
|
Type: protobuf.CommunityTokenType_ERC721,
|
|
Symbol: "OWNTEST",
|
|
Name: "Owner-Test",
|
|
Amount: "5",
|
|
// No account has a positive balance for these token IDs, so we
|
|
// expect this collectible to not be present in the final result.
|
|
TokenIds: []uint64{666},
|
|
ContractAddresses: map[uint64]string{mainnetID: mainnetOwnerAddress.Hex()},
|
|
},
|
|
},
|
|
},
|
|
},
|
|
&CommunityTokenPermission{
|
|
CommunityTokenPermission: &protobuf.CommunityTokenPermission{
|
|
Type: protobuf.CommunityTokenPermission_BECOME_ADMIN,
|
|
TokenCriteria: []*protobuf.TokenCriteria{
|
|
&protobuf.TokenCriteria{
|
|
Type: protobuf.CommunityTokenType_ERC20,
|
|
Symbol: "ETH",
|
|
Name: "Ethereum",
|
|
Amount: "20",
|
|
Decimals: 18,
|
|
ContractAddresses: map[uint64]string{
|
|
arbitrumID: arbitrumETHContractAddress.Hex(),
|
|
mainnetID: mainnetETHContractAddress.Hex(),
|
|
},
|
|
},
|
|
&protobuf.TokenCriteria{
|
|
Type: protobuf.CommunityTokenType_ERC20,
|
|
Symbol: "ETH",
|
|
Name: "Ethereum",
|
|
Amount: "4",
|
|
Decimals: 18,
|
|
ContractAddresses: map[uint64]string{arbitrumID: arbitrumETHContractAddress.Hex()},
|
|
},
|
|
},
|
|
},
|
|
},
|
|
&CommunityTokenPermission{
|
|
CommunityTokenPermission: &protobuf.CommunityTokenPermission{
|
|
Type: protobuf.CommunityTokenPermission_BECOME_MEMBER,
|
|
TokenCriteria: []*protobuf.TokenCriteria{
|
|
&protobuf.TokenCriteria{
|
|
Type: protobuf.CommunityTokenType_ERC20,
|
|
Symbol: "SNT",
|
|
Name: "Status",
|
|
Amount: "1000",
|
|
Decimals: 16,
|
|
ContractAddresses: map[uint64]string{mainnetID: mainnetSNTContractAddress.Hex()},
|
|
},
|
|
},
|
|
},
|
|
},
|
|
&CommunityTokenPermission{
|
|
CommunityTokenPermission: &protobuf.CommunityTokenPermission{
|
|
// Unknown permission should be ignored.
|
|
Type: protobuf.CommunityTokenPermission_UNKNOWN_TOKEN_PERMISSION,
|
|
TokenCriteria: []*protobuf.TokenCriteria{
|
|
&protobuf.TokenCriteria{
|
|
Type: protobuf.CommunityTokenType_ERC20,
|
|
Symbol: "DAI",
|
|
Name: "Dai",
|
|
Amount: "7",
|
|
Decimals: 12,
|
|
ContractAddresses: map[uint64]string{mainnetID: "0x1234567"},
|
|
},
|
|
},
|
|
},
|
|
},
|
|
}
|
|
|
|
actual := m.calculatePermissionedBalances(
|
|
chainIDs,
|
|
accountAddresses,
|
|
erc20Balances,
|
|
erc721Balances,
|
|
tokenPermissions,
|
|
)
|
|
|
|
expected := make(map[gethcommon.Address][]PermissionedBalance)
|
|
expected[account1Address] = []PermissionedBalance{
|
|
PermissionedBalance{
|
|
Type: protobuf.CommunityTokenType_ERC20,
|
|
Symbol: "ETH",
|
|
Name: "Ethereum",
|
|
Decimals: 18,
|
|
Amount: &bigint.BigInt{Int: big.NewInt(35)},
|
|
},
|
|
}
|
|
expected[account2Address] = []PermissionedBalance{
|
|
PermissionedBalance{
|
|
Type: protobuf.CommunityTokenType_ERC20,
|
|
Symbol: "ETH",
|
|
Name: "Ethereum",
|
|
Decimals: 18,
|
|
Amount: &bigint.BigInt{Int: big.NewInt(2)},
|
|
},
|
|
PermissionedBalance{
|
|
Type: protobuf.CommunityTokenType_ERC20,
|
|
Symbol: "SNT",
|
|
Name: "Status",
|
|
Decimals: 16,
|
|
Amount: &bigint.BigInt{Int: big.NewInt(120)},
|
|
},
|
|
PermissionedBalance{
|
|
Type: protobuf.CommunityTokenType_ERC721,
|
|
Symbol: "TM_NO_TOKEN_IDS",
|
|
Name: "TMaster-NoTokenIDs",
|
|
Amount: &bigint.BigInt{Int: big.NewInt(1)},
|
|
},
|
|
PermissionedBalance{
|
|
Type: protobuf.CommunityTokenType_ERC721,
|
|
Symbol: "TMTEST",
|
|
Name: "TMaster-Test",
|
|
Amount: &bigint.BigInt{Int: big.NewInt(1)},
|
|
},
|
|
}
|
|
|
|
_, ok := actual[account1Address]
|
|
s.Require().True(ok, "not found account1Address='%s'", account1Address)
|
|
_, ok = actual[account1Address]
|
|
s.Require().True(ok, "not found account2Address='%s'", account2Address)
|
|
|
|
for accountAddress, permissionedTokens := range actual {
|
|
s.Require().ElementsMatch(expected[accountAddress], permissionedTokens, "accountAddress='%s'", accountAddress)
|
|
}
|
|
}
|
|
|
|
func (s *ManagerSuite) Test_GetPermissionedBalances() {
|
|
m, collectiblesManager, tokenManager := s.setupManagerForTokenPermissions()
|
|
s.Require().NotNil(m)
|
|
s.Require().NotNil(collectiblesManager)
|
|
|
|
request := &requests.CreateCommunity{
|
|
Membership: protobuf.CommunityPermissions_AUTO_ACCEPT,
|
|
}
|
|
community, err := m.CreateCommunity(request, true)
|
|
s.Require().NoError(err)
|
|
s.Require().NotNil(community)
|
|
|
|
accountAddress := gethcommon.HexToAddress("0x1")
|
|
accountAddresses := []gethcommon.Address{accountAddress}
|
|
|
|
var chainID uint64 = 5
|
|
erc20ETHAddress := gethcommon.HexToAddress("0xA")
|
|
erc721Address := gethcommon.HexToAddress("0x123")
|
|
|
|
permissionRequest := &requests.CreateCommunityTokenPermission{
|
|
CommunityID: community.ID(),
|
|
Type: protobuf.CommunityTokenPermission_BECOME_MEMBER,
|
|
TokenCriteria: []*protobuf.TokenCriteria{
|
|
&protobuf.TokenCriteria{
|
|
Type: protobuf.CommunityTokenType_ERC20,
|
|
Symbol: "ETH",
|
|
Name: "Ethereum",
|
|
Amount: "3",
|
|
Decimals: 18,
|
|
ContractAddresses: map[uint64]string{chainID: erc20ETHAddress.Hex()},
|
|
},
|
|
},
|
|
}
|
|
_, changes, err := m.CreateCommunityTokenPermission(permissionRequest)
|
|
s.Require().NoError(err)
|
|
s.Require().Len(changes.TokenPermissionsAdded, 1)
|
|
|
|
permissionRequest = &requests.CreateCommunityTokenPermission{
|
|
CommunityID: community.ID(),
|
|
Type: protobuf.CommunityTokenPermission_BECOME_TOKEN_MASTER,
|
|
TokenCriteria: []*protobuf.TokenCriteria{
|
|
&protobuf.TokenCriteria{
|
|
Type: protobuf.CommunityTokenType_ERC721,
|
|
Symbol: "TMTEST",
|
|
Name: "TMaster-Test",
|
|
Amount: "1",
|
|
TokenIds: []uint64{666},
|
|
ContractAddresses: map[uint64]string{chainID: erc721Address.Hex()},
|
|
},
|
|
},
|
|
}
|
|
_, changes, err = m.CreateCommunityTokenPermission(permissionRequest)
|
|
s.Require().NoError(err)
|
|
s.Require().Len(changes.TokenPermissionsAdded, 1)
|
|
|
|
tokenManager.setResponse(chainID, accountAddress, erc20ETHAddress, 42)
|
|
collectiblesManager.setResponse(chainID, accountAddress, erc721Address, []thirdparty.TokenBalance{
|
|
thirdparty.TokenBalance{
|
|
TokenID: uintToDecBig(666),
|
|
Balance: uintToDecBig(15),
|
|
},
|
|
})
|
|
|
|
actual, err := m.GetPermissionedBalances(context.Background(), community.ID(), accountAddresses)
|
|
s.Require().NoError(err)
|
|
|
|
expected := make(map[gethcommon.Address][]PermissionedBalance)
|
|
expected[accountAddress] = []PermissionedBalance{
|
|
PermissionedBalance{
|
|
Type: protobuf.CommunityTokenType_ERC20,
|
|
Symbol: "ETH",
|
|
Name: "Ethereum",
|
|
Decimals: 18,
|
|
Amount: &bigint.BigInt{Int: big.NewInt(42)},
|
|
},
|
|
PermissionedBalance{
|
|
Type: protobuf.CommunityTokenType_ERC721,
|
|
Symbol: "TMTEST",
|
|
Name: "TMaster-Test",
|
|
Amount: &bigint.BigInt{Int: big.NewInt(1)},
|
|
},
|
|
}
|
|
|
|
_, ok := actual[accountAddress]
|
|
s.Require().True(ok, "not found accountAddress='%s'", accountAddress)
|
|
|
|
for address, permissionedBalances := range actual {
|
|
s.Require().ElementsMatch(expected[address], permissionedBalances)
|
|
}
|
|
}
|