Valantis Documentation
Valantis Website
  • Welcome to Valantis
  • Sovereign Pool
    • The Modules
      • Pool Manager
      • Liquidity Module
      • Swap Fee Module
      • Verifier Module
      • Oracle Module
      • Sovereign Vault
        • Rebase token support
      • Gauge
    • Interacting with Pools
      • Swap Parameters
      • Swap Steps
      • Multi Token Support
      • Deposit Liquidity
      • Withdraw Liquidity
      • Flash Loans
  • Hybrid Order Type (HOT)
    • Understanding HOT: A Graphical Overview
    • HOT API
      • HTTP request parameters
      • HTTP request response
      • Reasoning for Request structure
      • Solver Integration
      • Market Maker integration
    • HOT Smart Contracts
      • Interfaces
      • State variables and roles
      • AMM
      • HOT Swap
      • AMM Swap
      • Hybrid Order Type (HOT) struct parameters
      • Alternating Nonce Bitmap
      • Deposits
      • Withdrawals
      • Deployment Assumptions
    • Liquidity Manager Docs
      • Reference Oracle
      • Deposit
      • Withdraw
      • Signature
    • Swap
      • Swap Context
      • AMM Swap
      • HOT Swap
      • HOT Quote Parameters
        • Bitmap Nonce Instructions
    • Solver Docs
      • Solver Request
      • Simple HOT Swap Example
      • Partial Fill HOT Swap Example
    • Risks and Trust Assumptions
      • Roles
        • Sovereign Pool Manager
        • HOT Manager
        • HOT Signer
        • Liquidity Provider
      • Threats
        • Deposit Sandwich
        • Malicious Price Bound
        • Malicious Signer
        • Mispriced HOT Quote
  • Validly
    • Understanding Validly
    • Swap
    • Deposits and Withdrawals
    • Deployments
  • Stake Exchange (stHYPE AMM)
    • Swap
      • Instant Withdrawals (LST -> Native Token)
      • New Stake (Native Token -> LST)
    • LP Positions
      • LP Withdrawals Instant
      • LP Withdrawal Queued
    • Ratio Fee
    • Lending of Reserves
    • Smart contracts
      • STEXAMM.sol
      • StHYPEWithdrawalModule.sol
      • StexRatioSwapFeeModule.sol
      • DepositWrapper.sol
      • AaveLendingModule.sol
    • Risks and Trust Assumptions
    • Integration examples
  • Deploy and Build
  • Resources
    • Audits
    • Links
    • Get HYPE on HyperEVM
Powered by GitBook
On this page
  • Swap from stHYPE to Wrapped HYPE
  • Swap from WHYPE to stHYPE
  • Swap from HYPE to stHYPE

Was this helpful?

  1. Stake Exchange (stHYPE AMM)

Integration examples

PreviousRisks and Trust AssumptionsNextDeploy and Build

Last updated 1 month ago

Was this helpful?

Swap from stHYPE to Wrapped HYPE

This is an example of how to swap stHYPEinto Wrapped HYPEon STEX AMM. As always, the entry-point contract for swaps will be STEX AMM's respective .

Requirements to run the following example:

  • Ensure you have an EOA wallet with private key PRIVATE_KEYinside a .envfile, with enough HYPE balance to pay for gas costs.

  • Ensure your EOA has non-zero stHYPE to execute the swap. See .

import { createWalletClient, defineChain, erc20Abi, http, parseEther, publicActions, parseAbi } from 'viem';
import { privateKeyToAccount } from 'viem/accounts';

// Read `PRIVATE_KEY` from .env
// WARNING: Make sure this is an EOA on HyperEVM (chain id 999) with sufficient HYPE to pay for gas,
// as well as non-zero stHYPE to execute the swap
const dotenv = require('dotenv');
dotenv.config();

// ABI definitions

const STEX_AMM_ABI = parseAbi(['function getAmountOut(address _tokenIn, uint256 _amountIn, bool _isInstantWithdraw) view returns (uint256)']);

const SOVEREIGN_POOL_ABI = parseAbi([
  'function swap(SovereignPoolSwapParams _params) returns (uint256, uint256)',
  'struct SovereignPoolSwapParams { bool isSwapCallback; bool isZeroToOne; uint256 amountIn; uint256 amountOutMin; uint256 deadline; address recipient; address swapTokenOut; SovereignPoolSwapContextData swapContext; }',
  'struct SovereignPoolSwapContextData { bytes externalContext; bytes verifierContext; bytes swapCallbackContext; bytes swapFeeModuleContext; }',
]);

