UNPKG

@ixily/activ

Version:

Alpha Capture Trade Idea Verification. Blockchain ownership proven trade ideas and strategies.

1,240 lines (1,141 loc) 31 kB
import { CONTRACT_INTERFACES, CONTRACT_TOOLS, CacheService, ContractModule, CryptoIdeasModule, IContract, IGetClosedIdeasHistoryByStrategyUniqueKeyPayload, IPaging, IStrategyChain, IStrategyIdeaChain, IStrategyWithCreator, ProvableIdeasModule, decomposeUniqueStrategyReference, getBoolean, isDecryptableIdea, LogModule as log, postQueryIdeasFilterAndPagination, querychain, uniqueKeyJoin, uniqueKeySplit, IPortfolioView, IPortfolioRebalance, IPortfolioRebalanceOpaque, IPortfolioRebalanceAsset, IPortfolioViewEntry, ISupportedBlockchainNetwork, } from '../..' import { ViewsSourceGateModule as Views } from './views-source-gate.module' import CI = CONTRACT_INTERFACES import { BigNumber } from 'bignumber.js' const listContracts = async ( network?: ISupportedBlockchainNetwork, ): Promise<string[]> => { if (network === undefined) { const contract = ContractModule.thisOrGet() network = contract.recipe.chain } return Views.listContracts() } // queries updated ITradeIdeaCreator data details from latest trade idea of the creator const getWalletInfoDetails = async ( creatorWallet?: string, contract?: IContract, ): Promise<CI.ITradeIdeaCreator> => { contract = ContractModule.thisOrGet(contract) const contractReference = uniqueKeyJoin([ contract.recipe.chain, contract.gate!.address, ]) log.dev('contractReference', contractReference) log.dev('creatorWallet', creatorWallet) if (creatorWallet === undefined) { creatorWallet = await contract.gate!.signer.getAddress() } return Views.getCreator(contractReference, creatorWallet) } const getValidatedStrategyInfoDetails = async ( uniqueStrategyKey: string, contract?: IContract, ): Promise<{ strategy: CI.ITradeIdeaStrategy creator: CI.ITradeIdeaCreator }> => { contract = ContractModule.thisOrGet(contract) const decomposed = uniqueKeySplit(uniqueStrategyKey) const chain = decomposed[0] const contractAddress = decomposed[1] const creatorAddress = decomposed[2] const strategyKey = decomposed[3] if ( contract.recipe.chain === chain && contract.gate!.address === contractAddress ) { const signerUser = await ContractModule.thisOrGetCreator( undefined, contract, ) if (signerUser === creatorAddress) { const stgChainWithCache = await ProvableIdeasModule.chain.getValidatedStrategyChainWithCache( strategyKey, creatorAddress, ) if (stgChainWithCache.cache?.cachedStrategy === undefined) { throw new Error('Strategy does not exists') } stgChainWithCache.cache.cachedStrategy.strategy.uniqueKey = uniqueKeyJoin([ chain, contractAddress, creatorAddress, strategyKey, ]) return { strategy: stgChainWithCache.cache.cachedStrategy.strategy, creator: stgChainWithCache.cache.cachedStrategy.creator, } } } return Views.getStrategyWithCreator(uniqueStrategyKey) } const listMyStrategies = async (page: number = 1, limit: number = 5) => { return listCreatorStrategies(undefined, page, limit) } const listCreatorStrategies = async ( creatorWallet?: string, page: number = 1, limit: number = 5, ) => { const contract = ContractModule.thisOrGet() const contractReference = uniqueKeyJoin([ contract.recipe.chain, contract.gate!.address, ]) log.dev('contractReference', contractReference) if (creatorWallet === undefined) { creatorWallet = await contract.gate!.signer.getAddress() } log.dev('creatorWallet', creatorWallet) return Views.listCreatorStrategies( contractReference, creatorWallet, page, limit, ) } const listPublicStrategies = async ( page: number = 1, limit: number = 5, contractUniqueKey?: string, network?: ISupportedBlockchainNetwork, ): Promise<IPaging<IStrategyWithCreator>> => { if (contractUniqueKey === undefined && network === undefined) { const contract = ContractModule.thisOrGet() network = contract.recipe.chain } return Views.listStrategiesPublic(contractUniqueKey, page, limit, network) } const listStrategiesWithAccessibleIdeas = async ( accessorWallet?: string, page: number = 1, limit: number = 5, ): Promise<IPaging<IStrategyWithCreator>> => { const contract = ContractModule.thisOrGet() const contractReference = uniqueKeyJoin([ contract.recipe.chain, contract.gate!.address, ]) if (accessorWallet === undefined) { accessorWallet = await contract.gate!.signer.getAddress() } return Views.listStrategiesWithAccessibleIdeasBy( contractReference, accessorWallet, page, limit, ) } const listStrategiesSubscribedTo = async ( subscriberWallet?: string, page: number = 1, limit: number = 5, ): Promise<IPaging<IStrategyWithCreator>> => { const contract = ContractModule.thisOrGet() const contractReference = uniqueKeyJoin([ contract.recipe.chain, contract.gate!.address, ]) if (subscriberWallet === undefined) { subscriberWallet = await contract.gate!.signer.getAddress() } return Views.listStrategiesSubscribedToBy( contractReference, subscriberWallet, page, limit, ) } const listStrategiesByCreator = async ( creatorWallet?: string, type: 'all' | 'my' | 'accesible' | 'public' = 'all', page: number = 1, limit: number = 5, network?: ISupportedBlockchainNetwork, ) => { const contract = ContractModule.thisOrGet() if (creatorWallet === undefined) { creatorWallet = await contract.gate!.signer.getAddress() } if (network === undefined) { network = contract.recipe.chain } log.dev('creatorWallet') log.dev(creatorWallet) if (type === 'my') { return listCreatorStrategies(creatorWallet, page, limit) } else if (type === 'public') { return listPublicStrategies(page, limit, network) } else if (type === 'accesible') { return listStrategiesWithAccessibleIdeas(creatorWallet, page, limit) } else { const createdList = await listCreatorStrategies( creatorWallet, page, limit, ) log.dev('createdList') log.dev(createdList) const accessibleList = await listStrategiesWithAccessibleIdeas( creatorWallet, page, limit, ) log.dev('accessibleList') log.dev(accessibleList) const publicList = await listPublicStrategies(page, limit, network) log.dev('publicList') log.dev(publicList) const data = CONTRACT_TOOLS.deterministicEvenlyMixedArray([ createdList.data, accessibleList.data, publicList.data, ]) const errors = createdList.errors === undefined && accessibleList.errors === undefined && publicList.errors === undefined ? undefined : [ ...(createdList.errors || []), ...(accessibleList.errors || []), ...(publicList.errors || []), ] const result: IPaging<IStrategyWithCreator> = { data, paging: { page, limit: limit * 3, }, total: createdList.total! + accessibleList.total! + publicList.total!, errors, } return result } } const listIdeasByStrategyUniqueKeyFromChain = async ( strategyUniqueKey: string, validatedOnly: boolean = true, page: number = 1, limit: number = 5, filterType: CONTRACT_INTERFACES.ITradeIdeaIdeaKind[] | 'bypass' = 'bypass', filterIncludeEncrypted: boolean = false, bypassPaginationAndGetAll: boolean = false, ): Promise<IPaging<CI.ITradeIdea>> => { const { contract, strategyKey, creatorAddress } = await solveContractAndKeys(strategyUniqueKey) const { cache } = await ProvableIdeasModule.chain.getValidatedStrategyChainWithCache( strategyKey, creatorAddress, contract, ) let ideas: CI.ITradeIdea[] if (validatedOnly) { ideas = await CONTRACT_TOOLS.queryChain.getValidatedIdeas( cache.cachedStrategy, ) } else { ideas = await CONTRACT_TOOLS.queryChain.getAllIdeas( cache.cachedStrategy, ) } return postQueryIdeasFilterAndPagination( ideas, page, limit, filterType, filterIncludeEncrypted, bypassPaginationAndGetAll, ) } const listValidatedIdeasByStrategyUniqueKeyFromChainOnlyLatestStagesByLatest = async ( strategyUniqueKey: string, page: number = 1, limit: number = 5, filterType: | CONTRACT_INTERFACES.ITradeIdeaIdeaKind[] | 'bypass' = 'bypass', filterIncludeEncrypted: boolean = false, bypassPaginationAndGetAll: boolean = false, ): Promise<IPaging<CI.ITradeIdea>> => { const { contract, strategyKey, creatorAddress } = await solveContractAndKeys(strategyUniqueKey) const { cache } = await ProvableIdeasModule.chain.getValidatedStrategyChainWithCache( strategyKey, creatorAddress, contract, ) const ideas: CI.ITradeIdea[] = await CONTRACT_TOOLS.queryChain.getOnlyLastStageOfEachIdea( cache.cachedStrategy, ) ideas.reverse() return postQueryIdeasFilterAndPagination( ideas, page, limit, filterType, filterIncludeEncrypted, bypassPaginationAndGetAll, ) } const getValidatedIdeasByStrategy = async ( strategyUniqueKey: string, page: number = 1, limit: number = 5, filterType: CONTRACT_INTERFACES.ITradeIdeaIdeaKind[] | 'bypass' = 'bypass', filterIncludeEncrypted: boolean = true, bypassPaginationAndGetAll: boolean = false, ) => { return listValidatedIdeasByStrategyUniqueKeyFromChainOnlyLatestStagesByLatest( strategyUniqueKey, page, limit, filterType, filterIncludeEncrypted, bypassPaginationAndGetAll, ) } const listIdeasByStrategy = async ( strategyUniqueKey: string, creator?: string, page: number = 1, limit: number = 5, filterType: CONTRACT_INTERFACES.ITradeIdeaIdeaKind[] | 'bypass' = 'bypass', filterIncludeEncrypted: boolean = true, bypassPaginationAndGetAll: boolean = false, ) => { const ideas = await Views.listStrategyIdeas( strategyUniqueKey, page, limit, filterType, filterIncludeEncrypted, bypassPaginationAndGetAll, ) if (filterIncludeEncrypted) { creator = await ContractModule.thisOrGetCreator(creator) if (creator !== undefined) { await doDecryptableIdeasOnPagingIfAccessible(ideas, creator) } } return ideas } const getIdeasCreatedBy = async ( page: number = 1, limit: number = 5, creator?: string, filterType: CONTRACT_INTERFACES.ITradeIdeaIdeaKind[] | 'bypass' = 'bypass', filterIncludeEncrypted: boolean = false, bypassPaginationAndGetAll: boolean = false, contract?: IContract, ): Promise<IPaging<CI.ITradeIdea>> => { contract = ContractModule.thisOrGet(contract) const contractCreator = await contract.gate!.signer.getAddress() creator = creator || contractCreator const contractReference = uniqueKeyJoin([ contract.recipe.chain, contract.gate!.address, ]) const ideas = await Views.listCreatorIdeas( contractReference, creator, page, limit, filterType, filterIncludeEncrypted, bypassPaginationAndGetAll, ) await doDecryptableIdeasOnPagingIfAccessible(ideas, creator) return ideas } const getIdeasOwnedBy = async ( page: number = 1, limit: number = 5, // filterType: ITradeIdeaIdeaKind[] = [], owner?: string, filterType: CONTRACT_INTERFACES.ITradeIdeaIdeaKind[] | 'bypass' = 'bypass', filterIncludeEncrypted: boolean = false, bypassPaginationAndGetAll: boolean = false, contract?: IContract, ): Promise<IPaging<CI.ITradeIdea>> => { contract = ContractModule.thisOrGet(contract) const contractCreator = await contract.gate!.signer.getAddress() owner = owner || contractCreator const contractReference = uniqueKeyJoin([ contract.recipe.chain, contract.gate!.address, ]) const ideas = await Views.listOwnedIdeas( contractReference, owner, page, limit, filterType, filterIncludeEncrypted, bypassPaginationAndGetAll, ) await doDecryptableIdeasOnPagingIfAccessible(ideas, owner) return ideas } const listIdeaNftsByStrategyUniqueKey = async ( strategyUniqueKey: string, validatedOnly: boolean = true, page: number = 1, limit: number = 5, filterType: CONTRACT_INTERFACES.ITradeIdeaIdeaKind[] | 'bypass' = 'bypass', filterIncludeEncrypted: boolean = false, bypassPaginationAndGetAll: boolean = false, ): Promise<number[]> => { const ideas = await listIdeasByStrategyUniqueKeyFromChain( strategyUniqueKey, validatedOnly, page, limit, filterType, filterIncludeEncrypted, bypassPaginationAndGetAll, ) return ideas.data.map((idea) => idea.nftId!) } const solveContract = async (strategyUniqueKey: string): Promise<IContract> => { const { chain, contractAddress } = decomposeUniqueStrategyReference(strategyUniqueKey) let contract = await ContractModule.thisOrGet() if (contract.recipe.chain !== chain) { contract = await ContractModule.changeToContract(chain, 'v4') } if (contract.gate!.address !== contractAddress) { throw new Error('Contract mismatch error.') } return contract } const solveContractAndKeys = async ( strategyUniqueKey: string, contract?: IContract, ): Promise<{ contract: IContract chain: string contractAddress: string creatorAddress: string strategyKey: string }> => { const { chain, contractAddress, creatorAddress, strategyKey } = decomposeUniqueStrategyReference(strategyUniqueKey) if (contract === undefined) { contract = await ContractModule.thisOrGet() if (contract.recipe.chain !== chain) { contract = await ContractModule.changeToContract(chain, 'v4') } if (contract.gate!.address !== contractAddress) { throw new Error('Contract mismatch error.') } } return { contract, chain, contractAddress, creatorAddress, strategyKey, } } const getClosedIdeasHistoryByStrategy = async ( payload: IGetClosedIdeasHistoryByStrategyUniqueKeyPayload, contract?: IContract, ) => { if (contract === undefined) { await solveContract(payload.strategyUniqueKey) } let nftIds = await listIdeasByStrategyUniqueKeyFromChain( payload.strategyUniqueKey, ) // console.log('nftIds:') // console.log(nftIds) nftIds.data = nftIds.data.filter((each) => { if (typeof each.idea === 'string') { return false } else { return each.idea.kind === 'close' } }) // console.log('nftIds') // console.log(nftIds) // const allTokens = [...nftIds?.map((each) => each.id)] const ideas = nftIds.data.reverse() // console.log('ideas') // console.log(ideas) const results = ideas.map((idea) => { const ticker = (idea.idea as CI.ITradeIdeaIdea).asset.ticker const chainIdeas = (idea.idea as CI.ITradeIdeaIdea).chainIdeas! const open = chainIdeas.find((each) => each.idea.kind === 'open')!.idea const close = idea.idea as CI.ITradeIdeaIdea const summary = (idea.idea as CI.ITradeIdeaIdea).result!.summary const obj = { nftId: idea.nftId!, opents: open.priceInfo!.price!.timestamp!, closets: close.priceInfo!.price!.timestamp!, ticker: ticker, direction: open.trade!.direction, percentage: Number(summary.percentage.toFixed(6)), profit: summary.profit, capital: summary.capital, stages: [] as { stage: number nftId: number type: CI.ITradeIdeaIdeaKind adjtype: 'increase' | 'decrease' | undefined adjmt: number | undefined bid: number ask: number }[], } if (getBoolean(payload.stages)) { obj.stages = chainIdeas?.map((each, index) => { const idea = each.idea const response = { stage: index, nftId: each.nftId, type: idea.kind, adjtype: undefined as 'increase' | 'decrease' | undefined, adjmt: undefined as number | undefined, bid: idea.priceInfo!.price!.ask || idea.priceInfo!.price!.globalPrice, ask: idea.priceInfo!.price!.bid || idea.priceInfo!.price!.globalPrice, } if (idea.kind === 'adjust') { response.adjtype = idea.adjustment!.kind response.adjmt = idea.adjustment!.percentage } return response }) // to attach the close idea obj.stages.push({ stage: chainIdeas.length, nftId: idea.nftId!, type: close.kind, bid: close.priceInfo!.price!.ask || close.priceInfo!.price!.globalPrice, ask: close.priceInfo!.price!.bid || close.priceInfo!.price!.globalPrice, adjtype: undefined, adjmt: undefined, }) } return obj }) const strategy = ideas[ideas.length - 1]?.strategy if (!strategy) { throw new Error('Strategy not found') } return { summary: { strategyReference: strategy.reference, strategyName: strategy.name, profit: Number( results.reduce((a, b) => a + b.capital, 0).toFixed(6), ), percentage: Number( ( results.reduce((a, b) => a + b.percentage, 0) / results.length ).toFixed(6), ), ideas: results.length || 0, }, data: results, } } const listLatestPublicIdeas = async ( page: number = 1, limit: number = 5, contract?: string, network?: ISupportedBlockchainNetwork, ): Promise<IPaging<CI.ITradeIdea>> => { /* // contract = ContractModule.thisOrGet(contract) const { data } = await CacheService.getData({ contract: 'public_one', key: `getPublicIdeas_${page}_${limit}`, init: async () => { contract = await ContractModule.thisOrGet(contract) const chain = contract.recipe.chain const address = contract.gate!.address const uniqueContractReference = uniqueKeyJoin([chain, address]) const publicNfts = return publicNfts }, }) const contractCreator = await contract.gate!.signer.getAddress() await doDecryptableIdeasOnPagingIfAccessible(data, contractCreator) return data */ if (contract === undefined && network === undefined) { const contract = ContractModule.thisOrGet() network = contract.recipe.chain } return Views.listLatestPublicIdeas(contract, page, limit, network) } const listLatestIdeas = async ( page: number = 1, limit: number = 5, contract?: IContract, ) => { contract = ContractModule.thisOrGet(contract) const { data } = await CacheService.getData({ contract: contract.gate!, key: `listLatestIdeas${page}_${limit}`, init: async () => { contract = await ContractModule.thisOrGet(contract) const chain = contract.recipe.chain const address = contract.gate!.address const uniqueContractReference = uniqueKeyJoin([chain, address]) const publicNfts = await Views.listLatestIdeas( uniqueContractReference, page, limit, ) return publicNfts }, }) const contractCreator = await contract.gate!.signer.getAddress() await doDecryptableIdeasOnPagingIfAccessible(data, contractCreator) return data } const seekAll = async <T>( seekFunction: (page: number, limit: number) => Promise<IPaging<T>>, ) => { let page = 1 const limit = 10 let total = 0 let data: T[] = [] let result: IPaging<T> = { data: [], paging: { page, limit, }, total: 0, } do { result = await seekFunction(page, limit) data = [...data, ...result.data] total += result.data.length page++ } while (result.data.length > 0 && result.data.length === limit) result.total = total return result } const listAllMyStrategies = async (): Promise<IStrategyWithCreator[]> => { return (await seekAll(listMyStrategies)).data } const getAllMyCachedStrategies = async (): Promise< { result: IStrategyChain cache: { ideas: IStrategyIdeaChain[] nullifiedIdeas: Map<number, Set<number>> cachedStrategy: CI.IStrategyState } }[] > => { const myStrategies = await listAllMyStrategies() const myCachedStrategies = await Promise.all( myStrategies.map((strategy) => ProvableIdeasModule.chain.getValidatedStrategyChainWithCache( strategy.strategy.reference, strategy.creator.walletAddress, ), ), ) return myCachedStrategies } const getCachedStrategyOpenPositions = ( cachedStrategy: CI.IStrategyState, ): CI.ITradeIdea[] => { return querychain.getAllStillNotClosedLatestIdeas(cachedStrategy) } const getAllMyCachedStrategiesWithStillOpenPositions = async (): Promise<{ allOpenPositions: CI.ITradeIdea[] strategies: { cachedStrategy: { result: IStrategyChain cache: { ideas: IStrategyIdeaChain[] nullifiedIdeas: Map<number, Set<number>> cachedStrategy: CI.IStrategyState } } strategy: CI.ITradeIdeaStrategy openPositions: CI.ITradeIdea[] }[] }> => { const myCachedStrategies = await getAllMyCachedStrategies() let allOpenPositions: CI.ITradeIdea[] = [] const strategies: { cachedStrategy: { result: IStrategyChain cache: { ideas: IStrategyIdeaChain[] nullifiedIdeas: Map<number, Set<number>> cachedStrategy: CI.IStrategyState } } strategy: CI.ITradeIdeaStrategy openPositions: CI.ITradeIdea[] }[] = [] for (const myCachedStrategy of myCachedStrategies) { const openPositions = getCachedStrategyOpenPositions( myCachedStrategy.cache.cachedStrategy, ) if (openPositions.length !== 0) { strategies.push({ cachedStrategy: myCachedStrategy, strategy: myCachedStrategy.cache.cachedStrategy.strategy, openPositions, }) } allOpenPositions = [...allOpenPositions, ...openPositions] } return { allOpenPositions, strategies, } } const getMyOpenPositions = async ( page: number = 1, limit: number = 5, ): Promise<IPaging<CI.ITradeIdea>> => { const allData = await getAllMyCachedStrategiesWithStillOpenPositions() return postQueryIdeasFilterAndPagination( [...allData.allOpenPositions].reverse(), page, limit, 'bypass', ) } const getAllMyIdeas = async (): Promise<CI.ITradeIdea[]> => { const myCachedStrategies = await getAllMyCachedStrategies() const myIdeas = myCachedStrategies.map((strategy) => { return CONTRACT_TOOLS.queryChain.getAllIdeas( strategy.cache.cachedStrategy, ) }) return (await Promise.all(myIdeas)).flat() } const getMyIdeas = async ( page: number = 1, limit: number = 5, filterType: CONTRACT_INTERFACES.ITradeIdeaIdeaKind[] | 'bypass' = 'bypass', filterIncludeEncrypted: boolean = false, bypassPaginationAndGetAll: boolean = false, ) => { const ideas = await getAllMyIdeas() ideas.reverse() return postQueryIdeasFilterAndPagination( ideas, page, limit, filterType, filterIncludeEncrypted, bypassPaginationAndGetAll, ) } const getAllMyOpenIdeas = async (): Promise<CI.ITradeIdea[]> => { const allIdeas = await getAllMyIdeas() return allIdeas.filter( (idea) => (idea.idea as CI.ITradeIdeaIdea).kind === 'open', ) } const getMyOpenIdeas = async ( page: number = 1, limit: number = 5, filterIncludeEncrypted: boolean = false, ) => { return getMyIdeas(page, limit, ['open'], filterIncludeEncrypted, false) } const getAllMyAdjustIdeas = async (): Promise<CI.ITradeIdea[]> => { const allIdeas = await getAllMyIdeas() return allIdeas.filter( (idea) => (idea.idea as CI.ITradeIdeaIdea).kind === 'adjust', ) } const getMyAdjustIdeas = async ( page: number = 1, limit: number = 5, filterIncludeEncrypted: boolean = false, ) => { return getMyIdeas(page, limit, ['adjust'], filterIncludeEncrypted, false) } const getAllMyCloseIdeas = async (): Promise<CI.ITradeIdea[]> => { const allIdeas = await getAllMyIdeas() return allIdeas.filter( (idea) => (idea.idea as CI.ITradeIdeaIdea).kind === 'close', ) } const getMyCloseIdeas = async ( page: number = 1, limit: number = 5, filterIncludeEncrypted: boolean = false, ) => { return getMyIdeas(page, limit, ['close'], filterIncludeEncrypted, false) } const decryptIdea = async ( idea: CI.ITradeIdea, inflateImages: boolean = false, ) => { await CryptoIdeasModule.restoreIdeaByNftId(idea, inflateImages) } const doDecryptableIdea = async ( idea: CI.ITradeIdea, wallet: string, inflateImages: boolean = false, ) => { if (isDecryptableIdea(idea, wallet)) { await decryptIdea(idea, inflateImages) } } const doDecryptableIdeas = async ( ideas: CI.ITradeIdea[], wallet: string, inflateImages: boolean = false, ) => { await Promise.all( ideas.map((idea) => doDecryptableIdea(idea, wallet, inflateImages)), ) } const doDecryptableIdeasOnPagingIfAccessible = async ( ideas: IPaging<CI.ITradeIdea>, wallet: string, accessible: boolean = true, ) => { if (accessible) { await doDecryptableIdeas(ideas.data, wallet, false) } } const getStrategyPortfolio = async ( uniqueStrategyKey: string, ): Promise<IPortfolioView | 'ENCRYPTED'> => { const fromViews = await Views.getStrategyPortfolio(uniqueStrategyKey) if (fromViews !== 'ENCRYPTED') { return fromViews } else { const rebal = (await listStrategyRebalances(uniqueStrategyKey, 1, 1)) .data[0] if (rebal.totalAllocation === undefined) { return 'ENCRYPTED' } const entries: IPortfolioViewEntry[] = [] for (const asset of rebal.assets) { const idea = asset.lastIdea.idea as CI.ITradeIdeaIdea let firstIdea: CI.ITradeIdeaIdea | undefined = undefined if (asset.prevIdeas) { if (asset.prevIdeas!.length > 0) { firstIdea = asset.prevIdeas![0].idea as CI.ITradeIdeaIdea } } if (firstIdea === undefined) { firstIdea = idea } const entry: IPortfolioViewEntry = { reference: asset.lastIdea.content.reference, pricing: asset.lastIdea.pricing, price: idea.priceInfo!.price!, notes: idea.notes.commentary, title: idea.title, asset: idea.asset, direction: firstIdea!.trade!.direction, allocation: asset.allocation!, } entries.push(entry) } const view: IPortfolioView = { strategyKey: rebal.strategyKey, totalEntries: rebal.totalAssets, totalAllocation: rebal.totalAllocation!, entries, } return view } } const decryptEnrichRebalance = async ( opaque: IPortfolioRebalanceOpaque, userWallet?: string, ): Promise<IPortfolioRebalance | IPortfolioRebalanceOpaque> => { opaque.assets = await Promise.all( opaque.assets.map(async (asset) => { asset.prevIdeas = [] const strategyReference = asset.lastIdea.strategy.reference const creatorWallet = asset.lastIdea.creator.walletAddress! const ideaKey = asset.lastIdea.content.ideaKey! for ( let index = 0; index < asset.lastIdea.content.ideaStageKey!; index++ ) { const ideaToSeek = await ProvableIdeasModule.general.getIdeaByKeys( strategyReference, ideaKey, index, creatorWallet, ) const nftId = await ProvableIdeasModule.general.getIdeaNftIdByKeys( creatorWallet, strategyReference, ideaKey, index, ) ideaToSeek.nftId = nftId asset.prevIdeas.push(ideaToSeek) } return asset }), ) let allPublic = true for (const asset of opaque.assets) { if (typeof asset.lastIdea.idea === 'string') { allPublic = false break } for (const prevIdea of asset.prevIdeas || []) { if (typeof prevIdea.idea === 'string') { allPublic = false break } } } if (!allPublic) { // try decrypt all userWallet = (await ContractModule.thisOrGetCreator(userWallet))! opaque.assets = await Promise.all( opaque.assets.map(async (asset) => { await doDecryptableIdea(asset.lastIdea, userWallet!) asset.prevIdeas = await Promise.all( asset.prevIdeas!.map(async (prevIdea) => { await doDecryptableIdea(prevIdea, userWallet!) return prevIdea }), ) return asset }), ) } allPublic = true for (const asset of opaque.assets) { if (typeof asset.lastIdea.idea === 'string') { allPublic = false break } for (const prevIdea of asset.prevIdeas || []) { if (typeof prevIdea.idea === 'string') { allPublic = false break } } } if (allPublic) { let totalAllocation = 0 const assets: IPortfolioRebalanceAsset[] = [] for (const asset of opaque.assets) { let allocation = 0 const ideaIdea = asset.lastIdea.idea as CI.ITradeIdeaIdea const ticker = ideaIdea.asset.ticker if (asset.prevIdeas!.length === 0) { allocation = ideaIdea.trade!.allocation! } else { for (const prevIdea of [...asset.prevIdeas!, asset.lastIdea]) { const prevIdeaIdea = prevIdea.idea as CI.ITradeIdeaIdea if (allocation === 0) { allocation = prevIdeaIdea.trade!.allocation! } else { const howMuchToIncDec = BigNumber(allocation).times( BigNumber( prevIdeaIdea.adjustment!.percentage!, ).dividedBy(100), ) if (prevIdeaIdea.adjustment!.kind === 'increase') { allocation = +BigNumber(allocation) .plus(howMuchToIncDec) .toFixed(2) } else { allocation = +BigNumber(allocation) .minus(howMuchToIncDec) .toFixed(2) } } } } totalAllocation = +BigNumber(totalAllocation) .plus(allocation) .toFixed(2) const assetEnriched: IPortfolioRebalanceAsset = { ...asset, ticker, allocation, prevIdeas: asset.prevIdeas!, } assets.push(assetEnriched) } const result: IPortfolioRebalance = { ...opaque, totalAllocation, assets, } return result } else { return opaque } } const listStrategyRebalances = async ( uniqueStrategyKey: string, page: number = 1, limit: number = 5, userWallet?: string, ): Promise<IPaging<IPortfolioRebalance | IPortfolioRebalanceOpaque>> => { const fromViews = await Views.listStrategyRebalances( uniqueStrategyKey, page, limit, ) const dataEnriched = await Promise.all( fromViews.data.map(async (each) => { return decryptEnrichRebalance(each, userWallet) }), ) const enriched = { ...fromViews, data: dataEnriched, } return enriched } const getStrategyRebalance = async ( uniqueStrategyKey: string, rebalanceReference: string, userWallet?: string, ): Promise<IPortfolioRebalance | IPortfolioRebalanceOpaque> => { const fromViews = await Views.getStrategyRebalance( uniqueStrategyKey, rebalanceReference, ) return decryptEnrichRebalance(fromViews, userWallet) } const listStrategyRebalancesInPeriod = async ( uniqueStrategyKey: string, from: number, to: number, page: number = 1, limit: number = 5, userWallet?: string, ): Promise<IPaging<IPortfolioRebalance | IPortfolioRebalanceOpaque>> => { const fromViews = await Views.listStrategyRebalancesInPeriod( uniqueStrategyKey, from, to, page, limit, ) const dataEnriched = await Promise.all( fromViews.data.map(async (each) => { return decryptEnrichRebalance(each, userWallet) }), ) const enriched = { ...fromViews, data: dataEnriched, } return enriched } export const QueryViewsModule = { seekAll, listContracts, getWalletInfoDetails, getValidatedStrategyInfoDetails, listMyStrategies, listCreatorStrategies, listPublicStrategies, listLatestIdeas, listLatestPublicIdeas, listAllMyStrategies, getIdeasCreatedBy, getIdeasOwnedBy, // getIdeaByNftId, // listStrategiesWithAccessibleIdeas, listStrategiesSubscribedTo, listStrategiesByCreator, getClosedIdeasHistoryByStrategy, listIdeasByStrategy, getValidatedIdeasByStrategy, // getAllMyCachedStrategies, getAllMyIdeas, getAllMyOpenIdeas, getAllMyAdjustIdeas, getAllMyCloseIdeas, // getMyIdeas, getMyOpenIdeas, getMyAdjustIdeas, getMyCloseIdeas, getMyOpenPositions, // getAllMyCachedStrategiesWithStillOpenPositions, // decryptIdea, doDecryptableIdea, doDecryptableIdeas, doDecryptableIdeasOnPagingIfAccessible, // listIdeasByStrategyUniqueKeyFromChain, listIdeaNftsByStrategyUniqueKey, getStrategyPortfolio, listStrategyRebalances, getStrategyRebalance, listStrategyRebalancesInPeriod, public: { getIdeaByUniqueContractAndId: Views.getIdeaByUniqueContractAndId, getIdeaByUniqueId: Views.getIdeaByUniqueId, getStrategyWithCreator: Views.getPublicStrategyWithCreator, }, }