@swivel-finance/illuminate-js
TypeScript icon, indicating that this package has built-in type declarations

2.0.0 • Public • Published
╭╮╭╮ ╭╮            ╭╮           ╭╮            ╭╮      
╰╯││ ││            ╰╯           ││            ╰╯      
╭╮││ ││ ╭╮ ╭╮╭────╮╭╮╭───╮╭───╮╭╯╰╮╭───╮      ╭╮╭────╮
││││ ││ ││ │││╭╮╭╮││││╭─╮│╰──╮│╰╮╭╯│╭─ │ ╭──╮ │││╭───╯
││││ ││ ││ ││││││││││││ ││╭──╯│ ││ │╭──╯ ╰──╯ ││╰────╮
│││╰╮│╰╮│╰─╯│││││││││││ │││╰─ ╰╮│╰╮│╰───╮    ╭╯│╭───╯│
╰╯╰─╯╰─╯╰───╯╰╯╰╯╰╯╰╯╰╯ ╰╯╰────╯╰─╯╰────╯    ╰─╯╰────╯

TypeScript library for working with the Illuminate Protocol

Installation

Installing ethers

In order use illuminate-js you'll need a compatible version (^5.2.0) of ethers. Being a peer dependency, you can use any compatible version of ethers you already have installed in your project.

If you haven't installed a compatible version of ethers in your project yet, run:

npm install --save ethers

Installing illuminate-js

npm install --save @swivel-finance/illuminate-js

Quickstart

illuminate-js provides TypeScript implementations for the 3 main contracts of the Illuminate protocol:

  • MarketPlace:
    • Retrieve market information (iPT and pool addresses).
    • Buy and sell iPTs using Illuminate's secondary on-chain markets (YieldSpace AMM).
  • Lender:
    • Mint Illuminate's Principal Token (iPT) by depositing external/integrated Principal Tokens you already own.
    • Lend underlying to one of 8 supported lending protocols through Illuminate and receive Illuminate's Principal Token (iPT).
  • Redeemer:
    • Redeem your Illuminate Principal Tokens (iPT) for underlying.

In addition, illuminate-js provides TypeScript implementations for Illuminate's Strategy and StrategyRouter contracts. These contracts allow you to pool your Principal Tokens (iPT) in exchange for Strategy Shares, which earn additional yield, support auto-rollover and can be burned for underlying at any time.

Usage

Principals

Illuminate lets you lend to 8 different lending protocols to ensure you always get the best possible rate. Each of these protocols is referred to as a Principal. You can select a Principal using the Principals enum:

import { Principals } from '@swivel-finance/illuminate-js';

const principal = Principals.Swivel;

or you can use the Principal's numeric value:

/**
 * The Principal's numeric values
 * 
 * Illuminate = 0
 * Swivel     = 1
 * Yield      = 2
 * Pendle     = 3
 * APWine     = 4
 * Notional   = 5
 * Exactly    = 6
 * Term       = 7
 */ 
 
const principal = 3; // Pendle

Lend on Illuminate

When lending on Illuminate, you will receive Illuminate's Principal Tokens (iPT) in exchange for your underlying, regardless of which Principal/Protocol you lend to.

Make sure to also approve the Lender contract to spend your underlying before lending.

Lending to a protocol of your choice
import { Lender, Principals } from '@swivel-finance/illuminate-js';
import ethers from 'ethers';

// you'll need the address of the deployed Lender contract
const LENDER_ADDRESS = '0xILLUMINATE_LENDER_ADDRESS';

// create an ethers signer to perform payable transactions
const provider = new ethers.providers.Web3Provider(window.ethereum);
const signer = provider.getSigner();

// create an instance of the Lender constract
const lender = new Lender(LENDER_ADDRESS, signer);

// specify the market you want to lend on and the amount you want to lend
const underlying = '0xUNDERLYING_TOKEN_ADDRESS';
const maturity = '1735448400';
const amount = ethers.utils.parseEther('100').toString();

// depending on the protocol you want to lend on, different params are required
// the Lender contract source documents the required params for each principal
// here, we will lend to Yield, which requires a yieldspace pool address and a 
// minimum amount of principal tokens to mint (a slippage protection)
const principal = Principals.Yield;
const pool = '0xPOOL_ADDRESS';
const minimum = ethers.utils.parseEther('99').toString();

// if this is your first time lending this underlying, you'll need to approve
// the Lender contract to spend your underlying (see in the next section)

// lend your underlying to the protocol of your choice
const result = await lender.lend(principal, underlying, maturity, amount, [pool, minimum]);
Approving the Lender contract to spend your underlying