// STEX AMM deployments

// Address of the Valantis Sovereign Pool,
// always the entry-point for swaps
const STEX_AMM_SOVEREIGN_POOL = '0x5365b6EF09253C7aBc0A9286eC578A9f4B413B7D';

// Address of STEX AMM Liquidity Module bound to `STEX_AMM_SOVEREIGN_POOL`.
// This is the main AMM module which handles all swap related pricing logic.
const STEX_AMM = '0x39694eFF3b02248929120c73F90347013Aec834d';

// Temporary solution, until Hyper EVM is supported in viem
const hyperEvm = defineChain({
  id: 999,
  name: 'HyperEVM',
  nativeCurrency: {
    decimals: 18,
    name: 'HYPE',
    symbol: 'HYPE',
  },
  rpcUrls: {
    default: {
      http: ['https://rpc.hyperliquid.xyz/evm'],
      webSocket: ['wss://rpc.hyperliquid.xyz/evm'],
    },
  },
  blockExplorers: {
    default: { name: 'Blockscout', url: 'https://hyperliquid.cloud.blockscout.com/' },
  },
  contracts: {},
});

async function swapStHypeToWHYPE() {
  // Address of stHYPE
  const tokenIn = '0xfFaa4a3D97fE9107Cef8a3F48c069F577Ff76cC1';
  // Address of WHYPE
  // WARNING: Sovereign Pool (the entry point for swaps)
  // only works with ERC-20 tokens. Native token always needs to be wrapped.
  const tokenOut = '0x5555555555555555555555555555555555555555';

  const amountIn = parseEther('0.01');

  const account = privateKeyToAccount(process.env.PRIVATE_KEY as `0x${string}`);

  const walletClient = createWalletClient({
    chain: hyperEvm,
    transport: http(),
    account,
  }).extend(publicActions);

  // In `STEX_AMM_SOVEREIGN_POOL`, toke0=stHYPE and token1=WHYPE
  const isZeroToOne = true;
  // 60 seconds deadline. Can use block.timestamp for extra accuracy
  const deadline = BigInt(Math.floor(Date.now() / 1_000) + 60);
  const recipient = account.address;

  // Ensure that `account` approves `STEX_AMM_SOVEREIGN_POOL`
  // to spend `amountIn` of `tokenIn` before proceeding.

  const tokenInAllowance = await walletClient.readContract({
    address: tokenIn,
    abi: erc20Abi,
    functionName: 'allowance',
    args: [account.address, STEX_AMM_SOVEREIGN_POOL],
  });
  if (tokenInAllowance < amountIn) {
    console.log('Submitting tokenIn approval to Sovereign Pool');

    await walletClient.writeContract({
      chain: hyperEvm,
      account,
      address: tokenIn,
      abi: erc20Abi,
      functionName: 'approve',
      args: [STEX_AMM_SOVEREIGN_POOL, amountIn],
      gas: 100_000n,
    });

    // Wait 10 seconds to reflect state updates on RPC node,
    // remove this in prod
    await setTimeout(() => {}, 10_000);
  }

  // Estimate `tokenOut` amount before swapping
  const amountOutExpected = await walletClient.readContract({
    address: STEX_AMM,
    abi: STEX_AMM_ABI,
    functionName: 'getAmountOut',
    args: [tokenIn, amountIn, false],
  });

  console.log(`Amount tokenOut expected on swap: ${amountOutExpected}`);

  // Zero slippage, adjust as required
  const amountOutMin = amountOutExpected;

  // Simulate swap
  let request;
  try {
    request = await walletClient.simulateContract({
      chain: hyperEvm,
      account,
      address: STEX_AMM_SOVEREIGN_POOL,
      abi: SOVEREIGN_POOL_ABI,
      functionName: 'swap',
      args: [
        {
          isSwapCallback: false,
          isZeroToOne,
          amountIn,
          amountOutMin,
          deadline,
          recipient,
          swapTokenOut: tokenOut,
          swapContext: {
            externalContext: '0x',
            verifierContext: '0x',
            swapCallbackContext: '0x',
            swapFeeModuleContext: '0x',
          },
        },
      ],
      gas: 250_000n,
    });
  } catch (error) {
    console.log(`swapStHypeToWHYPE: Swap simulation failed with error: ${error.message}`);
    return;
  }

  console.log('Submitting swap to Sovereign Pool');
  // Execute swap
  await walletClient.writeContract(request.request);
}

