Merchant Operations Guide
Learn how to register merchants, manage settings, configure currencies, and query merchant data using the DolphinPay TypeScript SDK.
Overview
The Merchant Module provides methods for:
- Merchant registration and onboarding
- Currency management (add/remove supported currencies)
- Receiving address configuration per currency
- Status management (activate/deactivate)
- Query operations for merchant data
- Dry run testing for all operations
Merchant Registration
Register a New Merchant
import { createClient } from '@dolphinpay/sdk';
const client = createClient({
packageId: '0x9c7ca262d020b005e0e6b6a5d083b329d58716e0d80c07b46804324074468f9c',
network: 'testnet',
});
// Build merchant registration transaction
const txb = client.merchant.buildRegisterMerchant({
name: 'My Online Store',
description: 'E-commerce platform for digital goods',
});
// Execute transaction
const result = await wallet.signAndExecuteTransactionBlock({
transactionBlock: txb,
});
console.log('Merchant registered:', result.digest);
After registration, you'll receive:
- Merchant Object: The merchant account on-chain
- MerchantCap: Capability object for managing the merchant
Extract Merchant ID
// Get transaction details
const tx = await suiClient.getTransactionBlock({
digest: result.digest,
options: { showObjectChanges: true },
});
// Find created objects
const createdObjects = tx.objectChanges?.filter(
(change) => change.type === 'created'
);
// Merchant object
const merchantObject = createdObjects?.find((obj) =>
obj.objectType.includes('::merchant::Merchant')
);
// MerchantCap object
const merchantCap = createdObjects?.find((obj) =>
obj.objectType.includes('::merchant::MerchantCap')
);
console.log('Merchant ID:', merchantObject?.objectId);
console.log('MerchantCap ID:', merchantCap?.objectId);
Currency Management
Add Supported Currency
Add a currency that your merchant accepts:
const txb = client.merchant.buildAddSupportedCurrency({
merchantObjectId: '0xMERCHANT_OBJECT_ID',
merchantCapId: '0xMERCHANT_CAP_ID',
currencyType: '0x2::sui::SUI', // SUI token
receivingAddress: '0xYOUR_WALLET_ADDRESS',
});
const result = await wallet.signAndExecuteTransactionBlock({
transactionBlock: txb,
});
Add Multiple Currencies
// Add USDC
const usdcTxb = client.merchant.buildAddSupportedCurrency({
merchantObjectId: '0xMERCHANT_OBJECT_ID',
merchantCapId: '0xMERCHANT_CAP_ID',
currencyType: '0xUSDC_TOKEN_TYPE',
receivingAddress: '0xYOUR_USDC_ADDRESS',
});
await wallet.signAndExecuteTransactionBlock({ transactionBlock: usdcTxb });
// Add USDT
const usdtTxb = client.merchant.buildAddSupportedCurrency({
merchantObjectId: '0xMERCHANT_OBJECT_ID',
merchantCapId: '0xMERCHANT_CAP_ID',
currencyType: '0xUSDT_TOKEN_TYPE',
receivingAddress: '0xYOUR_USDT_ADDRESS',
});
await wallet.signAndExecuteTransactionBlock({ transactionBlock: usdtTxb });
Remove Supported Currency
const txb = client.merchant.buildRemoveSupportedCurrency({
merchantObjectId: '0xMERCHANT_OBJECT_ID',
merchantCapId: '0xMERCHANT_CAP_ID',
currencyType: '0xUSDC_TOKEN_TYPE',
});
const result = await wallet.signAndExecuteTransactionBlock({
transactionBlock: txb,
});
Update Receiving Address
Change the receiving address for a specific currency:
const txb = client.merchant.buildSetReceivingAddress({
merchantObjectId: '0xMERCHANT_OBJECT_ID',
merchantCapId: '0xMERCHANT_CAP_ID',
currencyType: '0x2::sui::SUI',
newAddress: '0xNEW_WALLET_ADDRESS',
});
const result = await wallet.signAndExecuteTransactionBlock({
transactionBlock: txb,
});
Merchant Information Management
Update Merchant Info
Update merchant name and description:
const txb = client.merchant.buildUpdateMerchantInfo({
merchantObjectId: '0xMERCHANT_OBJECT_ID',
merchantCapId: '0xMERCHANT_CAP_ID',
name: 'My Updated Store Name',
description: 'Updated description with new services',
});
const result = await wallet.signAndExecuteTransactionBlock({
transactionBlock: txb,
});
Toggle Merchant Status
Activate or deactivate your merchant account:
// Deactivate merchant (e.g., for maintenance)
const txb = client.merchant.buildToggleMerchantStatus({
merchantObjectId: '0xMERCHANT_OBJECT_ID',
merchantCapId: '0xMERCHANT_CAP_ID',
});
const result = await wallet.signAndExecuteTransactionBlock({
transactionBlock: txb,
});
// Status is toggled (active -> inactive, or inactive -> active)
Querying Merchant Data
Get Merchant Details
const merchant = await client.merchant.getMerchant('0xMERCHANT_OBJECT_ID');
console.log('Merchant Details:');
console.log(' Name:', merchant.name);
console.log(' Description:', merchant.description);
console.log(' Owner:', merchant.owner);
console.log(' Active:', merchant.is_active);
console.log(' Created:', new Date(Number(merchant.created_at)));
Check Merchant Status
const isActive = await client.merchant.isMerchantActive('0xMERCHANT_OBJECT_ID');
if (isActive) {
console.log('Merchant is active and can accept payments');
} else {
console.log('Merchant is inactive');
}
Get Merchant Fee Configuration
const feeConfig = await client.merchant.getMerchantFeeConfig(
'0xMERCHANT_OBJECT_ID'
);
console.log('Fee Configuration:');
console.log(' Platform Fee (BPS):', feeConfig.platform_fee_bps); // Default: 30 (0.3%)
console.log(' Custom Fee Enabled:', feeConfig.custom_fee_enabled);
if (feeConfig.custom_fee_enabled) {
console.log(' Custom Fee (BPS):', feeConfig.custom_fee_bps);
console.log(' Min Fee:', feeConfig.min_fee);
console.log(' Max Fee:', feeConfig.max_fee);
}
Dry Run Testing
Test Merchant Registration
const result = await client.merchant.dryRunRegisterMerchant(
{
name: 'Test Store',
description: 'Testing registration',
},
'0xYOUR_ADDRESS'
);
if (result.success) {
console.log('✅ Registration will succeed');
console.log('Gas estimate:', result.effects.gasUsed);
console.log('Objects to be created:', result.objectChanges?.length);
// Proceed with actual registration
const txb = client.merchant.buildRegisterMerchant({
name: 'Test Store',
description: 'Testing registration',
});
} else {
console.error('❌ Registration would fail:', result.error);
}
Test Currency Operations
// Test adding currency
const addResult = await client.merchant.dryRunAddSupportedCurrency(
{
merchantObjectId: '0xMERCHANT_OBJECT_ID',
merchantCapId: '0xMERCHANT_CAP_ID',
currencyType: '0x2::sui::SUI',
receivingAddress: '0xWALLET_ADDRESS',
},
'0xYOUR_ADDRESS'
);
if (addResult.success) {
console.log('Currency addition will succeed');
}
// Test removing currency
const removeResult = await client.merchant.dryRunRemoveSupportedCurrency(
{
merchantObjectId: '0xMERCHANT_OBJECT_ID',
merchantCapId: '0xMERCHANT_CAP_ID',
currencyType: '0xUSDC_TYPE',
},
'0xYOUR_ADDRESS'
);
Complete Merchant Setup Example
Here's a complete example of setting up a new merchant:
import { createClient } from '@dolphinpay/sdk';
async function setupMerchant(wallet: any) {
const client = createClient({
packageId: '0x9c7ca262d020b005e0e6b6a5d083b329d58716e0d80c07b46804324074468f9c',
network: 'testnet',
});
// Step 1: Register merchant
console.log('Step 1: Registering merchant...');
const registerTxb = client.merchant.buildRegisterMerchant({
name: 'Acme Online Store',
description: 'Premium digital goods marketplace',
});
const registerResult = await wallet.signAndExecuteTransactionBlock({
transactionBlock: registerTxb,
});
// Step 2: Extract merchant IDs
console.log('Step 2: Extracting merchant IDs...');
const tx = await suiClient.getTransactionBlock({
digest: registerResult.digest,
options: { showObjectChanges: true },
});
const createdObjects = tx.objectChanges?.filter(
(change) => change.type === 'created'
);
const merchantObject = createdObjects?.find((obj) =>
obj.objectType.includes('::merchant::Merchant')
);
const merchantCap = createdObjects?.find((obj) =>
obj.objectType.includes('::merchant::MerchantCap')
);
const merchantId = merchantObject?.objectId;
const merchantCapId = merchantCap?.objectId;
console.log('Merchant ID:', merchantId);
console.log('MerchantCap ID:', merchantCapId);
// Step 3: Add supported currencies
console.log('Step 3: Adding supported currencies...');
// Add SUI
const suiTxb = client.merchant.buildAddSupportedCurrency({
merchantObjectId: merchantId!,
merchantCapId: merchantCapId!,
currencyType: '0x2::sui::SUI',
receivingAddress: wallet.address,
});
await wallet.signAndExecuteTransactionBlock({ transactionBlock: suiTxb });
console.log(' ✓ SUI added');
// Add USDC (example)
const usdcTxb = client.merchant.buildAddSupportedCurrency({
merchantObjectId: merchantId!,
merchantCapId: merchantCapId!,
currencyType: '0xUSDC_TYPE',
receivingAddress: wallet.address,
});
await wallet.signAndExecuteTransactionBlock({ transactionBlock: usdcTxb });
console.log(' ✓ USDC added');
// Step 4: Verify setup
console.log('Step 4: Verifying merchant setup...');
const merchant = await client.merchant.getMerchant(merchantId!);
const isActive = await client.merchant.isMerchantActive(merchantId!);
console.log('Merchant setup complete!');
console.log(' Name:', merchant.name);
console.log(' Active:', isActive);
return {
merchantId,
merchantCapId,
merchant,
};
}
Validation and Error Handling
Input Validation
import { validateMerchantName, validateDescription } from '@dolphinpay/sdk';
try {
// Validate merchant name (1-100 chars)
validateMerchantName('My Store');
// Validate description (max 500 chars)
validateDescription('A description of my store');
// Proceed with registration
const txb = client.merchant.buildRegisterMerchant({
name: 'My Store',
description: 'A description of my store',
});
} catch (error) {
console.error('Validation error:', error.message);
}
Common Errors
try {
const txb = client.merchant.buildAddSupportedCurrency({
merchantObjectId: '0xMERCHANT_ID',
merchantCapId: '0xMERCHANT_CAP_ID',
currencyType: '0x2::sui::SUI',
receivingAddress: '0xWALLET',
});
await wallet.signAndExecuteTransactionBlock({ transactionBlock: txb });
} catch (error) {
if (error.message.includes('E_CURRENCY_ALREADY_SUPPORTED')) {
console.error('Currency is already supported');
} else if (error.message.includes('E_INVALID_ADDRESS')) {
console.error('Invalid receiving address');
} else if (error.message.includes('E_NOT_MERCHANT_OWNER')) {
console.error('Not authorized to modify this merchant');
} else {
console.error('Transaction failed:', error.message);
}
}
Best Practices
1. Store Merchant IDs Securely
// After registration, save merchant IDs for future use
const merchantConfig = {
merchantId: '0xMERCHANT_OBJECT_ID',
merchantCapId: '0xMERCHANT_CAP_ID',
createdAt: Date.now(),
};
// Save to database or local storage
localStorage.setItem('merchantConfig', JSON.stringify(merchantConfig));
2. Verify Before Currency Operations
async function addCurrencySafely(
merchantId: string,
merchantCapId: string,
currencyType: string,
receivingAddress: string
) {
// Check if currency is already supported
const merchant = await client.merchant.getMerchant(merchantId);
if (merchant.supported_currencies?.includes(currencyType)) {
console.log('Currency already supported, updating address instead');
const txb = client.merchant.buildSetReceivingAddress({
merchantObjectId: merchantId,
merchantCapId,
currencyType,
newAddress: receivingAddress,
});
return await wallet.signAndExecuteTransactionBlock({
transactionBlock: txb,
});
}
// Add new currency
const txb = client.merchant.buildAddSupportedCurrency({
merchantObjectId: merchantId,
merchantCapId,
currencyType,
receivingAddress,
});
return await wallet.signAndExecuteTransactionBlock({ transactionBlock: txb });
}
3. Test with Dry Run
// Always test before executing
async function safeExecute(txBuilder: () => Transaction, sender: string) {
const dryRun = await client.dryRunTransaction(txBuilder(), sender);
if (dryRun.success) {
const txb = txBuilder();
return await wallet.signAndExecuteTransactionBlock({
transactionBlock: txb,
});
} else {
throw new Error(`Dry run failed: ${dryRun.error}`);
}
}
4. Handle MerchantCap Carefully
// MerchantCap is required for all merchant operations
// Never share or lose this object ID
// Store securely
const MERCHANT_CAP_ID = process.env.MERCHANT_CAP_ID;
// Verify ownership before operations
async function verifyMerchantOwnership(
merchantCapId: string,
expectedOwner: string
) {
const obj = await suiClient.getObject({
id: merchantCapId,
options: { showOwner: true },
});
const owner = (obj.data?.owner as any)?.AddressOwner;
if (owner !== expectedOwner) {
throw new Error('Not the merchant owner');
}
}
Next Steps
- Event Querying - Track merchant activity and payments
- Payment Operations - Learn payment management
- Merchant Getting Started - Complete merchant setup guide
API Reference
For complete API documentation, see: