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-rebased
branch. 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
- 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
.
- Install dependencies:
pnpm install
- Locate the Rebalancing App in
src/main/examples/rebalancing-app/
. - 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.ts
defines 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:
- 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);
}
- 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;
[...]
- 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;
}
[...]
- 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.
Updated 20 days ago