Skip to content

Commit

Permalink
Merge pull request #1064 from MoralisWeb3/feat/internal_transactions
Browse files Browse the repository at this point in the history
feat: add internal transactions
  • Loading branch information
ErnoW authored Mar 22, 2023
2 parents 9953de8 + 71bdc4e commit 7f5c52e
Show file tree
Hide file tree
Showing 18 changed files with 457 additions and 33 deletions.
6 changes: 6 additions & 0 deletions .changeset/soft-oranges-relate.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
---
'@moralisweb3/common-evm-utils': minor
'@moralisweb3/evm-api': minor
---

Add internal transactions param to several operations and `Moralis.Evm.transaction.getInternalTransactions()`
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import { EvmNative } from '../EvmNative';
import { EvmTransactionLog } from '../EvmTransactionLog';
import { EvmSignature } from '../EvmSignature/EvmSignature';
import { EvmTransactionInput, EvmTransactionData } from './types';
import { EvmInternalTransaction } from '../EvmInternalTransaction';

/**
* Valid input for a new EvmTransaction instance.
Expand Down Expand Up @@ -68,6 +69,9 @@ export class EvmTransaction implements MoralisDataObject {
receiptStatus: maybe(data.receiptStatus, (status) => +status),

logs: (data.logs ?? []).map((log) => EvmTransactionLog.create(log)),
internalTransactions: (data.internalTransactions ?? []).map((transaction) =>
EvmInternalTransaction.create(transaction, core),
),

signature: maybe(data.signature, EvmSignature.create),
};
Expand Down Expand Up @@ -124,6 +128,7 @@ export class EvmTransaction implements MoralisDataObject {
chain: data.chain?.format(),
contractAddress: data.contractAddress?.format(),
logs: data.logs.map((log) => log.toJSON()),
internalTransactions: data.internalTransactions.map((transaction) => transaction.toJSON()),
signature: data.signature?.toJSON(),
blockNumber: data.blockNumber?.toString(),
blockTimestamp: data.blockTimestamp.toString(),
Expand Down Expand Up @@ -273,6 +278,17 @@ export class EvmTransaction implements MoralisDataObject {
return this._data.contractAddress;
}

/**
* @returns the internal transactions
* @example
* ```
* transaction.logs // EvmInternalTransaction[]
* ```
*/
get internalTransactions() {
return this._data.internalTransactions;
}

