Skip to content

Commit

Permalink
Merge pull request #608 from radixdlt/sdk-update
Browse files Browse the repository at this point in the history
Sdk update
  • Loading branch information
PawelPawelec-RDX authored Jan 12, 2024
2 parents edd28a5 + d52433f commit 4cadcfb
Show file tree
Hide file tree
Showing 2 changed files with 133 additions and 64 deletions.
24 changes: 0 additions & 24 deletions sdk/typescript/lib/helpers/exhaust-pagination.ts
Original file line number Diff line number Diff line change
@@ -1,29 +1,5 @@
import { LedgerState } from '../generated'

/**
* Exhausts a paginated API resource and returns all the results.
*/
export const exhaustPagination = async <T>(
queryFunction: (
cursor?: string
) => Promise<{ items: T[]; next_cursor?: string | null }>,
start?: string
): Promise<T[]> => {
let next_cursor: string | null | undefined = start
const aggregatedEntities: T[] = []

do {
const queryFunctionResponse: {
next_cursor?: string | null
items: T[]
} = await queryFunction(next_cursor)
aggregatedEntities.push(...queryFunctionResponse.items)
next_cursor = queryFunctionResponse.next_cursor
} while (next_cursor)

return aggregatedEntities
}

/**
* Exhausts a paginated API resource and returns all the results.
*/
Expand Down
173 changes: 133 additions & 40 deletions sdk/typescript/lib/subapis/state.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
import { chunk } from '../helpers/chunk'
import {
exhaustPagination,
exhaustPaginationWithLedgerState,
} from '../helpers/exhaust-pagination'
import {
Expand All @@ -17,6 +16,7 @@ import {
StateEntityDetailsResponseItem,
StateEntityFungiblesPageResponse,
StateEntityMetadataPageResponse,
StateEntityNonFungiblesPageResponse,
StateNonFungibleDetailsResponseItem,
StateNonFungibleIdsResponse,
StateNonFungibleLocationResponseItem,
Expand Down Expand Up @@ -62,14 +62,14 @@ export class State {
constructor(
public innerClient: StateApi,
public configuration: RuntimeConfiguration
) {}
) { }

/**
* Get detailed information about entities together with vault aggregated fungible and non-fungible resources.
* Returns an array or single item depending on input value. If array is passed, it will be split into chunks of 20 addresses
* which will be requested separately and returned only if all requests are successful.
*
* Calling this function will exhaust list of all fungible resources for each entity.
* Calling this function will exhaust list of all resources for each entity.
* If any of the requests fail, the whole operation will fail.
*
* When requesting details for `internal_vault` entity, `non_fungible_resources` and `fungible_resources` will be defaulted to objects with empty arrays
Expand Down Expand Up @@ -135,21 +135,20 @@ export class State {

return isArray
? Promise.all(
(items as StateEntityDetailsVaultResponseItem[]).map((item) =>
this.queryAllFungibles(
item,
ledgerState || {
state_version: ledger_state.state_version,
}
)
(items as StateEntityDetailsVaultResponseItem[]).map((item) =>
this.queryAllResources(
item,
ledgerState || {
state_version: ledger_state.state_version,
}
)
)
: this.queryAllFungibles(
items[0] as StateEntityDetailsVaultResponseItem,
ledgerState || {
state_version: ledger_state.state_version,
}
)
))
: this.queryAllResources(
items[0] as StateEntityDetailsVaultResponseItem,
ledgerState || {
state_version: ledger_state.state_version,
}
)
}

/**
Expand Down Expand Up @@ -208,10 +207,10 @@ export class State {
address: string,
startCursor?: string
): Promise<EntityMetadataItem[]> {
return exhaustPagination(
return exhaustPaginationWithLedgerState(
this.getEntityMetadata.bind(this, address),
startCursor
)
).then((res) => res.aggregatedEntities)
}

/**
Expand All @@ -232,11 +231,20 @@ export class State {
* Get list of all validators. This will iterate over returned cursors and aggregate all responses.
*/
async getAllValidators(start?: string): Promise<ValidatorCollectionItem[]> {
return exhaustPagination(this.getValidators.bind(this), start)
return exhaustPaginationWithLedgerState((cursor?: string) => {
const v = this.getValidatorsWithLedgerState(cursor)
return v.then((res) => ({
items: res.validators.items,
ledger_state: res.ledger_state,
next_cursor: res.validators.next_cursor
}))
}, start).then(
(res) => res.aggregatedEntities
)
}

/**
* Get paged list of validators
* Get paged list of validators with ledger state
* @param cursor
*/
async getValidatorsWithLedgerState(cursor?: string) {
Expand All @@ -256,6 +264,7 @@ export class State {
this.getValidatorsWithLedgerState(cursor).then((res) => ({
items: res.validators.items,
ledger_state: res.ledger_state,
next_cursor: res.validators.next_cursor
})),
start
)
Expand Down Expand Up @@ -383,6 +392,57 @@ export class State {
>
}

private async getEntityNonFungiblesPageVaultAggregated(
entity: string,
nextCursor?: string | undefined,
ledgerState?: LedgerStateSelector
): Promise<
ReplaceProperty<
StateEntityNonFungiblesPageResponse,
'items',
NonFungibleResourcesCollectionItemVaultAggregated[]
>
> {
return this.innerClient.entityNonFungiblesPage({
stateEntityNonFungiblesPageRequest: {
address: entity,
cursor: nextCursor,
aggregation_level: 'Vault',
at_ledger_state: ledgerState,
},
}) as Promise<
ReplaceProperty<
StateEntityNonFungiblesPageResponse,
'items',
NonFungibleResourcesCollectionItemVaultAggregated[]
>
>
}

private ensureResourcesProperties(
response: StateEntityDetailsResponse
): ReplaceProperty<
StateEntityDetailsResponse,
'items',
StateEntityDetailsVaultResponseItem[]
> {
return {
...response,
items: response.items.map((item) => ({
...item,
fungible_resources: item.fungible_resources || {
total_count: 0,
items: [],
},
non_fungible_resources: item.non_fungible_resources || {
total_count: 0,
items: [],
},
})) as StateEntityDetailsVaultResponseItem[],
}
}


private async queryAllFungibles(
stateEntityDetails: StateEntityDetailsVaultResponseItem,
ledgerState?: LedgerStateSelector
Expand Down Expand Up @@ -412,26 +472,59 @@ export class State {
})
}

private ensureResourcesProperties(
response: StateEntityDetailsResponse
): ReplaceProperty<
StateEntityDetailsResponse,
'items',
StateEntityDetailsVaultResponseItem[]
> {
return {
...response,
items: response.items.map((item) => ({
...item,
fungible_resources: item.fungible_resources || {
total_count: 0,
items: [],

private async queryAllNonFungibles(
stateEntityDetails: StateEntityDetailsVaultResponseItem,
ledgerState?: LedgerStateSelector
): Promise<StateEntityDetailsVaultResponseItem> {
const nextCursor = stateEntityDetails.non_fungible_resources.next_cursor

if (!nextCursor) return Promise.resolve(stateEntityDetails)

const allNonFungibles = await exhaustPaginationWithLedgerState(
(cursor) =>
this.getEntityNonFungiblesPageVaultAggregated(
stateEntityDetails.address,
cursor,
ledgerState
),
nextCursor
)

return Promise.resolve({
...stateEntityDetails,
non_fungible_resources: {
items: [
...stateEntityDetails.non_fungible_resources.items,
...allNonFungibles.aggregatedEntities,
],
},
})
}

private async queryAllResources(
stateEntityDetails: StateEntityDetailsVaultResponseItem,
ledgerState?: LedgerStateSelector
): Promise<StateEntityDetailsVaultResponseItem> {
const itemsWithAllFungibles = this.queryAllFungibles(stateEntityDetails, ledgerState)
const itemsWithAllNonFungibles = this.queryAllNonFungibles(stateEntityDetails, ledgerState)

return Promise.all([itemsWithAllFungibles, itemsWithAllNonFungibles]).then((results) => {
return {
...stateEntityDetails,
fungible_resources: {
...stateEntityDetails.fungible_resources,
items: [
...results[0].fungible_resources.items,
],
},
non_fungible_resources: item.non_fungible_resources || {
total_count: 0,
items: [],
non_fungible_resources: {
...stateEntityDetails.non_fungible_resources,
items: [
...results[1].non_fungible_resources.items,
],
},
})) as StateEntityDetailsVaultResponseItem[],
}
}
})
}
}

0 comments on commit 4cadcfb

Please sign in to comment.