@ixily/activ
Version:
Alpha Capture Trade Idea Verification. Blockchain ownership proven trade ideas and strategies.
1,240 lines (1,141 loc) • 31 kB
text/typescript
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,
},
}