Configuration
Staking widget configuration
Last updated
Staking widget configuration
Last updated
The configuration of this widget is almost the same as the Swap widget. Take a look at these docs:
In addtion to the standard widget config, the staking widget requires a stakeConfig
.
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
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;
})[];
}
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>
);
}