-
Notifications
You must be signed in to change notification settings - Fork 12
/
relay_transfer.go
106 lines (95 loc) · 3.48 KB
/
relay_transfer.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 (
"encoding/hex"
"fmt"
"strings"
"time"
sdkmath "cosmossdk.io/math"
sdk "github.com/cosmos/cosmos-sdk/types"
"github.com/cosmos/cosmos-sdk/types/bech32"
transfertypes "github.com/cosmos/ibc-go/v6/modules/apps/transfer/types"
ibcclienttypes "github.com/cosmos/ibc-go/v6/modules/core/02-client/types"
"github.com/ethereum/go-ethereum/common"
fxtypes "github.com/functionx/fx-core/v4/types"
"github.com/functionx/fx-core/v4/x/crosschain/types"
)
func (k Keeper) RelayTransferHandler(ctx sdk.Context, eventNonce uint64, targetHex string, receiver sdk.AccAddress, coin sdk.Coin) error {
// ignore hex decode error
targetByte, _ := hex.DecodeString(targetHex)
fxTarget := fxtypes.ParseFxTarget(string(targetByte))
if fxTarget.IsIBC() {
// transfer to ibc
cacheCtx, commit := ctx.CacheContext()
targetIBCCoin, err1 := k.erc20Keeper.ConvertDenomToTarget(cacheCtx, receiver, coin, fxTarget)
var err2 error
if err1 == nil {
if err2 = k.transferIBCHandler(cacheCtx, eventNonce, receiver, targetIBCCoin, fxTarget); err2 == nil {
commit()
return nil
}
}
k.Logger(ctx).Info("failed to transfer ibc", "err1", err1, "err2", err2)
}
// todo do not convert FX to evm
if fxTarget.GetTarget() == fxtypes.ERC20Target {
// transfer to evm
cacheCtx, commit := ctx.CacheContext()
if err := k.transferErc20Handler(cacheCtx, eventNonce, receiver, coin); err != nil {
return err
}
commit()
}
return nil
}
func (k Keeper) transferErc20Handler(ctx sdk.Context, eventNonce uint64, receiver sdk.AccAddress, coin sdk.Coin) error {
receiverEthAddr := common.BytesToAddress(receiver.Bytes())
if err := k.erc20Keeper.TransferAfter(ctx, receiver, receiverEthAddr.String(), coin, sdk.NewCoin(coin.Denom, sdkmath.ZeroInt()), false); err != nil {
k.Logger(ctx).Error("transfer convert denom failed", "error", err.Error())
return err
}
ctx.EventManager().EmitEvent(sdk.NewEvent(
types.EventTypeEvmTransfer,
sdk.NewAttribute(sdk.AttributeKeyModule, k.moduleName),
sdk.NewAttribute(types.AttributeKeyEventNonce, fmt.Sprint(eventNonce)),
))
return nil
}
func (k Keeper) transferIBCHandler(ctx sdk.Context, eventNonce uint64, receive sdk.AccAddress, coin sdk.Coin, target fxtypes.FxTarget) error {
var ibcReceiveAddress string
if strings.ToLower(target.Prefix) == fxtypes.EthereumAddressPrefix {
ibcReceiveAddress = common.BytesToAddress(receive.Bytes()).String()
} else {
var err error
ibcReceiveAddress, err = bech32.ConvertAndEncode(target.Prefix, receive)
if err != nil {
return err
}
}
// Note: Height is fixed for 5 seconds
ibcTransferTimeoutHeight := k.GetIbcTransferTimeoutHeight(ctx) * 5
ibcTimeoutTime := ctx.BlockTime().Add(time.Second * time.Duration(ibcTransferTimeoutHeight))
response, err := k.ibcTransferKeeper.Transfer(sdk.WrapSDKContext(ctx),
transfertypes.NewMsgTransfer(
target.SourcePort,
target.SourceChannel,
coin,
receive.String(),
ibcReceiveAddress,
ibcclienttypes.ZeroHeight(),
uint64(ibcTimeoutTime.UnixNano()),
"",
),
)
if err != nil {
return err
}
ctx.EventManager().EmitEvent(sdk.NewEvent(
types.EventTypeIbcTransfer,
sdk.NewAttribute(sdk.AttributeKeyModule, k.moduleName),
sdk.NewAttribute(types.AttributeKeyEventNonce, fmt.Sprint(eventNonce)),
sdk.NewAttribute(types.AttributeKeyIbcSendSequence, fmt.Sprint(response.GetSequence())),
sdk.NewAttribute(types.AttributeKeyIbcSourcePort, target.SourcePort),
sdk.NewAttribute(types.AttributeKeyIbcSourceChannel, target.SourceChannel),
))
return err
}