-
Notifications
You must be signed in to change notification settings - Fork 39
/
msg_server.go
155 lines (129 loc) · 4.35 KB
/
msg_server.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
package keeper
import (
"context"
sdk "github.com/cosmos/cosmos-sdk/types"
core "github.com/classic-terra/core/types"
"github.com/classic-terra/core/x/market/types"
oracletypes "github.com/classic-terra/core/x/oracle/types"
)
type msgServer struct {
Keeper
}
// NewMsgServerImpl returns an implementation of the market MsgServer interface
// for the provided Keeper.
func NewMsgServerImpl(keeper Keeper) types.MsgServer {
return &msgServer{Keeper: keeper}
}
var _ types.MsgServer = msgServer{}
func (k msgServer) Swap(goCtx context.Context, msg *types.MsgSwap) (*types.MsgSwapResponse, error) {
ctx := sdk.UnwrapSDKContext(goCtx)
addr, err := sdk.AccAddressFromBech32(msg.Trader)
if err != nil {
return nil, err
}
return k.handleSwapRequest(ctx, addr, addr, msg.OfferCoin, msg.AskDenom)
}
func (k msgServer) SwapSend(goCtx context.Context, msg *types.MsgSwapSend) (*types.MsgSwapSendResponse, error) {
ctx := sdk.UnwrapSDKContext(goCtx)
fromAddr, err := sdk.AccAddressFromBech32(msg.FromAddress)
if err != nil {
return nil, err
}
toAddr, err := sdk.AccAddressFromBech32(msg.ToAddress)
if err != nil {
return nil, err
}
res, err := k.handleSwapRequest(ctx, fromAddr, toAddr, msg.OfferCoin, msg.AskDenom)
if err != nil {
return nil, err
}
return &types.MsgSwapSendResponse{
SwapCoin: res.SwapCoin,
SwapFee: res.SwapFee,
}, nil
}
// handleMsgSwap handles the logic of a MsgSwap
// This function does not repeat checks that have already been performed in msg.ValidateBasic()
// Ex) assert(offerCoin.Denom != askDenom)
func (k msgServer) handleSwapRequest(ctx sdk.Context,
trader sdk.AccAddress, receiver sdk.AccAddress,
offerCoin sdk.Coin, askDenom string,
) (*types.MsgSwapResponse, error) {
// Compute exchange rates between the ask and offer
swapDecCoin, spread, err := k.ComputeSwap(ctx, offerCoin, askDenom)
if err != nil {
return nil, err
}
// Charge a spread if applicable; the spread is burned
var feeDecCoin sdk.DecCoin
if spread.IsPositive() {
feeDecCoin = sdk.NewDecCoinFromDec(swapDecCoin.Denom, spread.Mul(swapDecCoin.Amount))
} else {
feeDecCoin = sdk.NewDecCoin(swapDecCoin.Denom, sdk.ZeroInt())
}
// Subtract fee from the swap coin
swapDecCoin.Amount = swapDecCoin.Amount.Sub(feeDecCoin.Amount)
// Update pool delta
err = k.ApplySwapToPool(ctx, offerCoin, swapDecCoin)
if err != nil {
return nil, err
}
// Send offer coins to module account
offerCoins := sdk.NewCoins(offerCoin)
err = k.BankKeeper.SendCoinsFromAccountToModule(ctx, trader, types.ModuleName, offerCoins)
if err != nil {
return nil, err
}
// Burn offered coins and subtract from the trader's account
err = k.BankKeeper.BurnCoins(ctx, types.ModuleName, offerCoins)
if err != nil {
return nil, err
}
// Mint asked coins and credit Trader's account
swapCoin, decimalCoin := swapDecCoin.TruncateDecimal()
// Ensure to fail the swap tx when zero swap coin
if ctx.ChainID() == core.ColumbusChainID && ctx.BlockHeight() >= core.SwapDisableForkHeight {
if !swapCoin.IsPositive() {
return nil, types.ErrZeroSwapCoin
}
}
feeDecCoin = feeDecCoin.Add(decimalCoin) // add truncated decimalCoin to swapFee
feeCoin, _ := feeDecCoin.TruncateDecimal()
mintCoins := sdk.NewCoins(swapCoin.Add(feeCoin))
err = k.BankKeeper.MintCoins(ctx, types.ModuleName, mintCoins)
if err != nil {
return nil, err
}
// Send swap coin to the trader
swapCoins := sdk.NewCoins(swapCoin)
err = k.BankKeeper.SendCoinsFromModuleToAccount(ctx, types.ModuleName, receiver, swapCoins)
if err != nil {
return nil, err
}
// Send swap fee to oracle account
if feeCoin.IsPositive() {
feeCoins := sdk.NewCoins(feeCoin)
err = k.BankKeeper.SendCoinsFromModuleToModule(ctx, types.ModuleName, oracletypes.ModuleName, feeCoins)
if err != nil {
return nil, err
}
}
ctx.EventManager().EmitEvents(sdk.Events{
sdk.NewEvent(
types.EventSwap,
sdk.NewAttribute(types.AttributeKeyOffer, offerCoin.String()),
sdk.NewAttribute(types.AttributeKeyTrader, trader.String()),
sdk.NewAttribute(types.AttributeKeyRecipient, receiver.String()),
sdk.NewAttribute(types.AttributeKeySwapCoin, swapCoin.String()),
sdk.NewAttribute(types.AttributeKeySwapFee, feeCoin.String()),
),
sdk.NewEvent(
sdk.EventTypeMessage,
sdk.NewAttribute(sdk.AttributeKeyModule, types.AttributeValueCategory),
),
})
return &types.MsgSwapResponse{
SwapCoin: swapCoin,
SwapFee: feeCoin,
}, nil
}