Skip to main content
The MPP SDK is compatible with both JavaScript and TypeScript in Node.js, Bun, and browser environments. npm version If you have any issues, please join us in Discord or open an issue on GitHub.
Code examples in this page use the exact currency identifiers configured on each supported chain, such as USDC.e on SKALE Base and eUSDC on BITE Sandbox. In your application UI, you can still present a normalized display label like USDC if that is clearer for users.

Overview

The MPP SDK enables developers to integrate private, gasless payments into their applications on the SKALE Network. It provides support for:
  • Standard transfers on SKALE Base
  • Gasless payments via EIP-3009 and EIP-2612 permits
  • BITE encryption for confidential transaction amounts
  • Confidential tokens for native privacy

Installation

# npm
npm install @skalenetwork/mpp

# yarn
yarn add @skalenetwork/mpp

# pnpm
pnpm add @skalenetwork/mpp

# bun
bun add @skalenetwork/mpp

Quick Start

Client-Side Usage

import { mpp } from '@skalenetwork/mpp/client'

// Standard transfer on SKALE Base
const method = mpp.charge({
  chain: 'skale-base',
  currency: 'USDC.e'
})

// Gasless with EIP-3009
const gaslessMethod = mpp.charge({
  chain: 'skale-base',
  currency: 'USDC.e',
  extensions: { gasless: 'eip3009' }
})

// BITE encryption for confidential transaction amounts
const encryptedMethod = mpp.charge({
  chain: 'skale-base',
  currency: 'USDC.e',
  extensions: { skale: { encrypted: true } }
})

// Confidential token with native privacy + gasless
const confidentialMethod = mpp.charge({
  chain: 'bite-sandbox',
  currency: 'eUSDC',
  extensions: {
    skale: { encrypted: true, confidentialToken: true },
    gasless: 'eip3009'
  }
})

Server-Side Usage

import { mpp } from '@skalenetwork/mpp/server'

const method = mpp.charge({
  chain: 'skale-base',
  currency: 'USDC.e',
  extensions: { gasless: 'eip3009' }
})

// In your MPPx server setup
const mppx = Mppx.create({
  methods: [method],
  realm: 'api.example.com',
  secretKey: process.env.MPP_SECRET
})
MPP_SECRET is a server-only secret used by your MPPx backend to sign or verify payment requests. Generate a long random value for your application, store it in your server environment, and never expose it in client-side code or commit it to your repository.

Supported Chains

ChainNetworkChain ID
skale-baseSKALE Base Mainnet284351530983
skale-base-sepoliaSKALE Base Testnet2024883468
bite-sandboxBITE Sandbox Testnet103698795
baseBase Mainnet8453
base-sepoliaBase Sepolia84532

API Reference

mpp.charge(options)

Creates a payment method for MPP integration. Parameters:
  • chain: string | Chain – Chain identifier (string) or custom viem Chain object
  • currency: string | CurrencyConfig – Currency identifier or custom configuration
  • extensions?: object – Optional extensions for gasless and privacy features
Returns: PaymentMethod – Configured payment method for MPP

Extensions

Gasless Payments

Enable gasless transactions using EIP-3009 or EIP-2612:
extensions: { gasless: 'eip3009' }  // EIP-3009 transfer with authorization
extensions: { gasless: 'eip2612' }  // ERC-2612 permit
extensions: { gasless: true }       // Auto-detect EIP-3009
Gasless payments allow users to pay without holding the native gas token (sFUEL/ETH). The transaction fees are deducted from the token being transferred.

BITE Encryption

Encrypt transaction amounts onchain:
extensions: { skale: { encrypted: true } }
BITE encryption uses threshold encryption to hide transaction amounts while maintaining verifiability. Requires a BITE-enabled SKALE chain.

Confidential Tokens

Use native confidential tokens with built-in privacy:
extensions: {
  skale: {
    encrypted: true,
    confidentialToken: true
  }
}
Confidential tokens are native tokens with built-in privacy features. Currently available on BITE Sandbox testnet with tokens like eUSDC.

Payment Strategies

The SDK supports various combinations of features:
ChainCurrencyGaslessEncryptedConfidential Token
skale-baseUSDC.eOptionalNo
bite-sandboxeUSDCAlwaysYes
Feature details:
  • Gasless: EIP-3009 transfer with authorization, eliminating gas fees
  • Encrypted: Transaction “to” address and amounts are encrypted in the mempool until onchain execution, after which they become visible on the ledger
  • Confidential Token: Native confidential tokens (e.g., eUSDC) provide fully shielded balances and transaction amounts that remain private even onchain

Custom Chains

You can use any viem Chain object for custom chain configurations:
import { mpp } from '@skalenetwork/mpp/client'
import { defineChain } from 'viem'

const myChain = defineChain({
  id: 123456,
  name: 'My Chain',
  nativeCurrency: { name: 'ETH', symbol: 'ETH', decimals: 18 },
  rpcUrls: {
    default: { http: ['https://mychain.rpc'] }
  }
})

const method = mpp.charge({
  chain: myChain,
  currency: {
    address: '0xTokenAddress...',
    symbol: 'TOKEN',
    decimals: 18,
    eip3009: true
  }
})
Custom chain configurations support standard ERC-20 transfers and EIP-3009 gasless payments only. BITE encryption and confidential tokens require built-in chain configurations with specific contract addresses and cannot be used with custom chains.

Best Practices

Choosing the Right Configuration

Select the simplest configuration that meets your privacy and UX requirements. Standard transfers are fastest and most cost-effective, while full privacy configurations provide maximum confidentiality.

Testing

Always test payment flows on testnet before mainnet deployment:
  • Use skale-base-sepolia or bite-sandbox for testing
  • Verify gasless transactions work with your token contracts
  • Test encrypted transaction decryption and retrieval

Security Considerations

When using server-side MPP integration, never expose your secretKey in client-side code. Always handle sensitive credentials in secure server environments.

Browser Compatibility

When using the SDK in browser environments, you may need to polyfill Buffer. Install the buffer package and configure your bundler:
npm install buffer
For Vite, add to your vite.config.ts:
import { defineConfig } from 'vite'

export default defineConfig({
  resolve: {
    alias: {
      buffer: 'buffer',
    },
  },
})
For Webpack 5, add to your webpack.config.js:
module.exports = {
  resolve: {
    fallback: {
      buffer: require.resolve('buffer/'),
    },
  },
}

Resources