/**
* @returns the transaction logs
* @example
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import { EvmChain, EvmChainish } from '../EvmChain';
import { EvmNativeish, EvmNative } from '../EvmNative';
import { EvmTransactionLogish, EvmTransactionLog } from '../EvmTransactionLog';
import { EvmSignature, EvmSignatureish } from '../EvmSignature/EvmSignature';
import { EvmInternalTransaction, EvmInternalTransactionish } from '../EvmInternalTransaction';

/**
* This can be any object with valid transaction data.
Expand Down Expand Up @@ -63,6 +64,7 @@ export interface EvmTransactionInput {
receiptStatus?: null | string | number;

logs?: EvmTransactionLogish[];
internalTransactions?: EvmInternalTransactionish[];

signature?: EvmSignatureish;
}
Expand Down Expand Up @@ -96,6 +98,7 @@ export interface EvmTransactionData {
receiptStatus?: number;

logs: EvmTransactionLog[];
internalTransactions: EvmInternalTransaction[];

signature?: EvmSignature;
}
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ describe('getBlockOperation', () => {
const request: Required<GetBlockRequest> = {
blockNumberOrHash: '0x123',
chain: EvmChain.create(chain, core),
include: 'internal_transactions',
};

const serializedRequest = getBlockOperation.serializeRequest(request, core);
Expand Down
22 changes: 20 additions & 2 deletions packages/common/evmUtils/src/operations/block/getBlockOperation.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,13 @@
import { Core, Camelize, Operation, toCamelCase, ResponseAdapter } from '@moralisweb3/common-core';
import { EvmBlock, EvmChain, EvmChainish, EvmTransaction, EvmTransactionLog, LogTopic } from '../../dataTypes';
import {
EvmBlock,
EvmChain,
EvmChainish,
EvmInternalTransaction,
EvmTransaction,
EvmTransactionLog,
LogTopic,
} from '../../dataTypes';
import { EvmChainResolver } from '../../EvmChainResolver';
import { operations } from '../openapi';

Expand Down Expand Up @@ -39,7 +47,7 @@ export const getBlockOperation: Operation<
isNullable: true,
urlPathPattern: '/block/{blockNumberOrHash}',
urlPathParamNames: ['blockNumberOrHash'],
urlSearchParamNames: ['chain'],
urlSearchParamNames: ['chain', 'include'],

getRequestUrlParams,
serializeRequest,
Expand All @@ -53,6 +61,7 @@ function getRequestUrlParams(request: GetBlockRequest, core: Core) {
return {
chain: EvmChainResolver.resolve(request.chain, core).apiHex,
blockNumberOrHash: request.blockNumberOrHash,
include: request.include,
};
}

Expand Down Expand Up @@ -103,6 +112,13 @@ function deserializeResponse(jsonResponse: GetBlockJSONResponse, request: GetBlo
transactionIndex: +log.transactionIndex,
});
}),
internalTransactions: (transaction.internalTransactions ?? []).map((jsonInternalTransaction) => {
const internalTransaction = toCamelCase(jsonInternalTransaction);
return EvmInternalTransaction.create({
chain,
...internalTransaction,
});
}),
},
core,
),
Expand All @@ -116,12 +132,14 @@ function serializeRequest(request: GetBlockRequest, core: Core) {
return {
chain: EvmChainResolver.resolve(request.chain, core).apiHex,
blockNumberOrHash: request.blockNumberOrHash,
include: request.include,
};
}

function deserializeRequest(jsonRequest: GetBlockJSONRequest, core: Core): GetBlockRequest {
return {
chain: EvmChain.create(jsonRequest.chain, core),
blockNumberOrHash: jsonRequest.blockNumberOrHash,
include: jsonRequest.include,
};
}
98 changes: 98 additions & 0 deletions packages/common/evmUtils/src/operations/openapi.ts
Original file line number Diff line number Diff line change
Expand Up @@ -162,6 +162,10 @@ export interface paths {
/** Get native transactions and logs ordered by block number in descending order. */
get: operations["getWalletTransactionsVerbose"];
};
"/transaction/{transaction_hash}/internal-transactions": {
/** Get the contents of a internal transaction by transaction hash. */
get: operations["getInternalTransactions"];
};
"/transaction/{transaction_hash}": {
/** Get the contents of a transaction by the given transaction hash. */
get: operations["getTransaction"];
Expand Down Expand Up @@ -704,6 +708,8 @@ export interface components {
block_hash: string;
/** @description The logs of the transaction */
logs?: components["schemas"]["log"][];
/** @description The internal transactions of the transaction */
internal_transactions?: components["schemas"]["internalTransaction"][];
};
block: {
/**
Expand Down Expand Up @@ -1040,6 +1046,65 @@ export interface components {
* @example 0x0372c302e3c52e8f2e15d155e2c545e6d802e479236564af052759253b20fd86
*/
block_hash: string;
/** @description The internal transaction */
internal_transactions?: components["schemas"]["internalTransaction"][];
};
internalTransaction: {
/**
* @description The hash of the transaction
* @example 0x057Ec652A4F150f7FF94f089A38008f49a0DF88e
*/
transaction_hash: string;
/**
* @description The block number
* @example 12526958
*/
block_number: string;
/**
* @description The block hash
* @example 0x0372c302e3c52e8f2e15d155e2c545e6d802e479236564af052759253b20fd86
*/
block_hash: string;
/**
* @description Call type
* @example CALL
*/
type: string;
/**
* @description The sender
* @example 0xd4a3BebD824189481FC45363602b83C9c7e9cbDf
*/
from: string;
/**
* @description The recipient
* @example 0xa71db868318f0a0bae9411347cd4a6fa23d8d4ef
*/
to: string;
/**
* @description The value that was transfered (in wei)
* @example 650000000000000000
*/
value: string;
/**
* @description The gas of the transaction
* @example 6721975
*/
gas: string;
/**
* @description The used gas
* @example 6721975
*/
gas_used: string;
/**
* @description The input
* @example 0x
*/
input: string;
/**
* @description The output
* @example 0x
*/
output: string;
};
erc20Allowance: {
/** @description The allowance */
Expand Down Expand Up @@ -1161,6 +1226,12 @@ export interface components {
page_size?: number;
result?: components["schemas"]["trade"][];
};
/**
* @default
* @example internal_transactions
* @enum {string}
*/
includeList: "internal_transactions";
/**
* @default eth
* @example eth
Expand Down Expand Up @@ -3175,6 +3246,8 @@ export interface operations {
limit?: number;
/** If the result should skip returning the total count (Improves performance). */
disable_total?: boolean;
/** If the result should contain the internal transactions. */
include?: components["schemas"]["includeList"];
};
path: {
/** The address of the wallet */
Expand Down Expand Up @@ -3241,12 +3314,35 @@ export interface operations {
};
};
};
/** Get the contents of a internal transaction by transaction hash. */
getInternalTransactions: {
parameters: {
query: {
/** The chain to query */
chain?: components["schemas"]["chainList"];
};
path: {
/** The transaction hash */
transaction_hash: string;
};
};
responses: {
/** Internal Transaction details by transaction hash */
200: {
content: {
"application/json": components["schemas"]["internalTransaction"][];
};
};
};
};
/** Get the contents of a transaction by the given transaction hash. */
getTransaction: {
parameters: {
query: {
/** The chain to query */
chain?: components["schemas"]["chainList"];
/** If the result should contain the internal transactions. */
include?: components["schemas"]["includeList"];
};
path: {
/** The transaction hash */
Expand Down Expand Up @@ -3289,6 +3385,8 @@ export interface operations {
query: {
/** The chain to query */
chain?: components["schemas"]["chainList"];
/** If the result should contain the internal transactions. */
include?: components["schemas"]["includeList"];
};
path: {
/** The block number or block hash */
Expand Down
7 changes: 4 additions & 3 deletions packages/common/evmUtils/src/operations/operations.ts
Original file line number Diff line number Diff line change
Expand Up @@ -33,18 +33,18 @@ import {
getWalletTokenBalancesOperation,
getErc20TransfersOperation,
getErc20MintsOperation,
getWalletTokenTransfersOperation,
getErc20ApprovalsOperation,
getErc20BurnsOperation,
} from './token';
import { getWalletTokenTransfersOperation } from './token/getWalletTokenTransfersOperation';
import {
getTransactionOperation,
getTransactionVerboseOperation,
getWalletTransactionsOperation,
getWalletTransactionsVerboseOperation,
getInternalTransactionsOperation,
} from './transaction';
import { endpointWeightsOperation, web3ApiVersionOperation } from './utils';
import { runContractFunctionOperation } from './utils/runContractFunctionOperation';
import { endpointWeightsOperation, web3ApiVersionOperation, runContractFunctionOperation } from './utils';

export const operations = [
endpointWeightsOperation,
Expand All @@ -57,6 +57,7 @@ export const operations = [
getErc20BurnsOperation,
getErc20TransfersOperation,
getErc20MintsOperation,
getInternalTransactionsOperation,
getMultipleNFTsOperation,
getNativeBalanceOperation,
getNativeBalancesForAddressesOperation,
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
import MoralisCore from '@moralisweb3/common-core';
import { EvmChain } from '../../dataTypes';
import { getInternalTransactionsOperation, GetInternalTransactionsRequest } from './getInternalTransactionsOperation';

describe('getInternalTransactionsOperation', () => {
let core: MoralisCore;

beforeAll(() => {
core = MoralisCore.create();
});

it('serializeRequest() serializes correctly and deserializeRequest() deserializes correctly', () => {
const chain = '0x10';

const request: Required<GetInternalTransactionsRequest> = {
chain: EvmChain.create(chain, core),
transactionHash: '0x9857d679ab331210161427d36d08c3b00e6d28c03366e9b891832ad9b5d478f7z',
};

const serializedRequest = getInternalTransactionsOperation.serializeRequest(request, core);

expect(serializedRequest.chain).toBe(chain);
expect(serializedRequest.transactionHash).toBe(request.transactionHash);

const deserializedRequest = getInternalTransactionsOperation.deserializeRequest(serializedRequest, core);

expect((deserializedRequest.chain as EvmChain).apiHex).toBe(chain);
expect(deserializedRequest.transactionHash).toBe(request.transactionHash);
});
});
Loading

0 comments on commit 7f5c52e

Please sign in to comment.