Common SDK Error Messages

If you're encountering issues with our SDK, this guide will help you understand some of our common SDK error messages.

Chain is not available

This error occurs when the connect() function in the SDK throws an error:

await swingSDK.wallet.connect(window.ethereum, chainSlug);

Error Message

Error: Chain is not available. Please try a different chain.

If you encounter a "Chain is not available" error, it could mean one of three reasons:

  • The value of the supplied chainSlug parameter in the wallet.connect() function is incorrect:
const chainSlug = 'polygo'; // <- incorrect chain slug, the presumed chain slug here would have been `polygon`
 
const swingSDK = new SwingSDK({
  projectId: 'replug',
  environment: 'production',
  debug: true,
});
 
await swingSDK.init();
 
await swingSDK.wallet.connect(window.ethereum, chainSlug);
  • The value of the supplied chainSlug parameter in the wallet.connect() function is correct but however, the chain has been disabled by Swing.

  • The value of the supplied chainSlug parameter in the wallet.connect() function is correct but has been disabled in your projects rules configurations.

Chain Is Not Supported

This error occurs when the getQuote() function in the SDK throws an error. It indicates that the supplied fromChain or toChain slug value is not available on Swing:

const quotes = await swingSDK.getQuote(transferParams);

Error Message

[Chain Slug] chain is not supported in [Enviromment]
 
(example: Rubik is Not supported in production)

If you encounter a "Chain Is Not Supported" error, it could mean one of three reasons:

  • The value of the supplied fromChain or toChain parameter in the quote transferParams object is incorrect:
const transferParams: TransferParams = {
  amount: '1',
  fromChain: 'polygons', // <- incorrect chain slug, the presumed chain slug here would have been `polygon`
  fromToken: 'MATIC',
  fromUserAddress: '',
  toChain: 'polygon',
  toToken: 'USDC',
  toUserAddress: '',
};
 
const quotes = await swingSDK.getQuote(transferParams);
  • The value of the supplied fromChain or toChain parameter in the quote transferParams object is correct but however, the chain has been disabled by Swing.

  • The value of the supplied fromChain or toChain parameter in the quote transferParams object is correct but has been disabled in your projects rules configurations.

Token Is Not Supported

This error occurs when the getQuote() function in the SDK throws an error. It indicates that the supplied token slug on the connected chain is not available on Swing:

const quotes = await swingSDK.getQuote(transferParams);

Error Message

[Token Slug] token is not supported on [Chain Slug] in [Enviromment]
 
(example: USDB token is not supported on Ethereum in production)

If you encounter a "Token Is Not Supported" error, it could mean one of three reasons:

  • The supplied fromToken or toToken parameter in the quote transferParams object is incorrect:
const transferParams: TransferParams = {
  amount: '1',
  fromChain: 'polygon',
  fromToken: 'MATI', // <- incorrect token slug, the presumed token slug here would have been `MATIC`
  fromUserAddress: '',
  toChain: 'polygon',
  toToken: 'USDC',
  toUserAddress: '',
};
 
const quotes = await swingSDK.getQuote(transferParams);
  • The value of the supplied fromToken or toToken parameter in the quote transferParams object is correct but however, the token has been disabled by Swing

  • The value of the supplied fromToken or toToken parameter in the quote transferParams object is correct but has been disabled in your projects rules configurations

Transfer Failed

This error occurs when the transfer() function in the SDK throws an error:

await swingSDK.transfer(route, transferParams);

It is important to note that sending a transaction to the blockchain is an asynchronous process. Therefore, you can only receive real-time updates on the status of your transaction by listening to the SDK's internal event listener:

swingSDK.on('TRANSFER', async (transferStepStatus, transferResults) => {
  console.log('TRANSFER:', transferStepStatus, transferResults);
});

When you execute the transfer() function, your pending transactions goes through four (4) phases/steps, each step has a corresponding transaction status attached to it:

StepDescription
AllowanceSwing is instructed on the amount of allocated tokens to be swapped or bridged.
ApprovalThe user must sign the approval transaction using their wallet for the process to continue.
SendSwing will proceed to bridge or swap the approved tokens.
BridgeThe assets have been received by Swing and will be swapped or bridged to the destination chain.

