Skip to content

Commit 92ef94d

Browse files
authored
Feat: GetTokenOwners (#1208)
chore: add getTokenOwners function to sdk
1 parent 673bd39 commit 92ef94d

16 files changed

+324
-11
lines changed

.changeset/tall-icons-remain.md

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
---
2+
'@moralisweb3/common-evm-utils': patch
3+
'@moralisweb3/evm-api': patch
4+
'moralis': patch
5+
---
6+
7+
add getTokenOwners function to SDK

packages/common/evmUtils/generator.config.json

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -120,7 +120,8 @@
120120
"getTopCryptoCurrenciesByTradingVolume",
121121
"getWalletHistory",
122122
"getNFTSalePrices",
123-
"getNFTContractSalePrices"
123+
"getNFTContractSalePrices",
124+
"getTokenOwners"
124125
]
125126
}
126127
}

packages/common/evmUtils/src/generated/client/abstractClient.ts

Lines changed: 21 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,8 @@ import { GetNFTSalePricesOperation, GetNFTSalePricesOperationRequest, GetNFTSale
66
import { GetMultipleTokenPricesOperation, GetMultipleTokenPricesOperationRequest, GetMultipleTokenPricesOperationRequestJSON } from '../operations/GetMultipleTokenPricesOperation';
77
import { EvmErc20Price, EvmErc20PriceJSON } from '../types/EvmErc20Price';
88
import { EvmGetMultipleTokenPricesDto, EvmGetMultipleTokenPricesDtoInput, EvmGetMultipleTokenPricesDtoJSON } from '../types/EvmGetMultipleTokenPricesDto';
9+
import { GetTokenOwnersOperation, GetTokenOwnersOperationRequest, GetTokenOwnersOperationRequestJSON } from '../operations/GetTokenOwnersOperation';
10+
import { EvmErc20TokenOwnerCollection, EvmErc20TokenOwnerCollectionJSON } from '../types/EvmErc20TokenOwnerCollection';
911
import { GetWalletHistoryOperation, GetWalletHistoryOperationRequest, GetWalletHistoryOperationRequestJSON } from '../operations/GetWalletHistoryOperation';
1012
import { EvmWalletHistory, EvmWalletHistoryJSON } from '../types/EvmWalletHistory';
1113
import { GetWalletTokenBalancesPriceOperation, GetWalletTokenBalancesPriceOperationRequest, GetWalletTokenBalancesPriceOperationRequestJSON } from '../operations/GetWalletTokenBalancesPriceOperation';
@@ -188,7 +190,7 @@ export abstract class AbstractClient {
188190
* @param {Date} [request.toDate] The end date from which to get the transfers (format in seconds or datestring accepted by momentjs)
189191
* * Provide the param 'to_block' or 'to_date'
190192
* * If 'to_date' and 'to_block' are provided, 'to_block' will be used. (optional)
191-
* @param {Object} [request.marketplace] Marketplace from which to get the trades (only OpenSea is supported at the moment) (optional)
193+
* @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)
192194
* @param {String} [request.cursor] The cursor returned in the previous response (used for getting the next page). (optional)
193195
* @param {Number} [request.limit] The desired page size of the result. (optional)
194196
* @returns {Object} Response for the request.
@@ -205,7 +207,7 @@ export abstract class AbstractClient {
205207
* @param {Object} request.address The address of the NFT collection
206208
* @param {Object} [request.chain] The chain to query (optional)
207209
* @param {Number} [request.days] The number of days to look back to find the lowest price
208-
* If not provided 7 days will be the default (optional)
210+
* If not provided 7 days will be the default and 365 is the maximum (optional)
209211
* @returns {Object} Response for the request.
210212
*/
211213
getNFTContractSalePrices: this.createEndpoint<
@@ -221,7 +223,7 @@ export abstract class AbstractClient {
221223
* @param {String} request.tokenId The token id of the NFT collection
222224
* @param {Object} [request.chain] The chain to query (optional)
223225
* @param {Number} [request.days] The number of days to look back to find the lowest price
224-
* If not provided 7 days will be the default (optional)
226+
* If not provided 7 days will be the default and 365 is the maximum (optional)
225227
* @returns {Object} Response for the request.
226228
*/
227229
getNFTSalePrices: this.createEndpoint<
@@ -291,6 +293,22 @@ export abstract class AbstractClient {
291293
EvmGetMultipleTokenPricesDtoInput | EvmGetMultipleTokenPricesDto,
292294
EvmGetMultipleTokenPricesDtoJSON
293295
>(GetMultipleTokenPricesOperation),
296+
/**
297+
* @description Identify the major holders of an ERC20 token and understand their ownership percentages
298+
* @param request Request with parameters.
299+
* @param {String} request.tokenAddress The address of the token contract
300+
* @param {Object} [request.chain] The chain to query (optional)
301+
* @param {Number} [request.limit] The desired page size of the result. (optional)
302+
* @param {String} [request.cursor] The cursor returned in the previous response (used for getting the next page). (optional)
303+
* @param {Object} [request.order] The order of the result, in ascending (ASC) or descending (DESC) (optional)
304+
* @returns {Object} Response for the request.
305+
*/
306+
getTokenOwners: this.createEndpoint<
307+
GetTokenOwnersOperationRequest,
308+
GetTokenOwnersOperationRequestJSON,
309+
EvmErc20TokenOwnerCollection,
310+
EvmErc20TokenOwnerCollectionJSON
311+
>(GetTokenOwnersOperation),
294312
/**
295313
* @description Get the stats for a erc20 token
296314
* @param request Request with parameters.

packages/common/evmUtils/src/generated/operations/GetNFTContractSalePricesOperation.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ export interface GetNFTContractSalePricesOperationRequest {
1313
readonly chain?: EvmChainInput | EvmChain;
1414
/**
1515
* @description The number of days to look back to find the lowest price
16-
* If not provided 7 days will be the default
16+
* If not provided 7 days will be the default and 365 is the maximum
1717
*/
1818
readonly days?: number;
1919
/**

packages/common/evmUtils/src/generated/operations/GetNFTSalePricesOperation.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ export interface GetNFTSalePricesOperationRequest {
1414
readonly chain?: EvmChainInput | EvmChain;
1515
/**
1616
* @description The number of days to look back to find the lowest price
17-
* If not provided 7 days will be the default
17+
* If not provided 7 days will be the default and 365 is the maximum
1818
*/
1919
readonly days?: number;
2020
/**

packages/common/evmUtils/src/generated/operations/GetNFTTradesOperation.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -41,7 +41,7 @@ export interface GetNFTTradesOperationRequest {
4141
*/
4242
readonly toDate?: Date;
4343
/**
44-
* @description Marketplace from which to get the trades (only OpenSea is supported at the moment)
44+
* @description Marketplace from which to get the trades. See [supported Marketplaces](https://docs.moralis.io/web3-data-api/evm/nft-marketplaces).
4545
*/
4646
readonly marketplace?: EvmGetNFTTradesMarketplaceEnumInput | EvmGetNFTTradesMarketplaceEnumValue;
4747
/**
Lines changed: 74 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,74 @@
1+
import { EvmChain, EvmChainInput, EvmChainJSON } from '../../dataTypes';
2+
import { EvmOrderList, EvmOrderListValue, EvmOrderListInput, EvmOrderListJSON } from '../types/EvmOrderList';
3+
import { EvmErc20TokenOwnerCollection, EvmErc20TokenOwnerCollectionJSON } from '../types/EvmErc20TokenOwnerCollection';
4+
5+
// request parameters:
6+
// - chain ($ref: #/components/schemas/chainList)
7+
// - token_address ($ref: #/paths/~1erc20~1{token_address}~1owners/get/parameters/1/schema)
8+
// - limit ($ref: #/paths/~1erc20~1{token_address}~1owners/get/parameters/2/schema)
9+
// - cursor ($ref: #/paths/~1erc20~1{token_address}~1owners/get/parameters/3/schema)
10+
// - order ($ref: #/components/schemas/orderList)
11+
12+
export interface GetTokenOwnersOperationRequest {
13+
/**
14+
* @description The chain to query
15+
*/
16+
readonly chain?: EvmChainInput | EvmChain;
17+
/**
18+
* @description The address of the token contract
19+
*/
20+
readonly tokenAddress: string;
21+
/**
22+
* @description The desired page size of the result.
23+
*/
24+
readonly limit?: number;
25+
/**
26+
* @description The cursor returned in the previous response (used for getting the next page).
27+
*/
28+
readonly cursor?: string;
29+
/**
30+
* @description The order of the result, in ascending (ASC) or descending (DESC)
31+
*/
32+
readonly order?: EvmOrderListInput | EvmOrderListValue;
33+
}
34+
35+
export interface GetTokenOwnersOperationRequestJSON {
36+
readonly chain?: EvmChainJSON;
37+
readonly token_address: string;
38+
readonly limit?: number;
39+
readonly cursor?: string;
40+
readonly order?: EvmOrderListJSON;
41+
}
42+
43+
export type GetTokenOwnersOperationResponse = EvmErc20TokenOwnerCollection;
44+
export type GetTokenOwnersOperationResponseJSON = EvmErc20TokenOwnerCollectionJSON;
45+
46+
export const GetTokenOwnersOperation = {
47+
operationId: "getTokenOwners",
48+
groupName: "token",
49+
httpMethod: "get",
50+
routePattern: "/erc20/{token_address}/owners",
51+
parameterNames: ["chain","token_address","limit","cursor","order"],
52+
hasResponse: true,
53+
hasBody: false,
54+
55+
parseResponse(json: EvmErc20TokenOwnerCollectionJSON): EvmErc20TokenOwnerCollection {
56+
return EvmErc20TokenOwnerCollection.fromJSON(json);
57+
},
58+
59+
serializeRequest(request: GetTokenOwnersOperationRequest): GetTokenOwnersOperationRequestJSON {
60+
const chain = request.chain ? EvmChain.create(request.chain) : undefined;
61+
const tokenAddress = request.tokenAddress;
62+
const limit = request.limit;
63+
const cursor = request.cursor;
64+
const order = request.order ? EvmOrderList.create(request.order) : undefined;
65+
return {
66+
chain: chain ? chain.toJSON() : undefined,
67+
token_address: tokenAddress,
68+
limit: limit,
69+
cursor: cursor,
70+
order: order ? order : undefined,
71+
};
72+
},
73+
74+
}

packages/common/evmUtils/src/generated/operations/index.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ export * from './GetNFTTradesOperation';
22
export * from './GetNFTContractSalePricesOperation';
33
export * from './GetNFTSalePricesOperation';
44
export * from './GetMultipleTokenPricesOperation';
5+
export * from './GetTokenOwnersOperation';
56
export * from './GetWalletHistoryOperation';
67
export * from './GetWalletTokenBalancesPriceOperation';
78
export * from './GetWalletNetWorthOperation';

packages/common/evmUtils/src/generated/operations/operations.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ import { GetNFTTradesOperation } from './GetNFTTradesOperation';
22
import { GetNFTContractSalePricesOperation } from './GetNFTContractSalePricesOperation';
33
import { GetNFTSalePricesOperation } from './GetNFTSalePricesOperation';
44
import { GetMultipleTokenPricesOperation } from './GetMultipleTokenPricesOperation';
5+
import { GetTokenOwnersOperation } from './GetTokenOwnersOperation';
56
import { GetWalletHistoryOperation } from './GetWalletHistoryOperation';
67
import { GetWalletTokenBalancesPriceOperation } from './GetWalletTokenBalancesPriceOperation';
78
import { GetWalletNetWorthOperation } from './GetWalletNetWorthOperation';
@@ -28,6 +29,7 @@ export const operations = [
2829
GetNFTContractSalePricesOperation,
2930
GetNFTSalePricesOperation,
3031
GetMultipleTokenPricesOperation,
32+
GetTokenOwnersOperation,
3133
GetWalletHistoryOperation,
3234
GetWalletTokenBalancesPriceOperation,
3335
GetWalletNetWorthOperation,

packages/common/evmUtils/src/generated/types/EvmErc20Price.ts

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,8 @@ import { EvmNativeErc20Price, EvmNativeErc20PriceInput, EvmNativeErc20PriceJSON
1717
// - toBlock ($ref: #/components/schemas/erc20Price/properties/toBlock)
1818
// - possibleSpam ($ref: #/components/schemas/erc20Price/properties/possibleSpam)
1919
// - verifiedContract ($ref: #/components/schemas/erc20Price/properties/verifiedContract)
20+
// - pairAddress ($ref: #/components/schemas/erc20Price/properties/pairAddress)
21+
// - pairTotalLiquidityUsd ($ref: #/components/schemas/erc20Price/properties/pairTotalLiquidityUsd)
2022

2123
export interface EvmErc20PriceJSON {
2224
readonly tokenName?: string;
@@ -33,6 +35,8 @@ export interface EvmErc20PriceJSON {
3335
readonly toBlock?: string;
3436
readonly possibleSpam: boolean;
3537
readonly verifiedContract: boolean;
38+
readonly pairAddress?: string;
39+
readonly pairTotalLiquidityUsd?: string;
3640
}
3741

3842
export interface EvmErc20PriceInput {
@@ -50,6 +54,8 @@ export interface EvmErc20PriceInput {
5054
readonly toBlock?: string;
5155
readonly possibleSpam: boolean;
5256
readonly verifiedContract: boolean;
57+
readonly pairAddress?: string;
58+
readonly pairTotalLiquidityUsd?: string;
5359
}
5460

5561
export class EvmErc20Price {
@@ -76,6 +82,8 @@ export class EvmErc20Price {
7682
toBlock: json.toBlock,
7783
possibleSpam: json.possibleSpam,
7884
verifiedContract: json.verifiedContract,
85+
pairAddress: json.pairAddress,
86+
pairTotalLiquidityUsd: json.pairTotalLiquidityUsd,
7987
};
8088
return EvmErc20Price.create(input);
8189
}
@@ -133,6 +141,14 @@ export class EvmErc20Price {
133141
* @description Indicates if the contract is verified
134142
*/
135143
public readonly verifiedContract: boolean;
144+
/**
145+
* @description The address of the pair
146+
*/
147+
public readonly pairAddress?: string;
148+
/**
149+
* @description The total liquidity in USD of the pair
150+
*/
151+
public readonly pairTotalLiquidityUsd?: string;
136152

137153
private constructor(input: EvmErc20PriceInput) {
138154
this.tokenName = input.tokenName;
@@ -149,6 +165,8 @@ export class EvmErc20Price {
149165
this.toBlock = input.toBlock;
150166
this.possibleSpam = input.possibleSpam;
151167
this.verifiedContract = input.verifiedContract;
168+
this.pairAddress = input.pairAddress;
169+
this.pairTotalLiquidityUsd = input.pairTotalLiquidityUsd;
152170
}
153171

154172
public toJSON(): EvmErc20PriceJSON {
@@ -167,6 +185,8 @@ export class EvmErc20Price {
167185
toBlock: this.toBlock,
168186
possibleSpam: this.possibleSpam,
169187
verifiedContract: this.verifiedContract,
188+
pairAddress: this.pairAddress,
189+
pairTotalLiquidityUsd: this.pairTotalLiquidityUsd,
170190
}
171191
}
172192
}
Lines changed: 103 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,103 @@
1+
// $ref: #/components/schemas/erc20TokenOwner
2+
// type: erc20TokenOwner
3+
// properties:
4+
// - owner_address ($ref: #/components/schemas/erc20TokenOwner/properties/owner_address)
5+
// - owner_address_label ($ref: #/components/schemas/erc20TokenOwner/properties/owner_address_label)
6+
// - balance ($ref: #/components/schemas/erc20TokenOwner/properties/balance)
7+
// - balance_formatted ($ref: #/components/schemas/erc20TokenOwner/properties/balance_formatted)
8+
// - usd_value ($ref: #/components/schemas/erc20TokenOwner/properties/usd_value)
9+
// - is_contract ($ref: #/components/schemas/erc20TokenOwner/properties/is_contract)
10+
// - percentage_relative_to_total_supply ($ref: #/components/schemas/erc20TokenOwner/properties/percentage_relative_to_total_supply)
11+
12+
export interface EvmErc20TokenOwnerJSON {
13+
readonly owner_address: string;
14+
readonly owner_address_label: string;
15+
readonly balance: string;
16+
readonly balance_formatted: string;
17+
readonly usd_value: string;
18+
readonly is_contract: boolean;
19+
readonly percentage_relative_to_total_supply: number;
20+
}
21+
22+
export interface EvmErc20TokenOwnerInput {
23+
readonly ownerAddress: string;
24+
readonly ownerAddressLabel: string;
25+
readonly balance: string;
26+
readonly balanceFormatted: string;
27+
readonly usdValue: string;
28+
readonly isContract: boolean;
29+
readonly percentageRelativeToTotalSupply: number;
30+
}
31+
32+
export class EvmErc20TokenOwner {
33+
public static create(input: EvmErc20TokenOwnerInput | EvmErc20TokenOwner): EvmErc20TokenOwner {
34+
if (input instanceof EvmErc20TokenOwner) {
35+
return input;
36+
}
37+
return new EvmErc20TokenOwner(input);
38+
}
39+
40+
public static fromJSON(json: EvmErc20TokenOwnerJSON): EvmErc20TokenOwner {
41+
const input: EvmErc20TokenOwnerInput = {
42+
ownerAddress: json.owner_address,
43+
ownerAddressLabel: json.owner_address_label,
44+
balance: json.balance,
45+
balanceFormatted: json.balance_formatted,
46+
usdValue: json.usd_value,
47+
isContract: json.is_contract,
48+
percentageRelativeToTotalSupply: json.percentage_relative_to_total_supply,
49+
};
50+
return EvmErc20TokenOwner.create(input);
51+
}
52+
53+
/**
54+
* @description The address of the erc20 token owner
55+
*/
56+
public readonly ownerAddress: string;
57+
/**
58+
* @description The label of the owner_address
59+
*/
60+
public readonly ownerAddressLabel: string;
61+
/**
62+
* @description The amount holding of the ERC20 token
63+
*/
64+
public readonly balance: string;
65+
/**
66+
* @description The amount holding of the ERC20 token in decimaal
67+
*/
68+
public readonly balanceFormatted: string;
69+
/**
70+
* @description The USD value of the balance
71+
*/
72+
public readonly usdValue: string;
73+
/**
74+
* @description Indicates if the token address is for a contract or not
75+
*/
76+
public readonly isContract: boolean;
77+
/**
78+
* @description The percentage of total supply held by the owner
79+
*/
80+
public readonly percentageRelativeToTotalSupply: number;
81+
82+
private constructor(input: EvmErc20TokenOwnerInput) {
83+
this.ownerAddress = input.ownerAddress;
84+
this.ownerAddressLabel = input.ownerAddressLabel;
85+
this.balance = input.balance;
86+
this.balanceFormatted = input.balanceFormatted;
87+
this.usdValue = input.usdValue;
88+
this.isContract = input.isContract;
89+
this.percentageRelativeToTotalSupply = input.percentageRelativeToTotalSupply;
90+
}
91+
92+
public toJSON(): EvmErc20TokenOwnerJSON {
93+
return {
94+
owner_address: this.ownerAddress,
95+
owner_address_label: this.ownerAddressLabel,
96+
balance: this.balance,
97+
balance_formatted: this.balanceFormatted,
98+
usd_value: this.usdValue,
99+
is_contract: this.isContract,
100+
percentage_relative_to_total_supply: this.percentageRelativeToTotalSupply,
101+
}
102+
}
103+
}

0 commit comments

Comments
 (0)