mirror of
https://github.com/status-im/status-lib.git
synced 2025-01-11 13:04:26 +00:00
feat(@desktop/wallet2): Enable multi chain for collectible (#5)
This commit is contained in:
parent
c716a89544
commit
ea02568fbc
@ -129,12 +129,12 @@ proc checkRecentHistory*(addresses: seq[string]): string =
|
||||
let payload = %* [addresses]
|
||||
result = callPrivateRPC("wallet_checkRecentHistory", payload)
|
||||
|
||||
proc getOpenseaCollections*(address: string): string =
|
||||
let payload = %* [address]
|
||||
proc getOpenseaCollections*(chainId: int, address: string): string =
|
||||
let payload = %* [chainId, address]
|
||||
result = callPrivateRPC("wallet_getOpenseaCollectionsByOwner", payload)
|
||||
|
||||
proc getOpenseaAssets*(address: string, collectionSlug: string, limit: int): string =
|
||||
let payload = %* [address, collectionSlug, limit]
|
||||
proc getOpenseaAssets*(chainId: int, address: string, collectionSlug: string, limit: int): string =
|
||||
let payload = %* [chainId, address, collectionSlug, limit]
|
||||
result = callPrivateRPC("wallet_getOpenseaAssetsByOwnerAndCollection", payload)
|
||||
|
||||
proc fetchCryptoServices*(success: var bool): string =
|
||||
|
@ -422,12 +422,6 @@ proc watchTransaction*(transactionHash: string): string =
|
||||
proc hex2Token*(self: WalletModel, input: string, decimals: int): string =
|
||||
result = status_wallet.hex2Token(input, decimals)
|
||||
|
||||
proc getOpenseaCollections*(address: string): string =
|
||||
result = status_wallet.getOpenseaCollections(address)
|
||||
|
||||
proc getOpenseaAssets*(address: string, collectionSlug: string, limit: int): string =
|
||||
result = status_wallet.getOpenseaAssets(address, collectionSlug, limit)
|
||||
|
||||
proc getGasPrice*(self: WalletModel): string =
|
||||
let response = status_wallet.getGasPrice().parseJson
|
||||
if response.hasKey("result"):
|
||||
@ -436,7 +430,6 @@ proc getGasPrice*(self: WalletModel): string =
|
||||
error "Error obtaining max priority fee per gas", error=response
|
||||
raise newException(StatusGoException, "Error obtaining gas price")
|
||||
|
||||
|
||||
proc setLatestBaseFee*(self: WalletModel, latestBaseFee: string) =
|
||||
self.latestBaseFee = latestBaseFee
|
||||
|
||||
|
@ -10,14 +10,6 @@ type CollectibleList* = ref object
|
||||
type Collectible* = ref object
|
||||
name*, image*, id*, collectibleType*, description*, externalUrl*: string
|
||||
|
||||
type OpenseaCollection* = ref object
|
||||
name*, slug*, imageUrl*: string
|
||||
ownedAssetCount*: int
|
||||
|
||||
type OpenseaAsset* = ref object
|
||||
id*: int
|
||||
name*, description*, permalink*, imageThumbnailUrl*, imageUrl*, address*: string
|
||||
|
||||
type CurrencyArgs* = ref object of Args
|
||||
currency*: string
|
||||
|
||||
@ -34,29 +26,4 @@ type WalletAccount* = ref object
|
||||
transactions*: tuple[hasMore: bool, data: seq[Transaction]]
|
||||
|
||||
type AccountArgs* = ref object of Args
|
||||
account*: WalletAccount
|
||||
|
||||
proc `$`*(self: OpenseaCollection): string =
|
||||
return fmt"OpenseaCollection(name:{self.name}, slug:{self.slug}, owned asset count:{self.ownedAssetCount})"
|
||||
|
||||
proc `$`*(self: OpenseaAsset): string =
|
||||
return fmt"OpenseaAsset(id:{self.id}, name:{self.name}, address:{self.address}, imageUrl: {self.imageUrl}, imageThumbnailUrl: {self.imageThumbnailUrl})"
|
||||
|
||||
proc toOpenseaCollection*(jsonCollection: JsonNode): OpenseaCollection =
|
||||
return OpenseaCollection(
|
||||
name: jsonCollection{"name"}.getStr,
|
||||
slug: jsonCollection{"slug"}.getStr,
|
||||
imageUrl: jsonCollection{"image_url"}.getStr,
|
||||
ownedAssetCount: jsonCollection{"owned_asset_count"}.getInt
|
||||
)
|
||||
|
||||
proc toOpenseaAsset*(jsonAsset: JsonNode): OpenseaAsset =
|
||||
return OpenseaAsset(
|
||||
id: jsonAsset{"id"}.getInt,
|
||||
name: jsonAsset{"name"}.getStr,
|
||||
description: jsonAsset{"description"}.getStr,
|
||||
permalink: jsonAsset{"permalink"}.getStr,
|
||||
imageThumbnailUrl: jsonAsset{"image_thumbnail_url"}.getStr,
|
||||
imageUrl: jsonAsset{"image_url"}.getStr,
|
||||
address: jsonAsset{"asset_contract"}{"address"}.getStr
|
||||
)
|
||||
account*: WalletAccount
|
@ -7,14 +7,14 @@ import statusgo_backend/wallet as status_wallet
|
||||
import statusgo_backend/network as status_network
|
||||
import statusgo_backend/settings as status_settings
|
||||
import eth/[contracts]
|
||||
import wallet2/[balance_manager, collectibles, network]
|
||||
import wallet2/[balance_manager, network]
|
||||
import wallet2/account as wallet_account
|
||||
import ./types/[account, transaction, network_type, setting, gas_prediction, rpc_response]
|
||||
import ../eventemitter
|
||||
from web3/ethtypes import Address
|
||||
from web3/conversions import `$`
|
||||
|
||||
export wallet_account, collectibles
|
||||
export wallet_account
|
||||
|
||||
logScope:
|
||||
topics = "status-wallet2"
|
||||
@ -205,10 +205,12 @@ proc deleteAccount*(self: StatusWalletController, address: string): string =
|
||||
self.accounts = self.accounts.filter(acc => acc.address.toLowerAscii != address.toLowerAscii)
|
||||
|
||||
proc getOpenseaCollections*(address: string): string =
|
||||
result = status_wallet.getOpenseaCollections(address)
|
||||
let networkId = status_settings.getCurrentNetworkDetails().config.networkId
|
||||
result = status_wallet.getOpenseaCollections(networkId, address)
|
||||
|
||||
proc getOpenseaAssets*(address: string, collectionSlug: string, limit: int): string =
|
||||
result = status_wallet.getOpenseaAssets(address, collectionSlug, limit)
|
||||
let networkId = status_settings.getCurrentNetworkDetails().config.networkId
|
||||
result = status_wallet.getOpenseaAssets(networkId, address, collectionSlug, limit)
|
||||
|
||||
proc onAsyncFetchCryptoServices*(self: StatusWalletController, response: string) =
|
||||
let responseArray = response.parseJson
|
||||
|
@ -3,13 +3,6 @@ import Tables, options, json, strformat, strutils
|
||||
from ../../eventemitter import Args
|
||||
import ../types/[transaction]
|
||||
|
||||
type CollectibleList* = ref object
|
||||
collectibleType*, collectiblesJSON*, error*: string
|
||||
loading*: int
|
||||
|
||||
type Collectible* = ref object
|
||||
name*, image*, id*, collectibleType*, description*, externalUrl*: string
|
||||
|
||||
type OpenseaCollectionTrait* = ref object
|
||||
min*, max*: float
|
||||
|
||||
@ -38,7 +31,6 @@ type WalletAccount* = ref object
|
||||
realFiatBalance*: Option[float]
|
||||
assetList*: seq[Asset]
|
||||
wallet*, chat*: bool
|
||||
collectiblesLists*: seq[CollectibleList]
|
||||
transactions*: tuple[hasMore: bool, data: seq[Transaction]]
|
||||
|
||||
type TraitType* {.pure.} = enum
|
||||
|
@ -1,260 +0,0 @@
|
||||
import # std libs
|
||||
atomics, strformat, httpclient, json, chronicles, sequtils, strutils, tables,
|
||||
sugar, net
|
||||
|
||||
import # vendor libs
|
||||
stint
|
||||
|
||||
import # status-desktop libs
|
||||
../statusgo_backend/core as status, ../eth/contracts as contracts,
|
||||
../stickers as status_stickers,
|
||||
../utils as status_utils,
|
||||
web3/[conversions, ethtypes], ../utils, account
|
||||
|
||||
const CRYPTOKITTY* = "cryptokitty"
|
||||
const KUDO* = "kudo"
|
||||
const ETHERMON* = "ethermon"
|
||||
const STICKER* = "stickers"
|
||||
|
||||
const COLLECTIBLE_TYPES* = [CRYPTOKITTY, KUDO, ETHERMON, STICKER]
|
||||
|
||||
const MAX_TOKENS = 200
|
||||
|
||||
proc getTokenUri(contract: Erc721Contract, tokenId: Stuint[256]): string =
|
||||
try:
|
||||
let
|
||||
tokenUri = TokenUri(tokenId: tokenId)
|
||||
payload = %* [{
|
||||
"to": $contract.address,
|
||||
"data": contract.methods["tokenURI"].encodeAbi(tokenUri)
|
||||
}, "latest"]
|
||||
response = callPrivateRPC("eth_call", payload)
|
||||
var postfixedResult: string = parseJson($response)["result"].str
|
||||
postfixedResult.removeSuffix('0')
|
||||
postfixedResult.removePrefix("0x")
|
||||
postfixedResult = parseHexStr(postfixedResult)
|
||||
let index = postfixedResult.find("http")
|
||||
if (index < -1):
|
||||
return ""
|
||||
result = postfixedResult[index .. postfixedResult.high]
|
||||
except Exception as e:
|
||||
error "Error getting the token URI", mes = e.msg
|
||||
result = ""
|
||||
|
||||
proc tokenOfOwnerByIndex(contract: Erc721Contract, address: Address, index: Stuint[256]): int =
|
||||
let
|
||||
tokenOfOwnerByIndex = TokenOfOwnerByIndex(address: address, index: index)
|
||||
payload = %* [{
|
||||
"to": $contract.address,
|
||||
"data": contract.methods["tokenOfOwnerByIndex"].encodeAbi(tokenOfOwnerByIndex)
|
||||
}, "latest"]
|
||||
response = callPrivateRPC("eth_call", payload)
|
||||
jsonResponse = parseJson($response)
|
||||
if (not jsonResponse.hasKey("result")):
|
||||
return -1
|
||||
let res = jsonResponse["result"].getStr
|
||||
if (res == "0x"):
|
||||
return -1
|
||||
result = fromHex[int](res)
|
||||
|
||||
proc balanceOf(contract: Erc721Contract, address: Address): int =
|
||||
let
|
||||
balanceOf = BalanceOf(address: address)
|
||||
payload = %* [{
|
||||
"to": $contract.address,
|
||||
"data": contract.methods["balanceOf"].encodeAbi(balanceOf)
|
||||
}, "latest"]
|
||||
response = callPrivateRPC("eth_call", payload)
|
||||
jsonResponse = parseJson($response)
|
||||
if (not jsonResponse.hasKey("result")):
|
||||
return 0
|
||||
let res = jsonResponse["result"].getStr
|
||||
if (res == "0x"):
|
||||
return 0
|
||||
result = fromHex[int](res)
|
||||
|
||||
proc tokensOfOwnerByIndex(contract: Erc721Contract, address: Address): seq[int] =
|
||||
var index = 0
|
||||
var token: int
|
||||
var maxIndex: int = balanceOf(contract, address)
|
||||
result = @[]
|
||||
while index < maxIndex and result.len <= MAX_TOKENS:
|
||||
token = tokenOfOwnerByIndex(contract, address, index.u256)
|
||||
result.add(token)
|
||||
index = index + 1
|
||||
|
||||
return result
|
||||
|
||||
proc getCryptoKittiesBatch*(address: Address, offset: int = 0): seq[Collectible] =
|
||||
var cryptokitties: seq[Collectible]
|
||||
cryptokitties = @[]
|
||||
# TODO handle testnet -- does this API exist in testnet??
|
||||
let url: string = fmt"https://api.cryptokitties.co/kitties?limit=20&offset={$offset}&owner_wallet_address={$address}&parents=false"
|
||||
let secureSSLContext = newContext()
|
||||
let client = newHttpClient(sslContext = secureSSLContext)
|
||||
client.headers = newHttpHeaders({ "Content-Type": "application/json" })
|
||||
|
||||
let response = client.request(url)
|
||||
let responseBody = parseJson(response.body)
|
||||
let kitties = responseBody["kitties"]
|
||||
for kitty in kitties:
|
||||
try:
|
||||
var id = kitty["id"]
|
||||
var name = kitty["name"]
|
||||
var finalId = ""
|
||||
var finalName = ""
|
||||
if id.kind != JNull:
|
||||
finalId = $id
|
||||
if name.kind != JNull:
|
||||
finalName = $name
|
||||
cryptokitties.add(Collectible(id: finalId,
|
||||
name: finalName,
|
||||
image: kitty["image_url_png"].str,
|
||||
collectibleType: CRYPTOKITTY,
|
||||
description: "",
|
||||
externalUrl: ""))
|
||||
except Exception as e2:
|
||||
error "Error with this individual cat", msg = e2.msg, cat = kitty
|
||||
|
||||
let limit = responseBody["limit"].getInt
|
||||
let total = responseBody["total"].getInt
|
||||
let currentCount = limit * (offset + 1)
|
||||
if (currentCount < total and currentCount < MAX_TOKENS):
|
||||
# Call the API again with offset + 1
|
||||
let nextBatch = getCryptoKittiesBatch(address, offset + 1)
|
||||
return concat(cryptokitties, nextBatch)
|
||||
return cryptokitties
|
||||
|
||||
proc getCryptoKitties*(address: Address): string =
|
||||
try:
|
||||
let cryptokitties = getCryptoKittiesBatch(address, 0)
|
||||
|
||||
return $(%*cryptokitties)
|
||||
except Exception as e:
|
||||
error "Error getting Cryptokitties", msg = e.msg
|
||||
return e.msg
|
||||
|
||||
proc getCryptoKitties*(address: string): string =
|
||||
let eth_address = parseAddress(address)
|
||||
result = getCryptoKitties(eth_address)
|
||||
|
||||
proc getEthermons*(address: Address): string =
|
||||
try:
|
||||
var ethermons: seq[Collectible]
|
||||
ethermons = @[]
|
||||
let contract = getErc721Contract("ethermon")
|
||||
if contract == nil: return $(%*ethermons)
|
||||
|
||||
let tokens = tokensOfOwnerByIndex(contract, address)
|
||||
|
||||
if (tokens.len == 0):
|
||||
return $(%*ethermons)
|
||||
|
||||
let tokensJoined = strutils.join(tokens, ",")
|
||||
let url = fmt"https://www.ethermon.io/api/monster/get_data?monster_ids={tokensJoined}"
|
||||
let secureSSLContext = newContext()
|
||||
let client = newHttpClient(sslContext = secureSSLContext)
|
||||
client.headers = newHttpHeaders({ "Content-Type": "application/json" })
|
||||
|
||||
let response = client.request(url)
|
||||
let monsters = parseJson(response.body)["data"]
|
||||
var i = 0
|
||||
for monsterKey in json.keys(monsters):
|
||||
let monster = monsters[monsterKey]
|
||||
ethermons.add(Collectible(id: $tokens[i],
|
||||
name: monster["class_name"].str,
|
||||
image: monster["image"].str,
|
||||
collectibleType: ETHERMON,
|
||||
description: "",
|
||||
externalUrl: ""))
|
||||
i = i + 1
|
||||
|
||||
return $(%*ethermons)
|
||||
except Exception as e:
|
||||
error "Error getting Ethermons", msg = e.msg
|
||||
result = e.msg
|
||||
|
||||
proc getEthermons*(address: string): string =
|
||||
let eth_address = parseAddress(address)
|
||||
result = getEthermons(eth_address)
|
||||
|
||||
proc getKudos*(address: Address): string =
|
||||
try:
|
||||
var kudos: seq[Collectible]
|
||||
kudos = @[]
|
||||
let contract = getErc721Contract("kudos")
|
||||
if contract == nil: return $(%*kudos)
|
||||
|
||||
let tokens = tokensOfOwnerByIndex(contract, address)
|
||||
|
||||
if (tokens.len == 0):
|
||||
return $(%*kudos)
|
||||
|
||||
for token in tokens:
|
||||
let url = getTokenUri(contract, token.u256)
|
||||
|
||||
if (url == ""):
|
||||
return $(%*kudos)
|
||||
|
||||
let secureSSLContext = newContext()
|
||||
let client = newHttpClient(sslContext = secureSSLContext)
|
||||
client.headers = newHttpHeaders({ "Content-Type": "application/json" })
|
||||
|
||||
let response = client.request(url)
|
||||
let kudo = parseJson(response.body)
|
||||
|
||||
kudos.add(Collectible(id: $token,
|
||||
name: kudo["name"].str,
|
||||
image: kudo["image"].str,
|
||||
collectibleType: KUDO,
|
||||
description: kudo["description"].str,
|
||||
externalUrl: kudo["external_url"].str))
|
||||
|
||||
return $(%*kudos)
|
||||
except Exception as e:
|
||||
error "Error getting Kudos", msg = e.msg
|
||||
result = e.msg
|
||||
|
||||
proc getKudos*(address: string): string =
|
||||
let eth_address = parseAddress(address)
|
||||
result = getKudos(eth_address)
|
||||
|
||||
proc getStickers*(address: Address, running: var Atomic[bool]): string =
|
||||
try:
|
||||
var stickers: seq[Collectible]
|
||||
stickers = @[]
|
||||
let contract = getErc721Contract("sticker-pack")
|
||||
if contract == nil: return
|
||||
|
||||
let tokensIds = tokensOfOwnerByIndex(contract, address)
|
||||
|
||||
if (tokensIds.len == 0):
|
||||
return $(%*stickers)
|
||||
|
||||
let purchasedStickerPacks = tokensIds.map(tokenId => status_stickers.getPackIdFromTokenId(tokenId.u256))
|
||||
|
||||
if (purchasedStickerPacks.len == 0):
|
||||
return $(%*stickers)
|
||||
# TODO find a way to keep those in memory so as not to reload it each time
|
||||
let availableStickerPacks = getAvailableStickerPacks(running)
|
||||
|
||||
var index = 0
|
||||
for stickerId in purchasedStickerPacks:
|
||||
let sticker = availableStickerPacks[stickerId]
|
||||
stickers.add(Collectible(id: $tokensIds[index],
|
||||
name: sticker.name,
|
||||
image: fmt"https://ipfs.infura.io/ipfs/{status_utils.decodeContentHash(sticker.preview)}",
|
||||
collectibleType: STICKER,
|
||||
description: sticker.author,
|
||||
externalUrl: "")
|
||||
)
|
||||
index = index + 1
|
||||
|
||||
return $(%*stickers)
|
||||
except Exception as e:
|
||||
error "Error getting Stickers", msg = e.msg
|
||||
result = e.msg
|
||||
|
||||
proc getStickers*(address: string, running: var Atomic[bool]): string =
|
||||
let eth_address = parseAddress(address)
|
||||
result = getStickers(eth_address, running)
|
Loading…
x
Reference in New Issue
Block a user