Payment Module API Reference
Complete API documentation for the dolphinpay::payment module.
Overview
The Payment module (payment.move) handles the core payment lifecycle:
- Payment creation with customizable parameters
- Payment execution with automatic fee calculation
- Payment cancellation by merchants
- Status tracking and query operations
Package Location: dolphinpay::payment
Data Structures
Payment
The main payment object representing a payment transaction.
public struct Payment has key, store {
id: UID,
merchant: address,
payer: Option<address>,
amount: u64,
currency: TypeName,
created_at: u64,
completed_at: Option<u64>,
expires_at: u64,
status: u8,
metadata: VecMap<String, String>,
description: String,
refundable: bool,
refund_window: u64,
}
Fields:
id- Unique object identifiermerchant- Merchant's address to receive paymentpayer- Address of the payer (set after execution)amount- Payment amount in smallest unit (e.g., MIST for SUI)currency- Type of the currency (e.g.,0x2::sui::SUI)created_at- Timestamp when payment was created (milliseconds)completed_at- Timestamp when payment was completed (if applicable)expires_at- Timestamp when payment expiresstatus- Current payment status (see Status Codes)metadata- Custom key-value pairs for trackingdescription- Human-readable payment descriptionrefundable- Whether the payment can be refundedrefund_window- Time window for refunds (seconds)
PaymentConfig
Configuration for payment parameters.
public struct PaymentConfig has store {
default_expiry: u64,
min_amount: u64,
max_amount: u64,
enabled: bool,
}
Constants
Status Codes
const STATUS_PENDING: u8 = 0; // Payment created, awaiting execution
const STATUS_SUCCESS: u8 = 1; // Payment successfully completed
const STATUS_FAILED: u8 = 2; // Payment execution failed
const STATUS_EXPIRED: u8 = 3; // Payment expired without execution
const STATUS_CANCELLED: u8 = 4; // Payment cancelled by merchant
Fee Configuration
const PLATFORM_FEE_BPS: u64 = 30; // 0.3% platform fee (30 basis points)
Limits
const DEFAULT_EXPIRY_MS: u64 = 3600000; // 1 hour (default)
const MAX_EXPIRY_SECONDS: u64 = 31536000; // 1 year maximum
const MAX_PAYMENT_AMOUNT: u64 = 1_000_000_000_000; // 1000 SUI
const MAX_DESCRIPTION_LENGTH: u64 = 500; // Max description chars
const MAX_METADATA_ENTRIES: u64 = 10; // Max metadata pairs
Error Codes
const E_NOT_AUTHORIZED: u64 = 1;
const E_INVALID_AMOUNT: u64 = 100;
const E_PAYMENT_EXPIRED: u64 = 101;
const E_PAYMENT_ALREADY_COMPLETED: u64 = 102;
const E_INVALID_STATUS: u64 = 103;
const E_AMOUNT_MISMATCH: u64 = 104;
const E_CURRENCY_MISMATCH: u64 = 105;
const E_INVALID_MERCHANT: u64 = 106;
const E_INVALID_EXPIRY: u64 = 107;
const E_AMOUNT_TOO_LARGE: u64 = 108;
const E_DESCRIPTION_TOO_LONG: u64 = 109;
const E_METADATA_TOO_LARGE: u64 = 110;
const E_MERCHANT_INACTIVE: u64 = 111;
const E_MERCHANT_MISMATCH: u64 = 112;
Public Functions
create_payment
Creates a new payment order.
public fun create_payment(
merchant: address,
amount: u64,
currency: TypeName,
description: String,
metadata: VecMap<String, String>,
expiry_seconds: u64,
ctx: &mut TxContext
): Payment
Parameters:
merchant- Merchant's address to receive payment (must not be 0x0)amount- Payment amount in smallest unit (e.g., MIST for SUI)- Must be > 0
- Must be ≤ MAX_PAYMENT_AMOUNT
currency- Type of currency (e.g.,0x2::sui::SUI)description- Human-readable description (max 500 chars)metadata- Custom key-value pairs (max 10 entries)expiry_seconds- Expiry time in seconds (0 = use default 1 hour)- Must be ≤ MAX_EXPIRY_SECONDS (1 year)
ctx- Transaction context
Returns:
Payment- New payment object in PENDING status
Emits:
PaymentCreatedevent
Errors:
E_INVALID_MERCHANT- Merchant address is 0x0E_INVALID_AMOUNT- Amount is 0 or exceeds maxE_DESCRIPTION_TOO_LONG- Description exceeds 500 charsE_METADATA_TOO_LARGE- More than 10 metadata entriesE_INVALID_EXPIRY- Expiry exceeds maximum
Example Usage:
// Using SDK
const txb = client.payment.buildCreatePayment({
merchant: '0xMERCHANT_ADDRESS',
amount: suiToMist(10), // 10 SUI
currency: 'SUI',
description: 'Premium subscription',
metadata: { orderId: 'ORD-123' },
expirySeconds: 3600, // 1 hour
});
create_payment_with_merchant
Creates a payment with merchant validation.
public fun create_payment_with_merchant(
merchant_obj: &Merchant,
amount: u64,
currency: TypeName,
description: String,
metadata: VecMap<String, String>,
expiry_seconds: u64,
ctx: &mut TxContext
): Payment
Parameters:
merchant_obj- Reference to merchant object (for validation)- Other parameters same as
create_payment
Additional Validation:
- Verifies merchant is active
- Checks currency is supported by merchant
Returns:
Payment- New payment object
Emits:
PaymentCreatedevent
Errors:
- All errors from
create_paymentplus: E_MERCHANT_INACTIVE- Merchant is not activeE_CURRENCY_MISMATCH- Currency not supported by merchant
execute_payment
Executes a pending payment.
public fun execute_payment<T>(
payment: &mut Payment,
payment_coin: Coin<T>,
ctx: &mut TxContext
)
Type Parameters:
T- Type of the coin being paid (e.g.,SUI)
Parameters:
payment- Mutable reference to payment objectpayment_coin- Coin to pay with (must have sufficient balance)ctx- Transaction context
Effects:
- Transfers
payment_cointo merchant's address - Deducts platform fee and sends to platform
- Updates payment status to SUCCESS
- Records payer address and completion timestamp
Emits:
PaymentCompletedevent
Errors:
E_PAYMENT_EXPIRED- Payment has expiredE_PAYMENT_ALREADY_COMPLETED- Payment already executedE_AMOUNT_MISMATCH- Coin value doesn't match payment amountE_CURRENCY_MISMATCH- Coin type doesn't match payment currency
Fee Calculation:
Platform Fee = Amount × PLATFORM_FEE_BPS / 10000
= Amount × 30 / 10000
= Amount × 0.003 (0.3%)
Net Amount = Amount - Platform Fee
Example:
// Using SDK
const txb = client.payment.buildExecutePayment(
{
paymentId: '0xPAYMENT_ID',
coinObjectId: '0xCOIN_ID',
},
SUI_TYPES.SUI
);
execute_payment_with_merchant
Executes payment with merchant-specific fee handling.
public fun execute_payment_with_merchant<T>(
payment: &mut Payment,
merchant_obj: &Merchant,
payment_coin: Coin<T>,
ctx: &mut TxContext
)
Parameters:
payment- Mutable reference to paymentmerchant_obj- Reference to merchant objectpayment_coin- Coin to pay withctx- Transaction context
Additional Validation:
- Verifies payment belongs to this merchant
- Applies merchant-specific fee configuration
Returns:
- None (modifies payment in place)
Emits:
PaymentCompletedevent
Errors:
- All errors from
execute_paymentplus: E_MERCHANT_MISMATCH- Payment merchant doesn't match provided merchantE_MERCHANT_INACTIVE- Merchant is not active
cancel_payment
Cancels a pending payment (merchant only).
public fun cancel_payment(
payment: &mut Payment,
merchant_cap: &MerchantCap,
ctx: &mut TxContext
)
Parameters:
payment- Mutable reference to paymentmerchant_cap- Merchant capability (proves ownership)ctx- Transaction context
Effects:
- Changes payment status to CANCELLED
- Payment can no longer be executed
Emits:
PaymentCancelledevent
Errors:
E_NOT_AUTHORIZED- Caller is not the merchantE_INVALID_STATUS- Payment is not in PENDING status
Example:
// Using SDK
const txb = client.payment.buildCancelPayment({
paymentId: '0xPAYMENT_ID',
merchantCapId: '0xMERCHANT_CAP_ID',
});
Query Functions
get_status
Returns the current payment status.
public fun get_status(payment: &Payment): u8
Returns:
u8- Status code (0-4, see Status Codes)
get_amount
Returns the payment amount.
public fun get_amount(payment: &Payment): u64
Returns:
u64- Payment amount in smallest unit
get_merchant
Returns the merchant address.
public fun get_merchant(payment: &Payment): address
Returns:
address- Merchant's address
get_payer
Returns the payer address if payment is completed.
public fun get_payer(payment: &Payment): Option<address>
Returns:
Option<address>- Payer's address (Some if completed, None otherwise)
get_currency
Returns the payment currency type.
public fun get_currency(payment: &Payment): TypeName
Returns:
TypeName- Currency type name
is_expired
Checks if payment has expired.
public fun is_expired(payment: &Payment, current_time: u64): bool
Parameters:
payment- Reference to paymentcurrent_time- Current timestamp (milliseconds)
Returns:
bool- true if payment has expired
Example:
let current_time = tx_context::epoch_timestamp_ms(ctx);
if (is_expired(payment, current_time)) {
// Handle expired payment
}
get_description
Returns the payment description.
public fun get_description(payment: &Payment): String
Returns:
String- Payment description
get_metadata
Returns the payment metadata.
public fun get_metadata(payment: &Payment): &VecMap<String, String>
Returns:
&VecMap<String, String>- Reference to metadata map
Helper Functions
calculate_fee_with_bps
Calculates fee using basis points.
public fun calculate_fee_with_bps(amount: u64, fee_bps: u64): u64
Parameters:
amount- Base amountfee_bps- Fee in basis points (1 bps = 0.01%)
Returns:
u64- Calculated fee
Formula:
fee = (amount × fee_bps) / 10000
Example:
// Calculate 0.3% fee (30 bps)
let fee = calculate_fee_with_bps(1_000_000_000, 30);
// fee = 3_000_000 (0.003 SUI)
Events
PaymentCreated
Emitted when a payment is created.
public struct PaymentCreated has copy, drop {
payment_id: ID,
merchant: address,
amount: u64,
currency: TypeName,
description: String,
timestamp: u64,
}
PaymentCompleted
Emitted when a payment is successfully executed.
public struct PaymentCompleted has copy, drop {
payment_id: ID,
merchant: address,
payer: address,
amount: u64,
currency: TypeName,
fee_amount: u64,
net_amount: u64,
tx_hash: vector<u8>,
timestamp: u64,
}
PaymentCancelled
Emitted when a payment is cancelled.
public struct PaymentCancelled has copy, drop {
payment_id: ID,
reason: String,
timestamp: u64,
}
PaymentExpired
Emitted when a payment expires.
public struct PaymentExpired has copy, drop {
payment_id: ID,
timestamp: u64,
}
PaymentFailed
Emitted when a payment execution fails.
public struct PaymentFailed has copy, drop {
payment_id: ID,
merchant: address,
payer: address,
reason: String,
timestamp: u64,
}
Usage Examples
Complete Payment Flow
// 1. Create payment
let payment = payment::create_payment(
merchant_address,
1_000_000_000, // 1 SUI
type_name::get<SUI>(),
string::utf8(b"Premium subscription"),
vec_map::empty(),
3600, // 1 hour
ctx
);
// 2. Transfer payment object to shared object or merchant
transfer::public_share_object(payment);
// 3. Later, execute payment
let payment_coin = coin::take(&mut coins, 1_000_000_000, ctx);
payment::execute_payment(&mut payment, payment_coin, ctx);
// 4. Check status
let status = payment::get_status(&payment);
assert!(status == STATUS_SUCCESS, 0);
With Merchant Validation
// Create payment with merchant validation
let payment = payment::create_payment_with_merchant(
&merchant_obj,
5_000_000_000, // 5 SUI
type_name::get<SUI>(),
string::utf8(b"Service payment"),
metadata,
7200, // 2 hours
ctx
);
// Execute with merchant object
payment::execute_payment_with_merchant(
&mut payment,
&merchant_obj,
payment_coin,
ctx
);
Security Considerations
Reentrancy Protection
The module updates payment state before transferring funds:
// Safe pattern used in execute_payment:
payment.status = STATUS_SUCCESS; // Update state first
payment.payer = some(sender);
payment.completed_at = some(timestamp);
transfer::public_transfer(coin, merchant); // Then transfer
Integer Overflow Protection
Fee calculations use u128 for intermediate values:
let amount_u128 = (amount as u128);
let fee_u128 = (amount_u128 * (fee_bps as u128)) / 10000;
let fee = (fee_u128 as u64);
Input Validation
All inputs are validated:
- ✅ Merchant address not zero
- ✅ Amount within limits
- ✅ Description length checked
- ✅ Metadata size limited
- ✅ Expiry within bounds
Best Practices
- Always check expiry before executing payments
- Use metadata for tracking (order IDs, customer IDs)
- Set appropriate expiry based on use case
- Validate merchant when creating payments
- Handle events for off-chain tracking
- Test with dry run before actual execution
Next Steps
- Merchant Module API - Merchant management functions
- Admin Module API - Admin operations
- SDK Guide - Using the SDK
- Examples - Code examples