Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix: fix the inflows sum adding when sender chain is source chain #2417

Merged
merged 11 commits into from
Feb 8, 2024
4 changes: 4 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,10 @@ Ref: https://keepachangelog.com/en/1.0.0/

- [2388](https://github.com/umee-network/umee/pull/2388) Adjust interest rate algorithm and associated token parameter validation rules.

### Bug Fixes

- [2417](https://github.com/umee-network/umee/pull/2417) Fix the ibc inflows storing of registered tokens when sender chain is source chain.

## v6.3.0 - 2024-01-03

### Improvements
Expand Down
43 changes: 29 additions & 14 deletions x/uibc/quota/intest/quota_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ import (
"github.com/golang/mock/gomock"
"gotest.tools/v3/assert"

appparams "github.com/umee-network/umee/v6/app/params"
lfixtures "github.com/umee-network/umee/v6/x/leverage/fixtures"
ltypes "github.com/umee-network/umee/v6/x/leverage/types"
"github.com/umee-network/umee/v6/x/oracle/types"
Expand Down Expand Up @@ -149,12 +150,14 @@ func TestKeeper_UndoUpdateQuota(t *testing.T) {
}

func TestKeeper_RecordIBCInflow(t *testing.T) {
atomAmount := sdkmath.NewInt(100_000000)
atomPrice := sdk.MustNewDecFromStr("0.37")
// ibc incoming denom from packet is `port/path/base_denom`
atomToken := sdk.NewCoin("transfer/channel-10/uatom", atomAmount)
atomExponent := 6
inflowBaseDenom := "ibc/D6372674F0E9A3A7ADC2FEFD8B2708C5008C7ED04DA6566E279DC1321BDDCB6F"
tokenAmount := sdkmath.NewInt(100_000000)
tokenPrice := sdk.MustNewDecFromStr("0.37")
tokenExponent := 6
// ibc denom = base_denom when sender chain is source chain
atomToken := sdk.NewCoin("uatom", tokenAmount)
// ibc denom = (port/channel/base_denom) when we receive token back which is send from UMEE
umeeNativeToken := sdk.NewCoin("transfer/channel-10/uumee", tokenAmount)
atomIBCDenom := "ibc/C4CFF46FD6DE35CA4CF4CE031E643C8FDC9BA4B99AE598E9B0ED98FE3A2319F9"

ctrl := gomock.NewController(t)
defer ctrl.Finish()
Expand All @@ -167,11 +170,16 @@ func TestKeeper_RecordIBCInflow(t *testing.T) {
err := k.ResetAllQuotas()
assert.NilError(t, err)

// ATOM, returns token settings and prices from mock leverage and oracle keepers, no errors expected
leverageMock.EXPECT().GetTokenSettings(ctx, inflowBaseDenom).Return(
lfixtures.Token(inflowBaseDenom, "ATOM", uint32(atomExponent)), nil,
// ATOM returns token settings and prices from mock leverage and oracle keepers, no errors expected
leverageMock.EXPECT().GetTokenSettings(ctx, atomIBCDenom).Return(
lfixtures.Token(atomIBCDenom, "ATOM", uint32(tokenExponent)), nil,
).AnyTimes()
oracleMock.EXPECT().Price(ctx, "ATOM").Return(atomPrice, nil).AnyTimes()
oracleMock.EXPECT().Price(ctx, "ATOM").Return(tokenPrice, nil).AnyTimes()
// UMEE
leverageMock.EXPECT().GetTokenSettings(ctx, appparams.BondDenom).Return(
lfixtures.Token(appparams.BondDenom, appparams.DisplayDenom, uint32(tokenExponent)), nil,
).AnyTimes()
oracleMock.EXPECT().Price(ctx, appparams.DisplayDenom).Return(tokenPrice, nil).AnyTimes()

packet := channeltypes.Packet{
Sequence: 10,
Expand All @@ -182,27 +190,34 @@ func TestKeeper_RecordIBCInflow(t *testing.T) {
Data: nil,
}

// A -> B (record if B is receiver chain)
ackErr := k.RecordIBCInflow(packet, atomToken.Denom, atomToken.Amount.String())
assert.Assert(t, nil, ackErr)
// A -> B (record if B is source chain, we are receiving token back which is send from A chain)
ackErr = k.RecordIBCInflow(packet, umeeNativeToken.Denom, umeeNativeToken.Amount.String())
assert.Assert(t, nil, ackErr)

o := k.GetTokenInflow(inflowBaseDenom)
o := k.GetTokenInflow(atomIBCDenom)
// expected inflow amount 37 =( atomPrice * atomAmount) / atomExponent
inflowAmount := sdkmath.LegacyMustNewDecFromStr("37")
assert.DeepEqual(t, o.Amount, inflowAmount)

ackErr = k.RecordIBCInflow(packet, atomToken.Denom, atomToken.Amount.String())
assert.Assert(t, nil, ackErr)

o = k.GetTokenInflow(inflowBaseDenom)
o = k.GetTokenInflow(atomIBCDenom)
assert.DeepEqual(t, o.Amount, inflowAmount.Add(inflowAmount))

p := k.GetTokenInflow(appparams.BondDenom)
assert.DeepEqual(t, p.Amount, inflowAmount)

allInflows, err := k.GetAllInflows()
assert.NilError(t, err)
assert.DeepEqual(t, allInflows, sdk.DecCoins{o})
assert.DeepEqual(t, allInflows, sdk.DecCoins{o, p})

err = k.ResetAllQuotas()
assert.NilError(t, err)

o = k.GetTokenInflow(inflowBaseDenom)
o = k.GetTokenInflow(atomIBCDenom)
assert.DeepEqual(t, o.Amount, sdk.ZeroDec())
}
68 changes: 41 additions & 27 deletions x/uibc/quota/quota.go
Original file line number Diff line number Diff line change
Expand Up @@ -231,39 +231,53 @@ func (k Keeper) UndoUpdateQuota(denom string, amount sdkmath.Int) error {
// RecordIBCInflow will save the inflow amount if token is registered otherwise it will skip
func (k Keeper) RecordIBCInflow(packet channeltypes.Packet, denom, amount string,
) exported.Acknowledgement {
// if chain is recevier and sender chain is source then we need create ibc_denom (ibc/hash(channel,denom)) to
// check ibc_denom is exists in leverage token registry
if !ics20types.SenderChainIsSource(packet.GetSourcePort(), packet.GetSourceChannel(), denom) {
// since SendPacket did not prefix the denomination, we must prefix denomination here
// if chain is recevier and sender chain is source then we need create ibc_denom (ibc/hash(channel,denom)).
if ics20types.SenderChainIsSource(packet.GetSourcePort(), packet.GetSourceChannel(), denom) {
gsk967 marked this conversation as resolved.
Show resolved Hide resolved
gsk967 marked this conversation as resolved.
Show resolved Hide resolved
// SendPacket did not prefix the denom, so we must prefix denom here
// NOTE: sourcePrefix already contains the trailing "/"
sourcePrefix := ics20types.GetDenomPrefix(packet.GetDestPort(), packet.GetDestChannel())
gsk967 marked this conversation as resolved.
Show resolved Hide resolved
// NOTE: sourcePrefix contains the trailing "/"
prefixedDenom := sourcePrefix + denom
// construct the denomination trace from the full raw denomination and get the ibc_denom
ibcDenom := ics20types.ParseDenomTrace(prefixedDenom).IBCDenom()
ts, err := k.leverage.GetTokenSettings(*k.ctx, ibcDenom)
if err != nil {
if ltypes.ErrNotRegisteredToken.Is(err) {
return nil // skip recording inflow if the token is not registered
}
k.ctx.Logger().Error("can't get x/leverage token settings", "error", err)
return channeltypes.NewErrorAcknowledgement(err)
denom = ics20types.ParseDenomTrace(prefixedDenom).IBCDenom()
} else {
// if we receive back a token, that was originally sent from UMEE, then we need to fetch the native denom
// receive denom(port/channel/base_denom) to base_denom

// remove prefix added by the sender chain
voucherPrefix := ics20types.GetDenomPrefix(packet.GetSourcePort(), packet.GetSourceChannel())
unprefixedDenom := denom[len(voucherPrefix):]
// coin denomination used in sending from the escrow address
denom = unprefixedDenom
// The denomination used to send the coins is either the native denom or the hash of the path
// if the denomination is not native.
denomTrace := ics20types.ParseDenomTrace(unprefixedDenom)
if !denomTrace.IsNativeDenom() {
denom = denomTrace.IBCDenom()
}
}

// get the exchange price (eg: UMEE) in USD from oracle using SYMBOL Denom eg: `UMEE`
exchangeRate, err := k.oracle.Price(*k.ctx, strings.ToUpper(ts.SymbolDenom))
if err != nil {
return channeltypes.NewErrorAcknowledgement(err)
ts, err := k.leverage.GetTokenSettings(*k.ctx, denom)
if err != nil {
if ltypes.ErrNotRegisteredToken.Is(err) {
return nil // skip recording inflow if the token is not registered
}
// calculate total exchange rate
powerReduction := ten.Power(uint64(ts.Exponent))
inflowInUSD := sdk.MustNewDecFromStr(amount).Quo(powerReduction).Mul(exchangeRate)

tokenInflow := k.GetTokenInflow(ibcDenom)
tokenInflow.Amount = tokenInflow.Amount.Add(inflowInUSD)
k.SetTokenInflow(tokenInflow)
totalInflowSum := k.GetInflowSum()
k.SetInflowSum(totalInflowSum.Add(inflowInUSD))
k.ctx.Logger().Error("can't get x/leverage token settings", "error", err)
return channeltypes.NewErrorAcknowledgement(err)
}

// get the exchange price (eg: UMEE) in USD from oracle using SYMBOL Denom eg: `UMEE`
exchangeRate, err := k.oracle.Price(*k.ctx, strings.ToUpper(ts.SymbolDenom))
if err != nil {
return channeltypes.NewErrorAcknowledgement(err)
}
// calculate total exchange rate
powerReduction := ten.Power(uint64(ts.Exponent))
inflowInUSD := sdk.MustNewDecFromStr(amount).Quo(powerReduction).Mul(exchangeRate)

tokenInflow := k.GetTokenInflow(denom)
tokenInflow.Amount = tokenInflow.Amount.Add(inflowInUSD)
k.SetTokenInflow(tokenInflow)
totalInflowSum := k.GetInflowSum()
k.SetInflowSum(totalInflowSum.Add(inflowInUSD))

return nil
}
Loading