controller.ts
Overview
The [controller.ts](/projects/291/68853) file implements the REST API controller for the Ethereum Virtual Machine (EVM) blockchain coinstack within a unified multi-blockchain API platform. It exposes a set of HTTP endpoints under the route `/api/v1` that allow clients to:
Fetch basic network info
Query account details by address
Retrieve paginated transaction history for an account
Get detailed information on a specific transaction
Broadcast raw signed transactions to the network
Execute generic JSON-RPC calls on the underlying Ethereum node
Fetch metadata for ERC721 and ERC1155 tokens
This controller class, named `EVM`, implements the `BaseAPI` interface (except for gas fee estimation methods) and extends the base `Controller` class from `tsoa` to provide OpenAPI-compliant routing, validation, response types, and example data.
All business logic and blockchain interactions are delegated to a static `Service` instance, separating HTTP concerns from data handling. The controller validates parameters and request bodies, maps HTTP verbs and routes to methods, and defines response schemas including error responses.
This file is a critical part of the Unified API Layer that standardizes blockchain access across different protocols, specialized here for EVM-compatible chains like Ethereum mainnet and testnets.
Class: EVM
Description
`EVM` is a controller class exposing REST endpoints under the `/api/v1` route and tagged as `'v1'`. It implements the core blockchain API for EVM chains by defining HTTP methods decorated with metadata for automatic routing, parameter extraction, validation, and response formatting.
It implements the `BaseAPI` interface (with some omissions) and provides additional endpoints for JSON-RPC proxying and token metadata retrieval.
The controller methods are asynchronous and return promises resolving to typed response models.
Static Properties
Property | Type | Description |
|---|---|---|
`service` | `Service` | Static reference to the EVM `Service` instance handling business logic |
Methods
getInfo()
@Get('info/')
async getInfo(): Promise<BaseInfo>
Description:
Retrieves basic information about the running coinstack instance, including the network name.Returns:
A promise resolving to aBaseInfoobject containing the network string.Example Response:
{ "network": "mainnet" }Usage:
GET /api/v1/info/
getAccount(pubkey: string)
@Get('account/{pubkey}')
async getAccount(@Path() pubkey: string): Promise<Account>
Description:
Retrieves account details for a specified public key (address), including balances, nonce, and held tokens (ERC20, NFTs).Parameters:
pubkey(string, path parameter): The address of the account to query.
Returns:
A promise resolving to anAccountobject containing:balance: string representing account balance in weiunconfirmedBalance: string representing unconfirmed balancenonce: nonce number for transaction orderingpubkey: account addresstokens: array of token balances and metadata
Response Codes:
400 Bad Request
422 Validation Error
500 Internal Server Error
Example Response:
{ "balance": "0", "unconfirmedBalance": "0", "nonce": 0, "pubkey": "0xFFfFfFffFFfffFFfFFfFFFFFffFFFffffFfFFFfF", "tokens": [ { "balance": "1337", "contract": "0xc770EEfAd204B5180dF6a14Ee197D99d808ee52d", "decimals": 18, "name": "FOX", "symbol": "FOX", "type": "ERC20" } ] }Usage:
GET /api/v1/account/0xFFfFfFffFFfffFFfFFfFFFFFffFFFffffFfFFFfF
getTxHistory(pubkey: string, cursor?: string, pageSize?: number, from?: number, to?: number)
@Get('account/{pubkey}/txs')
async getTxHistory(
@Path() pubkey: string,
@Query() cursor?: string,
@Query() pageSize = 10,
@Query() from?: number,
@Query() to?: number
): Promise<TxHistory>
Description:
Retrieves the transaction history for an account, with support for cursor-based pagination and optional block range filtering.Parameters:
pubkey(string, path): Account address to query.cursor(string, query, optional): Base64 encoded JSON cursor for paging.pageSize(number, query, optional, default=10): Number of transactions per page.from(number, query, optional): Starting block number for filtering. Defaults to 0.to(number, query, optional): Ending block number for filtering. Defaults to pending.
Returns:
A promise resolving to aTxHistoryobject containing:pubkey: the queried addresstxs: array of transactions with detailed fields (txid, blockHash, blockHeight, timestamp, status, from, to, confirmations, value, fee, gasLimit, gasUsed, gasPrice)
Response Codes:
400 Bad Request
422 Validation Error
500 Internal Server Error
Example Response:
{ "pubkey": "0xFFfFfFffFFfffFFfFFfFFFFFffFFFffffFfFFFfF", "txs": [ { "txid": "0x6850c6f3af68eb60a211af8f07f5b305375d0c94786b79a48371f5143953cb26", "blockHash": "0x969bda3f454330557492deacffb0ee8a7fd1d094cf884926d24c71ad11ed13bb", "blockHeight": 15624164, "timestamp": 1664275343, "status": 1, "from": "0xc730B028dA66EBB14f20e67c68DD809FBC49890D", "to": "0xFFfFfFffFFfffFFfFFfFFFFFffFFFffffFfFFFfF", "confirmations": 3911254, "value": "5384660932716527", "fee": "278408778879000", "gasLimit": "21000", "gasUsed": "21000", "gasPrice": "13257560899" } ] }Usage:
GET /api/v1/account/0xFFfFfFffFFfffFFfFFfFFFFFffFFFffffFfFFFfF/txs?pageSize=20&cursor=eyJwYWdlIjoxfQ==
getTransaction(txid: string)
@Get('tx/{txid}')
async getTransaction(@Path() txid: string): Promise<Tx>
Description:
Returns detailed information for a specific transaction by its hash.Parameters:
txid(string, path): Transaction hash.
Returns:
A promise resolving to aTxobject with comprehensive transaction details including block info, confirmations, gas usage, and status.Response Codes:
400 Bad Request
422 Validation Error
500 Internal Server Error
Example Response:
{ "txid": "0x6850c6f3af68eb60a211af8f07f5b305375d0c94786b79a48371f5143953cb26", "blockHash": "0x969bda3f454330557492deacffb0ee8a7fd1d094cf884926d24c71ad11ed13bb", "blockHeight": 15624164, "timestamp": 1664275343, "status": 1, "from": "0xc730B028dA66EBB14f20e67c68DD809FBC49890D", "to": "0xFFfFfFffFFfffFFfFFfFFFFFffFFFffffFfFFFfF", "confirmations": 3911254, "value": "5384660932716527", "fee": "278408778879000", "gasLimit": "21000", "gasUsed": "21000", "gasPrice": "13257560899" }Usage:
GET /api/v1/tx/0x6850c6f3af68eb60a211af8f07f5b305375d0c94786b79a48371f5143953cb26
sendTx(body: SendTxBody)
@Post('send/')
async sendTx(@Body() body: SendTxBody): Promise<string>
Description:
Broadcasts a raw serialized transaction hex to the Ethereum network.Parameters:
body(SendTxBody): Request body containing ahexproperty with the serialized transaction data.
Returns:
A promise resolving to the transaction ID (hash) string upon successful broadcast.Response Codes:
400 Bad Request
422 Validation Error
500 Internal Server Error
Example Usage:
POST /api/v1/send/ Content-Type: application/json { "hex": "0xf86b808504a817c80082520894..." }Example Response:
"0x6850c6f3af68eb60a211af8f07f5b305375d0c94786b79a48371f5143953cb26"
doRpcRequest(body: RPCRequest | Array)
@Post('jsonrpc/')
async doRpcRequest(@Body() body: RPCRequest | Array<RPCRequest>): Promise<RPCResponse | Array<RPCResponse>>
Description:
Passes a JSON-RPC request or batch of requests directly to the underlying Ethereum node. Supports arbitrary RPC methods.Parameters:
body: Single or array ofRPCRequestobjects following JSON-RPC 2.0 spec.
Returns:
A promise resolving to a singleRPCResponseor an array ofRPCResponseobjects.Example Request Body:
{ "jsonrpc": "2.0", "id": "test", "method": "eth_blockNumber", "params": [] }Example Response:
{ "jsonrpc": "2.0", "id": "test", "result": "0x1a4" }Usage:
POST /api/v1/jsonrpc/ Content-Type: application/json { "jsonrpc": "2.0", "id": "test", "method": "eth_blockNumber", "params": [] }
getTokenMetadata(contract: string, id: string, type: TokenType)
@Get('/metadata/token')
async getTokenMetadata(
@Query() contract: string,
@Query() id: string,
@Query() type: TokenType
): Promise<TokenMetadata>
Description:
Retrieves metadata for a specific token identified by its smart contract address, token ID, and token standard type (ERC721 or ERC1155).Parameters:
contract(string, query): Token contract address.id(string, query): Token identifier (tokenId).type(TokenType, query): Token standard type, e.g.,'erc721'or'erc1155'.
Returns:
A promise resolving to aTokenMetadataobject including:name: token namedescription: textual descriptionmedia: media object with URL and type (e.g., image)
Response Codes:
422 Validation Error
500 Internal Server Error
Example Response:
{ "name": "FoxyFox", "description": "FOXatars are a cyber-fox NFT project created by ShapeShift and Mercle", "media": { "url": "https://storage.mercle.xyz/ipfs/bafybeifihbavnaqwmisq72nwqpmxy3qkfqxj5nvjg7wimluhisp7wkzcru", "type": "image" } }Usage:
GET /api/v1/metadata/token?contract=0xabc123...&id=1&type=erc721
Important Implementation Details
Environment Variable Enforcement:
TheNETWORKenvironment variable must be set before the controller is instantiated, otherwise the module throws an error. This ensures the controller knows which network it serves (e.g., mainnet, rinkeby).Separation of Concerns:
The controller delegates all blockchain data fetching, transaction broadcasting, and metadata resolution to the staticServiceinstance, which encapsulates complex logic, including:Querying Blockbook indexer for account balances and transactions.
Merging on-chain and internal transactions for history.
Broadcasting raw transactions via Ethereum node JSON-RPC.
Fetching token metadata by invoking contract ABI calls and resolving URIs.
Proxying arbitrary JSON-RPC calls to the Ethereum node.
Decorators for Routing and Validation:
The file usestsoadecorators for:Defining routes (
@Route,@Get,@Post)Tagging endpoints (
@Tags)Specifying parameter sources (
@Path,@Query,@Body)Example responses (
@Example)Response codes and error responses (
@Response)
Error Handling:
The controller methods annotate possible error responses (400, 422, 500) using specific error classes (BadRequestError,ValidationError,InternalServerError), enabling the API framework to generate proper OpenAPI documentation and consistent HTTP responses.Omission of Certain Methods:
The controller implementsBaseAPIexcept forgetGasFeesandestimateGas, which are omitted (Omit<API, 'getGasFees' | 'estimateGas'>), possibly implemented elsewhere.
Interaction with Other System Components
Service Layer (
Service):
The controller calls methods on theServiceclass instance to perform blockchain interactions. The service handles all external API calls to Blockbook, Ethereum nodes, and other dependencies.Models:
The controller returns instances of domain models imported from./models, such asAccount,Tx,TxHistory,TokenMetadata, and uses types likeSendTxBody,RPCRequest,RPCResponsefor request and response payloads.Error Classes:
Uses common error classes defined in the shared API library (BadRequestError,ValidationError,InternalServerError) for consistent API error reporting.Environment Configuration:
Relies on theNETWORKenvironment variable to indicate which blockchain network is targeted.API Framework (
tsoa):
Usestsoafor automatic generation of OpenAPI specs, request validation, and routing based on decorators.
Usage Summary
Clients interact with this controller over HTTP by sending requests to:
/api/v1/info/for basic network info/api/v1/account/{address}for account details/api/v1/account/{address}/txsfor transaction history (paginated)/api/v1/tx/{txid}for transaction details/api/v1/send/to broadcast raw transactions/api/v1/jsonrpc/to send arbitrary JSON-RPC requests/api/v1/metadata/tokento fetch token metadata
Visual Diagram: Class Structure of EVM Controller
classDiagram
class EVM {
<<Controller>>
+static service: Service
+getInfo(): Promise<BaseInfo>
+getAccount(pubkey: string): Promise<Account>
+getTxHistory(pubkey: string, cursor?: string, pageSize?: number, from?: number, to?: number): Promise<TxHistory>
+getTransaction(txid: string): Promise<Tx>
+sendTx(body: SendTxBody): Promise<string>
+doRpcRequest(body: RPCRequest | RPCRequest[]): Promise<RPCResponse | RPCResponse[]>
+getTokenMetadata(contract: string, id: string, type: TokenType): Promise<TokenMetadata>
}
EVM ..|> Controller
EVM ..|> BaseAPI
EVM --> Service : delegates calls
Summary
The [controller.ts](/projects/291/68853) file defines the `EVM` controller class, a REST API interface for EVM-compatible blockchains within a unified multi-blockchain API platform. It exposes endpoints for querying network info, account data, transaction history, transaction details, sending transactions, performing generic JSON-RPC calls, and fetching token metadata. The controller validates inputs, declares response schemas and error cases, and delegates all data processing to a dedicated business logic `Service` class.
This modular design cleanly separates API routing from blockchain interaction logic and integrates with shared API models, error classes, and environment configuration. It is a critical component enabling standardized, extensible blockchain access for Ethereum and compatible chains in the broader Unified API Layer ecosystem.