The Allowance and Approval steps are optional and only required when the source token (fromToken) is an ERC20 token.

The event listener's callback function receives two arguments:

  • transferStepStatus: Returns an object that provides the current step of a transaction as well as it's corresponding status:
{
  "step": "send",
  "status": "FAILED",
  "error": "execution reverted: ERC20: transfer amount exceeds balance"
}
  • transferResults: Returns an object that provides the statuses of all the steps involved in a transaction. This helps to monitor the progress and outcome of each step, allowing for detailed tracking and troubleshooting:
{
  "status": "SUCCESS",
  "transferId": "OMXoSKJSU37rNluMPUxQL",
  "allowance": {
    "step": "allowance",
    "status": "SUCCESS",
    "needsApproval": false
  },
  "approve": {
    "step": "approve",
    "status": "SUCCESS",
    "txHash": ""
  },
  "send": {
    "step": "send",
    "status": "SUCCESS"
  },
  "bridge": {
    "step": "bridge",
    "status": "SUCCESS"
  }
}

Transaction Statuses

Below is a list of transaction statuses that are returned by the status property in both the transferStepStatus and the transferResults objects:

StatusDescription
PENDINGThe transaction at a particular step has started and is pending.
SUCCESSThe transaction at a particular step has been completed.
FAILEDThe transaction at a particular step has failed.

Transaction Step Statuses

Below is a list of transaction statuses that are returned by the status property and is exclusive to the transferStepStatus objects:

StatusDescription
ACTION_REQUIREDUser action is required such as interacting with metamask
CHAIN_SWITCH_REQUIREDWallet needs to switch chains before continuing
WALLET_CONNECTION_REQUIREDWallet with address needs to be connected
CONFIRMINGWaiting for transaction confirmation
BRIDGINGWaiting for bridge contract transaction to complete

It's important to note that these statuses apply to the status property for every step (i.e., allowance, approval, send, bridge).

Handling failed transactions

The transferResults object contains the overall status of a transaction. Therefore, you can use the status property on the transferResults to determine the transaction's status, regardless of its current step.

To ensure that you're displaying a human-readable error, we suggest using the status property on the transferResults object to determine the finality of a transaction, as its status will remain PENDING until the transaction either fails or completes, regardless of the transaction's current step:

swingSDK.on('TRANSFER', async (transferStepStatus, transferResults) => {
  switch (transferResults.status) {
    case 'SUCCESS':
      console.log('Transaction is completed');
      break;
 
    case 'FAILED':
      console.log(
        `Transaction failed at STEP: ${transferStepStatus.step}, error: ${transferStepStatus.error}`,
      ); // use the `error` property in `transferStepStatus` to display error messages
      break;
 
    default:
      switch (transferStepStatus.status) {
        case 'CHAIN_SWITCH_REQUIRED':
          await switchChain(transferStepStatus.chain);
          break;
 
        case 'WALLET_CONNECTION_REQUIRED':
          await connectWallet(transferStepStatus.chain.chainId);
          break;
      }
  }
});

A transaction can fail due to handful of reasons. A typical error message from the SDK would look something like this:

{
  "status": "FAILED",
  "transferId": "OMXoSKJSU37rNluMPUxQL",
  "allowance": {
    "step": "allowance",
    "status": "SUCCESS",
    "needsApproval": false
  },
  "approve": {
    "step": "approve",
    "status": "SUCCESS",
    "txHash": ""
  },
  "send": {
    "step": "send",
    "status": "FAILED",
    "error": "execution reverted: ERC20: transfer amount exceeds balance"
  },
  "bridge": {
    "step": "bridge"
  }
}

From the error object above, it is clear that the transaction failed at the send step. The error message, "execution reverted: ERC20: transfer amount exceeds balance", suggests that the wallet involved in this transaction did not have enough tokens to complete the transaction..

Here are the most common reasons why a transaction would fail and what to look out for:

