This repository has been archived by the owner on Dec 29, 2022. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 8
/
handler.go
142 lines (132 loc) · 4.54 KB
/
handler.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
package goldcdp
import (
"encoding/binary"
"encoding/hex"
"fmt"
"strconv"
"strings"
"github.com/bandprotocol/bandchain/chain/x/oracle"
sdk "github.com/cosmos/cosmos-sdk/types"
sdkerrors "github.com/cosmos/cosmos-sdk/types/errors"
channel "github.com/cosmos/cosmos-sdk/x/ibc/04-channel"
channeltypes "github.com/cosmos/cosmos-sdk/x/ibc/04-channel/types"
"github.com/bandprotocol/goldcdp/x/goldcdp/types"
)
// NewHandler creates the msg handler of this module, as required by Cosmos-SDK standard.
func NewHandler(keeper Keeper) sdk.Handler {
return func(ctx sdk.Context, msg sdk.Msg) (*sdk.Result, error) {
ctx = ctx.WithEventManager(sdk.NewEventManager())
switch msg := msg.(type) {
case MsgBuyGold:
return handleBuyGold(ctx, msg, keeper)
case MsgSetSourceChannel:
return handleSetSourceChannel(ctx, msg, keeper)
case channeltypes.MsgPacket:
var responsePacket oracle.OracleResponsePacketData
if err := types.ModuleCdc.UnmarshalJSON(msg.GetData(), &responsePacket); err == nil {
return handleOracleRespondPacketData(ctx, responsePacket, keeper)
}
return nil, sdkerrors.Wrapf(sdkerrors.ErrUnknownRequest, "cannot unmarshal oracle packet data")
default:
return nil, sdkerrors.Wrapf(sdkerrors.ErrUnknownRequest, "unrecognized %s message type: %T", ModuleName, msg)
}
}
}
func handleBuyGold(ctx sdk.Context, msg MsgBuyGold, keeper Keeper) (*sdk.Result, error) {
orderID, err := keeper.AddOrder(ctx, msg.Buyer, msg.Amount)
if err != nil {
return nil, err
}
// TODO: Set all bandchain parameter here
bandChainID := "bandchain"
port := "goldcdp"
oracleScriptID := oracle.OracleScriptID(3)
calldata := make([]byte, 8)
binary.LittleEndian.PutUint64(calldata, 1000000)
askCount := int64(1)
minCount := int64(1)
channelID, err := keeper.GetChannel(ctx, bandChainID, port)
if err != nil {
return nil, sdkerrors.Wrapf(
sdkerrors.ErrUnknownRequest,
"not found channel to bandchain",
)
}
sourceChannelEnd, found := keeper.ChannelKeeper.GetChannel(ctx, port, channelID)
if !found {
return nil, sdkerrors.Wrapf(
sdkerrors.ErrUnknownRequest,
"unknown channel %s port goldcdp",
channelID,
)
}
destinationPort := sourceChannelEnd.Counterparty.PortID
destinationChannel := sourceChannelEnd.Counterparty.ChannelID
sequence, found := keeper.ChannelKeeper.GetNextSequenceSend(
ctx, port, channelID,
)
if !found {
return nil, sdkerrors.Wrapf(
sdkerrors.ErrUnknownRequest,
"unknown sequence number for channel %s port oracle",
channelID,
)
}
packet := oracle.NewOracleRequestPacketData(
fmt.Sprintf("Order:%d", orderID), oracleScriptID, hex.EncodeToString(calldata),
askCount, minCount,
)
err = keeper.ChannelKeeper.SendPacket(ctx, channel.NewPacket(packet.GetBytes(),
sequence, port, channelID, destinationPort, destinationChannel,
1000000000, // Arbitrarily high timeout for now
))
if err != nil {
return nil, err
}
return &sdk.Result{Events: ctx.EventManager().Events().ToABCIEvents()}, nil
}
func handleSetSourceChannel(ctx sdk.Context, msg MsgSetSourceChannel, keeper Keeper) (*sdk.Result, error) {
keeper.SetChannel(ctx, msg.ChainName, msg.SourcePort, msg.SourceChannel)
return &sdk.Result{Events: ctx.EventManager().Events().ToABCIEvents()}, nil
}
func handleOracleRespondPacketData(ctx sdk.Context, packet oracle.OracleResponsePacketData, keeper Keeper) (*sdk.Result, error) {
clientID := strings.Split(packet.ClientID, ":")
if len(clientID) != 2 {
return nil, sdkerrors.Wrapf(types.ErrUnknownClientID, "unknown client id %s", packet.ClientID)
}
orderID, err := strconv.ParseUint(clientID[1], 10, 64)
if err != nil {
return nil, err
}
rawResult, err := hex.DecodeString(packet.Result)
if err != nil {
return nil, err
}
result, err := types.DecodeResult(rawResult)
if err != nil {
return nil, err
}
// Assume multiplier should be 1000000
order, err := keeper.GetOrder(ctx, orderID)
if err != nil {
return nil, err
}
// TODO: Calculate collateral percentage
goldAmount := order.Amount[0].Amount.Int64() / int64(result.Px)
if goldAmount == 0 {
escrowAddress := types.GetEscrowAddress()
err = keeper.BankKeeper.SendCoins(ctx, escrowAddress, order.Owner, order.Amount)
if err != nil {
return nil, err
}
order.Status = types.Completed
keeper.SetOrder(ctx, orderID, order)
} else {
goldToken := sdk.NewCoin("gold", sdk.NewInt(goldAmount))
keeper.BankKeeper.AddCoins(ctx, order.Owner, sdk.NewCoins(goldToken))
order.Gold = goldToken
order.Status = types.Active
keeper.SetOrder(ctx, orderID, order)
}
return &sdk.Result{Events: ctx.EventManager().Events().ToABCIEvents()}, nil
}