Shibaswap v1 is built on a system of smart contracts that work together to provide decentralized exchange functionality. This page provides an overview of the core contracts and their interactions.

Technical Reference

Shibaswap v1 consists of several core smart contracts that work together to enable decentralized token swapping:
  • Factory Contract: Creates and manages trading pairs
  • Pair Contract: Handles the actual trading logic and liquidity provision
  • Pair ERC-20 Contract: Represents liquidity provider tokens
  • Library Contract: Provides utility functions for calculations and price queries
  • Router02 Contract: Offers user-friendly interface for all trading and liquidity operations
Shibaswap v1 is based on the Uniswap v2 protocol architecture, adapted specifically for the Shiba Inu ecosystem and Shibarium network.

Factory Contract

The Factory contract is responsible for creating and managing all trading pairs on Shibaswap v1. It serves as the central registry for all pair contracts.

Key Functions

// Create a new trading pair
function createPair(address tokenA, address tokenB) 
    external 
    returns (address pair);

// Get the address of an existing pair
function getPair(address tokenA, address tokenB) 
    external 
    view 
    returns (address pair);

// Get the total number of pairs
function allPairs(uint) 
    external 
    view 
    returns (address pair);

// Get the total number of pairs created
function allPairsLength() 
    external 
    view 
    returns (uint);

Creating a New Pair

When you want to create a new trading pair, the Factory contract:
  1. Validates that the token addresses are different
  2. Sorts the token addresses to ensure consistent pair addresses
  3. Checks if the pair already exists
  4. Deploys a new Pair contract with the specified tokens
  5. Registers the new pair in its internal mapping
Token addresses are sorted alphabetically to ensure consistent pair addresses regardless of the order they’re provided.

Pair Address Calculation

The Factory uses a deterministic address calculation to ensure the same pair address is generated for the same token combination:
bytes32 salt = keccak256(abi.encodePacked(token0, token1));
address pair = address(uint160(uint256(keccak256(abi.encodePacked(
    bytes1(0xff),
    factory,
    salt,
    keccak256(type(Pair).creationCode)
)))));

Pair Contract

The Pair contract handles the core trading logic, including:
  • Token swaps
  • Liquidity provision and removal
  • Price calculations
  • Fee collection

Core State Variables

// Token addresses
address public token0;
address public token1;

// Reserves for each token
uint112 private reserve0;
uint112 private reserve1;

// Timestamp of last update
uint32 private blockTimestampLast;

// Price oracle data
uint public price0CumulativeLast;
uint public price1CumulativeLast;

// Trading fees (0.3% = 3000)
uint public constant MINIMUM_LIQUIDITY = 10**3;
uint public constant FEE_DENOMINATOR = 1000000;
uint public constant SWAP_FEE = 3000;

Swap Function

The main swap function handles token exchanges:
function swap(
    uint amount0Out,
    uint amount1Out,
    address to,
    bytes calldata data
) external {
    require(amount0Out > 0 || amount1Out > 0, 'Shibaswap: INSUFFICIENT_OUTPUT_AMOUNT');
    (uint112 _reserve0, uint112 _reserve1,) = getReserves();
    require(amount0Out < _reserve0 && amount1Out < _reserve1, 'Shibaswap: INSUFFICIENT_LIQUIDITY');

    uint balance0;
    uint balance1;
    { // scope for _token{0,1}, avoids stack too deep errors
    address _token0 = token0;
    address _token1 = token1;
    require(to != _token0 && to != _token1, 'Shibaswap: INVALID_TO');
    if (amount0Out > 0) _safeTransfer(_token0, to, amount0Out);
    if (amount1Out > 0) _safeTransfer(_token1, to, amount1Out);
    if (data.length > 0) IShibaswapCallee(to).shibaswapCall(msg.sender, amount0Out, amount1Out, data);
    balance0 = IERC20(_token0).balanceOf(address(this));
    balance1 = IERC20(_token1).balanceOf(address(this));
    }
    uint amount0In = balance0 > _reserve0 - amount0Out ? balance0 - (_reserve0 - amount0Out) : 0;
    uint amount1In = balance1 > _reserve1 - amount1Out ? balance1 - (_reserve1 - amount1Out) : 0;
    require(amount0In > 0 || amount1In > 0, 'Shibaswap: INSUFFICIENT_INPUT_AMOUNT');
    { // scope for reserve{0,1}Adjusted, avoids stack too deep errors
    uint balance0Adjusted = balance0.mul(1000).sub(amount0In.mul(3));
    uint balance1Adjusted = balance1.mul(1000).sub(amount1In.mul(3));
    require(balance0Adjusted.mul(balance1Adjusted) >= uint(_reserve0).mul(_reserve1).mul(1000**2), 'Shibaswap: K');
    }

    _update(balance0, balance1, _reserve0, _reserve1);
    emit Swap(msg.sender, amount0In, amount1In, amount0Out, amount1Out, to);
}

Liquidity Functions

