Squid Dev Documentation
  • Getting Started
    • Overview
    • Get an Integrator ID
    • Integrator Quickstart
  • Widget Integration
    • Add A Widget
      • Swap widget
        • Getting Started
        • Installing the Widget
        • React Installation
        • NextJS Installation
        • Vite Installation
        • Iframe Installation
        • Customization Guide
          • Default User Settings
          • Configuring Content
          • Default Chains and Tokens
          • Configuration Types
          • Collect Fees
        • Information for Integrators
        • Set default chains and tokens via URL
        • Errors
    • Upgrade Your Widget
  • API & SDK Integration
    • API
      • Swap & Bridge Example
      • Staking Example
      • Cross-chain NFT Purchase Example
      • Get Route Status
    • SDK
      • Cross-chain Swap Example
      • Staking Example
      • Cross-chain NFT Purchase Example
      • Get Route Status
    • Key Concepts
      • Route Request Parameters
      • Get a route
      • Execute the route
      • 🪝Hooks
        • How do hooks work
        • Build a preHook
        • Build a postHook
        • Using the full ERC20 or Native balance in a call
        • ❗Transfer the remainder to the user
        • Get a route and execute as normal
      • Express
      • Track status
      • Types
      • Collect Fees
      • Get supported tokens and chains
    • Coral: Intent Swaps
      • Integrating Coral
    • NEW: Bitcoin and Solana
  • Adding Tokens
    • Whitelist a Token
    • Interchain Token(ITS) Listings
      • How To List
    • Circle's EURC Integration Guide
  • Migration
    • Squid v2 vs Squid v1
    • v1 -> v2 Migration
  • Additional Resources
    • Contracts
    • Squid v1 Docs
      • SDK
        • Installing our SDK
        • Get supported tokens and chains
          • Example chains response
          • Example tokens response
        • Set your transfer parameters
        • Get a route
          • Understanding the route response
        • Execute your swap or call
        • Get Route Status
        • Contract calls
          • Code example
          • Creating a ContractCall object
          • Contract call types
          • Approving ERC20s in our multicall
          • Transferring the remainder to a user
        • Collect Fees
          • Fee collector contract addresses
        • Working example!
      • API
        • integratorId
        • API playground
        • Base URLs
        • Get supported tokens and chains
        • Get a route
        • Checking the status of a transaction
        • Error codes
          • V2 API
      • Cosmos
        • Installing our SDK
        • Get supported tokens and chains
          • Example chains response
          • Example tokens response
        • Set your transfer parameters
        • Get a route
          • Cosmos route response
        • Execute your swap or call on Cosmos
        • Get Route Status
        • Cosmos custom calls
        • Working cosmos example!
        • Fallback Addresses
    • Additional Dev Resources
      • Choose How To Integrate Squid
      • Squid x Tenderly
      • Testnet or Mainnet?
      • Understanding Gas Payments
      • Supported Chains and Tokens
      • Request a new supported token
      • Liquidity Sources
        • axlASSET Liquidity
      • Integrator type specific docs
        • DEXs
        • Aggregators
        • NFTs
      • Setting up an EVM signer
      • Setting up Cosmos signer
      • Contract addresses
      • SDK easter eggs
        • Setting toAmount
        • getAllBalances
        • Advanced set up
        • Manually approve a route
        • Manually approve an ERC20
      • Whitelist a token
      • Security & Audits
        • Security
        • Audits
        • Axelar
      • Get an integrator-id
    • Architecture
      • FAQ
      • Liquidity model
      • Architecture
      • General message passing (GMP)
      • Transaction times and fees
      • Fallback behaviour on failed transactions
      • Axelar
    • Brand Assets
      • "Powered by Squid" Policy
    • Audits & Security
    • Contact
  • Changelog
    • SDK
      • v1.3
      • v1.2
    • API
      • v1.9
      • v1.8
      • v1.7
      • v1.6
  • Old v2 Documentation (Deprecated)
    • Whitelist a Token
    • Interchain Token(ITS) Listings
      • How To List
    • Add A Widget
      • Swap widget
        • Getting Started
        • Installing the Widget
        • React Installation
        • NextJS Installation
        • Iframe Installation
        • Customization Guide
          • Default User Settings
          • Theme Customization
          • Configuring Content
          • Default Chains and Tokens
          • Configuration Types
          • Collect fees
        • Information for Integrators
        • Set default chains and tokens via URL
        • Errors
      • Stake widget
        • Installing the Widget
        • Configuration
        • Importing The widget
    • Quick Start
    • API
      • Swap & Bridge Example
      • Staking Example
      • Cross-chain NFT Purchase Example
    • SDK
      • Cross-chain Swap Example
      • Staking Example
      • Cross-chain NFT Purchase Example
    • Key Concepts
      • Route Request Parameters
      • Get a route
      • Execute the route
      • 🪝Hooks
        • How do hooks work
        • Build a preHook
        • Build a postHook
        • Using the full ERC20 or Native balance in a call
        • ❗Transfer the remainder to the user
        • Add your hooks to a route request, or widget
        • Get a route and execute as normal
      • Boost
      • Track status
      • Types
      • Collect Fees
      • Get supported tokens and chains
