Admin Module API Reference
Complete API documentation for the dolphinpay::admin module.
Overview
The Admin module (admin.move) handles platform administration:
- Global platform configuration (default fees, statistics)
- Merchant fee management (set custom fees per merchant)
- Merchant status control (force activate/deactivate)
- Platform statistics tracking (merchants, payments, volume)
- Single admin capability for secure access control
Package Location: dolphinpay::admin
Architecture
Admin Capability Pattern
DolphinPay uses a single AdminCap pattern for platform administration:
┌─────────────────────────────────────┐
│ Admin Capability Architecture │
├─────────────────────────────────────┤
│ │
│ Module Initialization │
│ ├─► Create AdminCap (unique) │
│ ├─► Transfer to Deployer │
│ └─► Share AdminConfig │
│ │
│ Admin Operations (require AdminCap)│
│ ├─► Set Merchant Fees │
│ ├─► Force Activate/Deactivate │
│ ├─► Update Platform Stats │
│ └─► Set Default Fees │
│ │
│ Query Operations (no cap required) │
│ ├─► Get Platform Stats │
│ ├─► Get Default Fee │
│ └─► Get Merchant Counts │
│ │
└─────────────────────────────────────┘
Data Structures
AdminCap
Single admin capability object for platform control.
public struct AdminCap has key, store {
id: UID,
}
Fields:
id- Unique object identifier
Creation:
- Created once during module initialization
- Transferred to deployer address
- Only one AdminCap should exist
Security:
- ⚠️ CRITICAL: Must be stored securely
- Loss of AdminCap = loss of platform control
- Should be held by platform owner only
AdminConfig
Global configuration object for platform settings.
public struct AdminConfig has key {
id: UID,
default_platform_fee_bps: u64,
total_merchants: u64,
total_payments: u64,
total_volume: u64,
}
Fields:
id- Unique object identifierdefault_platform_fee_bps- Default fee for new merchants (basis points)total_merchants- Total number of registered merchantstotal_payments- Total number of payments processedtotal_volume- Total payment volume (in smallest unit)
Sharing:
- Shared globally during initialization
- Readable by anyone
- Writable only by admin (with AdminCap)
Constants
Fee Limits
const MAX_PLATFORM_FEE_BPS: u64 = 1000; // 10% maximum platform fee
Default Fee:
- New merchants start with 30 bps (0.3%) platform fee
- Set in
init()function
Error Codes
const E_NOT_AUTHORIZED: u64 = 1; // Caller lacks AdminCap
const E_INVALID_FEE: u64 = 100; // Fee is invalid
const E_FEE_TOO_HIGH: u64 = 101; // Fee exceeds maximum
Module Initialization
init
Called automatically when module is published.
fun init(ctx: &mut TxContext)
Effects:
- Creates AdminCap
- Creates AdminConfig with default values
- Transfers AdminCap to deployer
- Shares AdminConfig globally
Initial Config Values:
default_platform_fee_bps: 30 (0.3%)total_merchants: 0total_payments: 0total_volume: 0
Note: This function runs exactly once during deployment.
Admin Functions
All admin functions require AdminCap for authorization.
set_merchant_platform_fee
Sets custom platform fee for a specific merchant.
public entry fun set_merchant_platform_fee(
_admin_cap: &AdminCap,
merchant: &mut Merchant,
fee_bps: u64,
)
Parameters:
_admin_cap- Admin capability (proves authorization)merchant- Mutable reference to merchant objectfee_bps- New platform fee in basis points (1 bps = 0.01%)
Effects:
- Updates merchant's platform fee
- Overrides default platform fee
- Allows merchant-specific pricing
Errors:
E_FEE_TOO_HIGH- Fee exceeds MAX_PLATFORM_FEE_BPS (1000 = 10%)
Example:
// Using SDK
const txb = client.admin.buildSetMerchantPlatformFee({
adminCapId: '0xADMIN_CAP_ID',
merchantObjectId: '0xMERCHANT_ID',
feeBps: 50, // 0.5% custom fee
});
await adminWallet.signAndExecuteTransactionBlock({ transactionBlock: txb });
Use Cases:
- Premium merchants: Lower fees (e.g., 20 bps = 0.2%)
- High-volume merchants: Volume discounts
- Trial merchants: Temporary fee adjustments
- Special partnerships: Custom fee structures
set_default_platform_fee
Sets global default platform fee for all new merchants.
public entry fun set_default_platform_fee(
_admin_cap: &AdminCap,
config: &mut AdminConfig,
fee_bps: u64,
)
Parameters:
_admin_cap- Admin capabilityconfig- Mutable reference to AdminConfigfee_bps- New default platform fee in basis points
Effects:
- Updates
default_platform_fee_bpsin AdminConfig - Affects all newly registered merchants
- Does not affect existing merchants
Errors:
E_FEE_TOO_HIGH- Fee exceeds maximum (1000 bps)
Example:
const txb = client.admin.buildSetDefaultPlatformFee({
adminCapId: '0xADMIN_CAP_ID',
adminConfigId: '0xADMIN_CONFIG_ID',
feeBps: 25, // Change default to 0.25%
});
await adminWallet.signAndExecuteTransactionBlock({ transactionBlock: txb });
Note: Existing merchants keep their current fee until individually updated.
force_deactivate_merchant
Force deactivates a merchant (admin override).
public entry fun force_deactivate_merchant(
_admin_cap: &AdminCap,
merchant: &mut Merchant,
)
Parameters:
_admin_cap- Admin capabilitymerchant- Mutable reference to merchant
Effects:
- Sets merchant
is_activetofalse - Merchant can no longer accept new payments
- Existing pending payments can still be executed
Use Cases:
- Policy violations
- Security concerns
- Temporary suspension
- Compliance requirements
Example:
const txb = client.admin.buildForceDeactivateMerchant({
adminCapId: '0xADMIN_CAP_ID',
merchantObjectId: '0xMERCHANT_ID',
});
await adminWallet.signAndExecuteTransactionBlock({ transactionBlock: txb });
Important: This bypasses merchant owner's control.
force_activate_merchant
Force activates a merchant (admin override).
public entry fun force_activate_merchant(
_admin_cap: &AdminCap,
merchant: &mut Merchant,
)
Parameters:
_admin_cap- Admin capabilitymerchant- Mutable reference to merchant
Effects:
- Sets merchant
is_activetotrue - Merchant can accept new payments
- Overrides merchant's self-deactivation
Use Cases:
- Reactivate after suspension
- Override merchant deactivation
- Emergency merchant restoration
Example:
const txb = client.admin.buildForceActivateMerchant({
adminCapId: '0xADMIN_CAP_ID',
merchantObjectId: '0xMERCHANT_ID',
});
await adminWallet.signAndExecuteTransactionBlock({ transactionBlock: txb });
update_platform_stats
Updates platform-wide statistics.
public entry fun update_platform_stats(
_admin_cap: &AdminCap,
config: &mut AdminConfig,
merchants_delta: u64,
payments_delta: u64,
volume_delta: u64,
)
Parameters:
_admin_cap- Admin capabilityconfig- Mutable reference to AdminConfigmerchants_delta- Change in total merchants (increment)payments_delta- Change in total payments (increment)volume_delta- Change in total volume (increment)
Effects:
- Increments
total_merchantsbymerchants_delta - Increments
total_paymentsbypayments_delta - Increments
total_volumebyvolume_delta
Example:
// Record 10 new merchants, 1000 new payments, 50000 SUI volume
const txb = client.admin.buildUpdatePlatformStats({
adminCapId: '0xADMIN_CAP_ID',
adminConfigId: '0xADMIN_CONFIG_ID',
merchantsDelta: 10,
paymentsDelta: 1000,
volumeDelta: 50000_000_000_000, // 50000 SUI in MIST
});
await adminWallet.signAndExecuteTransactionBlock({ transactionBlock: txb });
Note: This function is for manual stats tracking. Consider using event-based aggregation for automatic tracking.
Query Functions
These functions can be called by anyone (no AdminCap required).
get_default_platform_fee_bps
Returns the default platform fee for new merchants.
public fun get_default_platform_fee_bps(config: &AdminConfig): u64
Parameters:
config- Reference to AdminConfig
Returns:
u64- Default platform fee in basis points
Example:
const defaultFee = await client.admin.getDefaultPlatformFee(
'0xADMIN_CONFIG_ID'
);
console.log(`Default fee: ${defaultFee} bps (${defaultFee / 100}%)`);
get_total_merchants
Returns total number of registered merchants.
public fun get_total_merchants(config: &AdminConfig): u64
Parameters:
config- Reference to AdminConfig
Returns:
u64- Total merchants count
get_total_payments
Returns total number of payments processed.
public fun get_total_payments(config: &AdminConfig): u64
Parameters:
config- Reference to AdminConfig
Returns:
u64- Total payments count
get_total_volume
Returns total payment volume processed.
public fun get_total_volume(config: &AdminConfig): u64
Parameters:
config- Reference to AdminConfig
Returns:
u64- Total volume in smallest unit (e.g., MIST for SUI)
Example:
const stats = {
merchants: await client.admin.getTotalMerchants('0xADMIN_CONFIG_ID'),
payments: await client.admin.getTotalPayments('0xADMIN_CONFIG_ID'),
volume: await client.admin.getTotalVolume('0xADMIN_CONFIG_ID'),
};
console.log('Platform Statistics:');
console.log(` Merchants: ${stats.merchants}`);
console.log(` Payments: ${stats.payments}`);
console.log(` Volume: ${mistToSui(stats.volume)} SUI`);
Usage Examples
Platform Setup (Deployment)
// Module initialization (automatic on deployment)
module dolphinpay::admin {
fun init(ctx: &mut TxContext) {
// AdminCap created and transferred to deployer
// AdminConfig created and shared globally
}
}
After Deployment:
// Find AdminCap in deployer's owned objects
const adminCap = await findAdminCap(deployerAddress);
console.log('AdminCap ID:', adminCap.objectId);
// Find shared AdminConfig
const adminConfig = await findAdminConfig();
console.log('AdminConfig ID:', adminConfig.objectId);
// Store IDs securely for admin operations
process.env.ADMIN_CAP_ID = adminCap.objectId;
process.env.ADMIN_CONFIG_ID = adminConfig.objectId;
Merchant Fee Management
// Set custom fee for high-volume merchant
admin::set_merchant_platform_fee(
&admin_cap,
&mut merchant,
20, // 0.2% fee (lower than default 0.3%)
);
// Set custom fee for trial merchant
admin::set_merchant_platform_fee(
&admin_cap,
&mut new_merchant,
100, // 1% fee (higher for testing)
);
// Update global default fee
admin::set_default_platform_fee(
&admin_cap,
&mut config,
25, // New default: 0.25%
);
TypeScript Example:
// Premium merchant discount
async function applyPremiumFee(merchantId: string) {
const txb = client.admin.buildSetMerchantPlatformFee({
adminCapId: process.env.ADMIN_CAP_ID!,
merchantObjectId: merchantId,
feeBps: 15, // 0.15% premium rate
});
const result = await adminWallet.signAndExecuteTransactionBlock({
transactionBlock: txb,
});
console.log('Premium fee applied:', result.digest);
}
Merchant Status Control
// Suspend merchant for policy violation
admin::force_deactivate_merchant(&admin_cap, &mut merchant);
// Verify merchant is deactivated
assert!(!merchant::is_active(&merchant), 0);
// Later, reactivate after issue resolved
admin::force_activate_merchant(&admin_cap, &mut merchant);
// Verify merchant is active again
assert!(merchant::is_active(&merchant), 0);
TypeScript Example:
// Suspend merchant
async function suspendMerchant(merchantId: string, reason: string) {
console.log(`Suspending merchant ${merchantId}: ${reason}`);
const txb = client.admin.buildForceDeactivateMerchant({
adminCapId: process.env.ADMIN_CAP_ID!,
merchantObjectId: merchantId,
});
await adminWallet.signAndExecuteTransactionBlock({ transactionBlock: txb });
// Log suspension (off-chain)
await logMerchantAction(merchantId, 'suspended', reason);
}
// Reactivate merchant
async function reactivateMerchant(merchantId: string) {
const txb = client.admin.buildForceActivateMerchant({
adminCapId: process.env.ADMIN_CAP_ID!,
merchantObjectId: merchantId,
});
await adminWallet.signAndExecuteTransactionBlock({ transactionBlock: txb });
await logMerchantAction(merchantId, 'reactivated', 'Issue resolved');
}
Platform Statistics Tracking
// Get current platform stats
async function getPlatformDashboard() {
const configId = process.env.ADMIN_CONFIG_ID!;
const [merchants, payments, volume, defaultFee] = await Promise.all([
client.admin.getTotalMerchants(configId),
client.admin.getTotalPayments(configId),
client.admin.getTotalVolume(configId),
client.admin.getDefaultPlatformFee(configId),
]);
const volumeInSui = mistToSui(volume.toString());
const avgPaymentSize =
payments > 0 ? mistToSui((volume / payments).toString()) : '0';
return {
merchants,
payments,
volume: volumeInSui + ' SUI',
averagePaymentSize: avgPaymentSize + ' SUI',
defaultFee: `${defaultFee} bps (${defaultFee / 100}%)`,
};
}
// Usage
const dashboard = await getPlatformDashboard();
console.log('Platform Dashboard:', dashboard);
Fee Strategy Management
// Apply tiered fee structure based on merchant volume
async function applyTieredFees() {
const merchants = await getAllMerchants();
for (const merchant of merchants) {
const volume = await getMerchantVolume(merchant.id);
let feeBps: number;
// Determine fee tier
if (volume > 1_000_000_000_000_000) {
// > 1M SUI
feeBps = 10; // 0.1% for enterprise
} else if (volume > 100_000_000_000_000) {
// > 100K SUI
feeBps = 20; // 0.2% for high-volume
} else if (volume > 10_000_000_000_000) {
// > 10K SUI
feeBps = 25; // 0.25% for medium-volume
} else {
feeBps = 30; // 0.3% default
}
// Update merchant fee
const txb = client.admin.buildSetMerchantPlatformFee({
adminCapId: process.env.ADMIN_CAP_ID!,
merchantObjectId: merchant.id,
feeBps,
});
await adminWallet.signAndExecuteTransactionBlock({
transactionBlock: txb,
});
console.log(`Merchant ${merchant.id}: ${feeBps} bps`);
}
}
Security Considerations
AdminCap Protection
// ✅ GOOD: AdminCap stored securely
const ADMIN_CAP_ID = process.env.ADMIN_CAP_ID; // Environment variable
const adminWallet = loadSecureWallet(); // Hardware wallet or secure storage
// ❌ BAD: AdminCap exposed
const ADMIN_CAP_ID = '0x123...'; // Hardcoded in source code
Access Control
// All admin functions require AdminCap
public entry fun set_merchant_platform_fee(
_admin_cap: &AdminCap, // ← Must provide AdminCap
merchant: &mut Merchant,
fee_bps: u64,
)
Key Points:
- ✅ Only AdminCap holder can execute admin functions
- ✅ AdminCap cannot be cloned or duplicated
- ✅ AdminCap can be transferred if needed
- ⚠️ Loss of AdminCap = loss of admin control
Fee Validation
// Fee limits enforced on-chain
const MAX_PLATFORM_FEE_BPS: u64 = 1000; // 10% hard limit
assert!(fee_bps <= MAX_PLATFORM_FEE_BPS, E_FEE_TOO_HIGH);
Protection:
- ✅ Cannot set fees above 10%
- ✅ Prevents accidental excessive fees
- ✅ Protects merchant interests
Merchant Status Control
// Best practice: Log all status changes
async function suspendMerchantWithAudit(
merchantId: string,
reason: string,
adminAddress: string
) {
// Record action before execution
await auditLog.record({
action: 'merchant_suspension',
merchantId,
reason,
adminAddress,
timestamp: Date.now(),
});
// Execute suspension
const txb = client.admin.buildForceDeactivateMerchant({
adminCapId: process.env.ADMIN_CAP_ID!,
merchantObjectId: merchantId,
});
const result = await adminWallet.signAndExecuteTransactionBlock({
transactionBlock: txb,
});
// Record result
await auditLog.update({
transactionDigest: result.digest,
status: 'completed',
});
}
Best Practices
1. Secure AdminCap Storage
// Use hardware wallet or secure key management
import { Ed25519Keypair } from '@mysten/sui.js/keypairs/ed25519';
// Load from secure storage
const keypair = Ed25519Keypair.fromSecretKey(
Buffer.from(process.env.ADMIN_PRIVATE_KEY!, 'hex')
);
// Never commit private keys to version control
// Use environment variables or secret management systems
2. Audit All Admin Actions
interface AdminAction {
timestamp: number;
action: string;
targetId: string;
adminAddress: string;
transactionDigest: string;
parameters: Record<string, any>;
}
class AdminAuditLog {
async recordAction(action: AdminAction) {
// Store in database or blockchain
await database.adminActions.insert(action);
}
async getHistory(merchantId?: string) {
return database.adminActions.find(
merchantId ? { targetId: merchantId } : {}
);
}
}
3. Implement Role-Based Access
// Multi-signature for critical operations
enum AdminRole {
SUPER_ADMIN, // Can do everything
FEE_MANAGER, // Can only manage fees
SUPPORT, // Can only activate/deactivate
}
async function executeAdminAction(
action: () => Promise<void>,
requiredRole: AdminRole,
currentRole: AdminRole
) {
if (currentRole < requiredRole) {
throw new Error('Insufficient permissions');
}
await action();
}
4. Test Admin Operations
// Always test with dry run first
async function safeAdminOperation(txBuilder: () => Transaction) {
const dryRun = await client.dryRunTransaction(
txBuilder(),
adminWallet.address
);
if (!dryRun.success) {
throw new Error(`Dry run failed: ${dryRun.error}`);
}
// Execute if dry run succeeds
const txb = txBuilder();
return await adminWallet.signAndExecuteTransactionBlock({
transactionBlock: txb,
});
}
5. Monitor Platform Statistics
// Regular monitoring
async function monitorPlatformHealth() {
const stats = await getPlatformDashboard();
// Alert on anomalies
if (stats.payments > previousStats.payments * 1.5) {
await alert('Payment volume spike detected');
}
// Track growth
await metrics.record({
merchants: stats.merchants,
payments: stats.payments,
volume: stats.volume,
timestamp: Date.now(),
});
}
// Run every hour
setInterval(monitorPlatformHealth, 60 * 60 * 1000);
Testing
Test Helper Functions
The module provides test-only functions for unit testing:
#[test_only]
public fun create_admin_cap_for_testing(ctx: &mut TxContext): AdminCap
#[test_only]
public fun create_admin_config_for_testing(ctx: &mut TxContext): AdminConfig
Usage in tests:
#[test]
fun test_set_merchant_fee() {
let ctx = tx_context::dummy();
// Create test admin cap
let admin_cap = admin::create_admin_cap_for_testing(&mut ctx);
// Create test merchant
let merchant = merchant::create_merchant_for_testing(&mut ctx);
// Set fee
admin::set_merchant_platform_fee(&admin_cap, &mut merchant, 50);
// Verify
assert!(merchant::get_platform_fee_bps(&merchant) == 50, 0);
}
Next Steps
- Payment Module API - Payment operations
- Merchant Module API - Merchant management
- TypeScript SDK - SDK documentation
- Basic Payment Example - Complete integration example
Related Documentation
- Core Modules - Module architecture overview
- Environment Setup - Development environment
- Testnet Deployment - Deploy to testnet