/
attestation_handler.go
128 lines (112 loc) · 4.67 KB
/
attestation_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
package keeper
import (
"fmt"
errorsmod "cosmossdk.io/errors"
sdk "github.com/cosmos/cosmos-sdk/types"
fxtypes "github.com/functionx/fx-core/v5/types"
"github.com/functionx/fx-core/v5/x/crosschain/types"
)
// AttestationHandler Handle is the entry point for Attestation processing.
//
//gocyclo:ignore
func (k Keeper) AttestationHandler(ctx sdk.Context, externalClaim types.ExternalClaim) error {
switch claim := externalClaim.(type) {
case *types.MsgSendToFxClaim:
bridgeToken := k.GetBridgeTokenDenom(ctx, claim.TokenContract)
if bridgeToken == nil {
return errorsmod.Wrap(types.ErrInvalid, "bridge token is not exist")
}
coin := sdk.NewCoin(bridgeToken.Denom, claim.Amount)
receiveAddr, err := sdk.AccAddressFromBech32(claim.Receiver)
if err != nil {
return errorsmod.Wrap(types.ErrInvalid, "receiver address")
}
isOriginDenom := k.erc20Keeper.IsOriginDenom(ctx, bridgeToken.Denom)
if !isOriginDenom {
// If it is not fxcore originated, mint the coins (aka vouchers)
if err := k.bankKeeper.MintCoins(ctx, k.moduleName, sdk.NewCoins(coin)); err != nil {
return errorsmod.Wrapf(err, "mint vouchers coins")
}
}
if err = k.bankKeeper.SendCoinsFromModuleToAccount(ctx, k.moduleName, receiveAddr, sdk.NewCoins(coin)); err != nil {
return errorsmod.Wrap(err, "transfer vouchers")
}
// convert to base denom
cacheCtx, commit := ctx.CacheContext()
targetCoin, err := k.erc20Keeper.ConvertDenomToTarget(cacheCtx, receiveAddr, coin, fxtypes.ParseFxTarget(fxtypes.ERC20Target))
if err != nil {
k.Logger(ctx).Info("failed to convert base denom", "error", err)
return nil
}
commit()
// relay transfer
if err = k.RelayTransferHandler(ctx, claim.EventNonce, claim.TargetIbc, receiveAddr, targetCoin); err != nil {
k.Logger(ctx).Info("failed to relay transfer", "error", err)
return nil
}
case *types.MsgSendToExternalClaim:
k.OutgoingTxBatchExecuted(ctx, claim.TokenContract, claim.BatchNonce)
case *types.MsgBridgeTokenClaim:
// Check if it already exists
isExist := k.HasBridgeToken(ctx, claim.TokenContract)
if isExist {
return errorsmod.Wrap(types.ErrInvalid, "bridge token is exist")
}
k.Logger(ctx).Info("add bridge token claim", "symbol", claim.Symbol, "token", claim.TokenContract, "channelIbc", claim.ChannelIbc)
if claim.Symbol == fxtypes.DefaultDenom {
// Check if denom exists
metadata, found := k.bankKeeper.GetDenomMetaData(ctx, claim.Symbol)
if !found {
return errorsmod.Wrap(
types.ErrUnknown,
fmt.Sprintf("denom not found %s", claim.Symbol))
}
// Check if attributes of ERC20 match fx denom
if claim.Name != metadata.Name {
return errorsmod.Wrap(
types.ErrInvalid,
fmt.Sprintf("ERC20 name %s does not match denom display %s", claim.Name, metadata.Description))
}
if claim.Symbol != metadata.Symbol {
return errorsmod.Wrap(
types.ErrInvalid,
fmt.Sprintf("ERC20 symbol %s does not match denom display %s", claim.Symbol, metadata.Display))
}
if fxtypes.DenomUnit != uint32(claim.Decimals) {
return errorsmod.Wrap(
types.ErrInvalid,
fmt.Sprintf("ERC20 decimals %d does not match denom decimals %d", claim.Decimals, fxtypes.DenomUnit))
}
k.AddBridgeToken(ctx, claim.TokenContract, claim.Symbol)
return nil
}
denom, err := k.SetIbcDenomTrace(ctx, claim.TokenContract, claim.ChannelIbc)
if err != nil {
return err
}
k.AddBridgeToken(ctx, claim.TokenContract, denom)
k.Logger(ctx).Info("add bridge token success", "symbol", claim.Symbol, "token", claim.TokenContract, "denom", denom, "channelIbc", claim.ChannelIbc)
case *types.MsgOracleSetUpdatedClaim:
observedOracleSet := &types.OracleSet{
Nonce: claim.OracleSetNonce,
Members: claim.Members,
}
// check the contents of the validator set against the store
if claim.OracleSetNonce != 0 {
trustedOracleSet := k.GetOracleSet(ctx, claim.OracleSetNonce)
if trustedOracleSet == nil {
ctx.Logger().Error("Received attestation for a oracle set which does not exist in store", "oracleSetNonce", claim.OracleSetNonce, "claim", claim)
return errorsmod.Wrapf(types.ErrInvalid, "attested oracleSet (%v) does not exist in store", claim.OracleSetNonce)
}
// overwrite the height, since it's not part of the claim
observedOracleSet.Height = trustedOracleSet.Height
if _, err := trustedOracleSet.Equal(observedOracleSet); err != nil {
panic(fmt.Sprintf("Potential bridge highjacking: observed oracleSet (%+v) does not match stored oracleSet (%+v)! %s", observedOracleSet, trustedOracleSet, err.Error()))
}
}
k.SetLastObservedOracleSet(ctx, observedOracleSet)
default:
return errorsmod.Wrapf(types.ErrInvalid, "event type: %s", claim.GetType())
}
return nil
}