swapStHypeToWHYPE();

Swap from WHYPE to stHYPE

Requirements to run the following example:

  • Ensure you have an EOA wallet with private key PRIVATE_KEYinside a .envfile, with enough HYPE balance to pay for gas costs.

  • Ensure that this wallet has enough HYPE or Wrapped HYPE (WHYPE) to swap.

WARNING: Valantis Sovereign Pool does not work with native token, hence HYPE needs to be wrapped into WHYPE and approved before the call to `SovereignPool::swap`.

import { createWalletClient, defineChain, erc20Abi, http, parseEther, publicActions, parseAbi } from 'viem';
import { privateKeyToAccount } from 'viem/accounts';

// Read `PRIVATE_KEY` from .env
// WARNING: Make sure this is an EOA on HyperEVM (chain id 999) with sufficient HYPE to pay for gas,
// as well as non-zero stHYPE to execute the swap
const dotenv = require('dotenv');
dotenv.config();

// ABI definitions

const STEX_AMM_ABI = parseAbi(['function getAmountOut(address _tokenIn, uint256 _amountIn, bool _isInstantWithdraw) view returns (uint256)']);

const SOVEREIGN_POOL_ABI = parseAbi([
  'function swap(SovereignPoolSwapParams _params) returns (uint256, uint256)',
  'struct SovereignPoolSwapParams { bool isSwapCallback; bool isZeroToOne; uint256 amountIn; uint256 amountOutMin; uint256 deadline; address recipient; address swapTokenOut; SovereignPoolSwapContextData swapContext; }',
  'struct SovereignPoolSwapContextData { bytes externalContext; bytes verifierContext; bytes swapCallbackContext; bytes swapFeeModuleContext; }',
]);

// STEX AMM deployments

// Address of the Valantis Sovereign Pool,
// always the entry-point for swaps
const STEX_AMM_SOVEREIGN_POOL = '0x5365b6EF09253C7aBc0A9286eC578A9f4B413B7D';

// Address of STEX AMM Liquidity Module bound to `STEX_AMM_SOVEREIGN_POOL`.
// This is the main AMM module which handles all swap related pricing logic.
const STEX_AMM = '0x39694eFF3b02248929120c73F90347013Aec834d';

// Temporary solution, until Hyper EVM is supported in viem
const hyperEvm = defineChain({
  id: 999,
  name: 'HyperEVM',
  nativeCurrency: {
    decimals: 18,
    name: 'HYPE',
    symbol: 'HYPE',
  },
  rpcUrls: {
    default: {
      http: ['https://rpc.hyperliquid.xyz/evm'],
      webSocket: ['wss://rpc.hyperliquid.xyz/evm'],
    },
  },
  blockExplorers: {
    default: { name: 'Blockscout', url: 'https://hyperliquid.cloud.blockscout.com/' },
  },
  contracts: {},
});

