The ShibaSwap V1 SDK (@shibaswap/sdk) is a TypeScript/JavaScript library that lets you build on top of ShibaSwap V1—a Uniswap V2 fork originally inherited via SushiSwap—using familiar abstractions like Token, Pair, Route, and Trade. It runs in any JS environment (browsers, Node) and powers both quick hackathon prototypes and production-grade integrations. Under the hood:
  • It swaps in ShibaSwap’s factory and router addresses
  • Computes CREATE2 pair addresses offline
  • Fetches on-chain reserves via ethers
  • Generates all parameters needed to craft router transactions

Quick Start & Installation

npm install @shibaswap/sdk
This pulls in @shibaswap/sdk-core and ethers as dependencies.

Imports & Initialization

import { ChainId } from '@shibaswap/sdk-core'
import { Pair }   from '@shibaswap/sdk'

console.log(`Mainnet chainId = ${ChainId.MAINNET}`)

Fetching On-Chain Data

You must supply on-chain data for tokens and pairs.

Case 1: Tokens

import { ChainId, Token } from '@shibaswap/sdk-core'

const DAI = new Token(
  ChainId.MAINNET,
  '0x6B175474E89094C44Da98b954EedeAC495271d0F',
  18,
  'DAI',
  'Dai Stablecoin'
)
To fetch decimals dynamically:
import { ethers } from 'ethers'
import erc20ABI from './erc20.json'

async function getDecimals(chainId: ChainId, tokenAddress: string): Promise<number> {
  const provider = new ethers.providers.JsonRpcProvider(/* RPC URL */)
  const tokenContract = new ethers.Contract(tokenAddress, erc20ABI, provider)
  return tokenContract.decimals()
}

Case 2: Pairs

import {
  ChainId,
  Token,
  WETH9,
  CurrencyAmount
} from '@shibaswap/sdk-core'
import { Pair } from '@shibaswap/sdk'
import { ethers } from 'ethers'
import poolABI from './V2Pool.json'

const DAI  = new Token(/* … */)
const WETH = WETH9[ChainId.MAINNET]

async function createDAIWethPair(): Promise<Pair> {
  const pairAddress = Pair.getAddress(DAI, WETH)
  const provider    = new ethers.providers.JsonRpcProvider(/* RPC URL */)
  const pool        = new ethers.Contract(pairAddress, poolABI, provider)
  const [reserve0, reserve1] = await pool.getReserves()

  const [token0, token1] = [DAI, WETH].sort((a, b) => a.sortsBefore(b) ? -1 : 1)
  return new Pair(
    CurrencyAmount.fromRawAmount(token0, reserve0.toString()),
    CurrencyAmount.fromRawAmount(token1, reserve1.toString())
  )
}

Pricing

Mid Price (Direct & Indirect)

import { Route } from '@shibaswap/sdk'

const pair = await createDAIWethPair()
const route = new Route([pair], WETH, DAI)

console.log(route.midPrice.toSignificant(6))
console.log(route.midPrice.invert().toSignificant(6))
For multi-hop (e.g., via USDC):
const USDC = new Token(/* … */)
const usdcWeth = await createPair(USDC, WETH)
const daiUsdc  = await createPair(DAI, USDC)

const indirectRoute = new Route([usdcWeth, daiUsdc], WETH, DAI)
console.log(indirectRoute.midPrice.toSignificant(6))

Execution Price (with Slippage)

import { Trade, TradeType, CurrencyAmount } from '@shibaswap/sdk-core'

const trade = new Trade(
  route,
  CurrencyAmount.fromRawAmount(WETH, '1000000000000000000'), // 1 WETH
  TradeType.EXACT_INPUT
)

console.log(trade.executionPrice.toSignificant(6))

Trading

The SDK does not send transactions. It generates transaction parameters for you to send manually via ethers.
Router Address: 0x03f7724180aa6b939894b5ca4314783b0b36b329 Example: Swap 1 ETH → DAI
import { Percent } from '@shibaswap/sdk-core'
import routerABI from './V2Router02.json'
import { ethers } from 'ethers'

const provider = new ethers.providers.Web3Provider(window.ethereum)
const signer   = provider.getSigner()
const router   = new ethers.Contract(
  '0x03f7724180aa6b939894b5ca4314783b0b36b329',
  routerABI,
  signer
)

const slippageTolerance = new Percent('50', '10000') // 0.50%
const amountOutMin      = trade.minimumAmountOut(slippageTolerance).toExact()
const path              = [WETH.address, DAI.address]
const to                = await signer.getAddress()
const deadline          = Math.floor(Date.now() / 1000) + 60 * 20
const value             = trade.inputAmount.toExact()

