Example: Using IbAlluoUSD and Ricochet to do capital efficient DCA into ETH

This tutorial walks through how users can use IbAlluo to most capital efficiently dollar cost average into assets by constantly earning yield on both sides of the transaction.

The most capital efficient way to buy an asset

If you were to do standard DCA from USDC --> ETH, it would actually not be the most capital efficient because your assets on both sides (USDC before it is DCAed and ETH after you have DCAed) are sitting idle instead of earning yield.

Using IbAlluo can boost your returns on both sides if you were to do IbAlluoUSD --> IbAlluoETH. Your USD is earning yield with Alluo before it is converted to IbAlluoETH and your IbAlluoETH will continue to earn yield.

Ricochet Exchange has built on top of the Alluo ecosystem so that users can do exactly this, boosting DCA yields by over 5% simply by making sure that assets on both sides of the DCA stream are being used efficiently in the DeFi ecosystem.

Going from IbAlluoUSD to DCAing into IbAlluoETH

You can do this whole process without the Superfluid SDK but it simplifies the calls significantly. We recommend you use it but if you for some reason cannot use it for your project purposes, join our discord for guidance.

This tutorial assumes you know the difference between StIbAlluo and StIbAlluoUSD. Ricochet is only natively compatible with StIbAlluo so we are working with that token throughout. The user must have StIbAlluoUSD tokens rather than IbAlluoUSD to do this tutorial. There are a couple work-arounds to this, including using a contract on chain, combining approvals and wrapping from IbAlluoUSD--> StIbAlluoUSD in the batchCall etc. However here - for simplicity - we will only work with StIbAlluo (which is a simple wrapper for IbAlluo!)

1. Set up the Superfluid SDK

npm install @superfluid-finance/sdk-core

2. Set key constants and parameters

Import key dependencies, set up addresses and set up the signer.

All the Ricochet parameters are unique for each DCA pair. If you need more guidance on this , reach out on discord.

import { Signer, Wallet } from "ethers";
import { ethers} from "hardhat"
import { Framework } from "@superfluid-finance/sdk-core";

async function main() {

    // Key addresses
    const StIbAlluoUSD = "0xE9E759B969B991F2bFae84308385405B9Ab01541" 
    const StIbAlluoETH = "0x2D4Dc956FBd0044a4EBA945e8bbaf98a14025C2d";
    
    // Ric address and key ricochet parameters
    const subsidy = "0x263026E7e53DBFDce5ae55Ade22493f828922965";
    const subsidyIndex = 3;
    const inputIndex =0 ;
    const outputIndex =1;
    const twoWayMarketibAlluoUSDETHAddress = '0xD0a8aeD52e80F99F7daDa1E22369B707437b6B34';
    const userData = '0x';

    // Setup
    const provider =  ethers.provider;
    const sf = await Framework.create({
        chainId: 137, //your chainId here
        provider: provider,
      });
    let signer: Signer;
    if (typeof mneumonic !== "string") {
        return
    }
    signer = provider.getSigner();

3. Encode correct function calls

The first two operations are approving Ricochet Exchange to 'airdrop' IbAlluoETH and RIC (Ricochet native incentive tokens) to us. This is how Ricochet distributes DCA'd assets.

The last createFlow operation creates a flow of 0.00012 IbAlluoUSD per second to be DCA'd - equivalently 311.04 IbAlluoUSD per month.

Start the DCA!
const operations = [
    sf.idaV1.approveSubscription({
        superToken: StIbAlluoETH,
        indexId: outputIndex.toString(),
        publisher: twoWayMarketibAlluoUSDETHAddress,
        userData
    }),
    sf.idaV1.approveSubscription({
        superToken: subsidy,
        indexId: subsidyIndex.toString(),
        publisher: twoWayMarketibAlluoUSDETHAddress,
        userData
    }),
    sf.cfaV1.createFlow({
        superToken: StIbAlluoUSD,
        sender: wallet.address,
        receiver: twoWayMarketibAlluoUSDETHAddress,
        flowRate: "120000000000000",
        userData
    }),
];
await sf.batchCall(operations).exec(signer);

Why batchCall?

BatchCall allows us to 'batch' together multiple superfluid calls so that the user only needs to approve one transaction. Great for UX!

When do we need to approveSubscription to Ricochet?

Only the first time you start the DCA. The second time the user wants to createFlow, updateFlow or DeleteFlow, there is no need to do so. However, if the user wants to DCA into a different asset pair (say IbAlluoUSD --> IbAlluoBTC), this needs to be setup again with the appropriate parameters.

If you do not approveSubscription, you will not receive your DCA'd rewards so please ensure that you do so.

Full code snippet
import { Signer, Wallet } from "ethers";
import { ethers} from "hardhat"
import { Framework } from "@superfluid-finance/sdk-core";

async function main() {

    // Key addresses
    const StIbAlluoUSD = "0xE9E759B969B991F2bFae84308385405B9Ab01541" 
    const StIbAlluoETH = "0x2D4Dc956FBd0044a4EBA945e8bbaf98a14025C2d";
    
    // Ric address and key ricochet parameters
    const subsidy = "0x263026E7e53DBFDce5ae55Ade22493f828922965";
    const subsidyIndex = 3;
    const inputIndex =0 ;
    const outputIndex =1;
    const twoWayMarketibAlluoUSDETHAddress = '0xD0a8aeD52e80F99F7daDa1E22369B707437b6B34';
    const userData = '0x';

    // Setup
    const provider =  ethers.provider;
    const sf = await Framework.create({
        chainId: 137, 
        provider: provider,
      });
    let signer: Signer;
    if (typeof mneumonic !== "string") {
        return
    }
    signer = provider.getSigner();
    
    const operations = [
        sf.idaV1.approveSubscription({
            superToken: StIbAlluoETH,
            indexId: outputIndex.toString(),
            publisher: twoWayMarketibAlluoUSDETHAddress,
            userData
        }),
        sf.idaV1.approveSubscription({
            superToken: subsidy,
            indexId: subsidyIndex.toString(),
            publisher: twoWayMarketibAlluoUSDETHAddress,
            userData
        }),
        sf.cfaV1.createFlow({
            superToken: StIbAlluoUSD,
            sender: wallet.address,
            receiver: twoWayMarketibAlluoUSDETHAddress,
            flowRate: "120000000000000",
            userData
        }),
    ];
    await sf.batchCall(operations).exec(signer);
    }

main()
  .then(() => process.exit(0))
  .catch((error) => {
    console.error(error);
    process.exit(1);
  });

Last updated