If you're lending a specific underlying for the first time, you'll need to approve the Lender contract to spend your underlying. You can do this by calling the approve method on your underlying's token contract - illuminate-js provides an ERC20 implementation for this purpose:

import { ERC20 } from '@swivel-finance/illuminate-js';
import ethers from 'ethers';

// you'll need the address of the deployed Lender contract
const LENDER_ADDRESS = '0xILLUMINATE_LENDER_ADDRESS';

// you'll need the address of the underlying token you want to lend
const underlying = '0xUNDERLYING_TOKEN_ADDRESS';

// create an ethers signer to perform payable transactions
const provider = new ethers.providers.Web3Provider(window.ethereum);
const signer = provider.getSigner();

// create an instance of the ERC20 constract
const token = new ERC20(underlying, signer);

// you can choose to approve the maximum amount of underlying if you
// don't want to approve the Lender contract again in the future
// or just approve the amount you want to lend this time
const amount = ethers.constants.MaxUint256;

// approve the Lender contract to spend your underlying
const result = await token.approve(LENDER_ADDRESS, amount);
Lending to the protocol with the best rate

The previous examples assume you know which Protocol/Principal you want to lend to. You can always use https://app.illuminate.finance/ to find the best rate for your underlying. Alternatively, you can request a quote from Illuminate's public API to find the best rate for your underlying.

Check out our API documentation for more details.

In general, the quotes endpoint will return an array of Quotes, each containing the following information:

export interface Quote<T = QuoteMeta> {
    principal: Principals;
    maturity: string;
    amount: string;
    fee: string;
    apr: string;
    underlying: {
        address: string;
        decimals: number;
    };
    pt: {
        address: string;
        decimals: number;
        maturity: string;
        amount: string;
        meta?: T;
    },
}

export type QuoteMeta = {
    [key: string]: unknown;
};

The QuoteMeta is left generic, as it will be different for each Principal. For example, the QuoteMeta for the Principals.Yield protocol will contain the poolAddress parameter required by the Lender contract:

export type YieldQuoteMeta = {
    poolAddress: string;
};

To fetch the quotes for your underlying, make a GET request to the quotes endpoint:

const fetchQuotes = async (underlying: string, maturity: string, amount: string): Promise<Quote[]> => {

    // you'll need Illuminate's public API URL (see API docs)
    const API_URL = 'https://illumigate.swivel.exchange/v3/';
    
    // the endpoint for fetching quotes
    const endpoint = 'quotes';

    // the params for the quotes endpoint
    const params = {
        underlying, // e.g.: 0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48 (USDC)
        maturity,   // e.g.: 1735448400 (December 29, 2024)
        amount,     // e.g.: 20000000 (20 USDC)
    };

    // the request init object for the fetch call
    const init: RequestInit = {
        method: 'GET',
        headers: {
            'accept': 'application/json',
        },
    };

    const url = new URL(`${ API_URL }${ endpoint }`);

    url.search = new URLSearchParams(params).toString();

    const response = await fetch(url, init);

    const quotes = await response.json();

    return quotes;
};

With the list of quotes, you can find the best rate/quote for your underlying by comparing the apr of each quote:

const bestQuote = (quotes: Quote[]): Quote => {

    let best = quotes[0];

    quotes.forEach(quote => {

        const apr = parseFloat(quote.apr ?? '0');

        if (parseFloat(best.apr ?? '0') < apr) {

            best = quote;
        }
    });

    return best;
};

const quotes = await fetchQuotes(underlying, maturity, amount);

const best = bestQuote(quotes);

Once you have the best quote, you can lend to the protocol with the best rate:

import { Lender } from '@swivel-finance/illuminate-js';
import ethers from 'ethers';

// you'll need the address of the deployed Lender contract
const LENDER_ADDRESS = '0xILLUMINATE_LENDER_ADDRESS';

// create an ethers signer to perform payable transactions
const provider = new ethers.providers.Web3Provider(window.ethereum);
const signer = provider.getSigner();

// create an instance of the Lender constract
const lender = new Lender(LENDER_ADDRESS, signer);

// specify the market you want to lend on and the amount you want to lend
const underlying = '0xUNDERLYING_TOKEN_ADDRESS';
const maturity = '1735448400';
const amount = ethers.utils.parseEther('100').toString();

// specify your slippage protection (minimum amount of PTs to return)
const minimum = ethers.utils.parseEther('99').toString();

// get the quotes for your selected market and amount
const quotes = await fetchQuotes(underlying, maturity, amount);

// find the best quote
const best = bestQuote(quotes);

// assuming the best quote is for the Yield protocol, you can now lend like this:
const response = await lender.lend(
    quote.principal,
    quote.underlying.address,
    quote.maturity,
    quote.amount,
    [
        (quote.pt.meta as YieldQuoteMeta).poolAddress,
        minimum,
    ],
);

