Make your Portfolio Tracking App

This guide helps sedimenting the knowledge obtained in the previous guides by assembling different DeFi API endpoints to build a portfolio tracking application

In the DeFi API Examples repository we have example applications that illustrate the usage of several APIs.

⚠️

Legal Warning

The example applications provided in this repository are intended solely as starting points to help you learn about the DeFi API and its capabilities. We do not provide any guarantees regarding their usage, and they should not be used in production environments. For more information or assistance, please contact our team through our support page.

There are example applications under src/main/examples that illustrate the functionalities and flexibility of the DeFi APIs, in the rebalance-app-rebasedbranch. More information about each specific app is in its README.md. Currently, we have one example app at src/main/examples/rebalancing-app.

The rebalancing application works as a portfolio tracking application. Rebalancing ensures that monitored token balances remain within predefined thresholds. This is vital in an environment where liquidity is critical (operational efficiency, risk mitigation, automation). The rebalancing application (rebalance-main.ts) demonstrates how to maintain healthy token balances by monitoring and correcting imbalances between accounts using Blockdaemon's DeFi API. The tool ensures liquidity is maintained and trading or operational objectives are met by combining several API endpoints to check balances, fetch token data, calculate swap routes, and execute token transfers.

How to Check Out the Rebalancing Example

  1. Clone the repository and navigate to the folder:

git clone https://github.com/Blockdaemon/defi-api-examples.git cd defi-api-examples. Change to the right branch: git checkout rebalance-app-rebased.

  1. Install dependencies: pnpm install
  2. Locate the Rebalancing App in src/main/examples/rebalancing-app/.
  3. Configure the application as instructed in the README.md

Rebalance Application Components

configuration.json

The rebalance application depends on a configuration file that defines several aspects of its workings. The config file defines:
periodicity (in seconds) – how often to create new rebalance jobs
senderAddress and receiverAddress – accounts used for moving funds
supplierTokens – tokens that supply liquidity (e.g., bridging funds from these tokens)
monitoredTokens – tokens that must remain above certain threshold balances

Each token object includes mandatory fields such as:
address – ERC-20 or native token address
chainID – the CAIP-2 identifier for the blockchain (e.g., eip155:137 for Polygon)
maximumRebalance or minimumBalance – how many tokens can be shifted or the minimum balance to uphold

For example:

{
  "periodicity": 30,
  "senderAddress": "...",
  "receiverAddress": "...",
  "supplierTokens": [
    {
      "address": "0x0000000000000000000000000000000000000000",
      "maximumRebalance": "0.0001",
      "chainID": "eip155:10"
    }
  ],
  "monitoredTokens": [
    {
      "address": "0x2791Bca1f2de4661ED88A30C99A7a9449Aa84174",
      "minimumBalance": "0.1",
      "chainID": "eip155:137"
    }
  ]
}

The file rebalance-config.tsdefines checks (e.g., via validateConfig) that confirm required fields, validity of token, and that the chains and tokens in the configuration are supported by the DeFi API.

rebalance-main.ts

It is the entry point to the application. It loads the rebalancing config with creates a RebalanceJobManager instance, then starts the monitoring. It periodically logs job stats so you can monitor successes and failures.

import { initRebalanceConfig, getRebalanceConfig } from "./rebalance-config";
import { RebalanceJobManager } from "./rebalance-job-manager";
import { ExchangeApi, ApprovalsApi, BalancesApi } from "@blockdaemon/blockdaemon-defi-api-typescript-fetch";

async function main() {
  await initRebalanceConfig();
  const jobManager = new RebalanceJobManager(
    getRebalanceConfig(),
    new ExchangeApi(...),
    new ApprovalsApi(...),
    new BalancesApi(...)
  );
  jobManager.start();
}

rebalance-job-manager.ts

Has the core logic of the rebalancing application. Schedules periodic jobs based on the config’s periodicity. Each job:

  1. Fetches on-chain balances using the BalancesApi:
private async getMonitoredTokenBalance(
  chainId: string,
  tokenAddress: string,
  accountAddress: string,
): Promise<bigint> {
  const request: GetBalancesRequest = {
    accountAddress: accountAddress,
    chainIDs: [chainId],
    tokenAddress: tokenAddress,
  };
  const response: BalancesResponse = await this.balancesApi.getBalances(request);
  const balance = response.balances[0].tokenBalances[0].amount;
  [...]
  return BigInt(balance);
}
  1. Compares actual balances to thresholds
[...]
 for (const token of this.config.monitoredTokens) {
    try {
      const balance = await this.getMonitoredTokenBalance(
        token.chainID,
        token.address,
        this.config.receiverAddress,
      );

      const tokenDecimalsMinimumBalance = BigInt(
        tokenUnitsToDecimals(token.minimumBalance, token.token),
      );

      // Compare actual balance to threshold
      if (balance < tokenDecimalsMinimumBalance) {
        logger.info(`Balance below threshold for token ${token.address}`);
      } else {
        logger.info(`Balance is above threshold for token ${token.address}`);
      }
      const balanceDifference = await this.calculateAmountToTransfer(
        tokenDecimalsMinimumBalance,
        token,
      );
      balanceDifferences.push(balanceDifference);
    } catch (error) {
      logger.error(
        `Error retrieving balance for token ${token.address} on ${token.chainID}:`,
        error,
      );
      balanceDifferences.push(0n);
    }
  }
  return balanceDifferences;
[...]
  1. Uses approval and exchange endpoints (if needed) to correct imbalances
[...]
job.status = JobStatus.CHECKING_APPROVAL;

const walletConfig = getWalletApprovalConfig()[routeParameters.fromChain === "optimism" ? "optimism" : "polygon"];

const approvalTxHash = await handleTokenApproval(
  selectedRoute,
  routeParameters,
  this.approvalsApi,
  walletConfig.wallet,
  walletConfig.rpcUrl,
  logger,
);

if (approvalTxHash) {
  job.status = JobStatus.APPROVING;
  await this.waitForConfirmation(approvalTxHash, routeParameters);
  job.approvalHash = approvalTxHash;
}
[...]
  1. Executes swaps:
[...]
job.status = JobStatus.SWAPPING;
try {
  const swapResult = await executeSwap(
    selectedRoute,
    {
      address: this.config.senderAddress,
      privateKey: walletConfig.wallet.privateKey,
    },
    walletConfig.rpcUrl,
  );
  job.swapHash = swapResult.hash;
  await this.waitForConfirmation(swapResult.hash, routeParameters);
  job.status = JobStatus.COMPLETED;
[...]

Running the App

Use the following command, pointing to your chosen JSON config (e.g., rebalance-config-op-polygon.json):
pnpm run start --config=src/main/examples/rebalancing-app/rebalance-config-op-polygon.json

This will start the rebalancing application, which is loaded with the chosen configuration until it is stopped. For more details, please refer to the code and guide in the official repository.


What’s Next