-
Notifications
You must be signed in to change notification settings - Fork 0
/
send_to_ibc.go
executable file
·132 lines (115 loc) · 3.49 KB
/
send_to_ibc.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
package evmhandler
import (
"fmt"
"math/big"
sdk "github.com/cosmos/cosmos-sdk/types"
"github.com/ethereum/go-ethereum/accounts/abi"
"github.com/ethereum/go-ethereum/common"
swakeeper "github.com/swag-eag/swa/v2/x/swa/keeper"
"github.com/swag-eag/swa/v2/x/swa/types"
)
var _ types.EvmLogHandler = SendToIbcHandler{}
const SendToIbcEventName = "__SwaSendToIbc"
// SendToIbcEvent represent the signature of
// `event __SwaSendToIbc(address sender, string recipient, uint256 amount)`
var SendToIbcEvent abi.Event
func init() {
addressType, _ := abi.NewType("address", "", nil)
uint256Type, _ := abi.NewType("uint256", "", nil)
stringType, _ := abi.NewType("string", "", nil)
SendToIbcEvent = abi.NewEvent(
SendToIbcEventName,
SendToIbcEventName,
false,
abi.Arguments{abi.Argument{
Name: "sender",
Type: addressType,
Indexed: false,
}, abi.Argument{
Name: "recipient",
Type: stringType,
Indexed: false,
}, abi.Argument{
Name: "amount",
Type: uint256Type,
Indexed: false,
}},
)
}
// SendToIbcHandler handles `__SwaSendToIbc` log
type SendToIbcHandler struct {
bankKeeper types.BankKeeper
swaKeeper swakeeper.Keeper
}
func NewSendToIbcHandler(bankKeeper types.BankKeeper, swaKeeper swakeeper.Keeper) *SendToIbcHandler {
return &SendToIbcHandler{
bankKeeper: bankKeeper,
swaKeeper: swaKeeper,
}
}
func (h SendToIbcHandler) EventID() common.Hash {
return SendToIbcEvent.ID
}
func (h SendToIbcHandler) Handle(
ctx sdk.Context,
contract common.Address,
topics []common.Hash,
data []byte,
_ func(contractAddress common.Address, logSig common.Hash, logData []byte),
) error {
unpacked, err := SendToIbcEvent.Inputs.Unpack(data)
if err != nil {
// log and ignore
h.swaKeeper.Logger(ctx).Error("log signature matches but failed to decode", "error", err)
return nil
}
sender := unpacked[0].(common.Address)
recipient := unpacked[1].(string)
amount := unpacked[2].(*big.Int)
return h.handle(ctx, contract, sender, recipient, amount, nil)
}
func (h SendToIbcHandler) handle(
ctx sdk.Context,
contract common.Address,
senderAddress common.Address,
recipient string,
amountInt *big.Int,
id *big.Int,
) error {
denom, found := h.swaKeeper.GetDenomByContract(ctx, contract)
if !found {
return fmt.Errorf("contract %s is not connected to native token", contract)
}
if !types.IsValidIBCDenom(denom) && !types.IsValidSwaDenom(denom) {
return fmt.Errorf("the native token associated with the contract %s is neither an ibc voucher or a swa token", contract)
}
contractAddr := sdk.AccAddress(contract.Bytes())
sender := sdk.AccAddress(senderAddress.Bytes())
amount := sdk.NewIntFromBigInt(amountInt)
coins := sdk.NewCoins(sdk.NewCoin(denom, amount))
var err error
if types.IsSourceCoin(denom) {
// it is a source token, we need to mint coins
if err = h.bankKeeper.MintCoins(ctx, types.ModuleName, coins); err != nil {
return err
}
// send the coin to the user
if err = h.bankKeeper.SendCoinsFromModuleToAccount(ctx, types.ModuleName, sender, coins); err != nil {
return err
}
} else {
// First, transfer IBC coin to user so that he will be the refunded address if transfer fails
if err = h.bankKeeper.SendCoins(ctx, contractAddr, sender, coins); err != nil {
return err
}
}
channelId := ""
if id != nil {
channelId = "channel-" + id.String()
}
// Initiate IBC transfer from sender account
if err = h.swaKeeper.IbcTransferCoins(ctx, sender.String(), recipient, coins, channelId); err != nil {
return err
}
return nil
}