/
msg_server_take_swap.go
106 lines (88 loc) · 3.15 KB
/
msg_server_take_swap.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
package keeper
import (
"context"
"errors"
sdk "github.com/cosmos/cosmos-sdk/types"
"github.com/sideprotocol/ibcswap/v6/modules/apps/100-atomic-swap/types"
)
// TakeSwap is the step 5 (Lock Order & Lock Token) of the atomic swap: https://github.com/liangping/ibc/blob/atomic-swap/spec/app/ics-100-atomic-swap/ibcswap.png
// This method lock the order (set a value to the field "Taker") and lock Token
func (k Keeper) TakeSwap(goCtx context.Context, msg *types.TakeSwapMsg) (*types.MsgTakeSwapResponse, error) {
ctx := sdk.UnwrapSDKContext(goCtx)
// pre-check
if err := msg.ValidateBasic(); err != nil {
return nil, err
}
msgByte, err0 := types.ModuleCdc.MarshalJSON(msg)
if err0 != nil {
return nil, err0
}
order, ok := k.GetAtomicOrder(ctx, msg.OrderId)
if !ok {
return nil, types.ErrOrderDoesNotExists
}
sourceChannel := extractSourceChannelForTakerMsg(order.Path)
sourcePort := extractSourcePortForTakerMsg(order.Path)
escrowAddr := types.GetEscrowAddress(sourcePort, sourceChannel)
if order.Status != types.Status_SYNC && order.Status != types.Status_INITIAL {
return nil, errors.New("order is not in valid state")
}
// Make sure the maker's buy token matches the taker's sell token
if order.Maker.BuyToken.Denom != msg.SellToken.Denom && !order.Maker.BuyToken.Amount.Equal(msg.SellToken.Amount) {
return &types.MsgTakeSwapResponse{}, errors.New("invalid sell token")
}
// Checks if the order has already been taken
if order.Takers != nil {
return &types.MsgTakeSwapResponse{}, errors.New("order has already been taken")
}
// If `desiredTaker` is set, only the desiredTaker can accept the order.
if order.Maker.DesiredTaker != "" && order.Maker.DesiredTaker != msg.TakerAddress {
return &types.MsgTakeSwapResponse{}, errors.New("invalid taker address")
}
takerAddr, err := sdk.AccAddressFromBech32(msg.TakerAddress)
if err != nil {
return &types.MsgTakeSwapResponse{}, err
}
_, err = sdk.AccAddressFromBech32(msg.TakerReceivingAddress)
if err == nil {
return &types.MsgTakeSwapResponse{}, types.ErrFailedMakeSwap
}
balance := k.bankKeeper.GetBalance(ctx, takerAddr, msg.SellToken.Denom)
if balance.Amount.LT(msg.SellToken.Amount) {
return &types.MsgTakeSwapResponse{}, errors.New("insufficient balance")
}
// Locks the sellToken to the escrow account
if err = k.bankKeeper.SendCoins(ctx, takerAddr, escrowAddr, sdk.NewCoins(msg.SellToken)); err != nil {
return &types.MsgTakeSwapResponse{}, err
}
packet := types.AtomicSwapPacketData{
Type: types.TAKE_SWAP,
Data: msgByte,
Memo: "",
}
if _, err := k.SendSwapPacket(ctx, sourcePort, sourceChannel, msg.TimeoutHeight, msg.TimeoutTimestamp, packet); err != nil {
return nil, err
}
// Update order state
// Mark that the order has been occupied
order.Takers = msg
k.SetAtomicOrder(ctx, order)
ctx.EventManager().EmitEvent(
sdk.NewEvent(
types.ModuleName,
sdk.Attribute{
Key: types.AttributeAction,
Value: types.EventValueActionTakeOrder,
},
sdk.Attribute{
Key: types.AttributeOrderId,
Value: order.Id,
},
sdk.Attribute{
Key: types.AttributeName,
Value: types.EventOwner,
},
),
)
return &types.MsgTakeSwapResponse{}, nil
}