The Pair contract provides functions for adding and removing liquidity:
// Add liquidity to the pair
function addLiquidity(
    uint amount0Desired,
    uint amount1Desired,
    uint amount0Min,
    uint amount1Min,
    address to,
    uint deadline
) external returns (uint amount0, uint amount1, uint liquidity);

// Remove liquidity from the pair
function removeLiquidity(
    uint liquidity,
    uint amount0Min,
    uint amount1Min,
    address to,
    uint deadline
) external returns (uint amount0, uint amount1);
Always use the Router contract for adding and removing liquidity. Direct interaction with Pair contracts can result in suboptimal amounts or failed transactions.

Pair ERC-20 Contract

Each trading pair has an associated ERC-20 token that represents liquidity provider (LP) positions. These tokens are minted when liquidity is added and burned when liquidity is removed.

Token Properties

// ERC-20 standard properties
string public constant name = 'Shibaswap V2';
string public constant symbol = 'SHIB-V2';
uint8 public constant decimals = 18;

// Total supply of LP tokens
uint public totalSupply;

// Mapping of addresses to LP token balances
mapping(address => uint) public balanceOf;

// Mapping of addresses to allowances
mapping(address => mapping(address => uint)) public allowance;

Minting and Burning

LP tokens are minted when liquidity is added and burned when liquidity is removed:
function _mint(address to, uint value) internal {
    totalSupply = totalSupply.add(value);
    balanceOf[to] = balanceOf[to].add(value);
    emit Transfer(address(0), to, value);
}

function _burn(address from, uint value) internal {
    balanceOf[from] = balanceOf[from].sub(value);
    totalSupply = totalSupply.sub(value);
    emit Transfer(from, address(0), value);
}

ERC-20 Functions

The Pair contract implements standard ERC-20 functions:
// Transfer LP tokens
function transfer(address to, uint value) external returns (bool);

// Approve spending of LP tokens
function approve(address spender, uint value) external returns (bool);

// Transfer LP tokens from approved address
function transferFrom(address from, address to, uint value) external returns (bool);
LP tokens represent your share of the liquidity pool. The number of LP tokens you receive when adding liquidity is proportional to your contribution relative to the existing liquidity.

Library Contract

The Library contract provides utility functions for calculating amounts, reserves, and pair addresses. It’s used by the Router and other periphery contracts to perform calculations without making external calls.

Key Functions

// Sort token addresses to ensure consistent ordering
function sortTokens(address tokenA, address tokenB) 
    internal 
    pure 
    returns (address token0, address token1);

// Calculate pair address without external calls
function pairFor(address factory, address tokenA, address tokenB) 
    internal 
    pure 
    returns (address pair);

// Get reserves for a token pair
function getReserves(address factory, address tokenA, address tokenB) 
    internal 
    view 
    returns (uint reserveA, uint reserveB);

// Calculate equivalent value of one asset in terms of another
function quote(uint amountA, uint reserveA, uint reserveB) 
    internal 
    pure 
    returns (uint amountB);

// Calculate output amount for a given input (with fees)
function getAmountOut(uint amountIn, uint reserveIn, uint reserveOut) 
    internal 
    pure 
    returns (uint amountOut);

// Calculate input amount needed for a given output (with fees)
function getAmountIn(uint amountOut, uint reserveIn, uint reserveOut) 
    internal 
    pure 
    returns (uint amountIn);

// Calculate amounts for multi-hop swaps (output amounts)
function getAmountsOut(uint amountIn, address[] memory path) 
    internal 
    view 
    returns (uint[] memory amounts);

// Calculate amounts for multi-hop swaps (input amounts)
function getAmountsIn(address factory, uint amountOut, address[] memory path) 
    internal 
    view 
    returns (uint[] memory amounts);

Usage Examples

The Library is primarily used for:
  • Price calculations before executing swaps
  • Multi-hop routing to find optimal swap paths
  • Liquidity calculations for adding/removing liquidity
  • Reserve queries without direct pair contract calls
The Library contract contains pure and view functions only, making it gas-efficient for calculations and safe to use without state changes.

Router02 Contract

The Router02 contract is the main interface for users to interact with Shibaswap v1. It provides user-friendly functions for all trading and liquidity operations, handling the complexity of direct contract interactions.

Key Properties

// Factory contract address
function factory() external pure returns (address);

// Wrapped ETH contract address
function WETH() external pure returns (address);

Liquidity Functions

Adding Liquidity

// Add liquidity to ERC-20⇄ERC-20 pool
function addLiquidity(
    address tokenA,
    address tokenB,
    uint amountADesired,
    uint amountBDesired,
    uint amountAMin,
    uint amountBMin,
    address to,
    uint deadline
) external returns (uint amountA, uint amountB, uint liquidity);

// Add liquidity to ERC-20⇄ETH pool
function addLiquidityETH(
    address token,
    uint amountTokenDesired,
    uint amountTokenMin,
    uint amountETHMin,
    address to,
    uint deadline
) external payable returns (uint amountToken, uint amountETH, uint liquidity);

