Skip to content

Commit 6fad886

Browse files
dongsamjaybxyzhallazzangCoinedLiberty
authored
release liquidity v1.4.1 (#459)
* feat: add markdown link checker github workflow * feat: bump cosmos sdk to v0.44.1 * feat: bump cosmos-sdk to v0.44.2 * fix: Pool Coin Decimal Truncation During Deposit (#446) * fix: wip poc for reproduce and fix poolcoin truncation * fix: simplify calculation logic and add more tests * fix: use equality check in MintingPoolCoinsInvariant * test: fix expected value due to the change in deposit logic, expected value in test also changed * test: add test for MintingPoolCoinsInvariant * fix: update deposit truncation logic and simulation ordering * docs: update changelog and readme * fix: revert MulTruncate to Mul on Deposit Co-authored-by: Hanjun Kim <[email protected]> * Fix: add overflow checking and test codes for cover edge cases (#458) * test: add testcase for cover small withdrawal case * test: add test case for CreatePool * fix: refactor and optimize depleted pool validation * feat: add overflow checking logic * chore: add testcase and remove comments * test: add test code for big deposit * fix: apply PR suggestions * fix: add overflow checking logic and test cases Co-authored-by: Hanjun Kim <[email protected]> Co-authored-by: typark391 <[email protected]> Co-authored-by: kogisin <[email protected]> Co-authored-by: Hanjun Kim <[email protected]> Co-authored-by: typark391 <[email protected]>
1 parent 4844b2f commit 6fad886

File tree

17 files changed

+1121
-143
lines changed

17 files changed

+1121
-143
lines changed

.github/workflows/linkchecker.yml

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
name: Check Markdown links
2+
3+
on:
4+
pull_request:
5+
push:
6+
branches:
7+
- master
8+
- develop
9+
schedule:
10+
- cron: '* */24 * * *'
11+
12+
jobs:
13+
markdown-link-check:
14+
runs-on: ubuntu-latest
15+
steps:
16+
- uses: actions/checkout@master
17+
- uses: gaurav-nelson/[email protected]
18+
with:
19+
folder-path: "."

CHANGELOG.md

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,13 @@ Ref: https://keepachangelog.com/en/1.0.0/
3737

3838
## [Unreleased]
3939

40+
## [v1.4.1](https://github.com/tendermint/liquidity/releases) - 2021.10.25
41+
42+
* [\#455](https://github.com/tendermint/liquidity/pull/455) (sdk) Bump SDK version to [v0.44.2](https://github.com/cosmos/cosmos-sdk/releases/tag/v0.44.2)
43+
* [\#446](https://github.com/tendermint/liquidity/pull/446) Fix: Pool Coin Decimal Truncation During Deposit
44+
* [\#448](https://github.com/tendermint/liquidity/pull/448) Fix: add overflow checking and test codes for cover edge cases
45+
46+
4047
## [v1.4.0](https://github.com/tendermint/liquidity/releases/tag/v1.4.0) - 2021.09.07
4148

4249
* [\#440](https://github.com/tendermint/liquidity/pull/440) (sdk) Bump SDK version to [v0.44.0](https://github.com/cosmos/cosmos-sdk/releases/tag/v0.44.0)

README.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,7 @@ For details, see the [Liquidity Module Light Paper](doc/LiquidityModuleLightPape
3535
Requirement | Notes
3636
----------- | -----------------
3737
Go version | Go1.15 or higher
38-
Cosmos SDK | v0.44.0 or higher
38+
Cosmos SDK | v0.44.2 or higher
3939

4040
### Get Liquidity Module source code
4141

app/app.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -381,8 +381,8 @@ func NewLiquidityApp(
381381
slashing.NewAppModule(appCodec, app.SlashingKeeper, app.AccountKeeper, app.BankKeeper, app.StakingKeeper),
382382
params.NewAppModule(app.ParamsKeeper),
383383
evidence.NewAppModule(app.EvidenceKeeper),
384-
authzmodule.NewAppModule(appCodec, app.AuthzKeeper, app.AccountKeeper, app.BankKeeper, app.interfaceRegistry),
385384
liquidity.NewAppModule(appCodec, app.LiquidityKeeper, app.AccountKeeper, app.BankKeeper, app.DistrKeeper),
385+
authzmodule.NewAppModule(appCodec, app.AuthzKeeper, app.AccountKeeper, app.BankKeeper, app.interfaceRegistry),
386386
)
387387

388388
// register the store decoders for simulation tests

go.mod

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ go 1.15
33
module github.com/tendermint/liquidity
44

55
require (
6-
github.com/cosmos/cosmos-sdk v0.44.0
6+
github.com/cosmos/cosmos-sdk v0.44.2
77
github.com/gogo/protobuf v1.3.3
88
github.com/golang/mock v1.6.0
99
github.com/golang/protobuf v1.5.2
@@ -12,15 +12,15 @@ require (
1212
github.com/grpc-ecosystem/grpc-gateway/v2 v2.0.1
1313
github.com/rakyll/statik v0.1.7
1414
github.com/spf13/cast v1.3.1
15-
github.com/spf13/cobra v1.1.3
15+
github.com/spf13/cobra v1.2.1
1616
github.com/spf13/pflag v1.0.5
17-
github.com/spf13/viper v1.8.0
17+
github.com/spf13/viper v1.8.1
1818
github.com/stretchr/testify v1.7.0
19-
github.com/tendermint/tendermint v0.34.12
19+
github.com/tendermint/tendermint v0.34.13
2020
github.com/tendermint/tm-db v0.6.4
2121
google.golang.org/genproto v0.0.0-20210602131652-f16073e35f0c
22-
google.golang.org/grpc v1.38.0
23-
google.golang.org/protobuf v1.26.0
22+
google.golang.org/grpc v1.40.0
23+
google.golang.org/protobuf v1.27.1
2424
gopkg.in/yaml.v2 v2.4.0
2525
)
2626

go.sum

Lines changed: 374 additions & 26 deletions
Large diffs are not rendered by default.

x/liquidity/keeper/batch.go

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -236,7 +236,14 @@ func (k Keeper) WithdrawWithinBatch(ctx sdk.Context, msg *types.MsgWithdrawWithi
236236

237237
// In order to deal with the batch at the same time, the coins of msgs are deposited in escrow.
238238
func (k Keeper) SwapWithinBatch(ctx sdk.Context, msg *types.MsgSwapWithinBatch, orderExpirySpanHeight int64) (*types.SwapMsgState, error) {
239-
if err := k.ValidateMsgSwapWithinBatch(ctx, *msg); err != nil {
239+
pool, found := k.GetPool(ctx, msg.PoolId)
240+
if !found {
241+
return nil, types.ErrPoolNotExists
242+
}
243+
if k.IsDepletedPool(ctx, pool) {
244+
return nil, types.ErrDepletedPool
245+
}
246+
if err := k.ValidateMsgSwapWithinBatch(ctx, *msg, pool); err != nil {
240247
return nil, err
241248
}
242249
poolBatch, found := k.GetPoolBatch(ctx, msg.PoolId)

x/liquidity/keeper/invariants.go

Lines changed: 9 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -94,10 +94,15 @@ func MintingPoolCoinsInvariant(poolCoinTotalSupply, mintPoolCoin, depositCoinA,
9494
expectedMintPoolCoinAmtBasedA := depositCoinARatio.MulInt(poolCoinTotalSupply).TruncateInt()
9595
expectedMintPoolCoinAmtBasedB := depositCoinBRatio.MulInt(poolCoinTotalSupply).TruncateInt()
9696

97-
// NewPoolCoinAmount / LastPoolCoinSupply <= AfterRefundedDepositCoinA / LastReserveCoinA
98-
// NewPoolCoinAmount / LastPoolCoinSupply <= AfterRefundedDepositCoinA / LastReserveCoinB
99-
if depositCoinARatio.LT(poolCoinRatio) || depositCoinBRatio.LT(poolCoinRatio) {
100-
panic("invariant check fails due to incorrect ratio of pool coins")
97+
// NewPoolCoinAmount / LastPoolCoinSupply == AfterRefundedDepositCoinA / LastReserveCoinA
98+
// NewPoolCoinAmount / LastPoolCoinSupply == AfterRefundedDepositCoinA / LastReserveCoinB
99+
if depositCoinA.GTE(coinAmountThreshold) && depositCoinB.GTE(coinAmountThreshold) &&
100+
lastReserveCoinA.GTE(coinAmountThreshold) && lastReserveCoinB.GTE(coinAmountThreshold) &&
101+
mintPoolCoin.GTE(coinAmountThreshold) && poolCoinTotalSupply.GTE(coinAmountThreshold) {
102+
if errorRate(depositCoinARatio, poolCoinRatio).GT(errorRateThreshold) ||
103+
errorRate(depositCoinBRatio, poolCoinRatio).GT(errorRateThreshold) {
104+
panic("invariant check fails due to incorrect ratio of pool coins")
105+
}
101106
}
102107

103108
if mintPoolCoin.GTE(coinAmountThreshold) &&

x/liquidity/keeper/invariants_test.go

Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,62 @@ func TestWithdrawRatioInvariant(t *testing.T) {
2121
})
2222
}
2323

24+
func TestMintingPoolCoinsInvariant(t *testing.T) {
25+
for _, tc := range []struct {
26+
poolCoinSupply int64
27+
mintingPoolCoin int64
28+
reserveA int64
29+
depositA int64
30+
refundedA int64
31+
reserveB int64
32+
depositB int64
33+
refundedB int64
34+
expectPanic bool
35+
}{
36+
{
37+
10000, 1000,
38+
100000, 10000, 0,
39+
100000, 10000, 0,
40+
false,
41+
},
42+
{
43+
10000, 1000,
44+
100000, 10000, 5000,
45+
100000, 10000, 300,
46+
true,
47+
},
48+
{
49+
3000000, 100,
50+
100000000, 4000, 667,
51+
200000000, 8000, 1334,
52+
false,
53+
},
54+
{
55+
3000000, 100,
56+
100000000, 4000, 0,
57+
200000000, 8000, 1334,
58+
true,
59+
},
60+
} {
61+
f := require.NotPanics
62+
if tc.expectPanic {
63+
f = require.Panics
64+
}
65+
f(t, func() {
66+
keeper.MintingPoolCoinsInvariant(
67+
sdk.NewInt(tc.poolCoinSupply),
68+
sdk.NewInt(tc.mintingPoolCoin),
69+
sdk.NewInt(tc.depositA),
70+
sdk.NewInt(tc.depositB),
71+
sdk.NewInt(tc.reserveA),
72+
sdk.NewInt(tc.reserveB),
73+
sdk.NewInt(tc.refundedA),
74+
sdk.NewInt(tc.refundedB),
75+
)
76+
})
77+
}
78+
}
79+
2480
func TestLiquidityPoolsEscrowAmountInvariant(t *testing.T) {
2581
simapp, ctx := app.CreateTestInput()
2682

x/liquidity/keeper/liquidity_pool.go

Lines changed: 55 additions & 75 deletions
Original file line numberDiff line numberDiff line change
@@ -188,9 +188,6 @@ func (k Keeper) ExecuteDeposit(ctx sdk.Context, msg types.DepositMsgState, batch
188188

189189
params := k.GetParams(ctx)
190190

191-
var inputs []banktypes.Input
192-
var outputs []banktypes.Output
193-
194191
reserveCoins := k.GetReserveCoins(ctx, pool)
195192

196193
// reinitialize pool if the pool is depleted
@@ -240,77 +237,59 @@ func (k Keeper) ExecuteDeposit(ctx sdk.Context, msg types.DepositMsgState, batch
240237
return nil
241238
}
242239

243-
// only two coins are acceptable
244-
if reserveCoins.Len() != msg.Msg.DepositCoins.Len() {
245-
return types.ErrNumOfReserveCoin
246-
}
247-
248240
reserveCoins.Sort()
249241

250-
// Decimal Error, divide the Int coin amount by the Decimal Rate and erase the decimal point to deposit a lower value
251-
lastReserveCoinA := reserveCoins[0].Amount
252-
lastReserveCoinB := reserveCoins[1].Amount
253-
lastReserveRatio := lastReserveCoinA.ToDec().QuoTruncate(lastReserveCoinB.ToDec())
242+
lastReserveCoinA := reserveCoins[0]
243+
lastReserveCoinB := reserveCoins[1]
254244

255245
depositCoinA := depositCoins[0]
256246
depositCoinB := depositCoins[1]
257-
depositCoinAmountA := depositCoinA.Amount
258-
depositCoinAmountB := depositCoinB.Amount
259-
depositableCoinAmountA := depositCoinB.Amount.ToDec().MulTruncate(lastReserveRatio).TruncateInt()
260-
261-
refundedCoins := sdk.NewCoins()
262-
refundedCoinA := sdk.ZeroInt()
263-
refundedCoinB := sdk.ZeroInt()
264-
265-
var acceptedCoins sdk.Coins
266-
// handle when depositing coin A amount is less than, greater than or equal to depositable amount
267-
if depositCoinA.Amount.LT(depositableCoinAmountA) {
268-
depositCoinAmountB = depositCoinA.Amount.ToDec().QuoTruncate(lastReserveRatio).TruncateInt()
269-
acceptedCoins = sdk.NewCoins(depositCoinA, sdk.NewCoin(depositCoinB.Denom, depositCoinAmountB))
270-
271-
inputs = append(inputs, banktypes.NewInput(batchEscrowAcc, acceptedCoins))
272-
outputs = append(outputs, banktypes.NewOutput(reserveAcc, acceptedCoins))
273-
274-
refundedCoinB = depositCoinB.Amount.Sub(depositCoinAmountB)
275-
276-
if refundedCoinB.IsPositive() {
277-
refundedCoins = sdk.NewCoins(sdk.NewCoin(depositCoinB.Denom, refundedCoinB))
278-
inputs = append(inputs, banktypes.NewInput(batchEscrowAcc, refundedCoins))
279-
outputs = append(outputs, banktypes.NewOutput(depositor, refundedCoins))
280-
}
281-
} else if depositCoinA.Amount.GT(depositableCoinAmountA) {
282-
depositCoinAmountA = depositCoinB.Amount.ToDec().MulTruncate(lastReserveRatio).TruncateInt()
283-
acceptedCoins = sdk.NewCoins(depositCoinB, sdk.NewCoin(depositCoinA.Denom, depositCoinAmountA))
284247

285-
inputs = append(inputs, banktypes.NewInput(batchEscrowAcc, acceptedCoins))
286-
outputs = append(outputs, banktypes.NewOutput(reserveAcc, acceptedCoins))
287-
288-
refundedCoinA = depositCoinA.Amount.Sub(depositCoinAmountA)
289-
290-
if refundedCoinA.IsPositive() {
291-
refundedCoins = sdk.NewCoins(sdk.NewCoin(depositCoinA.Denom, refundedCoinA))
292-
inputs = append(inputs, banktypes.NewInput(batchEscrowAcc, refundedCoins))
293-
outputs = append(outputs, banktypes.NewOutput(depositor, refundedCoins))
294-
}
295-
} else {
296-
acceptedCoins = sdk.NewCoins(depositCoinA, depositCoinB)
297-
inputs = append(inputs, banktypes.NewInput(batchEscrowAcc, acceptedCoins))
298-
outputs = append(outputs, banktypes.NewOutput(reserveAcc, acceptedCoins))
248+
poolCoinTotalSupply := k.GetPoolCoinTotalSupply(ctx, pool).ToDec()
249+
if err := types.CheckOverflowWithDec(poolCoinTotalSupply, depositCoinA.Amount.ToDec()); err != nil {
250+
return err
299251
}
252+
if err := types.CheckOverflowWithDec(poolCoinTotalSupply, depositCoinB.Amount.ToDec()); err != nil {
253+
return err
254+
}
255+
poolCoinMintAmt := sdk.MinDec(
256+
poolCoinTotalSupply.MulTruncate(depositCoinA.Amount.ToDec()).QuoTruncate(lastReserveCoinA.Amount.ToDec()),
257+
poolCoinTotalSupply.MulTruncate(depositCoinB.Amount.ToDec()).QuoTruncate(lastReserveCoinB.Amount.ToDec()),
258+
)
259+
mintRate := poolCoinMintAmt.TruncateDec().QuoTruncate(poolCoinTotalSupply)
260+
acceptedCoins := sdk.NewCoins(
261+
sdk.NewCoin(depositCoins[0].Denom, lastReserveCoinA.Amount.ToDec().Mul(mintRate).TruncateInt()),
262+
sdk.NewCoin(depositCoins[1].Denom, lastReserveCoinB.Amount.ToDec().Mul(mintRate).TruncateInt()),
263+
)
264+
refundedCoins := depositCoins.Sub(acceptedCoins)
265+
refundedCoinA := sdk.NewCoin(depositCoinA.Denom, refundedCoins.AmountOf(depositCoinA.Denom))
266+
refundedCoinB := sdk.NewCoin(depositCoinB.Denom, refundedCoins.AmountOf(depositCoinB.Denom))
300267

301-
// calculate pool token mint amount
302-
poolCoinTotalSupply := k.GetPoolCoinTotalSupply(ctx, pool)
303-
poolCoinAmt := sdk.MinInt(
304-
poolCoinTotalSupply.ToDec().MulTruncate(depositCoinAmountA.ToDec()).QuoTruncate(reserveCoins[0].Amount.ToDec()).TruncateInt(),
305-
poolCoinTotalSupply.ToDec().MulTruncate(depositCoinAmountB.ToDec()).QuoTruncate(reserveCoins[1].Amount.ToDec()).TruncateInt())
306-
mintPoolCoin := sdk.NewCoin(pool.PoolCoinDenom, poolCoinAmt)
268+
mintPoolCoin := sdk.NewCoin(pool.PoolCoinDenom, poolCoinMintAmt.TruncateInt())
307269
mintPoolCoins := sdk.NewCoins(mintPoolCoin)
308270

309-
// mint pool token to the depositor
271+
if mintPoolCoins.IsZero() || acceptedCoins.IsZero() {
272+
return fmt.Errorf("pool coin truncated, no accepted coin, refund")
273+
}
274+
310275
if err := k.bankKeeper.MintCoins(ctx, types.ModuleName, mintPoolCoins); err != nil {
311276
return err
312277
}
313278

279+
var inputs []banktypes.Input
280+
var outputs []banktypes.Output
281+
282+
if !refundedCoins.IsZero() {
283+
// refund truncated deposit coins
284+
inputs = append(inputs, banktypes.NewInput(batchEscrowAcc, refundedCoins))
285+
outputs = append(outputs, banktypes.NewOutput(depositor, refundedCoins))
286+
}
287+
288+
// send accepted deposit coins
289+
inputs = append(inputs, banktypes.NewInput(batchEscrowAcc, acceptedCoins))
290+
outputs = append(outputs, banktypes.NewOutput(reserveAcc, acceptedCoins))
291+
292+
// send minted pool coins
314293
inputs = append(inputs, banktypes.NewInput(batchEscrowAcc, mintPoolCoins))
315294
outputs = append(outputs, banktypes.NewOutput(depositor, mintPoolCoins))
316295

@@ -328,10 +307,10 @@ func (k Keeper) ExecuteDeposit(ctx sdk.Context, msg types.DepositMsgState, batch
328307
afterReserveCoinA := afterReserveCoins[0].Amount
329308
afterReserveCoinB := afterReserveCoins[1].Amount
330309

331-
MintingPoolCoinsInvariant(poolCoinTotalSupply, mintPoolCoin.Amount, depositCoinA.Amount, depositCoinB.Amount,
332-
lastReserveCoinA, lastReserveCoinB, refundedCoinA, refundedCoinB)
333-
DepositInvariant(lastReserveCoinA, lastReserveCoinB, depositCoinA.Amount, depositCoinB.Amount,
334-
afterReserveCoinA, afterReserveCoinB, refundedCoinA, refundedCoinB)
310+
MintingPoolCoinsInvariant(poolCoinTotalSupply.TruncateInt(), mintPoolCoin.Amount, depositCoinA.Amount, depositCoinB.Amount,
311+
lastReserveCoinA.Amount, lastReserveCoinB.Amount, refundedCoinA.Amount, refundedCoinB.Amount)
312+
DepositInvariant(lastReserveCoinA.Amount, lastReserveCoinB.Amount, depositCoinA.Amount, depositCoinB.Amount,
313+
afterReserveCoinA, afterReserveCoinB, refundedCoinA.Amount, refundedCoinB.Amount)
335314
}
336315

337316
ctx.EventManager().EmitEvent(
@@ -350,7 +329,7 @@ func (k Keeper) ExecuteDeposit(ctx sdk.Context, msg types.DepositMsgState, batch
350329
)
351330

352331
reserveCoins = k.GetReserveCoins(ctx, pool)
353-
lastReserveRatio = sdk.NewDecFromInt(reserveCoins[0].Amount).Quo(sdk.NewDecFromInt(reserveCoins[1].Amount))
332+
lastReserveRatio := sdk.NewDecFromInt(reserveCoins[0].Amount).Quo(sdk.NewDecFromInt(reserveCoins[1].Amount))
354333

355334
logger := k.Logger(ctx)
356335
logger.Debug(
@@ -405,6 +384,12 @@ func (k Keeper) ExecuteWithdrawal(ctx sdk.Context, msg types.WithdrawMsgState, b
405384
} else {
406385
// Calculate withdraw amount of respective reserve coin considering fees and pool coin's totally supply
407386
for _, reserveCoin := range reserveCoins {
387+
if err := types.CheckOverflow(reserveCoin.Amount, msg.Msg.PoolCoin.Amount); err != nil {
388+
return err
389+
}
390+
if err := types.CheckOverflow(reserveCoin.Amount.Mul(msg.Msg.PoolCoin.Amount).ToDec().TruncateInt(), poolCoinTotalSupply); err != nil {
391+
return err
392+
}
408393
// WithdrawAmount = ReserveAmount * PoolCoinAmount * WithdrawFeeProportion / TotalSupply
409394
withdrawAmtWithFee := reserveCoin.Amount.Mul(msg.Msg.PoolCoin.Amount).ToDec().TruncateInt().Quo(poolCoinTotalSupply)
410395
withdrawAmt := reserveCoin.Amount.Mul(msg.Msg.PoolCoin.Amount).ToDec().MulTruncate(withdrawProportion).TruncateInt().Quo(poolCoinTotalSupply)
@@ -797,21 +782,12 @@ func (k Keeper) ValidateMsgWithdrawWithinBatch(ctx sdk.Context, msg types.MsgWit
797782
}
798783

799784
// ValidateMsgSwapWithinBatch validates MsgSwapWithinBatch.
800-
func (k Keeper) ValidateMsgSwapWithinBatch(ctx sdk.Context, msg types.MsgSwapWithinBatch) error {
801-
pool, found := k.GetPool(ctx, msg.PoolId)
802-
if !found {
803-
return types.ErrPoolNotExists
804-
}
805-
785+
func (k Keeper) ValidateMsgSwapWithinBatch(ctx sdk.Context, msg types.MsgSwapWithinBatch, pool types.Pool) error {
806786
denomA, denomB := types.AlphabeticalDenomPair(msg.OfferCoin.Denom, msg.DemandCoinDenom)
807787
if denomA != pool.ReserveCoinDenoms[0] || denomB != pool.ReserveCoinDenoms[1] {
808788
return types.ErrNotMatchedReserveCoin
809789
}
810790

811-
if k.IsDepletedPool(ctx, pool) {
812-
return types.ErrDepletedPool
813-
}
814-
815791
params := k.GetParams(ctx)
816792

817793
// can not exceed max order ratio of reserve coins that can be ordered at a order
@@ -827,6 +803,10 @@ func (k Keeper) ValidateMsgSwapWithinBatch(ctx sdk.Context, msg types.MsgSwapWit
827803
return types.ErrBadOfferCoinFee
828804
}
829805

806+
if err := types.CheckOverflowWithDec(msg.OfferCoin.Amount.ToDec(), msg.OrderPrice); err != nil {
807+
return err
808+
}
809+
830810
if !msg.OfferCoinFee.Equal(types.GetOfferCoinFee(msg.OfferCoin, params.SwapFeeRate)) {
831811
return types.ErrBadOfferCoinFee
832812
}

0 commit comments

Comments
 (0)