feat: implemented multi chain collectible ownership provider
This commit is contained in:
parent
0919a87588
commit
1f379aec1f
|
@ -27,7 +27,6 @@ import (
|
||||||
|
|
||||||
gethcommon "github.com/ethereum/go-ethereum/common"
|
gethcommon "github.com/ethereum/go-ethereum/common"
|
||||||
"github.com/ethereum/go-ethereum/common/hexutil"
|
"github.com/ethereum/go-ethereum/common/hexutil"
|
||||||
"github.com/ethereum/go-ethereum/event"
|
|
||||||
"github.com/status-im/status-go/account"
|
"github.com/status-im/status-go/account"
|
||||||
"github.com/status-im/status-go/eth-node/crypto"
|
"github.com/status-im/status-go/eth-node/crypto"
|
||||||
"github.com/status-im/status-go/eth-node/types"
|
"github.com/status-im/status-go/eth-node/types"
|
||||||
|
@ -41,7 +40,7 @@ import (
|
||||||
"github.com/status-im/status-go/protocol/transport"
|
"github.com/status-im/status-go/protocol/transport"
|
||||||
"github.com/status-im/status-go/services/wallet/bigint"
|
"github.com/status-im/status-go/services/wallet/bigint"
|
||||||
walletcommon "github.com/status-im/status-go/services/wallet/common"
|
walletcommon "github.com/status-im/status-go/services/wallet/common"
|
||||||
"github.com/status-im/status-go/services/wallet/thirdparty/opensea"
|
"github.com/status-im/status-go/services/wallet/thirdparty"
|
||||||
"github.com/status-im/status-go/services/wallet/token"
|
"github.com/status-im/status-go/services/wallet/token"
|
||||||
"github.com/status-im/status-go/signal"
|
"github.com/status-im/status-go/signal"
|
||||||
)
|
)
|
||||||
|
@ -71,11 +70,11 @@ type Manager struct {
|
||||||
identity *ecdsa.PrivateKey
|
identity *ecdsa.PrivateKey
|
||||||
accountsManager account.Manager
|
accountsManager account.Manager
|
||||||
tokenManager TokenManager
|
tokenManager TokenManager
|
||||||
|
collectiblesManager CollectiblesManager
|
||||||
logger *zap.Logger
|
logger *zap.Logger
|
||||||
stdoutLogger *zap.Logger
|
stdoutLogger *zap.Logger
|
||||||
transport *transport.Transport
|
transport *transport.Transport
|
||||||
quit chan struct{}
|
quit chan struct{}
|
||||||
openseaClientBuilder openseaClientBuilder
|
|
||||||
torrentConfig *params.TorrentConfig
|
torrentConfig *params.TorrentConfig
|
||||||
torrentClient *torrent.Client
|
torrentClient *torrent.Client
|
||||||
walletConfig *params.WalletConfig
|
walletConfig *params.WalletConfig
|
||||||
|
@ -87,21 +86,6 @@ type Manager struct {
|
||||||
stopped bool
|
stopped bool
|
||||||
}
|
}
|
||||||
|
|
||||||
type openseaClient interface {
|
|
||||||
FetchAllAssetsByOwnerAndContractAddress(owner gethcommon.Address, contractAddresses []gethcommon.Address, cursor string, limit int) (*opensea.AssetContainer, error)
|
|
||||||
}
|
|
||||||
|
|
||||||
type openseaClientBuilder interface {
|
|
||||||
NewOpenseaClient(uint64, string, *event.Feed) (openseaClient, error)
|
|
||||||
}
|
|
||||||
|
|
||||||
type defaultOpenseaBuilder struct {
|
|
||||||
}
|
|
||||||
|
|
||||||
func (b *defaultOpenseaBuilder) NewOpenseaClient(chainID uint64, apiKey string, feed *event.Feed) (openseaClient, error) {
|
|
||||||
return opensea.NewOpenseaClient(chainID, apiKey, nil)
|
|
||||||
}
|
|
||||||
|
|
||||||
type HistoryArchiveDownloadTask struct {
|
type HistoryArchiveDownloadTask struct {
|
||||||
CancelChan chan struct{}
|
CancelChan chan struct{}
|
||||||
Waiter sync.WaitGroup
|
Waiter sync.WaitGroup
|
||||||
|
@ -123,10 +107,10 @@ func (t *HistoryArchiveDownloadTask) Cancel() {
|
||||||
}
|
}
|
||||||
|
|
||||||
type managerOptions struct {
|
type managerOptions struct {
|
||||||
accountsManager account.Manager
|
accountsManager account.Manager
|
||||||
tokenManager TokenManager
|
tokenManager TokenManager
|
||||||
walletConfig *params.WalletConfig
|
collectiblesManager CollectiblesManager
|
||||||
openseaClientBuilder openseaClientBuilder
|
walletConfig *params.WalletConfig
|
||||||
}
|
}
|
||||||
|
|
||||||
type TokenManager interface {
|
type TokenManager interface {
|
||||||
|
@ -157,6 +141,10 @@ func (m *DefaultTokenManager) GetAllChainIDs() ([]uint64, error) {
|
||||||
return chainIDs, nil
|
return chainIDs, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type CollectiblesManager interface {
|
||||||
|
FetchBalancesByOwnerAndContractAddress(chainID uint64, ownerAddress gethcommon.Address, contractAddresses []gethcommon.Address) (thirdparty.TokenBalancesPerContractAddress, error)
|
||||||
|
}
|
||||||
|
|
||||||
func (m *DefaultTokenManager) GetBalancesByChain(ctx context.Context, accounts, tokenAddresses []gethcommon.Address, chainIDs []uint64) (BalancesByChain, error) {
|
func (m *DefaultTokenManager) GetBalancesByChain(ctx context.Context, accounts, tokenAddresses []gethcommon.Address, chainIDs []uint64) (BalancesByChain, error) {
|
||||||
clients, err := m.tokenManager.RPCClient.EthClients(chainIDs)
|
clients, err := m.tokenManager.RPCClient.EthClients(chainIDs)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -175,9 +163,9 @@ func WithAccountManager(accountsManager account.Manager) ManagerOption {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func WithOpenseaClientBuilder(builder openseaClientBuilder) ManagerOption {
|
func WithCollectiblesManager(collectiblesManager CollectiblesManager) ManagerOption {
|
||||||
return func(opts *managerOptions) {
|
return func(opts *managerOptions) {
|
||||||
opts.openseaClientBuilder = builder
|
opts.collectiblesManager = collectiblesManager
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -235,6 +223,10 @@ func NewManager(identity *ecdsa.PrivateKey, db *sql.DB, encryptor *encryption.Pr
|
||||||
manager.accountsManager = managerConfig.accountsManager
|
manager.accountsManager = managerConfig.accountsManager
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if managerConfig.collectiblesManager != nil {
|
||||||
|
manager.collectiblesManager = managerConfig.collectiblesManager
|
||||||
|
}
|
||||||
|
|
||||||
if managerConfig.tokenManager != nil {
|
if managerConfig.tokenManager != nil {
|
||||||
manager.tokenManager = managerConfig.tokenManager
|
manager.tokenManager = managerConfig.tokenManager
|
||||||
}
|
}
|
||||||
|
@ -243,12 +235,6 @@ func NewManager(identity *ecdsa.PrivateKey, db *sql.DB, encryptor *encryption.Pr
|
||||||
manager.walletConfig = managerConfig.walletConfig
|
manager.walletConfig = managerConfig.walletConfig
|
||||||
}
|
}
|
||||||
|
|
||||||
if managerConfig.openseaClientBuilder != nil {
|
|
||||||
manager.openseaClientBuilder = managerConfig.openseaClientBuilder
|
|
||||||
} else {
|
|
||||||
manager.openseaClientBuilder = &defaultOpenseaBuilder{}
|
|
||||||
}
|
|
||||||
|
|
||||||
if verifier != nil {
|
if verifier != nil {
|
||||||
|
|
||||||
sub := verifier.Subscribe()
|
sub := verifier.Subscribe()
|
||||||
|
@ -2002,8 +1988,9 @@ func (m *Manager) checkPermissions(permissions []*protobuf.CommunityTokenPermiss
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
if _, exists := ownedERC721Tokens[chainID][account][strings.ToLower(address)]; exists {
|
tokenBalances := ownedERC721Tokens[chainID][account][gethcommon.HexToAddress(address)]
|
||||||
|
if len(tokenBalances) > 0 {
|
||||||
|
// 'account' owns some TokenID owned from contract 'address'
|
||||||
if _, exists := accountsChainIDsCombinations[account]; !exists {
|
if _, exists := accountsChainIDsCombinations[account]; !exists {
|
||||||
accountsChainIDsCombinations[account] = make(map[uint64]bool)
|
accountsChainIDsCombinations[account] = make(map[uint64]bool)
|
||||||
}
|
}
|
||||||
|
@ -2019,8 +2006,8 @@ func (m *Manager) checkPermissions(permissions []*protobuf.CommunityTokenPermiss
|
||||||
for _, tokenID := range tokenRequirement.TokenIds {
|
for _, tokenID := range tokenRequirement.TokenIds {
|
||||||
tokenIDBigInt := new(big.Int).SetUint64(tokenID)
|
tokenIDBigInt := new(big.Int).SetUint64(tokenID)
|
||||||
|
|
||||||
for _, asset := range ownedERC721Tokens[chainID][account][strings.ToLower(address)] {
|
for _, asset := range tokenBalances {
|
||||||
if asset.TokenID.Cmp(tokenIDBigInt) == 0 {
|
if asset.TokenID.Cmp(tokenIDBigInt) == 0 && asset.Balance.Sign() > 0 {
|
||||||
tokenRequirementMet = true
|
tokenRequirementMet = true
|
||||||
accountsChainIDsCombinations[account][chainID] = true
|
accountsChainIDsCombinations[account][chainID] = true
|
||||||
break tokenIDsLoop
|
break tokenIDsLoop
|
||||||
|
@ -2143,15 +2130,14 @@ func (m *Manager) checkPermissions(permissions []*protobuf.CommunityTokenPermiss
|
||||||
return response, nil
|
return response, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
type CollectiblesByChain = map[uint64]map[gethcommon.Address]map[string][]opensea.Asset
|
type CollectiblesByChain = map[uint64]map[gethcommon.Address]thirdparty.TokenBalancesPerContractAddress
|
||||||
|
|
||||||
func (m *Manager) GetOwnedERC721Tokens(walletAddresses []gethcommon.Address, tokenRequirements map[uint64]map[string]*protobuf.TokenCriteria, chainIDs []uint64) (CollectiblesByChain, error) {
|
func (m *Manager) GetOwnedERC721Tokens(walletAddresses []gethcommon.Address, tokenRequirements map[uint64]map[string]*protobuf.TokenCriteria, chainIDs []uint64) (CollectiblesByChain, error) {
|
||||||
|
if m.collectiblesManager == nil {
|
||||||
if m.walletConfig == nil || m.walletConfig.OpenseaAPIKey == "" {
|
return nil, errors.New("no collectibles manager")
|
||||||
return nil, errors.New("no opensea client")
|
|
||||||
}
|
}
|
||||||
|
|
||||||
ownedERC721Tokens := make(map[uint64]map[gethcommon.Address]map[string][]opensea.Asset)
|
ownedERC721Tokens := make(CollectiblesByChain)
|
||||||
|
|
||||||
for chainID, erc721Tokens := range tokenRequirements {
|
for chainID, erc721Tokens := range tokenRequirements {
|
||||||
|
|
||||||
|
@ -2166,41 +2152,22 @@ func (m *Manager) GetOwnedERC721Tokens(walletAddresses []gethcommon.Address, tok
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
client, err := m.openseaClientBuilder.NewOpenseaClient(chainID, m.walletConfig.OpenseaAPIKey, nil)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
contractAddresses := make([]gethcommon.Address, 0)
|
contractAddresses := make([]gethcommon.Address, 0)
|
||||||
for contractAddress := range erc721Tokens {
|
for contractAddress := range erc721Tokens {
|
||||||
contractAddresses = append(contractAddresses, gethcommon.HexToAddress(contractAddress))
|
contractAddresses = append(contractAddresses, gethcommon.HexToAddress(contractAddress))
|
||||||
}
|
}
|
||||||
|
|
||||||
if _, exists := ownedERC721Tokens[chainID]; !exists {
|
if _, exists := ownedERC721Tokens[chainID]; !exists {
|
||||||
ownedERC721Tokens[chainID] = make(map[gethcommon.Address]map[string][]opensea.Asset)
|
ownedERC721Tokens[chainID] = make(map[gethcommon.Address]thirdparty.TokenBalancesPerContractAddress)
|
||||||
}
|
}
|
||||||
|
|
||||||
for _, owner := range walletAddresses {
|
for _, owner := range walletAddresses {
|
||||||
assets, err := client.FetchAllAssetsByOwnerAndContractAddress(owner, contractAddresses, "", 5)
|
balances, err := m.collectiblesManager.FetchBalancesByOwnerAndContractAddress(chainID, owner, contractAddresses)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
m.logger.Info("couldn't fetch owner assets", zap.Error(err))
|
m.logger.Info("couldn't fetch owner assets", zap.Error(err))
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
ownedERC721Tokens[chainID][owner] = balances
|
||||||
if len(assets.Assets) == 0 {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
|
|
||||||
if _, exists := ownedERC721Tokens[chainID][owner]; !exists {
|
|
||||||
ownedERC721Tokens[chainID][owner] = make(map[string][]opensea.Asset, 0)
|
|
||||||
}
|
|
||||||
|
|
||||||
for _, asset := range assets.Assets {
|
|
||||||
if _, exists := ownedERC721Tokens[chainID][owner][asset.Contract.Address]; !exists {
|
|
||||||
ownedERC721Tokens[chainID][owner][asset.Contract.Address] = make([]opensea.Asset, 0)
|
|
||||||
}
|
|
||||||
ownedERC721Tokens[chainID][owner][asset.Contract.Address] = append(ownedERC721Tokens[chainID][owner][asset.Contract.Address], asset)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return ownedERC721Tokens, nil
|
return ownedERC721Tokens, nil
|
||||||
|
|
|
@ -14,14 +14,14 @@ import (
|
||||||
|
|
||||||
gethcommon "github.com/ethereum/go-ethereum/common"
|
gethcommon "github.com/ethereum/go-ethereum/common"
|
||||||
"github.com/ethereum/go-ethereum/common/hexutil"
|
"github.com/ethereum/go-ethereum/common/hexutil"
|
||||||
"github.com/ethereum/go-ethereum/event"
|
|
||||||
"github.com/status-im/status-go/appdatabase"
|
"github.com/status-im/status-go/appdatabase"
|
||||||
"github.com/status-im/status-go/eth-node/types"
|
"github.com/status-im/status-go/eth-node/types"
|
||||||
userimages "github.com/status-im/status-go/images"
|
userimages "github.com/status-im/status-go/images"
|
||||||
"github.com/status-im/status-go/params"
|
"github.com/status-im/status-go/params"
|
||||||
"github.com/status-im/status-go/protocol/requests"
|
"github.com/status-im/status-go/protocol/requests"
|
||||||
"github.com/status-im/status-go/protocol/transport"
|
"github.com/status-im/status-go/protocol/transport"
|
||||||
"github.com/status-im/status-go/services/wallet/thirdparty/opensea"
|
"github.com/status-im/status-go/services/wallet/bigint"
|
||||||
|
"github.com/status-im/status-go/services/wallet/thirdparty"
|
||||||
|
|
||||||
"github.com/golang/protobuf/proto"
|
"github.com/golang/protobuf/proto"
|
||||||
_ "github.com/mutecomm/go-sqlcipher/v4" // require go-sqlcipher that overrides default implementation
|
_ "github.com/mutecomm/go-sqlcipher/v4" // require go-sqlcipher that overrides default implementation
|
||||||
|
@ -63,6 +63,17 @@ func intToBig(n int64) *hexutil.Big {
|
||||||
return (*hexutil.Big)(big.NewInt(n))
|
return (*hexutil.Big)(big.NewInt(n))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func uintToDecBig(n uint64) *bigint.BigInt {
|
||||||
|
return &bigint.BigInt{Int: big.NewInt(int64(n))}
|
||||||
|
}
|
||||||
|
|
||||||
|
func tokenBalance(tokenID uint64, balance uint64) thirdparty.TokenBalance {
|
||||||
|
return thirdparty.TokenBalance{
|
||||||
|
TokenID: uintToDecBig(tokenID),
|
||||||
|
Balance: uintToDecBig(balance),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func (s *ManagerSuite) getHistoryTasksCount() int {
|
func (s *ManagerSuite) getHistoryTasksCount() int {
|
||||||
// sync.Map doesn't have a Len function, so we need to count manually
|
// sync.Map doesn't have a Len function, so we need to count manually
|
||||||
count := 0
|
count := 0
|
||||||
|
@ -73,11 +84,26 @@ func (s *ManagerSuite) getHistoryTasksCount() int {
|
||||||
return count
|
return count
|
||||||
}
|
}
|
||||||
|
|
||||||
type openseaClientTestBuilder struct {
|
type testCollectiblesManager struct {
|
||||||
|
response map[uint64]map[gethcommon.Address]thirdparty.TokenBalancesPerContractAddress
|
||||||
}
|
}
|
||||||
|
|
||||||
func (b *openseaClientTestBuilder) NewOpenseaClient(chainID uint64, apiKey string, feed *event.Feed) (openseaClient, error) {
|
func (m *testCollectiblesManager) setResponse(chainID uint64, walletAddress gethcommon.Address, contractAddress gethcommon.Address, balances []thirdparty.TokenBalance) {
|
||||||
return opensea.NewOpenseaClient(chainID, apiKey, nil)
|
if m.response == nil {
|
||||||
|
m.response = make(map[uint64]map[gethcommon.Address]thirdparty.TokenBalancesPerContractAddress)
|
||||||
|
}
|
||||||
|
if m.response[chainID] == nil {
|
||||||
|
m.response[chainID] = make(map[gethcommon.Address]thirdparty.TokenBalancesPerContractAddress)
|
||||||
|
}
|
||||||
|
if m.response[chainID][walletAddress] == nil {
|
||||||
|
m.response[chainID][walletAddress] = make(thirdparty.TokenBalancesPerContractAddress)
|
||||||
|
}
|
||||||
|
|
||||||
|
m.response[chainID][walletAddress][contractAddress] = balances
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m *testCollectiblesManager) FetchBalancesByOwnerAndContractAddress(chainID uint64, ownerAddress gethcommon.Address, contractAddresses []gethcommon.Address) (thirdparty.TokenBalancesPerContractAddress, error) {
|
||||||
|
return m.response[chainID][ownerAddress], nil
|
||||||
}
|
}
|
||||||
|
|
||||||
type testTokenManager struct {
|
type testTokenManager struct {
|
||||||
|
@ -110,7 +136,7 @@ func (m *testTokenManager) GetBalancesByChain(ctx context.Context, accounts, tok
|
||||||
return m.response, nil
|
return m.response, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *ManagerSuite) setupManagerForTokenPermissions() (*Manager, *testTokenManager) {
|
func (s *ManagerSuite) setupManagerForTokenPermissions() (*Manager, *testCollectiblesManager, *testTokenManager) {
|
||||||
db, err := appdatabase.InitializeDB(sqlite.InMemoryPath, "", sqlite.ReducedKDFIterationsNumber)
|
db, err := appdatabase.InitializeDB(sqlite.InMemoryPath, "", sqlite.ReducedKDFIterationsNumber)
|
||||||
s.NoError(err, "creating sqlite db instance")
|
s.NoError(err, "creating sqlite db instance")
|
||||||
err = sqlite.Migrate(db)
|
err = sqlite.Migrate(db)
|
||||||
|
@ -120,13 +146,14 @@ func (s *ManagerSuite) setupManagerForTokenPermissions() (*Manager, *testTokenMa
|
||||||
s.Require().NoError(err)
|
s.Require().NoError(err)
|
||||||
s.Require().NoError(err)
|
s.Require().NoError(err)
|
||||||
|
|
||||||
|
cm := &testCollectiblesManager{}
|
||||||
tm := &testTokenManager{}
|
tm := &testTokenManager{}
|
||||||
|
|
||||||
options := []ManagerOption{
|
options := []ManagerOption{
|
||||||
WithWalletConfig(¶ms.WalletConfig{
|
WithWalletConfig(¶ms.WalletConfig{
|
||||||
OpenseaAPIKey: "some-key",
|
OpenseaAPIKey: "some-key",
|
||||||
}),
|
}),
|
||||||
WithOpenseaClientBuilder(&openseaClientTestBuilder{}),
|
WithCollectiblesManager(cm),
|
||||||
WithTokenManager(tm),
|
WithTokenManager(tm),
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -134,11 +161,11 @@ func (s *ManagerSuite) setupManagerForTokenPermissions() (*Manager, *testTokenMa
|
||||||
s.Require().NoError(err)
|
s.Require().NoError(err)
|
||||||
s.Require().NoError(m.Start())
|
s.Require().NoError(m.Start())
|
||||||
|
|
||||||
return m, tm
|
return m, cm, tm
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *ManagerSuite) TestRetrieveTokens() {
|
func (s *ManagerSuite) TestRetrieveTokens() {
|
||||||
m, tm := s.setupManagerForTokenPermissions()
|
m, _, tm := s.setupManagerForTokenPermissions()
|
||||||
|
|
||||||
var chainID uint64 = 5
|
var chainID uint64 = 5
|
||||||
contractAddresses := make(map[uint64]string)
|
contractAddresses := make(map[uint64]string)
|
||||||
|
@ -185,6 +212,56 @@ func (s *ManagerSuite) TestRetrieveTokens() {
|
||||||
s.Require().False(resp.Satisfied)
|
s.Require().False(resp.Satisfied)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (s *ManagerSuite) TestRetrieveCollectibles() {
|
||||||
|
m, cm, _ := s.setupManagerForTokenPermissions()
|
||||||
|
|
||||||
|
var chainID uint64 = 5
|
||||||
|
contractAddresses := make(map[uint64]string)
|
||||||
|
contractAddresses[chainID] = "0x3d6afaa395c31fcd391fe3d562e75fe9e8ec7e6a"
|
||||||
|
|
||||||
|
tokenID := uint64(10)
|
||||||
|
var tokenBalances []thirdparty.TokenBalance
|
||||||
|
|
||||||
|
var tokenCriteria = []*protobuf.TokenCriteria{
|
||||||
|
&protobuf.TokenCriteria{
|
||||||
|
ContractAddresses: contractAddresses,
|
||||||
|
TokenIds: []uint64{tokenID},
|
||||||
|
Type: protobuf.CommunityTokenType_ERC721,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
var permissions = []*protobuf.CommunityTokenPermission{
|
||||||
|
&protobuf.CommunityTokenPermission{
|
||||||
|
Id: "some-id",
|
||||||
|
Type: protobuf.CommunityTokenPermission_BECOME_MEMBER,
|
||||||
|
TokenCriteria: tokenCriteria,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
accountChainIDsCombination := []*AccountChainIDsCombination{
|
||||||
|
&AccountChainIDsCombination{
|
||||||
|
Address: gethcommon.HexToAddress("0xD6b912e09E797D291E8D0eA3D3D17F8000e01c32"),
|
||||||
|
ChainIDs: []uint64{chainID},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
// Set response to exactly the right one
|
||||||
|
tokenBalances = []thirdparty.TokenBalance{tokenBalance(tokenID, 1)}
|
||||||
|
cm.setResponse(chainID, accountChainIDsCombination[0].Address, gethcommon.HexToAddress(contractAddresses[chainID]), tokenBalances)
|
||||||
|
resp, err := m.checkPermissionToJoin(permissions, accountChainIDsCombination, false)
|
||||||
|
s.Require().NoError(err)
|
||||||
|
s.Require().NotNil(resp)
|
||||||
|
s.Require().True(resp.Satisfied)
|
||||||
|
|
||||||
|
// Set balances to 0
|
||||||
|
tokenBalances = []thirdparty.TokenBalance{}
|
||||||
|
cm.setResponse(chainID, accountChainIDsCombination[0].Address, gethcommon.HexToAddress(contractAddresses[chainID]), tokenBalances)
|
||||||
|
resp, err = m.checkPermissionToJoin(permissions, accountChainIDsCombination, false)
|
||||||
|
s.Require().NoError(err)
|
||||||
|
s.Require().NotNil(resp)
|
||||||
|
s.Require().False(resp.Satisfied)
|
||||||
|
}
|
||||||
|
|
||||||
func (s *ManagerSuite) TestCreateCommunity() {
|
func (s *ManagerSuite) TestCreateCommunity() {
|
||||||
|
|
||||||
request := &requests.CreateCommunity{
|
request := &requests.CreateCommunity{
|
||||||
|
@ -812,7 +889,7 @@ func (s *ManagerSuite) TestUnseedHistoryArchiveTorrent() {
|
||||||
|
|
||||||
func (s *ManagerSuite) TestCheckChannelPermissions_NoPermissions() {
|
func (s *ManagerSuite) TestCheckChannelPermissions_NoPermissions() {
|
||||||
|
|
||||||
m, tm := s.setupManagerForTokenPermissions()
|
m, _, tm := s.setupManagerForTokenPermissions()
|
||||||
|
|
||||||
var chainID uint64 = 5
|
var chainID uint64 = 5
|
||||||
contractAddresses := make(map[uint64]string)
|
contractAddresses := make(map[uint64]string)
|
||||||
|
@ -841,7 +918,7 @@ func (s *ManagerSuite) TestCheckChannelPermissions_NoPermissions() {
|
||||||
|
|
||||||
func (s *ManagerSuite) TestCheckChannelPermissions_ViewOnlyPermissions() {
|
func (s *ManagerSuite) TestCheckChannelPermissions_ViewOnlyPermissions() {
|
||||||
|
|
||||||
m, tm := s.setupManagerForTokenPermissions()
|
m, _, tm := s.setupManagerForTokenPermissions()
|
||||||
|
|
||||||
var chainID uint64 = 5
|
var chainID uint64 = 5
|
||||||
contractAddresses := make(map[uint64]string)
|
contractAddresses := make(map[uint64]string)
|
||||||
|
@ -899,7 +976,7 @@ func (s *ManagerSuite) TestCheckChannelPermissions_ViewOnlyPermissions() {
|
||||||
|
|
||||||
func (s *ManagerSuite) TestCheckChannelPermissions_ViewAndPostPermissions() {
|
func (s *ManagerSuite) TestCheckChannelPermissions_ViewAndPostPermissions() {
|
||||||
|
|
||||||
m, tm := s.setupManagerForTokenPermissions()
|
m, _, tm := s.setupManagerForTokenPermissions()
|
||||||
|
|
||||||
var chainID uint64 = 5
|
var chainID uint64 = 5
|
||||||
contractAddresses := make(map[uint64]string)
|
contractAddresses := make(map[uint64]string)
|
||||||
|
@ -958,7 +1035,7 @@ func (s *ManagerSuite) TestCheckChannelPermissions_ViewAndPostPermissions() {
|
||||||
|
|
||||||
func (s *ManagerSuite) TestCheckChannelPermissions_ViewAndPostPermissionsCombination() {
|
func (s *ManagerSuite) TestCheckChannelPermissions_ViewAndPostPermissionsCombination() {
|
||||||
|
|
||||||
m, tm := s.setupManagerForTokenPermissions()
|
m, _, tm := s.setupManagerForTokenPermissions()
|
||||||
|
|
||||||
var chainID uint64 = 5
|
var chainID uint64 = 5
|
||||||
contractAddresses := make(map[uint64]string)
|
contractAddresses := make(map[uint64]string)
|
||||||
|
@ -1032,7 +1109,7 @@ func (s *ManagerSuite) TestCheckChannelPermissions_ViewAndPostPermissionsCombina
|
||||||
|
|
||||||
func (s *ManagerSuite) TestCheckAllChannelsPermissions_EmptyPermissions() {
|
func (s *ManagerSuite) TestCheckAllChannelsPermissions_EmptyPermissions() {
|
||||||
|
|
||||||
m, _ := s.setupManagerForTokenPermissions()
|
m, _, _ := s.setupManagerForTokenPermissions()
|
||||||
|
|
||||||
createRequest := &requests.CreateCommunity{
|
createRequest := &requests.CreateCommunity{
|
||||||
Name: "channel permission community",
|
Name: "channel permission community",
|
||||||
|
@ -1079,7 +1156,7 @@ func (s *ManagerSuite) TestCheckAllChannelsPermissions_EmptyPermissions() {
|
||||||
|
|
||||||
func (s *ManagerSuite) TestCheckAllChannelsPermissions() {
|
func (s *ManagerSuite) TestCheckAllChannelsPermissions() {
|
||||||
|
|
||||||
m, tm := s.setupManagerForTokenPermissions()
|
m, _, tm := s.setupManagerForTokenPermissions()
|
||||||
|
|
||||||
var chatID1 string
|
var chatID1 string
|
||||||
var chatID2 string
|
var chatID2 string
|
||||||
|
|
|
@ -422,10 +422,19 @@ func NewMessenger(
|
||||||
|
|
||||||
ensVerifier := ens.New(node, logger, transp, database, c.verifyENSURL, c.verifyENSContractAddress)
|
ensVerifier := ens.New(node, logger, transp, database, c.verifyENSURL, c.verifyENSContractAddress)
|
||||||
|
|
||||||
|
var walletAPI *wallet.API
|
||||||
|
if c.walletService != nil {
|
||||||
|
walletAPI = wallet.NewAPI(c.walletService)
|
||||||
|
}
|
||||||
|
|
||||||
managerOptions := []communities.ManagerOption{
|
managerOptions := []communities.ManagerOption{
|
||||||
communities.WithAccountManager(accountsManager),
|
communities.WithAccountManager(accountsManager),
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if walletAPI != nil {
|
||||||
|
managerOptions = append(managerOptions, communities.WithCollectiblesManager(walletAPI))
|
||||||
|
}
|
||||||
|
|
||||||
if c.tokenManager != nil {
|
if c.tokenManager != nil {
|
||||||
managerOptions = append(managerOptions, communities.WithTokenManager(c.tokenManager))
|
managerOptions = append(managerOptions, communities.WithTokenManager(c.tokenManager))
|
||||||
} else if c.rpcClient != nil {
|
} else if c.rpcClient != nil {
|
||||||
|
@ -545,7 +554,7 @@ func NewMessenger(
|
||||||
messenger.mentionsManager = NewMentionManager(messenger)
|
messenger.mentionsManager = NewMentionManager(messenger)
|
||||||
|
|
||||||
if c.walletService != nil {
|
if c.walletService != nil {
|
||||||
messenger.walletAPI = wallet.NewAPI(c.walletService)
|
messenger.walletAPI = walletAPI
|
||||||
}
|
}
|
||||||
|
|
||||||
if c.outputMessagesCSV {
|
if c.outputMessagesCSV {
|
||||||
|
|
|
@ -338,6 +338,11 @@ func (api *API) GetCollectibleOwnersByContractAddress(chainID uint64, contractAd
|
||||||
return api.s.collectiblesManager.FetchNFTOwnersByContractAddress(chainID, contractAddress)
|
return api.s.collectiblesManager.FetchNFTOwnersByContractAddress(chainID, contractAddress)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (api *API) FetchBalancesByOwnerAndContractAddress(chainID uint64, ownerAddress common.Address, contractAddresses []common.Address) (thirdparty.TokenBalancesPerContractAddress, error) {
|
||||||
|
log.Debug("call to FetchBalancesByOwnerAndContractAddress")
|
||||||
|
return api.s.collectiblesManager.FetchBalancesByOwnerAndContractAddress(chainID, ownerAddress, contractAddresses)
|
||||||
|
}
|
||||||
|
|
||||||
func (api *API) AddEthereumChain(ctx context.Context, network params.Network) error {
|
func (api *API) AddEthereumChain(ctx context.Context, network params.Network) error {
|
||||||
log.Debug("call to AddEthereumChain")
|
log.Debug("call to AddEthereumChain")
|
||||||
return api.s.rpcClient.NetworkManager.Upsert(&network)
|
return api.s.rpcClient.NetworkManager.Upsert(&network)
|
||||||
|
|
|
@ -3,6 +3,7 @@ package collectibles
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"math/big"
|
||||||
"strings"
|
"strings"
|
||||||
"sync"
|
"sync"
|
||||||
"time"
|
"time"
|
||||||
|
@ -14,6 +15,7 @@ import (
|
||||||
"github.com/ethereum/go-ethereum/event"
|
"github.com/ethereum/go-ethereum/event"
|
||||||
"github.com/status-im/status-go/contracts/collectibles"
|
"github.com/status-im/status-go/contracts/collectibles"
|
||||||
"github.com/status-im/status-go/rpc"
|
"github.com/status-im/status-go/rpc"
|
||||||
|
"github.com/status-im/status-go/services/wallet/bigint"
|
||||||
"github.com/status-im/status-go/services/wallet/thirdparty"
|
"github.com/status-im/status-go/services/wallet/thirdparty"
|
||||||
"github.com/status-im/status-go/services/wallet/thirdparty/opensea"
|
"github.com/status-im/status-go/services/wallet/thirdparty/opensea"
|
||||||
)
|
)
|
||||||
|
@ -121,6 +123,48 @@ func (o *Manager) FetchAllAssetsByOwnerAndCollection(chainID uint64, owner commo
|
||||||
return assetContainer, nil
|
return assetContainer, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Need to combine different providers to support all needed ChainIDs
|
||||||
|
func (o *Manager) FetchBalancesByOwnerAndContractAddress(chainID uint64, ownerAddress common.Address, contractAddresses []common.Address) (thirdparty.TokenBalancesPerContractAddress, error) {
|
||||||
|
ret := make(thirdparty.TokenBalancesPerContractAddress)
|
||||||
|
|
||||||
|
for _, contractAddress := range contractAddresses {
|
||||||
|
ret[contractAddress] = make([]thirdparty.TokenBalance, 0)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Try with more direct endpoint first (OpenSea)
|
||||||
|
assetsContainer, err := o.FetchAllAssetsByOwnerAndContractAddress(chainID, ownerAddress, contractAddresses, "", 0)
|
||||||
|
if err == opensea.ErrChainIDNotSupported {
|
||||||
|
// Use contract ownership providers
|
||||||
|
for _, contractAddress := range contractAddresses {
|
||||||
|
ownership, err := o.FetchNFTOwnersByContractAddress(chainID, contractAddress)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
for _, nftOwner := range ownership.Owners {
|
||||||
|
if nftOwner.OwnerAddress == ownerAddress {
|
||||||
|
ret[contractAddress] = nftOwner.TokenBalances
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else if err == nil {
|
||||||
|
// OpenSea could provide
|
||||||
|
for _, asset := range assetsContainer.Assets {
|
||||||
|
contractAddress := common.HexToAddress(asset.Contract.Address)
|
||||||
|
balance := thirdparty.TokenBalance{
|
||||||
|
TokenID: asset.TokenID,
|
||||||
|
Balance: &bigint.BigInt{Int: big.NewInt(1)},
|
||||||
|
}
|
||||||
|
ret[contractAddress] = append(ret[contractAddress], balance)
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// OpenSea could have provided, but returned error
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return ret, nil
|
||||||
|
}
|
||||||
|
|
||||||
func (o *Manager) FetchAllAssetsByOwnerAndContractAddress(chainID uint64, owner common.Address, contractAddresses []common.Address, cursor string, limit int) (*opensea.AssetContainer, error) {
|
func (o *Manager) FetchAllAssetsByOwnerAndContractAddress(chainID uint64, owner common.Address, contractAddresses []common.Address, cursor string, limit int) (*opensea.AssetContainer, error) {
|
||||||
client, err := opensea.NewOpenseaClient(chainID, o.openseaAPIKey, o.walletFeed)
|
client, err := opensea.NewOpenseaClient(chainID, o.openseaAPIKey, o.walletFeed)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|
|
@ -67,6 +67,8 @@ type TokenBalance struct {
|
||||||
Balance *bigint.BigInt `json:"balance"`
|
Balance *bigint.BigInt `json:"balance"`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type TokenBalancesPerContractAddress = map[common.Address][]TokenBalance
|
||||||
|
|
||||||
type NFTOwner struct {
|
type NFTOwner struct {
|
||||||
OwnerAddress common.Address `json:"ownerAddress"`
|
OwnerAddress common.Address `json:"ownerAddress"`
|
||||||
TokenBalances []TokenBalance `json:"tokenBalances"`
|
TokenBalances []TokenBalance `json:"tokenBalances"`
|
||||||
|
|
Loading…
Reference in New Issue