Display Functions

Display functions are intended to provide helpful information for the UI.

Vault Status

getVaultStatus

const getVaultStatus = async ({ vaultKey, chainId }: VaultStatusParams) => {
  const normalizedChainId =
    typeof chainId === 'string' ? Number(chainId) : chainId;
  const vault = await getVaultByKey(vaultKey);
  if (!vault) {
    throw new Error(`Vault not found: ${vaultKey}`);
  }

  const tellerAddress = vault.contracts.teller;
  const accountantAddress = vault.contracts.accountant;

  const [tellerStatus, accountantStatus] = await getPausedStates({
    accountantAddress,
    tellerAddress,
    chainId: normalizedChainId,
  });

  if (tellerStatus.status === 'failure') {
    throw new Error(tellerStatus.error.message);
  }

  if (accountantStatus.status === 'failure') {
    throw new Error(accountantStatus.error.message);
  }

  if (tellerStatus.result === true || accountantStatus.result[7] === true) {
    return {
      isPaused: true,
    };
  }

  return {
    isPaused: false,
  };
};

Approvals

isDepositSpendApproved

const isDepositSpendApproved = async ({
  vaultKey,
  sourceChainId,
  depositTokenSymbol,
  userAddress,
}: {
  vaultKey: VaultKey;
  sourceChainId: number;
  userAddress: Address;
  depositTokenSymbol: string;
}) => {
  const {
    data: vault,
    error: vaultError,
    success: vaultSuccess,
  } = await tryCatch(getVaultByKey(vaultKey));
  if (!vaultSuccess) {
    throw new Error(`Vault not found for ${vaultKey}: ${vaultError.message}`);
  }

  if (!vault.contracts) {
    throw new Error(`Contracts not found: ${vaultKey}`);
  }
  const normalizedSourceChainId =
    typeof sourceChainId === 'string' ? Number(sourceChainId) : sourceChainId;
  const {
    data: depositAssetAddress,
    error: depositAssetAddressError,
    success: depositAssetAddressSuccess,
  } = await tryCatch(
    getTokenAddress(normalizedSourceChainId, depositTokenSymbol)
  );
  if (!depositAssetAddressSuccess) {
    throw new Error(
      `Deposit asset address not found: ${depositAssetAddressError.message}`
    );
  }

  const { deposit } = vault;

  const { sourceChains } = deposit;

  const sourceChain = sourceChains[sourceChainId];
  if (!sourceChain) {
    throw new Error(`Source chain not found: ${sourceChainId}`);
  }

  const [allowance, decimals] = await getErc20AllowanceWithDecimals({
    chainId: sourceChainId,
    tokenAddress: depositAssetAddress,
    userAddress: userAddress,
    spenderAddress: vault.contracts.boringVault,
  });

  if (allowance.status === 'failure' || decimals.status === 'failure') {
    return {
      isApproved: false,
      allowance: '0',
      allowanceAsBigInt: '0',
      decimals: '0',
      error: allowance.error || decimals.error,
    };
  }

  return {
    isApproved: allowance.result > 0n,
    allowance: formatUnits(allowance.result, decimals.result),
    allowanceAsBigInt: allowance.result.toString(),
    decimals: decimals.result,
    error: null,
  };
};

isWithdrawalSpendApproved

const isWithdrawalSpendApproved = async ({
  vaultKey,
  destinationChainId,
  userAddress,
  error,
}: {
  vaultKey: VaultKey;
  destinationChainId: number;
  userAddress: Address;
  error: string;
}) => {
  const {
    data: vault,
    error: vaultError,
    success: vaultSuccess,
  } = await tryCatch(getVaultByKey(vaultKey));
  if (!vaultSuccess) {
    throw new Error(`Vault not found for ${vaultKey}: ${vaultError.message}`);
  }

  if (!vault.contracts) {
    throw new Error(`Contracts not found for ${vaultKey}`);
  }
  const boringVaultAddress = vault.contracts.boringVault;

  const [allowance, decimals] = await getErc20AllowanceWithDecimals({
    chainId: destinationChainId,
    tokenAddress: boringVaultAddress,
    userAddress: userAddress,
    spenderAddress: ATOMIC_QUEUE_CONTRACT_ADDRESS,
  });

  if (allowance.status === 'failure' || decimals.status === 'failure') {
    return {
      isApproved: false,
      allowance: '0',
      allowanceAsBigInt: '0',
      decimals: '0',
      error: allowance.error || decimals.error,
    };
  }

  return {
    isApproved: allowance.result > 0n,
    allowance: formatUnits(allowance.result, decimals.result),
    allowanceAsBigInt: allowance.result.toString(),
    decimals: decimals.result,
    error: null,
  };
};

Exchange Rates

getDepositExchangeRate

interface GetDepositExchangeRateParams {
  vaultKey: VaultKey;
  sourceChainId: number | string;
  depositTokenSymbol: string;
  minimumFractionDigits?: number;
  maximumFractionDigits?: number;
}