async function swapWHYPEToStHYPE() {
  // Address of WHYPE
  // WARNING: Sovereign Pool (the entry point for swaps)
  // only works with ERC-20 tokens. Native token always needs to be wrapped.
  const tokenIn = '0x5555555555555555555555555555555555555555';

  // Address of stHYPE
  const tokenOut = '0xfFaa4a3D97fE9107Cef8a3F48c069F577Ff76cC1';

  const amountIn = parseEther('0.01');

  const account = privateKeyToAccount(process.env.PRIVATE_KEY as `0x${string}`);

  const walletClient = createWalletClient({
    chain: hyperEvm,
    transport: http(),
    account,
  }).extend(publicActions);

  // In `STEX_AMM_SOVEREIGN_POOL`, toke0=stHYPE and token1=WHYPE
  const isZeroToOne = false;
  // 60 seconds deadline. Can use block.timestamp for extra accuracy
  const deadline = BigInt(Math.floor(Date.now() / 1_000) + 60);
  const recipient = account.address;

  const wHypeBalance = await walletClient.readContract({
    address: tokenIn,
    abi: erc20Abi,
    functionName: 'balanceOf',
    args: [account.address],
  });

  if (wHypeBalance < amountIn) {
    console.log('Submitting wrapping of HYPE into WHYPE');
    await walletClient.writeContract({
      chain: hyperEvm,
      account,
      address: tokenIn,
      abi: parseAbi(['function deposit() payable']),
      functionName: 'deposit',
      value: amountIn - wHypeBalance,
      gas: 100_000n,
    });

    // Wait 10 seconds to reflect state updates on RPC node,
    // remove this in prod
    await setTimeout(() => {}, 10_000);
  }

  const wHypeAllowance = await walletClient.readContract({
    address: tokenIn,
    abi: erc20Abi,
    functionName: 'allowance',
    args: [account.address, STEX_AMM_SOVEREIGN_POOL],
  });
  if (wHypeAllowance < amountIn) {
    console.log('Submitting WHYPE approval to Sovereign Pool');

    await walletClient.writeContract({
      chain: hyperEvm,
      account,
      address: tokenIn,
      abi: erc20Abi,
      functionName: 'approve',
      args: [STEX_AMM_SOVEREIGN_POOL, amountIn],
      gas: 100_000n,
    });

    // Wait 10 seconds to reflect state updates on RPC node,
    // remove this in prod
    await setTimeout(() => {}, 10_000);
  }

  // Estimate `tokenOut` amount before swapping
  const amountOutExpected = await walletClient.readContract({
    address: STEX_AMM,
    abi: STEX_AMM_ABI,
    functionName: 'getAmountOut',
    args: [tokenIn, amountIn, false],
  });

  console.log(`Amount tokenOut expected on swap: ${amountOutExpected}`);

  // Zero slippage, adjust as required
  const amountOutMin = amountOutExpected;

  // Simulate swap
  let request;
  try {
    request = await walletClient.simulateContract({
      chain: hyperEvm,
      account,
      address: STEX_AMM_SOVEREIGN_POOL,
      abi: SOVEREIGN_POOL_ABI,
      functionName: 'swap',
      args: [
        {
          isSwapCallback: false,
          isZeroToOne,
          amountIn,
          amountOutMin,
          deadline,
          recipient,
          swapTokenOut: tokenOut,
          swapContext: {
            externalContext: '0x',
            verifierContext: '0x',
            swapCallbackContext: '0x',
            swapFeeModuleContext: '0x',
          },
        },
      ],
      gas: 250_000n,
    });
  } catch (error) {
    console.log(`swapHYPEToStHype: Swap simulation failed with error: ${error.message}`);
    return;
  }

  console.log('Submitting swap to Sovereign Pool');
  // Execute swap
  await walletClient.writeContract(request.request);
}

swapWHYPEToStHYPE();

Swap from HYPE to stHYPE

In this example, we use Valantis' Swap Router swapfunction to wrap HYPEinto WHYPEbefore interacting with the Sovereign Pool.

import {
  createWalletClient,
  defineChain,
  erc20Abi,
  http,
  parseEther,
  publicActions,
  parseAbi,
  parseAbiParameters,
  encodeAbiParameters,
} from 'viem';
import { privateKeyToAccount } from 'viem/accounts';

// Read `PRIVATE_KEY` from .env
// WARNING: Make sure this is an EOA on HyperEVM (chain id 999) with sufficient HYPE to pay for gas,
// as well as non-zero stHYPE to execute the swap
const dotenv = require('dotenv');
dotenv.config();

// ABI definitions

const STEX_AMM_ABI = parseAbi(['function getAmountOut(address _tokenIn, uint256 _amountIn, bool _isInstantWithdraw) view returns (uint256)']);

const SOVEREIGN_POOL_ABI = parseAbi([
  'function swap(SovereignPoolSwapParams _params) returns (uint256, uint256)',
  'struct SovereignPoolSwapParams { bool isSwapCallback; bool isZeroToOne; uint256 amountIn; uint256 amountOutMin; uint256 deadline; address recipient; address swapTokenOut; SovereignPoolSwapContextData swapContext; }',
  'struct SovereignPoolSwapContextData { bytes externalContext; bytes verifierContext; bytes swapCallbackContext; bytes swapFeeModuleContext; }',
]);

const SWAP_ROUTER_ABI = parseAbi([
  'function swap(DirectSwapParams _directSwapParams) payable returns (uint256)',
  'struct DirectSwapParams { bool[] isUniversalPool; address[] pools; uint256[] amountInSpecified; bytes[] payloads; bool isTokenOutEth; address tokenIn; address tokenOut; address recipient; uint256 amountOutMin; uint256 deadline; }',
]);

