From fb8ea4a054947844f174226a0e15b8edcc6203f1 Mon Sep 17 00:00:00 2001 From: Dario Gabriel Lipicar Date: Mon, 17 Apr 2023 15:41:00 -0300 Subject: [PATCH] feat: add api to get list of owners from a given nft contract Fixes #10290 --- resources/node-config.json | 5 +- src/app_service/common/network_constants.nim | 64 ++++++++++++++++++-- src/app_service/service/accounts/service.nim | 10 ++- src/app_service/service/collectible/dto.nim | 53 ++++++++++++++++ src/backend/collectibles.nim | 4 ++ vendor/status-go | 2 +- 6 files changed, 129 insertions(+), 9 deletions(-) diff --git a/resources/node-config.json b/resources/node-config.json index 7495d04911..72f039c3b6 100644 --- a/resources/node-config.json +++ b/resources/node-config.json @@ -74,7 +74,10 @@ }, "WalletConfig": { "Enabled": true, - "OpenseaAPIKey": "" + "OpenseaAPIKey": "", + "AlchemyAPIKeys": {}, + "InfuraAPIKey": "", + "InfuraAPIKeySecret": "" }, "Networks": [], "TorrentConfig": { diff --git a/src/app_service/common/network_constants.nim b/src/app_service/common/network_constants.nim index e79900fcf8..517802c215 100644 --- a/src/app_service/common/network_constants.nim +++ b/src/app_service/common/network_constants.nim @@ -1,10 +1,12 @@ import json, os, chronicles, strutils import ../../constants as main_constants -# set via `nim c` param `-d:POKT_TOKEN:[token]`; should be set in CI/release builds -const POKT_TOKEN {.strdefine.} = "" +# provider Tokens # allow runtime override via environment variable; core contributors can set a # release token in this way for local development + +# set via `nim c` param `-d:POKT_TOKEN:[token]`; should be set in CI/release builds +const POKT_TOKEN {.strdefine.} = "" let POKT_TOKEN_ENV = $getEnv("POKT_TOKEN") let POKT_TOKEN_RESOLVED = if POKT_TOKEN_ENV != "": @@ -14,15 +16,57 @@ let POKT_TOKEN_RESOLVED = # set via `nim c` param `-d:INFURA_TOKEN:[token]`; should be set in CI/release builds const INFURA_TOKEN {.strdefine.} = "" -# allow runtime override via environment variable; core contributors can set a -# release token in this way for local development let INFURA_TOKEN_ENV = $getEnv("INFURA_TOKEN") -let INFURA_TOKEN_RESOLVED = +let INFURA_TOKEN_RESOLVED* = if INFURA_TOKEN_ENV != "": INFURA_TOKEN_ENV else: INFURA_TOKEN +# set via `nim c` param `-d:INFURA_TOKEN_SECRET:[token]`; should be set in CI/release builds +const INFURA_TOKEN_SECRET {.strdefine.} = "" +let INFURA_TOKEN_SECRET_ENV = $getEnv("INFURA_TOKEN_SECRET") +let INFURA_TOKEN_SECRET_RESOLVED* = + if INFURA_TOKEN_SECRET_ENV != "": + INFURA_TOKEN_SECRET_ENV + else: + INFURA_TOKEN_SECRET + +# set via `nim c` param `-d:ALCHEMY_ARBITRUM_MAINNET_TOKEN:[token]`; should be set in CI/release builds +const ALCHEMY_ARBITRUM_MAINNET_TOKEN {.strdefine.} = "" +let ALCHEMY_ARBITRUM_MAINNET_TOKEN_ENV = $getEnv("ALCHEMY_ARBITRUM_MAINNET_TOKEN") +let ALCHEMY_ARBITRUM_MAINNET_TOKEN_RESOLVED* = + if ALCHEMY_ARBITRUM_MAINNET_TOKEN_ENV != "": + ALCHEMY_ARBITRUM_MAINNET_TOKEN_ENV + else: + ALCHEMY_ARBITRUM_MAINNET_TOKEN + +# set via `nim c` param `-d:ALCHEMY_ARBITRUM_GOERLI_TOKEN:[token]`; should be set in CI/release builds +const ALCHEMY_ARBITRUM_GOERLI_TOKEN {.strdefine.} = "" +let ALCHEMY_ARBITRUM_GOERLI_TOKEN_ENV = $getEnv("ALCHEMY_ARBITRUM_GOERLI_TOKEN") +let ALCHEMY_ARBITRUM_GOERLI_TOKEN_RESOLVED* = + if ALCHEMY_ARBITRUM_GOERLI_TOKEN_ENV != "": + ALCHEMY_ARBITRUM_GOERLI_TOKEN_ENV + else: + ALCHEMY_ARBITRUM_GOERLI_TOKEN + +# set via `nim c` param `-d:ALCHEMY_OPTIMISM_MAINNET_TOKEN:[token]`; should be set in CI/release builds +const ALCHEMY_OPTIMISM_MAINNET_TOKEN {.strdefine.} = "" +let ALCHEMY_OPTIMISM_MAINNET_TOKEN_ENV = $getEnv("ALCHEMY_OPTIMISM_MAINNET_TOKEN") +let ALCHEMY_OPTIMISM_MAINNET_TOKEN_RESOLVED* = + if ALCHEMY_OPTIMISM_MAINNET_TOKEN_ENV != "": + ALCHEMY_OPTIMISM_MAINNET_TOKEN_ENV + else: + ALCHEMY_OPTIMISM_MAINNET_TOKEN + +# set via `nim c` param `-d:ALCHEMY_OPTIMISM_GOERLI_TOKEN:[token]`; should be set in CI/release builds +const ALCHEMY_OPTIMISM_GOERLI_TOKEN {.strdefine.} = "" +let ALCHEMY_OPTIMISM_GOERLI_TOKEN_ENV = $getEnv("ALCHEMY_OPTIMISM_GOERLI_TOKEN") +let ALCHEMY_OPTIMISM_GOERLI_TOKEN_RESOLVED* = + if ALCHEMY_OPTIMISM_GOERLI_TOKEN_ENV != "": + ALCHEMY_OPTIMISM_GOERLI_TOKEN_ENV + else: + ALCHEMY_OPTIMISM_GOERLI_TOKEN const GANACHE_NETWORK_RPC_URL = $getEnv("GANACHE_NETWORK_RPC_URL") const OPENSEA_API_KEY {.strdefine.} = "" @@ -339,7 +383,15 @@ var NODE_CONFIG* = %* { }, "WalletConfig": { "Enabled": true, - "OpenseaAPIKey": OPENSEA_API_KEY_RESOLVED + "OpenseaAPIKey": OPENSEA_API_KEY_RESOLVED, + "AlchemyAPIKeys": %* { + "42161": ALCHEMY_ARBITRUM_MAINNET_TOKEN_RESOLVED, + "421613": ALCHEMY_ARBITRUM_GOERLI_TOKEN_RESOLVED, + "10": ALCHEMY_OPTIMISM_MAINNET_TOKEN_RESOLVED, + "420": ALCHEMY_OPTIMISM_GOERLI_TOKEN_RESOLVED + }, + "InfuraAPIKey": INFURA_TOKEN_RESOLVED, + "InfuraAPIKeySecret": INFURA_TOKEN_SECRET_RESOLVED }, "EnsConfig": { "Enabled": true diff --git a/src/app_service/service/accounts/service.nim b/src/app_service/service/accounts/service.nim index 274e725976..dfd0e98939 100644 --- a/src/app_service/service/accounts/service.nim +++ b/src/app_service/service/accounts/service.nim @@ -633,7 +633,15 @@ QtObject: }, "WalletConfig": { "Enabled": true, - "OpenseaAPIKey": OPENSEA_API_KEY_RESOLVED + "OpenseaAPIKey": OPENSEA_API_KEY_RESOLVED, + "AlchemyAPIKeys": %* { + "42161": ALCHEMY_ARBITRUM_MAINNET_TOKEN_RESOLVED, + "421613": ALCHEMY_ARBITRUM_GOERLI_TOKEN_RESOLVED, + "10": ALCHEMY_OPTIMISM_MAINNET_TOKEN_RESOLVED, + "420": ALCHEMY_OPTIMISM_GOERLI_TOKEN_RESOLVED + }, + "InfuraAPIKey": INFURA_TOKEN_RESOLVED, + "InfuraAPIKeySecret": INFURA_TOKEN_SECRET_RESOLVED }, "TorrentConfig": { "Enabled": false, diff --git a/src/app_service/service/collectible/dto.nim b/src/app_service/service/collectible/dto.nim index edea6dd7b3..5ce6aae35f 100644 --- a/src/app_service/service/collectible/dto.nim +++ b/src/app_service/service/collectible/dto.nim @@ -27,6 +27,35 @@ type CollectibleDto* = ref object address*, collectionSlug*, name*, description*, permalink*, imageThumbnailUrl*, imageUrl*, animationUrl*, animationMediaType*, backgroundColor*: string properties*, rankings*, statistics*: seq[CollectibleTrait] +type CollectibleBalance* = ref object + tokenId*: UInt256 + balance*: UInt256 + +proc `$`*(self: CollectibleBalance): string = + return fmt"""CollectibleBalance( + tokenId:{self.tokenId}, + balance:{self.balance} + """ + +type CollectibleOwner* = ref object + address*: string + balances*: seq[CollectibleBalance] + +proc `$`*(self: CollectibleOwner): string = + return fmt"""CollectibleOwner( + address:{self.address}, + balances:{self.balances} + """ + +type CollectibleOwnershipDto* = ref object + contractAddress*: string + owners*: seq[CollectibleOwner] + +proc `$`*(self: CollectibleOwnershipDto): string = + return fmt"""CollectibleOwnershipDto( + contractAddress:{self.contractAddress}, + owners:{self.owners} + """ proc newCollectibleDto*: CollectibleDto = return CollectibleDto( id: -1 @@ -122,3 +151,27 @@ proc toCollectibleDto*(jsonAsset: JsonNode): CollectibleDto = rankings: getTrait(jsonAsset, CollectibleTraitType.Rankings), statistics: getTrait(jsonAsset, CollectibleTraitType.Statistics) ) + +proc getCollectibleBalances(jsonAsset: JsonNode): seq[CollectibleBalance] = + var balanceList: seq[CollectibleBalance] = @[] + for item in jsonAsset.items: + balanceList.add(CollectibleBalance( + tokenId: stint.parse(item{"tokenId"}.getStr, Uint256), + balance: stint.parse(item{"balance"}.getStr, Uint256) + )) + return balanceList + +proc getCollectibleOwners(jsonAsset: JsonNode): seq[CollectibleOwner] = + var ownerList: seq[CollectibleOwner] = @[] + for item in jsonAsset.items: + ownerList.add(CollectibleOwner( + address: item{"ownerAddress"}.getStr, + balances: getCollectibleBalances(item{"tokenBalances"}) + )) + return ownerList + +proc toCollectibleOwnershipDto*(jsonAsset: JsonNode): CollectibleOwnershipDto = + return CollectibleOwnershipDto( + contractAddress: jsonAsset{"contractAddress"}.getStr, + owners: getCollectibleOwners(jsonAsset{"owners"}) + ) diff --git a/src/backend/collectibles.nim b/src/backend/collectibles.nim index f0b4bdd344..c1fe3c9099 100644 --- a/src/backend/collectibles.nim +++ b/src/backend/collectibles.nim @@ -35,3 +35,7 @@ rpc(getOpenseaAssetsByNFTUniqueID, "wallet"): chainId: int uniqueIds: seq[NFTUniqueID] limit: int + +rpc(getCollectibleOwnersByContractAddress, "wallet"): + chainId: int + contractAddress: string diff --git a/vendor/status-go b/vendor/status-go index 7e14da4a4a..4ef5eba6b5 160000 --- a/vendor/status-go +++ b/vendor/status-go @@ -1 +1 @@ -Subproject commit 7e14da4a4a2bceb9a6b71351dc1a47886259cb17 +Subproject commit 4ef5eba6b5041eaa80fba6ee9774f41a2a78b219