Powered by GitBook
On this page
  • Working example
  • Adding the Staking transactions
  • stakeConfig structure
  1. Widget Integration
  2. Add A Widget
  3. Stake widget

Configuration

Staking widget configuration

Last updated 1 year ago

The configuration of this widget is almost the same as the Swap widget. Take a look at these docs:

  • Customization Guide

  • Theme Customization

In addtion to the standard widget config, the staking widget requires a stakeConfig.

Working example

Adding the Staking transactions

Basically the stakeConfig is here to tell the widget what happens after the cross chain swap.

Here's an example flow:

  • User wants to stake USDC on Moonbeam from BNB on Binance

  • Normal cross chain swap happens with Squid (swap to axlUSDC, bridge, swap to destination token, configured by the developer)

  • Now it's time to execute customContractCalls:

    • Give approval to SquidMultiCall to send dest token (let's say GLMR received earlier)

    • Effectively stake this amount on Moonbeam

    • Send staked token to user

The main attribute to update is customContractCalls.

You can read more about the configuration of customContractCalls here: Contract calls

stakeConfig structure

export interface StakeConfig {
  // TokenData will have all informations about the stakedToken,
  // such as symbol, image, name, chainId, etc)
  stakedToken: TokenData;
  
  // This method will be used to compute the exchange rate between the staked token and the token to stake
  // Basically a multiplier from 0 to x
  // Then if the amount that the route gets is 100, and the exchange rate is 0.5, we'll show 50 as the amount to be received for stakedToken
  // If nothing is specified, the exchange rate will be 1
  stakedTokenExchangeRateGetter?: () => Promise<number>;


  // At the moment we cannot unstake directly through the widget, 
  // If you want to tell the user that he can unstake, we'll display a link for this
  unstakeLink?: string;
  
  // Intro page is optional, it will display a page before proposing to swap,
  // This can be useful for the user to understand what will be possible
  introPage?: {
    title: string;
    logoUrl: string;
    stakingContract?: {
      address: string;
      explorerLink?: string;
    };
  };
  
  // This is mandatory, and different from stakedToken
  // This token won't be displayed but will be used to stake
  // Route will be like this: 
  // -  User selects BNB on Binance
  // -  We swap this to axlUSDC using Axelar
  // -  axlUSDC is bridged to the chainId of token below
  // -  axlUSDC is swapped to token below
  tokenToStake: {
    chainId: number | string;
    address: string;
  };
  
  // After swap/bridge is done, custom contract call can be executed
  // For example staking the "tokenToStake" into "stakedToken"
  customContractCalls: (Omit<ContractCall, "callData"> & {
    callData?: (routeVariables: CallDataGetter) => string;
  })[];
}
https://github.com/0xsquid/widget-integrations/blob/main/packages/next-app/pages/staking.tsx
import { AppConfig } from "@0xsquid/widget/widget/core/types/config";

import { SquidCallType } from "@0xsquid/sdk";
import { SquidStakingWidget } from "@0xsquid/staking-widget";
import { StakeConfig } from "@0xsquid/staking-widget/widget/core/types/config";
import { ethers } from "ethers";
import erc20Abi from "../abi/erc20Abi";
import pinjamStakingPoolAbi from "../abi/pinjamStakingPoolAbi";
import styles from "../styles/Home.module.css";

/**
 * Here you'll find an example of how to use the SquidStakingWidget.
 * @returns
 */
export default function Home() {
  // Define the staking contract config
  const kavaId = 2222;
  const pinjamAxlUsdcPoolAddress = "0x11c3d91259b1c2bd804344355c6a255001f7ba1e";
  const axlUsdcKavaAddress = "0xeb466342c4d449bc9f53a865d5cb90586f405215";
  const pAxlUsdcAddress = "0x5c91f5d2b7046a138c7d1775bffea68d5e95d68d";

  const pinjamStakingPoolInterface = new ethers.utils.Interface(
    pinjamStakingPoolAbi
  );

  const erc20Interface = new ethers.utils.Interface(erc20Abi);

  const stakeConfig: StakeConfig = {
    // This method will be used to compute the exchange rate between the staked token and the token to stake
    // Basically a multiplier from 0 to x
    // Then if the amount that the route gets is 100, and the exchange rate is 0.5, we'll show 50 as the amount to be received for stakedToken
    // If nothing is specified, the exchange rate will be 1
    stakedTokenExchangeRateGetter: async () => {
      await new Promise((res) => setTimeout(res, 5000));
      return 1;
    },

    // This link will be used to redirect the user to the unstake page, because it's not possible yet with the widget
    unstakeLink: "https://app.pinjamlabs.com/manage",

    // Here are the calls that will be called by Squid MultiCall contract after the cross chain swap is done
    customContractCalls: [
      {
        callType: SquidCallType.FULL_TOKEN_BALANCE, // Full token balance means that the MultiCall will stake all token balance it received from the swap
        target: axlUsdcKavaAddress, // Contract address
        value: "0",

        // CallData is a method instead of a static value because it could depend on the route
        callData: () => {
          return erc20Interface.encodeFunctionData("approve", [
            pinjamAxlUsdcPoolAddress,
            "0",
          ]);
        },
        payload: {
          tokenAddress: axlUsdcKavaAddress,
          inputPos: 1,
        },
        estimatedGas: "50000",
      },
      {
        callType: SquidCallType.FULL_TOKEN_BALANCE,
        target: pinjamAxlUsdcPoolAddress,
        value: "0",

        // CallData is a method instead of a static value because it could depend on the route
        // Here we can see that we use the user address as a parameter (destinationAddress)
        // It's needed as a callback because you can't know upfront what the user address will be
        // route object also offers the possibility to get other parameters like swapRoute:
        // - fromChainId?: number | string;
        // - toChainId?: number | string;
        // - fromTokenAddress?: string;
        // - toTokenAddress?: string;
        callData: (route) => {
          if (route.destinationAddress) {
            return pinjamStakingPoolInterface.encodeFunctionData("deposit", [
              axlUsdcKavaAddress,
              "0",
              route.destinationAddress,
              true,
            ]);
          }

          // If the user address is not available, we return a dummy value
          // The funds won't be sent there, but it's needed to avoid having errors when fetching data when the user is not connected
          // For example getting a quote for a staking mechanism
          return "0x0000000000000000000000000000000000000000";
        },
        payload: {
          tokenAddress: axlUsdcKavaAddress,
          inputPos: 1,
        },
        estimatedGas: "250000",
      },
    ],

    // This will be the token that the user will receive after the swap + staking
    // The coingeckoId is used to fetch the price of the token (USD price)
    stakedToken: {
      chainId: kavaId,
      address: pAxlUsdcAddress,
      name: "paxlUSDC",
      symbol: "paxlUSDC",
      decimals: 6,
      logoURI:
        "https://assets.coingecko.com/coins/images/6319/thumb/USD_Coin_icon.png?1547042389",
      coingeckoId: "usd-coin",
    },

    // Won't be seen by the user, but is needed for the config
    // This is the token that will be swapped TO
    tokenToStake: {
      chainId: kavaId,
      address: axlUsdcKavaAddress,
    },

    // The intro page is optional, but it's a good way to explain to the user what he's going to do
    // It will be displayed as the first page of the widget if it's defined
    introPage: {
      title: "Stake paxlUSDC on Kava",
      stakingContract: {
        address: "0xe5274e38e91b615d8822e8512a29a16ff1b9c4af",
        explorerLink: "https://kava.mintscan.io/account/",
      },
      logoUrl: "https://app.pinjamlabs.com/icons/pinkav.svg",
    },
  };

  const config = {
    companyName: "Test Widget",
    integratorId: "example-swap-widget",
    slippage: 3,
    instantExec: true,
    infiniteApproval: false,
    apiUrl: "https://dev.api.0xsquid.com",
    stakeConfig,
  } as AppConfig;

  return (
    <div className={styles.container}>
      <SquidStakingWidget config={config} />
    </div>
  );
}