@paulstinchcombe/gasless-nft-tx
v0.17.6
Published
Complete library for deploying and managing KAMI NFT contracts with truly gasless transactions using EIP-4337 Account Abstraction. Now compatible with OpenZeppelin Contracts v5.
Maintainers
Readme
KAMI Gasless NFT Platform
A comprehensive TypeScript library for truly gasless KAMI NFT operations where users pay ZERO gas fees for all transactions.
🆕 Latest Update: OpenZeppelin v5 Upgrade
✅ Upgraded to OpenZeppelin Contracts v5 - All KAMI contracts now use the latest OpenZeppelin patterns
✅ No Breaking Changes - Existing deployments continue to work seamlessly
✅ Gas Optimizations - Manual counter implementation reduces gas costs
✅ Future-Proofed - Ready for upcoming OpenZeppelin releases
See OPENZEPPELIN_V5_UPGRADE.md for details.
🎯 What This Platform Does
- ✅ 100% Gasless for Users - Users never need ETH for any operation
- ✅ Complete NFT Management - Deploy, mint, rent, sell, and manage NFTs
- ✅ Three NFT Standards - Support for KAMI721C (ERC721), KAMI721AC (ERC721A), and KAMI1155C (ERC1155)
- ✅ Platform-Sponsored - Platform pays all gas costs
- ✅ Public RPC compatible - Platform signing is done locally; works with any RPC that supports
eth_sendRawTransaction(e.g. drpc.org, 1RPC, Ankr) - ✅ Admin Role Management - Platform controls contract administration
- ✅ Token Payment Integration - Users pay with ERC20 tokens
- ✅ Type-Safe - Full TypeScript support with comprehensive type definitions
🏗️ Architecture
┌─────────────────┐ Signs Message ┌──────────────────┐ Pays All Gas ┌────────────────────┐
│ User's EOA ├───────────────────>│ Platform ├───────────────────>│ KAMI Contract │
│ (NO ETH) │ │ SimpleAccount │ │ (executes) │
└─────────────────┘ └──────────────────┘ └────────────────────┘Account Roles
Platform Funding EOA:
- Holds the main ETH balance (treasury)
- Sends ETH to SimpleAccount when needed
- Sends execute calls to SimpleAccount
- Distinct from platformAddress, which receives fees
Platform SimpleAccount:
- Receives ETH from Platform Funding EOA
- Pays for all user operations (deployments, mints, etc.)
- Executes contract deployments
User's EOA:
- Signs messages only
- Never needs ETH
- Owns the deployed contracts
💰 Funding Flow & Requirements
Funding Architecture
The Platform Funding EOA serves as the funding source for the Platform SimpleAccount:
Platform Funding EOA (Treasury) → Platform SimpleAccount (Operations) → User OperationsInitial Setup Requirements
- Platform Funding EOA: Needs ~0.1 ETH for initial setup and ongoing funding
- Platform SimpleAccount: Receives ETH from Platform Funding EOA for operations
- User's EOA: Requires NO ETH (that's the whole point!)
Funding Methods
1. Manual Funding
// Fund SimpleAccount with specific amount
const result = await sponsoredDeployment.fundSimpleAccount(parseEther('0.05'));
if (result.success) {
console.log(`✅ SimpleAccount funded! Transaction: ${result.transactionHash}`);
} else {
console.error(`❌ Funding failed: ${result.error}`);
}2. Auto-Funding on Deployment
The system automatically checks and funds the SimpleAccount when needed:
// Deploy contract (will auto-fund if SimpleAccount balance is low)
const result = await sponsoredDeployment.deployKAMI721C({
contractName: 'My NFT Collection',
contractSymbol: 'MNC',
baseTokenURI: 'https://api.example.com/metadata/',
initialMintPrice: parseEther('0.001'),
platformCommissionPercentage: 250,
userSignature: userSignatureData,
});
// System will automatically:
// 1. Check SimpleAccount balance
// 2. If low, fund it from Platform Funding EOA
// 3. Proceed with deployment3. Balance Monitoring
// Check SimpleAccount balance
const simpleAccountBalance = await sponsoredDeployment.getPlatformBalance();
console.log(`SimpleAccount balance: ${formatEther(simpleAccountBalance)} ETH`);
// Check Platform Funding EOA balance
const platformBalance = await publicClient.getBalance({
address: platformAccount.address,
});
console.log(`Platform Funding EOA balance: ${formatEther(platformBalance)} ETH`);
// Ensure SimpleAccount is funded
const isFunded = await sponsoredDeployment.ensureSimpleAccountFunded();
if (!isFunded) {
console.log('⚠️ SimpleAccount funding failed');
}Funding Flow Example
import { KamiSponsoredDeployment, createUserSignatureData } from '@paulstinchcombe/gasless-nft-tx';
import { parseEther, formatEther } from 'viem';
// Platform configuration
const config = {
rpcUrl: 'https://sepolia.base.org',
platformPrivateKey: process.env.PLATFORM_PRIVATE_KEY,
platformSimpleAccountAddress: process.env.PLATFORM_SIMPLE_ACCOUNT_ADDRESS,
contractDeployerAddress: process.env.CONTRACT_DEPLOYER_ADDRESS,
platformAddress: process.env.PLATFORM_ADDRESS,
paymentToken: process.env.PAYMENT_TOKEN,
};
const sponsoredDeployment = new KamiSponsoredDeployment(config);
async function deployWithFunding() {
// 1. Check balances
const simpleAccountBalance = await sponsoredDeployment.getPlatformBalance();
const platformBalance = await publicClient.getBalance({
address: config.platformPrivateKey ? privateKeyToAccount(config.platformPrivateKey).address : '0x0',
});
console.log(`SimpleAccount balance: ${formatEther(simpleAccountBalance)} ETH`);
console.log(`Platform Funding EOA balance: ${formatEther(platformBalance)} ETH`);
// 2. Fund SimpleAccount if needed
if (simpleAccountBalance < parseEther('0.01')) {
console.log('🔄 Funding SimpleAccount...');
const fundResult = await sponsoredDeployment.fundSimpleAccount(parseEther('0.05'));
if (!fundResult.success) {
throw new Error(`Funding failed: ${fundResult.error}`);
}
console.log(`✅ SimpleAccount funded! Transaction: ${fundResult.transactionHash}`);
}
// 3. Deploy contract (will auto-fund if needed)
const userSignatureData = createUserSignatureData(
userAddress,
'My NFT Collection',
'MNC',
'https://api.example.com/metadata/',
parseEther('0.001'),
250,
userSignature
);
const result = await sponsoredDeployment.deployKAMI721C({
contractName: 'My NFT Collection',
contractSymbol: 'MNC',
baseTokenURI: 'https://api.example.com/metadata/',
initialMintPrice: parseEther('0.001'),
platformCommissionPercentage: 250,
userSignature: userSignatureData,
});
if (result.success) {
console.log(`🎉 Contract deployed: ${result.contractAddress}`);
console.log(`💰 Gas paid by: Platform`);
console.log(`💸 User paid: ZERO ETH`);
} else {
console.error(`❌ Deployment failed: ${result.error}`);
}
}Cost Management
Platform Costs
- Contract Deployment: ~0.015 ETH per contract
- Token Minting: ~0.003 ETH per token
- Other Operations: ~0.001-0.002 ETH per operation
Funding Strategy
// Recommended funding amounts
const FUNDING_AMOUNTS = {
INITIAL_SETUP: parseEther('0.1'), // Initial SimpleAccount funding
TOP_UP: parseEther('0.05'), // Regular top-up amount
MINIMUM_BALANCE: parseEther('0.01'), // Minimum balance threshold
PLATFORM_EOA_MIN: parseEther('0.02'), // Minimum Platform Funding EOA balance
};
// Auto-funding logic
async function manageFunding() {
const simpleAccountBalance = await sponsoredDeployment.getPlatformBalance();
const platformBalance = await publicClient.getBalance({
address: platformAccount.address,
});
// Check if SimpleAccount needs funding
if (simpleAccountBalance < FUNDING_AMOUNTS.MINIMUM_BALANCE) {
if (platformBalance >= FUNDING_AMOUNTS.TOP_UP) {
await sponsoredDeployment.fundSimpleAccount(FUNDING_AMOUNTS.TOP_UP);
} else {
console.warn('⚠️ Platform Funding EOA balance too low for funding');
}
}
}📚 Documentation
🚀 Quick Start
Comprehensive Guide ⭐ START HERE
Complete guide covering everything you need to know:
- Platform architecture and setup
- Quick start examples
- Complete API reference
- Frontend and backend integration
- Security considerations
- Advanced configuration
- Troubleshooting guide
📖 Detailed Guides
API Reference
Complete API documentation:
- All classes, methods, and interfaces
- Parameter and return type definitions
- Error handling and types
- Advanced usage examples
- Performance considerations
Deployment Guide
Infrastructure setup and deployment:
- Platform setup and configuration
- Contract deployment process
- Admin role management
- Cost analysis and monitoring
Operations Guide
All NFT operations and management:
- Minting, renting, selling, and management operations
- Frontend and backend integration
- User signature verification
- Complete operation examples
Security Guide
Security best practices and implementation:
- Private key management
- Signature security
- Access control
- Monitoring and alerting
- Incident response
🚀 Quick Start
Prerequisites
This project uses pnpm as the package manager. Make sure you have pnpm installed:
# Install pnpm globally if you haven't already
npm install -g pnpm
# Or using corepack (recommended)
corepack enable
corepack prepare pnpm@latest --activate1. Installation
pnpm install @paulstinchcombe/gasless-nft-tx2. Create Platform Funding EOA (Required)
The Platform Funding EOA is your treasury account that funds all operations:
# Generate a new private key for the platform
node -e "console.log('0x' + require('crypto').randomBytes(32).toString('hex'))"
# Set as environment variable
export PRIVATE_KEY=0x[GENERATED_PRIVATE_KEY]
# Fund this account with ETH (~0.1 ETH recommended)
# Send ETH from your main account to the Platform Funding EOA address3. Deploy Infrastructure (One-Time Setup)
# Deploy all infrastructure needed for sponsored transactions
npx tsx setup-sponsored-infrastructure.tsThis will deploy:
- SimpleAccountFactory
- Platform SimpleAccount (funded with ETH)
- ContractDeployer helper
- KAMI Libraries
4. Environment Configuration
Create a .env file with the addresses from the setup:
# Platform Configuration (from setup)
PLATFORM_PRIVATE_KEY="0x..." # Platform Funding EOA's private key (has ETH)
PLATFORM_SIMPLE_ACCOUNT_ADDRESS="0x..." # Platform's SimpleAccount (has ETH)
CONTRACT_DEPLOYER_ADDRESS="0x..." # ContractDeployer address
PLATFORM_ADDRESS="0x..." # Platform address (for receiving ERC20 commissions)
PAYMENT_TOKEN="0x..." # Payment token address (USDC, etc.)
# Network Configuration
RPC_URL="https://sepolia.base.org"5. Platform Setup
import { KamiSponsoredOperations, KamiSponsoredDeployment } from '@paulstinchcombe/gasless-nft-tx';
// Platform configuration
const config = {
rpcUrl: 'https://sepolia.base.org',
platformPrivateKey: process.env.PLATFORM_PRIVATE_KEY, // Platform's key (has ETH)
platformSimpleAccountAddress: process.env.PLATFORM_SIMPLE_ACCOUNT_ADDRESS, // Platform's SA (has ETH)
contractDeployerAddress: process.env.CONTRACT_DEPLOYER_ADDRESS,
platformAddress: process.env.PLATFORM_ADDRESS,
paymentToken: process.env.PAYMENT_TOKEN,
};
// Create handlers
const sponsoredDeployment = new KamiSponsoredDeployment(config);
const sponsoredOps = new KamiSponsoredOperations(config);6. Deploy Contract (Sponsored)
// User signs message for deployment (no ETH needed)
const userSignature = createUserSignatureData(
userAddress,
"Paul's NFT Collection",
'PNC',
'https://api.example.com/metadata/',
parseEther('0.001'),
250, // 2.5% platform commission
userSignature
);
// Platform deploys contract with sponsored gas
const result = await sponsoredDeployment.deployKAMI721C({
contractName: "Paul's NFT Collection",
contractSymbol: 'PNC',
baseTokenURI: 'https://api.example.com/metadata/',
initialMintPrice: parseEther('0.001'),
platformCommissionPercentage: 250,
userSignature,
});
console.log('Contract deployed:', result.contractAddress);
console.log('Gas paid by: Platform');
console.log('User paid: ZERO ETH');7. Mint Token (Sponsored)
// User signs message for minting (no ETH needed)
const mintSignature = createSponsoredOperationSignature(
userAddress,
'mint',
contractAddress,
{
recipient: userAddress,
tokenPrice: parseEther('0.001'),
uri: 'https://api.example.com/metadata/1',
mintRoyalties: [
{ receiver: userAddress, percentage: 500 },
{ receiver: platformAddress, percentage: 250 },
],
},
userSignature
);
// Platform mints token with sponsored gas
const result = await sponsoredOps.mintToken(
contractAddress,
'KAMI721C',
{
recipient: userAddress,
tokenPrice: parseEther('0.001'),
uri: 'https://api.example.com/metadata/1',
mintRoyalties: [
{ receiver: userAddress, percentage: 500 },
{ receiver: platformAddress, percentage: 250 },
],
},
mintSignature
);
console.log('Token minted:', result.data?.tokenId);
console.log('Gas paid by: Platform');
console.log('User paid: ZERO ETH');📋 Supported Operations
Deployment Operations
- ✅ Deploy KAMI721C - ERC721 with Creator features
- ✅ Deploy KAMI721AC - ERC721A with batch minting
- ✅ Deploy KAMI1155C - ERC1155 multi-token
Minting Operations
- ✅ Mint tokens with custom prices and royalties
- ✅ Batch minting for KAMI721AC
- ✅ Multi-token minting for KAMI1155C
Rental Operations
- ✅ Rent tokens for specific durations
- ✅ Extend rentals with additional payment
- ✅ End rentals when duration expires
Sales Operations
- ✅ Sell tokens to other users
- ✅ Transfer ownership with payment
Management Operations
- ✅ Set token prices individually
- ✅ Set token URIs for metadata
- ✅ Set token royalties and recipients
- ✅ Contract administration (pause/unpause)
💰 Cost Analysis
User Costs
- Gas Fees: ZERO ETH ✅
- Transaction Fees: ZERO ETH ✅
- All Operations: ZERO ETH ✅
Platform Costs
- Contract Deployment: ~0.015 ETH per contract
- Token Minting: ~0.003 ETH per token
- Other Operations: ~0.001-0.002 ETH per operation
🔧 Environment Setup
Required Environment Variables
Create a .env file with the following variables:
# Platform Configuration (Required)
PLATFORM_PRIVATE_KEY="0x..." # Platform Funding EOA's private key (has ETH for funding)
PLATFORM_SIMPLE_ACCOUNT_ADDRESS="0x..." # Platform's SimpleAccount (receives ETH)
CONTRACT_DEPLOYER_ADDRESS="0x..." # ContractDeployer helper address
PLATFORM_ADDRESS="0x..." # Platform address (for receiving ERC20 commissions)
PAYMENT_TOKEN="0x..." # Payment token address (USDC, etc.)
# Network Configuration
RPC_URL="https://sepolia.base.org" # RPC endpointAccount Setup Process
Generate Platform Funding EOA:
# Generate private key node -e "console.log('0x' + require('crypto').randomBytes(32).toString('hex'))" # Set environment variable export PRIVATE_KEY=0x[GENERATED_PRIVATE_KEY]Fund Platform Funding EOA:
- Send ~0.1 ETH to the Platform Funding EOA address
- This account will fund the SimpleAccount for operations
Deploy Infrastructure:
pnpm exec tsx setup-sponsored-infrastructure.tsUpdate Environment Variables:
- Copy the addresses from the setup output
- Update your
.envfile with the new addresses
Balance Requirements
| Account | Purpose | Minimum Balance | Recommended | | -------------------------- | ---------------- | --------------- | ----------- | | Platform Funding EOA | Treasury/Funding | 0.02 ETH | 0.1 ETH | | Platform SimpleAccount | Operations | 0.01 ETH | 0.05 ETH | | User's EOA | Signatures Only | 0 ETH | 0 ETH |
Funding Management
// Check balances
const simpleAccountBalance = await sponsoredDeployment.getPlatformBalance();
const platformBalance = await publicClient.getBalance({
address: platformAccount.address,
});
console.log(`SimpleAccount: ${formatEther(simpleAccountBalance)} ETH`);
console.log(`Platform Funding EOA: ${formatEther(platformBalance)} ETH`);
// Auto-fund if needed
if (simpleAccountBalance < parseEther('0.01')) {
await sponsoredDeployment.fundSimpleAccount(parseEther('0.05'));
}📚 Documentation
- Sponsored Deployment Guide - Complete deployment guide
- Sponsored Operations Guide - Complete operations guide
- Migration Guide - Migrate from old gasless to sponsored
- Examples - Working examples and frontend integration
🚀 Examples
Infrastructure Setup
# Deploy all infrastructure (one-time setup)
pnpm exec tsx setup-sponsored-infrastructure.ts
# Deploy individual components
pnpm exec tsx deploy-simpleaccount.ts
pnpm exec tsx deploy-contract-deployer.ts
pnpm exec tsx deploy-kami-libraries.tsBackend Examples
# Deploy contracts with sponsored gas
pnpm exec tsx examples/sponsored-deployment-example.ts
# Perform all operations with sponsored gas
pnpm exec tsx examples/sponsored-operations-example.tsFrontend Examples
// User signs message for any operation
const { userAddress, signature, nonce } = await requestUserSignatureForOperation(
'mint',
contractAddress,
{
recipient: userAddress,
tokenPrice: parseEther('0.001'),
uri: 'https://api.example.com/metadata/1',
mintRoyalties: [
{ receiver: userAddress, percentage: 500 },
{ receiver: platformAddress, percentage: 250 },
],
},
userAddress
);🛡️ Security
- Signature Verification: All user signatures are verified
- Replay Protection: Nonce and timestamp prevent replay attacks
- Parameter Validation: All operation parameters are validated
- Platform Security: Platform private keys are kept secure
🛠️ Troubleshooting
Common Funding Issues
1. "Insufficient balance" Error
Error: The total cost (gas * gas fee + value) of executing this transaction exceeds the balance of the account.Solution: Check which account has insufficient balance:
// Check Platform Funding EOA balance
const platformBalance = await publicClient.getBalance({
address: platformAccount.address,
});
// Check SimpleAccount balance
const simpleAccountBalance = await sponsoredDeployment.getPlatformBalance();
console.log(`Platform Funding EOA: ${formatEther(platformBalance)} ETH`);
console.log(`SimpleAccount: ${formatEther(simpleAccountBalance)} ETH`);2. "Function constructor not found on ABI" Error
Error: Function "constructor" not found on ABI.Solution: This was fixed in v0.8.1. Update to the latest version:
pnpm install @paulstinchcombe/gasless-nft-tx@latest3. Transaction Sent from Wrong Account
from: 0xeaA30cdd68C6002e0ebA0Bed2374223561D0785E # User's address (wrong!)Solution: Check your PLATFORM_PRIVATE_KEY environment variable:
# This should be the Platform Funding EOA's private key, NOT the user's
export PLATFORM_PRIVATE_KEY=0x[PLATFORM_PRIVATE_KEY]4. SimpleAccount Balance Too Low
Error: Insufficient SimpleAccount balance: 0.005 ETH (minimum required: 0.01 ETH)Solution: Fund the SimpleAccount:
// Manual funding
await sponsoredDeployment.fundSimpleAccount(parseEther('0.05'));
// Or let the system auto-fund
const result = await sponsoredDeployment.deployKAMI721C(params);
// System will auto-fund if neededDebugging Steps
Check Account Addresses:
console.log(`Platform Funding EOA: ${platformAccount.address}`); console.log(`SimpleAccount: ${config.platformSimpleAccountAddress}`); console.log(`User Address: ${userSignature.userAddress}`);Check Balances:
const balances = await Promise.all([ publicClient.getBalance({ address: platformAccount.address }), sponsoredDeployment.getPlatformBalance(), ]); console.log(`Platform Funding EOA: ${formatEther(balances[0])} ETH`); console.log(`SimpleAccount: ${formatEther(balances[1])} ETH`);Test Funding:
const fundResult = await sponsoredDeployment.fundSimpleAccount(parseEther('0.01')); console.log(`Funding result:`, fundResult);
Environment Variable Checklist
- [ ]
PLATFORM_PRIVATE_KEY- Platform Funding EOA's private key (has ETH) - [ ]
PLATFORM_SIMPLE_ACCOUNT_ADDRESS- Platform's SimpleAccount address - [ ]
CONTRACT_DEPLOYER_ADDRESS- ContractDeployer address - [ ]
PLATFORM_ADDRESS- Platform address (for ERC20 commissions) - [ ]
PAYMENT_TOKEN- Payment token address - [ ]
RPC_URL- RPC endpoint URL
🎯 Benefits
- True Gasless Experience: Users never need ETH
- Complete Operation Coverage: All KAMI functions supported
- Platform Control: Platform manages all gas costs
- User Ownership: Operations affect user's contracts
- Scalable: One platform SimpleAccount serves all users
- Cost Effective: Platform pays only for actual operations
🔧 API Reference
Sponsored Deployment
// Deploy KAMI721C
const result = await sponsoredDeployment.deployKAMI721C(params);
// Deploy KAMI721AC
const result = await sponsoredDeployment.deployKAMI721AC(params);
// Deploy KAMI1155C
const result = await sponsoredDeployment.deployKAMI1155C(params);Sponsored Operations
// Mint token
const result = await sponsoredOps.mintToken(contractAddress, contractType, params, signature);
// Rent token
const result = await sponsoredOps.rentToken(contractAddress, contractType, params, signature);
// Sell token
const result = await sponsoredOps.sellToken(contractAddress, contractType, params, signature);
// Set price
const result = await sponsoredOps.setPrice(contractAddress, contractType, params, signature);
// Set URI
const result = await sponsoredOps.setTokenURI(contractAddress, contractType, params, signature);
// Set royalties
const result = await sponsoredOps.setTokenRoyalties(contractAddress, contractType, params, signature);
// Pause contract
const result = await sponsoredOps.pauseContract(contractAddress, contractType, signature);
// Unpause contract
const result = await sponsoredOps.unpauseContract(contractAddress, contractType, signature);🚀 Getting Started
- Install pnpm:
npm install -g pnpmor usecorepack enable - Install the library:
pnpm install @paulstinchcombe/gasless-nft-tx - Set up environment: Create
.envfile with platform configuration - Deploy infrastructure: Deploy ContractDeployer and libraries (one-time setup)
- Start using: Deploy contracts and perform operations with sponsored gas!
📄 License
MIT License - see LICENSE file for details.
🤝 Contributing
Contributions are welcome! Please read our contributing guidelines and submit pull requests.
📞 Support
For support and questions:
- Create an issue on GitHub
- Check the documentation
- Review the examples
🎉 Enjoy truly gasless NFT operations with the Sponsored KAMI NFT Transactions Library!