ErrorDescription
execution reverted: ERC20: transfer amount exceeds balanceWallet has insufficient ERC20 tokens to fund the transaction
Insufficient Funds For Intrinsic Transaction CostWallet has insufficient native tokens to fund the transaction
CHAIN_SWITCH_REQUIREDWallet needs to switch chains before continuing
WALLET_CONNECTION_REQUIREDWallet with address needs to be connected

Handling CHAIN_SWITCH_REQUIRED Exception

CHAIN_SWITCH_REQUIRED is an instruction from the SwingSDK to our dApp, requiring us to switch our wallet's network to continue the transaction on the correct chain.

As part of this instruction, the SDK will also return the chainId to which you must switch for the transaction to proceed. It is important to note that failing to switch to the correct chainId will result in a CHAIN_SWITCH_REQUIRED exception.

A CHAIN_SWITCH_REQUIRED exception occurs when the chain to which a wallet is connected differs from the source chain (chainSlug) that the SDK is connected to.

To fix this issue, two steps are required:

  • First, switch connected wallet's networks to the value provided in transferStepStatus.chain.id:
connector.activate({ chainId: transferStepStatus.chain.id });
  • Next, Sync the SDK with the wallet's provider by calling the wallet.connect() function again on the SDK:
const walletAddress = await swingSDK.wallet.connect(
  provider?.getSigner(),
  chainId,
);

For instance, if you are connected to the Arbitrum network and are bridging your assets from Polygon (MATIC) on the source chain to Ethereum (USDC) on the destination chain, the SDK will return a CHAIN_SWITCH_REQUIRED status. This indicates that you must programmatically switch your wallet's connected chain from Arbitrum to Polygon.

Here's an example on how you can do this using Web3React:

import { useWeb3React } from '@web3-react/core';
 
const { connector, provider, chainId } = useWeb3React();
 
const transferParams = {
  amount: '1',
  fromChain: 'polygon',
  fromToken: 'MATIC',
  toChain: 'ethereum',
  toToken: 'USDC',
  fromUserAddress: 'user-address',
  toUserAddress: 'user-address',
};
 
const swingSDK = new SwingSDK({
  projectId: 'replug',
  environment: 'production',
  debug: true,
});
 
await swingSDK.init();
 
useEffect(() => {
  async function syncProviderWithSwingSDK() {
    const walletAddress = await swingSDK.wallet.connect(
      provider?.getSigner(),
      chainId,
    );
  }
 
  syncProviderWithSwingSDK();
}, [chainId]);
 
const quote = await swingSdk.getQuote(transferParams);
 
await swingSdk.transfer(quote.routes[0], transferParams);
 
swingSDK.on('TRANSFER', async (transferStepStatus, transferResults) => {
  setStatus(transferStepStatus);
  setResults(transferResults);
 
  console.log('TRANSFER:', transferStepStatus, transferResults);
 
  switch (transferStepStatus.status) {
    case 'CHAIN_SWITCH_REQUIRED':
      connector.activate(transferStepStatus.chain.id);
      break;
 
    case 'WALLET_CONNECTION_REQUIRED':
      await connectWallet(transferStepStatus.chain.chainId);
      break;
  }
});

From our transferParams object, we're transacting from the Polygon network. If we're connected to any chain other than Polygon, the SDK will instruct us to switch chains.

Using Web3React, we can switch chains by calling the connector.activate() function, which is available through the useWeb3React() hook, and then passing transferStepStatus.chain.id as the chainId:

   case 'CHAIN_SWITCH_REQUIRED':
      connector.activate({ chainId: transferStepStatus.chain.id });
      break;

Our useEffect hook listens for changes to the chainId property. By calling connector.activate({ chainId: transferStepStatus.chain.id });, our hook will be triggered, which will then reconnect the SDK to the correct chainId:

useEffect(() => {
  async function syncProviderWithSwingSDK() {
    const walletAddress = await swingSDK.wallet.connect(
      provider?.getSigner(),
      chainId,
    );
  }
 
  syncProviderWithSwingSDK();
}, [chainId]);