Skip to content

Commit

Permalink
feat: getWalletTokenBalancesPrice, getPairPrice, resolveAddressToDoma… (
Browse files Browse the repository at this point in the history
#1179)

feat: getWalletTokenBalancesPrice, getPairPrice, resolveAddressToDomain, resolveENSAddress, getWalletNetWorth.
  • Loading branch information
b4rtaz authored Feb 23, 2024
1 parent cbbc82c commit 31d73a7
Show file tree
Hide file tree
Showing 25 changed files with 1,234 additions and 32 deletions.
7 changes: 7 additions & 0 deletions .changeset/selfish-nails-exist.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
---
'@moralisweb3/common-evm-utils': minor
'@moralisweb3/evm-api': minor
'moralis': minor
---

Updated the types of the `toBlock` and `toDate` properties in the `GetNFTTradesOperationRequest` interface to number and Date, respectively.
7 changes: 7 additions & 0 deletions .changeset/tasty-planes-admire.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
---

Added `getWalletTokenBalancesPrice`, `getPairPrice`, `resolveAddressToDomain`, `resolveENSAddress`, `getWalletNetWorth` methods to the EVM API.
Original file line number Diff line number Diff line change
Expand Up @@ -2,19 +2,26 @@ import { TypeConversionCodeGenerator } from './TypeConversionCodeGenerator';

describe('TypeConversionCodeGenerator', () => {
it('does not change value if types are the same', () => {
expect(TypeConversionCodeGenerator.generate('string', 'string', 'value')).toEqual('value');
expect(TypeConversionCodeGenerator.generate('number', 'number', 'this.value')).toEqual('this.value');
expect(TypeConversionCodeGenerator.generate(true, 'string', 'string', 'value')).toEqual('value');
expect(TypeConversionCodeGenerator.generate(true, 'number', 'number', 'this.value')).toEqual('this.value');
expect(TypeConversionCodeGenerator.generate(false, 'number', 'number', 'this.value')).toEqual('this.value');
});

it('converts string to Date', () => {
expect(TypeConversionCodeGenerator.generate('string', 'Date', 'value')).toEqual('new Date(value)');
expect(TypeConversionCodeGenerator.generate(true, 'string', 'Date', 'value')).toEqual('new Date(value)');
});

it('converts string to number', () => {
expect(TypeConversionCodeGenerator.generate('string', 'number', 'value')).toEqual('Number(value)');
expect(TypeConversionCodeGenerator.generate(true, 'string', 'number', 'value')).toEqual('Number(value)');
expect(TypeConversionCodeGenerator.generate(false, 'string', 'number', 'this.value')).toEqual(
'this.value !== undefined ? Number(this.value) : undefined',
);
});

it('converts Date to string', () => {
expect(TypeConversionCodeGenerator.generate('Date', 'string', 'value')).toEqual('value.toISOString()');
expect(TypeConversionCodeGenerator.generate(true, 'Date', 'string', 'value')).toEqual('value.toISOString()');
expect(TypeConversionCodeGenerator.generate(false, 'Date', 'string', 'value')).toEqual(
'value !== undefined ? value.toISOString() : undefined',
);
});
});
Original file line number Diff line number Diff line change
@@ -1,34 +1,47 @@
export class TypeConversionCodeGenerator {
public static generate(sourceNativeType: string, targetNativeType: string, valueCode: string): string {
public static generate(
isRequired: boolean,
sourceNativeType: string,
targetNativeType: string,
valueCode: string,
): string {
if (sourceNativeType === targetNativeType) {
return valueCode;
}

let code: string | undefined;
switch (targetNativeType) {
case 'number':
switch (sourceNativeType) {
case 'string':
return `Number(${valueCode})`;
code = `Number(${valueCode})`;
break;
}
break;

case 'string':
switch (sourceNativeType) {
case 'number':
return `String(${valueCode})`;
code = `String(${valueCode})`;
break;
case 'Date':
return `${valueCode}.toISOString()`;
code = `${valueCode}.toISOString()`;
break;
}
break;

case 'Date':
switch (sourceNativeType) {
case 'string':
return `new Date(${valueCode})`;
code = `new Date(${valueCode})`;
break;
}
break;
}

if (code) {
return isRequired ? code : `${valueCode} !== undefined ? ${code} : undefined`;
}
throw new Error(`Conversion from ${sourceNativeType} to ${targetNativeType} is not supported`);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ export class ValueMappingCodeGenerator {

if (resolvedType.nativeType) {
return TypeConversionCodeGenerator.generate(
isRequired,
resolvedType.nativeType.jsonType,
resolvedType.nativeType.valueType,
valueCode,
Expand Down Expand Up @@ -46,6 +47,7 @@ export class ValueMappingCodeGenerator {

if (resolvedType.nativeType) {
return TypeConversionCodeGenerator.generate(
isRequired,
resolvedType.nativeType.valueType,
resolvedType.nativeType.jsonType,
valueCode,
Expand Down
34 changes: 30 additions & 4 deletions packages/common/evmUtils/generator.config.json
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,11 @@
"types": [],
"refs": [
{
"refs": ["#/components/schemas/trade/properties/price"],
"refs": [
"#/components/schemas/trade/properties/price",
"#/components/schemas/erc20TokenBalanceWithPrice/properties/balance",
"#/components/schemas/chainNetWorth/properties/native_balance"
],
"className": "EvmNative",
"import": "../../dataTypes"
},
Expand Down Expand Up @@ -42,7 +46,7 @@
"import": "@moralisweb3/common-core"
},
{
"names": ["transaction_index", "token_decimals", "log_index"],
"names": ["transaction_index", "token_decimals", "log_index", "decimals"],
"nativeType": "number"
}
],
Expand All @@ -53,9 +57,26 @@
"import": "../../dataTypes"
},
{
"names": ["address", "contract_addresses", "wallet_addresses", "exclude_wallets", "exclude_contracts"],
"names": [
"address",
"contract_addresses",
"wallet_addresses",
"exclude_wallets",
"exclude_contracts",
"token0_address",
"token1_address",
"token_addresses"
],
"className": "EvmAddress",
"import": "../../dataTypes"
},
{
"names": ["to_block"],
"nativeType": "number"
},
{
"names": "to_date",
"nativeType": "Date"
}
]
},
Expand All @@ -81,7 +102,12 @@
"getNFTCollectionStats",
"getBlockStats",
"getTokenStats",
"getMultipleTokenPrices"
"getMultipleTokenPrices",
"getWalletNetWorth",
"getWalletTokenBalancesPrice",
"getPairPrice",
"resolveAddressToDomain",
"resolveENSAddress"
]
}
}
Expand Down
83 changes: 81 additions & 2 deletions packages/common/evmUtils/src/generated/client/abstractClient.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,10 +3,18 @@ import { EvmTradeCollection, EvmTradeCollectionJSON } from '../types/EvmTradeCol
import { GetMultipleTokenPricesOperation, GetMultipleTokenPricesOperationRequest, GetMultipleTokenPricesOperationRequestJSON } from '../operations/GetMultipleTokenPricesOperation';
import { EvmErc20Price, EvmErc20PriceJSON } from '../types/EvmErc20Price';
import { EvmGetMultipleTokenPricesDto, EvmGetMultipleTokenPricesDtoInput, EvmGetMultipleTokenPricesDtoJSON } from '../types/EvmGetMultipleTokenPricesDto';
import { GetWalletTokenBalancesPriceOperation, GetWalletTokenBalancesPriceOperationRequest, GetWalletTokenBalancesPriceOperationRequestJSON } from '../operations/GetWalletTokenBalancesPriceOperation';
import { EvmErc20TokenBalanceWithPriceResult, EvmErc20TokenBalanceWithPriceResultJSON } from '../types/EvmErc20TokenBalanceWithPriceResult';
import { GetWalletNetWorthOperation, GetWalletNetWorthOperationRequest, GetWalletNetWorthOperationRequestJSON } from '../operations/GetWalletNetWorthOperation';
import { EvmNetWorthResult, EvmNetWorthResultJSON } from '../types/EvmNetWorthResult';
import { Web3ApiVersionOperation, Web3ApiVersionOperationRequest, Web3ApiVersionOperationRequestJSON } from '../operations/Web3ApiVersionOperation';
import { EvmWeb3version, EvmWeb3versionJSON } from '../types/EvmWeb3version';
import { EndpointWeightsOperation, EndpointWeightsOperationRequest, EndpointWeightsOperationRequestJSON } from '../operations/EndpointWeightsOperation';
import { EvmEndpointWeights, EvmEndpointWeightsJSON } from '../types/EvmEndpointWeights';
import { ResolveAddressToDomainOperation, ResolveAddressToDomainOperationRequest, ResolveAddressToDomainOperationRequestJSON } from '../operations/ResolveAddressToDomainOperation';
import { EvmUnstoppableDomain, EvmUnstoppableDomainJSON } from '../types/EvmUnstoppableDomain';
import { GetPairPriceOperation, GetPairPriceOperationRequest, GetPairPriceOperationRequestJSON } from '../operations/GetPairPriceOperation';
import { EvmGetPairPrice, EvmGetPairPriceJSON } from '../types/EvmGetPairPrice';
import { GetTopERC20TokensByMarketCapOperation, GetTopERC20TokensByMarketCapOperationRequest, GetTopERC20TokensByMarketCapOperationRequestJSON } from '../operations/GetTopERC20TokensByMarketCapOperation';
import { EvmMarketDataERC20TokenItem, EvmMarketDataERC20TokenItemJSON } from '../types/EvmMarketDataERC20TokenItem';
import { GetTopERC20TokensByPriceMoversOperation, GetTopERC20TokensByPriceMoversOperationRequest, GetTopERC20TokensByPriceMoversOperationRequestJSON } from '../operations/GetTopERC20TokensByPriceMoversOperation';
Expand Down Expand Up @@ -67,6 +75,27 @@ export abstract class AbstractClient {
EvmBlockTokenStatJSON
>(GetBlockStatsOperation),
};
public readonly defi = {
/**
* @description Get the price of a given token pair. Only Uniswap V2 based exchanges supported at the moment.
* @param request Request with parameters.
* @param {Object} request.token0Address The token0 address
* @param {Object} request.token1Address The token1 address
* @param {Object} [request.chain] The chain to query (optional)
* @param {Number} [request.toBlock] The block number to get the reserves from (optional)
* @param {Date} [request.toDate] Get the price up to this date (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 {String} [request.exchange] The factory name or address of the token exchange (optional)
* @returns {Object} Response for the request.
*/
getPairPrice: this.createEndpoint<
GetPairPriceOperationRequest,
GetPairPriceOperationRequestJSON,
EvmGetPairPrice,
EvmGetPairPriceJSON
>(GetPairPriceOperation),
};
public readonly marketData = {
/**
* @description Get the top ERC20 tokens by market cap
Expand Down Expand Up @@ -122,11 +151,11 @@ export abstract class AbstractClient {
* @param {Number} [request.fromBlock] The minimum block number from which to get the transfers
* * Provide the param 'from_block' or 'from_date'
* * If 'from_date' and 'from_block' are provided, 'from_block' will be used. (optional)
* @param {String} [request.toBlock] The block number to get the trades from (optional)
* @param {Number} [request.toBlock] The block number to get the trades from (optional)
* @param {String} [request.fromDate] The start date from which to get the transfers (format in seconds or datestring accepted by momentjs)
* * Provide the param 'from_block' or 'from_date'
* * If 'from_date' and 'from_block' are provided, 'from_block' will be used. (optional)
* @param {String} [request.toDate] The end date from which to get the transfers (format in seconds or datestring accepted by momentjs)
* @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)
Expand Down Expand Up @@ -168,6 +197,21 @@ export abstract class AbstractClient {
EvmNftTokenStatJSON
>(GetNFTTokenStatsOperation),
};
public readonly resolve = {
/**
* @description Resolve a specific address to its Unstoppable domain
* @param request Request with parameters.
* @param {Object} request.address The address to be resolved
* @param {Object} [request.currency] The currency to query (optional)
* @returns {Object} Response for the request.
*/
resolveAddressToDomain: this.createEndpoint<
ResolveAddressToDomainOperationRequest,
ResolveAddressToDomainOperationRequestJSON,
EvmUnstoppableDomain,
EvmUnstoppableDomainJSON
>(ResolveAddressToDomainOperation),
};
public readonly token = {
/**
* @description Returns an array of token prices denominated in the blockchain's native token and USD for a given token contract address
Expand Down Expand Up @@ -241,6 +285,41 @@ export abstract class AbstractClient {
>(ReviewContractsOperation),
};
public readonly wallets = {
/**
* @description Get token balances for a specific wallet address and their token prices in USD.
* @param request Request with parameters.
* @param {Object} request.address The address from which token balances will be checked
* @param {Object} [request.chain] The chain to query (optional)
* @param {Number} [request.toBlock] The block number up to which the balances will be checked. (optional)
* @param {Object[]} [request.tokenAddresses] The addresses to get balances for (optional) (optional)
* @param {Boolean} [request.excludeSpam] Exclude spam tokens from the result (optional)
* @param {Boolean} [request.excludeUnverifiedContracts] Exclude unverified contracts from the result (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)
* @param {Boolean} [request.excludeNative] Exclude native balance from the result (optional)
* @returns {Object} Response for the request.
*/
getWalletTokenBalancesPrice: this.createEndpoint<
GetWalletTokenBalancesPriceOperationRequest,
GetWalletTokenBalancesPriceOperationRequestJSON,
EvmErc20TokenBalanceWithPriceResult,
EvmErc20TokenBalanceWithPriceResultJSON
>(GetWalletTokenBalancesPriceOperation),
/**
* @description Get the net worth of a wallet in USD. We recommend to filter out spam tokens and unverified contracts to get a more accurate result.
* @param request Request with parameters.
* @param {Object} request.address The wallet address
* @param {Object[]} [request.chains] The chains to query (optional)
* @param {Boolean} [request.excludeSpam] Exclude spam tokens from the result (optional)
* @param {Boolean} [request.excludeUnverifiedContracts] Exclude unverified contracts from the result (optional)
* @returns {Object} Response for the request.
*/
getWalletNetWorth: this.createEndpoint<
GetWalletNetWorthOperationRequest,
GetWalletNetWorthOperationRequestJSON,
EvmNetWorthResult,
EvmNetWorthResultJSON
>(GetWalletNetWorthOperation),
/**
* @description Get the active chains for a wallet address.
* @param request Request with parameters.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ export interface GetNFTTradesOperationRequest {
/**
* @description The block number to get the trades from
*/
readonly toBlock?: string;
readonly toBlock?: number;
/**
* @description The start date from which to get the transfers (format in seconds or datestring accepted by momentjs)
* * Provide the param 'from_block' or 'from_date'
Expand All @@ -39,7 +39,7 @@ export interface GetNFTTradesOperationRequest {
* * Provide the param 'to_block' or 'to_date'
* * If 'to_date' and 'to_block' are provided, 'to_block' will be used.
*/
readonly toDate?: string;
readonly toDate?: Date;
/**
* @description Marketplace from which to get the trades (only OpenSea is supported at the moment)
*/
Expand Down Expand Up @@ -99,9 +99,9 @@ export const GetNFTTradesOperation = {
return {
chain: chain ? chain.toJSON() : undefined,
from_block: fromBlock,
to_block: toBlock,
to_block: toBlock !== undefined ? String(toBlock) : undefined,
from_date: fromDate,
to_date: toDate,
to_date: toDate !== undefined ? toDate.toISOString() : undefined,
marketplace: marketplace ? marketplace : undefined,
cursor: cursor,
limit: limit,
Expand Down
Loading

1 comment on commit 31d73a7

@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: 86%
87.37% (90/103) 66.66% (6/9) 81.15% (56/69)
common-aptos-utils Coverage: 4%
4.56% (151/3306) 4.49% (25/556) 5.53% (45/813)
common-evm-utils Coverage: 61%
62.35% (1784/2861) 23.06% (194/841) 41.88% (436/1041)
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.