Removing Liquidity

// Remove liquidity from ERC-20⇄ERC-20 pool
function removeLiquidity(
    address tokenA,
    address tokenB,
    uint liquidity,
    uint amountAMin,
    uint amountBMin,
    address to,
    uint deadline
) external returns (uint amountA, uint amountB);

// Remove liquidity from ERC-20⇄ETH pool
function removeLiquidityETH(
    address token,
    uint liquidity,
    uint amountTokenMin,
    uint amountETHMin,
    address to,
    uint deadline
) external returns (uint amountToken, uint amountETH);

// Remove liquidity with permit (no approval needed)
function removeLiquidityWithPermit(
    address tokenA,
    address tokenB,
    uint liquidity,
    uint amountAMin,
    uint amountBMin,
    address to,
    uint deadline,
    bool approveMax,
    uint8 v,
    bytes32 r,
    bytes32 s
) external returns (uint amountA, uint amountB);

Swap Functions

Exact Input Swaps

// Swap exact tokens for tokens
function swapExactTokensForTokens(
    uint amountIn,
    uint amountOutMin,
    address[] calldata path,
    address to,
    uint deadline
) external returns (uint[] memory amounts);

// Swap exact ETH for tokens
function swapExactETHForTokens(
    uint amountOutMin,
    address[] calldata path,
    address to,
    uint deadline
) external payable returns (uint[] memory amounts);

// Swap exact tokens for ETH
function swapExactTokensForETH(
    uint amountIn,
    uint amountOutMin,
    address[] calldata path,
    address to,
    uint deadline
) external returns (uint[] memory amounts);

Exact Output Swaps

// Swap tokens for exact tokens
function swapTokensForExactTokens(
    uint amountOut,
    uint amountInMax,
    address[] calldata path,
    address to,
    uint deadline
) external returns (uint[] memory amounts);

// Swap ETH for exact tokens
function swapETHForExactTokens(
    uint amountOut,
    address[] calldata path,
    address to,
    uint deadline
) external payable returns (uint[] memory amounts);

// Swap tokens for exact ETH
function swapTokensForExactETH(
    uint amountOut,
    uint amountInMax,
    address[] calldata path,
    address to,
    uint deadline
) external returns (uint[] memory amounts);

Fee-On-Transfer Support

Router02 includes special functions for tokens with transfer fees:
// Swap functions supporting fee-on-transfer tokens
function swapExactTokensForTokensSupportingFeeOnTransferTokens(
    uint amountIn,
    uint amountOutMin,
    address[] calldata path,
    address to,
    uint deadline
) external;

function swapExactETHForTokensSupportingFeeOnTransferTokens(
    uint amountOutMin,
    address[] calldata path,
    address to,
    uint deadline
) external payable;

function swapExactTokensForETHSupportingFeeOnTransferTokens(
    uint amountIn,
    uint amountOutMin,
    address[] calldata path,
    address to,
    uint deadline
) external;
Use the fee-on-transfer supporting functions when swapping tokens that have transfer fees (like some rebase tokens). These functions account for the actual amount received after fees.

Calculation Functions

The Router02 also provides the same calculation functions as the Library:
// Get quote for equivalent value
function quote(uint amountA, uint reserveA, uint reserveB) 
    external 
    pure 
    returns (uint amountB);

// Calculate output amount
function getAmountOut(uint amountIn, uint reserveIn, uint reserveOut) 
    external 
    pure 
    returns (uint amountOut);

// Calculate input amount
function getAmountIn(uint amountOut, uint reserveIn, uint reserveOut) 
    external 
    pure 
    returns (uint amountIn);

// Calculate amounts for multi-hop swaps
function getAmountsOut(uint amountIn, address[] memory path) 
    external 
    view 
    returns (uint[] memory amounts);

function getAmountsIn(uint amountOut, address[] memory path) 
    external 
    view 
    returns (uint[] memory amounts);

Contract Interactions

The smart contracts work together in the following flow:
  1. Factory creates new Pair contracts for token combinations
  2. Pair contracts handle swaps and liquidity operations
  3. Pair ERC-20 tokens represent LP positions and can be traded or staked
  4. Library provides calculation utilities for amounts and reserves
  5. Router02 provides user-friendly interface for all operations
  6. All contracts interact through the Router for user-friendly operations
Flow diagram showing how Factory, Pair, Pair ERC-20, Library, and Router02 contracts interact
For most users, interaction with these contracts should be done through the Shibaswap Router02 contract, which provides a simplified interface and handles complex operations like optimal swap routing.

Security Considerations

When interacting with Shibaswap v1 smart contracts:
  • Always verify contract addresses from official sources
  • Use the Router contract for swaps and liquidity operations
  • Be aware of slippage and set appropriate limits
  • Consider gas costs when performing multiple operations
  • Verify token approvals before transactions
Never send tokens directly to contract addresses. Always use the proper Router functions or approved interfaces.