The Automated Portfolio Manager automatically rebalances an investment portfolio using real-time data from on-chain and off-chain sources. These contracts enable adjustments in asset allocations within a portfolio based on dynamic market conditions, sentiment scores, and volatility indicators such as the Gold Volatility Index (GVZ). This approach provides a modern way to manage digital assets.
A live demo is available at https://automated-portfolio-manager.vercel.app.
The example contract supports dynamic asset management using tokens that adhere to the ERC20 standard. For this demonstration, Mimic Tokens representing gold (mXAU), Wrapped Bitcoin (mWBTC), and Ethereum (mETH) are used as the underlying assets. These tokens are automatically bought or sold to mirror changes in crypto market sentiment and gold volatility (GVZ) to ensure the portfolio adjusts to evolving market conditions. This functionality demonstrates how blockchain and Chainlink technologies can be used to create a dynamic investment strategy that adapts to global financial movements in real-time.
Note: In a real-world use case, you can integrate the portfolio rebalancing mechanism with any DeFi protocol, such as a swapping mechanism, investments in ERC-4626 vaults, etc.
-
This tutorial represents an educational example to use a Chainlink system, product, or service and is provided to demonstrate how to interact with Chainlink’s systems, products, and services to integrate them into your own. This template is provided “AS IS” and “AS AVAILABLE” without warranties of any kind, it has not been audited, and it may be missing key checks or error handling to make the usage of the system, product or service more clear. Do not use the code in this example in a production environment without completing your own audits and application of best practices. Neither Chainlink Labs, the Chainlink Foundation, nor Chainlink node operators are responsible for unintended outputs that are generated due to errors in code.
-
The rebalancing strategy and logic outlined in this tutorial are solely for educational purposes and have not been backtested. This content is not meant to be financial advice and should not be interpreted as such. The example is intended to demonstrate the potential of Chainlink products. Users are strongly advised to perform their own due diligence before making any financial decisions.
- Requirements
- Project setup
OffchainDataFetcherdeployment and setupAutomatedPortfolioManagerdeployment and setup- Run the dApp locally
-
Git: Make sure you have Git installed. You can check your current version by running
git --versionin your terminal and download the latest version from the official Git website if necessary. -
Foundry: This guide requires Foundry. Follow the instructions in the Foundry documentation to install it.
-
Nodejs and npm: Install the latest release of Node.js 20. Note: To ensure you are running the correct version in a terminal, type
node -v.node -v v20.11.0
-
RPC URL: You need a Remote Procedure Call (RPC) URL for the Ethereum Sepolia network. You can obtain one by creating an account on Alchemy or Infura and setting up an Ethereum Sepolia project.
-
Private key: You need the private key of the account that will deploy and interact with the contracts. If you use MetaMask, follow the instructions to Export a Private Key.
-
Testnet funds: This guide requires testnet ETH, LINK, and USDC on Ethereum Sepolia.
- Get Sepolia testnet ETH and LINK at faucets.chain.link.
- Get Sepolia testnet USDC at faucet.circle.com.
-
Etherscan API Key: An API key to verify your deployed contracts on the Etherscan block explorer.
-
CryptoCompare API key: You need an API key to fetch BTC and ETH trading signals from CryptoCompare. Create one for free at CryptoCompare. Select the Poll Live and Historical Data permission level within the Read All Price Streaming and Polling Endpoints dropdown menu.
-
MarketData token: You need a valid token from MarketData to fetch the GVZ index value. Create a free account and generate a token.
-
Chainlink Functions subscription: A Chainlink Functions subscription is required for this guide. If you do not already have a subscription, you can create one using the Chainlink Functions UI.
-
Clone and navigate to the repository:
git clone https://github.com/smartcontractkit/quickstarts-automated-portfolio-manager.git cd quickstarts-automated-portfolio-manager -
Install the front-end and back-end dependencies:
make install
-
Copy the
.env.examplefile to.env:cp .env.example .env
-
Open your
.envfile and fill in the required environment variables. -
Run
source .envto make your environment variables available in your terminal session.source .env -
Run
forge compileto update dependencies in thelibfolder.forge compile
Expect an output similar to the following in your terminal:
[⠔] Compiling... [⠰] Compiling 54 files with 0.8.19 [⠔] Solc 0.8.19 finished in 1.82s Compiler run successful!
Run the following script to deploy your OffchainDataFetcher contract on Ethereum Sepolia:
forge script script/DeployOffChainDataFetcher.s.sol --rpc-url $RPC_URL_SEPOLIA --private-key $PRIVATE_KEY --broadcast --verify -vvvv-
Open the
functions/updateRequestDon.jsscript and update thesubscriptionIdvariable with your Chainlink Functions subscription ID. -
Fund your Functions subscription with at least 5 testnet LINK (Chainlink Functions UI).
-
Run the following script to update the
OffchainDataFetcherFunctions request with DON-hosted Secrets:node functions/updateRequestDon.js
Expect output similar to the following in your terminal:
Make request... Upload encrypted secret to gateways https://01.functions-gateway.testnet.chain.link/,https://02.functions-gateway.testnet.chain.link/. slotId 1. Expiration in minutes: 4320 ✅ Secrets uploaded properly to gateways https://01.functions-gateway.testnet.chain.link/,https://02.functions-gateway.testnet.chain.link/! Gateways response: { version: 1717010963, success: true } ✅ Automated Functions request settings updated! Transaction hash 0xfaafcfcbb42163679681d189af6e777b36df4ec7a6d2cf14aea6fe220be0899e - Check the explorer https://sepolia.etherscan.io/tx/0xfaafcfcbb42163679681d189af6e777b36df4ec7a6d2cf14aea6fe220be0899e
Note: On testnets, DON-hosted secrets have a maximum Time to Live (TTL) of 72 hours. If you need to extend the TTL beyond this period, consider using secrets hosted in your own GitHub gists for your requests. For this approach, include your
GITHUB_API_TOKENin your.envfile and use theupdateRequestGists.jsscript instead ofupdateRequestDon.js. -
Add your
OffChainDataFetchercontract as a consumer in your Functions subscription (Chainlink Functions UI). Note: You can find your deployedOffchainDataFetchercontract address inoutput/deployedOffchainDataFetcher.json.
-
Register an upkeep to call the
sendRequestCBORfunction on yourOffchainDataFetchercontract daily:- Go to the Chainlink Automation UI.
- Create a Time-based upkeep that targets the
sendRequestCBORfunction. - To run the upkeep daily at 3 AM UTC, use the following CRON expression:
0 3 * * *. - Set the gas limit to
1000000. - Fund your upkeep with 5 testnet LINK.
Note: You can find your deployed
OffchainDataFetchercontract address inoutput/deployedOffchainDataFetcher.json. -
Configure your contract so only the upkeep contract (and your admin account, which deployed the contract) can call the
sendRequestCBORfunction. This security measure is important to prevent anyone from calling several timessendRequestCBORand draining your Functions subscription balance.- Go to Etherscan.
- Enter your
OffchainDataFetchercontract address in the search bar. Note: This address is available inoutput/deployedOffchainDataFetcher.json. - Select the
Contractsection, then click on theWrite Contracttab. - Connect your admin account, which is the wallet you used to deploy the contract.
- Call the
setAutomationCronContractfunction with theUpkeep addressas the input parameter. Note: You can find theUpkeep addressin the Details section of your upkeep in the Automation UI.
Run the following script to deploy your AutomatedPortfolioManager contract on Ethereum Sepolia:
forge script script/DeployAutomatedPortfolioManager.s.sol --rpc-url $RPC_URL_SEPOLIA --private-key $PRIVATE_KEY --broadcast --verify -vvvv-
Go to the Chainlink Automation UI.
-
Create a new Custom logic upkeep with a starting balance of 5 testnet LINK. Note: You can find your deployed
AutomatedPortfolioManagercontract address inoutput/deployedPortfolioManager.json. -
Configure your contract so only the upkeep contract (and your admin account, which deployed the contract) can call the
performUpkeepfunction. This security measure is important to prevent anyone from calling several timesperformUpkeepand draining your Automation balance.- Go to Etherscan.
- Enter your
AutomatedPortfolioManagercontract address in the search bar. Note: This address is available inoutput/deployedPortfolioManager.json. - Select the
Contractsection, then click on theWrite Contracttab. - Connect your admin account, which is the wallet you used to deploy the contract.
- In the function inputs, enter the
Forwarder addressinto thesetAutomationUpkeepForwarderContractfunction. Note: You can find theForwarder addressin the Details section of your upkeep in the Automation UI.
-
Navigate to the
appfolder:cd app -
Run the dApp locally:
npm run dev
-
Navigate to
http://localhost:3000with your favorite browser. -
Change tab to
My Investment. -
Connect your wallet.
-
Enter the amount of testnet USDC you want to invest and click
Invest.
Note: The initial assets allocation is 40% mXAU, 30% mWBTC, and 30% mETH. You can wait until the next scheduled time-based upkeep at 3 AM UTC to fetch the latest data and make it available in your OffchainDataFetcherContract. Your custom upkeep will then automatically rebalance the portfolio. Alternatively, you can call the sendRequestCBOR function on your OffchainDataFetcherContract on Etherscan with your admin account to initiate the first rebalance.
