Skip to content
This repository was archived by the owner on Mar 19, 2025. It is now read-only.

Commit 888e3d1

Browse files
committed
chore: remove map in pool data
1 parent dfa8be4 commit 888e3d1

16 files changed

Lines changed: 336 additions & 226 deletions

go.mod

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -217,6 +217,7 @@ require (
217217
github.com/cosmos/cosmos-proto v1.0.0-beta.4
218218
github.com/cosmos/ics23/go v0.10.0
219219
github.com/prometheus/client_golang v1.16.0
220+
github.com/shopspring/decimal v1.3.1
220221
golang.org/x/tools v0.12.0
221222
google.golang.org/genproto/googleapis/api v0.0.0-20231212172506-995d672761c0
222223
google.golang.org/grpc v1.60.1

go.sum

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -951,6 +951,8 @@ github.com/samuel/go-zookeeper v0.0.0-20190923202752-2cc03de413da/go.mod h1:gi+0
951951
github.com/sasha-s/go-deadlock v0.3.1 h1:sqv7fDNShgjcaxkO0JNcOAlr8B9+cV5Ey/OB71efZx0=
952952
github.com/sasha-s/go-deadlock v0.3.1/go.mod h1:F73l+cr82YSh10GxyRI6qZiCgK64VaZjwesgfQ1/iLM=
953953
github.com/sean-/seed v0.0.0-20170313163322-e2103e2c3529/go.mod h1:DxrIzT+xaE7yg65j358z/aeFdxmN0P9QXhEzd20vsDc=
954+
github.com/shopspring/decimal v1.3.1 h1:2Usl1nmF/WZucqkFZhnfFYxxxu8LG21F6nPQBE5gKV8=
955+
github.com/shopspring/decimal v1.3.1/go.mod h1:DKyhrW/HYNuLGql+MJL6WCR6knT2jwCFRcu2hWCYk4o=
954956
github.com/shurcooL/sanitized_anchor_name v1.0.0/go.mod h1:1NzhyTcUVG4SuEtjjoZeVRXNmyL/1OwPU0+IJeTBvfc=
955957
github.com/sideprotocol/cosmos-sdk v0.47.111 h1:BaNMkp918+nAhxDP37+slIGEJlJiRxAJFAiciPgwi9I=
956958
github.com/sideprotocol/cosmos-sdk v0.47.111/go.mod h1:F3+fgTq4W3kYIw+ETBaKaXi/t3eUPVKCDvKYqcei5WQ=

proto/side/gmm/pool.proto

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ message Pool {
1212
string pool_id = 1;
1313
string sender = 2;
1414
PoolParams poolParams = 3 [(gogoproto.nullable) = false];
15-
map<string, PoolAsset> assets = 4 [(gogoproto.nullable) = false];
15+
repeated PoolAsset assets = 4 [(gogoproto.nullable) = false];
1616
// sum of all LP tokens sent out
1717
cosmos.base.v1beta1.Coin total_shares = 5 [
1818
(gogoproto.moretags) = "yaml:\"total_shares\"",

x/gmm/keeper/msg_server_create_pool_test.go

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -228,12 +228,12 @@ func (suite *KeeperTestSuite) createNewStablePool() string {
228228
},
229229
[]types.PoolAsset{
230230
{
231-
Token: sdk.NewCoin(simapp.WDAI, sdkmath.NewInt(100)),
231+
Token: sdk.NewCoin(simapp.WDAI, sdkmath.NewInt(100000)),
232232
Weight: &weight,
233233
Decimal: sdk.NewInt(6),
234234
},
235235
{
236-
Token: sdk.NewCoin(simapp.WUSDT, sdkmath.NewInt(100)),
236+
Token: sdk.NewCoin(simapp.WUSDT, sdkmath.NewInt(100000)),
237237
Weight: &weight,
238238
Decimal: sdk.NewInt(6),
239239
},

x/gmm/keeper/msg_server_swap_test.go

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,7 @@ func (suite *KeeperTestSuite) TestMsgSwap() {
2727
"swap in stable pool",
2828
types.PoolType_STABLE,
2929
func(msg *types.MsgSwap, poolID string) {
30-
msg.TokenIn = sdk.NewCoin(simapp.WDAI, sdk.NewInt(100))
30+
msg.TokenIn = sdk.NewCoin(simapp.WDAI, sdk.NewInt(50))
3131
msg.TokenOut = sdk.NewCoin(simapp.WUSDT, sdk.NewInt(0))
3232
},
3333
},
@@ -57,7 +57,8 @@ func (suite *KeeperTestSuite) TestMsgSwap() {
5757
suite.Require().NoError(err)
5858

5959
pool := queryResBeforeSwap.Pool.ToPool()
60-
outAssetBeforeSwap := pool.Assets[msg.TokenOut.Denom]
60+
outAssetBeforeSwap, _, exist := pool.GetAssetByDenom(msg.TokenOut.Denom)
61+
suite.Require().Equal(exist, true)
6162
estimatedOut, err := pool.EstimateSwap(msg.TokenIn, msg.TokenOut.Denom)
6263
suite.Require().NoError(err)
6364
msg.TokenOut = estimatedOut
@@ -75,7 +76,8 @@ func (suite *KeeperTestSuite) TestMsgSwap() {
7576
})
7677
suite.Require().NoError(err)
7778
pool = queryResAfterSwap.Pool.ToPool()
78-
outAssetAfterSwap := pool.Assets[msg.TokenOut.Denom]
79+
outAssetAfterSwap, _, exist := pool.GetAssetByDenom(msg.TokenOut.Denom)
80+
suite.Require().Equal(exist, true)
7981
out := outAssetBeforeSwap.Token.Sub(outAssetAfterSwap.Token)
8082
suite.Require().Equal(out, estimatedOut)
8183
})

x/gmm/keeper/pool_apr_test.go

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -15,20 +15,20 @@ func TestAPRCalculation(t *testing.T) {
1515
keeper, ctx := testkeeper.GmmKeeper(t)
1616
amp := sdkmath.NewInt(100)
1717
//params := types.DefaultParams()
18-
mockAssets := make(map[string]types.PoolAsset)
18+
mockAssets := []types.PoolAsset{}
1919
weight := sdkmath.NewInt(6)
2020
tokenIn := sdk.NewCoin("usdt", sdk.NewInt(100))
2121
//tokenOut := sdk.NewCoin("usdc", sdk.NewInt(80))
22-
mockAssets["usdt"] = types.PoolAsset{
22+
mockAssets = append(mockAssets, types.PoolAsset{
2323
Decimal: sdkmath.NewInt(6),
2424
Weight: &weight,
2525
Token: sdk.NewCoin("usdt", sdk.NewInt(1000000)),
26-
}
27-
mockAssets["usdc"] = types.PoolAsset{
26+
})
27+
mockAssets = append(mockAssets, types.PoolAsset{
2828
Decimal: sdkmath.NewInt(6),
2929
Weight: &weight,
3030
Token: sdk.NewCoin("usdc", sdk.NewInt(1000000)),
31-
}
31+
})
3232

3333
pool := types.Pool{
3434
PoolId: "test",

x/gmm/keeper/volume_test.go

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -15,20 +15,20 @@ func TestVolumeQuery(t *testing.T) {
1515
keeper, ctx := testkeeper.GmmKeeper(t)
1616
amp := sdkmath.NewInt(100)
1717
//params := types.DefaultParams()
18-
mockAssets := make(map[string]types.PoolAsset)
18+
mockAssets := []types.PoolAsset{}
1919
weight := sdkmath.NewInt(6)
2020
tokenIn := sdk.NewCoin("usdt", sdk.NewInt(100))
2121
tokenOut := sdk.NewCoin("usdc", sdk.NewInt(80))
22-
mockAssets["usdt"] = types.PoolAsset{
22+
mockAssets = append(mockAssets, types.PoolAsset{
2323
Decimal: sdkmath.NewInt(6),
2424
Weight: &weight,
2525
Token: sdk.NewCoin("usdt", sdk.NewInt(1000000)),
26-
}
27-
mockAssets["usdc"] = types.PoolAsset{
26+
})
27+
mockAssets = append(mockAssets, types.PoolAsset{
2828
Decimal: sdkmath.NewInt(6),
2929
Weight: &weight,
3030
Token: sdk.NewCoin("usdc", sdk.NewInt(1000000)),
31-
}
31+
})
3232

3333
pool := types.Pool{
3434
PoolId: "test",

x/gmm/types/approx_power.go

Lines changed: 145 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,145 @@
1+
package types
2+
3+
import (
4+
"errors"
5+
"math/big"
6+
"strings"
7+
8+
"github.com/shopspring/decimal"
9+
)
10+
11+
// DecimalFractional constant for decimal calculations
12+
var DecimalFractional = decimal.NewFromBigInt(big.NewInt(1_000_000_000_000_000_000), 0)
13+
14+
// SubSign returns mod subtraction and boolean indicating if the result is negative
15+
func SubSign(a, b decimal.Decimal) (decimal.Decimal, bool) {
16+
if a.GreaterThanOrEqual(b) {
17+
return a.Sub(b), false
18+
}
19+
return b.Sub(a), true
20+
}
21+
22+
// Sqrt computes the square root of a decimal number using Newton's method.
23+
func Sqrt(value decimal.Decimal, precision decimal.Decimal) (decimal.Decimal, error) {
24+
if value.LessThan(decimal.Zero) {
25+
return decimal.Decimal{}, errors.New("square root of negative number")
26+
}
27+
28+
x := value.DivRound(decimal.NewFromInt(2), precision.Exponent())
29+
lastX := decimal.Zero
30+
31+
for x.Sub(lastX).Abs().GreaterThan(precision) {
32+
lastX = x
33+
x = decimal.Avg(x, value.Div(x))
34+
}
35+
36+
return x, nil
37+
}
38+
39+
// CalculatePow computes base^(exp) using an approximation algorithm
40+
func ApproximatePow(baseS, expS string, precisionS string) (decimal.Decimal, error) {
41+
// Convert string to Decimal
42+
base, err := decimal.NewFromString(baseS)
43+
if err != nil {
44+
return decimal.Decimal{}, err
45+
}
46+
47+
exp, err := decimal.NewFromString(expS)
48+
if err != nil {
49+
return decimal.Decimal{}, err
50+
}
51+
52+
precision, err := decimal.NewFromString(precisionS)
53+
if err != nil {
54+
return decimal.Decimal{}, err
55+
}
56+
57+
if base.IsZero() && !exp.IsZero() {
58+
return base, nil
59+
}
60+
61+
if base.GreaterThan(decimal.NewFromInt(2)) {
62+
return decimal.Decimal{}, errors.New("calculatePow: base must be less than 2")
63+
}
64+
65+
integer := exp.Div(DecimalFractional).Floor()
66+
fractional := exp.Mod(DecimalFractional)
67+
integerPow := base.Pow(integer)
68+
69+
if fractional.IsZero() {
70+
return integerPow, nil
71+
}
72+
73+
fractionalPow, err := PowApprox(base, fractional, precision)
74+
if err != nil {
75+
return decimal.Decimal{}, err
76+
}
77+
78+
result := integerPow.Mul(fractionalPow)
79+
return result, nil
80+
}
81+
82+
// PowApprox approximates power for fractional exponents
83+
func PowApprox(base, exp, precision decimal.Decimal) (decimal.Decimal, error) {
84+
if exp.Equals(decimal.NewFromInt(1).Div(decimal.NewFromInt(2))) {
85+
sqrtBase, err := Sqrt(base, precision)
86+
if err != nil {
87+
return decimal.Decimal{}, err
88+
}
89+
return sqrtBase, nil
90+
}
91+
92+
x, xNeg := SubSign(base, decimal.NewFromInt(1))
93+
term := decimal.NewFromInt(1)
94+
sum := decimal.NewFromInt(1)
95+
negative := false
96+
97+
a := exp
98+
bigK := decimal.Zero
99+
i := decimal.NewFromInt(1)
100+
101+
for term.GreaterThanOrEqual(precision) {
102+
c, cNeg := SubSign(a, bigK)
103+
bigK = i
104+
105+
newTerm := term.Mul(c).Mul(x).Div(bigK)
106+
term = newTerm
107+
108+
if term.IsZero() {
109+
break
110+
}
111+
112+
if xNeg {
113+
negative = !negative
114+
}
115+
116+
if cNeg {
117+
negative = !negative
118+
}
119+
120+
if negative {
121+
sum = sum.Sub(term)
122+
} else {
123+
sum = sum.Add(term)
124+
}
125+
126+
i = i.Add(decimal.NewFromInt(1))
127+
}
128+
fixedPoint := DecimalPlacesFromPrecision(precision)
129+
return sum.RoundDown(fixedPoint), nil
130+
}
131+
132+
// DecimalPlacesFromPrecision calculates the number of decimal places based on the precision decimal.
133+
// DecimalPlacesFromPrecision calculates the number of decimal places based on the precision decimal.
134+
func DecimalPlacesFromPrecision(precision decimal.Decimal) int32 {
135+
// Convert precision to string using no fixed decimal places to avoid trailing zeros.
136+
str := precision.String()
137+
dotIndex := strings.IndexRune(str, '.')
138+
if dotIndex != -1 {
139+
// Remove trailing zeros to get the correct count of significant decimal places.
140+
str = strings.TrimRight(str, "0")
141+
// Count the number of characters after the decimal point to determine the scale.
142+
return int32(len(str) - dotIndex - 1)
143+
}
144+
return 0 // Return 0 if there is no fractional part.
145+
}

x/gmm/types/message_create_pool.go

Lines changed: 21 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,8 @@
11
package types
22

33
import (
4+
"sort"
5+
46
sdkerrors "cosmossdk.io/errors"
57
sdkmath "cosmossdk.io/math"
68
sdk "github.com/cosmos/cosmos-sdk/types"
@@ -101,27 +103,38 @@ func (msg *MsgCreatePool) GetAssetDenoms() []string {
101103
return denoms
102104
}
103105

104-
// Return denom list of liquidity
105106
func (msg *MsgCreatePool) CreatePool() Pool {
106107
// Extract denom list from Liquidity
107108
denoms := msg.GetAssetDenoms()
108109

109-
assets := make(map[string]PoolAsset)
110+
// Sort denoms in alphabetical order
111+
sort.Strings(denoms) // This ensures the denoms are in a deterministic order
112+
113+
assets := make([]PoolAsset, len(msg.Liquidity)) // Change this to a slice to maintain order
110114
totalShares := sdk.NewInt(0)
111-
for _, liquidity := range msg.Liquidity {
112-
assets[liquidity.Token.Denom] = liquidity
113-
totalShares = totalShares.Add(liquidity.Token.Amount)
115+
116+
// Fill the assets slice in a deterministic manner
117+
for i, denom := range denoms {
118+
for _, liquidity := range msg.Liquidity {
119+
if liquidity.Token.Denom == denom {
120+
assets[i] = liquidity // Assigning by sorted index
121+
totalShares = totalShares.Add(liquidity.Token.Amount)
122+
break // Move to next denom after finding and assigning
123+
}
124+
}
114125
}
115126

116-
// Generate new PoolId
117-
newPoolID := GetPoolID(denoms)
127+
// Generate new PoolId using sorted denoms
128+
newPoolID := GetPoolID(denoms) // Assuming this is already implemented to be deterministic
118129
poolShareBaseDenom := GetPoolShareDenom(newPoolID)
130+
119131
pool := Pool{
120132
PoolId: newPoolID,
121133
Sender: msg.Sender,
122134
PoolParams: *msg.Params,
123-
Assets: assets,
135+
Assets: assets, // Now a slice, maintaining the order
124136
TotalShares: sdk.NewCoin(poolShareBaseDenom, totalShares),
125137
}
138+
126139
return pool
127140
}

x/gmm/types/pool.go

Lines changed: 22 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -82,13 +82,13 @@ func (p *Pool) DecreaseShare(amt sdkmath.Int) {
8282
// IncreaseLiquidity adds xx amount liquidity to assets in pool
8383
func (p *Pool) IncreaseLiquidity(coins []sdk.Coin) error {
8484
for _, coin := range coins {
85-
asset, exists := p.Assets[coin.Denom]
85+
asset, index, exists := p.GetAssetByDenom(coin.Denom) //Assets[coin.Denom]
8686
if !exists {
8787
return ErrNotFoundAssetInPool
8888
}
8989
// Add liquidity logic here
9090
asset.Token.Amount = asset.Token.Amount.Add(coin.Amount)
91-
p.Assets[coin.Denom] = asset
91+
p.Assets[index] = asset
9292
}
9393
// Update TotalShares or other fields if necessary
9494
return nil
@@ -97,18 +97,27 @@ func (p *Pool) IncreaseLiquidity(coins []sdk.Coin) error {
9797
// DecreaseLiquidity subtracts xx amount liquidity from assets in pool
9898
func (p *Pool) DecreaseLiquidity(coins []sdk.Coin) error {
9999
for _, coin := range coins {
100-
asset, exists := p.Assets[coin.Denom]
100+
asset, index, exists := p.GetAssetByDenom(coin.Denom)
101101
if !exists {
102102
return ErrNotFoundAssetInPool
103103
}
104104
// Add liquidity logic here
105105
asset.Token.Amount = asset.Token.Amount.Sub(coin.Amount)
106-
p.Assets[coin.Denom] = asset
106+
p.Assets[index] = asset
107107
}
108108
// Update TotalShares or other fields if necessary
109109
return nil
110110
}
111111

112+
func (p *Pool) GetAssetByDenom(denom string) (PoolAsset, int, bool) {
113+
for index, asset := range p.Assets {
114+
if asset.Token.Denom == denom {
115+
return asset, index, true
116+
}
117+
}
118+
return PoolAsset{}, 0, false
119+
}
120+
112121
// findAssetByDenom finds pool asset by denom
113122
func (p *Pool) findAssetByDenom(denom string) (PoolAsset, error) {
114123
for _, asset := range p.Assets {
@@ -162,3 +171,12 @@ func (p *Pool) Sum() sdkmath.Int {
162171
}
163172
return sdk.ZeroInt()
164173
}
174+
175+
func FindAsset(assets []PoolAsset, denom string) (PoolAsset, bool) {
176+
for _, asset := range assets {
177+
if asset.Token.Denom == denom {
178+
return asset, true
179+
}
180+
}
181+
return PoolAsset{}, false
182+
}

0 commit comments

Comments
 (0)