// STEX AMM deployments

// Address of the Valantis Sovereign Pool,
// always the entry-point for swaps
const STEX_AMM_SOVEREIGN_POOL = '0x5365b6EF09253C7aBc0A9286eC578A9f4B413B7D';

// Address of STEX AMM Liquidity Module bound to `STEX_AMM_SOVEREIGN_POOL`.
// This is the main AMM module which handles all swap related pricing logic.
const STEX_AMM = '0x39694eFF3b02248929120c73F90347013Aec834d';

// Not a requirement for a swap against a single pool,
// but useful for automatically wrapping HYPE into WHYPE
const SWAP_ROUTER = '0x5Abe35DDb420703bA6Dd7226ACDCb24be71192e5';

// Temporary solution, until Hyper EVM is supported in viem
const hyperEvm = defineChain({
  id: 999,
  name: 'HyperEVM',
  nativeCurrency: {
    decimals: 18,
    name: 'HYPE',
    symbol: 'HYPE',
  },
  rpcUrls: {
    default: {
      http: ['https://rpc.hyperliquid.xyz/evm'],
      webSocket: ['wss://rpc.hyperliquid.xyz/evm'],
    },
  },
  blockExplorers: {
    default: { name: 'Blockscout', url: 'https://hyperliquid.cloud.blockscout.com/' },
  },
  contracts: {},
});

async function swapHYPEToStHype() {
  const account = privateKeyToAccount(process.env.PRIVATE_KEY as `0x${string}`);

  const walletClient = createWalletClient({
    chain: hyperEvm,
    transport: http(),
    account,
  }).extend(publicActions);

  // Address of WHYPE,
  // even though the user will provide HYPE
  const tokenIn = '0x5555555555555555555555555555555555555555';

  // Address of stHYPE
  const tokenOut = '0xfFaa4a3D97fE9107Cef8a3F48c069F577Ff76cC1';

  const amountIn = parseEther('0.01');

  const recipient = account.address;

  // Estimate `tokenOut` amount before swapping
  const amountOutExpected = await walletClient.readContract({
    address: STEX_AMM,
    abi: STEX_AMM_ABI,
    functionName: 'getAmountOut',
    args: [tokenIn, amountIn, false],
  });

  console.log(`Amount tokenOut expected on swap: ${amountOutExpected}`);

  // Zero slippage, adjust as required
  const amountOutMin = amountOutExpected;

  // 60 seconds deadline. Can use block.timestamp for extra accuracy
  const deadline = BigInt(Math.floor(Date.now() / 1_000) + 60);

  const sovereignPoolPayload = encodeAbiParameters(
    parseAbiParameters(
      '(bool isZeroToOne, address recipient, address swapTokenOut, uint256 amountOutMin, bytes externalContext, bytes verificationContext, bytes swapFeeModuleContext)',
    ),
    [
      {
        isZeroToOne: false,
        recipient,
        swapTokenOut: tokenOut,
        amountOutMin,
        externalContext: '0x',
        verificationContext: '0x',
        swapFeeModuleContext: '0x',
      },
    ],
  );

  // Execute swap from HYPE to stHYPE
  // `SWAP_ROUTER` automatically wraps into WHYPE before interacting with `STEX_AMM_SOVEREIGN_POOL`
  let request;
  try {
    request = await walletClient.simulateContract({
      chain: hyperEvm,
      account,
      address: SWAP_ROUTER,
      abi: SWAP_ROUTER_ABI,
      functionName: 'swap',
      args: [
        {
          isUniversalPool: [false],
          pools: [STEX_AMM_SOVEREIGN_POOL],
          amountInSpecified: [amountIn],
          payloads: [sovereignPoolPayload],
          isTokenOutEth: false,
          tokenIn,
          tokenOut,
          recipient,
          amountOutMin,
          deadline,
        },
      ],
      value: amountIn,
      gas: 500_000n,
    });
  } catch (error) {
    console.log(`swapHYPEToStHype: Swap simulation failed with error: ${error.message}`);
  }

  console.log('Submitting HYPE to stHYPE swap to Swap Router');
  // Execute swap
  await walletClient.writeContract(request.request);
}

swapHYPEToStHype();
Sovereign Pool
https://www.stakedhype.fi/