Skip to main content

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 identifier
  • default_platform_fee_bps - Default fee for new merchants (basis points)
  • total_merchants - Total number of registered merchants
  • total_payments - Total number of payments processed
  • total_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:

  1. Creates AdminCap
  2. Creates AdminConfig with default values
  3. Transfers AdminCap to deployer
  4. Shares AdminConfig globally

Initial Config Values:

  • default_platform_fee_bps: 30 (0.3%)
  • total_merchants: 0
  • total_payments: 0
  • total_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 object
  • fee_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 capability
  • config - Mutable reference to AdminConfig
  • fee_bps - New default platform fee in basis points

Effects:

  • Updates default_platform_fee_bps in 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 capability
  • merchant - Mutable reference to merchant

Effects:

  • Sets merchant is_active to false
  • 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 capability
  • merchant - Mutable reference to merchant

Effects:

  • Sets merchant is_active to true
  • 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 capability
  • config - Mutable reference to AdminConfig
  • merchants_delta - Change in total merchants (increment)
  • payments_delta - Change in total payments (increment)
  • volume_delta - Change in total volume (increment)

Effects:

  • Increments total_merchants by merchants_delta
  • Increments total_payments by payments_delta
  • Increments total_volume by volume_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