Redeem on Illuminate

Because Illuminate mints its own Illuminate Principal Tokens (iPT) when you lend, you'll only need to redeem your iPT at maturity, regardless of which Principal/Protocol you lent to. In fact, your lend position can be composed of multiple different Principals, and you'll still only need to redeem your iPT at maturity.

Redeeming matured positions
import { Redeemer, Principals } from '@swivel-finance/illuminate-js';
import ethers from 'ethers';

// you'll need the address of the deployed Redeemer contract
const REDEEMER_ADDRESS = '0xILLUMINATE_REDEEMER_ADDRESS';

// create an ethers signer to perform payable transactions
const provider = new ethers.providers.Web3Provider(window.ethereum);
const signer = provider.getSigner(); 

// create an instance of the Redeemer constract
const redeemer = new Redeemer(REDEEMER_ADDRESS, signer);

// specify the market you want to redeem from
const underlying = '0xUNDERLYING_TOKEN_ADDRESS';
const maturity = '1735448400';

// redeem your Illuminate Principal Tokens (iPT)
// NOTE: Illuminate will always redeem your entire iPT balance
const result = await redeemer.redeem(Principals.Illuminate, underlying, maturity);
Redeeming un-matured positions

Illuminate Principal Tokens (iPT) can only be redeemed after maturity. However, you can sell your iPT using Illuminate's secondary on-chain markets, utilizing YieldSpace's AMM. You can use the MarketPlace contract to do this:

Make sure to also approve the MarketPlace contract to spend your iPT before selling.

import { MarketPlace } from '@swivel-finance/illuminate-js';
import ethers from 'ethers';

// you'll need the address of the deployed MarketPlace contract
const MARKETPLACE_ADDRESS = '0xILLUMINATE_MARKETPLACE_ADDRESS';

// create an ethers signer to perform payable transactions
const provider = new ethers.providers.Web3Provider(window.ethereum);
const signer = provider.getSigner(); 

// create an instance of the MarketPlace constract
const marketplace = new MarketPlace(MARKETPLACE_ADDRESS, signer);

// specify the market...
const underlying = '0xUNDERLYING_TOKEN_ADDRESS';
const maturity = '1735448400';
// ...the amount of iPT you want to sell...
const amount = ethers.utils.parseEther('100').toString();
// ...and the minimum amount of underlying you want to receive (slippage cap)
const minimum = ethers.utils.parseEther('99').toString();

// if this is your first time selling this market's iPT, you'll need to approve
// the MarketPlace contract to spend your iPT (see in the next section)

// sell your Illuminate Principal Tokens (iPT)
const result = await marketplace.sellPrincipalToken(underlying, maturity, amount, minimum);
Approving the MarketPlace contract to spend your iPT

If you're selling a specific iPT for the first time, you'll need to approve the MarketPlace contract to spend your iPT. You can do this by calling the approve method on your iPT's token contract - illuminate-js provides an ERC20 implementation for this purpose:

import { ERC20 } from '@swivel-finance/illuminate-js';
import ethers from 'ethers';

// you'll need the address of the deployed MarketPlace contract
const MARKETPLACE_ADDRESS = '0xILLUMINATE_MARKETPLACE_ADDRESS';

// you'll need the address of the Illuminate Principal Token (iPT) 
// you want to sell
const ipt = '0xIPT_ADDRESS';

// create an ethers signer to perform payable transactions
const provider = new ethers.providers.Web3Provider(window.ethereum);
const signer = provider.getSigner();

// create an instance of the ERC20 constract
const token = new ERC20(ipt, signer);

// you can choose to approve the maximum amount of ipt if you don't 
// want to approve the MarketPlace contract again in the future
// or just approve the amount you want to sell this time
const amount = ethers.constants.MaxUint256;

// approve the MarketPlace contract to spend your iPT
const result = await token.approve(MARKETPLACE_ADDRESS, amount);

Deployed Contract Addresses

You can find the currently deployed illuminate contract addresses here: https://github.com/Swivel-Finance/illuminate#current-deployments

Other Providers

You can use ethers.js to connect to the Ethereum network in different ways, not only using MetaMask. Please refer to the ethers.js documentation for different ways to connect: https://docs.ethers.io/v5/getting-started/#getting-started--connecting.

Once you have created a provider and a signer, creating a MarketPlace, Lender or Redeemer instance is identical to the steps illustrated above.

Package Sidebar

Install

npm i @swivel-finance/illuminate-js

Weekly Downloads

3

Version

2.0.0

License

MIT

Unpacked Size

664 kB

Total Files

204

Last publish

Collaborators

  • swivel-finance