package pool
import (
"errors"
"gno.land/p/gnoswap/store"
bptree "gno.land/p/nt/bptree/v0"
ufmt "gno.land/p/nt/ufmt/v0"
)
// StoreKey defines the keys used for storing pool data in the KV store.
// These keys are prefixed with the domain address to ensure namespace isolation.
type StoreKey string
func (s StoreKey) String() string {
return string(s)
}
const (
// Pool data storage keys
StoreKeyPools StoreKey = "pools" // Map containing all pools
StoreKeyFeeAmountTickSpacing StoreKey = "feeAmountTickSpacing" // Fee tier to tick spacing mapping
StoreKeySlot0FeeProtocol StoreKey = "slot0FeeProtocol" // Protocol fee percentage
// Protocol fee storage keys
StoreKeyPoolCreationFee StoreKey = "poolCreationFee" // Pool creation fee amount
StoreKeyPendingProtocolFees StoreKey = "pendingProtocolFees" // tokenPath -> amount held locally for protocol_fee
StoreKeyWithdrawalFeeBPS StoreKey = "withdrawalFeeBPS" // Withdrawal fee in basis points
StoreKeyUnlocked StoreKey = "unlocked" // Global pool reentrancy lock
// Swap hook storage keys
StoreKeySwapStartHook StoreKey = "swapStartHook" // Swap start hook function
StoreKeySwapEndHook StoreKey = "swapEndHook" // Swap end hook function
StoreKeyTickCrossHook StoreKey = "tickCrossHook" // Tick cross hook function
)
// poolStore implements the IPoolStore interface for pool domain storage.
// It provides type-safe access to pool data stored in the underlying KV store.
type poolStore struct {
kvStore store.KVStore
}
func (s *poolStore) HasPools() bool {
return s.kvStore.Has(StoreKeyPools.String())
}
// GetPools retrieves the map containing all pool data.
// This is the main data structure that stores all pool instances.
func (s *poolStore) GetPools() *bptree.BPTree {
pools, err := s.kvStore.GetBPTree(StoreKeyPools.String())
if err != nil {
panic(err)
}
if pools == nil {
panic("pools is nil")
}
return pools
}
// SetPools stores the map containing all pool data.
func (s *poolStore) SetPools(_ int, rlm realm, pools *bptree.BPTree) error {
if !rlm.IsCurrent() {
return errors.New(ErrSpoofedRealm)
}
if pools == nil {
panic("pools is nil")
}
return s.kvStore.Set(0, rlm, StoreKeyPools.String(), pools)
}
func (s *poolStore) HasFeeAmountTickSpacing() bool {
return s.kvStore.Has(StoreKeyFeeAmountTickSpacing.String())
}
// GetFeeAmountTickSpacing retrieves the mapping between fee amounts and tick spacing.
// This mapping determines the tick spacing for each supported fee tier.
func (s *poolStore) GetFeeAmountTickSpacing() map[uint32]int32 {
result, err := s.kvStore.Get(StoreKeyFeeAmountTickSpacing.String())
if err != nil {
panic(err)
}
feeAmountTickSpacing, ok := result.(map[uint32]int32)
if !ok {
panic(ufmt.Sprintf("failed to cast result to map[uint32]int32: %T", result))
}
if feeAmountTickSpacing == nil {
panic("feeAmountTickSpacing is nil")
}
return cloneFeeAmountTickSpacings(feeAmountTickSpacing)
}
// SetFeeAmountTickSpacing stores the mapping between fee amounts and tick spacing.
func (s *poolStore) SetFeeAmountTickSpacing(_ int, rlm realm, feeAmountTickSpacing map[uint32]int32) error {
if !rlm.IsCurrent() {
return errors.New(ErrSpoofedRealm)
}
if feeAmountTickSpacing == nil {
panic("feeAmountTickSpacing is nil")
}
return s.kvStore.Set(0, rlm, StoreKeyFeeAmountTickSpacing.String(), feeAmountTickSpacing)
}
func (s *poolStore) HasSlot0FeeProtocol() bool {
return s.kvStore.Has(StoreKeySlot0FeeProtocol.String())
}
// GetSlot0FeeProtocol retrieves the protocol fee percentage for slot0.
func (s *poolStore) GetSlot0FeeProtocol() uint8 {
result, err := s.kvStore.Get(StoreKeySlot0FeeProtocol.String())
if err != nil {
panic(err)
}
slot0FeeProtocol, ok := result.(uint8)
if !ok {
panic(ufmt.Sprintf("failed to cast result to uint8: %T", result))
}
return slot0FeeProtocol
}
// SetSlot0FeeProtocol stores the protocol fee percentage for slot0.
func (s *poolStore) SetSlot0FeeProtocol(_ int, rlm realm, slot0FeeProtocol uint8) error {
if !rlm.IsCurrent() {
return errors.New(ErrSpoofedRealm)
}
return s.kvStore.Set(0, rlm, StoreKeySlot0FeeProtocol.String(), slot0FeeProtocol)
}
func (s *poolStore) HasPoolCreationFee() bool {
return s.kvStore.Has(StoreKeyPoolCreationFee.String())
}
// GetPoolCreationFee retrieves the pool creation fee amount.
func (s *poolStore) GetPoolCreationFee() int64 {
result, err := s.kvStore.Get(StoreKeyPoolCreationFee.String())
if err != nil {
panic(err)
}
poolCreationFee, ok := result.(int64)
if !ok {
panic(ufmt.Sprintf("failed to cast result to int64: %T", result))
}
return poolCreationFee
}
// SetPoolCreationFee stores the pool creation fee amount.
func (s *poolStore) SetPoolCreationFee(_ int, rlm realm, poolCreationFee int64) error {
if !rlm.IsCurrent() {
return errors.New(ErrSpoofedRealm)
}
return s.kvStore.Set(0, rlm, StoreKeyPoolCreationFee.String(), poolCreationFee)
}
func (s *poolStore) HasPendingProtocolFees() bool {
return s.kvStore.Has(StoreKeyPendingProtocolFees.String())
}
func (s *poolStore) GetPendingProtocolFees() map[string]int64 {
result, err := s.kvStore.Get(StoreKeyPendingProtocolFees.String())
if err != nil {
panic(err)
}
pendingProtocolFees, ok := result.(map[string]int64)
if !ok {
panic(ufmt.Sprintf("failed to cast result to map[string]int64: %T", result))
}
return cloneStringInt64Map(pendingProtocolFees)
}
func (s *poolStore) SetPendingProtocolFees(_ int, rlm realm, pendingProtocolFees map[string]int64) error {
if !rlm.IsCurrent() {
return errors.New(ErrSpoofedRealm)
}
return s.kvStore.Set(0, rlm, StoreKeyPendingProtocolFees.String(), pendingProtocolFees)
}
func (s *poolStore) HasWithdrawalFeeBPS() bool {
return s.kvStore.Has(StoreKeyWithdrawalFeeBPS.String())
}
// GetWithdrawalFeeBPS retrieves the withdrawal fee in basis points.
func (s *poolStore) GetWithdrawalFeeBPS() uint64 {
result, err := s.kvStore.Get(StoreKeyWithdrawalFeeBPS.String())
if err != nil {
panic(err)
}
withdrawalFeeBPS, ok := result.(uint64)
if !ok {
panic(ufmt.Sprintf("failed to cast result to uint64: %T", result))
}
return withdrawalFeeBPS
}
// SetWithdrawalFeeBPS stores the withdrawal fee in basis points.
func (s *poolStore) SetWithdrawalFeeBPS(_ int, rlm realm, withdrawalFeeBPS uint64) error {
if !rlm.IsCurrent() {
return errors.New(ErrSpoofedRealm)
}
return s.kvStore.Set(0, rlm, StoreKeyWithdrawalFeeBPS.String(), withdrawalFeeBPS)
}
func (s *poolStore) HasUnlocked() bool {
return s.kvStore.Has(StoreKeyUnlocked.String())
}
func (s *poolStore) GetUnlocked() bool {
result, err := s.kvStore.Get(StoreKeyUnlocked.String())
if err != nil {
panic(err)
}
unlocked, ok := result.(bool)
if !ok {
panic(ufmt.Sprintf("failed to cast result to bool: %T", result))
}
return unlocked
}
func (s *poolStore) SetUnlocked(_ int, rlm realm, unlocked bool) error {
if !rlm.IsCurrent() {
return errors.New(ErrSpoofedRealm)
}
return s.kvStore.Set(0, rlm, StoreKeyUnlocked.String(), unlocked)
}
// HasSwapStartHook checks if the swap start hook is set.
func (s *poolStore) HasSwapStartHook() bool {
return s.kvStore.Has(StoreKeySwapStartHook.String())
}
// GetSwapStartHook retrieves the swap start hook function.
func (s *poolStore) GetSwapStartHook() func(cur realm, poolPath string, timestamp int64) {
result, err := s.kvStore.Get(StoreKeySwapStartHook.String())
if err != nil {
panic(err)
}
swapStartHook, ok := result.(func(cur realm, poolPath string, timestamp int64))
if !ok {
panic(ufmt.Sprintf("failed to cast result to func(poolPath string, timestamp int64): %T", result))
}
return swapStartHook
}
// SetSwapStartHook stores the swap start hook function.
func (s *poolStore) SetSwapStartHook(_ int, rlm realm, swapStartHook func(cur realm, poolPath string, timestamp int64)) error {
if !rlm.IsCurrent() {
return errors.New(ErrSpoofedRealm)
}
return s.kvStore.Set(0, rlm, StoreKeySwapStartHook.String(), swapStartHook)
}
// HasSwapEndHook checks if the swap end hook is set.
func (s *poolStore) HasSwapEndHook() bool {
return s.kvStore.Has(StoreKeySwapEndHook.String())
}
// GetSwapEndHook retrieves the swap end hook function.
func (s *poolStore) GetSwapEndHook() func(cur realm, poolPath string) error {
result, err := s.kvStore.Get(StoreKeySwapEndHook.String())
if err != nil {
panic(err)
}
swapEndHook, ok := result.(func(cur realm, poolPath string) error)
if !ok {
panic(ufmt.Sprintf("failed to cast result to func(poolPath string): %T", result))
}
return swapEndHook
}
// SetSwapEndHook stores the swap end hook function.
func (s *poolStore) SetSwapEndHook(_ int, rlm realm, swapEndHook func(cur realm, poolPath string) error) error {
if !rlm.IsCurrent() {
return errors.New(ErrSpoofedRealm)
}
return s.kvStore.Set(0, rlm, StoreKeySwapEndHook.String(), swapEndHook)
}
// HasTickCrossHook checks if the tick cross hook is set.
func (s *poolStore) HasTickCrossHook() bool {
return s.kvStore.Has(StoreKeyTickCrossHook.String())
}
// GetTickCrossHook retrieves the tick cross hook function.
func (s *poolStore) GetTickCrossHook() func(cur realm, poolPath string, tickId int32, zeroForOne bool, timestamp int64) {
result, err := s.kvStore.Get(StoreKeyTickCrossHook.String())
if err != nil {
panic(err)
}
tickCrossHook, ok := result.(func(cur realm, poolPath string, tickId int32, zeroForOne bool, timestamp int64))
if !ok {
panic(ufmt.Sprintf("failed to cast result to func(poolPath string, tickId int32, zeroForOne bool, timestamp int64): %T", result))
}
return tickCrossHook
}
// SetTickCrossHook stores the tick cross hook function.
func (s *poolStore) SetTickCrossHook(_ int, rlm realm, tickCrossHook func(cur realm, poolPath string, tickId int32, zeroForOne bool, timestamp int64)) error {
if !rlm.IsCurrent() {
return errors.New(ErrSpoofedRealm)
}
return s.kvStore.Set(0, rlm, StoreKeyTickCrossHook.String(), tickCrossHook)
}
// NewPoolStore creates a new pool store instance with the provided KV store.
// This function is used by the upgrade system to create storage instances for each implementation.
func NewPoolStore(kvStore store.KVStore) IPoolStore {
return &poolStore{
kvStore: kvStore,
}
}