Skip to main content

Documentation Index

Fetch the complete documentation index at: https://docs.skale.space/llms.txt

Use this file to discover all available pages before exploring further.

Accept fully confidential payments using the MPP SDK on SKALE chains with Programmable Privacy. Confidential tokens (eUSDC) provide native privacy — hiding sender, receiver, and amount onchain.

Prerequisites

  • Node.js, Bun, or pnpm installed
  • SKALE chain with Programmable Privacy access (SKALE Base Sepolia)
  • eUSDC tokens for testing
  • Understanding of confidential tokens vs standard tokens

Overview

Confidential token features:
  • Native privacy – Amounts hidden by default at the token level
  • Optional encryption – Add threshold encryption for extra security
  • Gasless support – EIP-3009 for gas-free UX
  • Chains with Programmable Privacy only – Requires a privacy-enabled chain

Environment Setup

Create a .env file:
# SKALE Base Sepolia RPC
SKALE_RPC=https://base-sepolia-testnet.skalenodes.com/v1/jubilant-horrible-ancha

# Your receiving address
RECEIVING_ADDRESS=0xYourReceivingAddress

# Chain configuration
CHAIN=skale-base-sepolia
CURRENCY=eUSDC

Confidential Token Payment

Basic confidential payment with eUSDC:
import { mpp } from '@skalenetwork/mpp/client'
import { createWalletClient, http } from 'viem'
import { privateKeyToAccount } from 'viem/accounts'

// Setup wallet
const account = privateKeyToAccount('0xYourPrivateKey')
const walletClient = createWalletClient({
  account,
  transport: http(process.env.SKALE_RPC)
})

// Create confidential payment method
const confidentialPayment = mpp.charge({
  chain: 'skale-base-sepolia',
  currency: 'eUSDC',
  extensions: {
    skale: { confidentialToken: true }
  }
})

async function processConfidentialPayment(amount: string) {
  const tx = await confidentialPayment.createTransfer({
    to: process.env.RECEIVING_ADDRESS,
    amount: amount, // Amount in base units
    from: account.address
  })
  
  const hash = await walletClient.sendTransaction(tx)
  console.log('Confidential payment sent:', hash)
  return hash
}

// Process 5 eUSDC privately
await processConfidentialPayment('5000000')

Gasless Confidential Payments

Combine gasless UX with full privacy:
const gaslessConfidential = mpp.charge({
  chain: 'skale-base-sepolia',
  currency: 'eUSDC',
  extensions: {
    skale: { confidentialToken: true },
    gasless: 'eip3009'
  }
})

async function processPrivateGaslessPayment(amount: string) {
  const tx = await gaslessConfidential.createTransfer({
    to: process.env.RECEIVING_ADDRESS,
    amount: amount,
    from: account.address
  })
  
  const hash = await walletClient.sendTransaction(tx)
  console.log('Private gasless payment:', hash)
  return hash
}

Maximum Privacy (All Features)

Enable all privacy layers:
const fullPrivacy = mpp.charge({
  chain: 'skale-base-sepolia',
  currency: 'eUSDC',
  extensions: {
    skale: { 
      encrypted: true,      // Threshold encryption
      confidentialToken: true // Native token privacy
    },
    gasless: 'eip3009'        // No gas needed
  }
})

async function processMaximumPrivacy(amount: string) {
  const tx = await fullPrivacy.createTransfer({
    to: process.env.RECEIVING_ADDRESS,
    amount: amount,
    from: account.address
  })
  
  const hash = await walletClient.sendTransaction(tx)
  console.log('Maximum privacy payment:', hash)
  return hash
}

Server Integration

Backend processing for confidential payments:
import { mpp } from '@skalenetwork/mpp/server'
import express from 'express'

const app = express()

const confidentialMethod = mpp.charge({
  chain: 'skale-base-sepolia',
  currency: 'eUSDC',
  extensions: {
    skale: { confidentialToken: true },
    gasless: 'eip3009'
  }
})

app.post('/api/private-payment', async (req, res) => {
  const { amount, from, proof } = req.body
  
  try {
    // Verify proof (confidential token specific)
    const isValid = await verifyConfidentialProof(proof)
    if (!isValid) throw new Error('Invalid proof')
    
    const tx = await confidentialMethod.createTransfer({
      to: process.env.RECEIVING_ADDRESS,
      amount,
      from
    })
    
    res.json({ success: true, txData: tx })
  } catch (error) {
    res.status(400).json({ error: error.message })
  }
})

Payment Verification

Verifying confidential transactions:
import { createPublicClient, http } from 'viem'

const publicClient = createPublicClient({
  transport: http(process.env.SKALE_RPC)
})

async function verifyConfidentialPayment(txHash: string) {
  const receipt = await publicClient.getTransactionReceipt({ hash: txHash })
  
  if (receipt.status !== 'success') {
    throw new Error('Transaction failed')
  }
  
  // Confidential tokens emit different events
  // Check for confidential transfer events
  const confidentialEvents = receipt.logs.filter(
    log => log.topics[0] === '0xConfidentialTransferTopic'
  )
  
  console.log('Confidential payment verified')
  return { verified: true, events: confidentialEvents }
}

Testing on SKALE Base Sepolia

SKALE Base Sepolia supports confidential tokens for testing:
SKALE_RPC=https://base-sepolia-testnet.skalenodes.com/v1/jubilant-horrible-ancha
CHAIN=skale-base-sepolia
CURRENCY=eUSDC
const testConfidential = mpp.charge({
  chain: 'skale-base-sepolia',
  currency: 'eUSDC',
  extensions: {
    skale: { confidentialToken: true },
    gasless: 'eip3009'
  }
})

const tx = await testConfidential.createTransfer({
  to: '0xTestReceiver',
  amount: '100000', // 0.1 eUSDC
  from: account.address
})

Comparing Payment Types

FeatureStandardGaslessEncryptedConfidential
ChainSKALE BaseSKALE BaseSKALE BaseSKALE Base Sepolia
TokenUSDC.eUSDC.eUSDC.eeUSDC
Gas tokenCREDIT requiredNot neededCREDIT requiredNot needed (gasless)
Amount visibleHiddenHidden
Native privacy---

Error Handling

try {
  const hash = await processConfidentialPayment('1000000')
} catch (error) {
  if (error.message.includes('BITE')) {
    console.error('Not on a chain with Programmable Privacy')
  } else if (error.message.includes('confidential')) {
    console.error('Token not configured for confidentiality')
  } else if (error.message.includes('eUSDC')) {
    console.error('Insufficient eUSDC balance')
  }
}

Best Practices

When to use confidential tokens:
  • Maximum privacy requirements
  • Sensitive transaction amounts
  • Chains with Programmable Privacy available
  • Users comfortable with eUSDC
Important considerations:
  • Confidential tokens only work on chains with Programmable Privacy
  • eUSDC is different from USDC.e (different addresses)
  • Always test on SKALE Base Sepolia first
  • Verify chain supports Programmable Privacy before deploying

Resources