await router.swapExactETHForTokens(
  amountOutMin,
  path,
  to,
  deadline,
  { value }
)

Pair Addresses (CREATE2 vs On-Chain)

On-chain:
factory.getPair(tokenA, tokenB)
Off-chain via CREATE2:
import {
  FACTORY_ADDRESS,
  INIT_CODE_HASH
} from '@shibaswap/sdk'
import { pack, keccak256 } from '@ethersproject/solidity'
import { getCreate2Address } from '@ethersproject/address'

const pairAddress = getCreate2Address(
  FACTORY_ADDRESS,
  keccak256(['bytes'], [pack(['address','address'], [token0, token1])]),
  INIT_CODE_HASH
)

Technical Reference

Pair

class Pair {
  constructor(tokenAmountA: CurrencyAmount, tokenAmountB: CurrencyAmount)
  static getAddress(tokenA: Token, tokenB: Token): string
  reserveOf(token: Token): CurrencyAmount
  getOutputAmount(inputAmount: CurrencyAmount): [CurrencyAmount, Pair]
  getInputAmount(outputAmount: CurrencyAmount): [CurrencyAmount, Pair]
  getLiquidityMinted(...): CurrencyAmount
  getLiquidityValue(...): CurrencyAmount
}

Route

class Route {
  constructor(pairs: Pair[], input: Token, output: Token)
  readonly midPrice: Price
}

Trade

class Trade {
  constructor(route: Route, amount: CurrencyAmount, tradeType: TradeType)
  readonly inputAmount: CurrencyAmount
  readonly outputAmount: CurrencyAmount
  readonly executionPrice: Price
  readonly priceImpact: Percent

  minimumAmountOut(slippageTolerance: Percent): CurrencyAmount
  maximumAmountIn(slippageTolerance: Percent): CurrencyAmount
  worstExecutionPrice(slippageTolerance: Percent): Price

  static exactIn(...): Trade
  static exactOut(...): Trade
  static bestTradeExactIn(...): Trade[]
  static bestTradeExactOut(...): Trade[]
}

Other Exports

  • FACTORY_ADDRESS: ShibaSwap V1 Factory Address
  • INIT_CODE_HASH: For CREATE2 address generation
  • MINIMUM_LIQUIDITY: Protocol-reserved
  • Errors: InsufficientReservesError, InsufficientInputAmountError

Complete Example

Here’s a complete example showing how to use the SDK to perform a swap:
import { 
  ChainId, 
  Token, 
  WETH9, 
  CurrencyAmount, 
  TradeType, 
  Percent 
} from '@shibaswap/sdk-core'
import { Pair, Route, Trade } from '@shibaswap/sdk'
import { ethers } from 'ethers'

// Define tokens
const WETH = WETH9[ChainId.MAINNET]
const DAI = new Token(
  ChainId.MAINNET,
  '0x6B175474E89094C44Da98b954EedeAC495271d0F',
  18,
  'DAI',
  'Dai Stablecoin'
)

// Create pair and route
async function createSwap() {
  const pair = await createDAIWethPair()
  const route = new Route([pair], WETH, DAI)
  
  // Create trade
  const trade = new Trade(
    route,
    CurrencyAmount.fromRawAmount(WETH, '1000000000000000000'), // 1 WETH
    TradeType.EXACT_INPUT
  )
  
  // Set up transaction
  const slippageTolerance = new Percent('50', '10000') // 0.50%
  const amountOutMin = trade.minimumAmountOut(slippageTolerance).toExact()
  
  console.log(`Swapping 1 WETH for at least ${amountOutMin} DAI`)
  
  return {
    amountOutMin,
    path: [WETH.address, DAI.address],
    deadline: Math.floor(Date.now() / 1000) + 60 * 20
  }
}

Best Practices

Always use the SDK’s built-in functions for calculations rather than implementing your own. This ensures accuracy and consistency with the protocol.
Set appropriate slippage tolerance based on your use case. Lower values provide better prices but may fail more often.
Always verify token addresses and chain IDs before creating Token instances to avoid errors.
Never hardcode amounts or addresses in production code. Always fetch them dynamically from the blockchain or configuration.

Error Handling

The SDK provides specific error types for common scenarios:
import { InsufficientReservesError, InsufficientInputAmountError } from '@shibaswap/sdk'

try {
  const trade = new Trade(route, amount, TradeType.EXACT_INPUT)
} catch (error) {
  if (error instanceof InsufficientReservesError) {
    console.log('Insufficient liquidity in the pool')
  } else if (error instanceof InsufficientInputAmountError) {
    console.log('Input amount too small')
  }
}