Portfolio Management API

Overview

The Velvet Portfolio Management API enables you to manage and rebalance tokenized portfolios (vaults) programmatically. With this API, you can:

  • Retrieve and inspect all portfolios (vaults) created by a given owner.

  • Rebalance portfolios by selling one token and buying another.

  • Execute trades using on-chain calls.

  • Deposit and withdraw tokens from portfolios.

  • Obtain helper information, such as the number of portfolio tokens a user holds.

This guide will walk you through key endpoints and illustrate how to integrate the provided data and call parameters into your applications.


Prerequisites

  • A wallet with a private key to sign blockchain transactions.

  • A JSON-RPC provider URL for your target chain (for instance, Base chain with chainId = 8453).

  • Familiarity with Ethereum-compatible contracts, tokens, and basic web3 concepts.


Trade Flow Overview

To execute a trade withing a Velvet portfolio (vault), follow these steps:

  1. Fetch All Created Vaults: Retrieve all portfolios (vaults) associated with a specific owner.

  2. Use the Rebalance API Endpoint: Generate the necessary call data and parameters for the intended trade.

  3. Execute the Trade On-Chain: Use the parameters from the Rebalance API to call the vault’s rebalance contract function.


Fetch All Created Vaults

Endpoint: GET https://api.velvet.capital/api/v3/portfolio/owner/<OWNER_WALLET_ADDRESS>?chain=base

Description: Retrieves all vaults created by a specified owner on the Velvet V3 platform.

URL Parameters:

  • OWNER_WALLET_ADDRESS (string): The Ethereum address of the owner.

Response:

Copy

jsonCopy code{
  "data": [
    {
      "portfolioId": "string",
      "portfolio": "string",
      "name": "string",
      "symbol": "string",
      "public": true,
      "initialized": true,
      "confirmed": true,
      "tokenExclusionManager": "string",
      "rebalancing": "string",       // ← Use this address in next steps
      "owner": "string",
      "assetManagementConfig": "string",
      "accessController": "string",
      "feeModule": "string",
      "vaultAddress": "string",
      "gnosisModule": "string",
      "whitelistedUsers": [],
      "whitelistedTokens": [],
      "whitelistAccessGrantedUsers": [],
      "assetManagerAccessGrantedUsers": [],
      "chainID": 8453,
      "chainName": "base",
      "txnHash": "string",
      "createdAt": "Date",
      "updatedAt": "Date",
      "creatorName": "string",
      "description": "string",
      "avatar": "string"
    }
  ]
}

Usage: From the response, note the rebalancing address, which will be needed to prepare the trade in the next step.


Rebalance API Endpoint

Endpoint: POST https://eventsapi.velvetdao.xyz/api/v3/rebalance

Description: Generates the necessary parameters (call data, handler address, etc.) to execute a trade within a portfolio’s rebalance contract.

Request Body:

Copy

jsonCopy code{
  "rebalanceAddress": "string",
  "sellToken": "string",
  "buyToken": "string",
  "sellAmount": "string",
  "slippage": "string",
  "remainingTokens": ["string"],
  "owner": "string"
}

Parameters:

  • rebalanceAddress (string, required): The rebalance contract address retrieved from the "Fetch All Created Vaults" response.

  • sellToken (string, required): The token address you want to sell.

  • buyToken (string, required): The token address you want to buy.

  • sellAmount (string, required): The amount of sellToken to sell (in smallest unit, e.g., if USDC is 6 decimals, 1 USDC = 1000000).

  • slippage (string, required): Allowed slippage in basis points. For example, "100" means 1%.

  • remainingTokens (array, required): The list of tokens that will remain in the vault after the trade.

  • owner (string, required): The vault owner’s Ethereum address.

Response:

Copy

jsonCopy code{
  "newTokens": ["string"],
  "sellTokens": ["string"],
  "sellAmounts": ["string"],
  "handler": "string",
  "callData": "string",
  "estimateGas": "string",
  "gasPrice": "string"
}

Note: Use the returned data (newTokens, sellTokens, sellAmounts, handler, and callData) to execute the trade in the next step.


Executing the Trade On-Chain

After obtaining the necessary parameters from the Rebalance API, you can execute the trade by interacting directly with the rebalance contract on-chain.

Prerequisite: Install Ethers.js:

Copy

bashCopy codenpm install [email protected]

Example Code:

Copy

javascriptCopy codeimport { ethers } from 'ethers'

const provider = new ethers.providers.JsonRpcProvider('<RPC_URL>')
const privateKey = '<OWNER_WALLET_PRIVATE_KEY>'
const wallet = new ethers.Wallet(privateKey, provider)

const RebalanceABI = [
  {
    inputs: [
      {
        components: [
          { internalType: 'address[]', name: '_newTokens', type: 'address[]' },
          { internalType: 'address[]', name: '_sellTokens', type: 'address[]' },
          { internalType: 'uint256[]', name: '_sellAmounts', type: 'uint256[]' },
          { internalType: 'address', name: '_handler', type: 'address' },
          { internalType: 'bytes', name: '_callData', type: 'bytes' }
        ],
        internalType: 'struct FunctionParameters.RebalanceIntent',
        name: 'rebalanceData',
        type: 'tuple'
      }
    ],
    name: 'updateTokens',
    outputs: [],
    stateMutability: 'nonpayable',
    type: 'function'
  }
]

