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 }