Reference
The Neutron Transfer module is a wrapper over the standard IBC Transfer module with additional features for smart contract integration.
Key Differences from Standard IBC Transfer
1. Enhanced Transfer Response
Instead of an empty response, Neutron provides tracking information:
message MsgTransferResponse {
// channel's sequence_id for outgoing ibc packet. Unique per a channel.
uint64 sequence_id = 1;
// channel src channel on neutron side transaction was submitted from
string channel = 2;
}
This allows contracts to correlate transfers with their acknowledgements.
2. Contract Detection and Callbacks
The Transfer module automatically detects smart contract senders using HasContractInfo() and provides Sudo callbacks for transfer results.
Callback messages are prepared using the Contract Manager module's PrepareSudoCallbackMessage() function.
3. Fee Integration
message MsgTransfer {
// Standard IBC Transfer fields...
string source_port = 1;
string source_channel = 2;
cosmos.base.v1beta1.Coin token = 3;
string sender = 4;
string receiver = 5;
ibc.core.client.v1.Height timeout_height = 6;
uint64 timeout_timestamp = 7;
string memo = 8;
// Neutron addition: fees for IBC packet processing
neutron.feerefunder.Fee fee = 9;
}
4. Contract-Specific Validation
The Transfer module includes conditional validation:
func (msg *MsgTransfer) Validate(isContract bool) error {
if isContract {
if err := msg.Fee.Validate(); err != nil {
return err
}
}
// ... standard IBC validation
}
- For contracts: Fee validation is required
- For non-contracts: Fee validation is bypassed
5. Automatic Fee Operations
For contract senders, the module automatically:
// Fee locking before packet transmission
if err := k.FeeKeeper.LockFees(ctx, senderAddr, packetID, msg.Fee); err != nil {
return nil, errors.Wrapf(err, "failed to lock fees")
}
// Fee distribution on acknowledgement
im.wrappedKeeper.FeeKeeper.DistributeAcknowledgementFee(ctx, relayer, packetID)
// Fee distribution on timeout
im.wrappedKeeper.FeeKeeper.DistributeTimeoutFee(ctx, relayer, packetID)
Module Implementation
Wrapper Architecture
The module implements a wrapper pattern around the standard IBC Transfer module:
type IBCModule struct {
wrappedKeeper wrapkeeper.KeeperTransferWrapper
keeper keeper.Keeper
sudoKeeper neutrontypes.WasmKeeper
tokenfactoryKeeper neutrontypes.TokenfactoryKeeper
transfer.IBCModule
}
Method Overrides
Key methods are overridden to add contract functionality:
- OnAcknowledgementPacket(): Adds callback processing after standard IBC handling
- OnTimeoutPacket(): Adds callback processing after standard IBC handling
- Transfer(): Adds contract detection, fee validation/locking, and enhanced response
Standard IBC Delegation
All standard IBC Transfer functionality is delegated to the underlying implementation:
service Query {
// Delegated to ibc.applications.transfer.v1
rpc DenomTrace(ibc.applications.transfer.v1.QueryDenomTraceRequest) returns (ibc.applications.transfer.v1.QueryDenomTraceResponse);
rpc DenomTraces(ibc.applications.transfer.v1.QueryDenomTracesRequest) returns (ibc.applications.transfer.v1.QueryDenomTracesResponse);
rpc Params(ibc.applications.transfer.v1.QueryParamsRequest) returns (ibc.applications.transfer.v1.QueryParamsResponse);
rpc DenomHash(ibc.applications.transfer.v1.QueryDenomHashRequest) returns (ibc.applications.transfer.v1.QueryDenomHashResponse);
}
Error Handling
Sudo Call Error Handling
The Transfer module's callback error handling:
_, err = im.sudoKeeper.Sudo(ctx, senderAddress, msg)
if err != nil {
im.keeper.Logger(ctx).Debug("HandleAcknowledgement: failed to Sudo contract on packet acknowledgement", "error", err)
}
// Processing continues regardless of callback success/failure
Failed Sudo calls are logged but do not block IBC packet processing.
Fee Processing Independence
Fee operations occur independently of callback success:
- Fee locking happens before packet transmission
- Fee distribution occurs regardless of callback outcomes
- IBC processing continues even if contracts fail to handle callbacks
Integration Dependencies
The Transfer module relies on external modules for specific functionality:
Contract Manager Module
- PrepareSudoCallbackMessage(): Determines callback message format and structure
- Request ID handling: Manages correlation between transfers and callbacks
- Sudo message specifications: Defines contract interface requirements
Fee Refunder Module
- Fee structure: Defines
neutron.feerefunder.Feetype and validation - Fee operations: Implements
LockFees(),DistributeAcknowledgementFee(),DistributeTimeoutFee() - Balance requirements: Manages fee payment and distribution logic
Key Concepts
Transfer Flow for Contracts
- Contract Detection: Module checks
HasContractInfo(ctx, senderAddress) - Fee Validation: Calls
msg.Fee.Validate()for contracts only - Fee Locking: Uses
FeeKeeper.LockFees()before packet transmission - Standard IBC Processing: Delegates to underlying IBC Transfer module
- Enhanced Response: Returns
sequence_idandchannelinformation - Callback Preparation: Uses Contract Manager's
PrepareSudoCallbackMessage() - Sudo Callback: Calls
sudoKeeper.Sudo()with prepared message - Fee Distribution: Distributes fees to relayers regardless of callback success
Non-Contract Processing
For non-contract senders:
- Fee validation is skipped
- Fee locking is bypassed
- No callbacks are sent
- Standard IBC processing applies
- Standard (empty) response is returned