const getDepositExchangeRate = async ({
  vaultKey,
  sourceChainId,
  depositTokenSymbol,
  minimumFractionDigits,
  maximumFractionDigits = 3,
}: GetDepositExchangeRateParams) => {
  const vault = await getVaultByKey(vaultKey);
  const chainId =
    typeof sourceChainId === 'string' ? Number(sourceChainId) : sourceChainId;
  const tokenAddress = await getTokenAddress(chainId, depositTokenSymbol);
  if (!tokenAddress || tokenAddress === null) {
    return;
  }

  const rateAndDecimalsResults = await getRateInQuoteWithAssetDecimals({
    assetAddress: tokenAddress,
    accountantAddress: vault.contracts.accountant,
    chainId: sourceChainId,
  });

  const [decimals, rate] = rateAndDecimalsResults;

  if (rate.status === 'failure') {
    return new Error(rate.error.message);
  }
  if (decimals.status === 'failure') {
    return new Error(decimals.error.message);
  }

  const depositExchangeRate = bigIntToNumberAsString(rate.result, {
    decimals: decimals.result,
    minimumFractionDigits,
    maximumFractionDigits,
  });

  return depositExchangeRate;
};

getWithdrawExchangeRate

interface GetWithdrawExchangeRateParams {
  vaultKey: VaultKey;
  sourceChainId: number | string;
  wantTokenSymbol: string;
  minimumFractionDigits?: number;
  maximumFractionDigits?: number;
}

const getWithdrawExchangeRate = async ({
  vaultKey,
  sourceChainId,
  wantTokenSymbol,
  minimumFractionDigits,
  maximumFractionDigits = 3,
}: GetWithdrawExchangeRateParams) => {
  const vault = await getVaultByKey(vaultKey);
  const chainId =
    typeof sourceChainId === 'string' ? Number(sourceChainId) : sourceChainId;
  const tokenAddress = await getTokenAddress(chainId, wantTokenSymbol);
  if (!tokenAddress || tokenAddress === null) {
    return;
  }

  const rateAndDecimalsResults = await getRateInQuoteWithAssetDecimals({
    assetAddress: tokenAddress,
    accountantAddress: vault.contracts.accountant,
    chainId: sourceChainId,
  });

  const [decimals, rate] = rateAndDecimalsResults;

  if (rate.status === 'failure') {
    return new Error(rate.error.message);
  }
  if (decimals.status === 'failure') {
    return new Error(decimals.error.message);
  }

  const withdrawExchangeRate = bigIntToNumberAsString(rate.result, {
    decimals: decimals.result,
    minimumFractionDigits,
    maximumFractionDigits,
  });

  return withdrawExchangeRate;
};

Bridge

getBridgeFee

interface GetPreviewFeeParams {
  vaultKey: VaultKey;
  bridgeAmount: bigint;
  sourceChainId: number | string;
  destinationChainId: number | string;
  userAddress: Address;
  nativeTokenForBridgeFee?: Address;
}

const getBridgeFee = async ({
  vaultKey,
  bridgeAmount,
  sourceChainId,
  destinationChainId,
  userAddress,
  nativeTokenForBridgeFee = NATIVE_TOKEN_FOR_BRIDGE_FEE,
}: GetPreviewFeeParams) => {
  const vault = await getVaultByKey(vaultKey);
  if (!vault) {
    throw new Error(`Invalid vault key: ${vaultKey}`);
  }

  if (!vault.contracts) {
    throw new Error(`Contracts not configured for vault ${vaultKey}`);
  }

  if (!vault.contracts.boringVault) {
    throw new Error(
      `BoringVault contract not configured for vault ${vaultKey}`
    );
  }

  if (!vault.contracts.accountant) {
    throw new Error(`Accountant contract not configured for vault ${vaultKey}`);
  }

  if (!vault.contracts.teller) {
    throw new Error(`Teller contract not configured for vault ${vaultKey}`);
  }

  const sourceChainIdString = sourceChainId.toString();
  const sourceChain = vault.withdraw.sourceChains[sourceChainIdString];
  if (!sourceChain) {
    throw new Error(`Source chain not configured for vault ${vaultKey}`);
  }

  const destinationChain = sourceChain.destinationChains[destinationChainId];
  if (!destinationChain) {
    throw new Error(`Destination chain not configured for vault ${vaultKey}`);
  }

  const bridgeChainIdentifier = destinationChain.bridge.chainIdentifier;

  const bridgeContractArg = prepareBridgeContractArg({
    bridgeChainIdentifier,
    userAddress,
    nativeTokenForBridgeFee,
  });

  const previewFee = await getPreviewFee({
    shareAmount: bridgeAmount,
    bridgeData: bridgeContractArg,
    contractAddress: vault.contracts.teller,
    chainId: sourceChainId,
  });

  // TODO: use native currency from chains object returned from API
  return previewFee;
};

Last updated