Skip to content

Commit

Permalink
Feat: GetTokenOwners (#1208)
Browse files Browse the repository at this point in the history
chore: add getTokenOwners function to sdk
  • Loading branch information
Kayconfig authored Jun 10, 2024
1 parent 673bd39 commit 92ef94d
Show file tree
Hide file tree
Showing 16 changed files with 324 additions and 11 deletions.
7 changes: 7 additions & 0 deletions .changeset/tall-icons-remain.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
---
'@moralisweb3/common-evm-utils': patch
'@moralisweb3/evm-api': patch
'moralis': patch
---

add getTokenOwners function to SDK
3 changes: 2 additions & 1 deletion packages/common/evmUtils/generator.config.json
Original file line number Diff line number Diff line change
Expand Up @@ -120,7 +120,8 @@
"getTopCryptoCurrenciesByTradingVolume",
"getWalletHistory",
"getNFTSalePrices",
"getNFTContractSalePrices"
"getNFTContractSalePrices",
"getTokenOwners"
]
}
}
Expand Down
24 changes: 21 additions & 3 deletions packages/common/evmUtils/src/generated/client/abstractClient.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,8 @@ import { GetNFTSalePricesOperation, GetNFTSalePricesOperationRequest, GetNFTSale
import { GetMultipleTokenPricesOperation, GetMultipleTokenPricesOperationRequest, GetMultipleTokenPricesOperationRequestJSON } from '../operations/GetMultipleTokenPricesOperation';
import { EvmErc20Price, EvmErc20PriceJSON } from '../types/EvmErc20Price';
import { EvmGetMultipleTokenPricesDto, EvmGetMultipleTokenPricesDtoInput, EvmGetMultipleTokenPricesDtoJSON } from '../types/EvmGetMultipleTokenPricesDto';
import { GetTokenOwnersOperation, GetTokenOwnersOperationRequest, GetTokenOwnersOperationRequestJSON } from '../operations/GetTokenOwnersOperation';
import { EvmErc20TokenOwnerCollection, EvmErc20TokenOwnerCollectionJSON } from '../types/EvmErc20TokenOwnerCollection';
import { GetWalletHistoryOperation, GetWalletHistoryOperationRequest, GetWalletHistoryOperationRequestJSON } from '../operations/GetWalletHistoryOperation';
import { EvmWalletHistory, EvmWalletHistoryJSON } from '../types/EvmWalletHistory';
import { GetWalletTokenBalancesPriceOperation, GetWalletTokenBalancesPriceOperationRequest, GetWalletTokenBalancesPriceOperationRequestJSON } from '../operations/GetWalletTokenBalancesPriceOperation';
Expand Down Expand Up @@ -188,7 +190,7 @@ export abstract class AbstractClient {
* @param {Date} [request.toDate] The end date from which to get the transfers (format in seconds or datestring accepted by momentjs)
* * Provide the param 'to_block' or 'to_date'
* * If 'to_date' and 'to_block' are provided, 'to_block' will be used. (optional)
* @param {Object} [request.marketplace] Marketplace from which to get the trades (only OpenSea is supported at the moment) (optional)
* @param {Object} [request.marketplace] Marketplace from which to get the trades. See [supported Marketplaces](https://docs.moralis.io/web3-data-api/evm/nft-marketplaces). (optional)
* @param {String} [request.cursor] The cursor returned in the previous response (used for getting the next page). (optional)
* @param {Number} [request.limit] The desired page size of the result. (optional)
* @returns {Object} Response for the request.
Expand All @@ -205,7 +207,7 @@ export abstract class AbstractClient {
* @param {Object} request.address The address of the NFT collection
* @param {Object} [request.chain] The chain to query (optional)
* @param {Number} [request.days] The number of days to look back to find the lowest price
* If not provided 7 days will be the default (optional)
* If not provided 7 days will be the default and 365 is the maximum (optional)
* @returns {Object} Response for the request.
*/
getNFTContractSalePrices: this.createEndpoint<
Expand All @@ -221,7 +223,7 @@ export abstract class AbstractClient {
* @param {String} request.tokenId The token id of the NFT collection
* @param {Object} [request.chain] The chain to query (optional)
* @param {Number} [request.days] The number of days to look back to find the lowest price
* If not provided 7 days will be the default (optional)
* If not provided 7 days will be the default and 365 is the maximum (optional)
* @returns {Object} Response for the request.
*/
getNFTSalePrices: this.createEndpoint<
Expand Down Expand Up @@ -291,6 +293,22 @@ export abstract class AbstractClient {
EvmGetMultipleTokenPricesDtoInput | EvmGetMultipleTokenPricesDto,
EvmGetMultipleTokenPricesDtoJSON
>(GetMultipleTokenPricesOperation),
/**
* @description Identify the major holders of an ERC20 token and understand their ownership percentages
* @param request Request with parameters.
* @param {String} request.tokenAddress The address of the token contract
* @param {Object} [request.chain] The chain to query (optional)
* @param {Number} [request.limit] The desired page size of the result. (optional)
* @param {String} [request.cursor] The cursor returned in the previous response (used for getting the next page). (optional)
* @param {Object} [request.order] The order of the result, in ascending (ASC) or descending (DESC) (optional)
* @returns {Object} Response for the request.
*/
getTokenOwners: this.createEndpoint<
GetTokenOwnersOperationRequest,
GetTokenOwnersOperationRequestJSON,
EvmErc20TokenOwnerCollection,
EvmErc20TokenOwnerCollectionJSON
>(GetTokenOwnersOperation),
/**
* @description Get the stats for a erc20 token
* @param request Request with parameters.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ export interface GetNFTContractSalePricesOperationRequest {
readonly chain?: EvmChainInput | EvmChain;
/**
* @description The number of days to look back to find the lowest price
* If not provided 7 days will be the default
* If not provided 7 days will be the default and 365 is the maximum
*/
readonly days?: number;
/**
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ export interface GetNFTSalePricesOperationRequest {
readonly chain?: EvmChainInput | EvmChain;
/**
* @description The number of days to look back to find the lowest price
* If not provided 7 days will be the default
* If not provided 7 days will be the default and 365 is the maximum
*/
readonly days?: number;
/**
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,7 @@ export interface GetNFTTradesOperationRequest {
*/
readonly toDate?: Date;
/**
* @description Marketplace from which to get the trades (only OpenSea is supported at the moment)
* @description Marketplace from which to get the trades. See [supported Marketplaces](https://docs.moralis.io/web3-data-api/evm/nft-marketplaces).
*/
readonly marketplace?: EvmGetNFTTradesMarketplaceEnumInput | EvmGetNFTTradesMarketplaceEnumValue;
/**
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,74 @@
import { EvmChain, EvmChainInput, EvmChainJSON } from '../../dataTypes';
import { EvmOrderList, EvmOrderListValue, EvmOrderListInput, EvmOrderListJSON } from '../types/EvmOrderList';
import { EvmErc20TokenOwnerCollection, EvmErc20TokenOwnerCollectionJSON } from '../types/EvmErc20TokenOwnerCollection';

// request parameters:
// - chain ($ref: #/components/schemas/chainList)
// - token_address ($ref: #/paths/~1erc20~1{token_address}~1owners/get/parameters/1/schema)
// - limit ($ref: #/paths/~1erc20~1{token_address}~1owners/get/parameters/2/schema)
// - cursor ($ref: #/paths/~1erc20~1{token_address}~1owners/get/parameters/3/schema)
// - order ($ref: #/components/schemas/orderList)

export interface GetTokenOwnersOperationRequest {
/**
* @description The chain to query
*/
readonly chain?: EvmChainInput | EvmChain;
/**
* @description The address of the token contract
*/
readonly tokenAddress: string;
/**
* @description The desired page size of the result.
*/
readonly limit?: number;
/**
* @description The cursor returned in the previous response (used for getting the next page).
*/
readonly cursor?: string;
/**
* @description The order of the result, in ascending (ASC) or descending (DESC)
*/
readonly order?: EvmOrderListInput | EvmOrderListValue;
}

export interface GetTokenOwnersOperationRequestJSON {
readonly chain?: EvmChainJSON;
readonly token_address: string;
readonly limit?: number;
readonly cursor?: string;
readonly order?: EvmOrderListJSON;
}

export type GetTokenOwnersOperationResponse = EvmErc20TokenOwnerCollection;
export type GetTokenOwnersOperationResponseJSON = EvmErc20TokenOwnerCollectionJSON;

export const GetTokenOwnersOperation = {
operationId: "getTokenOwners",
groupName: "token",
httpMethod: "get",
routePattern: "/erc20/{token_address}/owners",
parameterNames: ["chain","token_address","limit","cursor","order"],
hasResponse: true,
hasBody: false,

parseResponse(json: EvmErc20TokenOwnerCollectionJSON): EvmErc20TokenOwnerCollection {
return EvmErc20TokenOwnerCollection.fromJSON(json);
},

serializeRequest(request: GetTokenOwnersOperationRequest): GetTokenOwnersOperationRequestJSON {
const chain = request.chain ? EvmChain.create(request.chain) : undefined;
const tokenAddress = request.tokenAddress;
const limit = request.limit;
const cursor = request.cursor;
const order = request.order ? EvmOrderList.create(request.order) : undefined;
return {
chain: chain ? chain.toJSON() : undefined,
token_address: tokenAddress,
limit: limit,
cursor: cursor,
order: order ? order : undefined,
};
},

}
1 change: 1 addition & 0 deletions packages/common/evmUtils/src/generated/operations/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ export * from './GetNFTTradesOperation';
export * from './GetNFTContractSalePricesOperation';
export * from './GetNFTSalePricesOperation';
export * from './GetMultipleTokenPricesOperation';
export * from './GetTokenOwnersOperation';
export * from './GetWalletHistoryOperation';
export * from './GetWalletTokenBalancesPriceOperation';
export * from './GetWalletNetWorthOperation';
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import { GetNFTTradesOperation } from './GetNFTTradesOperation';
import { GetNFTContractSalePricesOperation } from './GetNFTContractSalePricesOperation';
import { GetNFTSalePricesOperation } from './GetNFTSalePricesOperation';
import { GetMultipleTokenPricesOperation } from './GetMultipleTokenPricesOperation';
import { GetTokenOwnersOperation } from './GetTokenOwnersOperation';
import { GetWalletHistoryOperation } from './GetWalletHistoryOperation';
import { GetWalletTokenBalancesPriceOperation } from './GetWalletTokenBalancesPriceOperation';
import { GetWalletNetWorthOperation } from './GetWalletNetWorthOperation';
Expand All @@ -28,6 +29,7 @@ export const operations = [
GetNFTContractSalePricesOperation,
GetNFTSalePricesOperation,
GetMultipleTokenPricesOperation,
GetTokenOwnersOperation,
GetWalletHistoryOperation,
GetWalletTokenBalancesPriceOperation,
GetWalletNetWorthOperation,
Expand Down
20 changes: 20 additions & 0 deletions packages/common/evmUtils/src/generated/types/EvmErc20Price.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,8 @@ import { EvmNativeErc20Price, EvmNativeErc20PriceInput, EvmNativeErc20PriceJSON
// - toBlock ($ref: #/components/schemas/erc20Price/properties/toBlock)
// - possibleSpam ($ref: #/components/schemas/erc20Price/properties/possibleSpam)
// - verifiedContract ($ref: #/components/schemas/erc20Price/properties/verifiedContract)
// - pairAddress ($ref: #/components/schemas/erc20Price/properties/pairAddress)
// - pairTotalLiquidityUsd ($ref: #/components/schemas/erc20Price/properties/pairTotalLiquidityUsd)

export interface EvmErc20PriceJSON {
readonly tokenName?: string;
Expand All @@ -33,6 +35,8 @@ export interface EvmErc20PriceJSON {
readonly toBlock?: string;
readonly possibleSpam: boolean;
readonly verifiedContract: boolean;
readonly pairAddress?: string;
readonly pairTotalLiquidityUsd?: string;
}

export interface EvmErc20PriceInput {
Expand All @@ -50,6 +54,8 @@ export interface EvmErc20PriceInput {
readonly toBlock?: string;
readonly possibleSpam: boolean;
readonly verifiedContract: boolean;
readonly pairAddress?: string;
readonly pairTotalLiquidityUsd?: string;
}

export class EvmErc20Price {
Expand All @@ -76,6 +82,8 @@ export class EvmErc20Price {
toBlock: json.toBlock,
possibleSpam: json.possibleSpam,
verifiedContract: json.verifiedContract,
pairAddress: json.pairAddress,
pairTotalLiquidityUsd: json.pairTotalLiquidityUsd,
};
return EvmErc20Price.create(input);
}
Expand Down Expand Up @@ -133,6 +141,14 @@ export class EvmErc20Price {
* @description Indicates if the contract is verified
*/
public readonly verifiedContract: boolean;
/**
* @description The address of the pair
*/
public readonly pairAddress?: string;
/**
* @description The total liquidity in USD of the pair
*/
public readonly pairTotalLiquidityUsd?: string;

private constructor(input: EvmErc20PriceInput) {
this.tokenName = input.tokenName;
Expand All @@ -149,6 +165,8 @@ export class EvmErc20Price {
this.toBlock = input.toBlock;
this.possibleSpam = input.possibleSpam;
this.verifiedContract = input.verifiedContract;
this.pairAddress = input.pairAddress;
this.pairTotalLiquidityUsd = input.pairTotalLiquidityUsd;
}

public toJSON(): EvmErc20PriceJSON {
Expand All @@ -167,6 +185,8 @@ export class EvmErc20Price {
toBlock: this.toBlock,
possibleSpam: this.possibleSpam,
verifiedContract: this.verifiedContract,
pairAddress: this.pairAddress,
pairTotalLiquidityUsd: this.pairTotalLiquidityUsd,
}
}
}
103 changes: 103 additions & 0 deletions packages/common/evmUtils/src/generated/types/EvmErc20TokenOwner.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,103 @@
// $ref: #/components/schemas/erc20TokenOwner
// type: erc20TokenOwner
// properties:
// - owner_address ($ref: #/components/schemas/erc20TokenOwner/properties/owner_address)
// - owner_address_label ($ref: #/components/schemas/erc20TokenOwner/properties/owner_address_label)
// - balance ($ref: #/components/schemas/erc20TokenOwner/properties/balance)
// - balance_formatted ($ref: #/components/schemas/erc20TokenOwner/properties/balance_formatted)
// - usd_value ($ref: #/components/schemas/erc20TokenOwner/properties/usd_value)
// - is_contract ($ref: #/components/schemas/erc20TokenOwner/properties/is_contract)
// - percentage_relative_to_total_supply ($ref: #/components/schemas/erc20TokenOwner/properties/percentage_relative_to_total_supply)

export interface EvmErc20TokenOwnerJSON {
readonly owner_address: string;
readonly owner_address_label: string;
readonly balance: string;
readonly balance_formatted: string;
readonly usd_value: string;
readonly is_contract: boolean;
readonly percentage_relative_to_total_supply: number;
}

export interface EvmErc20TokenOwnerInput {
readonly ownerAddress: string;
readonly ownerAddressLabel: string;
readonly balance: string;
readonly balanceFormatted: string;
readonly usdValue: string;
readonly isContract: boolean;
readonly percentageRelativeToTotalSupply: number;
}

export class EvmErc20TokenOwner {
public static create(input: EvmErc20TokenOwnerInput | EvmErc20TokenOwner): EvmErc20TokenOwner {
if (input instanceof EvmErc20TokenOwner) {
return input;
}
return new EvmErc20TokenOwner(input);
}

public static fromJSON(json: EvmErc20TokenOwnerJSON): EvmErc20TokenOwner {
const input: EvmErc20TokenOwnerInput = {
ownerAddress: json.owner_address,
ownerAddressLabel: json.owner_address_label,
balance: json.balance,
balanceFormatted: json.balance_formatted,
usdValue: json.usd_value,
isContract: json.is_contract,
percentageRelativeToTotalSupply: json.percentage_relative_to_total_supply,
};
return EvmErc20TokenOwner.create(input);
}

/**
* @description The address of the erc20 token owner
*/
public readonly ownerAddress: string;
/**
* @description The label of the owner_address
*/
public readonly ownerAddressLabel: string;
/**
* @description The amount holding of the ERC20 token
*/
public readonly balance: string;
/**
* @description The amount holding of the ERC20 token in decimaal
*/
public readonly balanceFormatted: string;
/**
* @description The USD value of the balance
*/
public readonly usdValue: string;
/**
* @description Indicates if the token address is for a contract or not
*/
public readonly isContract: boolean;
/**
* @description The percentage of total supply held by the owner
*/
public readonly percentageRelativeToTotalSupply: number;

private constructor(input: EvmErc20TokenOwnerInput) {
this.ownerAddress = input.ownerAddress;
this.ownerAddressLabel = input.ownerAddressLabel;
this.balance = input.balance;
this.balanceFormatted = input.balanceFormatted;
this.usdValue = input.usdValue;
this.isContract = input.isContract;
this.percentageRelativeToTotalSupply = input.percentageRelativeToTotalSupply;
}

public toJSON(): EvmErc20TokenOwnerJSON {
return {
owner_address: this.ownerAddress,
owner_address_label: this.ownerAddressLabel,
balance: this.balance,
balance_formatted: this.balanceFormatted,
usd_value: this.usdValue,
is_contract: this.isContract,
percentage_relative_to_total_supply: this.percentageRelativeToTotalSupply,
}
}
}
Loading

1 comment on commit 92ef94d

@github-actions
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Test coverage

Title Lines Statements Branches Functions
api-utils Coverage: 20%
20.6% (61/296) 20.48% (17/83) 19.04% (12/63)
auth Coverage: 89%
92.45% (98/106) 83.33% (20/24) 86.66% (26/30)
evm-api Coverage: 81%
82.56% (90/109) 66.66% (6/9) 74.66% (56/75)
common-aptos-utils Coverage: 4%
4.56% (151/3306) 4.49% (25/556) 5.53% (45/813)
common-evm-utils Coverage: 57%
58.14% (2013/3462) 18.41% (172/934) 39.19% (466/1189)
sol-api Coverage: 97%
97.56% (40/41) 66.66% (6/9) 93.75% (15/16)
common-sol-utils Coverage: 64%
65.42% (229/350) 41.86% (18/43) 50.89% (57/112)
common-streams-utils Coverage: 90%
90.73% (1204/1327) 73.63% (363/493) 82.07% (444/541)
streams Coverage: 91%
90.54% (603/666) 72.34% (68/94) 90.97% (131/144)

Please sign in to comment.