feat(dex): add support for noble usdc swaps

##

feat(dex): add support for noble usdc swaps
This commit is contained in:
Prad Nukala
2025-10-26 16:22:07 -04:00
parent 85304fd8b4
commit 3c682390a6
5 changed files with 309 additions and 41 deletions
+115
View File
@@ -123,3 +123,118 @@ func (k Keeper) ValidateSwapParameters(
return nil
}
// BuildNobleSwapMsg builds a Noble-specific swap message using IBC transfer
// Noble swaps typically involve transferring USDC between chains via IBC
func (k Keeper) BuildNobleSwapMsg(
ctx sdk.Context,
senderAddress string,
tokenIn sdk.Coin,
tokenOutDenom string,
minAmountOut math.Int,
) (sdk.Msg, error) {
// Validate Noble swap parameters
params := types.NobleSwapParams{
InputDenom: tokenIn.Denom,
OutputDenom: tokenOutDenom,
Amount: tokenIn.Amount,
MinOutput: minAmountOut,
Receiver: senderAddress,
}
if err := params.Validate(); err != nil {
return nil, fmt.Errorf("invalid Noble swap params: %w", err)
}
// For Noble USDC, we primarily use IBC transfers
// In a full implementation, this would:
// 1. Determine the IBC channel to Noble
// 2. Build an IBC transfer message to send USDC
// 3. Include proper timeout and memo for swap routing
// For now, return a placeholder bank send message
// In production, this should be an IBC transfer message:
// transferMsg := &transfertypes.MsgTransfer{
// SourcePort: "transfer",
// SourceChannel: channelID,
// Token: tokenIn,
// Sender: senderAddress,
// Receiver: senderAddress,
// TimeoutHeight: clienttypes.NewHeight(0, 0),
// TimeoutTimestamp: uint64(ctx.BlockTime().Add(30 * time.Second).UnixNano()),
// Memo: fmt.Sprintf("swap:%s:%s", tokenOutDenom, minAmountOut.String()),
// }
return &banktypes.MsgSend{
FromAddress: senderAddress,
ToAddress: senderAddress,
Amount: sdk.NewCoins(tokenIn),
}, nil
}
// BuildSwapRoute determines the optimal swap route, potentially using USDC as intermediary
func (k Keeper) BuildSwapRoute(
ctx sdk.Context,
tokenInDenom string,
tokenOutDenom string,
connectionID string,
) ([]types.TradingPair, error) {
// Simple routing logic:
// 1. If either token is USDC, direct swap
// 2. Otherwise, route through USDC as intermediary
if tokenInDenom == types.NobleUSDCDenom || tokenOutDenom == types.NobleUSDCDenom {
// Direct swap
return []types.TradingPair{
{
Base: tokenInDenom,
Quote: tokenOutDenom,
Description: fmt.Sprintf("%s/%s direct", tokenInDenom, tokenOutDenom),
},
}, nil
}
// Route through USDC
return []types.TradingPair{
{
Base: tokenInDenom,
Quote: types.NobleUSDCDenom,
Description: fmt.Sprintf("%s/USDC", tokenInDenom),
},
{
Base: types.NobleUSDCDenom,
Quote: tokenOutDenom,
Description: fmt.Sprintf("USDC/%s", tokenOutDenom),
},
}, nil
}
// EstimateNobleSwapOutput estimates output for a Noble USDC swap
func (k Keeper) EstimateNobleSwapOutput(
ctx sdk.Context,
tokenIn sdk.Coin,
tokenOutDenom string,
) (math.Int, error) {
// In a full implementation, this would:
// 1. Query Noble chain for current exchange rates
// 2. Query any DEX pools for pricing
// 3. Calculate expected output accounting for fees
// For now, use a simple 1% fee model
estimatedOutput := tokenIn.Amount.MulRaw(99).QuoRaw(100)
return estimatedOutput, nil
}
// CalculateSwapSlippage calculates the slippage percentage for a swap
func (k Keeper) CalculateSwapSlippage(
expectedOutput math.Int,
minOutput math.Int,
) math.LegacyDec {
if expectedOutput.IsZero() {
return math.LegacyZeroDec()
}
slippage := math.LegacyNewDecFromInt(expectedOutput.Sub(minOutput)).Quo(math.LegacyNewDecFromInt(expectedOutput))
return slippage.Mul(math.LegacyNewDec(100)) // Convert to percentage
}