mirror of
https://github.com/sonr-io/sonr.git
synced 2026-08-02 17:31:39 +00:00
192 lines
4.9 KiB
Go
192 lines
4.9 KiB
Go
package keeper
|
|
|
|
import (
|
|
"fmt"
|
|
"time"
|
|
|
|
"cosmossdk.io/math"
|
|
sdk "github.com/cosmos/cosmos-sdk/types"
|
|
banktypes "github.com/cosmos/cosmos-sdk/x/bank/types"
|
|
|
|
"github.com/sonr-io/sonr/x/dex/types"
|
|
)
|
|
|
|
// ProvideLiquidity handles liquidity provision through ICA
|
|
func (k Keeper) ProvideLiquidity(
|
|
ctx sdk.Context,
|
|
did string,
|
|
connectionID string,
|
|
poolID uint64,
|
|
tokenA sdk.Coin,
|
|
tokenB sdk.Coin,
|
|
minShares math.Int,
|
|
) (uint64, error) {
|
|
// Get the DEX account
|
|
account, err := k.GetDEXAccount(ctx, did, connectionID)
|
|
if err != nil {
|
|
return 0, fmt.Errorf("DEX account not found: %w", err)
|
|
}
|
|
|
|
// Verify account is active
|
|
if account.Status != types.ACCOUNT_STATUS_ACTIVE {
|
|
return 0, fmt.Errorf("DEX account is not active")
|
|
}
|
|
|
|
// Create liquidity provision message for remote chain
|
|
// This is a placeholder - actual implementation would use chain-specific messages
|
|
lpMsg := &banktypes.MsgSend{
|
|
FromAddress: account.AccountAddress,
|
|
ToAddress: account.AccountAddress, // Placeholder
|
|
Amount: sdk.NewCoins(tokenA, tokenB),
|
|
}
|
|
|
|
// Send the liquidity transaction via ICA
|
|
sequence, err := k.SendDEXTransaction(
|
|
ctx,
|
|
did,
|
|
connectionID,
|
|
[]sdk.Msg{lpMsg},
|
|
fmt.Sprintf("provide_liquidity_pool_%d", poolID),
|
|
30*time.Second,
|
|
)
|
|
if err != nil {
|
|
return 0, fmt.Errorf("failed to send liquidity transaction: %w", err)
|
|
}
|
|
|
|
// Emit liquidity event
|
|
ctx.EventManager().EmitEvent(
|
|
sdk.NewEvent(
|
|
types.EventTypeLiquidityProvided,
|
|
sdk.NewAttribute("did", did),
|
|
sdk.NewAttribute("connection", connectionID),
|
|
sdk.NewAttribute("pool_id", fmt.Sprintf("%d", poolID)),
|
|
sdk.NewAttribute("token_a", tokenA.String()),
|
|
sdk.NewAttribute("token_b", tokenB.String()),
|
|
sdk.NewAttribute("sequence", fmt.Sprintf("%d", sequence)),
|
|
),
|
|
)
|
|
|
|
return sequence, nil
|
|
}
|
|
|
|
// RemoveLiquidity handles liquidity removal through ICA
|
|
func (k Keeper) RemoveLiquidity(
|
|
ctx sdk.Context,
|
|
did string,
|
|
connectionID string,
|
|
poolID uint64,
|
|
shares math.Int,
|
|
minAmountA math.Int,
|
|
minAmountB math.Int,
|
|
) (uint64, error) {
|
|
// Get the DEX account
|
|
account, err := k.GetDEXAccount(ctx, did, connectionID)
|
|
if err != nil {
|
|
return 0, fmt.Errorf("DEX account not found: %w", err)
|
|
}
|
|
|
|
// Verify account is active
|
|
if account.Status != types.ACCOUNT_STATUS_ACTIVE {
|
|
return 0, fmt.Errorf("DEX account is not active")
|
|
}
|
|
|
|
// Create liquidity removal message for remote chain
|
|
// This is a placeholder - actual implementation would use chain-specific messages
|
|
removeMsg := &banktypes.MsgSend{
|
|
FromAddress: account.AccountAddress,
|
|
ToAddress: account.AccountAddress, // Placeholder
|
|
Amount: sdk.NewCoins(sdk.NewCoin("shares", shares)),
|
|
}
|
|
|
|
// Send the removal transaction via ICA
|
|
sequence, err := k.SendDEXTransaction(
|
|
ctx,
|
|
did,
|
|
connectionID,
|
|
[]sdk.Msg{removeMsg},
|
|
fmt.Sprintf("remove_liquidity_pool_%d", poolID),
|
|
30*time.Second,
|
|
)
|
|
if err != nil {
|
|
return 0, fmt.Errorf("failed to send liquidity removal transaction: %w", err)
|
|
}
|
|
|
|
// Emit removal event
|
|
ctx.EventManager().EmitEvent(
|
|
sdk.NewEvent(
|
|
types.EventTypeLiquidityRemoved,
|
|
sdk.NewAttribute("did", did),
|
|
sdk.NewAttribute("connection", connectionID),
|
|
sdk.NewAttribute("pool_id", fmt.Sprintf("%d", poolID)),
|
|
sdk.NewAttribute("shares", shares.String()),
|
|
sdk.NewAttribute("sequence", fmt.Sprintf("%d", sequence)),
|
|
),
|
|
)
|
|
|
|
return sequence, nil
|
|
}
|
|
|
|
// EstimateLPShares estimates the LP shares for given liquidity
|
|
func (k Keeper) EstimateLPShares(
|
|
ctx sdk.Context,
|
|
connectionID string,
|
|
poolID uint64,
|
|
tokenA sdk.Coin,
|
|
tokenB sdk.Coin,
|
|
) (math.Int, error) {
|
|
// This would query the remote chain for LP share estimation
|
|
// For now, return a placeholder value
|
|
totalValue := tokenA.Amount.Add(tokenB.Amount)
|
|
return totalValue.QuoRaw(2), nil // Simple average as placeholder
|
|
}
|
|
|
|
// GetPoolInfo retrieves pool information from remote chain
|
|
func (k Keeper) GetPoolInfo(
|
|
ctx sdk.Context,
|
|
connectionID string,
|
|
poolID uint64,
|
|
) (*PoolInfo, error) {
|
|
// This would query the remote chain for pool info
|
|
// For now, return placeholder data
|
|
return &PoolInfo{
|
|
PoolID: poolID,
|
|
TokenA: "uatom",
|
|
TokenB: "uosmo",
|
|
TotalShares: math.NewInt(1000000),
|
|
TotalLiquidity: sdk.NewCoins(
|
|
sdk.NewCoin("uatom", math.NewInt(500000)),
|
|
sdk.NewCoin("uosmo", math.NewInt(500000)),
|
|
),
|
|
}, nil
|
|
}
|
|
|
|
// PoolInfo represents pool information
|
|
type PoolInfo struct {
|
|
PoolID uint64
|
|
TokenA string
|
|
TokenB string
|
|
TotalShares math.Int
|
|
TotalLiquidity sdk.Coins
|
|
}
|
|
|
|
// ValidateLiquidityParameters validates liquidity parameters
|
|
func (k Keeper) ValidateLiquidityParameters(
|
|
tokenA sdk.Coin,
|
|
tokenB sdk.Coin,
|
|
minShares math.Int,
|
|
) error {
|
|
if tokenA.IsZero() || tokenB.IsZero() {
|
|
return fmt.Errorf("token amounts cannot be zero")
|
|
}
|
|
|
|
if tokenA.Denom == tokenB.Denom {
|
|
return fmt.Errorf("cannot provide liquidity with same token")
|
|
}
|
|
|
|
if minShares.IsNegative() {
|
|
return fmt.Errorf("minimum shares cannot be negative")
|
|
}
|
|
|
|
return nil
|
|
}
|