Skip to content

Commit

Permalink
Merge 2854273 into 92dd741
Browse files Browse the repository at this point in the history
  • Loading branch information
dongsam committed Apr 13, 2021
2 parents 92dd741 + 2854273 commit e371af1
Show file tree
Hide file tree
Showing 8 changed files with 168 additions and 391 deletions.
7 changes: 0 additions & 7 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -81,13 +81,6 @@ endif
build-linux: go.sum
LEDGER_ENABLED=false GOOS=linux GOARCH=amd64 $(MAKE) build

build-contract-tests-hooks:
ifeq ($(OS),Windows_NT)
go build -mod=readonly $(BUILD_FLAGS) -o build/contract_tests.exe ./cmd/contract_tests
else
go build -mod=readonly $(BUILD_FLAGS) -o build/contract_tests ./cmd/contract_tests
endif

install: go.sum
go install $(BUILD_FLAGS) ./cmd/liquidityd

Expand Down
16 changes: 8 additions & 8 deletions x/liquidity/keeper/invariants.go
Original file line number Diff line number Diff line change
Expand Up @@ -197,20 +197,20 @@ func ImmutablePoolPriceAfterWithdrawInvariant(reserveCoinA, reserveCoinB, withdr
}

// SwapMatchingInvariants checks swap matching results of both X to Y and Y to X cases.
func SwapMatchingInvariants(XtoY, YtoX []*types.SwapMsgState, fractionalCntX, fractionalCntY int, matchResultXtoY, matchResultYtoX []types.MatchResult) {
func SwapMatchingInvariants(XtoY, YtoX []*types.SwapMsgState, matchResultXtoY, matchResultYtoX []types.MatchResult) {
beforeMatchingXtoYLen := len(XtoY)
beforeMatchingYtoXLen := len(YtoX)
afterMatchingXtoYLen := len(matchResultXtoY)
afterMatchingYtoXLen := len(matchResultYtoX)

totalMatchingXtoYLen := beforeMatchingXtoYLen - afterMatchingXtoYLen + fractionalCntX
totalMatchingYtoXLen := beforeMatchingYtoXLen - afterMatchingYtoXLen + fractionalCntY
notMatchedXtoYLen := beforeMatchingXtoYLen - afterMatchingXtoYLen
notMatchedYtoXLen := beforeMatchingYtoXLen - afterMatchingYtoXLen

if totalMatchingXtoYLen != types.CountNotMatchedMsgs(XtoY)+types.CountFractionalMatchedMsgs(XtoY) {
if notMatchedXtoYLen != types.CountNotMatchedMsgs(XtoY) {
panic("invariant check fails due to invalid XtoY match length")
}

if totalMatchingYtoXLen != types.CountNotMatchedMsgs(YtoX)+types.CountFractionalMatchedMsgs(YtoX) {
if notMatchedYtoXLen != types.CountNotMatchedMsgs(YtoX) {
panic("invariant check fails due to invalid YtoX match length")
}
}
Expand Down Expand Up @@ -274,7 +274,7 @@ func SwapMsgStatesInvariants(matchResultXtoY, matchResultYtoX []types.MatchResul
}

for k, v := range matchResultMap {
if k != v.OrderMsgIndex {
if k != v.SwapMsgState.MsgIndex {
panic("broken map consistency")
}
}
Expand All @@ -301,8 +301,8 @@ func SwapMsgStatesInvariants(matchResultXtoY, matchResultYtoX []types.MatchResul
}

if msgAfter, ok := matchResultMap[sms.MsgIndex]; ok {
if sms.MsgIndex == msgAfter.BatchMsg.MsgIndex {
if *(sms) != *(msgAfter.BatchMsg) || sms != msgAfter.BatchMsg {
if sms.MsgIndex == msgAfter.SwapMsgState.MsgIndex {
if *(sms) != *(msgAfter.SwapMsgState) || sms != msgAfter.SwapMsgState {
panic("batch message not matched")
} else {
break
Expand Down
229 changes: 50 additions & 179 deletions x/liquidity/keeper/liquidity_pool.go
Original file line number Diff line number Diff line change
Expand Up @@ -399,7 +399,7 @@ func (k Keeper) WithdrawLiquidityPool(ctx sdk.Context, msg types.WithdrawMsgStat

// burn the escrowed pool coins
if err := k.bankKeeper.BurnCoins(ctx, types.ModuleName, poolCoins); err != nil {
panic(err)
return err
}

msg.Succeeded = true
Expand Down Expand Up @@ -589,177 +589,70 @@ func (k Keeper) TransactAndRefundSwapLiquidityPool(ctx sdk.Context, swapMsgState
if !found {
return types.ErrPoolBatchNotExists
}
sendCoin := func(from, to sdk.AccAddress, coin sdk.Coin) {
coins := sdk.NewCoins(coin)
if !coins.Empty() && coins.IsValid() {
inputs = append(inputs, banktypes.NewInput(from, coins))
outputs = append(outputs, banktypes.NewOutput(to, coins))
}
}
for _, sms := range swapMsgStates {
if pool.Id != sms.Msg.PoolId {
return fmt.Errorf("broken msg pool consistency")
}
if !sms.Executed && sms.Succeeded {
panic("can't refund not executed with succeed msg")
return fmt.Errorf("can't refund not executed with succeed msg")
}
if pool.Id != sms.Msg.PoolId {
panic("broken msg pool consistency")
if sms.RemainingOfferCoin.IsNegative() {
return fmt.Errorf("negative RemainingOfferCoin")
} else if sms.RemainingOfferCoin.IsPositive() &&
((!sms.ToBeDeleted && sms.OrderExpiryHeight <= ctx.BlockHeight()) ||
(sms.ToBeDeleted && sms.OrderExpiryHeight != ctx.BlockHeight())) {
return fmt.Errorf("consistency of OrderExpiryHeight and ToBeDeleted flag is broken")
}

// Full matched, fractional matched
if msgAfter, ok := matchResultMap[sms.MsgIndex]; ok {
if sms.MsgIndex != msgAfter.OrderMsgIndex {
panic("broken msg consistency")
}
if match, ok := matchResultMap[sms.MsgIndex]; ok {
sendCoin(batchEscrowAcc, poolReserveAcc, sdk.NewCoin(sms.Msg.OfferCoin.Denom, match.TransactedCoinAmt.TruncateInt()))
sendCoin(poolReserveAcc, sms.Msg.GetSwapRequester(), sdk.NewCoin(
sms.Msg.DemandCoinDenom, match.ExchangedDemandCoinAmt.Sub(match.ExchangedCoinFeeAmt).TruncateInt()))
sendCoin(batchEscrowAcc, poolReserveAcc, sdk.NewCoin(sms.Msg.OfferCoin.Denom, match.OfferCoinFeeAmt.TruncateInt()))

if (*msgAfter.BatchMsg) != (*sms) {
panic("broken msg consistency")
if sms.RemainingOfferCoin.IsPositive() && sms.OrderExpiryHeight == ctx.BlockHeight() {
sendCoin(batchEscrowAcc, sms.Msg.GetSwapRequester(), sms.RemainingOfferCoin.Add(sms.ReservedOfferCoinFee))
}

// Fractional match, but expired order case
if sms.RemainingOfferCoin.IsPositive() {
// Not to delete, but expired case
if !sms.ToBeDeleted && sms.OrderExpiryHeight <= ctx.BlockHeight() {
panic("Consistency of OrderExpiryHeight and ToBeDeleted is broken.")
} else if !sms.ToBeDeleted && sms.OrderExpiryHeight > ctx.BlockHeight() {
// Fractional matched, to be remaining order, not refund, only transact fractional exchange amt
// Add transacted coins to multisend
inputs = append(inputs, banktypes.NewInput(batchEscrowAcc,
sdk.NewCoins(sdk.NewCoin(sms.ExchangedOfferCoin.Denom, msgAfter.TransactedCoinAmt.TruncateInt()))))
outputs = append(outputs, banktypes.NewOutput(poolReserveAcc,
sdk.NewCoins(sdk.NewCoin(sms.ExchangedOfferCoin.Denom, msgAfter.TransactedCoinAmt.TruncateInt()))))
inputs = append(inputs, banktypes.NewInput(poolReserveAcc,
sdk.NewCoins(sdk.NewCoin(sms.Msg.DemandCoinDenom, msgAfter.ExchangedDemandCoinAmt.Sub(msgAfter.ExchangedCoinFeeAmt).TruncateInt()))))
outputs = append(outputs, banktypes.NewOutput(sms.Msg.GetSwapRequester(),
sdk.NewCoins(sdk.NewCoin(sms.Msg.DemandCoinDenom, msgAfter.ExchangedDemandCoinAmt.Sub(msgAfter.ExchangedCoinFeeAmt).TruncateInt()))))

// Add swap offer coin fee to multisend
inputs = append(inputs, banktypes.NewInput(batchEscrowAcc,
sdk.NewCoins(sdk.NewCoin(sms.ReservedOfferCoinFee.Denom, msgAfter.OfferCoinFeeAmt.TruncateInt()))))
outputs = append(outputs, banktypes.NewOutput(poolReserveAcc,
sdk.NewCoins(sdk.NewCoin(sms.ReservedOfferCoinFee.Denom, msgAfter.OfferCoinFeeAmt.TruncateInt()))))

sms.Succeeded = true

} else if sms.ToBeDeleted || sms.OrderExpiryHeight == ctx.BlockHeight() {
// Fractional matched, but expired order, transact with refund remaining offer coin
// Add transacted coins to multisend
inputs = append(inputs, banktypes.NewInput(batchEscrowAcc,
sdk.NewCoins(sdk.NewCoin(sms.ExchangedOfferCoin.Denom, msgAfter.TransactedCoinAmt.TruncateInt()))))
outputs = append(outputs, banktypes.NewOutput(poolReserveAcc,
sdk.NewCoins(sdk.NewCoin(sms.ExchangedOfferCoin.Denom, msgAfter.TransactedCoinAmt.TruncateInt()))))
inputs = append(inputs, banktypes.NewInput(poolReserveAcc,
sdk.NewCoins(sdk.NewCoin(sms.Msg.DemandCoinDenom, msgAfter.ExchangedDemandCoinAmt.Sub(msgAfter.ExchangedCoinFeeAmt).TruncateInt()))))
outputs = append(outputs, banktypes.NewOutput(sms.Msg.GetSwapRequester(),
sdk.NewCoins(sdk.NewCoin(sms.Msg.DemandCoinDenom, msgAfter.ExchangedDemandCoinAmt.Sub(msgAfter.ExchangedCoinFeeAmt).TruncateInt()))))

// Add swap offer coin fee to multisend
inputs = append(inputs, banktypes.NewInput(batchEscrowAcc,
sdk.NewCoins(sdk.NewCoin(sms.ReservedOfferCoinFee.Denom, msgAfter.OfferCoinFeeAmt.TruncateInt()))))
outputs = append(outputs, banktypes.NewOutput(poolReserveAcc,
sdk.NewCoins(sdk.NewCoin(sms.ReservedOfferCoinFee.Denom, msgAfter.OfferCoinFeeAmt.TruncateInt()))))

// Refund remaining OfferCoin, ReservedOfferCoinFee
if input, output, err := k.ReleaseEscrowForMultiSend(sms.Msg.GetSwapRequester(),
sdk.NewCoins(sms.RemainingOfferCoin.Add(sms.ReservedOfferCoinFee))); err != nil {
panic(err)
} else {
inputs = append(inputs, input)
outputs = append(outputs, output)
}

sms.Succeeded = true
sms.ToBeDeleted = true
} else {
panic("Consistency of OrderExpiryHeight and ToBeDeleted is broken.")
}
} else if sms.RemainingOfferCoin.IsZero() {
// Full matched case, Add transacted coins to multisend
inputs = append(inputs, banktypes.NewInput(batchEscrowAcc,
sdk.NewCoins(sdk.NewCoin(sms.ExchangedOfferCoin.Denom, msgAfter.TransactedCoinAmt.TruncateInt()))))
outputs = append(outputs, banktypes.NewOutput(poolReserveAcc,
sdk.NewCoins(sdk.NewCoin(sms.ExchangedOfferCoin.Denom, msgAfter.TransactedCoinAmt.TruncateInt()))))
inputs = append(inputs, banktypes.NewInput(poolReserveAcc,
sdk.NewCoins(sdk.NewCoin(sms.Msg.DemandCoinDenom, msgAfter.ExchangedDemandCoinAmt.Sub(msgAfter.ExchangedCoinFeeAmt).TruncateInt()))))
outputs = append(outputs, banktypes.NewOutput(sms.Msg.GetSwapRequester(),
sdk.NewCoins(sdk.NewCoin(sms.Msg.DemandCoinDenom, msgAfter.ExchangedDemandCoinAmt.Sub(msgAfter.ExchangedCoinFeeAmt).TruncateInt()))))

// Add swap offer coin fee to multisend
inputs = append(inputs, banktypes.NewInput(batchEscrowAcc,
sdk.NewCoins(sdk.NewCoin(sms.ReservedOfferCoinFee.Denom, msgAfter.OfferCoinFeeAmt.TruncateInt()))))
outputs = append(outputs, banktypes.NewOutput(poolReserveAcc,
sdk.NewCoins(sdk.NewCoin(sms.ReservedOfferCoinFee.Denom, msgAfter.OfferCoinFeeAmt.TruncateInt()))))

sms.Succeeded = true
sms.Succeeded = true
if sms.RemainingOfferCoin.IsZero() {
sms.ToBeDeleted = true
} else {
panic("Negative RemainingOfferCoin.")
}

ctx.EventManager().EmitEvent(
sdk.NewEvent(
types.EventTypeSwapTransacted,
sdk.NewAttribute(types.AttributeValuePoolId, strconv.FormatUint(pool.Id, 10)),
sdk.NewAttribute(types.AttributeValueBatchIndex, strconv.FormatUint(batch.Index, 10)),
sdk.NewAttribute(types.AttributeValueMsgIndex, strconv.FormatUint(msgAfter.BatchMsg.MsgIndex, 10)),
sdk.NewAttribute(types.AttributeValueSwapRequester, msgAfter.BatchMsg.Msg.GetSwapRequester().String()),
sdk.NewAttribute(types.AttributeValueSwapTypeId, strconv.FormatUint(uint64(msgAfter.BatchMsg.Msg.SwapTypeId), 10)),
sdk.NewAttribute(types.AttributeValueOfferCoinDenom, msgAfter.BatchMsg.Msg.OfferCoin.Denom),
sdk.NewAttribute(types.AttributeValueOfferCoinAmount, msgAfter.BatchMsg.Msg.OfferCoin.Amount.String()),
sdk.NewAttribute(types.AttributeValueOrderPrice, msgAfter.BatchMsg.Msg.OrderPrice.String()),
sdk.NewAttribute(types.AttributeValueMsgIndex, strconv.FormatUint(match.SwapMsgState.MsgIndex, 10)),
sdk.NewAttribute(types.AttributeValueSwapRequester, match.SwapMsgState.Msg.GetSwapRequester().String()),
sdk.NewAttribute(types.AttributeValueSwapTypeId, strconv.FormatUint(uint64(match.SwapMsgState.Msg.SwapTypeId), 10)),
sdk.NewAttribute(types.AttributeValueOfferCoinDenom, match.SwapMsgState.Msg.OfferCoin.Denom),
sdk.NewAttribute(types.AttributeValueOfferCoinAmount, match.SwapMsgState.Msg.OfferCoin.Amount.String()),
sdk.NewAttribute(types.AttributeValueOrderPrice, match.SwapMsgState.Msg.OrderPrice.String()),
sdk.NewAttribute(types.AttributeValueSwapPrice, batchResult.SwapPrice.String()),
sdk.NewAttribute(types.AttributeValueTransactedCoinAmount, msgAfter.TransactedCoinAmt.String()),
sdk.NewAttribute(types.AttributeValueRemainingOfferCoinAmount, msgAfter.BatchMsg.RemainingOfferCoin.Amount.String()),
sdk.NewAttribute(types.AttributeValueExchangedOfferCoinAmount, msgAfter.BatchMsg.ExchangedOfferCoin.Amount.String()),
sdk.NewAttribute(types.AttributeValueOfferCoinFeeAmount, msgAfter.OfferCoinFeeAmt.String()),
sdk.NewAttribute(types.AttributeValueReservedOfferCoinFeeAmount, msgAfter.BatchMsg.ReservedOfferCoinFee.Amount.String()),
sdk.NewAttribute(types.AttributeValueOrderExpiryHeight, strconv.FormatInt(msgAfter.OrderExpiryHeight, 10)),
sdk.NewAttribute(types.AttributeValueTransactedCoinAmount, match.TransactedCoinAmt.String()),
sdk.NewAttribute(types.AttributeValueRemainingOfferCoinAmount, match.SwapMsgState.RemainingOfferCoin.Amount.String()),
sdk.NewAttribute(types.AttributeValueExchangedOfferCoinAmount, match.SwapMsgState.ExchangedOfferCoin.Amount.String()),
sdk.NewAttribute(types.AttributeValueOfferCoinFeeAmount, match.OfferCoinFeeAmt.String()),
sdk.NewAttribute(types.AttributeValueReservedOfferCoinFeeAmount, match.SwapMsgState.ReservedOfferCoinFee.Amount.String()),
sdk.NewAttribute(types.AttributeValueOrderExpiryHeight, strconv.FormatInt(match.OrderExpiryHeight, 10)),
sdk.NewAttribute(types.AttributeValueSuccess, types.Success),
))
} else {
// Not matched, remaining
if !sms.ToBeDeleted && sms.OrderExpiryHeight > ctx.BlockHeight() {
// Have fractional matching history, not matched and expired, remaining refund
// Refund remaining coins
if input, output, err := k.ReleaseEscrowForMultiSend(sms.Msg.GetSwapRequester(),
sdk.NewCoins(sms.RemainingOfferCoin.Add(sms.ReservedOfferCoinFee))); err != nil {
panic(err)
} else {
inputs = append(inputs, input)
outputs = append(outputs, output)
}
sms.Succeeded = false
sms.ToBeDeleted = true
} else if sms.ToBeDeleted && sms.OrderExpiryHeight == ctx.BlockHeight() {
// Not matched and expired, Refund remaining coins
if input, output, err := k.ReleaseEscrowForMultiSend(sms.Msg.GetSwapRequester(),
sdk.NewCoins(sms.RemainingOfferCoin.Add(sms.ReservedOfferCoinFee))); err != nil {
panic(err)
} else {
inputs = append(inputs, input)
outputs = append(outputs, output)
}
sms.Succeeded = false
sms.ToBeDeleted = true
} else {
panic("Consistency of OrderExpiryHeight and ToBeDeleted is broken.")
}
}
}
// remove zero coins
newI := 0
for _, i := range inputs {
if !i.Coins.IsValid() {
i.Coins = sdk.NewCoins(i.Coins...) // for sanitizeCoins, remove zero coin
}
if !i.Coins.Empty() {
inputs[newI] = i
newI++
}
}
inputs = inputs[:newI]
newI = 0
for _, i := range outputs {
if !i.Coins.IsValid() {
i.Coins = sdk.NewCoins(i.Coins...) // for sanitizeCoins, remove zero coin
}
if !i.Coins.Empty() {
outputs[newI] = i
newI++
sendCoin(batchEscrowAcc, sms.Msg.GetSwapRequester(), sms.RemainingOfferCoin.Add(sms.ReservedOfferCoinFee))
sms.Succeeded = false
sms.ToBeDeleted = true
}
}
outputs = outputs[:newI]
if err := k.bankKeeper.InputOutputCoins(ctx, inputs, outputs); err != nil {
return err
}
Expand All @@ -770,42 +663,20 @@ func (k Keeper) TransactAndRefundSwapLiquidityPool(ctx sdk.Context, swapMsgState
func (k Keeper) RefundSwaps(ctx sdk.Context, pool types.Pool, swapMsgStates []*types.SwapMsgState) error {
var inputs []banktypes.Input
var outputs []banktypes.Output
sendCoin := func(from, to sdk.AccAddress, coin sdk.Coin) {
coins := sdk.NewCoins(coin)
if !coins.Empty() && coins.IsValid() {
inputs = append(inputs, banktypes.NewInput(from, coins))
outputs = append(outputs, banktypes.NewOutput(to, coins))
}
}
for _, sms := range swapMsgStates {
if sms.OrderExpiryHeight == ctx.BlockHeight() {
if input, output, err := k.ReleaseEscrowForMultiSend(sms.Msg.GetSwapRequester(),
sdk.NewCoins(sms.RemainingOfferCoin.Add(sms.ReservedOfferCoinFee))); err != nil {
panic(err)
} else {
inputs = append(inputs, input)
outputs = append(outputs, output)
}
sendCoin(k.accountKeeper.GetModuleAddress(types.ModuleName), sms.Msg.GetSwapRequester(), sms.RemainingOfferCoin.Add(sms.ReservedOfferCoinFee))
sms.Succeeded = false
sms.ToBeDeleted = true
}
}
// remove zero coins
newI := 0
for _, i := range inputs {
if !i.Coins.IsValid() {
i.Coins = sdk.NewCoins(i.Coins...) // for sanitizeCoins, remove zero coin
}
if !i.Coins.Empty() {
inputs[newI] = i
newI++
}
}
inputs = inputs[:newI]
newI = 0
for _, i := range outputs {
if !i.Coins.IsValid() {
i.Coins = sdk.NewCoins(i.Coins...) // for sanitizeCoins, remove zero coin
}
if !i.Coins.Empty() {
outputs[newI] = i
newI++
}
}
outputs = outputs[:newI]
if err := k.bankKeeper.InputOutputCoins(ctx, inputs, outputs); err != nil {
return err
}
Expand Down
Loading

0 comments on commit e371af1

Please sign in to comment.