const RebalanceInstance = new ethers.Contract(
  'VAULT_REBALANCING_ADDRESS',
  RebalanceABI,
  wallet
)

async function executeRebalance(newTokens, sellTokens, sellAmounts, handler, callData, estimateGas, gasPrice) {
  try {
    console.log('Executing Trade...')
    const tx = await RebalanceInstance.updateTokens(
      {
        _newTokens: newTokens,
        _sellTokens: sellTokens,
        _sellAmounts: sellAmounts,
        _handler: handler,
        _callData: callData
      },
      {
        gasLimit: ethers.BigNumber.from(estimateGas).add('1000000'),
        gasPrice: gasPrice
      }
    )

    console.log('Transaction successful:', tx)
  } catch (error) {
    console.error('Transaction failed:', error)
  }
}

Rebalance Transaction API

Endpoint: POST https://eventsapi.velvetdao.xyz/api/v3/rebalance/txn

Description: Initiates a rebalance transaction directly. Useful when you already know the parameters required to perform the rebalance.

Request Body:

Copy

jsonCopy code{
  "rebalanceAddress": "0x19bc26a8e42727a2567d244cca344ceddd0493ae",
  "sellToken": "0x833589fcd6edb6e08f4c7c32d4f71b54bda02913",
  "buyToken": "0xb6fe221fe9eef5aba221c348ba20a1bf5e73624c",
  "sellAmount": "883373",
  "slippage": "100",
  "remainingTokens": [
    "0xb6fe221fe9eef5aba221c348ba20a1bf5e73624c",
    "0xc1CBa3fCea344f92D9239c08C0568f6F2F0ee452"
  ],
  "owner": "0x86F91b660a5432CE4654D84B3AbAD38A6645425e"
}

Parameters:

  • Similar to the Rebalance API Endpoint (above), but returns direct transaction data for immediate execution.


Portfolio Deposit API

Endpoint: POST https://eventsapi.velvetdao.xyz/api/v3/portfolio/deposit

Description: Deposits a specified amount of tokens into a given portfolio.

Request Body:

Copy

jsonCopy code{
  "portfolio": "0x444ef5b66f3dc7f3d36fe607f84fcb2f3a666902",
  "depositAmount": "1000000",
  "depositToken": "0x50c5725949A6F0c72E6C4a641F24049A917DB0Cb",
  "user": "0x3C96e2Fc58332746fbBAB5eC44f01572F99033ed",
  "depositType": "batch",
  "tokenType": "erc20"
}

Parameters:

  • portfolio: The portfolio contract address.

  • depositAmount: The amount to deposit (in token’s smallest unit).

  • depositToken: The token’s contract address being deposited.

  • user: The depositor’s Ethereum address.

  • depositType: The deposit mode (e.g., batch).

  • tokenType: The type of token (e.g., erc20).

Response: Returns transaction data (to, data, gasLimit, gasPrice) needed to broadcast the transaction.

Example Code: After approval, send the returned transaction data via wallet.sendTransaction(tx).


Portfolio Withdraw API

Endpoint: POST https://eventsapi.velvetdao.xyz/api/v3/portfolio/withdraw

Description: Initiates a withdrawal from a specified portfolio.

Request Body:

Copy

jsonCopy code{
  "portfolio": "0xc4dc922c90d44d07ea5d1aa8c08253ebc17e42c2",
  "withdrawAmount": "8999999999989636786",
  "withdrawToken": "0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913",
  "user": "0x86F91b660a5432CE4654D84B3AbAD38A6645425e",
  "withdrawType": "batch",
  "tokenType": "erc20"
}

Parameters:

  • portfolio: The portfolio address.

  • withdrawAmount: The withdrawal amount (in smallest unit).

  • withdrawToken: The token address to withdraw.

  • user: The user’s Ethereum address initiating the withdrawal.

  • withdrawType: The withdrawal mode (e.g. batch).

  • tokenType: The type of token (e.g., erc20).

Response: Returns transaction data needed to finalize the withdrawal transaction on-chain.

Edge Case: If the portfolio contains only one token and the user wishes to withdraw that same token, use the multiTokenWithdrawalfunction from the portfolio contract’s ABI.


Helper Functions

Get Portfolio Token Amount

Function: getPortfolioTokenAmount(portfolioAddress, account, chainId=8453)

Description: Returns the number of portfolio tokens a user holds.

Example:

Copy

javascriptCopy codeexport const getPortfolioTokenAmount = async (portfolioAddress, account, chainId = 8453) => {
  try {
    const web3 = getWeb3Provider(chainId);
    const ContractInstance = new web3.eth.Contract(
      portfolio_abi,
      portfolioAddress
    );
    const contractData = await ContractInstance.methods.balanceOf(account).call();
    return web3.utils.fromWei(contractData, 'ether');
  } catch (error) {
    console.log(error, 'error');
  }
};

Conclusion

With the endpoints and code samples provided, you should be able to:

  • Discover and manage all your Velvet vaults.

  • Programmatically prepare and execute trades through the Rebalance interface.

  • Deposit and withdraw tokens from portfolios.

  • Monitor and query token amounts within portfolios.

For a seamless integration, ensure you handle proper token approvals and confirm transactions on-chain. By following these guidelines and examples, you can fully leverage the Velvet Portfolio Management API.

Happy coding!

Last updated