Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
52 changes: 18 additions & 34 deletions packages/relay/src/lib/clients/mirrorNodeClient.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ import { MirrorNodeClientError } from '../errors/MirrorNodeClientError';
import { SDKClientError } from '../errors/SDKClientError';
import { CacheService } from '../services/cacheService/cacheService';
import {
IAccountRequestParams,
IContractCallRequest,
IContractCallResponse,
IContractLogsResultsParams,
Expand All @@ -43,15 +44,14 @@ export class MirrorNodeClient {
private static readonly GET_CONTRACT_ENDPOINT = 'contracts/';
private static readonly CONTRACT_RESULT_LOGS_PROPERTY = 'logs';
private static readonly CONTRACT_ID_PLACEHOLDER = '{contractId}';
private static readonly ACCOUNT_TIMESTAMP_PROPERTY = 'timestamp';
private static readonly ACCOUNT_TRANSACTIONS_PROPERTY = 'transactions';
private static readonly CONTRACT_CALL_ENDPOINT = 'contracts/call';
private static readonly GET_ACCOUNTS_BY_ID_ENDPOINT = 'accounts/';
private static readonly GET_NETWORK_FEES_ENDPOINT = 'network/fees';
private static readonly GET_TRANSACTIONS_ENDPOINT = 'transactions';
private static readonly TRANSACTION_ID_PLACEHOLDER = '{transactionId}';
private static readonly GET_CONTRACT_RESULT_ENDPOINT = 'contracts/results/';
private static readonly GET_CONTRACT_RESULTS_ENDPOINT = 'contracts/results';
private static readonly ACCOUNT_TRANSACTION_TYPE_PROPERTY = 'transactiontype';
private static readonly GET_NETWORK_EXCHANGERATE_ENDPOINT = 'network/exchangerate';
private static readonly GET_CONTRACT_RESULT_LOGS_ENDPOINT = 'contracts/results/logs';
private static readonly CONTRACT_ADDRESS_STATE_ENDPOINT = `contracts/${MirrorNodeClient.ADDRESS_PLACEHOLDER}/state`;
Expand Down Expand Up @@ -514,13 +514,16 @@ export class MirrorNodeClient {
public async getAccount(
idOrAliasOrEvmAddress: string,
requestDetails: RequestDetails,
queryParamObject: IAccountRequestParams & ILimitOrderParams = { transactions: false },
retries?: number,
timestamp?: string,
) {
const queryParamObject = {};
this.setQueryParam(queryParamObject, 'timestamp', timestamp);
this.setQueryParam(queryParamObject, 'transactions', 'false');
const queryParams = this.getQueryParams(queryParamObject);
const queryParamsFiltered = Object.fromEntries(
Object.entries(queryParamObject).filter(([key, value]) => {
if (key === MirrorNodeClient.ACCOUNT_TRANSACTIONS_PROPERTY && value) return false;
return value !== undefined && value !== '';
}),
);
const queryParams = this.getQueryParams(queryParamsFiltered);
return this.get(
`${MirrorNodeClient.GET_ACCOUNTS_BY_ID_ENDPOINT}${idOrAliasOrEvmAddress}${queryParams}`,
MirrorNodeClient.GET_ACCOUNTS_BY_ID_ENDPOINT,
Expand All @@ -535,32 +538,12 @@ export class MirrorNodeClient {
requestDetails: RequestDetails,
numberOfTransactions: number = 1,
) {
const queryParamObject = {};
this.setQueryParam(
queryParamObject,
MirrorNodeClient.ACCOUNT_TRANSACTION_TYPE_PROPERTY,
MirrorNodeClient.ETHEREUM_TRANSACTION_TYPE,
);
this.setQueryParam(queryParamObject, MirrorNodeClient.ACCOUNT_TIMESTAMP_PROPERTY, `lte:${timestampTo}`);
this.setLimitOrderParams(
queryParamObject,
this.getLimitOrderQueryParam(numberOfTransactions, constants.ORDER.DESC),
); // get latest 2 transactions to infer for single case
const queryParams = this.getQueryParams(queryParamObject);

return this.get(
`${MirrorNodeClient.GET_ACCOUNTS_BY_ID_ENDPOINT}${idOrAliasOrEvmAddress}${queryParams}`,
MirrorNodeClient.GET_ACCOUNTS_BY_ID_ENDPOINT,
requestDetails,
);
}

public async getAccountPageLimit(idOrAliasOrEvmAddress: string, requestDetails: RequestDetails) {
return this.get(
`${MirrorNodeClient.GET_ACCOUNTS_BY_ID_ENDPOINT}${idOrAliasOrEvmAddress}?limit=${constants.MIRROR_NODE_QUERY_LIMIT}`,
MirrorNodeClient.GET_ACCOUNTS_BY_ID_ENDPOINT,
requestDetails,
);
return this.getAccount(idOrAliasOrEvmAddress, requestDetails, {
transactiontype: MirrorNodeClient.ETHEREUM_TRANSACTION_TYPE,
timestamp: `lte:${timestampTo}`,
transactions: true,
...this.getLimitOrderQueryParam(numberOfTransactions, constants.ORDER.DESC),
});
}

/**
Expand Down Expand Up @@ -1409,10 +1392,11 @@ export class MirrorNodeClient {

let data;
try {
const params = { timestamp, transactions: false };
const promises = [
searchableTypes.includes(constants.TYPE_ACCOUNT)
? buildPromise(
this.getAccount(entityIdentifier, requestDetails, retries, timestamp).catch(() => {
this.getAccount(entityIdentifier, requestDetails, params, retries).catch(() => {
return null;
}),
)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -151,7 +151,7 @@ export class AccountService implements IAccountService {

if (!balanceFound && !mirrorAccount) {
// If no balance and no account, then we need to make a request to the mirror node for the account.
mirrorAccount = await this.mirrorNodeClient.getAccountPageLimit(account, requestDetails);
mirrorAccount = await this.mirrorNodeClient.getAccount(account, requestDetails);
// Test if exists here
if (mirrorAccount !== null && mirrorAccount !== undefined) {
balanceFound = true;
Expand Down Expand Up @@ -265,7 +265,10 @@ export class AccountService implements IAccountService {
else {
let currentBalance = 0;
let balanceFromTxs = 0;
mirrorAccount = await this.mirrorNodeClient.getAccountPageLimit(account, requestDetails);
mirrorAccount = await this.mirrorNodeClient.getAccount(account, requestDetails, {
limit: constants.MIRROR_NODE_QUERY_LIMIT,
transactions: true,
});
if (mirrorAccount) {
if (mirrorAccount.balance) {
currentBalance = mirrorAccount.balance.balance;
Expand Down
6 changes: 6 additions & 0 deletions packages/relay/src/lib/types/mirrorNode.ts
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,12 @@ export interface ILimitOrderParams {
order?: string;
}

export interface IAccountRequestParams {
timestamp?: string;
transactions?: boolean;
[key: string]: string | boolean | number | undefined; // Allow dynamic params
}

export interface IContractResultsParams {
blockHash?: string;
blockNumber?: number;
Expand Down
13 changes: 7 additions & 6 deletions packages/relay/tests/lib/eth/eth_getBalance.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,7 @@ describe('@ethGetBalance using MirrorNode', async function () {

it('should return balance from mirror node', async () => {
restMock.onGet(BLOCKS_LIMIT_ORDER_URL).reply(200, JSON.stringify(MOCK_BLOCK_NUMBER_1000_RES));
restMock.onGet(`accounts/${CONTRACT_ADDRESS_1}?limit=100`).reply(200, JSON.stringify(MOCK_BALANCE_RES));
restMock.onGet(`accounts/${CONTRACT_ADDRESS_1}?transactions=false`).reply(200, JSON.stringify(MOCK_BALANCE_RES));

const resBalance = await ethImpl.getBalance(CONTRACT_ADDRESS_1, 'latest', requestDetails);
expect(resBalance).to.equal(DEF_HEX_BALANCE);
Expand All @@ -58,7 +58,7 @@ describe('@ethGetBalance using MirrorNode', async function () {
it('should return balance from mirror node with block number passed as param the same as latest', async () => {
const blockNumber = '0x2710';
restMock.onGet(BLOCKS_LIMIT_ORDER_URL).reply(200, JSON.stringify(MOCK_BLOCKS_FOR_BALANCE_RES));
restMock.onGet(`accounts/${CONTRACT_ADDRESS_1}?limit=100`).reply(200, JSON.stringify(MOCK_BALANCE_RES));
restMock.onGet(`accounts/${CONTRACT_ADDRESS_1}?transactions=false`).reply(200, JSON.stringify(MOCK_BALANCE_RES));

const resBalance = await ethImpl.getBalance(CONTRACT_ADDRESS_1, blockNumber, requestDetails);
expect(resBalance).to.equal(DEF_HEX_BALANCE);
Expand All @@ -73,7 +73,7 @@ describe('@ethGetBalance using MirrorNode', async function () {
number: 10000,
}),
);
restMock.onGet(`accounts/${CONTRACT_ADDRESS_1}?limit=100`).reply(200, JSON.stringify(MOCK_BALANCE_RES));
restMock.onGet(`accounts/${CONTRACT_ADDRESS_1}?transactions=false`).reply(200, JSON.stringify(MOCK_BALANCE_RES));

const resBalance = await ethImpl.getBalance(CONTRACT_ADDRESS_1, blockHash, requestDetails);
expect(resBalance).to.equal(DEF_HEX_BALANCE);
Expand All @@ -82,7 +82,7 @@ describe('@ethGetBalance using MirrorNode', async function () {
it('should return balance from mirror node with block number passed as param, one behind latest', async () => {
const blockNumber = '0x270F';
restMock.onGet(BLOCKS_LIMIT_ORDER_URL).reply(200, JSON.stringify(MOCK_BLOCKS_FOR_BALANCE_RES));
restMock.onGet(`accounts/${CONTRACT_ADDRESS_1}?limit=100`).reply(200, JSON.stringify(MOCK_BALANCE_RES));
restMock.onGet(`accounts/${CONTRACT_ADDRESS_1}?transactions=false`).reply(200, JSON.stringify(MOCK_BALANCE_RES));

const resBalance = await ethImpl.getBalance(CONTRACT_ADDRESS_1, blockNumber, requestDetails);
expect(resBalance).to.equal(DEF_HEX_BALANCE);
Expand Down Expand Up @@ -120,7 +120,7 @@ describe('@ethGetBalance using MirrorNode', async function () {
it('should return balance from consensus node', async () => {
restMock.onGet(BLOCKS_LIMIT_ORDER_URL).reply(200, JSON.stringify(MOCK_BLOCK_NUMBER_1000_RES));
restMock.onGet(`contracts/${CONTRACT_ADDRESS_1}`).reply(200, JSON.stringify(null));
restMock.onGet(`accounts/${CONTRACT_ADDRESS_1}?limit=100`).reply(404, JSON.stringify(NOT_FOUND_RES));
restMock.onGet(`accounts/${CONTRACT_ADDRESS_1}?transactions=false`).reply(404, JSON.stringify(NOT_FOUND_RES));

const resBalance = await ethImpl.getBalance(CONTRACT_ADDRESS_1, 'latest', requestDetails);
expect(resBalance).to.equal(constants.ZERO_HEX);
Expand Down Expand Up @@ -218,7 +218,7 @@ describe('@ethGetBalance using MirrorNode', async function () {
restMock.onGet(`blocks/2`).reply(200, JSON.stringify(recentBlock));
restMock.onGet(`blocks/1`).reply(200, JSON.stringify(earlierBlock));

restMock.onGet(`accounts/${CONTRACT_ID_1}?limit=100`).reply(
restMock.onGet(`accounts/${CONTRACT_ID_1}?transactions=false`).reply(
200,
JSON.stringify({
account: CONTRACT_ID_1,
Expand Down Expand Up @@ -698,6 +698,7 @@ describe('@ethGetBalance using MirrorNode', async function () {
},
};
restMock.onGet(`blocks/2`).reply(200, JSON.stringify(recentBlockWithinLastfifteen));
restMock.onGet(`accounts/${notFoundEvmAddress}?transactions=false`).reply(404, JSON.stringify(NOT_FOUND_RES));
restMock.onGet(`accounts/${notFoundEvmAddress}?limit=100`).reply(404, JSON.stringify(NOT_FOUND_RES));

const resBalance = await ethImpl.getBalance(notFoundEvmAddress, '2', requestDetails);
Expand Down
2 changes: 1 addition & 1 deletion packages/relay/tests/lib/relay.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -124,7 +124,7 @@ describe('Relay', () => {
beforeEach(() => {
// @ts-expect-error: Property 'operatorAccountId' is private and only accessible within class 'Relay'.
operatorId = relay.operatorAccountId!.toString();
getAccountPageLimitStub = sinon.stub(MirrorNodeClient.prototype, 'getAccountPageLimit');
getAccountPageLimitStub = sinon.stub(MirrorNodeClient.prototype, 'getAccount');
});

afterEach(() => {
Expand Down
Loading