Wallet Management
Wallet Types
Wallet Type Purpose Security Level Developer Wallet Testing, deploying to testnet Low (hot wallet OK) Deployer Wallet Mainnet contract deployment Medium (hardware wallet) Treasury Wallet Holding funds, revenue High (multisig) Minter Wallet Backend minting operations Medium (server-side)
Developer Wallet Setup
For local development and testnet:
Install MetaMask
Add Immutable Chain Testnet:
Network Name: Immutable Testnet
RPC: https://rpc.testnet.immutable.com
Chain ID: 13473
Symbol: tIMX
Get test tokens from the Faucet
Hardhat Configuration
// hardhat.config.ts
import { HardhatUserConfig } from 'hardhat/config' ;
const config : HardhatUserConfig = {
<HardhatNetworkConfig />
};
export default config ;
Never commit .env files to version control. Add .env and .env.local to your .gitignore file to prevent accidentally exposing private keys or API secrets.
Production Treasury: Multisig
For production funds, use a multisig wallet like Safe .
Why Multisig?
No single point of failure : Multiple signatures required
Team accountability : Track who approved transactions
Recovery : Lost keys don’t mean lost funds
Setting Up Safe
Go to Safe
Connect to Immutable Chain
Create a new Safe with:
Multiple owner addresses (team members)
Threshold (e.g., 2 of 3 signatures required)
Fund the Safe with IMX for gas
Transaction Flow
Team Member A proposes transaction
↓
Team Member B reviews and signs
↓
Threshold reached → Transaction executes
Backend Minting Wallet
Your backend needs a wallet for minting operations.
Key Management Options
Option Pros Cons Environment Variable Simple Less secure AWS KMS Secure, auditable More complex HashiCorp Vault Enterprise-grade Infrastructure overhead
Using AWS KMS with viem
import { KMSClient , SignCommand } from '@aws-sdk/client-kms' ;
import { createWalletClient , http , type Account } from 'viem' ;
import { immutableZkEvm } from 'viem/chains' ;
// Create a KMS-backed account for viem
async function createKMSAccount ( keyId : string ) : Promise < Account > {
const kms = new KMSClient ({ region: 'us-east-1' });
return {
address: '0x...' , // Derive from KMS public key
type: 'local' ,
signMessage : async ({ message }) => {
const command = new SignCommand ({
KeyId: keyId ,
Message: Buffer . from ( message as string ),
SigningAlgorithm: 'ECDSA_SHA_256' ,
MessageType: 'DIGEST' ,
});
const response = await kms . send ( command );
// Process and return signature
return '0x...' as `0x ${ string } ` ;
},
signTransaction : async ( tx ) => {
// Sign transaction with KMS
return '0x...' as `0x ${ string } ` ;
},
signTypedData : async ( data ) => {
// Sign typed data with KMS
return '0x...' as `0x ${ string } ` ;
},
};
}
// Use with viem
const account = await createKMSAccount ( process . env . KMS_KEY_ID ! );
const walletClient = createWalletClient ({
account ,
chain: immutableZkEvm ,
transport: http (),
});
Rate Limiting & Monitoring
Protect your minting wallet:
import rateLimit from 'express-rate-limit' ;
const mintLimiter = rateLimit ({
windowMs: 60 * 1000 , // 1 minute
max: 100 , // 100 requests per minute
message: 'Too many mint requests' ,
});
app . post ( '/api/mint' , mintLimiter , async ( req , res ) => {
// Log all mint operations
logger . info ( 'Mint request' , {
recipient: req . body . address ,
tokenId: req . body . tokenId ,
timestamp: new Date (),
});
// Process mint...
});
Security Checklist
Development
Production
Gas Management
Estimating Costs
import { createPublicClient , http , formatEther } from 'viem' ;
import { immutableZkEvm } from 'viem/chains' ;
const publicClient = createPublicClient ({
chain: immutableZkEvm ,
transport: http (),
});
async function estimateGas ( to : `0x ${ string } ` , data : `0x ${ string } ` ) {
const gasEstimate = await publicClient . estimateGas ({ to , data });
const gasPrice = await publicClient . getGasPrice ();
const maxCost = gasEstimate * gasPrice ;
console . log ( `Max cost: ${ formatEther ( maxCost ) } IMX` );
}
Maintaining Balance
Set up alerts when wallet balance drops:
import { createPublicClient , http , formatEther , parseEther } from 'viem' ;
import { immutableZkEvm } from 'viem/chains' ;
const publicClient = createPublicClient ({
chain: immutableZkEvm ,
transport: http (),
});
async function checkBalance ( address : `0x ${ string } ` , threshold : bigint ) {
const balance = await publicClient . getBalance ({ address });
if ( balance < threshold ) {
await sendAlert ( `Wallet ${ address } balance low: ${ formatEther ( balance ) } IMX` );
}
}
// Run periodically
setInterval (() => checkBalance ( MINTER_WALLET , parseEther ( '10' )), 60000 );
Funds Recovery
From Passport Wallet
Players control their Passport wallets. Recovery is through their authentication provider (Google, Apple, etc.).
From Studio Wallets
Multisig : Recover with threshold of remaining signers
Single-sig : Depends on backup strategy
KMS : AWS manages key durability
Always test your recovery procedures before you need them.
Next Steps
Contracts Deploy contracts from your secure wallet
Minting Set up backend minting