From d7544233e20de665f49dc925a839017bcf34d7ea Mon Sep 17 00:00:00 2001 From: Lucas Bertrand Date: Tue, 10 Oct 2023 09:12:13 -0700 Subject: [PATCH 01/27] refactor: change default mempool version in config (#1238) --- cmd/zetacored/root.go | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/cmd/zetacored/root.go b/cmd/zetacored/root.go index 84713de816..82a146c582 100644 --- a/cmd/zetacored/root.go +++ b/cmd/zetacored/root.go @@ -92,7 +92,7 @@ func NewRootCmd() (*cobra.Command, appparams.EncodingConfig) { customAppTemplate, customAppConfig := initAppConfig() - return server.InterceptConfigsPreRunHandler(cmd, customAppTemplate, customAppConfig, tmcfg.DefaultConfig()) + return server.InterceptConfigsPreRunHandler(cmd, customAppTemplate, customAppConfig, initTmConfig()) }, } @@ -107,6 +107,18 @@ func initAppConfig() (string, interface{}) { return servercfg.AppConfig(zetacoredconfig.BaseDenom) } +// initTmConfig overrides the default Tendermint config +func initTmConfig() *tmcfg.Config { + cfg := tmcfg.DefaultConfig() + + // use mempool version 1 to enable tx priority + if cfg.Mempool != nil { + cfg.Mempool.Version = tmcfg.MempoolV1 + } + + return cfg +} + func initRootCmd(rootCmd *cobra.Command, encodingConfig appparams.EncodingConfig) { rootCmd.AddCommand( ethermintclient.ValidateChainID( From 996f35d496edf1393bd2e2ad954f5e9bfd6e345f Mon Sep 17 00:00:00 2001 From: Lucas Bertrand Date: Tue, 10 Oct 2023 09:40:06 -0700 Subject: [PATCH 02/27] fix(`MsgWhitelistERC20`): set unique index for generate cctx (#1245) * update index * remove deprecated functions * make generate * add return value in message * initialize test * whitelist tests * make generate --- docs/openapi/openapi.swagger.yaml | 5 + docs/spec/crosschain/messages.md | 3 + proto/crosschain/tx.proto | 5 +- x/crosschain/keeper/cctx_utils.go | 10 +- .../keeper/msg_server_whitelist_erc20.go | 72 +++-- .../keeper/msg_server_whitelist_erc20_test.go | 177 +++++++++++ x/crosschain/types/tx.pb.go | 277 ++++++++++++------ x/fungible/types/errors.go | 51 ++-- 8 files changed, 461 insertions(+), 139 deletions(-) create mode 100644 x/crosschain/keeper/msg_server_whitelist_erc20_test.go diff --git a/docs/openapi/openapi.swagger.yaml b/docs/openapi/openapi.swagger.yaml index 3c4345f108..e7694c9585 100644 --- a/docs/openapi/openapi.swagger.yaml +++ b/docs/openapi/openapi.swagger.yaml @@ -50449,6 +50449,11 @@ definitions: type: object crosschainMsgWhitelistERC20Response: type: object + properties: + zrc20_address: + type: string + cctx_index: + type: string crosschainOutTxTracker: type: object properties: diff --git a/docs/spec/crosschain/messages.md b/docs/spec/crosschain/messages.md index 41c32d9f13..43a8678e41 100644 --- a/docs/spec/crosschain/messages.md +++ b/docs/spec/crosschain/messages.md @@ -207,6 +207,9 @@ message MsgVoteOnObservedInboundTx { ## MsgWhitelistERC20 +WhitelistERC20 deploys a new zrc20, create a foreign coin object for the ERC20 +and emit a crosschain tx to whitelist the ERC20 on the external chain + ```proto message MsgWhitelistERC20 { string creator = 1; diff --git a/proto/crosschain/tx.proto b/proto/crosschain/tx.proto index 417b899787..51826c92bc 100644 --- a/proto/crosschain/tx.proto +++ b/proto/crosschain/tx.proto @@ -37,7 +37,10 @@ message MsgWhitelistERC20 { int64 gas_limit = 7; } -message MsgWhitelistERC20Response {} +message MsgWhitelistERC20Response { + string zrc20_address = 1; + string cctx_index = 2; +} message MsgAddToOutTxTracker { string creator = 1; diff --git a/x/crosschain/keeper/cctx_utils.go b/x/crosschain/keeper/cctx_utils.go index b04b79a9b5..d77d928017 100644 --- a/x/crosschain/keeper/cctx_utils.go +++ b/x/crosschain/keeper/cctx_utils.go @@ -4,10 +4,10 @@ import ( "errors" "fmt" + cosmoserrors "cosmossdk.io/errors" "cosmossdk.io/math" sdk "github.com/cosmos/cosmos-sdk/types" - sdkerrors "github.com/cosmos/cosmos-sdk/types/errors" ethcommon "github.com/ethereum/go-ethereum/common" "github.com/zeta-chain/zetacore/common" "github.com/zeta-chain/zetacore/x/crosschain/types" @@ -24,24 +24,24 @@ func (k Keeper) UpdateNonce(ctx sdk.Context, receiveChainID int64, cctx *types.C nonce, found := k.GetChainNonces(ctx, chain.ChainName.String()) if !found { - return sdkerrors.Wrap(types.ErrCannotFindReceiverNonce, fmt.Sprintf("Chain(%s) | Identifiers : %s ", chain.ChainName.String(), cctx.LogIdentifierForCCTX())) + return cosmoserrors.Wrap(types.ErrCannotFindReceiverNonce, fmt.Sprintf("Chain(%s) | Identifiers : %s ", chain.ChainName.String(), cctx.LogIdentifierForCCTX())) } // SET nonce cctx.GetCurrentOutTxParam().OutboundTxTssNonce = nonce.Nonce tss, found := k.GetTSS(ctx) if !found { - return sdkerrors.Wrap(types.ErrCannotFindTSSKeys, fmt.Sprintf("Chain(%s) | Identifiers : %s ", chain.ChainName.String(), cctx.LogIdentifierForCCTX())) + return cosmoserrors.Wrap(types.ErrCannotFindTSSKeys, fmt.Sprintf("Chain(%s) | Identifiers : %s ", chain.ChainName.String(), cctx.LogIdentifierForCCTX())) } p, found := k.GetPendingNonces(ctx, tss.TssPubkey, receiveChainID) if !found { - return sdkerrors.Wrap(types.ErrCannotFindPendingNonces, fmt.Sprintf("chain_id %d, nonce %d", receiveChainID, nonce.Nonce)) + return cosmoserrors.Wrap(types.ErrCannotFindPendingNonces, fmt.Sprintf("chain_id %d, nonce %d", receiveChainID, nonce.Nonce)) } // #nosec G701 always in range if p.NonceHigh != int64(nonce.Nonce) { - return sdkerrors.Wrap(types.ErrNonceMismatch, fmt.Sprintf("chain_id %d, high nonce %d, current nonce %d", receiveChainID, p.NonceHigh, nonce.Nonce)) + return cosmoserrors.Wrap(types.ErrNonceMismatch, fmt.Sprintf("chain_id %d, high nonce %d, current nonce %d", receiveChainID, p.NonceHigh, nonce.Nonce)) } nonce.Nonce++ diff --git a/x/crosschain/keeper/msg_server_whitelist_erc20.go b/x/crosschain/keeper/msg_server_whitelist_erc20.go index a4118fc774..bd8d7b5f60 100644 --- a/x/crosschain/keeper/msg_server_whitelist_erc20.go +++ b/x/crosschain/keeper/msg_server_whitelist_erc20.go @@ -6,36 +6,45 @@ import ( "math/big" errorsmod "cosmossdk.io/errors" + "cosmossdk.io/math" + sdk "github.com/cosmos/cosmos-sdk/types" sdkerrors "github.com/cosmos/cosmos-sdk/types/errors" ethcommon "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/crypto" - tmbytes "github.com/tendermint/tendermint/libs/bytes" - tmtypes "github.com/tendermint/tendermint/types" + "github.com/zeta-chain/zetacore/common" "github.com/zeta-chain/zetacore/x/crosschain/types" fungibletypes "github.com/zeta-chain/zetacore/x/fungible/types" zetaObserverTypes "github.com/zeta-chain/zetacore/x/observer/types" ) +// WhitelistERC20 deploys a new zrc20, create a foreign coin object for the ERC20 +// and emit a crosschain tx to whitelist the ERC20 on the external chain func (k Keeper) WhitelistERC20(goCtx context.Context, msg *types.MsgWhitelistERC20) (*types.MsgWhitelistERC20Response, error) { ctx := sdk.UnwrapSDKContext(goCtx) if msg.Creator != k.zetaObserverKeeper.GetParams(ctx).GetAdminPolicyAccount(zetaObserverTypes.Policy_Type_group1) { - return nil, sdkerrors.Wrap(sdkerrors.ErrUnauthorized, "Deploy can only be executed by the correct policy account") + return nil, errorsmod.Wrap(sdkerrors.ErrUnauthorized, "Deploy can only be executed by the correct policy account") } erc20Addr := ethcommon.HexToAddress(msg.Erc20Address) if erc20Addr == (ethcommon.Address{}) { - return nil, sdkerrors.Wrapf(sdkerrors.ErrInvalidAddress, "invalid ERC20 contract address (%s)", msg.Erc20Address) + return nil, errorsmod.Wrapf(sdkerrors.ErrInvalidAddress, "invalid ERC20 contract address (%s)", msg.Erc20Address) } - // check if it's already whitelisted + // check if the erc20 is already whitelisted foreignCoins := k.fungibleKeeper.GetAllForeignCoins(ctx) - for _, fcoin := range foreignCoins { - assetAddr := ethcommon.HexToAddress(fcoin.Asset) - if assetAddr == erc20Addr && fcoin.ForeignChainId == msg.ChainId { - return nil, sdkerrors.Wrapf(types.ErrInvalidAddress, "ERC20 contract address (%s) already whitelisted on chain (%d)", msg.Erc20Address, msg.ChainId) + for _, fCoin := range foreignCoins { + assetAddr := ethcommon.HexToAddress(fCoin.Asset) + if assetAddr == erc20Addr && fCoin.ForeignChainId == msg.ChainId { + return nil, errorsmod.Wrapf( + fungibletypes.ErrForeignCoinAlreadyExist, + "ERC20 contract address (%s) already whitelisted on chain (%d)", + msg.Erc20Address, + msg.ChainId, + ) } } + tss, found := k.GetTSS(ctx) if !found { return nil, errorsmod.Wrapf(types.ErrCannotFindTSSKeys, "Cannot create new admin cmd of type whitelistERC20") @@ -43,10 +52,12 @@ func (k Keeper) WhitelistERC20(goCtx context.Context, msg *types.MsgWhitelistERC chain := k.zetaObserverKeeper.GetParams(ctx).GetChainFromChainID(msg.ChainId) if chain == nil { - return nil, sdkerrors.Wrapf(types.ErrInvalidChainID, "chain id (%d) not supported", msg.ChainId) + return nil, errorsmod.Wrapf(types.ErrInvalidChainID, "chain id (%d) not supported", msg.ChainId) } + // use a temporary context for the zrc20 deployment tmpCtx, commit := ctx.CacheContext() + // add to the foreign coins. Deploy ZRC20 contract for it. zrc20Addr, err := k.fungibleKeeper.DeployZRC20Contract( tmpCtx, @@ -60,29 +71,43 @@ func (k Keeper) WhitelistERC20(goCtx context.Context, msg *types.MsgWhitelistERC big.NewInt(msg.GasLimit), ) if err != nil { - return nil, sdkerrors.Wrapf(types.ErrDeployContract, "failed to deploy ZRC20 contract for ERC20 contract address (%s) on chain (%d)", msg.Erc20Address, msg.ChainId) + return nil, errorsmod.Wrapf( + types.ErrDeployContract, + "failed to deploy ZRC20 contract for ERC20 contract address (%s) on chain (%d)", + msg.Erc20Address, + msg.ChainId, + ) } if zrc20Addr == (ethcommon.Address{}) { - return nil, sdkerrors.Wrapf(types.ErrDeployContract, "deployed ZRC20 return 0 address for ERC20 contract address (%s) on chain (%d)", msg.Erc20Address, msg.ChainId) + return nil, errorsmod.Wrapf( + types.ErrDeployContract, + "deployed ZRC20 return 0 address for ERC20 contract address (%s) on chain (%d)", + msg.Erc20Address, + msg.ChainId, + ) } + // get necessary parameters to create the cctx param, found := k.zetaObserverKeeper.GetCoreParamsByChainID(ctx, msg.ChainId) if !found { - return nil, sdkerrors.Wrapf(types.ErrInvalidChainID, "core params not found for chain id (%d)", msg.ChainId) + return nil, errorsmod.Wrapf(types.ErrInvalidChainID, "core params not found for chain id (%d)", msg.ChainId) } - medianGasPrice, isFound := k.GetMedianGasPriceInUint(ctx, msg.ChainId) if !isFound { - return nil, sdkerrors.Wrapf(types.ErrUnableToGetGasPrice, "median gas price not found for chain id (%d)", msg.ChainId) + return nil, errorsmod.Wrapf(types.ErrUnableToGetGasPrice, "median gas price not found for chain id (%d)", msg.ChainId) } medianGasPrice = medianGasPrice.MulUint64(2) // overpays gas price by 2x - hash := tmbytes.HexBytes(tmtypes.Tx(ctx.TxBytes()).Hash()) + // calculate the cctx index + // we use the deployed zrc20 contract address to generate a unique index + // since other parts of the system may use the zrc20 for the index, we add a message specific suffix + hash := crypto.Keccak256Hash(zrc20Addr.Bytes(), []byte("WhitelistERC20")) + index := hash.Hex() - index := crypto.Keccak256Hash(hash.Bytes()) + // create a cmd cctx to whitelist the erc20 on the external chain cctx := types.CrossChainTx{ Creator: msg.Creator, - Index: index.String(), + Index: index, ZetaFees: sdk.NewUint(0), RelayedMessage: fmt.Sprintf("%s:%s", common.CmdWhitelistERC20, msg.Erc20Address), CctxStatus: &types.Status{ @@ -96,7 +121,7 @@ func (k Keeper) WhitelistERC20(goCtx context.Context, msg *types.MsgWhitelistERC TxOrigin: "", CoinType: common.CoinType_Cmd, Asset: "", - Amount: sdk.Uint{}, + Amount: math.Uint{}, InboundTxObservedHash: hash.String(), // all Upper case Cosmos TX HEX, with no 0x prefix InboundTxObservedExternalHeight: 0, InboundTxBallotIndex: "", @@ -107,7 +132,7 @@ func (k Keeper) WhitelistERC20(goCtx context.Context, msg *types.MsgWhitelistERC Receiver: param.Erc20CustodyContractAddress, ReceiverChainId: msg.ChainId, CoinType: common.CoinType_Cmd, - Amount: sdk.NewUint(0), + Amount: math.NewUint(0), OutboundTxTssNonce: 0, OutboundTxGasLimit: 100_000, OutboundTxGasPrice: medianGasPrice.String(), @@ -137,6 +162,11 @@ func (k Keeper) WhitelistERC20(goCtx context.Context, msg *types.MsgWhitelistERC } k.fungibleKeeper.SetForeignCoins(ctx, foreignCoin) k.SetCctxAndNonceToCctxAndInTxHashToCctx(ctx, cctx) + commit() - return &types.MsgWhitelistERC20Response{}, nil + + return &types.MsgWhitelistERC20Response{ + Zrc20Address: zrc20Addr.Hex(), + CctxIndex: index, + }, nil } diff --git a/x/crosschain/keeper/msg_server_whitelist_erc20_test.go b/x/crosschain/keeper/msg_server_whitelist_erc20_test.go new file mode 100644 index 0000000000..0f7fa29916 --- /dev/null +++ b/x/crosschain/keeper/msg_server_whitelist_erc20_test.go @@ -0,0 +1,177 @@ +package keeper_test + +import ( + "fmt" + "testing" + + sdkerrors "github.com/cosmos/cosmos-sdk/types/errors" + ethcommon "github.com/ethereum/go-ethereum/common" + "github.com/stretchr/testify/require" + "github.com/zeta-chain/zetacore/common" + keepertest "github.com/zeta-chain/zetacore/testutil/keeper" + "github.com/zeta-chain/zetacore/testutil/sample" + "github.com/zeta-chain/zetacore/x/crosschain/types" + fungibletypes "github.com/zeta-chain/zetacore/x/fungible/types" +) + +func TestKeeper_WhitelistERC20(t *testing.T) { + t.Run("can deploy and whitelist an erc20", func(t *testing.T) { + k, ctx, sdkk, zk := keepertest.CrosschainKeeper(t) + k.GetAuthKeeper().GetModuleAccount(ctx, fungibletypes.ModuleName) + + chainID := getValidEthChainID(t) + admin := sample.AccAddress() + setAdminPolicies(ctx, zk, admin) + + deploySystemContracts(t, ctx, zk.FungibleKeeper, sdkk.EvmKeeper) + setupGasCoin(t, ctx, zk.FungibleKeeper, sdkk.EvmKeeper, chainID, "foobar", "FOOBAR") + k.SetTssAndUpdateNonce(ctx, *sample.Tss()) + k.SetGasPrice(ctx, types.GasPrice{ + ChainId: chainID, + MedianIndex: 0, + Prices: []uint64{1}, + }) + + erc20Address := sample.EthAddress().Hex() + res, err := k.WhitelistERC20(ctx, &types.MsgWhitelistERC20{ + Creator: admin, + Erc20Address: erc20Address, + ChainId: chainID, + Name: "foo", + Symbol: "FOO", + Decimals: 18, + GasLimit: 100000, + }) + require.NoError(t, err) + require.NotNil(t, res) + zrc20 := res.Zrc20Address + cctxIndex := res.CctxIndex + + // check zrc20 and cctx created + assertContractDeployment(t, sdkk.EvmKeeper, ctx, ethcommon.HexToAddress(zrc20)) + fc, found := zk.FungibleKeeper.GetForeignCoins(ctx, zrc20) + require.True(t, found) + require.EqualValues(t, "foo", fc.Name) + require.EqualValues(t, erc20Address, fc.Asset) + cctx, found := k.GetCrossChainTx(ctx, cctxIndex) + require.True(t, found) + require.EqualValues(t, fmt.Sprintf("%s:%s", common.CmdWhitelistERC20, erc20Address), cctx.RelayedMessage) + + // Ensure that whitelist a new erc20 create a cctx with a different index + res, err = k.WhitelistERC20(ctx, &types.MsgWhitelistERC20{ + Creator: admin, + Erc20Address: sample.EthAddress().Hex(), + ChainId: chainID, + Name: "bar", + Symbol: "BAR", + Decimals: 18, + GasLimit: 100000, + }) + require.NoError(t, err) + require.NotNil(t, res) + require.NotEqual(t, cctxIndex, res.CctxIndex) + }) + + t.Run("should fail if not authorized", func(t *testing.T) { + k, ctx, _, _ := keepertest.CrosschainKeeper(t) + k.GetAuthKeeper().GetModuleAccount(ctx, fungibletypes.ModuleName) + + _, err := k.WhitelistERC20(ctx, &types.MsgWhitelistERC20{ + Creator: sample.AccAddress(), + Erc20Address: sample.EthAddress().Hex(), + ChainId: getValidEthChainID(t), + Name: "foo", + Symbol: "FOO", + Decimals: 18, + GasLimit: 100000, + }) + require.ErrorIs(t, err, sdkerrors.ErrUnauthorized) + }) + + t.Run("should fail if invalid erc20 address", func(t *testing.T) { + k, ctx, _, zk := keepertest.CrosschainKeeper(t) + k.GetAuthKeeper().GetModuleAccount(ctx, fungibletypes.ModuleName) + + admin := sample.AccAddress() + setAdminPolicies(ctx, zk, admin) + + _, err := k.WhitelistERC20(ctx, &types.MsgWhitelistERC20{ + Creator: admin, + Erc20Address: "invalid", + ChainId: getValidEthChainID(t), + Name: "foo", + Symbol: "FOO", + Decimals: 18, + GasLimit: 100000, + }) + require.ErrorIs(t, err, sdkerrors.ErrInvalidAddress) + }) + + t.Run("should fail if foreign coin already exists for the asset", func(t *testing.T) { + k, ctx, _, zk := keepertest.CrosschainKeeper(t) + k.GetAuthKeeper().GetModuleAccount(ctx, fungibletypes.ModuleName) + + admin := sample.AccAddress() + setAdminPolicies(ctx, zk, admin) + + chainID := getValidEthChainID(t) + asset := sample.EthAddress().Hex() + fc := sample.ForeignCoins(t, sample.EthAddress().Hex()) + fc.Asset = asset + fc.ForeignChainId = chainID + zk.FungibleKeeper.SetForeignCoins(ctx, fc) + + _, err := k.WhitelistERC20(ctx, &types.MsgWhitelistERC20{ + Creator: admin, + Erc20Address: asset, + ChainId: chainID, + Name: "foo", + Symbol: "FOO", + Decimals: 18, + GasLimit: 100000, + }) + require.ErrorIs(t, err, fungibletypes.ErrForeignCoinAlreadyExist) + }) + + t.Run("should fail if no tss set", func(t *testing.T) { + k, ctx, _, zk := keepertest.CrosschainKeeper(t) + k.GetAuthKeeper().GetModuleAccount(ctx, fungibletypes.ModuleName) + + chainID := getValidEthChainID(t) + admin := sample.AccAddress() + setAdminPolicies(ctx, zk, admin) + + erc20Address := sample.EthAddress().Hex() + _, err := k.WhitelistERC20(ctx, &types.MsgWhitelistERC20{ + Creator: admin, + Erc20Address: erc20Address, + ChainId: chainID, + Name: "foo", + Symbol: "FOO", + Decimals: 18, + GasLimit: 100000, + }) + require.ErrorIs(t, err, types.ErrCannotFindTSSKeys) + }) + + t.Run("should fail if nox valid chain ID", func(t *testing.T) { + k, ctx, _, zk := keepertest.CrosschainKeeper(t) + k.GetAuthKeeper().GetModuleAccount(ctx, fungibletypes.ModuleName) + + admin := sample.AccAddress() + setAdminPolicies(ctx, zk, admin) + k.SetTssAndUpdateNonce(ctx, *sample.Tss()) + + erc20Address := sample.EthAddress().Hex() + _, err := k.WhitelistERC20(ctx, &types.MsgWhitelistERC20{ + Creator: admin, + Erc20Address: erc20Address, + ChainId: 10000, + Name: "foo", + Symbol: "FOO", + Decimals: 18, + GasLimit: 100000, + }) + require.ErrorIs(t, err, types.ErrInvalidChainID) + }) +} diff --git a/x/crosschain/types/tx.pb.go b/x/crosschain/types/tx.pb.go index f255d88bc9..3261f28ea9 100644 --- a/x/crosschain/types/tx.pb.go +++ b/x/crosschain/types/tx.pb.go @@ -212,6 +212,8 @@ func (m *MsgWhitelistERC20) GetGasLimit() int64 { } type MsgWhitelistERC20Response struct { + Zrc20Address string `protobuf:"bytes,1,opt,name=zrc20_address,json=zrc20Address,proto3" json:"zrc20_address,omitempty"` + CctxIndex string `protobuf:"bytes,2,opt,name=cctx_index,json=cctxIndex,proto3" json:"cctx_index,omitempty"` } func (m *MsgWhitelistERC20Response) Reset() { *m = MsgWhitelistERC20Response{} } @@ -247,6 +249,20 @@ func (m *MsgWhitelistERC20Response) XXX_DiscardUnknown() { var xxx_messageInfo_MsgWhitelistERC20Response proto.InternalMessageInfo +func (m *MsgWhitelistERC20Response) GetZrc20Address() string { + if m != nil { + return m.Zrc20Address + } + return "" +} + +func (m *MsgWhitelistERC20Response) GetCctxIndex() string { + if m != nil { + return m.CctxIndex + } + return "" +} + type MsgAddToOutTxTracker struct { Creator string `protobuf:"bytes,1,opt,name=creator,proto3" json:"creator,omitempty"` ChainId int64 `protobuf:"varint,2,opt,name=chain_id,json=chainId,proto3" json:"chain_id,omitempty"` @@ -1230,93 +1246,94 @@ func init() { func init() { proto.RegisterFile("crosschain/tx.proto", fileDescriptor_81d6d611190b7635) } var fileDescriptor_81d6d611190b7635 = []byte{ - // 1361 bytes of a gzipped FileDescriptorProto - 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xb4, 0x57, 0xcd, 0x6e, 0xdb, 0xc6, - 0x13, 0x37, 0x63, 0x5b, 0x96, 0xc6, 0x96, 0x63, 0xaf, 0x9d, 0x98, 0xa1, 0x13, 0x39, 0xa1, 0xff, - 0xc9, 0x3f, 0x28, 0x62, 0x29, 0x75, 0x5a, 0x34, 0x4d, 0x7b, 0x68, 0x6c, 0xa4, 0x8e, 0x9b, 0xca, - 0x0e, 0x68, 0xa5, 0x05, 0x72, 0x21, 0x28, 0x72, 0x4d, 0x11, 0x16, 0xb9, 0x02, 0x77, 0x65, 0x48, - 0x41, 0x4f, 0x05, 0x7a, 0xe8, 0xad, 0x87, 0x02, 0x2d, 0xfa, 0x02, 0x7d, 0x95, 0xf4, 0x16, 0xf4, - 0xd4, 0xf6, 0x10, 0xb4, 0xc9, 0x1b, 0xf4, 0x09, 0x8a, 0xfd, 0x20, 0x2d, 0xca, 0x96, 0x64, 0xbb, - 0xe8, 0x89, 0x3b, 0xb3, 0xf3, 0xf1, 0x9b, 0x9d, 0x99, 0xdd, 0x21, 0x2c, 0xb8, 0x31, 0xa1, 0xd4, - 0x6d, 0x38, 0x41, 0x54, 0x61, 0x9d, 0x72, 0x2b, 0x26, 0x8c, 0xa0, 0x6b, 0x2f, 0x30, 0x73, 0x04, - 0xaf, 0x2c, 0x56, 0x24, 0xc6, 0xe5, 0x23, 0x39, 0x63, 0xc1, 0x25, 0x61, 0x48, 0xa2, 0x8a, 0xfc, - 0x48, 0x1d, 0x63, 0xd1, 0x27, 0x3e, 0x11, 0xcb, 0x0a, 0x5f, 0x49, 0xae, 0xb9, 0x03, 0x0b, 0x55, - 0xea, 0x3f, 0x6b, 0x79, 0x0e, 0xc3, 0x35, 0x4a, 0x1f, 0x7a, 0x5e, 0x8c, 0x29, 0x45, 0x3a, 0x4c, - 0xb9, 0x31, 0x76, 0x18, 0x89, 0x75, 0xed, 0xba, 0x76, 0xbb, 0x60, 0x25, 0x24, 0xba, 0x06, 0xc0, - 0x28, 0xb5, 0x5b, 0xed, 0xfa, 0x01, 0xee, 0xea, 0x17, 0xc4, 0x66, 0x81, 0x51, 0xfa, 0x54, 0x30, - 0xcc, 0x6b, 0xb0, 0x7c, 0x82, 0x3d, 0x0b, 0xd3, 0x16, 0x89, 0x28, 0x36, 0x7f, 0xd5, 0x60, 0xbe, - 0x4a, 0xfd, 0x2f, 0x1b, 0x01, 0xc3, 0xcd, 0x80, 0xb2, 0x47, 0xd6, 0xe6, 0xfa, 0xdd, 0x21, 0xde, - 0x56, 0xa1, 0x88, 0x63, 0x77, 0xfd, 0xae, 0xed, 0x48, 0x43, 0xca, 0xe1, 0x8c, 0x60, 0x26, 0x60, - 0xaf, 0x40, 0x5e, 0xc4, 0x6d, 0x07, 0x9e, 0x3e, 0x7e, 0x5d, 0xbb, 0x3d, 0x6e, 0x4d, 0x09, 0x7a, - 0xdb, 0x43, 0x08, 0x26, 0x22, 0x27, 0xc4, 0xfa, 0x84, 0x50, 0x13, 0x6b, 0x74, 0x19, 0x72, 0xb4, - 0x1b, 0xd6, 0x49, 0x53, 0x9f, 0x14, 0x5c, 0x45, 0x21, 0x03, 0xf2, 0x1e, 0x76, 0x83, 0xd0, 0x69, - 0x52, 0x3d, 0x77, 0x5d, 0xbb, 0x5d, 0xb4, 0x52, 0x1a, 0x2d, 0x43, 0xc1, 0x77, 0xa8, 0xdd, 0x0c, - 0xc2, 0x80, 0xe9, 0x53, 0xc2, 0x47, 0xde, 0x77, 0xe8, 0xe7, 0x9c, 0x36, 0x97, 0xe1, 0xca, 0xb1, - 0x98, 0xd2, 0x88, 0x7f, 0xd7, 0x60, 0xb1, 0x4a, 0xfd, 0x87, 0x9e, 0x57, 0x23, 0xbb, 0x6d, 0x56, - 0xeb, 0xd4, 0x62, 0xc7, 0x3d, 0xc0, 0xf1, 0x90, 0xa0, 0x7b, 0xe3, 0xb9, 0x90, 0x8d, 0x67, 0x11, - 0x26, 0x23, 0x12, 0xb9, 0x58, 0xc4, 0x39, 0x61, 0x49, 0x02, 0x2d, 0xc1, 0x14, 0xeb, 0xd8, 0x0d, - 0x87, 0x36, 0x54, 0xa0, 0x39, 0xd6, 0x79, 0xec, 0xd0, 0x06, 0x5a, 0x85, 0xc9, 0x56, 0x4c, 0xc8, - 0xbe, 0x88, 0x74, 0x7a, 0xbd, 0x58, 0x56, 0x15, 0xf1, 0x94, 0x33, 0x2d, 0xb9, 0xc7, 0x33, 0x5a, - 0x6f, 0x12, 0xf7, 0x40, 0x1a, 0xc8, 0xc9, 0x8c, 0x0a, 0x8e, 0xb0, 0x71, 0x05, 0xf2, 0xac, 0x63, - 0x07, 0x91, 0x87, 0x3b, 0x2a, 0xf2, 0x29, 0xd6, 0xd9, 0xe6, 0xa4, 0x59, 0x82, 0xab, 0x27, 0x85, - 0x96, 0xc6, 0xbe, 0x2f, 0x0e, 0xc6, 0xc2, 0x21, 0x39, 0xc4, 0x9f, 0xc6, 0x24, 0xfc, 0x8f, 0xe2, - 0x37, 0x57, 0xe1, 0xc6, 0x40, 0x3f, 0x29, 0x98, 0x9f, 0x65, 0xe9, 0x6d, 0x72, 0x27, 0xb8, 0xb6, - 0xb7, 0xf7, 0x05, 0x61, 0x43, 0x51, 0x0c, 0x2f, 0x74, 0xf4, 0x0e, 0xcc, 0x1d, 0xe0, 0xee, 0x16, - 0x8e, 0x9e, 0x63, 0xe6, 0x3c, 0xc6, 0x81, 0xdf, 0x60, 0xaa, 0xf8, 0x8e, 0xf1, 0xd1, 0x1a, 0xe4, - 0x28, 0x73, 0x58, 0x9b, 0x8a, 0xf4, 0xcc, 0xae, 0x5f, 0x4a, 0xf2, 0x60, 0x61, 0x17, 0x07, 0x87, - 0x78, 0x4f, 0x6c, 0x5a, 0x4a, 0x48, 0xd5, 0x53, 0x16, 0x68, 0x1a, 0xc6, 0x8f, 0x1a, 0xcc, 0x55, - 0xa9, 0xbf, 0xe5, 0xd0, 0xa7, 0x71, 0xe0, 0xe2, 0x51, 0x51, 0x0c, 0x3f, 0xcb, 0x16, 0x37, 0x91, - 0x9c, 0xa5, 0x20, 0xd0, 0x0d, 0x98, 0x91, 0xd5, 0x10, 0xb5, 0xc3, 0x3a, 0x8e, 0x05, 0xe2, 0x09, - 0x6b, 0x5a, 0xf0, 0x76, 0x04, 0x4b, 0x34, 0x50, 0xbb, 0xd5, 0x6a, 0x76, 0xd3, 0x06, 0x12, 0x94, - 0x69, 0x80, 0xde, 0x8f, 0x2c, 0x85, 0xfd, 0x1c, 0x8a, 0x55, 0xea, 0xef, 0xf0, 0x74, 0xfd, 0x3b, - 0xc8, 0x27, 0xa4, 0x7f, 0x09, 0x2e, 0x65, 0x6c, 0x1f, 0xf5, 0xde, 0xa4, 0xb8, 0x8d, 0x38, 0x73, - 0x37, 0xda, 0xad, 0x53, 0x1c, 0x1f, 0x62, 0x6f, 0xb7, 0xcd, 0xea, 0xa4, 0x1d, 0x79, 0xb5, 0xce, - 0x10, 0x0c, 0xcb, 0x50, 0x70, 0xdd, 0xa4, 0xa7, 0x64, 0xee, 0xf3, 0x9c, 0x21, 0x3a, 0xa2, 0x0c, - 0x0b, 0x44, 0x19, 0xb3, 0x09, 0x2f, 0x35, 0x29, 0x36, 0x2e, 0xc4, 0xe6, 0xc9, 0x91, 0x9f, 0x9a, - 0x94, 0xff, 0x18, 0x8c, 0x3e, 0x79, 0xd9, 0x5d, 0xb2, 0x68, 0xe4, 0x01, 0xeb, 0x19, 0xb5, 0x8d, - 0xa3, 0x7d, 0xf4, 0x3e, 0x2c, 0xf5, 0x69, 0xf3, 0x9b, 0xa8, 0x4d, 0xb1, 0xa7, 0x83, 0x50, 0x5d, - 0xcc, 0xa8, 0x6e, 0x39, 0xf4, 0x19, 0xc5, 0x1e, 0x7a, 0x01, 0x66, 0x9f, 0x1a, 0xde, 0xdf, 0xc7, - 0x2e, 0x0b, 0x0e, 0xb1, 0x30, 0x20, 0x53, 0x3f, 0xcd, 0x31, 0x6f, 0x94, 0x5f, 0xbe, 0x5e, 0x19, - 0xfb, 0xe3, 0xf5, 0xca, 0x2d, 0x3f, 0x60, 0x8d, 0x76, 0x9d, 0x57, 0x67, 0xc5, 0x25, 0x34, 0x24, - 0x54, 0x7d, 0xd6, 0xa8, 0x77, 0x50, 0x61, 0xdd, 0x16, 0xa6, 0xe5, 0xed, 0x88, 0x59, 0xa5, 0x8c, - 0xc7, 0x47, 0x89, 0xdd, 0x24, 0xf3, 0xe8, 0xb3, 0x11, 0xbe, 0xe5, 0x35, 0x3a, 0x23, 0xd0, 0x0f, - 0xb6, 0x25, 0x2e, 0x57, 0x44, 0x60, 0xf6, 0xd0, 0x69, 0xb6, 0xb1, 0x1d, 0xcb, 0x5e, 0xf1, 0x64, - 0xd1, 0x6d, 0x3c, 0x56, 0x98, 0xff, 0x7f, 0x0a, 0xcc, 0xcf, 0x82, 0x88, 0xfd, 0xfd, 0x7a, 0xe5, - 0x52, 0xd7, 0x09, 0x9b, 0x0f, 0xcc, 0xac, 0x39, 0xd3, 0x2a, 0x0a, 0x86, 0x6a, 0x45, 0xaf, 0xa7, - 0x59, 0x73, 0xa7, 0x68, 0x56, 0xb4, 0x02, 0xd3, 0x32, 0x44, 0x51, 0xa3, 0xea, 0x86, 0x04, 0xc1, - 0xda, 0xe4, 0x1c, 0x74, 0x0b, 0x2e, 0x4a, 0x01, 0x7e, 0x9b, 0xc8, 0xea, 0xcd, 0x8b, 0xc8, 0x8b, - 0x82, 0x5d, 0xa3, 0x54, 0x54, 0x2e, 0x5a, 0x83, 0x82, 0x4b, 0x82, 0xc8, 0xe6, 0x90, 0xf5, 0x82, - 0x70, 0x3d, 0x97, 0xb8, 0xde, 0x24, 0x41, 0x54, 0xeb, 0xb6, 0xb0, 0x95, 0x77, 0xd5, 0xca, 0xbc, - 0x09, 0xab, 0x43, 0x4a, 0x3b, 0x6d, 0x81, 0xbf, 0xc6, 0xc1, 0x38, 0x26, 0xb7, 0x1d, 0x8d, 0xee, - 0x00, 0xde, 0xe4, 0x38, 0xf2, 0x70, 0xac, 0xca, 0x5f, 0x51, 0x3c, 0x1c, 0xb9, 0xb2, 0xfb, 0xde, - 0xdc, 0xa2, 0x64, 0x6f, 0xaa, 0x56, 0x35, 0x20, 0xaf, 0x8e, 0x38, 0x56, 0x8f, 0x52, 0x4a, 0xa3, - 0x9b, 0x30, 0x9b, 0xac, 0xd5, 0xb1, 0x4d, 0x4a, 0x13, 0x09, 0x57, 0x9e, 0xdc, 0x16, 0xe4, 0x9c, - 0x90, 0xb4, 0x23, 0x26, 0x1f, 0xa5, 0x8d, 0xca, 0x19, 0x53, 0x6e, 0x29, 0x75, 0x1e, 0x65, 0x88, - 0x29, 0x75, 0x7c, 0x79, 0xf4, 0x05, 0x2b, 0x21, 0xd1, 0x55, 0x00, 0x7e, 0xe4, 0xaa, 0x83, 0x0b, - 0x12, 0x67, 0x10, 0xa9, 0xc6, 0xbd, 0x05, 0x17, 0x83, 0xc8, 0x56, 0x8f, 0xa3, 0xec, 0x56, 0xd9, - 0x72, 0xc5, 0x20, 0xea, 0x6d, 0xd1, 0xcc, 0x74, 0x30, 0x2d, 0x24, 0xd2, 0xe9, 0x20, 0x9b, 0xd7, - 0x99, 0x51, 0x79, 0xe5, 0xb6, 0x58, 0xc7, 0x26, 0x71, 0xe0, 0x07, 0x91, 0x5e, 0x94, 0x80, 0x58, - 0x67, 0x57, 0xd0, 0xfc, 0xfe, 0x73, 0x28, 0xc5, 0x4c, 0x9f, 0x15, 0x1b, 0x92, 0x30, 0xff, 0x07, - 0xe6, 0xe0, 0x14, 0xa7, 0x95, 0xf0, 0xad, 0x06, 0xb3, 0x55, 0xea, 0xef, 0x61, 0xb6, 0x43, 0x3c, - 0xfc, 0x04, 0x77, 0x87, 0x4d, 0x79, 0x15, 0x28, 0xc8, 0x87, 0x6f, 0x0f, 0x33, 0x51, 0x00, 0xd3, - 0xeb, 0xf3, 0xe9, 0xf0, 0xd0, 0xae, 0x3f, 0x11, 0x1b, 0xd6, 0x91, 0x0c, 0xba, 0x03, 0x88, 0xd7, - 0x37, 0x0d, 0xfc, 0x08, 0xc7, 0xb6, 0x9a, 0xcc, 0xd4, 0x95, 0x38, 0xc7, 0x28, 0xdd, 0x13, 0x1b, - 0x8a, 0x6f, 0xea, 0x70, 0x39, 0x0b, 0x25, 0x41, 0xb9, 0xfe, 0x4b, 0x01, 0xc6, 0xab, 0xd4, 0x47, - 0xdf, 0x68, 0x30, 0x7f, 0x7c, 0x66, 0xba, 0x57, 0x1e, 0x3a, 0xf8, 0x96, 0x4f, 0x9a, 0x46, 0x8c, - 0x8f, 0xce, 0xa1, 0x94, 0xe0, 0x41, 0xdf, 0x6b, 0x70, 0x79, 0xc0, 0x00, 0x73, 0x7f, 0xb4, 0xdd, - 0x93, 0x35, 0x8d, 0x4f, 0xce, 0xab, 0x99, 0xc2, 0xfa, 0x0a, 0x66, 0xfb, 0x06, 0x99, 0xbb, 0xa3, - 0x6d, 0x66, 0x35, 0x8c, 0xfb, 0x67, 0xd5, 0x48, 0xbd, 0x77, 0xa1, 0x98, 0x9d, 0x3f, 0x2a, 0xa3, - 0x4d, 0x65, 0x14, 0x8c, 0x0f, 0xce, 0xa8, 0x90, 0xba, 0x6e, 0x01, 0xf4, 0x0c, 0x11, 0x77, 0x46, - 0x9b, 0x39, 0x92, 0x36, 0xde, 0x3b, 0x8b, 0x74, 0xea, 0xf1, 0x27, 0x0d, 0xf4, 0x81, 0x13, 0xc4, - 0x83, 0xd1, 0x26, 0x07, 0xe9, 0x1a, 0x1b, 0xe7, 0xd7, 0x4d, 0xc1, 0xfd, 0xa0, 0xc1, 0xd2, 0xa0, - 0xbb, 0xfd, 0xc3, 0xb3, 0xda, 0x4f, 0x55, 0x8d, 0x87, 0xe7, 0x56, 0xed, 0xad, 0xd0, 0xbe, 0xbf, - 0xbc, 0x53, 0x54, 0x68, 0x56, 0xe3, 0x34, 0x15, 0x7a, 0xf2, 0x5f, 0x17, 0xfa, 0x5a, 0x83, 0xb9, - 0x63, 0x3f, 0xb5, 0xeb, 0xa3, 0xcd, 0xf5, 0xeb, 0x18, 0x0f, 0xce, 0xae, 0x93, 0x80, 0xd8, 0x78, - 0xf2, 0xf2, 0x4d, 0x49, 0x7b, 0xf5, 0xa6, 0xa4, 0xfd, 0xf9, 0xa6, 0xa4, 0x7d, 0xf7, 0xb6, 0x34, - 0xf6, 0xea, 0x6d, 0x69, 0xec, 0xb7, 0xb7, 0xa5, 0xb1, 0xe7, 0xef, 0xf6, 0xbc, 0x60, 0xdc, 0xea, - 0x9a, 0xfc, 0xbf, 0x4f, 0x1c, 0x54, 0x3a, 0x95, 0xde, 0xbf, 0x7e, 0xfe, 0xa0, 0xd5, 0x73, 0xe2, - 0x7f, 0xfd, 0xde, 0x3f, 0x01, 0x00, 0x00, 0xff, 0xff, 0xd7, 0x41, 0x25, 0x03, 0x10, 0x10, 0x00, - 0x00, + // 1383 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xb4, 0x58, 0x4f, 0x6f, 0x1b, 0x45, + 0x14, 0xcf, 0x36, 0x89, 0x63, 0xbf, 0xc4, 0x69, 0xb2, 0x49, 0x9b, 0xed, 0xa6, 0x71, 0xda, 0x0d, + 0x2d, 0x15, 0x6a, 0xec, 0xe2, 0x82, 0x28, 0x85, 0x03, 0x4d, 0x54, 0xd2, 0x50, 0x9c, 0x54, 0x1b, + 0x17, 0xa4, 0x5e, 0x56, 0xeb, 0xdd, 0xc9, 0x7a, 0x15, 0xef, 0x8e, 0xb5, 0x33, 0x8e, 0xec, 0x88, + 0x13, 0x12, 0x07, 0x6e, 0x1c, 0x90, 0x40, 0x7c, 0x01, 0xbe, 0x4a, 0xb9, 0x55, 0x9c, 0x28, 0x87, + 0x0a, 0x9a, 0x6f, 0xc0, 0x27, 0x40, 0xf3, 0x67, 0x37, 0x5e, 0x27, 0xb6, 0xe3, 0x20, 0x4e, 0x9e, + 0xf7, 0xe6, 0xfd, 0xde, 0xbf, 0x79, 0x6f, 0xe6, 0xad, 0x61, 0xc1, 0x89, 0x30, 0x21, 0x4e, 0xdd, + 0xf6, 0xc3, 0x12, 0x6d, 0x17, 0x9b, 0x11, 0xa6, 0x58, 0x5d, 0x39, 0x42, 0xd4, 0xe6, 0xbc, 0x22, + 0x5f, 0xe1, 0x08, 0x15, 0x4f, 0xe4, 0xf4, 0x05, 0x07, 0x07, 0x01, 0x0e, 0x4b, 0xe2, 0x47, 0x60, + 0xf4, 0x45, 0x0f, 0x7b, 0x98, 0x2f, 0x4b, 0x6c, 0x25, 0xb8, 0xc6, 0x0e, 0x2c, 0x54, 0x88, 0xf7, + 0xbc, 0xe9, 0xda, 0x14, 0x55, 0x09, 0x79, 0xe4, 0xba, 0x11, 0x22, 0x44, 0xd5, 0x60, 0xca, 0x89, + 0x90, 0x4d, 0x71, 0xa4, 0x29, 0x37, 0x94, 0x3b, 0x39, 0x33, 0x26, 0xd5, 0x15, 0x00, 0x4a, 0x88, + 0xd5, 0x6c, 0xd5, 0x0e, 0x50, 0x47, 0xbb, 0xc4, 0x37, 0x73, 0x94, 0x90, 0x67, 0x9c, 0x61, 0xac, + 0xc0, 0xf2, 0x19, 0xfa, 0x4c, 0x44, 0x9a, 0x38, 0x24, 0xc8, 0xf8, 0x5d, 0x81, 0xf9, 0x0a, 0xf1, + 0xbe, 0xae, 0xfb, 0x14, 0x35, 0x7c, 0x42, 0x1f, 0x9b, 0x9b, 0xe5, 0x7b, 0x03, 0xac, 0xad, 0x41, + 0x1e, 0x45, 0x4e, 0xf9, 0x9e, 0x65, 0x0b, 0x45, 0xd2, 0xe0, 0x0c, 0x67, 0xc6, 0xce, 0x5e, 0x83, + 0x2c, 0x8f, 0xdb, 0xf2, 0x5d, 0x6d, 0xfc, 0x86, 0x72, 0x67, 0xdc, 0x9c, 0xe2, 0xf4, 0xb6, 0xab, + 0xaa, 0x30, 0x11, 0xda, 0x01, 0xd2, 0x26, 0x38, 0x8c, 0xaf, 0xd5, 0xab, 0x90, 0x21, 0x9d, 0xa0, + 0x86, 0x1b, 0xda, 0x24, 0xe7, 0x4a, 0x4a, 0xd5, 0x21, 0xeb, 0x22, 0xc7, 0x0f, 0xec, 0x06, 0xd1, + 0x32, 0x37, 0x94, 0x3b, 0x79, 0x33, 0xa1, 0xd5, 0x65, 0xc8, 0x79, 0x36, 0xb1, 0x1a, 0x7e, 0xe0, + 0x53, 0x6d, 0x8a, 0xdb, 0xc8, 0x7a, 0x36, 0xf9, 0x92, 0xd1, 0x86, 0x05, 0xd7, 0x4e, 0xc5, 0x14, + 0x47, 0xcc, 0x22, 0x38, 0x4a, 0x45, 0x20, 0x22, 0x9c, 0x39, 0xea, 0x8e, 0x60, 0x05, 0xc0, 0x71, + 0x68, 0xdb, 0xf2, 0x43, 0x17, 0xb5, 0xe3, 0xa4, 0x32, 0xce, 0x36, 0x63, 0x18, 0xaf, 0x15, 0x58, + 0xac, 0x10, 0xef, 0x91, 0xeb, 0x56, 0xf1, 0x6e, 0x8b, 0x56, 0xdb, 0xd5, 0xc8, 0x76, 0x0e, 0x50, + 0x34, 0x20, 0x71, 0xdd, 0x39, 0xb9, 0x94, 0xce, 0xc9, 0x22, 0x4c, 0x86, 0x38, 0x74, 0x10, 0xcf, + 0xd5, 0x84, 0x29, 0x08, 0x75, 0x09, 0xa6, 0x68, 0xdb, 0xaa, 0xdb, 0xa4, 0x2e, 0x93, 0x95, 0xa1, + 0xed, 0x27, 0x36, 0xa9, 0xab, 0x6b, 0x30, 0xd9, 0x8c, 0x30, 0xde, 0xe7, 0xd9, 0x9a, 0x2e, 0xe7, + 0x8b, 0xb2, 0xaa, 0x9e, 0x31, 0xa6, 0x29, 0xf6, 0x58, 0x00, 0xb5, 0x06, 0x76, 0x0e, 0x84, 0x82, + 0x8c, 0x08, 0x80, 0x73, 0xb8, 0x8e, 0x6b, 0x90, 0x4d, 0xa2, 0x13, 0xd9, 0x9b, 0x8a, 0x63, 0x2b, + 0xc0, 0xf5, 0xb3, 0x42, 0x4b, 0x2a, 0x66, 0x9f, 0x27, 0xd7, 0x44, 0x01, 0x3e, 0x44, 0x9f, 0x47, + 0x38, 0xf8, 0x9f, 0xe2, 0x37, 0xd6, 0xe0, 0x66, 0x5f, 0x3b, 0x89, 0x33, 0xbf, 0x8a, 0xf2, 0xdd, + 0x64, 0x46, 0x50, 0x75, 0x6f, 0xef, 0x2b, 0x4c, 0x07, 0x7a, 0x31, 0xb8, 0x59, 0xd4, 0xf7, 0x60, + 0xee, 0x00, 0x75, 0xb6, 0x50, 0xf8, 0x02, 0x51, 0xfb, 0x09, 0xf2, 0xbd, 0x3a, 0x95, 0x05, 0x7c, + 0x8a, 0xaf, 0xae, 0x43, 0x86, 0x50, 0x9b, 0xb6, 0x08, 0x3f, 0x9e, 0xd9, 0xf2, 0x95, 0xf8, 0x1c, + 0x4c, 0xe4, 0x20, 0xff, 0x10, 0xed, 0xf1, 0x4d, 0x53, 0x0a, 0x19, 0xcb, 0x3c, 0x6d, 0x69, 0x47, + 0x93, 0x30, 0x7e, 0x56, 0x60, 0xae, 0x42, 0xbc, 0x2d, 0x9b, 0x3c, 0x8b, 0x7c, 0x07, 0x0d, 0x8b, + 0x62, 0x70, 0x2e, 0x9b, 0x4c, 0x45, 0x9c, 0x4b, 0x4e, 0xa8, 0x37, 0x61, 0x46, 0x54, 0x43, 0xd8, + 0x0a, 0x6a, 0x28, 0xe2, 0x1e, 0x4f, 0x98, 0xd3, 0x9c, 0xb7, 0xc3, 0x59, 0xbc, 0x09, 0x5b, 0xcd, + 0x66, 0xa3, 0x93, 0x34, 0x21, 0xa7, 0x0c, 0x1d, 0xb4, 0x5e, 0xcf, 0x12, 0xb7, 0x5f, 0x40, 0xbe, + 0x42, 0xbc, 0x1d, 0x76, 0x5c, 0xff, 0xcd, 0xe5, 0x33, 0x8e, 0x7f, 0x09, 0xae, 0xa4, 0x74, 0x27, + 0x46, 0x5f, 0x4f, 0xf2, 0x1b, 0x8d, 0x31, 0x77, 0xc3, 0xdd, 0x1a, 0x41, 0xd1, 0x21, 0x72, 0x77, + 0x5b, 0xb4, 0x86, 0x5b, 0xa1, 0x5b, 0x6d, 0x0f, 0xf0, 0x61, 0x19, 0x78, 0x0b, 0x8b, 0x96, 0x10, + 0x67, 0x9f, 0x65, 0x0c, 0xde, 0x11, 0x45, 0x58, 0xc0, 0x52, 0x99, 0x85, 0x59, 0xa9, 0x09, 0xb1, + 0x71, 0x2e, 0x36, 0x8f, 0x4f, 0xec, 0x54, 0x85, 0xfc, 0xa7, 0xa0, 0xf7, 0xc8, 0x8b, 0xee, 0x12, + 0x45, 0x23, 0x12, 0xac, 0xa5, 0x60, 0x1b, 0x27, 0xfb, 0xea, 0x87, 0xb0, 0xd4, 0x83, 0x66, 0xb7, + 0x59, 0x8b, 0x20, 0x57, 0x03, 0x0e, 0x5d, 0x4c, 0x41, 0xb7, 0x6c, 0xf2, 0x9c, 0x20, 0x57, 0x3d, + 0x02, 0xa3, 0x07, 0x86, 0xf6, 0xf7, 0x91, 0x43, 0xfd, 0x43, 0xc4, 0x15, 0x88, 0xa3, 0x9f, 0x66, + 0x3e, 0x6f, 0x14, 0x5f, 0xbe, 0x59, 0x1d, 0xfb, 0xf3, 0xcd, 0xea, 0x6d, 0xcf, 0xa7, 0xf5, 0x56, + 0x8d, 0x55, 0x67, 0xc9, 0xc1, 0x24, 0xc0, 0x44, 0xfe, 0xac, 0x13, 0xf7, 0xa0, 0x44, 0x3b, 0x4d, + 0x44, 0x8a, 0xdb, 0x21, 0x35, 0x0b, 0x29, 0x8b, 0x8f, 0x63, 0xbd, 0xf1, 0xc9, 0xab, 0x5f, 0x0c, + 0xb1, 0x2d, 0xae, 0xe2, 0x19, 0xee, 0x7d, 0x7f, 0x5d, 0xfc, 0x82, 0x56, 0x31, 0xcc, 0x1e, 0xda, + 0x8d, 0x16, 0xb2, 0x22, 0xd1, 0x2b, 0xae, 0x28, 0xba, 0x8d, 0x27, 0xd2, 0xe7, 0x77, 0xcf, 0xe1, + 0xf3, 0x73, 0x3f, 0xa4, 0xff, 0xbc, 0x59, 0xbd, 0xd2, 0xb1, 0x83, 0xc6, 0x43, 0x23, 0xad, 0xce, + 0x30, 0xf3, 0x9c, 0x21, 0x5b, 0xd1, 0xed, 0x6a, 0xd6, 0xcc, 0x39, 0x9a, 0x55, 0x5d, 0x85, 0x69, + 0x11, 0x22, 0xaf, 0x51, 0x79, 0x43, 0x02, 0x67, 0x6d, 0x32, 0x8e, 0x7a, 0x1b, 0x2e, 0x0b, 0x01, + 0x76, 0x9b, 0x88, 0xea, 0xcd, 0xf2, 0xc8, 0xf3, 0x9c, 0x5d, 0x25, 0x84, 0x57, 0xae, 0xba, 0x0e, + 0x39, 0x07, 0xfb, 0xa1, 0xc5, 0x5c, 0xd6, 0x72, 0xdc, 0xf4, 0x5c, 0x6c, 0x7a, 0x13, 0xfb, 0x61, + 0xb5, 0xd3, 0x44, 0x66, 0xd6, 0x91, 0x2b, 0xe3, 0x16, 0xac, 0x0d, 0x28, 0xed, 0xa4, 0x05, 0xfe, + 0x1e, 0x07, 0xfd, 0x94, 0xdc, 0x76, 0x38, 0xbc, 0x03, 0x58, 0x93, 0xa3, 0xd0, 0x45, 0x91, 0x2c, + 0x7f, 0x49, 0xb1, 0x70, 0xc4, 0xca, 0xea, 0x79, 0xb7, 0xf3, 0x82, 0xbd, 0x29, 0x5b, 0x55, 0x87, + 0xac, 0x4c, 0x71, 0x24, 0x1f, 0xa5, 0x84, 0x56, 0x6f, 0xc1, 0x6c, 0xbc, 0x96, 0x69, 0x9b, 0x14, + 0x2a, 0x62, 0xae, 0xc8, 0xdc, 0x16, 0x64, 0xec, 0x00, 0xb7, 0x42, 0x2a, 0x1e, 0xa5, 0x8d, 0xd2, + 0x88, 0x47, 0x6e, 0x4a, 0x38, 0x8b, 0x32, 0x40, 0x84, 0xd8, 0x9e, 0x48, 0x7d, 0xce, 0x8c, 0x49, + 0xf5, 0x3a, 0x00, 0x4b, 0xb9, 0xec, 0xe0, 0x9c, 0xf0, 0xd3, 0x0f, 0x65, 0xe3, 0xde, 0x86, 0xcb, + 0x7e, 0x68, 0xc9, 0xc7, 0x51, 0x74, 0xab, 0x68, 0xb9, 0xbc, 0x1f, 0x76, 0xb7, 0x68, 0x6a, 0xc2, + 0x98, 0xe6, 0x12, 0xc9, 0x84, 0x91, 0x3e, 0xd7, 0x99, 0x61, 0xe7, 0xca, 0x74, 0xd1, 0xb6, 0x85, + 0x23, 0xdf, 0xf3, 0x43, 0x2d, 0x2f, 0x1c, 0xa2, 0xed, 0x5d, 0x4e, 0xb3, 0xfb, 0xcf, 0x26, 0x04, + 0x51, 0x6d, 0x96, 0x6f, 0x08, 0xc2, 0x78, 0x07, 0x8c, 0xfe, 0x47, 0x9c, 0x54, 0xc2, 0xf7, 0x0a, + 0xcc, 0x56, 0x88, 0xb7, 0x87, 0xe8, 0x0e, 0x76, 0xd1, 0x53, 0xd4, 0x19, 0x34, 0x29, 0x96, 0x20, + 0x27, 0x1e, 0xbe, 0x3d, 0x44, 0x79, 0x01, 0x4c, 0x97, 0xe7, 0x93, 0xe1, 0xa1, 0x55, 0x7b, 0xca, + 0x37, 0xcc, 0x13, 0x19, 0xf5, 0x2e, 0xa8, 0xac, 0xbe, 0x89, 0xef, 0x85, 0x28, 0xb2, 0xe4, 0x6c, + 0x24, 0xaf, 0xc4, 0x39, 0x4a, 0xc8, 0x1e, 0xdf, 0x90, 0x7c, 0x43, 0x83, 0xab, 0x69, 0x57, 0x62, + 0x2f, 0xcb, 0xbf, 0xe5, 0x60, 0xbc, 0x42, 0x3c, 0xf5, 0x3b, 0x05, 0xe6, 0x4f, 0xcf, 0x4c, 0xf7, + 0x8b, 0x03, 0x87, 0xe7, 0xe2, 0x59, 0xd3, 0x88, 0xfe, 0xc9, 0x05, 0x40, 0xc9, 0x08, 0xf8, 0xa3, + 0x02, 0x57, 0xfb, 0x0c, 0x30, 0x0f, 0x86, 0xeb, 0x3d, 0x1b, 0xa9, 0x7f, 0x76, 0x51, 0x64, 0xe2, + 0xd6, 0x37, 0x30, 0xdb, 0x33, 0xc8, 0xdc, 0x1b, 0xae, 0x33, 0x8d, 0xd0, 0x1f, 0x8c, 0x8a, 0x48, + 0xac, 0x77, 0x20, 0x9f, 0x9e, 0x3f, 0x4a, 0xc3, 0x55, 0xa5, 0x00, 0xfa, 0x47, 0x23, 0x02, 0x12, + 0xd3, 0x4d, 0x80, 0xae, 0x21, 0xe2, 0xee, 0x70, 0x35, 0x27, 0xd2, 0xfa, 0x07, 0xa3, 0x48, 0x27, + 0x16, 0x7f, 0x51, 0x40, 0xeb, 0x3b, 0x41, 0x3c, 0x1c, 0xae, 0xb2, 0x1f, 0x56, 0xdf, 0xb8, 0x38, + 0x36, 0x71, 0xee, 0x27, 0x05, 0x96, 0xfa, 0xdd, 0xed, 0x1f, 0x8f, 0xaa, 0x3f, 0x81, 0xea, 0x8f, + 0x2e, 0x0c, 0xed, 0xae, 0xd0, 0x9e, 0x2f, 0xc5, 0x73, 0x54, 0x68, 0x1a, 0x71, 0x9e, 0x0a, 0xed, + 0xf3, 0xe5, 0xf6, 0xad, 0x02, 0x73, 0xa7, 0x3e, 0x8c, 0xcb, 0xc3, 0xd5, 0xf5, 0x62, 0xf4, 0x87, + 0xa3, 0x63, 0x62, 0x27, 0x36, 0x9e, 0xbe, 0x7c, 0x5b, 0x50, 0x5e, 0xbd, 0x2d, 0x28, 0x7f, 0xbd, + 0x2d, 0x28, 0x3f, 0x1c, 0x17, 0xc6, 0x5e, 0x1d, 0x17, 0xc6, 0xfe, 0x38, 0x2e, 0x8c, 0xbd, 0x78, + 0xbf, 0xeb, 0x05, 0x63, 0x5a, 0xd7, 0xc5, 0x7f, 0x04, 0xb1, 0x81, 0x52, 0xbb, 0xd4, 0xfd, 0xcf, + 0x01, 0x7b, 0xd0, 0x6a, 0x19, 0xfe, 0xcd, 0x7f, 0xff, 0xdf, 0x00, 0x00, 0x00, 0xff, 0xff, 0x43, + 0xc6, 0x61, 0x3f, 0x54, 0x10, 0x00, 0x00, } // Reference imports to suppress errors if they are not otherwise used. @@ -1833,6 +1850,20 @@ func (m *MsgWhitelistERC20Response) MarshalToSizedBuffer(dAtA []byte) (int, erro _ = i var l int _ = l + if len(m.CctxIndex) > 0 { + i -= len(m.CctxIndex) + copy(dAtA[i:], m.CctxIndex) + i = encodeVarintTx(dAtA, i, uint64(len(m.CctxIndex))) + i-- + dAtA[i] = 0x12 + } + if len(m.Zrc20Address) > 0 { + i -= len(m.Zrc20Address) + copy(dAtA[i:], m.Zrc20Address) + i = encodeVarintTx(dAtA, i, uint64(len(m.Zrc20Address))) + i-- + dAtA[i] = 0xa + } return len(dAtA) - i, nil } @@ -2602,6 +2633,14 @@ func (m *MsgWhitelistERC20Response) Size() (n int) { } var l int _ = l + l = len(m.Zrc20Address) + if l > 0 { + n += 1 + l + sovTx(uint64(l)) + } + l = len(m.CctxIndex) + if l > 0 { + n += 1 + l + sovTx(uint64(l)) + } return n } @@ -3353,6 +3392,70 @@ func (m *MsgWhitelistERC20Response) Unmarshal(dAtA []byte) error { return fmt.Errorf("proto: MsgWhitelistERC20Response: illegal tag %d (wire type %d)", fieldNum, wire) } switch fieldNum { + case 1: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Zrc20Address", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowTx + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + stringLen |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + intStringLen := int(stringLen) + if intStringLen < 0 { + return ErrInvalidLengthTx + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthTx + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.Zrc20Address = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + case 2: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field CctxIndex", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowTx + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + stringLen |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + intStringLen := int(stringLen) + if intStringLen < 0 { + return ErrInvalidLengthTx + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthTx + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.CctxIndex = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex default: iNdEx = preIndex skippy, err := skipTx(dAtA[iNdEx:]) diff --git a/x/fungible/types/errors.go b/x/fungible/types/errors.go index 6bfec4c107..8ab68525a3 100644 --- a/x/fungible/types/errors.go +++ b/x/fungible/types/errors.go @@ -8,29 +8,30 @@ import ( // x/fungible module sentinel errors var ( - ErrSample = sdkerrors.Register(ModuleName, 1100, "sample error") - ErrABIPack = sdkerrors.Register(ModuleName, 1101, "abi pack error") - ErrABIGet = sdkerrors.Register(ModuleName, 1102, "abi get error") - ErrUnexpectedEvent = sdkerrors.Register(ModuleName, 1103, "unexpected event") - ErrABIUnpack = sdkerrors.Register(ModuleName, 1104, "abi unpack error") - ErrBlanceQuery = sdkerrors.Register(ModuleName, 1105, "balance query error") - ErrBalanceInvariance = sdkerrors.Register(ModuleName, 1106, "balance invariance error") - ErrContractNotFound = sdkerrors.Register(ModuleName, 1107, "contract not found") - ErrChainNotFound = sdkerrors.Register(ModuleName, 1108, "chain not found") - ErrContractCall = sdkerrors.Register(ModuleName, 1109, "contract call error") - ErrSystemContractNotFound = sdkerrors.Register(ModuleName, 1110, "system contract not found") - ErrInvalidAddress = sdkerrors.Register(ModuleName, 1111, "invalid address") - ErrStateVariableNotFound = sdkerrors.Register(ModuleName, 1112, "state variable not found") - ErrDeployContract = sdkerrors.Register(ModuleName, 1113, "deploy contract error") - ErrEmitEvent = sdkerrors.Register(ModuleName, 1114, "emit event error") - ErrInvalidDecimals = sdkerrors.Register(ModuleName, 1115, "invalid decimals") - ErrGasPriceNotFound = sdkerrors.Register(ModuleName, 1116, "gas price not found") - ErrUpdateNonce = sdkerrors.Register(ModuleName, 1117, "update nonce error") - ErrInvalidGasLimit = sdkerrors.Register(ModuleName, 1118, "invalid gas limit") - ErrSetBytecode = sdkerrors.Register(ModuleName, 1119, "set bytecode error") - ErrInvalidContract = sdkerrors.Register(ModuleName, 1120, "invalid contract") - ErrPausedZRC20 = sdkerrors.Register(ModuleName, 1121, "ZRC20 is paused") - ErrForeignCoinNotFound = sdkerrors.Register(ModuleName, 1122, "foreign coin not found") - ErrForeignCoinCapReached = sdkerrors.Register(ModuleName, 1123, "foreign coin cap reached") - ErrCallNonContract = sdkerrors.Register(ModuleName, 1124, "can't call a non-contract address") + ErrSample = sdkerrors.Register(ModuleName, 1100, "sample error") + ErrABIPack = sdkerrors.Register(ModuleName, 1101, "abi pack error") + ErrABIGet = sdkerrors.Register(ModuleName, 1102, "abi get error") + ErrUnexpectedEvent = sdkerrors.Register(ModuleName, 1103, "unexpected event") + ErrABIUnpack = sdkerrors.Register(ModuleName, 1104, "abi unpack error") + ErrBlanceQuery = sdkerrors.Register(ModuleName, 1105, "balance query error") + ErrBalanceInvariance = sdkerrors.Register(ModuleName, 1106, "balance invariance error") + ErrContractNotFound = sdkerrors.Register(ModuleName, 1107, "contract not found") + ErrChainNotFound = sdkerrors.Register(ModuleName, 1108, "chain not found") + ErrContractCall = sdkerrors.Register(ModuleName, 1109, "contract call error") + ErrSystemContractNotFound = sdkerrors.Register(ModuleName, 1110, "system contract not found") + ErrInvalidAddress = sdkerrors.Register(ModuleName, 1111, "invalid address") + ErrStateVariableNotFound = sdkerrors.Register(ModuleName, 1112, "state variable not found") + ErrDeployContract = sdkerrors.Register(ModuleName, 1113, "deploy contract error") + ErrEmitEvent = sdkerrors.Register(ModuleName, 1114, "emit event error") + ErrInvalidDecimals = sdkerrors.Register(ModuleName, 1115, "invalid decimals") + ErrGasPriceNotFound = sdkerrors.Register(ModuleName, 1116, "gas price not found") + ErrUpdateNonce = sdkerrors.Register(ModuleName, 1117, "update nonce error") + ErrInvalidGasLimit = sdkerrors.Register(ModuleName, 1118, "invalid gas limit") + ErrSetBytecode = sdkerrors.Register(ModuleName, 1119, "set bytecode error") + ErrInvalidContract = sdkerrors.Register(ModuleName, 1120, "invalid contract") + ErrPausedZRC20 = sdkerrors.Register(ModuleName, 1121, "ZRC20 is paused") + ErrForeignCoinNotFound = sdkerrors.Register(ModuleName, 1122, "foreign coin not found") + ErrForeignCoinCapReached = sdkerrors.Register(ModuleName, 1123, "foreign coin cap reached") + ErrCallNonContract = sdkerrors.Register(ModuleName, 1124, "can't call a non-contract address") + ErrForeignCoinAlreadyExist = sdkerrors.Register(ModuleName, 1125, "foreign coin already exist") ) From 23d77246db11a9434443012c7c1df14a9fa09c1f Mon Sep 17 00:00:00 2001 From: Lucas Bertrand Date: Tue, 10 Oct 2023 12:00:55 -0700 Subject: [PATCH 03/27] fix(`observer`): remove error return in `IsAuthorized` (#1250) * update function * regenerate interfaces * update for crosschain --- testutil/keeper/mocks/crosschain/account.go | 2 +- testutil/keeper/mocks/crosschain/bank.go | 2 +- testutil/keeper/mocks/crosschain/fungible.go | 2 +- testutil/keeper/mocks/crosschain/observer.go | 16 +++------------- testutil/keeper/mocks/crosschain/staking.go | 2 +- testutil/keeper/mocks/fungible/account.go | 2 +- testutil/keeper/mocks/fungible/bank.go | 2 +- testutil/keeper/mocks/fungible/evm.go | 2 +- testutil/keeper/mocks/fungible/observer.go | 2 +- x/crosschain/keeper/keeper_chain_nonces.go | 10 ++++------ .../keeper_cross_chain_tx_vote_inbound_tx.go | 5 ++--- .../keeper_cross_chain_tx_vote_outbound_tx.go | 5 ++--- x/crosschain/keeper/keeper_gas_price.go | 9 ++++----- x/crosschain/keeper/keeper_out_tx_tracker.go | 7 ++----- x/crosschain/types/expected_keepers.go | 2 +- x/observer/keeper/keeper_utils.go | 8 ++++---- x/observer/keeper/msg_server_add_blame_vote.go | 5 ++--- x/observer/keeper/msg_server_add_block_header.go | 5 ++--- 18 files changed, 34 insertions(+), 54 deletions(-) diff --git a/testutil/keeper/mocks/crosschain/account.go b/testutil/keeper/mocks/crosschain/account.go index bde82aa1df..69df546af1 100644 --- a/testutil/keeper/mocks/crosschain/account.go +++ b/testutil/keeper/mocks/crosschain/account.go @@ -1,4 +1,4 @@ -// Code generated by mockery v2.34.2. DO NOT EDIT. +// Code generated by mockery v2.35.2. DO NOT EDIT. package mocks diff --git a/testutil/keeper/mocks/crosschain/bank.go b/testutil/keeper/mocks/crosschain/bank.go index bf4e73987b..8b4e4c1b04 100644 --- a/testutil/keeper/mocks/crosschain/bank.go +++ b/testutil/keeper/mocks/crosschain/bank.go @@ -1,4 +1,4 @@ -// Code generated by mockery v2.34.2. DO NOT EDIT. +// Code generated by mockery v2.35.2. DO NOT EDIT. package mocks diff --git a/testutil/keeper/mocks/crosschain/fungible.go b/testutil/keeper/mocks/crosschain/fungible.go index ba803b9a52..1a1452f5c7 100644 --- a/testutil/keeper/mocks/crosschain/fungible.go +++ b/testutil/keeper/mocks/crosschain/fungible.go @@ -1,4 +1,4 @@ -// Code generated by mockery v2.34.2. DO NOT EDIT. +// Code generated by mockery v2.35.2. DO NOT EDIT. package mocks diff --git a/testutil/keeper/mocks/crosschain/observer.go b/testutil/keeper/mocks/crosschain/observer.go index 0f1d2b310c..8ddc1504cd 100644 --- a/testutil/keeper/mocks/crosschain/observer.go +++ b/testutil/keeper/mocks/crosschain/observer.go @@ -1,4 +1,4 @@ -// Code generated by mockery v2.34.2. DO NOT EDIT. +// Code generated by mockery v2.35.2. DO NOT EDIT. package mocks @@ -333,27 +333,17 @@ func (_m *CrosschainObserverKeeper) GetParams(ctx types.Context) observertypes.P } // IsAuthorized provides a mock function with given fields: ctx, address, chain -func (_m *CrosschainObserverKeeper) IsAuthorized(ctx types.Context, address string, chain *common.Chain) (bool, error) { +func (_m *CrosschainObserverKeeper) IsAuthorized(ctx types.Context, address string, chain *common.Chain) bool { ret := _m.Called(ctx, address, chain) var r0 bool - var r1 error - if rf, ok := ret.Get(0).(func(types.Context, string, *common.Chain) (bool, error)); ok { - return rf(ctx, address, chain) - } if rf, ok := ret.Get(0).(func(types.Context, string, *common.Chain) bool); ok { r0 = rf(ctx, address, chain) } else { r0 = ret.Get(0).(bool) } - if rf, ok := ret.Get(1).(func(types.Context, string, *common.Chain) error); ok { - r1 = rf(ctx, address, chain) - } else { - r1 = ret.Error(1) - } - - return r0, r1 + return r0 } // IsInboundEnabled provides a mock function with given fields: ctx diff --git a/testutil/keeper/mocks/crosschain/staking.go b/testutil/keeper/mocks/crosschain/staking.go index 0faf55a58a..7288ae4125 100644 --- a/testutil/keeper/mocks/crosschain/staking.go +++ b/testutil/keeper/mocks/crosschain/staking.go @@ -1,4 +1,4 @@ -// Code generated by mockery v2.34.2. DO NOT EDIT. +// Code generated by mockery v2.35.2. DO NOT EDIT. package mocks diff --git a/testutil/keeper/mocks/fungible/account.go b/testutil/keeper/mocks/fungible/account.go index 81f510c6d3..6a77932f69 100644 --- a/testutil/keeper/mocks/fungible/account.go +++ b/testutil/keeper/mocks/fungible/account.go @@ -1,4 +1,4 @@ -// Code generated by mockery v2.34.2. DO NOT EDIT. +// Code generated by mockery v2.35.2. DO NOT EDIT. package mocks diff --git a/testutil/keeper/mocks/fungible/bank.go b/testutil/keeper/mocks/fungible/bank.go index da56574169..d04228faf7 100644 --- a/testutil/keeper/mocks/fungible/bank.go +++ b/testutil/keeper/mocks/fungible/bank.go @@ -1,4 +1,4 @@ -// Code generated by mockery v2.34.2. DO NOT EDIT. +// Code generated by mockery v2.35.2. DO NOT EDIT. package mocks diff --git a/testutil/keeper/mocks/fungible/evm.go b/testutil/keeper/mocks/fungible/evm.go index e0ac00173c..fe04262d80 100644 --- a/testutil/keeper/mocks/fungible/evm.go +++ b/testutil/keeper/mocks/fungible/evm.go @@ -1,4 +1,4 @@ -// Code generated by mockery v2.34.2. DO NOT EDIT. +// Code generated by mockery v2.35.2. DO NOT EDIT. package mocks diff --git a/testutil/keeper/mocks/fungible/observer.go b/testutil/keeper/mocks/fungible/observer.go index fc7ec327b6..d627f7d980 100644 --- a/testutil/keeper/mocks/fungible/observer.go +++ b/testutil/keeper/mocks/fungible/observer.go @@ -1,4 +1,4 @@ -// Code generated by mockery v2.34.2. DO NOT EDIT. +// Code generated by mockery v2.35.2. DO NOT EDIT. package mocks diff --git a/x/crosschain/keeper/keeper_chain_nonces.go b/x/crosschain/keeper/keeper_chain_nonces.go index 90291845ed..7ecd816075 100644 --- a/x/crosschain/keeper/keeper_chain_nonces.go +++ b/x/crosschain/keeper/keeper_chain_nonces.go @@ -4,13 +4,12 @@ import ( "context" "fmt" - zetaObserverTypes "github.com/zeta-chain/zetacore/x/observer/types" - "github.com/cosmos/cosmos-sdk/store/prefix" sdk "github.com/cosmos/cosmos-sdk/types" sdkerrors "github.com/cosmos/cosmos-sdk/types/errors" "github.com/cosmos/cosmos-sdk/types/query" "github.com/zeta-chain/zetacore/x/crosschain/types" + observertypes "github.com/zeta-chain/zetacore/x/observer/types" "google.golang.org/grpc/codes" "google.golang.org/grpc/status" ) @@ -108,12 +107,11 @@ func (k msgServer) NonceVoter(goCtx context.Context, msg *types.MsgNonceVoter) ( ctx := sdk.UnwrapSDKContext(goCtx) chain := k.zetaObserverKeeper.GetParams(ctx).GetChainFromChainID(msg.ChainId) if chain == nil { - return nil, zetaObserverTypes.ErrSupportedChains + return nil, observertypes.ErrSupportedChains } - ok, err := k.zetaObserverKeeper.IsAuthorized(ctx, msg.Creator, chain) - if !ok { - return nil, err + if ok := k.zetaObserverKeeper.IsAuthorized(ctx, msg.Creator, chain); !ok { + return nil, observertypes.ErrNotAuthorizedPolicy } chainNonce, isFound := k.GetChainNonces(ctx, chain.ChainName.String()) diff --git a/x/crosschain/keeper/keeper_cross_chain_tx_vote_inbound_tx.go b/x/crosschain/keeper/keeper_cross_chain_tx_vote_inbound_tx.go index 62c7813976..a384c320ba 100644 --- a/x/crosschain/keeper/keeper_cross_chain_tx_vote_inbound_tx.go +++ b/x/crosschain/keeper/keeper_cross_chain_tx_vote_inbound_tx.go @@ -77,9 +77,8 @@ func (k msgServer) VoteOnObservedInboundTx(goCtx context.Context, msg *types.Msg tssPub = tss.TssPubkey } // IsAuthorized does various checks against the list of observer mappers - ok, err := k.zetaObserverKeeper.IsAuthorized(ctx, msg.Creator, observationChain) - if !ok { - return nil, err + if ok := k.zetaObserverKeeper.IsAuthorized(ctx, msg.Creator, observationChain); !ok { + return nil, observerTypes.ErrNotAuthorizedPolicy } index := msg.Digest() diff --git a/x/crosschain/keeper/keeper_cross_chain_tx_vote_outbound_tx.go b/x/crosschain/keeper/keeper_cross_chain_tx_vote_outbound_tx.go index f8b845a925..f7d781bfd2 100644 --- a/x/crosschain/keeper/keeper_cross_chain_tx_vote_outbound_tx.go +++ b/x/crosschain/keeper/keeper_cross_chain_tx_vote_outbound_tx.go @@ -73,9 +73,8 @@ func (k msgServer) VoteOnObservedOutboundTx(goCtx context.Context, msg *types.Ms return nil, err } //Check is msg.Creator is authorized to vote - ok, err := k.zetaObserverKeeper.IsAuthorized(ctx, msg.Creator, observationChain) - if !ok { - return nil, err + if ok := k.zetaObserverKeeper.IsAuthorized(ctx, msg.Creator, observationChain); !ok { + return nil, observerTypes.ErrNotAuthorizedPolicy } // Check if CCTX exists diff --git a/x/crosschain/keeper/keeper_gas_price.go b/x/crosschain/keeper/keeper_gas_price.go index 63ea8e527f..50a103bec9 100644 --- a/x/crosschain/keeper/keeper_gas_price.go +++ b/x/crosschain/keeper/keeper_gas_price.go @@ -13,7 +13,7 @@ import ( sdkerrors "github.com/cosmos/cosmos-sdk/types/errors" "github.com/cosmos/cosmos-sdk/types/query" "github.com/zeta-chain/zetacore/x/crosschain/types" - zetaObserverTypes "github.com/zeta-chain/zetacore/x/observer/types" + observertypes "github.com/zeta-chain/zetacore/x/observer/types" "google.golang.org/grpc/codes" "google.golang.org/grpc/status" ) @@ -127,11 +127,10 @@ func (k msgServer) GasPriceVoter(goCtx context.Context, msg *types.MsgGasPriceVo chain := k.zetaObserverKeeper.GetParams(ctx).GetChainFromChainID(msg.ChainId) if chain == nil { - return nil, zetaObserverTypes.ErrSupportedChains + return nil, observertypes.ErrSupportedChains } - ok, err := k.zetaObserverKeeper.IsAuthorized(ctx, msg.Creator, chain) - if !ok { - return nil, err + if ok := k.zetaObserverKeeper.IsAuthorized(ctx, msg.Creator, chain); !ok { + return nil, observertypes.ErrNotAuthorizedPolicy } if chain == nil { return nil, sdkerrors.Wrap(types.ErrUnsupportedChain, fmt.Sprintf("ChainID : %d ", msg.ChainId)) diff --git a/x/crosschain/keeper/keeper_out_tx_tracker.go b/x/crosschain/keeper/keeper_out_tx_tracker.go index 5053687bd4..a11329aea2 100644 --- a/x/crosschain/keeper/keeper_out_tx_tracker.go +++ b/x/crosschain/keeper/keeper_out_tx_tracker.go @@ -173,11 +173,8 @@ func (k msgServer) AddToOutTxTracker(goCtx context.Context, msg *types.MsgAddToO adminPolicyAccount := k.zetaObserverKeeper.GetParams(ctx).GetAdminPolicyAccount(observertypes.Policy_Type_group1) isAdmin := msg.Creator == adminPolicyAccount - isObserver, err := k.zetaObserverKeeper.IsAuthorized(ctx, msg.Creator, chain) - if err != nil { - ctx.Logger().Error("Error while checking if the account is an observer", err) - return nil, cosmoserrors.Wrap(observertypes.ErrNotAuthorized, fmt.Sprintf("error IsAuthorized %s", msg.Creator)) - } + isObserver := k.zetaObserverKeeper.IsAuthorized(ctx, msg.Creator, chain) + // Sender needs to be either the admin policy account or an observer if !(isAdmin || isObserver) { return nil, cosmoserrors.Wrap(observertypes.ErrNotAuthorized, fmt.Sprintf("Creator %s", msg.Creator)) diff --git a/x/crosschain/types/expected_keepers.go b/x/crosschain/types/expected_keepers.go index fc5960b5e5..5b83869099 100644 --- a/x/crosschain/types/expected_keepers.go +++ b/x/crosschain/types/expected_keepers.go @@ -63,7 +63,7 @@ type ZetaObserverKeeper interface { SetLastObserverCount(ctx sdk.Context, lbc *zetaObserverTypes.LastObserverCount) AddVoteToBallot(ctx sdk.Context, ballot zetaObserverTypes.Ballot, address string, observationType zetaObserverTypes.VoteType) (zetaObserverTypes.Ballot, error) CheckIfFinalizingVote(ctx sdk.Context, ballot zetaObserverTypes.Ballot) (zetaObserverTypes.Ballot, bool) - IsAuthorized(ctx sdk.Context, address string, chain *common.Chain) (bool, error) + IsAuthorized(ctx sdk.Context, address string, chain *common.Chain) bool FindBallot(ctx sdk.Context, index string, chain *common.Chain, observationType zetaObserverTypes.ObservationType) (ballot zetaObserverTypes.Ballot, isNew bool, err error) AddBallotToList(ctx sdk.Context, ballot zetaObserverTypes.Ballot) GetBlockHeader(ctx sdk.Context, hash []byte) (val common.BlockHeader, found bool) diff --git a/x/observer/keeper/keeper_utils.go b/x/observer/keeper/keeper_utils.go index e36cd8e934..8424985d31 100644 --- a/x/observer/keeper/keeper_utils.go +++ b/x/observer/keeper/keeper_utils.go @@ -32,17 +32,17 @@ func (k Keeper) CheckIfFinalizingVote(ctx sdk.Context, ballot types.Ballot) (typ } // IsAuthorized checks whether a signer is authorized to sign , by checking their address against the observer mapper which contains the observer list for the chain and type -func (k Keeper) IsAuthorized(ctx sdk.Context, address string, chain *common.Chain) (bool, error) { +func (k Keeper) IsAuthorized(ctx sdk.Context, address string, chain *common.Chain) bool { observerMapper, found := k.GetObserverMapper(ctx, chain) if !found { - return false, errors.Wrap(types.ErrNotAuthorized, fmt.Sprintf("observer list not present for chain %s", chain.String())) + return false } for _, obs := range observerMapper.ObserverList { if obs == address { - return true, nil + return true } } - return false, errors.Wrap(types.ErrNotAuthorized, fmt.Sprintf("address: %s", address)) + return false } func (k Keeper) FindBallot(ctx sdk.Context, index string, chain *common.Chain, observationType types.ObservationType) (ballot types.Ballot, isNew bool, err error) { diff --git a/x/observer/keeper/msg_server_add_blame_vote.go b/x/observer/keeper/msg_server_add_blame_vote.go index b21bd30c69..1330cc4815 100644 --- a/x/observer/keeper/msg_server_add_blame_vote.go +++ b/x/observer/keeper/msg_server_add_blame_vote.go @@ -19,9 +19,8 @@ func (k msgServer) AddBlameVote(goCtx context.Context, vote *types.MsgAddBlameVo return nil, sdkerrors.Wrap(crosschainTypes.ErrUnsupportedChain, fmt.Sprintf("ChainID %d, Blame vote", vote.ChainId)) } // IsAuthorized does various checks against the list of observer mappers - ok, err := k.IsAuthorized(ctx, vote.Creator, observationChain) - if !ok { - return nil, err + if ok := k.IsAuthorized(ctx, vote.Creator, observationChain); !ok { + return nil, types.ErrNotAuthorizedPolicy } index := vote.Digest() diff --git a/x/observer/keeper/msg_server_add_block_header.go b/x/observer/keeper/msg_server_add_block_header.go index 8ee4ffa5cd..185fd9d061 100644 --- a/x/observer/keeper/msg_server_add_block_header.go +++ b/x/observer/keeper/msg_server_add_block_header.go @@ -17,9 +17,8 @@ func (k msgServer) AddBlockHeader(goCtx context.Context, msg *types.MsgAddBlockH // check authorization for this chain chain := common.GetChainFromChainID(msg.ChainId) - ok, err := k.IsAuthorized(ctx, msg.Creator, chain) - if !ok { - return nil, cosmoserrors.Wrap(types.ErrNotAuthorizedPolicy, err.Error()) + if ok := k.IsAuthorized(ctx, msg.Creator, chain); !ok { + return nil, types.ErrNotAuthorizedPolicy } // add vote to ballot From aa94a913cc77cf4ae9d2814c4fff371c7a34d9f5 Mon Sep 17 00:00:00 2001 From: Lucas Bertrand Date: Tue, 10 Oct 2023 13:29:47 -0700 Subject: [PATCH 04/27] fix(`GetForeignCoinFromAsset`): Ethereum comparaison checksum/non-checksum format (#1261) * fix error message * compare with ETH address type * tests * goimport --------- Co-authored-by: brewmaster012 <88689859+brewmaster012@users.noreply.github.com> --- x/crosschain/types/errors.go | 4 +- x/fungible/keeper/foreign_coins.go | 9 +- x/fungible/keeper/foreign_coins_test.go | 120 ++++++++++++++---------- 3 files changed, 81 insertions(+), 52 deletions(-) diff --git a/x/crosschain/types/errors.go b/x/crosschain/types/errors.go index ac6a1497f5..da0674b5c3 100644 --- a/x/crosschain/types/errors.go +++ b/x/crosschain/types/errors.go @@ -12,10 +12,10 @@ var ( ErrNotEnoughZetaBurnt = errorsmod.Register(ModuleName, 1109, "not enough zeta burnt") ErrCannotFindReceiverNonce = errorsmod.Register(ModuleName, 1110, "cannot find receiver chain nonce") - ErrGasCoinNotFound = errorsmod.Register(ModuleName, 1113, "gas coin not found for SenderChain") + ErrGasCoinNotFound = errorsmod.Register(ModuleName, 1113, "gas coin not found for sender chain") ErrUnableToParseAddress = errorsmod.Register(ModuleName, 1115, "cannot parse address and data") ErrCannotProcessWithdrawal = errorsmod.Register(ModuleName, 1116, "cannot process withdrawal event") - ErrForeignCoinNotFound = errorsmod.Register(ModuleName, 1118, "gas coin not found for SenderChain") + ErrForeignCoinNotFound = errorsmod.Register(ModuleName, 1118, "foreign coin not found for sender chain") ErrNotEnoughPermissions = errorsmod.Register(ModuleName, 1119, "not enough permissions for current actions") ErrCannotFindPendingNonces = errorsmod.Register(ModuleName, 1121, "cannot find pending nonces") diff --git a/x/fungible/keeper/foreign_coins.go b/x/fungible/keeper/foreign_coins.go index 7450b66cd8..faa96d2876 100644 --- a/x/fungible/keeper/foreign_coins.go +++ b/x/fungible/keeper/foreign_coins.go @@ -5,6 +5,7 @@ import ( "github.com/cosmos/cosmos-sdk/store/prefix" sdk "github.com/cosmos/cosmos-sdk/types" + ethcommon "github.com/ethereum/go-ethereum/common" "github.com/zeta-chain/zetacore/common" "github.com/zeta-chain/zetacore/x/fungible/types" ) @@ -93,9 +94,15 @@ func (k Keeper) GetGasCoinForForeignCoin(ctx sdk.Context, chainID int64) (types. // GetForeignCoinFromAsset returns the foreign coin for a given asset for a given chain func (k Keeper) GetForeignCoinFromAsset(ctx sdk.Context, asset string, chainID int64) (types.ForeignCoins, bool) { + if !ethcommon.IsHexAddress(asset) { + return types.ForeignCoins{}, false + } + assetAddr := ethcommon.HexToAddress(asset) + foreignCoinList := k.GetAllForeignCoinsForChain(ctx, chainID) for _, coin := range foreignCoinList { - if coin.Asset == asset && coin.ForeignChainId == chainID { + coinAssetAddr := ethcommon.HexToAddress(coin.Asset) + if coinAssetAddr == assetAddr && coin.ForeignChainId == chainID { return coin, true } } diff --git a/x/fungible/keeper/foreign_coins_test.go b/x/fungible/keeper/foreign_coins_test.go index 347630002d..0a5a0f37f0 100644 --- a/x/fungible/keeper/foreign_coins_test.go +++ b/x/fungible/keeper/foreign_coins_test.go @@ -77,56 +77,78 @@ func TestKeeper_GetGasCoinForForeignCoin(t *testing.T) { } func TestKeeperGetForeignCoinFromAsset(t *testing.T) { - k, ctx, _, _ := keepertest.FungibleKeeper(t) + t.Run("can get foreign coin from asset", func(t *testing.T) { + k, ctx, _, _ := keepertest.FungibleKeeper(t) - gasAsset := sample.EthAddress().String() + gasAsset := sample.EthAddress().String() - // populate - setForeignCoins(ctx, k, - types.ForeignCoins{ - Zrc20ContractAddress: sample.EthAddress().String(), - Asset: sample.EthAddress().String(), - ForeignChainId: 1, - CoinType: common.CoinType_ERC20, - Name: "foo", - }, - types.ForeignCoins{ - Zrc20ContractAddress: sample.EthAddress().String(), - Asset: gasAsset, - ForeignChainId: 1, - CoinType: common.CoinType_ERC20, - Name: "bar", - }, - types.ForeignCoins{ - Zrc20ContractAddress: sample.EthAddress().String(), - Asset: sample.EthAddress().String(), - ForeignChainId: 1, - CoinType: common.CoinType_Gas, - Name: "foo", - }, - types.ForeignCoins{ - Zrc20ContractAddress: sample.EthAddress().String(), - Asset: sample.EthAddress().String(), - ForeignChainId: 2, - CoinType: common.CoinType_ERC20, - Name: "foo", - }, - types.ForeignCoins{ - Zrc20ContractAddress: sample.EthAddress().String(), - Asset: sample.EthAddress().String(), - ForeignChainId: 2, - CoinType: common.CoinType_ERC20, - Name: "foo", - }, - ) + // populate + setForeignCoins(ctx, k, + types.ForeignCoins{ + Zrc20ContractAddress: sample.EthAddress().String(), + Asset: sample.EthAddress().String(), + ForeignChainId: 1, + CoinType: common.CoinType_ERC20, + Name: "foo", + }, + types.ForeignCoins{ + Zrc20ContractAddress: sample.EthAddress().String(), + Asset: gasAsset, + ForeignChainId: 1, + CoinType: common.CoinType_ERC20, + Name: "bar", + }, + types.ForeignCoins{ + Zrc20ContractAddress: sample.EthAddress().String(), + Asset: sample.EthAddress().String(), + ForeignChainId: 1, + CoinType: common.CoinType_Gas, + Name: "foo", + }, + types.ForeignCoins{ + Zrc20ContractAddress: sample.EthAddress().String(), + Asset: sample.EthAddress().String(), + ForeignChainId: 2, + CoinType: common.CoinType_ERC20, + Name: "foo", + }, + types.ForeignCoins{ + Zrc20ContractAddress: sample.EthAddress().String(), + Asset: sample.EthAddress().String(), + ForeignChainId: 2, + CoinType: common.CoinType_ERC20, + Name: "foo", + }, + ) - fc, found := k.GetForeignCoinFromAsset(ctx, gasAsset, 1) - require.True(t, found) - require.Equal(t, "bar", fc.Name) - fc, found = k.GetForeignCoinFromAsset(ctx, sample.EthAddress().String(), 1) - require.False(t, found) - fc, found = k.GetForeignCoinFromAsset(ctx, gasAsset, 2) - require.False(t, found) - fc, found = k.GetForeignCoinFromAsset(ctx, gasAsset, 3) - require.False(t, found) + fc, found := k.GetForeignCoinFromAsset(ctx, gasAsset, 1) + require.True(t, found) + require.Equal(t, "bar", fc.Name) + fc, found = k.GetForeignCoinFromAsset(ctx, sample.EthAddress().String(), 1) + require.False(t, found) + fc, found = k.GetForeignCoinFromAsset(ctx, "invalid_address", 1) + require.False(t, found) + fc, found = k.GetForeignCoinFromAsset(ctx, gasAsset, 2) + require.False(t, found) + fc, found = k.GetForeignCoinFromAsset(ctx, gasAsset, 3) + require.False(t, found) + }) + + t.Run("can get foreign coin with non-checksum address", func(t *testing.T) { + k, ctx, _, _ := keepertest.FungibleKeeper(t) + + setForeignCoins(ctx, k, + types.ForeignCoins{ + Zrc20ContractAddress: sample.EthAddress().String(), + Asset: "0xa0b86991c6218b36c1d19d4a2e9eb0ce3606eb48", + ForeignChainId: 1, + CoinType: common.CoinType_ERC20, + Name: "foo", + }, + ) + + fc, found := k.GetForeignCoinFromAsset(ctx, "0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48", 1) + require.True(t, found) + require.Equal(t, "foo", fc.Name) + }) } From ed35305f67fd76f943f79ef0473de8ea4aae8b88 Mon Sep 17 00:00:00 2001 From: Lucas Bertrand Date: Tue, 10 Oct 2023 13:58:43 -0700 Subject: [PATCH 05/27] feat(`fungible`): add ability to update gas limit (#1260) * add new field * update message type * message new logic --- docs/spec/fungible/messages.md | 1 + proto/fungible/events.proto | 2 + proto/fungible/tx.proto | 4 + x/crosschain/keeper/gas_payment_test.go | 12 +- ...blocker_deploy_system_contracts_privnet.go | 9 +- x/fungible/keeper/evm.go | 62 +++++- .../msg_server_update_zrc20_withdraw_fee.go | 37 ++-- ...g_server_update_zrc20_withdraw_fee_test.go | 141 ++++++++++++-- x/fungible/types/events.pb.go | 178 ++++++++++++++---- .../message_update_zrc20_withdraw_fee.go | 16 +- .../message_update_zrc20_withdraw_fee_test.go | 52 ++++- x/fungible/types/tx.pb.go | 164 ++++++++++------ 12 files changed, 527 insertions(+), 151 deletions(-) diff --git a/docs/spec/fungible/messages.md b/docs/spec/fungible/messages.md index 3977d2212c..984455ff41 100644 --- a/docs/spec/fungible/messages.md +++ b/docs/spec/fungible/messages.md @@ -78,6 +78,7 @@ message MsgUpdateZRC20WithdrawFee { string creator = 1; string zrc20_address = 2; string new_withdraw_fee = 6; + string new_gas_limit = 7; } ``` diff --git a/proto/fungible/events.proto b/proto/fungible/events.proto index 37c4feb10f..4c66f1a940 100644 --- a/proto/fungible/events.proto +++ b/proto/fungible/events.proto @@ -34,6 +34,8 @@ message EventZRC20WithdrawFeeUpdated { string old_withdraw_fee = 5; string new_withdraw_fee = 6; string signer = 7; + string old_gas_limit = 8; + string new_gas_limit = 9; } message EventZRC20PausedStatusUpdated { diff --git a/proto/fungible/tx.proto b/proto/fungible/tx.proto index aa5161a592..34608edb22 100644 --- a/proto/fungible/tx.proto +++ b/proto/fungible/tx.proto @@ -24,6 +24,10 @@ message MsgUpdateZRC20WithdrawFee { (gogoproto.customtype) = "github.com/cosmos/cosmos-sdk/types.Uint", (gogoproto.nullable) = false ]; + string new_gas_limit = 7 [ + (gogoproto.customtype) = "github.com/cosmos/cosmos-sdk/types.Uint", + (gogoproto.nullable) = false + ]; } message MsgUpdateZRC20WithdrawFeeResponse {} diff --git a/x/crosschain/keeper/gas_payment_test.go b/x/crosschain/keeper/gas_payment_test.go index f76d878607..e110017694 100644 --- a/x/crosschain/keeper/gas_payment_test.go +++ b/x/crosschain/keeper/gas_payment_test.go @@ -232,7 +232,7 @@ func TestKeeper_PayGasNativeAndUpdateCctx(t *testing.T) { zrc20 := setupGasCoin(t, ctx, zk.FungibleKeeper, sdkk.EvmKeeper, chainID, "foobar", "foobar") _, err := zk.FungibleKeeper.UpdateZRC20WithdrawFee( sdk.UnwrapSDKContext(ctx), - fungibletypes.NewMsgUpdateZRC20WithdrawFee(admin, zrc20.String(), sdk.NewUint(withdrawFee)), + fungibletypes.NewMsgUpdateZRC20WithdrawFee(admin, zrc20.String(), sdk.NewUint(withdrawFee), math.Uint{}), ) require.NoError(t, err) k.SetGasPrice(ctx, types.GasPrice{ @@ -330,7 +330,7 @@ func TestKeeper_PayGasNativeAndUpdateCctx(t *testing.T) { zrc20 := setupGasCoin(t, ctx, zk.FungibleKeeper, sdkk.EvmKeeper, chainID, "foobar", "foobar") _, err := zk.FungibleKeeper.UpdateZRC20WithdrawFee( sdk.UnwrapSDKContext(ctx), - fungibletypes.NewMsgUpdateZRC20WithdrawFee(admin, zrc20.String(), sdk.NewUint(withdrawFee)), + fungibletypes.NewMsgUpdateZRC20WithdrawFee(admin, zrc20.String(), sdk.NewUint(withdrawFee), math.Uint{}), ) require.NoError(t, err) k.SetGasPrice(ctx, types.GasPrice{ @@ -384,7 +384,7 @@ func TestKeeper_PayGasInERC20AndUpdateCctx(t *testing.T) { ) _, err := zk.FungibleKeeper.UpdateZRC20WithdrawFee( sdk.UnwrapSDKContext(ctx), - fungibletypes.NewMsgUpdateZRC20WithdrawFee(admin, gasZRC20.String(), sdk.NewUint(withdrawFee)), + fungibletypes.NewMsgUpdateZRC20WithdrawFee(admin, gasZRC20.String(), sdk.NewUint(withdrawFee), math.Uint{}), ) require.NoError(t, err) k.SetGasPrice(ctx, types.GasPrice{ @@ -497,7 +497,7 @@ func TestKeeper_PayGasInERC20AndUpdateCctx(t *testing.T) { gasZRC20 := setupGasCoin(t, ctx, zk.FungibleKeeper, sdkk.EvmKeeper, chainID, "foo", "foo") _, err := zk.FungibleKeeper.UpdateZRC20WithdrawFee( sdk.UnwrapSDKContext(ctx), - fungibletypes.NewMsgUpdateZRC20WithdrawFee(admin, gasZRC20.String(), sdk.NewUint(withdrawFee)), + fungibletypes.NewMsgUpdateZRC20WithdrawFee(admin, gasZRC20.String(), sdk.NewUint(withdrawFee), math.Uint{}), ) require.NoError(t, err) k.SetGasPrice(ctx, types.GasPrice{ @@ -551,7 +551,7 @@ func TestKeeper_PayGasInERC20AndUpdateCctx(t *testing.T) { ) _, err := zk.FungibleKeeper.UpdateZRC20WithdrawFee( sdk.UnwrapSDKContext(ctx), - fungibletypes.NewMsgUpdateZRC20WithdrawFee(admin, gasZRC20.String(), sdk.NewUint(withdrawFee)), + fungibletypes.NewMsgUpdateZRC20WithdrawFee(admin, gasZRC20.String(), sdk.NewUint(withdrawFee), math.Uint{}), ) require.NoError(t, err) k.SetGasPrice(ctx, types.GasPrice{ @@ -605,7 +605,7 @@ func TestKeeper_PayGasInERC20AndUpdateCctx(t *testing.T) { ) _, err := zk.FungibleKeeper.UpdateZRC20WithdrawFee( sdk.UnwrapSDKContext(ctx), - fungibletypes.NewMsgUpdateZRC20WithdrawFee(admin, gasZRC20.String(), sdk.NewUint(withdrawFee)), + fungibletypes.NewMsgUpdateZRC20WithdrawFee(admin, gasZRC20.String(), sdk.NewUint(withdrawFee), math.Uint{}), ) require.NoError(t, err) k.SetGasPrice(ctx, types.GasPrice{ diff --git a/x/fungible/keeper/begin_blocker_deploy_system_contracts_privnet.go b/x/fungible/keeper/begin_blocker_deploy_system_contracts_privnet.go index 18301cb3d8..803510d38d 100644 --- a/x/fungible/keeper/begin_blocker_deploy_system_contracts_privnet.go +++ b/x/fungible/keeper/begin_blocker_deploy_system_contracts_privnet.go @@ -7,6 +7,8 @@ import ( "fmt" "math/big" + "cosmossdk.io/math" + sdk "github.com/cosmos/cosmos-sdk/types" sdkerrors "github.com/cosmos/cosmos-sdk/types/errors" "github.com/zeta-chain/zetacore/common" @@ -146,7 +148,12 @@ func (k Keeper) TestUpdateZRC20WithdrawFee(goCtx context.Context) error { creator := k.observerKeeper.GetParams(ctx).GetAdminPolicyAccount(observertypes.Policy_Type_group1) for _, foreignCoin := range foreignCoins { - msg := types.NewMsgUpdateZRC20WithdrawFee(creator, foreignCoin.Zrc20ContractAddress, sdk.NewUint(uint64(foreignCoin.ForeignChainId))) + msg := types.NewMsgUpdateZRC20WithdrawFee( + creator, + foreignCoin.Zrc20ContractAddress, + sdk.NewUint(uint64(foreignCoin.ForeignChainId)), + math.Uint{}, + ) _, err := k.UpdateZRC20WithdrawFee(ctx, msg) if err != nil { return err diff --git a/x/fungible/keeper/evm.go b/x/fungible/keeper/evm.go index f176cf71c3..8606804bea 100644 --- a/x/fungible/keeper/evm.go +++ b/x/fungible/keeper/evm.go @@ -201,7 +201,67 @@ func (k Keeper) DepositZRC20( if err != nil { return nil, err } - return k.CallEVM(ctx, *zrc20ABI, types.ModuleAddressEVM, contract, BigIntZero, nil, true, false, "deposit", to, amount) + return k.CallEVM( + ctx, + *zrc20ABI, + types.ModuleAddressEVM, + contract, + BigIntZero, + nil, + true, + false, + "deposit", + to, + amount, + ) +} + +// UpdateZRC20ProtocolFlatFee updates the protocol flat fee for a given ZRC20 contract +func (k Keeper) UpdateZRC20ProtocolFlatFee( + ctx sdk.Context, + zrc20Addr common.Address, + newFee *big.Int, +) (*evmtypes.MsgEthereumTxResponse, error) { + zrc20ABI, err := zrc20.ZRC20MetaData.GetAbi() + if err != nil { + return nil, err + } + return k.CallEVM( + ctx, + *zrc20ABI, + types.ModuleAddressEVM, + zrc20Addr, + BigIntZero, + nil, + true, + false, + "updateProtocolFlatFee", + newFee, + ) +} + +// UpdateZRC20GasLimit updates the gas limit for a given ZRC20 contract +func (k Keeper) UpdateZRC20GasLimit( + ctx sdk.Context, + zrc20Addr common.Address, + newGasLimit *big.Int, +) (*evmtypes.MsgEthereumTxResponse, error) { + zrc20ABI, err := zrc20.ZRC20MetaData.GetAbi() + if err != nil { + return nil, err + } + return k.CallEVM( + ctx, + *zrc20ABI, + types.ModuleAddressEVM, + zrc20Addr, + BigIntZero, + nil, + true, + false, + "updateGasLimit", + newGasLimit, + ) } // DepositZRC20AndCallContract deposits into ZRC4 and call contract function in a single tx diff --git a/x/fungible/keeper/msg_server_update_zrc20_withdraw_fee.go b/x/fungible/keeper/msg_server_update_zrc20_withdraw_fee.go index 7c72496770..2cdb6f30b0 100644 --- a/x/fungible/keeper/msg_server_update_zrc20_withdraw_fee.go +++ b/x/fungible/keeper/msg_server_update_zrc20_withdraw_fee.go @@ -8,7 +8,6 @@ import ( sdk "github.com/cosmos/cosmos-sdk/types" sdkerrors "github.com/cosmos/cosmos-sdk/types/errors" ethcommon "github.com/ethereum/go-ethereum/common" - "github.com/zeta-chain/protocol-contracts/pkg/contracts/zevm/zrc20.sol" "github.com/zeta-chain/zetacore/x/fungible/types" zetaObserverTypes "github.com/zeta-chain/zetacore/x/observer/types" ) @@ -36,28 +35,24 @@ func (k Keeper) UpdateZRC20WithdrawFee(goCtx context.Context, msg *types.MsgUpda if err != nil { return nil, cosmoserrors.Wrapf(types.ErrContractCall, "failed to query protocol flat fee (%s)", err.Error()) } - - zrc20ABI, err := zrc20.ZRC20MetaData.GetAbi() + oldGasLimit, err := k.QueryGasLimit(ctx, zrc20Addr) if err != nil { - return nil, cosmoserrors.Wrapf(types.ErrABIGet, "failed to get zrc20 abi") + return nil, cosmoserrors.Wrapf(types.ErrContractCall, "failed to query gas limit (%s)", err.Error()) } - // call the contract method to update the fee + // call the contract methods tmpCtx, commit := ctx.CacheContext() - _, err = k.CallEVM( - tmpCtx, - *zrc20ABI, - types.ModuleAddressEVM, - zrc20Addr, - BigIntZero, - nil, - true, - false, - "updateProtocolFlatFee", - msg.NewWithdrawFee.BigInt(), - ) - if err != nil { - return nil, cosmoserrors.Wrapf(types.ErrContractCall, "failed to call zrc20 contract updateProtocolFlatFee method (%s)", err.Error()) + if !msg.NewWithdrawFee.IsNil() { + _, err = k.UpdateZRC20ProtocolFlatFee(tmpCtx, zrc20Addr, msg.NewWithdrawFee.BigInt()) + if err != nil { + return nil, cosmoserrors.Wrapf(types.ErrContractCall, "failed to call zrc20 contract updateProtocolFlatFee method (%s)", err.Error()) + } + } + if !msg.NewGasLimit.IsNil() { + _, err = k.UpdateZRC20GasLimit(tmpCtx, zrc20Addr, msg.NewGasLimit.BigInt()) + if err != nil { + return nil, cosmoserrors.Wrapf(types.ErrContractCall, "failed to call zrc20 contract updateGasLimit method (%s)", err.Error()) + } } err = ctx.EventManager().EmitTypedEvent( @@ -67,8 +62,10 @@ func (k Keeper) UpdateZRC20WithdrawFee(goCtx context.Context, msg *types.MsgUpda CoinType: coin.CoinType, Zrc20Address: zrc20Addr.Hex(), OldWithdrawFee: oldWithdrawFee.String(), - NewWithdrawFee: msg.NewWithdrawFee.BigInt().String(), + NewWithdrawFee: msg.NewWithdrawFee.String(), Signer: msg.Creator, + OldGasLimit: oldGasLimit.String(), + NewGasLimit: msg.NewGasLimit.String(), }, ) if err != nil { diff --git a/x/fungible/keeper/msg_server_update_zrc20_withdraw_fee_test.go b/x/fungible/keeper/msg_server_update_zrc20_withdraw_fee_test.go index 1b2cc0374b..9de490dc8b 100644 --- a/x/fungible/keeper/msg_server_update_zrc20_withdraw_fee_test.go +++ b/x/fungible/keeper/msg_server_update_zrc20_withdraw_fee_test.go @@ -33,22 +33,56 @@ func TestKeeper_UpdateZRC20WithdrawFee(t *testing.T) { zrc20Addr := setupGasCoin(t, ctx, k, sdkk.EvmKeeper, chainID, "alpha", "alpha") // initial protocol fee is zero - fee, err := k.QueryProtocolFlatFee(ctx, zrc20Addr) + protocolFee, err := k.QueryProtocolFlatFee(ctx, zrc20Addr) require.NoError(t, err) - require.Zero(t, fee.Uint64()) + require.Zero(t, protocolFee.Uint64()) - // can update the fee + // can update the protocol fee and gas limit _, err = k.UpdateZRC20WithdrawFee(ctx, types.NewMsgUpdateZRC20WithdrawFee( admin, zrc20Addr.String(), math.NewUint(42), + math.NewUint(42), )) require.NoError(t, err) // can query the updated fee - fee, err = k.QueryProtocolFlatFee(ctx, zrc20Addr) + protocolFee, err = k.QueryProtocolFlatFee(ctx, zrc20Addr) + require.NoError(t, err) + require.Equal(t, uint64(42), protocolFee.Uint64()) + gasLimit, err := k.QueryGasLimit(ctx, zrc20Addr) require.NoError(t, err) - require.Equal(t, uint64(42), fee.Uint64()) + require.Equal(t, uint64(42), gasLimit.Uint64()) + + // can update protocol fee only + _, err = k.UpdateZRC20WithdrawFee(ctx, types.NewMsgUpdateZRC20WithdrawFee( + admin, + zrc20Addr.String(), + math.NewUint(43), + math.Uint{}, + )) + require.NoError(t, err) + protocolFee, err = k.QueryProtocolFlatFee(ctx, zrc20Addr) + require.NoError(t, err) + require.Equal(t, uint64(43), protocolFee.Uint64()) + gasLimit, err = k.QueryGasLimit(ctx, zrc20Addr) + require.NoError(t, err) + require.Equal(t, uint64(42), gasLimit.Uint64()) + + // can update gas limit only + _, err = k.UpdateZRC20WithdrawFee(ctx, types.NewMsgUpdateZRC20WithdrawFee( + admin, + zrc20Addr.String(), + math.Uint{}, + math.NewUint(44), + )) + require.NoError(t, err) + protocolFee, err = k.QueryProtocolFlatFee(ctx, zrc20Addr) + require.NoError(t, err) + require.Equal(t, uint64(43), protocolFee.Uint64()) + gasLimit, err = k.QueryGasLimit(ctx, zrc20Addr) + require.NoError(t, err) + require.Equal(t, uint64(44), gasLimit.Uint64()) }) t.Run("should fail if not authorized", func(t *testing.T) { @@ -57,8 +91,9 @@ func TestKeeper_UpdateZRC20WithdrawFee(t *testing.T) { _, err := k.UpdateZRC20WithdrawFee(ctx, types.NewMsgUpdateZRC20WithdrawFee( sample.AccAddress(), sample.EthAddress().String(), - math.NewUint(42)), - ) + math.NewUint(42), + math.Uint{}, + )) require.ErrorIs(t, err, sdkerrors.ErrUnauthorized) }) @@ -70,8 +105,9 @@ func TestKeeper_UpdateZRC20WithdrawFee(t *testing.T) { _, err := k.UpdateZRC20WithdrawFee(ctx, types.NewMsgUpdateZRC20WithdrawFee( admin, "invalid_address", - math.NewUint(42)), - ) + math.NewUint(42), + math.Uint{}, + )) require.ErrorIs(t, err, sdkerrors.ErrInvalidAddress) }) @@ -83,8 +119,9 @@ func TestKeeper_UpdateZRC20WithdrawFee(t *testing.T) { _, err := k.UpdateZRC20WithdrawFee(ctx, types.NewMsgUpdateZRC20WithdrawFee( admin, sample.EthAddress().String(), - math.NewUint(42)), - ) + math.NewUint(42), + math.Uint{}, + )) require.ErrorIs(t, err, types.ErrForeignCoinNotFound) }) @@ -102,12 +139,13 @@ func TestKeeper_UpdateZRC20WithdrawFee(t *testing.T) { _, err := k.UpdateZRC20WithdrawFee(ctx, types.NewMsgUpdateZRC20WithdrawFee( admin, zrc20.String(), - math.NewUint(42)), - ) + math.NewUint(42), + math.Uint{}, + )) require.ErrorIs(t, err, types.ErrContractCall) }) - t.Run("should fail if contract call for setting new fee fails", func(t *testing.T) { + t.Run("should fail if contract call for setting new protocol fee fails", func(t *testing.T) { k, ctx, _, zk := keepertest.FungibleKeeperWithMocks(t, keepertest.FungibleMockOptions{UseEVMMock: true}) k.GetAuthKeeper().GetModuleAccount(ctx, types.ModuleName) mockEVMKeeper := keepertest.GetFungibleEVMMock(t, k) @@ -139,6 +177,16 @@ func TestKeeper_UpdateZRC20WithdrawFee(t *testing.T) { false, ).Return(&evmtypes.MsgEthereumTxResponse{Ret: protocolFlatFee}, nil) + gasLimit, err := zrc20ABI.Methods["GAS_LIMIT"].Outputs.Pack(big.NewInt(42)) + require.NoError(t, err) + mockEVMKeeper.On( + "ApplyMessage", + mock.Anything, + mock.Anything, + mock.Anything, + false, + ).Return(&evmtypes.MsgEthereumTxResponse{Ret: gasLimit}, nil) + // this is the update call (commit == true) mockEVMKeeper.On( "ApplyMessage", @@ -151,8 +199,71 @@ func TestKeeper_UpdateZRC20WithdrawFee(t *testing.T) { _, err = k.UpdateZRC20WithdrawFee(ctx, types.NewMsgUpdateZRC20WithdrawFee( admin, zrc20Addr.String(), - math.NewUint(42)), + math.NewUint(42), + math.Uint{}, + )) + require.ErrorIs(t, err, types.ErrContractCall) + + mockEVMKeeper.AssertExpectations(t) + }) + + t.Run("should fail if contract call for setting new protocol fee fails", func(t *testing.T) { + k, ctx, _, zk := keepertest.FungibleKeeperWithMocks(t, keepertest.FungibleMockOptions{UseEVMMock: true}) + k.GetAuthKeeper().GetModuleAccount(ctx, types.ModuleName) + mockEVMKeeper := keepertest.GetFungibleEVMMock(t, k) + + // setup + admin := sample.AccAddress() + setAdminPolicies(ctx, zk, admin, observertypes.Policy_Type_group2) + zrc20Addr := sample.EthAddress() + k.SetForeignCoins(ctx, sample.ForeignCoins(t, zrc20Addr.String())) + + // evm mocks + mockEVMKeeper.On("EstimateGas", mock.Anything, mock.Anything).Maybe().Return( + &evmtypes.EstimateGasResponse{Gas: 1000}, + nil, ) + mockEVMKeeper.On("WithChainID", mock.Anything).Maybe().Return(ctx) + mockEVMKeeper.On("ChainID").Maybe().Return(big.NewInt(1)) + + // this is the query (commit == false) + zrc20ABI, err := zrc20.ZRC20MetaData.GetAbi() + require.NoError(t, err) + protocolFlatFee, err := zrc20ABI.Methods["PROTOCOL_FLAT_FEE"].Outputs.Pack(big.NewInt(42)) + require.NoError(t, err) + mockEVMKeeper.On( + "ApplyMessage", + mock.Anything, + mock.Anything, + mock.Anything, + false, + ).Return(&evmtypes.MsgEthereumTxResponse{Ret: protocolFlatFee}, nil) + + gasLimit, err := zrc20ABI.Methods["GAS_LIMIT"].Outputs.Pack(big.NewInt(42)) + require.NoError(t, err) + mockEVMKeeper.On( + "ApplyMessage", + mock.Anything, + mock.Anything, + mock.Anything, + false, + ).Return(&evmtypes.MsgEthereumTxResponse{Ret: gasLimit}, nil) + + // this is the update call (commit == true) + mockEVMKeeper.On( + "ApplyMessage", + mock.Anything, + mock.Anything, + mock.Anything, + true, + ).Return(&evmtypes.MsgEthereumTxResponse{}, errors.New("transaction failed")) + + _, err = k.UpdateZRC20WithdrawFee(ctx, types.NewMsgUpdateZRC20WithdrawFee( + admin, + zrc20Addr.String(), + math.Uint{}, + math.NewUint(42), + )) require.ErrorIs(t, err, types.ErrContractCall) mockEVMKeeper.AssertExpectations(t) diff --git a/x/fungible/types/events.pb.go b/x/fungible/types/events.pb.go index c00e084019..9f3f881138 100644 --- a/x/fungible/types/events.pb.go +++ b/x/fungible/types/events.pb.go @@ -209,6 +209,8 @@ type EventZRC20WithdrawFeeUpdated struct { OldWithdrawFee string `protobuf:"bytes,5,opt,name=old_withdraw_fee,json=oldWithdrawFee,proto3" json:"old_withdraw_fee,omitempty"` NewWithdrawFee string `protobuf:"bytes,6,opt,name=new_withdraw_fee,json=newWithdrawFee,proto3" json:"new_withdraw_fee,omitempty"` Signer string `protobuf:"bytes,7,opt,name=signer,proto3" json:"signer,omitempty"` + OldGasLimit string `protobuf:"bytes,8,opt,name=old_gas_limit,json=oldGasLimit,proto3" json:"old_gas_limit,omitempty"` + NewGasLimit string `protobuf:"bytes,9,opt,name=new_gas_limit,json=newGasLimit,proto3" json:"new_gas_limit,omitempty"` } func (m *EventZRC20WithdrawFeeUpdated) Reset() { *m = EventZRC20WithdrawFeeUpdated{} } @@ -293,6 +295,20 @@ func (m *EventZRC20WithdrawFeeUpdated) GetSigner() string { return "" } +func (m *EventZRC20WithdrawFeeUpdated) GetOldGasLimit() string { + if m != nil { + return m.OldGasLimit + } + return "" +} + +func (m *EventZRC20WithdrawFeeUpdated) GetNewGasLimit() string { + if m != nil { + return m.NewGasLimit + } + return "" +} + type EventZRC20PausedStatusUpdated struct { MsgTypeUrl string `protobuf:"bytes,1,opt,name=msg_type_url,json=msgTypeUrl,proto3" json:"msg_type_url,omitempty"` Zrc20Addresses []string `protobuf:"bytes,2,rep,name=zrc20_addresses,json=zrc20Addresses,proto3" json:"zrc20_addresses,omitempty"` @@ -371,43 +387,45 @@ func init() { func init() { proto.RegisterFile("fungible/events.proto", fileDescriptor_858e6494730deffd) } var fileDescriptor_858e6494730deffd = []byte{ - // 564 bytes of a gzipped FileDescriptorProto - 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x8c, 0x94, 0xdd, 0x6e, 0xd3, 0x30, - 0x14, 0xc7, 0x97, 0x75, 0xeb, 0x5a, 0x6b, 0x8c, 0x61, 0x0a, 0x0a, 0x1d, 0x44, 0x55, 0xb9, 0xa0, - 0x37, 0x4b, 0xaa, 0x22, 0x1e, 0x60, 0x14, 0x90, 0x26, 0x81, 0x84, 0x3a, 0x26, 0xa4, 0xdd, 0x44, - 0x6e, 0x7c, 0x96, 0x5a, 0x4a, 0xec, 0x28, 0x76, 0xe9, 0xb2, 0xa7, 0xe0, 0x8e, 0x0b, 0xde, 0x84, - 0x27, 0xe0, 0x72, 0xdc, 0x71, 0x89, 0xda, 0x17, 0x41, 0x76, 0xdc, 0x2f, 0x10, 0xa3, 0x57, 0x3d, - 0xc7, 0x3d, 0x1f, 0x3f, 0xff, 0xcf, 0x89, 0xd1, 0x83, 0xcb, 0x31, 0x8f, 0xd9, 0x30, 0x81, 0x00, - 0x3e, 0x01, 0x57, 0xd2, 0xcf, 0x72, 0xa1, 0x04, 0x3e, 0xba, 0x06, 0x45, 0xa2, 0x11, 0x61, 0xdc, - 0x37, 0x96, 0xc8, 0xc1, 0x9f, 0x47, 0x36, 0xef, 0x47, 0x22, 0x4d, 0x05, 0x0f, 0xca, 0x9f, 0x32, - 0xa3, 0x79, 0x6f, 0x51, 0x48, 0x5d, 0xd9, 0xa3, 0x46, 0x2c, 0x62, 0x61, 0xcc, 0x40, 0x5b, 0xe5, - 0x69, 0xfb, 0x9b, 0x83, 0x9a, 0xaf, 0x75, 0xaf, 0xb3, 0x42, 0x2a, 0x48, 0xfb, 0x82, 0xab, 0x9c, - 0x44, 0xea, 0x3c, 0xa3, 0x44, 0x01, 0xc5, 0x2d, 0xb4, 0x9f, 0xca, 0x38, 0x54, 0x45, 0x06, 0xe1, - 0x38, 0x4f, 0x5c, 0xa7, 0xe5, 0x74, 0xea, 0x03, 0x94, 0xca, 0xf8, 0x43, 0x91, 0xc1, 0x79, 0x9e, - 0xe0, 0x2e, 0x6a, 0x70, 0x98, 0x84, 0x91, 0x4d, 0x0c, 0x09, 0xa5, 0x39, 0x48, 0xe9, 0x6e, 0x9b, - 0x48, 0xcc, 0x61, 0x32, 0xaf, 0x79, 0x52, 0xfe, 0xa3, 0x33, 0x44, 0x42, 0xff, 0xce, 0xa8, 0x94, - 0x19, 0x22, 0xa1, 0x7f, 0x66, 0x3c, 0x44, 0x55, 0xc9, 0x62, 0x0e, 0xb9, 0xbb, 0x63, 0x62, 0xac, - 0xd7, 0xfe, 0xb2, 0x8d, 0xb0, 0x81, 0xbf, 0x18, 0xf4, 0x7b, 0xdd, 0x57, 0x90, 0x25, 0xa2, 0xd8, - 0x08, 0xfa, 0x11, 0xaa, 0x19, 0x39, 0x43, 0x46, 0x0d, 0x68, 0x65, 0xb0, 0x67, 0xfc, 0x53, 0x8a, - 0x9b, 0xa8, 0x36, 0x27, 0xb3, 0x44, 0x0b, 0x1f, 0x63, 0xb4, 0xc3, 0x49, 0x0a, 0x96, 0xc2, 0xd8, - 0x86, 0xad, 0x48, 0x87, 0x22, 0x71, 0x77, 0x2d, 0x9b, 0xf1, 0x74, 0x1d, 0x0a, 0x11, 0x4b, 0x49, - 0x22, 0xdd, 0xaa, 0x69, 0xb1, 0xf0, 0xf1, 0x31, 0xaa, 0x47, 0x82, 0x71, 0x43, 0xe8, 0xee, 0xb5, - 0x9c, 0xce, 0x41, 0xef, 0xd0, 0xb7, 0xf3, 0xeb, 0x0b, 0xc6, 0x35, 0xa6, 0x6e, 0x5b, 0x5a, 0xb8, - 0x81, 0x76, 0x21, 0x8f, 0x7a, 0x5d, 0xb7, 0x66, 0x3a, 0x94, 0x0e, 0x3e, 0x42, 0xf5, 0x98, 0xc8, - 0x30, 0x61, 0x29, 0x53, 0x6e, 0xbd, 0xec, 0x10, 0x13, 0xf9, 0x56, 0xfb, 0xed, 0xaf, 0xdb, 0xe8, - 0xf1, 0x52, 0x99, 0x8f, 0x4c, 0x8d, 0x68, 0x4e, 0x26, 0x6f, 0x00, 0x36, 0x1f, 0xec, 0x2d, 0x1a, - 0xad, 0xf1, 0x57, 0xfe, 0xcb, 0xff, 0x14, 0xdd, 0xb9, 0xd6, 0xc8, 0x8b, 0x49, 0x97, 0xfa, 0xed, - 0x9b, 0xc3, 0xf9, 0x8c, 0x3b, 0xe8, 0x50, 0x6f, 0xc5, 0xc4, 0xa2, 0x86, 0x97, 0x00, 0x56, 0xd1, - 0x03, 0x91, 0xd0, 0x95, 0x1b, 0xe8, 0x48, 0xbd, 0x71, 0x6b, 0x91, 0xd5, 0x32, 0x92, 0xc3, 0x64, - 0x35, 0x72, 0xb9, 0x37, 0x7b, 0x6b, 0x7b, 0xf3, 0xc3, 0x41, 0x4f, 0x96, 0xea, 0xbc, 0x27, 0x63, - 0x09, 0xf4, 0x4c, 0x11, 0x35, 0x96, 0x9b, 0xcb, 0xf3, 0x0c, 0xdd, 0x5d, 0xbb, 0x14, 0xe8, 0x95, - 0xaf, 0x68, 0x88, 0xd5, 0x6b, 0x81, 0xc4, 0xef, 0x50, 0x95, 0x44, 0x8a, 0x09, 0x6e, 0x95, 0x7a, - 0xe1, 0xdf, 0xf2, 0x35, 0xfb, 0x25, 0xc0, 0x2a, 0xd2, 0x89, 0x49, 0x1e, 0xd8, 0x22, 0xff, 0xfa, - 0x16, 0x5e, 0x9e, 0x7e, 0x9f, 0x7a, 0xce, 0xcd, 0xd4, 0x73, 0x7e, 0x4d, 0x3d, 0xe7, 0xf3, 0xcc, - 0xdb, 0xba, 0x99, 0x79, 0x5b, 0x3f, 0x67, 0xde, 0xd6, 0x45, 0x10, 0x33, 0x35, 0x1a, 0x0f, 0xf5, - 0x80, 0x02, 0xdd, 0xf0, 0xd8, 0xf4, 0x0e, 0xe6, 0xbd, 0x83, 0xab, 0x60, 0xf9, 0x58, 0x14, 0x19, - 0xc8, 0x61, 0xd5, 0x3c, 0x0d, 0xcf, 0x7f, 0x07, 0x00, 0x00, 0xff, 0xff, 0x63, 0xa1, 0x97, 0xec, - 0x8e, 0x04, 0x00, 0x00, + // 593 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x8c, 0x54, 0xcb, 0x6e, 0xd3, 0x4c, + 0x14, 0xae, 0x9b, 0x36, 0x6d, 0xa6, 0x97, 0xbf, 0xff, 0x50, 0x90, 0x49, 0xc1, 0xaa, 0xc2, 0x82, + 0x6e, 0x6a, 0x57, 0x45, 0x3c, 0x40, 0x29, 0x17, 0x55, 0x02, 0x09, 0xa5, 0x54, 0x48, 0xdd, 0x58, + 0x13, 0xcf, 0xa9, 0x3b, 0x92, 0x3d, 0x63, 0x79, 0x26, 0xb8, 0xee, 0x53, 0xb0, 0xe3, 0x5d, 0x78, + 0x02, 0x96, 0x65, 0xc7, 0x12, 0x35, 0x2f, 0x82, 0xe6, 0xe2, 0x5c, 0x40, 0x94, 0xac, 0x72, 0xce, + 0xe4, 0x3b, 0xe7, 0xfb, 0xfc, 0x9d, 0x33, 0x83, 0xee, 0x5f, 0x0c, 0x79, 0xca, 0x06, 0x19, 0x44, + 0xf0, 0x09, 0xb8, 0x92, 0x61, 0x51, 0x0a, 0x25, 0xf0, 0xce, 0x35, 0x28, 0x92, 0x5c, 0x12, 0xc6, + 0x43, 0x13, 0x89, 0x12, 0xc2, 0x06, 0xd9, 0xbd, 0x97, 0x88, 0x3c, 0x17, 0x3c, 0xb2, 0x3f, 0xb6, + 0xa2, 0xfb, 0xff, 0xb8, 0x91, 0xba, 0x72, 0x47, 0xdb, 0xa9, 0x48, 0x85, 0x09, 0x23, 0x1d, 0xd9, + 0xd3, 0xde, 0x57, 0x0f, 0x75, 0x5f, 0x69, 0xae, 0xd3, 0x5a, 0x2a, 0xc8, 0x8f, 0x05, 0x57, 0x25, + 0x49, 0xd4, 0x59, 0x41, 0x89, 0x02, 0x8a, 0x77, 0xd1, 0x7a, 0x2e, 0xd3, 0x58, 0xd5, 0x05, 0xc4, + 0xc3, 0x32, 0xf3, 0xbd, 0x5d, 0x6f, 0xaf, 0xd3, 0x47, 0xb9, 0x4c, 0x3f, 0xd4, 0x05, 0x9c, 0x95, + 0x19, 0x3e, 0x40, 0xdb, 0x1c, 0xaa, 0x38, 0x71, 0x85, 0x31, 0xa1, 0xb4, 0x04, 0x29, 0xfd, 0x45, + 0x83, 0xc4, 0x1c, 0xaa, 0xa6, 0xe7, 0x91, 0xfd, 0x47, 0x57, 0x88, 0x8c, 0xfe, 0x59, 0xd1, 0xb2, + 0x15, 0x22, 0xa3, 0xbf, 0x57, 0x3c, 0x40, 0x6d, 0xc9, 0x52, 0x0e, 0xa5, 0xbf, 0x64, 0x30, 0x2e, + 0xeb, 0x7d, 0x59, 0x44, 0xd8, 0x88, 0x3f, 0xef, 0x1f, 0x1f, 0x1e, 0xbc, 0x84, 0x22, 0x13, 0xf5, + 0x5c, 0xa2, 0x1f, 0xa2, 0x55, 0x63, 0x67, 0xcc, 0xa8, 0x11, 0xda, 0xea, 0xaf, 0x98, 0xfc, 0x84, + 0xe2, 0x2e, 0x5a, 0x6d, 0x94, 0x39, 0x45, 0xe3, 0x1c, 0x63, 0xb4, 0xc4, 0x49, 0x0e, 0x4e, 0x85, + 0x89, 0x8d, 0xb6, 0x3a, 0x1f, 0x88, 0xcc, 0x5f, 0x76, 0xda, 0x4c, 0xa6, 0xfb, 0x50, 0x48, 0x58, + 0x4e, 0x32, 0xe9, 0xb7, 0x0d, 0xc5, 0x38, 0xc7, 0xfb, 0xa8, 0x93, 0x08, 0xc6, 0x8d, 0x42, 0x7f, + 0x65, 0xd7, 0xdb, 0xdb, 0x3c, 0xdc, 0x0a, 0xdd, 0xfc, 0x8e, 0x05, 0xe3, 0x5a, 0xa6, 0xa6, 0xb5, + 0x11, 0xde, 0x46, 0xcb, 0x50, 0x26, 0x87, 0x07, 0xfe, 0xaa, 0x61, 0xb0, 0x09, 0xde, 0x41, 0x9d, + 0x94, 0xc8, 0x38, 0x63, 0x39, 0x53, 0x7e, 0xc7, 0x32, 0xa4, 0x44, 0xbe, 0xd5, 0x79, 0x6f, 0xb4, + 0x88, 0x1e, 0x4d, 0x9c, 0xf9, 0xc8, 0xd4, 0x25, 0x2d, 0x49, 0xf5, 0x1a, 0x60, 0xfe, 0xc1, 0xde, + 0xe1, 0xd1, 0x8c, 0xfe, 0xd6, 0x3f, 0xf5, 0x3f, 0x41, 0x1b, 0xd7, 0x5a, 0xf2, 0x78, 0xd2, 0xd6, + 0xbf, 0x75, 0x73, 0xd8, 0xcc, 0x78, 0x0f, 0x6d, 0xe9, 0xad, 0xa8, 0x9c, 0xd4, 0xf8, 0x02, 0xc0, + 0x39, 0xba, 0x29, 0x32, 0x3a, 0xf5, 0x05, 0x1a, 0xa9, 0x37, 0x6e, 0x06, 0xd9, 0xb6, 0x48, 0x0e, + 0xd5, 0x34, 0x72, 0xb2, 0x37, 0x2b, 0xd3, 0x7b, 0x83, 0x7b, 0x68, 0x43, 0x73, 0x4d, 0xec, 0xb3, + 0xc6, 0xae, 0x89, 0x8c, 0xbe, 0x71, 0x0e, 0x6a, 0x8c, 0x66, 0x99, 0xb5, 0xb8, 0xd3, 0x5f, 0xe3, + 0x50, 0x35, 0x98, 0xde, 0x77, 0x0f, 0x3d, 0x9e, 0xb8, 0xfc, 0x9e, 0x0c, 0x25, 0xd0, 0x53, 0x45, + 0xd4, 0x50, 0xce, 0x6f, 0xf3, 0x53, 0xf4, 0xdf, 0x8c, 0x39, 0xa0, 0xaf, 0x4e, 0x4b, 0x7f, 0xcc, + 0xb4, 0x3d, 0x20, 0xf1, 0x3b, 0xd4, 0x26, 0x89, 0x62, 0x82, 0x3b, 0xc7, 0x9f, 0x87, 0x77, 0xbc, + 0x0a, 0xa1, 0x15, 0x30, 0x2d, 0xe9, 0xc8, 0x14, 0xf7, 0x5d, 0x93, 0xbf, 0xdd, 0xa9, 0x17, 0x27, + 0xdf, 0x6e, 0x03, 0xef, 0xe6, 0x36, 0xf0, 0x7e, 0xde, 0x06, 0xde, 0xe7, 0x51, 0xb0, 0x70, 0x33, + 0x0a, 0x16, 0x7e, 0x8c, 0x82, 0x85, 0xf3, 0x28, 0x65, 0xea, 0x72, 0x38, 0xd0, 0x83, 0x8e, 0x34, + 0xe1, 0xbe, 0xe1, 0x8e, 0x1a, 0xee, 0xe8, 0x2a, 0x9a, 0x3c, 0x3a, 0x75, 0x01, 0x72, 0xd0, 0x36, + 0x4f, 0xcc, 0xb3, 0x5f, 0x01, 0x00, 0x00, 0xff, 0xff, 0xaf, 0x60, 0xaf, 0x2f, 0xd6, 0x04, 0x00, + 0x00, } func (m *EventSystemContractUpdated) Marshal() (dAtA []byte, err error) { @@ -559,6 +577,20 @@ func (m *EventZRC20WithdrawFeeUpdated) MarshalToSizedBuffer(dAtA []byte) (int, e _ = i var l int _ = l + if len(m.NewGasLimit) > 0 { + i -= len(m.NewGasLimit) + copy(dAtA[i:], m.NewGasLimit) + i = encodeVarintEvents(dAtA, i, uint64(len(m.NewGasLimit))) + i-- + dAtA[i] = 0x4a + } + if len(m.OldGasLimit) > 0 { + i -= len(m.OldGasLimit) + copy(dAtA[i:], m.OldGasLimit) + i = encodeVarintEvents(dAtA, i, uint64(len(m.OldGasLimit))) + i-- + dAtA[i] = 0x42 + } if len(m.Signer) > 0 { i -= len(m.Signer) copy(dAtA[i:], m.Signer) @@ -767,6 +799,14 @@ func (m *EventZRC20WithdrawFeeUpdated) Size() (n int) { if l > 0 { n += 1 + l + sovEvents(uint64(l)) } + l = len(m.OldGasLimit) + if l > 0 { + n += 1 + l + sovEvents(uint64(l)) + } + l = len(m.NewGasLimit) + if l > 0 { + n += 1 + l + sovEvents(uint64(l)) + } return n } @@ -1493,6 +1533,70 @@ func (m *EventZRC20WithdrawFeeUpdated) Unmarshal(dAtA []byte) error { } m.Signer = string(dAtA[iNdEx:postIndex]) iNdEx = postIndex + case 8: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field OldGasLimit", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowEvents + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + stringLen |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + intStringLen := int(stringLen) + if intStringLen < 0 { + return ErrInvalidLengthEvents + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthEvents + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.OldGasLimit = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + case 9: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field NewGasLimit", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowEvents + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + stringLen |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + intStringLen := int(stringLen) + if intStringLen < 0 { + return ErrInvalidLengthEvents + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthEvents + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.NewGasLimit = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex default: iNdEx = preIndex skippy, err := skipEvents(dAtA[iNdEx:]) diff --git a/x/fungible/types/message_update_zrc20_withdraw_fee.go b/x/fungible/types/message_update_zrc20_withdraw_fee.go index 1b1d6de1ec..fb2b98955c 100644 --- a/x/fungible/types/message_update_zrc20_withdraw_fee.go +++ b/x/fungible/types/message_update_zrc20_withdraw_fee.go @@ -1,6 +1,9 @@ package types import ( + cosmoserror "cosmossdk.io/errors" + math "cosmossdk.io/math" + sdk "github.com/cosmos/cosmos-sdk/types" sdkerrors "github.com/cosmos/cosmos-sdk/types/errors" ethcommon "github.com/ethereum/go-ethereum/common" @@ -10,11 +13,12 @@ const TypeMsgUpdateZRC20WithdrawFee = "update_zrc20_withdraw_fee" var _ sdk.Msg = &MsgUpdateZRC20WithdrawFee{} -func NewMsgUpdateZRC20WithdrawFee(creator string, zrc20 string, newFee sdk.Uint) *MsgUpdateZRC20WithdrawFee { +func NewMsgUpdateZRC20WithdrawFee(creator string, zrc20 string, newFee math.Uint, newGasLimit math.Uint) *MsgUpdateZRC20WithdrawFee { return &MsgUpdateZRC20WithdrawFee{ Creator: creator, Zrc20Address: zrc20, NewWithdrawFee: newFee, + NewGasLimit: newGasLimit, } } @@ -23,7 +27,7 @@ func (msg *MsgUpdateZRC20WithdrawFee) Route() string { } func (msg *MsgUpdateZRC20WithdrawFee) Type() string { - return TypeMsgUpdateSystemContract + return TypeMsgUpdateZRC20WithdrawFee } func (msg *MsgUpdateZRC20WithdrawFee) GetSigners() []sdk.AccAddress { @@ -42,14 +46,14 @@ func (msg *MsgUpdateZRC20WithdrawFee) GetSignBytes() []byte { func (msg *MsgUpdateZRC20WithdrawFee) ValidateBasic() error { _, err := sdk.AccAddressFromBech32(msg.Creator) if err != nil { - return sdkerrors.Wrapf(sdkerrors.ErrInvalidAddress, "invalid creator address (%s)", err) + return cosmoserror.Wrapf(sdkerrors.ErrInvalidAddress, "invalid creator address (%s)", err) } // check if the system contract address is valid if !ethcommon.IsHexAddress(msg.Zrc20Address) { - return sdkerrors.Wrapf(sdkerrors.ErrInvalidAddress, "invalid system contract address (%s)", msg.Zrc20Address) + return cosmoserror.Wrapf(sdkerrors.ErrInvalidAddress, "invalid system contract address (%s)", msg.Zrc20Address) } - if msg.NewWithdrawFee.IsNil() { - return sdkerrors.Wrapf(sdkerrors.ErrInvalidRequest, "invalid withdraw fee (%s)", msg.NewWithdrawFee) + if msg.NewWithdrawFee.IsNil() && msg.NewGasLimit.IsNil() { + return cosmoserror.Wrapf(sdkerrors.ErrInvalidRequest, "nothing to update") } return nil diff --git a/x/fungible/types/message_update_zrc20_withdraw_fee_test.go b/x/fungible/types/message_update_zrc20_withdraw_fee_test.go index 9c9e3a38b4..2aba73d42a 100644 --- a/x/fungible/types/message_update_zrc20_withdraw_fee_test.go +++ b/x/fungible/types/message_update_zrc20_withdraw_fee_test.go @@ -3,7 +3,8 @@ package types_test import ( "testing" - sdk "github.com/cosmos/cosmos-sdk/types" + math "cosmossdk.io/math" + sdkerrors "github.com/cosmos/cosmos-sdk/types/errors" "github.com/stretchr/testify/require" "github.com/zeta-chain/zetacore/testutil/sample" @@ -21,7 +22,7 @@ func TestMsgUpdateZRC20WithdrawFee_ValidateBasic(t *testing.T) { msg: types.MsgUpdateZRC20WithdrawFee{ Creator: "invalid_address", Zrc20Address: sample.EthAddress().String(), - NewWithdrawFee: sdk.NewUint(1), + NewWithdrawFee: math.NewUint(1), }, err: sdkerrors.ErrInvalidAddress, }, @@ -30,15 +31,17 @@ func TestMsgUpdateZRC20WithdrawFee_ValidateBasic(t *testing.T) { msg: types.MsgUpdateZRC20WithdrawFee{ Creator: sample.AccAddress(), Zrc20Address: "invalid_address", - NewWithdrawFee: sdk.NewUint(1), + NewWithdrawFee: math.NewUint(1), }, err: sdkerrors.ErrInvalidAddress, }, { - name: "invalid new withdraw fee", + name: "both withdraw fee and gas limit nil", msg: types.MsgUpdateZRC20WithdrawFee{ - Creator: sample.AccAddress(), - Zrc20Address: sample.EthAddress().String(), + Creator: sample.AccAddress(), + Zrc20Address: sample.EthAddress().String(), + NewGasLimit: math.Uint{}, + NewWithdrawFee: math.Uint{}, }, err: sdkerrors.ErrInvalidRequest, }, @@ -47,7 +50,42 @@ func TestMsgUpdateZRC20WithdrawFee_ValidateBasic(t *testing.T) { msg: types.MsgUpdateZRC20WithdrawFee{ Creator: sample.AccAddress(), Zrc20Address: sample.EthAddress().String(), - NewWithdrawFee: sdk.NewUint(1), + NewWithdrawFee: math.NewUint(42), + NewGasLimit: math.NewUint(42), + }, + }, + { + name: "withdraw fee can be zero", + msg: types.MsgUpdateZRC20WithdrawFee{ + Creator: sample.AccAddress(), + Zrc20Address: sample.EthAddress().String(), + NewWithdrawFee: math.ZeroUint(), + NewGasLimit: math.NewUint(42), + }, + }, + { + name: "withdraw fee can be nil", + msg: types.MsgUpdateZRC20WithdrawFee{ + Creator: sample.AccAddress(), + Zrc20Address: sample.EthAddress().String(), + NewGasLimit: math.NewUint(42), + }, + }, + { + name: "gas limit can be zero", + msg: types.MsgUpdateZRC20WithdrawFee{ + Creator: sample.AccAddress(), + Zrc20Address: sample.EthAddress().String(), + NewGasLimit: math.ZeroUint(), + NewWithdrawFee: math.NewUint(42), + }, + }, + { + name: "gas limit can be nil", + msg: types.MsgUpdateZRC20WithdrawFee{ + Creator: sample.AccAddress(), + Zrc20Address: sample.EthAddress().String(), + NewWithdrawFee: math.NewUint(42), }, }, } diff --git a/x/fungible/types/tx.pb.go b/x/fungible/types/tx.pb.go index 41271cd126..476981cc21 100644 --- a/x/fungible/types/tx.pb.go +++ b/x/fungible/types/tx.pb.go @@ -60,6 +60,7 @@ type MsgUpdateZRC20WithdrawFee struct { Creator string `protobuf:"bytes,1,opt,name=creator,proto3" json:"creator,omitempty"` Zrc20Address string `protobuf:"bytes,2,opt,name=zrc20_address,json=zrc20Address,proto3" json:"zrc20_address,omitempty"` NewWithdrawFee github_com_cosmos_cosmos_sdk_types.Uint `protobuf:"bytes,6,opt,name=new_withdraw_fee,json=newWithdrawFee,proto3,customtype=github.com/cosmos/cosmos-sdk/types.Uint" json:"new_withdraw_fee"` + NewGasLimit github_com_cosmos_cosmos_sdk_types.Uint `protobuf:"bytes,7,opt,name=new_gas_limit,json=newGasLimit,proto3,customtype=github.com/cosmos/cosmos-sdk/types.Uint" json:"new_gas_limit"` } func (m *MsgUpdateZRC20WithdrawFee) Reset() { *m = MsgUpdateZRC20WithdrawFee{} } @@ -775,64 +776,65 @@ func init() { func init() { proto.RegisterFile("fungible/tx.proto", fileDescriptor_197fdedece277fa0) } var fileDescriptor_197fdedece277fa0 = []byte{ - // 899 bytes of a gzipped FileDescriptorProto - 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xa4, 0x56, 0x4b, 0x6f, 0xdb, 0x46, - 0x10, 0x16, 0xad, 0xf8, 0xa1, 0xa9, 0x2d, 0xcb, 0x5b, 0x21, 0x61, 0xe5, 0x42, 0x76, 0x98, 0x02, - 0x51, 0x03, 0x58, 0x74, 0xd5, 0x47, 0x50, 0xa0, 0x4d, 0x61, 0x2b, 0x31, 0x1a, 0x20, 0x6a, 0x03, - 0x3a, 0x46, 0xd1, 0x5c, 0x88, 0x15, 0xb9, 0xa6, 0x16, 0x15, 0xb9, 0x2c, 0x77, 0x55, 0x45, 0xb9, - 0xf5, 0x9a, 0x53, 0xd0, 0xfe, 0x8f, 0x02, 0x3d, 0xf4, 0x3f, 0xe4, 0x98, 0x63, 0xd1, 0x43, 0x50, - 0xd8, 0xff, 0xa3, 0x28, 0xb8, 0x7c, 0x84, 0x7a, 0x50, 0xb6, 0x9c, 0x93, 0x76, 0x56, 0x33, 0xdf, - 0x7e, 0xdf, 0xcc, 0xec, 0x70, 0x61, 0xeb, 0x74, 0xe0, 0x39, 0xb4, 0xdb, 0x27, 0xba, 0x78, 0xd6, - 0xf4, 0x03, 0x26, 0x18, 0xda, 0x7e, 0x4e, 0x04, 0xb6, 0x7a, 0x98, 0x7a, 0x4d, 0xb9, 0x62, 0x01, - 0x69, 0x26, 0x5e, 0xb5, 0xf7, 0x2d, 0xe6, 0xba, 0xcc, 0xd3, 0xa3, 0x9f, 0x28, 0xa2, 0x56, 0x75, - 0x98, 0xc3, 0xe4, 0x52, 0x0f, 0x57, 0xd1, 0xae, 0xf6, 0x97, 0x02, 0x1f, 0x74, 0xb8, 0x73, 0xe2, - 0xdb, 0x58, 0x90, 0xa7, 0x46, 0xbb, 0xb5, 0xff, 0x03, 0x15, 0x3d, 0x3b, 0xc0, 0xc3, 0x23, 0x42, - 0x90, 0x0a, 0xab, 0x56, 0x40, 0xb0, 0x60, 0x81, 0xaa, 0xec, 0x2a, 0x8d, 0x92, 0x91, 0x98, 0xe8, - 0x16, 0x6c, 0x3c, 0x0f, 0xac, 0xd6, 0xbe, 0x89, 0x6d, 0x3b, 0x20, 0x9c, 0xab, 0x4b, 0xf2, 0xff, - 0x75, 0xb9, 0x79, 0x10, 0xed, 0xa1, 0x1f, 0xa1, 0xe2, 0x91, 0xa1, 0x39, 0x8c, 0x11, 0xcd, 0x53, - 0x42, 0xd4, 0x95, 0xd0, 0xef, 0x50, 0x7f, 0xf5, 0x66, 0xa7, 0xf0, 0xcf, 0x9b, 0x9d, 0xdb, 0x0e, - 0x15, 0xbd, 0x41, 0xb7, 0x69, 0x31, 0x57, 0xb7, 0x18, 0x77, 0x19, 0x8f, 0x7f, 0xf6, 0xb8, 0xfd, - 0x93, 0x2e, 0x46, 0x3e, 0xe1, 0xcd, 0x13, 0xea, 0x09, 0xa3, 0xec, 0x91, 0x61, 0x86, 0x99, 0x76, - 0x0b, 0x6e, 0xe6, 0xd2, 0x36, 0x08, 0xf7, 0x99, 0xc7, 0x89, 0x16, 0xc0, 0x8d, 0xd4, 0xe9, 0x78, - 0xc4, 0x05, 0x71, 0xdb, 0xcc, 0x13, 0x01, 0xb6, 0xc4, 0x1c, 0x65, 0x5f, 0xc3, 0x76, 0x48, 0x9a, - 0x4b, 0x7f, 0xd3, 0x8a, 0x03, 0x26, 0x74, 0xaa, 0x1e, 0x19, 0x8e, 0x23, 0xc6, 0x9a, 0xb5, 0x9b, - 0xb0, 0x93, 0x73, 0x66, 0x4a, 0xeb, 0xc5, 0x12, 0xd4, 0x3a, 0xdc, 0xb9, 0x4f, 0xfc, 0x3e, 0x1b, - 0x1d, 0xc5, 0x45, 0x6b, 0x33, 0xea, 0x49, 0x21, 0x73, 0xa8, 0x55, 0x61, 0xf9, 0x41, 0xe8, 0x12, - 0x93, 0x88, 0x0c, 0xd4, 0x80, 0xca, 0x29, 0x0b, 0x08, 0x75, 0x3c, 0x53, 0x36, 0x84, 0x49, 0x6d, - 0xb5, 0xb8, 0xab, 0x34, 0x8a, 0x46, 0x39, 0xde, 0x6f, 0x87, 0xdb, 0x0f, 0x6d, 0x54, 0x83, 0x35, - 0x9b, 0x58, 0xd4, 0xc5, 0x7d, 0xae, 0x5e, 0xdb, 0x55, 0x1a, 0x1b, 0x46, 0x6a, 0x23, 0x04, 0xd7, - 0x3c, 0xec, 0x12, 0x75, 0x59, 0x42, 0xcb, 0x35, 0xba, 0x0e, 0x2b, 0x7c, 0xe4, 0x76, 0x59, 0x3f, - 0xaa, 0x9a, 0x11, 0x5b, 0x68, 0x0f, 0x4a, 0x16, 0xa3, 0x9e, 0x19, 0xd6, 0x47, 0x5d, 0xdd, 0x55, - 0x1a, 0xe5, 0x56, 0xa5, 0x19, 0x37, 0x5b, 0xa8, 0xe3, 0xc9, 0xc8, 0x27, 0xc6, 0x9a, 0x15, 0xaf, - 0xd0, 0x36, 0x94, 0x1c, 0xcc, 0xcd, 0x3e, 0x75, 0xa9, 0x50, 0xd7, 0x24, 0xb3, 0x35, 0x07, 0xf3, - 0x47, 0xa1, 0xad, 0xdd, 0x03, 0x2d, 0x3f, 0x17, 0x49, 0xca, 0xc2, 0x9c, 0x24, 0x05, 0x88, 0x73, - 0x12, 0x9b, 0xda, 0x7d, 0xa8, 0x76, 0xb8, 0x63, 0x10, 0x97, 0xfd, 0x42, 0x8e, 0x62, 0xb9, 0x8c, - 0x7a, 0x73, 0xb2, 0x98, 0x28, 0x5d, 0x7a, 0xab, 0x54, 0xab, 0xc3, 0x87, 0xb3, 0x50, 0xd2, 0x92, - 0xfd, 0x96, 0xbd, 0x26, 0x49, 0x41, 0x0f, 0x47, 0x82, 0x58, 0xcc, 0x9e, 0x77, 0x4d, 0x3e, 0x86, - 0x4a, 0x4e, 0x07, 0x6d, 0x5a, 0xe3, 0x8d, 0x83, 0xf6, 0xa1, 0x1a, 0xf6, 0x5d, 0x37, 0x06, 0x4d, - 0xdd, 0x8b, 0xd2, 0x1d, 0x79, 0x64, 0x98, 0x9c, 0x97, 0xb4, 0xda, 0xf7, 0x99, 0x3b, 0x30, 0xc9, - 0x29, 0xcd, 0xdc, 0x1d, 0xd8, 0x1a, 0x83, 0xed, 0x61, 0xde, 0x93, 0x2c, 0xd7, 0x8d, 0xcd, 0x0c, - 0xe6, 0xb7, 0x98, 0xf7, 0xb4, 0x3f, 0x14, 0xd9, 0x98, 0x99, 0x5b, 0xf5, 0x18, 0x0f, 0x38, 0xb1, - 0x8f, 0x05, 0x16, 0x03, 0x3e, 0x47, 0xe6, 0x6d, 0xd8, 0x1c, 0x9b, 0x06, 0x24, 0x54, 0x59, 0x6c, - 0x94, 0x8c, 0x72, 0x76, 0x1e, 0x10, 0x8e, 0x3a, 0xb0, 0x82, 0x2d, 0x41, 0x99, 0x27, 0x65, 0x95, - 0x5b, 0x9f, 0x37, 0xe7, 0xcc, 0xb1, 0x66, 0x44, 0x24, 0xcb, 0xe1, 0x40, 0x06, 0x1b, 0x31, 0x88, - 0xf6, 0x91, 0x6c, 0x9e, 0x1c, 0xbe, 0x69, 0xf1, 0xfe, 0x9c, 0x92, 0xf5, 0x88, 0xfe, 0x3c, 0xa0, - 0x36, 0x15, 0xa3, 0x36, 0xf6, 0xdf, 0x75, 0xc8, 0x3d, 0x81, 0x8d, 0x7e, 0x02, 0x67, 0x5a, 0xd8, - 0x8f, 0x0a, 0xb6, 0xf8, 0x84, 0x5b, 0xef, 0x67, 0x48, 0x4d, 0x2b, 0xcb, 0x52, 0x4e, 0x94, 0xdd, - 0x69, 0x81, 0x9a, 0x97, 0x23, 0x54, 0x82, 0xe5, 0xc7, 0x07, 0x27, 0xc7, 0x0f, 0x2a, 0x05, 0xf4, - 0x1e, 0xac, 0x9e, 0x7c, 0x17, 0x19, 0x4a, 0xeb, 0xbf, 0x55, 0x28, 0x76, 0xb8, 0x83, 0x7e, 0x57, - 0xe0, 0x46, 0xde, 0x08, 0xba, 0x3b, 0xb7, 0x2c, 0xf9, 0xf7, 0xb5, 0xf6, 0xcd, 0x15, 0x03, 0xd3, - 0x76, 0xfd, 0x55, 0x81, 0xad, 0xe9, 0xcb, 0xfc, 0xc9, 0x45, 0xb0, 0x53, 0x21, 0xb5, 0x2f, 0x17, - 0x0e, 0x49, 0x39, 0xbc, 0x50, 0xa0, 0x3a, 0xf3, 0xa3, 0xf1, 0xd9, 0x45, 0x98, 0xb3, 0xa2, 0x6a, - 0x5f, 0x5d, 0x25, 0x2a, 0x25, 0xf3, 0x52, 0x81, 0xeb, 0x39, 0x63, 0xe7, 0x8b, 0xcb, 0x01, 0x4f, - 0xc6, 0xd5, 0xee, 0x5d, 0x2d, 0x6e, 0x06, 0xa5, 0xa9, 0x07, 0xc3, 0x25, 0x29, 0x4d, 0xc6, 0x5d, - 0x96, 0x52, 0xde, 0x97, 0x5e, 0x36, 0x73, 0xde, 0xd8, 0xba, 0xbb, 0x00, 0x76, 0x36, 0xf0, 0xe2, - 0x66, 0xbe, 0x60, 0xf0, 0x4c, 0xb2, 0x1a, 0x9b, 0x3a, 0x8b, 0xb0, 0xca, 0x06, 0x2e, 0xc4, 0x6a, - 0xd6, 0xd0, 0x38, 0x7c, 0xf8, 0xea, 0xac, 0xae, 0xbc, 0x3e, 0xab, 0x2b, 0xff, 0x9e, 0xd5, 0x95, - 0x97, 0xe7, 0xf5, 0xc2, 0xeb, 0xf3, 0x7a, 0xe1, 0xef, 0xf3, 0x7a, 0xe1, 0xa9, 0x9e, 0x99, 0x55, - 0x21, 0xf4, 0x9e, 0x3c, 0x45, 0x4f, 0x4e, 0xd1, 0x9f, 0xe9, 0x6f, 0x1f, 0xa2, 0xe1, 0xe0, 0xea, - 0xae, 0xc8, 0x47, 0xe4, 0xa7, 0xff, 0x07, 0x00, 0x00, 0xff, 0xff, 0x62, 0x38, 0xf4, 0x5f, 0xa1, - 0x0a, 0x00, 0x00, + // 913 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xa4, 0x56, 0xcb, 0x6e, 0xdb, 0x46, + 0x14, 0x15, 0xad, 0xf8, 0xa1, 0x1b, 0x5b, 0x96, 0x59, 0x21, 0x61, 0xe5, 0x42, 0x76, 0x98, 0x02, + 0x51, 0x03, 0x58, 0x74, 0xd5, 0x47, 0x50, 0xa0, 0x4d, 0x61, 0x2b, 0x71, 0x1b, 0x20, 0x6a, 0x03, + 0x3a, 0x46, 0xd1, 0x6c, 0x88, 0x11, 0x39, 0xa6, 0x06, 0x15, 0x67, 0x54, 0xce, 0xa8, 0x8a, 0xb2, + 0xeb, 0xd6, 0xab, 0xa0, 0xfd, 0x8f, 0x02, 0xfd, 0x8b, 0x2c, 0xb3, 0x2c, 0xba, 0x08, 0x0a, 0xfb, + 0x3f, 0x8a, 0x82, 0xc3, 0x87, 0xa9, 0x07, 0x65, 0x4b, 0x5d, 0x69, 0x66, 0x74, 0xef, 0xe1, 0xb9, + 0xf7, 0x9e, 0x39, 0x24, 0x6c, 0x9d, 0xf6, 0xa9, 0x4b, 0xda, 0x5d, 0x6c, 0x88, 0x97, 0xf5, 0x9e, + 0xcf, 0x04, 0x53, 0xb7, 0x5f, 0x61, 0x81, 0xec, 0x0e, 0x22, 0xb4, 0x2e, 0x57, 0xcc, 0xc7, 0xf5, + 0x38, 0xaa, 0xf2, 0x9e, 0xcd, 0x3c, 0x8f, 0x51, 0x23, 0xfc, 0x09, 0x33, 0x2a, 0x65, 0x97, 0xb9, + 0x4c, 0x2e, 0x8d, 0x60, 0x15, 0x9e, 0xea, 0x67, 0x4b, 0xf0, 0x7e, 0x8b, 0xbb, 0x27, 0x3d, 0x07, + 0x09, 0xfc, 0xc2, 0x6c, 0x36, 0xf6, 0x7f, 0x20, 0xa2, 0xe3, 0xf8, 0x68, 0x70, 0x84, 0xb1, 0xaa, + 0xc1, 0xaa, 0xed, 0x63, 0x24, 0x98, 0xaf, 0x29, 0xbb, 0x4a, 0xad, 0x60, 0xc6, 0x5b, 0xf5, 0x2e, + 0x6c, 0xbc, 0xf2, 0xed, 0xc6, 0xbe, 0x85, 0x1c, 0xc7, 0xc7, 0x9c, 0x6b, 0x4b, 0xf2, 0xff, 0x75, + 0x79, 0x78, 0x10, 0x9e, 0xa9, 0x3f, 0x42, 0x89, 0xe2, 0x81, 0x35, 0x88, 0x10, 0xad, 0x53, 0x8c, + 0xb5, 0x95, 0x20, 0xee, 0xd0, 0x78, 0xf3, 0x6e, 0x27, 0xf7, 0xf7, 0xbb, 0x9d, 0x7b, 0x2e, 0x11, + 0x9d, 0x7e, 0xbb, 0x6e, 0x33, 0xcf, 0xb0, 0x19, 0xf7, 0x18, 0x8f, 0x7e, 0xf6, 0xb8, 0xf3, 0x93, + 0x21, 0x86, 0x3d, 0xcc, 0xeb, 0x27, 0x84, 0x0a, 0xb3, 0x48, 0xf1, 0x20, 0xcd, 0xec, 0x18, 0x36, + 0x02, 0x68, 0x17, 0x71, 0xab, 0x4b, 0x3c, 0x22, 0xb4, 0xd5, 0xc5, 0x70, 0x6f, 0x52, 0x3c, 0xf8, + 0x06, 0xf1, 0xa7, 0x01, 0x86, 0x7e, 0x17, 0xee, 0x64, 0xf6, 0xc2, 0xc4, 0xbc, 0xc7, 0x28, 0xc7, + 0xba, 0x0f, 0xb7, 0x93, 0xa0, 0xe3, 0x21, 0x17, 0xd8, 0x6b, 0x32, 0x2a, 0x7c, 0x64, 0x8b, 0x19, + 0xed, 0xfa, 0x0a, 0xb6, 0x03, 0xba, 0x5c, 0xc6, 0x5b, 0x76, 0x94, 0x30, 0xd6, 0x3c, 0x8d, 0xe2, + 0xc1, 0x28, 0x62, 0xd4, 0x48, 0xfd, 0x0e, 0xec, 0x64, 0x3c, 0x33, 0xa1, 0x75, 0xb6, 0x04, 0x95, + 0x16, 0x77, 0x1f, 0xe1, 0x5e, 0x97, 0x0d, 0x8f, 0x22, 0x25, 0x34, 0x19, 0xa1, 0xb2, 0x90, 0x19, + 0xd4, 0xca, 0xb0, 0xfc, 0x38, 0x08, 0x89, 0x48, 0x84, 0x1b, 0xb5, 0x06, 0xa5, 0x53, 0xe6, 0x63, + 0xe2, 0x52, 0x4b, 0xaa, 0xcc, 0x22, 0x8e, 0x96, 0xdf, 0x55, 0x6a, 0x79, 0xb3, 0x18, 0x9d, 0x37, + 0x83, 0xe3, 0x27, 0x8e, 0x5a, 0x81, 0x35, 0x07, 0xdb, 0xc4, 0x43, 0x5d, 0xae, 0xdd, 0xd8, 0x55, + 0x6a, 0x1b, 0x66, 0xb2, 0x57, 0x55, 0xb8, 0x41, 0x91, 0x87, 0xb5, 0x65, 0x09, 0x2d, 0xd7, 0xea, + 0x2d, 0x58, 0xe1, 0x43, 0xaf, 0xcd, 0xba, 0xa1, 0x14, 0xcc, 0x68, 0xa7, 0xee, 0x41, 0xc1, 0x66, + 0x84, 0x5a, 0xc1, 0x70, 0xe4, 0x34, 0x8b, 0x8d, 0x52, 0x3d, 0x52, 0x70, 0x50, 0xc7, 0xf3, 0x61, + 0x0f, 0x9b, 0x6b, 0x76, 0xb4, 0x52, 0xb7, 0xa1, 0x70, 0x39, 0xfc, 0x35, 0xc9, 0x6c, 0xcd, 0x8d, + 0x07, 0xf9, 0x10, 0xf4, 0xec, 0x5e, 0xc4, 0x2d, 0x0b, 0x7a, 0x12, 0x0f, 0x20, 0xea, 0x49, 0xb4, + 0xd5, 0x1f, 0x41, 0xb9, 0xc5, 0x5d, 0x13, 0x7b, 0xec, 0x17, 0x7c, 0x14, 0x95, 0xcb, 0x08, 0x9d, + 0xd1, 0xc5, 0xb8, 0xd2, 0xa5, 0xcb, 0x4a, 0xf5, 0x2a, 0x7c, 0x30, 0x0d, 0x25, 0x19, 0xd9, 0x6f, + 0x4a, 0xea, 0xee, 0xc5, 0x03, 0x3d, 0x1c, 0x0a, 0x6c, 0x33, 0x67, 0xd6, 0xdd, 0xfb, 0x08, 0x4a, + 0x19, 0x0a, 0xda, 0xb4, 0x47, 0x85, 0xa3, 0xee, 0x43, 0x39, 0xd0, 0x5d, 0x3b, 0x02, 0x4d, 0xc2, + 0xf3, 0x32, 0x5c, 0xa5, 0x78, 0x10, 0x3f, 0x2f, 0x96, 0xda, 0xf7, 0xa9, 0x3b, 0x30, 0xce, 0x29, + 0xe9, 0xdc, 0x7d, 0xd8, 0x1a, 0x81, 0xed, 0x20, 0xde, 0x91, 0x2c, 0xd7, 0xcd, 0xcd, 0x14, 0xe6, + 0xb7, 0x88, 0x77, 0xf4, 0x3f, 0x14, 0x29, 0xcc, 0xd4, 0xad, 0x7a, 0x86, 0xfa, 0x1c, 0x3b, 0xc7, + 0x02, 0x89, 0x3e, 0x9f, 0x51, 0xe6, 0x3d, 0xd8, 0x1c, 0xb1, 0x18, 0x1c, 0x54, 0x99, 0xaf, 0x15, + 0xcc, 0x62, 0xda, 0x64, 0x30, 0x57, 0x5b, 0xb0, 0x82, 0x6c, 0x41, 0x18, 0x95, 0x65, 0x15, 0x1b, + 0x9f, 0xd5, 0x67, 0x98, 0x63, 0x3d, 0x24, 0x92, 0xe6, 0x70, 0x20, 0x93, 0xcd, 0x08, 0x44, 0xff, + 0x50, 0x8a, 0x27, 0x83, 0x6f, 0x32, 0xbc, 0x3f, 0x27, 0xca, 0x7a, 0x4a, 0x7e, 0xee, 0x13, 0x87, + 0x88, 0x61, 0x13, 0xf5, 0xfe, 0xaf, 0x73, 0x3e, 0x87, 0x8d, 0x6e, 0x0c, 0x67, 0xd9, 0xa8, 0x17, + 0x0e, 0x6c, 0x7e, 0x7b, 0x5b, 0xef, 0xa6, 0x48, 0x4d, 0x56, 0x96, 0xa6, 0x1c, 0x57, 0x76, 0xbf, + 0x01, 0x5a, 0x56, 0x8f, 0xd4, 0x02, 0x2c, 0x3f, 0x3b, 0x38, 0x39, 0x7e, 0x5c, 0xca, 0xa9, 0x37, + 0x61, 0xf5, 0xe4, 0xbb, 0x70, 0xa3, 0x34, 0xfe, 0x5d, 0x85, 0x7c, 0x8b, 0xbb, 0xea, 0xef, 0x0a, + 0xdc, 0xce, 0xb2, 0xa0, 0x07, 0x33, 0xc7, 0x92, 0x7d, 0x5f, 0x2b, 0x5f, 0x2f, 0x98, 0x98, 0xc8, + 0xf5, 0x57, 0x05, 0xb6, 0x26, 0x2f, 0xf3, 0xc7, 0x57, 0xc1, 0x4e, 0xa4, 0x54, 0xbe, 0x98, 0x3b, + 0x25, 0xe1, 0x70, 0xa6, 0x40, 0x79, 0xea, 0x4b, 0xe3, 0xd3, 0xab, 0x30, 0xa7, 0x65, 0x55, 0xbe, + 0x5c, 0x24, 0x2b, 0x21, 0xf3, 0x5a, 0x81, 0x5b, 0x19, 0xb6, 0xf3, 0xf9, 0xf5, 0x80, 0xc7, 0xf3, + 0x2a, 0x0f, 0x17, 0xcb, 0x9b, 0x42, 0x69, 0xe2, 0x2b, 0xe4, 0x9a, 0x94, 0xc6, 0xf3, 0xae, 0x4b, + 0x29, 0xeb, 0x4d, 0x2f, 0xc5, 0x9c, 0x65, 0x5b, 0x0f, 0xe6, 0xc0, 0x4e, 0x27, 0x5e, 0x2d, 0xe6, + 0x2b, 0x8c, 0x67, 0x9c, 0xd5, 0x88, 0xeb, 0xcc, 0xc3, 0x2a, 0x9d, 0x38, 0x17, 0xab, 0x69, 0xa6, + 0x71, 0xf8, 0xe4, 0xcd, 0x79, 0x55, 0x79, 0x7b, 0x5e, 0x55, 0xfe, 0x39, 0xaf, 0x2a, 0xaf, 0x2f, + 0xaa, 0xb9, 0xb7, 0x17, 0xd5, 0xdc, 0x5f, 0x17, 0xd5, 0xdc, 0x0b, 0x23, 0xe5, 0x55, 0x01, 0xf4, + 0x9e, 0x7c, 0x8a, 0x11, 0x3f, 0xc5, 0x78, 0x69, 0x5c, 0x7e, 0xdd, 0x06, 0xc6, 0xd5, 0x5e, 0x91, + 0x5f, 0xa6, 0x9f, 0xfc, 0x17, 0x00, 0x00, 0xff, 0xff, 0x42, 0x83, 0xe6, 0x96, 0xf6, 0x0a, 0x00, + 0x00, } // Reference imports to suppress errors if they are not otherwise used. @@ -1151,6 +1153,16 @@ func (m *MsgUpdateZRC20WithdrawFee) MarshalToSizedBuffer(dAtA []byte) (int, erro _ = i var l int _ = l + { + size := m.NewGasLimit.Size() + i -= size + if _, err := m.NewGasLimit.MarshalTo(dAtA[i:]); err != nil { + return 0, err + } + i = encodeVarintTx(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0x3a { size := m.NewWithdrawFee.Size() i -= size @@ -1660,6 +1672,8 @@ func (m *MsgUpdateZRC20WithdrawFee) Size() (n int) { } l = m.NewWithdrawFee.Size() n += 1 + l + sovTx(uint64(l)) + l = m.NewGasLimit.Size() + n += 1 + l + sovTx(uint64(l)) return n } @@ -2000,6 +2014,40 @@ func (m *MsgUpdateZRC20WithdrawFee) Unmarshal(dAtA []byte) error { return err } iNdEx = postIndex + case 7: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field NewGasLimit", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowTx + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + stringLen |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + intStringLen := int(stringLen) + if intStringLen < 0 { + return ErrInvalidLengthTx + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthTx + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + if err := m.NewGasLimit.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex default: iNdEx = preIndex skippy, err := skipTx(dAtA[iNdEx:]) From a1d7be0d605c0dd6adb62da0503405adff461c58 Mon Sep 17 00:00:00 2001 From: kevinssgh <79858682+kevinssgh@users.noreply.github.com> Date: Tue, 10 Oct 2023 21:26:04 -0400 Subject: [PATCH 06/27] fix: Blame index update (#1264) * initial commit * added queries and unit tests * added cli * fix parse error * fix parse error 2 * fix lint and test errors * ran make generate * update index for keygen * refactor query name * refactor key calculation * refactor lib name --- cmd/zetaclientd/keygen_tss.go | 3 +- docs/openapi/openapi.swagger.yaml | 34 ++ proto/observer/query.proto | 14 + x/observer/client/cli/query.go | 1 + x/observer/client/cli/query_blame.go | 45 ++ x/observer/keeper/blame.go | 29 ++ x/observer/keeper/blame_test.go | 47 ++ x/observer/types/keys.go | 8 + x/observer/types/query.pb.go | 650 ++++++++++++++++++++++----- x/observer/types/query.pb.gw.go | 123 +++++ zetaclient/btc_signer.go | 2 +- zetaclient/btc_test.go | 2 +- zetaclient/evm_signer.go | 6 +- zetaclient/signer.go | 4 +- zetaclient/tss_signer.go | 10 +- 15 files changed, 848 insertions(+), 130 deletions(-) create mode 100644 x/observer/keeper/blame_test.go diff --git a/cmd/zetaclientd/keygen_tss.go b/cmd/zetaclientd/keygen_tss.go index 3b303450c3..5f76d7d512 100644 --- a/cmd/zetaclientd/keygen_tss.go +++ b/cmd/zetaclientd/keygen_tss.go @@ -134,7 +134,8 @@ func keygenTss(cfg *config.Config, tss *mc.TSS, keygenLogger zerolog.Logger) err if err != nil { return err } - zetaHash, err := tss.CoreBridge.PostBlameData(&res.Blame, common.ZetaChain().ChainId, digest) + index := fmt.Sprintf("keygen-%s-%d", digest, keyGen.BlockNumber) + zetaHash, err := tss.CoreBridge.PostBlameData(&res.Blame, common.ZetaChain().ChainId, index) if err != nil { keygenLogger.Error().Err(err).Msg("error sending blame data to core") return err diff --git a/docs/openapi/openapi.swagger.yaml b/docs/openapi/openapi.swagger.yaml index e7694c9585..39fa7d46df 100644 --- a/docs/openapi/openapi.swagger.yaml +++ b/docs/openapi/openapi.swagger.yaml @@ -27295,6 +27295,32 @@ paths: type: string tags: - Query + /zeta-chain/observer/blame_by_chain_and_nonce/{chain_id}/{nonce}: + get: + summary: Queries a list of VoterByIdentifier items. + operationId: Query_BlamesByChainAndNonce + responses: + "200": + description: A successful response. + schema: + $ref: '#/definitions/observerQueryBlameByChainAndNonceResponse' + default: + description: An unexpected error response. + schema: + $ref: '#/definitions/googlerpcStatus' + parameters: + - name: chain_id + in: path + required: true + type: string + format: int64 + - name: nonce + in: path + required: true + type: string + format: int64 + tags: + - Query /zeta-chain/observer/blame_by_identifier/{blame_identifier}: get: summary: Queries a list of VoterByIdentifier items. @@ -51119,6 +51145,14 @@ definitions: $ref: '#/definitions/observerObservationType' ballot_status: $ref: '#/definitions/observerBallotStatus' + observerQueryBlameByChainAndNonceResponse: + type: object + properties: + blame_info: + type: array + items: + type: object + $ref: '#/definitions/observerBlame' observerQueryBlameByIdentifierResponse: type: object properties: diff --git a/proto/observer/query.proto b/proto/observer/query.proto index fdd0733f04..1de4b9df30 100644 --- a/proto/observer/query.proto +++ b/proto/observer/query.proto @@ -80,6 +80,11 @@ service Query { option (google.api.http).get = "/zeta-chain/observer/get_all_blame_records"; } + // Queries a list of VoterByIdentifier items. + rpc BlamesByChainAndNonce(QueryBlameByChainAndNonceRequest) returns (QueryBlameByChainAndNonceResponse) { + option (google.api.http).get = "/zeta-chain/observer/blame_by_chain_and_nonce/{chain_id}/{nonce}"; + } + rpc GetAllBlockHeaders(QueryAllBlockHeaderRequest) returns (QueryAllBlockHeaderResponse) { option (google.api.http).get = "/zeta-chain/observer/get_all_block_headers"; } @@ -211,6 +216,15 @@ message QueryAllBlameRecordsResponse { repeated Blame blame_info = 1; } +message QueryBlameByChainAndNonceRequest { + int64 chain_id = 1; + int64 nonce = 2; +} + +message QueryBlameByChainAndNonceResponse { + repeated Blame blame_info = 1; +} + message QueryAllBlockHeaderRequest { cosmos.base.query.v1beta1.PageRequest pagination = 1; } diff --git a/x/observer/client/cli/query.go b/x/observer/client/cli/query.go index 1ea4d0d88b..47fd373eba 100644 --- a/x/observer/client/cli/query.go +++ b/x/observer/client/cli/query.go @@ -39,6 +39,7 @@ func GetQueryCmd(_ string) *cobra.Command { CmdShowObserverCount(), CmdBlameByIdentifier(), CmdGetAllBlameRecords(), + CmdGetBlameByChainAndNonce(), ) return cmd diff --git a/x/observer/client/cli/query_blame.go b/x/observer/client/cli/query_blame.go index aee13732b4..462c442279 100644 --- a/x/observer/client/cli/query_blame.go +++ b/x/observer/client/cli/query_blame.go @@ -1,6 +1,8 @@ package cli import ( + "strconv" + "github.com/cosmos/cosmos-sdk/client" "github.com/cosmos/cosmos-sdk/client/flags" "github.com/spf13/cobra" @@ -69,3 +71,46 @@ func CmdGetAllBlameRecords() *cobra.Command { return cmd } + +func CmdGetBlameByChainAndNonce() *cobra.Command { + cmd := &cobra.Command{ + Use: "list-blame-by-msg [chainId] [nonce]", + Short: "Query AllBlameRecords", + Args: cobra.ExactArgs(2), + RunE: func(cmd *cobra.Command, args []string) (err error) { + chainID := args[0] + nonce := args[1] + + clientCtx, err := client.GetClientTxContext(cmd) + if err != nil { + return err + } + + queryClient := types.NewQueryClient(clientCtx) + + chain, err := strconv.ParseInt(chainID, 10, 64) + if err != nil { + return err + } + nonceInt, err := strconv.ParseInt(nonce, 10, 64) + if err != nil { + return err + } + params := &types.QueryBlameByChainAndNonceRequest{ + ChainId: chain, + Nonce: nonceInt, + } + + res, err := queryClient.BlamesByChainAndNonce(cmd.Context(), params) + if err != nil { + return err + } + + return clientCtx.PrintProto(res) + }, + } + + flags.AddQueryFlagsToCmd(cmd) + + return cmd +} diff --git a/x/observer/keeper/blame.go b/x/observer/keeper/blame.go index 6acab15c64..a72ae4335f 100644 --- a/x/observer/keeper/blame.go +++ b/x/observer/keeper/blame.go @@ -40,6 +40,21 @@ func (k Keeper) GetAllBlame(ctx sdk.Context) (BlameRecords []*types.Blame, found return } +func (k Keeper) GetBlamesByChainAndNonce(ctx sdk.Context, chainID int64, nonce int64) (BlameRecords []*types.Blame, found bool) { + store := prefix.NewStore(ctx.KVStore(k.storeKey), types.KeyPrefix(types.BlameKey)) + blamePrefix := types.GetBlamePrefix(chainID, nonce) + iterator := sdk.KVStorePrefixIterator(store, []byte(blamePrefix)) + defer iterator.Close() + found = false + for ; iterator.Valid(); iterator.Next() { + var val types.Blame + k.cdc.MustUnmarshal(iterator.Value(), &val) + BlameRecords = append(BlameRecords, &val) + found = true + } + return +} + // Query func (k Keeper) BlameByIdentifier(goCtx context.Context, request *types.QueryBlameByIdentifierRequest) (*types.QueryBlameByIdentifierResponse, error) { @@ -71,3 +86,17 @@ func (k Keeper) GetAllBlameRecords(goCtx context.Context, request *types.QueryAl BlameInfo: blameRecords, }, nil } + +func (k Keeper) BlamesByChainAndNonce(goCtx context.Context, request *types.QueryBlameByChainAndNonceRequest) (*types.QueryBlameByChainAndNonceResponse, error) { + if request == nil { + return nil, status.Error(codes.InvalidArgument, "invalid request") + } + ctx := sdk.UnwrapSDKContext(goCtx) + blameRecords, found := k.GetBlamesByChainAndNonce(ctx, request.ChainId, request.Nonce) + if !found { + return nil, status.Error(codes.NotFound, "blame info not found") + } + return &types.QueryBlameByChainAndNonceResponse{ + BlameInfo: blameRecords, + }, nil +} diff --git a/x/observer/keeper/blame_test.go b/x/observer/keeper/blame_test.go new file mode 100644 index 0000000000..d12d69b84a --- /dev/null +++ b/x/observer/keeper/blame_test.go @@ -0,0 +1,47 @@ +package keeper + +import ( + "testing" + + "github.com/stretchr/testify/require" + "github.com/zeta-chain/zetacore/x/observer/types" +) + +func TestKeeper_BlameByIdentifier(t *testing.T) { + keeper, ctx := SetupKeeper(t) + var chainId int64 = 97 + var nonce uint64 = 101 + digest := "85f5e10431f69bc2a14046a13aabaefc660103b6de7a84f75c4b96181d03f0b5" + + index := types.GetBlameIndex(chainId, nonce, digest, 123) + + keeper.SetBlame(ctx, &types.Blame{ + Index: index, + FailureReason: "failed to join party", + Nodes: nil, + }) + + blameRecords, found := keeper.GetBlame(ctx, index) + require.True(t, found) + require.Equal(t, index, blameRecords.Index) +} + +func TestKeeper_BlameByChainAndNonce(t *testing.T) { + keeper, ctx := SetupKeeper(t) + var chainId int64 = 97 + var nonce uint64 = 101 + digest := "85f5e10431f69bc2a14046a13aabaefc660103b6de7a84f75c4b96181d03f0b5" + + index := types.GetBlameIndex(chainId, nonce, digest, 123) + + keeper.SetBlame(ctx, &types.Blame{ + Index: index, + FailureReason: "failed to join party", + Nodes: nil, + }) + + blameRecords, found := keeper.GetBlamesByChainAndNonce(ctx, chainId, int64(nonce)) + require.True(t, found) + require.Equal(t, 1, len(blameRecords)) + require.Equal(t, index, blameRecords[0].Index) +} diff --git a/x/observer/types/keys.go b/x/observer/types/keys.go index 4a28380ed9..0195496735 100644 --- a/x/observer/types/keys.go +++ b/x/observer/types/keys.go @@ -50,3 +50,11 @@ const ( BallotListKey = "BallotList-value-" ) + +func GetBlameIndex(chainID int64, nonce uint64, digest string, height uint64) string { + return fmt.Sprintf("%d-%d-%s-%d", chainID, nonce, digest, height) +} + +func GetBlamePrefix(chainID int64, nonce int64) string { + return fmt.Sprintf("%d-%d", chainID, nonce) +} diff --git a/x/observer/types/query.pb.go b/x/observer/types/query.pb.go index 6917312022..16985b39b0 100644 --- a/x/observer/types/query.pb.go +++ b/x/observer/types/query.pb.go @@ -1406,6 +1406,102 @@ func (m *QueryAllBlameRecordsResponse) GetBlameInfo() []*Blame { return nil } +type QueryBlameByChainAndNonceRequest struct { + ChainId int64 `protobuf:"varint,1,opt,name=chain_id,json=chainId,proto3" json:"chain_id,omitempty"` + Nonce int64 `protobuf:"varint,2,opt,name=nonce,proto3" json:"nonce,omitempty"` +} + +func (m *QueryBlameByChainAndNonceRequest) Reset() { *m = QueryBlameByChainAndNonceRequest{} } +func (m *QueryBlameByChainAndNonceRequest) String() string { return proto.CompactTextString(m) } +func (*QueryBlameByChainAndNonceRequest) ProtoMessage() {} +func (*QueryBlameByChainAndNonceRequest) Descriptor() ([]byte, []int) { + return fileDescriptor_dcb801e455adaee4, []int{31} +} +func (m *QueryBlameByChainAndNonceRequest) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *QueryBlameByChainAndNonceRequest) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_QueryBlameByChainAndNonceRequest.Marshal(b, m, deterministic) + } else { + b = b[:cap(b)] + n, err := m.MarshalToSizedBuffer(b) + if err != nil { + return nil, err + } + return b[:n], nil + } +} +func (m *QueryBlameByChainAndNonceRequest) XXX_Merge(src proto.Message) { + xxx_messageInfo_QueryBlameByChainAndNonceRequest.Merge(m, src) +} +func (m *QueryBlameByChainAndNonceRequest) XXX_Size() int { + return m.Size() +} +func (m *QueryBlameByChainAndNonceRequest) XXX_DiscardUnknown() { + xxx_messageInfo_QueryBlameByChainAndNonceRequest.DiscardUnknown(m) +} + +var xxx_messageInfo_QueryBlameByChainAndNonceRequest proto.InternalMessageInfo + +func (m *QueryBlameByChainAndNonceRequest) GetChainId() int64 { + if m != nil { + return m.ChainId + } + return 0 +} + +func (m *QueryBlameByChainAndNonceRequest) GetNonce() int64 { + if m != nil { + return m.Nonce + } + return 0 +} + +type QueryBlameByChainAndNonceResponse struct { + BlameInfo []*Blame `protobuf:"bytes,1,rep,name=blame_info,json=blameInfo,proto3" json:"blame_info,omitempty"` +} + +func (m *QueryBlameByChainAndNonceResponse) Reset() { *m = QueryBlameByChainAndNonceResponse{} } +func (m *QueryBlameByChainAndNonceResponse) String() string { return proto.CompactTextString(m) } +func (*QueryBlameByChainAndNonceResponse) ProtoMessage() {} +func (*QueryBlameByChainAndNonceResponse) Descriptor() ([]byte, []int) { + return fileDescriptor_dcb801e455adaee4, []int{32} +} +func (m *QueryBlameByChainAndNonceResponse) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *QueryBlameByChainAndNonceResponse) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_QueryBlameByChainAndNonceResponse.Marshal(b, m, deterministic) + } else { + b = b[:cap(b)] + n, err := m.MarshalToSizedBuffer(b) + if err != nil { + return nil, err + } + return b[:n], nil + } +} +func (m *QueryBlameByChainAndNonceResponse) XXX_Merge(src proto.Message) { + xxx_messageInfo_QueryBlameByChainAndNonceResponse.Merge(m, src) +} +func (m *QueryBlameByChainAndNonceResponse) XXX_Size() int { + return m.Size() +} +func (m *QueryBlameByChainAndNonceResponse) XXX_DiscardUnknown() { + xxx_messageInfo_QueryBlameByChainAndNonceResponse.DiscardUnknown(m) +} + +var xxx_messageInfo_QueryBlameByChainAndNonceResponse proto.InternalMessageInfo + +func (m *QueryBlameByChainAndNonceResponse) GetBlameInfo() []*Blame { + if m != nil { + return m.BlameInfo + } + return nil +} + type QueryAllBlockHeaderRequest struct { Pagination *query.PageRequest `protobuf:"bytes,1,opt,name=pagination,proto3" json:"pagination,omitempty"` } @@ -1414,7 +1510,7 @@ func (m *QueryAllBlockHeaderRequest) Reset() { *m = QueryAllBlockHeaderR func (m *QueryAllBlockHeaderRequest) String() string { return proto.CompactTextString(m) } func (*QueryAllBlockHeaderRequest) ProtoMessage() {} func (*QueryAllBlockHeaderRequest) Descriptor() ([]byte, []int) { - return fileDescriptor_dcb801e455adaee4, []int{31} + return fileDescriptor_dcb801e455adaee4, []int{33} } func (m *QueryAllBlockHeaderRequest) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -1459,7 +1555,7 @@ func (m *QueryAllBlockHeaderResponse) Reset() { *m = QueryAllBlockHeader func (m *QueryAllBlockHeaderResponse) String() string { return proto.CompactTextString(m) } func (*QueryAllBlockHeaderResponse) ProtoMessage() {} func (*QueryAllBlockHeaderResponse) Descriptor() ([]byte, []int) { - return fileDescriptor_dcb801e455adaee4, []int{32} + return fileDescriptor_dcb801e455adaee4, []int{34} } func (m *QueryAllBlockHeaderResponse) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -1510,7 +1606,7 @@ func (m *QueryGetBlockHeaderByHashRequest) Reset() { *m = QueryGetBlockH func (m *QueryGetBlockHeaderByHashRequest) String() string { return proto.CompactTextString(m) } func (*QueryGetBlockHeaderByHashRequest) ProtoMessage() {} func (*QueryGetBlockHeaderByHashRequest) Descriptor() ([]byte, []int) { - return fileDescriptor_dcb801e455adaee4, []int{33} + return fileDescriptor_dcb801e455adaee4, []int{35} } func (m *QueryGetBlockHeaderByHashRequest) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -1554,7 +1650,7 @@ func (m *QueryGetBlockHeaderByHashResponse) Reset() { *m = QueryGetBlock func (m *QueryGetBlockHeaderByHashResponse) String() string { return proto.CompactTextString(m) } func (*QueryGetBlockHeaderByHashResponse) ProtoMessage() {} func (*QueryGetBlockHeaderByHashResponse) Descriptor() ([]byte, []int) { - return fileDescriptor_dcb801e455adaee4, []int{34} + return fileDescriptor_dcb801e455adaee4, []int{36} } func (m *QueryGetBlockHeaderByHashResponse) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -1622,6 +1718,8 @@ func init() { proto.RegisterType((*QueryBlameByIdentifierResponse)(nil), "zetachain.zetacore.observer.QueryBlameByIdentifierResponse") proto.RegisterType((*QueryAllBlameRecordsRequest)(nil), "zetachain.zetacore.observer.QueryAllBlameRecordsRequest") proto.RegisterType((*QueryAllBlameRecordsResponse)(nil), "zetachain.zetacore.observer.QueryAllBlameRecordsResponse") + proto.RegisterType((*QueryBlameByChainAndNonceRequest)(nil), "zetachain.zetacore.observer.QueryBlameByChainAndNonceRequest") + proto.RegisterType((*QueryBlameByChainAndNonceResponse)(nil), "zetachain.zetacore.observer.QueryBlameByChainAndNonceResponse") proto.RegisterType((*QueryAllBlockHeaderRequest)(nil), "zetachain.zetacore.observer.QueryAllBlockHeaderRequest") proto.RegisterType((*QueryAllBlockHeaderResponse)(nil), "zetachain.zetacore.observer.QueryAllBlockHeaderResponse") proto.RegisterType((*QueryGetBlockHeaderByHashRequest)(nil), "zetachain.zetacore.observer.QueryGetBlockHeaderByHashRequest") @@ -1631,120 +1729,126 @@ func init() { func init() { proto.RegisterFile("observer/query.proto", fileDescriptor_dcb801e455adaee4) } var fileDescriptor_dcb801e455adaee4 = []byte{ - // 1798 bytes of a gzipped FileDescriptorProto - 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xac, 0x59, 0xcd, 0x4f, 0x1b, 0x49, - 0x16, 0xa7, 0x21, 0x38, 0xf0, 0x0c, 0x01, 0x0a, 0x92, 0x80, 0x01, 0xe3, 0x2d, 0x36, 0x89, 0x03, - 0x89, 0x1d, 0x1c, 0x29, 0x5f, 0x04, 0x22, 0x8c, 0xf2, 0x41, 0xbe, 0xd7, 0xd9, 0xcd, 0xae, 0x76, - 0xb5, 0x6b, 0xb5, 0xed, 0xc2, 0x38, 0x69, 0x5c, 0x4e, 0x77, 0x43, 0xf0, 0x46, 0x48, 0xab, 0x3d, - 0xcf, 0x48, 0x91, 0x46, 0x9a, 0xf3, 0x9c, 0xe6, 0x36, 0x73, 0xc8, 0x65, 0x0e, 0xd1, 0x5c, 0xe6, - 0x32, 0x39, 0x8d, 0x32, 0x1a, 0x69, 0x34, 0x73, 0x98, 0xd1, 0x28, 0x99, 0x3f, 0x64, 0xd4, 0xf5, - 0xd1, 0x2e, 0xb7, 0xbb, 0xed, 0x36, 0xca, 0x89, 0xae, 0x8f, 0xf7, 0xea, 0xf7, 0x7b, 0x55, 0xf5, - 0xde, 0xaf, 0x30, 0x4c, 0xd0, 0x82, 0x45, 0xcc, 0x5d, 0x62, 0xa6, 0x9f, 0xed, 0x10, 0xb3, 0x9e, - 0xaa, 0x99, 0xd4, 0xa6, 0x68, 0xfa, 0xbf, 0xc4, 0xd6, 0x8b, 0x5b, 0x7a, 0xa5, 0x9a, 0x62, 0x5f, - 0xd4, 0x24, 0x29, 0x39, 0x31, 0x36, 0x5e, 0xa4, 0xdb, 0xdb, 0xb4, 0x9a, 0xe6, 0x7f, 0xb8, 0x45, - 0x6c, 0xa1, 0x48, 0xad, 0x6d, 0x6a, 0xa5, 0x0b, 0xba, 0x45, 0xb8, 0xab, 0xf4, 0xee, 0x52, 0x81, - 0xd8, 0xfa, 0x52, 0xba, 0xa6, 0x97, 0x2b, 0x55, 0xdd, 0xae, 0xb8, 0x73, 0x27, 0xca, 0xb4, 0x4c, - 0xd9, 0x67, 0xda, 0xf9, 0x12, 0xbd, 0x33, 0x65, 0x4a, 0xcb, 0x06, 0x49, 0xeb, 0xb5, 0x4a, 0x5a, - 0xaf, 0x56, 0xa9, 0xcd, 0x4c, 0x2c, 0x31, 0x7a, 0xd4, 0xc5, 0x59, 0xd0, 0x0d, 0x83, 0xda, 0xd2, - 0x55, 0xa3, 0xdb, 0xd0, 0xb7, 0x89, 0xe8, 0x9d, 0x73, 0x7b, 0x8b, 0x26, 0xb5, 0x2c, 0x46, 0x24, - 0xbf, 0x69, 0xe8, 0xe5, 0x56, 0x6f, 0x4f, 0x49, 0xbd, 0x4c, 0x24, 0xb0, 0x69, 0xb7, 0xbb, 0x4a, - 0x4b, 0x24, 0xaf, 0x17, 0x8b, 0x74, 0xa7, 0x2a, 0x97, 0x3a, 0xee, 0x0e, 0xca, 0x8f, 0x16, 0x67, - 0x35, 0xdd, 0xd4, 0xb7, 0xc5, 0x1a, 0xf8, 0x73, 0x0d, 0xc6, 0xfe, 0xe2, 0x04, 0xe2, 0xa1, 0x49, - 0x77, 0x49, 0x8e, 0x3c, 0xdb, 0x21, 0x96, 0x8d, 0xa6, 0x60, 0x80, 0xc3, 0xa9, 0x94, 0x26, 0xb5, - 0x84, 0x96, 0x3c, 0x94, 0x3b, 0xcc, 0xda, 0x1b, 0x25, 0x74, 0x1c, 0x0e, 0xdb, 0x7b, 0xf9, 0x2d, - 0xdd, 0xda, 0x9a, 0xec, 0x4d, 0x68, 0xc9, 0xc1, 0x5c, 0xc4, 0xde, 0xbb, 0xa5, 0x5b, 0x5b, 0x68, - 0x1e, 0xfa, 0x6b, 0x26, 0xa5, 0x9b, 0x93, 0x7d, 0x09, 0x2d, 0x19, 0xcd, 0x0c, 0xa7, 0x44, 0xe4, - 0x1f, 0x3a, 0x9d, 0x39, 0x3e, 0x86, 0x66, 0x01, 0x0a, 0x06, 0x2d, 0x3e, 0xe5, 0x0e, 0x0e, 0x31, - 0x07, 0x83, 0xac, 0x87, 0xf9, 0x98, 0x82, 0x01, 0x7b, 0x2f, 0x5f, 0xa9, 0x96, 0xc8, 0xde, 0x64, - 0x7f, 0x42, 0x4b, 0xf6, 0xe5, 0x0e, 0xdb, 0x7b, 0x1b, 0x4e, 0x13, 0x2f, 0x00, 0x52, 0x71, 0x5a, - 0x35, 0x5a, 0xb5, 0x08, 0x9a, 0x80, 0xfe, 0x5d, 0xdd, 0x10, 0x28, 0x07, 0x72, 0xbc, 0x81, 0x27, - 0xe4, 0x5c, 0xc6, 0x54, 0x90, 0xc2, 0xff, 0x80, 0xf1, 0xa6, 0x5e, 0xe1, 0x62, 0x0d, 0x22, 0x3c, - 0x22, 0xcc, 0x47, 0x34, 0x33, 0x9f, 0x6a, 0x73, 0xac, 0x52, 0xdc, 0x38, 0x7b, 0xe8, 0xcd, 0xaf, - 0x73, 0x3d, 0x39, 0x61, 0x88, 0xef, 0x41, 0x9c, 0x79, 0xce, 0xb2, 0x4d, 0xcf, 0xd6, 0x37, 0x4a, - 0xa4, 0x6a, 0x57, 0x36, 0x2b, 0xc4, 0x94, 0x01, 0x5d, 0x84, 0x31, 0x7e, 0x22, 0xf2, 0x15, 0x77, - 0x8c, 0xad, 0x37, 0x98, 0x1b, 0xe5, 0x03, 0x0d, 0x1b, 0x6c, 0xc3, 0xe0, 0x63, 0x6a, 0x13, 0xf3, - 0x6e, 0xc5, 0xb2, 0xd1, 0x3c, 0x0c, 0xef, 0x3a, 0x8d, 0xbc, 0x5e, 0x2a, 0x99, 0xc4, 0xb2, 0x84, - 0xd5, 0x10, 0xeb, 0x5c, 0xe3, 0x7d, 0x28, 0x0b, 0x83, 0x4e, 0x3b, 0x6f, 0xd7, 0x6b, 0x84, 0x6d, - 0xcb, 0x91, 0xcc, 0x89, 0xb6, 0x34, 0x1c, 0xff, 0x7f, 0xad, 0xd7, 0x48, 0x6e, 0x60, 0x57, 0x7c, - 0xe1, 0xaf, 0x7a, 0x61, 0x2e, 0x90, 0x85, 0x88, 0x55, 0x37, 0x34, 0xd0, 0x2a, 0x44, 0x18, 0x48, - 0x6b, 0xb2, 0x37, 0xd1, 0x97, 0x8c, 0x66, 0x4e, 0x76, 0x44, 0xc4, 0x18, 0xe7, 0x84, 0x15, 0xfa, - 0x3b, 0x8c, 0xf2, 0x51, 0x76, 0xc5, 0x38, 0xb7, 0x3e, 0xc6, 0xed, 0x4c, 0x5b, 0x4f, 0x0f, 0x1a, - 0x46, 0x8c, 0xe2, 0x08, 0x6d, 0xee, 0x40, 0xf7, 0x61, 0x58, 0xb0, 0xb0, 0x6c, 0xdd, 0xde, 0xb1, - 0xd8, 0x39, 0x3c, 0x92, 0x39, 0xdd, 0xd6, 0x2b, 0x8f, 0xca, 0x23, 0x66, 0x90, 0x1b, 0x2a, 0x28, - 0x2d, 0x7c, 0x07, 0x66, 0x58, 0xe0, 0x1e, 0x88, 0xb9, 0x56, 0xb6, 0xbe, 0xee, 0x78, 0x51, 0x36, - 0x5f, 0x25, 0xc2, 0x56, 0x90, 0x51, 0x53, 0x06, 0x98, 0x0d, 0x5e, 0x81, 0xd9, 0x00, 0x67, 0x62, - 0x0f, 0x66, 0x60, 0x50, 0x82, 0x72, 0x0e, 0x43, 0x9f, 0x73, 0x83, 0xdc, 0x0e, 0x9c, 0x10, 0x47, - 0x71, 0xcd, 0x30, 0xa4, 0x87, 0x7b, 0x7a, 0xad, 0x46, 0x4c, 0xf7, 0x1a, 0xd4, 0xc5, 0x36, 0xfb, - 0xcd, 0x10, 0x4b, 0x3c, 0x96, 0x91, 0x27, 0x66, 0x7e, 0x9b, 0x8f, 0xb1, 0x95, 0xa2, 0x99, 0xc5, - 0x10, 0x91, 0x97, 0xfe, 0x64, 0xe0, 0x5d, 0xff, 0xf8, 0x18, 0x4c, 0xb0, 0xa5, 0x1f, 0xed, 0xd4, - 0x6a, 0xd4, 0xb4, 0x49, 0x89, 0x31, 0xb3, 0xf0, 0x75, 0x11, 0x40, 0x4f, 0xbf, 0x8b, 0xe7, 0x04, - 0x44, 0xd8, 0x92, 0x12, 0x85, 0x9b, 0x5b, 0x78, 0x64, 0xc4, 0x20, 0x5e, 0x85, 0x3f, 0x31, 0x37, - 0x37, 0x89, 0xbd, 0x4e, 0x4d, 0xc2, 0xaf, 0xea, 0x0d, 0x6a, 0x36, 0x6d, 0x86, 0x37, 0xb5, 0xf5, - 0xb9, 0xa9, 0x0d, 0x57, 0x01, 0xb7, 0xb3, 0x17, 0x60, 0x6e, 0x41, 0xd4, 0x61, 0x9d, 0x6f, 0x4a, - 0x1a, 0xa7, 0xda, 0xc6, 0xa5, 0xe1, 0x2d, 0x07, 0x45, 0xf7, 0x1b, 0x4f, 0xc3, 0x54, 0xeb, 0x7a, - 0x72, 0x9b, 0x9e, 0x40, 0xcc, 0x6f, 0x50, 0x80, 0xb8, 0xeb, 0x07, 0x62, 0x31, 0x24, 0x08, 0x76, - 0xcb, 0x54, 0x20, 0x99, 0xc6, 0x5a, 0xf7, 0x69, 0x89, 0xac, 0xf1, 0x8a, 0x22, 0x23, 0x36, 0x01, - 0xfd, 0x3c, 0x23, 0xf3, 0x23, 0xcb, 0x1b, 0xf8, 0x09, 0x4c, 0xfb, 0xda, 0x08, 0x80, 0x77, 0x60, - 0x48, 0xad, 0x4e, 0x02, 0x61, 0xb2, 0x2d, 0x42, 0xd5, 0x4f, 0xb4, 0xda, 0x68, 0xe0, 0x92, 0xc0, - 0xb7, 0x66, 0x18, 0x3e, 0xf8, 0x6e, 0x00, 0x34, 0x8a, 0xb7, 0x58, 0xe8, 0x64, 0x8a, 0x57, 0xfa, - 0x94, 0x53, 0xe9, 0x53, 0x5c, 0x34, 0x88, 0x4a, 0x9f, 0x7a, 0xa8, 0x97, 0x65, 0xa1, 0xcb, 0x29, - 0x96, 0xf8, 0x95, 0x26, 0x28, 0x79, 0x97, 0x11, 0x94, 0x6e, 0x43, 0x54, 0xe9, 0x16, 0x47, 0xb1, - 0x0b, 0x46, 0x4a, 0x03, 0xdd, 0x6c, 0xc2, 0xdc, 0x2b, 0xce, 0x50, 0x27, 0xcc, 0x1c, 0x48, 0x13, - 0x68, 0x79, 0xdf, 0x9d, 0x63, 0xe2, 0xaa, 0x88, 0x1b, 0x8e, 0x88, 0x90, 0x07, 0xe9, 0x7f, 0x9a, - 0xb8, 0xf0, 0x7e, 0x53, 0x04, 0xb5, 0x7f, 0xc3, 0xa8, 0x57, 0x83, 0x88, 0x40, 0xb6, 0x4f, 0xb5, - 0x1e, 0x7f, 0xa2, 0x2c, 0x8e, 0x14, 0x9b, 0xbb, 0xf1, 0x71, 0x38, 0x2a, 0x11, 0xdc, 0x61, 0x4a, - 0x46, 0x62, 0xfb, 0x1b, 0x1c, 0xf3, 0x0e, 0x08, 0x44, 0xcb, 0x10, 0xe1, 0xa2, 0x27, 0x54, 0x55, - 0x16, 0xc6, 0xc2, 0x04, 0xcf, 0x89, 0x1c, 0xfa, 0x68, 0x8b, 0x3e, 0x97, 0x39, 0x69, 0x5d, 0x39, - 0x32, 0x4e, 0x4c, 0xe2, 0x41, 0x33, 0x04, 0x80, 0xff, 0xc0, 0xb8, 0xa1, 0x5b, 0x76, 0xde, 0x4d, - 0x84, 0xea, 0x39, 0x4e, 0xb5, 0x45, 0x73, 0x57, 0xb7, 0xec, 0x66, 0xa7, 0x63, 0x86, 0xb7, 0x0b, - 0xdf, 0x16, 0x18, 0xb3, 0x8e, 0x22, 0xf4, 0x93, 0x0c, 0xa7, 0x61, 0x94, 0xa9, 0xc5, 0xd6, 0x52, - 0x3b, 0xc2, 0xfa, 0x15, 0xc1, 0x50, 0x94, 0xfa, 0xa3, 0xd5, 0x97, 0x2b, 0x72, 0x40, 0x38, 0xab, - 0x6e, 0x52, 0x41, 0x02, 0xb7, 0xaf, 0x77, 0xce, 0x74, 0x47, 0x9b, 0x39, 0x4b, 0x55, 0x37, 0x29, - 0x9e, 0x6d, 0xdc, 0x0e, 0x3e, 0x46, 0x8a, 0xd4, 0x2c, 0xb9, 0xc7, 0x4c, 0x17, 0x39, 0xbc, 0x65, - 0x38, 0x00, 0x41, 0x5f, 0xf7, 0x08, 0x94, 0x34, 0x90, 0x65, 0x92, 0x91, 0xe8, 0xa5, 0x46, 0xbc, - 0x3e, 0x54, 0x1a, 0xf8, 0x4c, 0x53, 0x89, 0x2a, 0xcb, 0x08, 0x22, 0x97, 0x60, 0x58, 0x48, 0x58, - 0xd6, 0x2f, 0x6b, 0xd2, 0xb8, 0xac, 0x49, 0xaa, 0xcd, 0x50, 0xa1, 0xd1, 0xb0, 0x3e, 0xdc, 0xa5, - 0x5f, 0x83, 0x84, 0xbc, 0x36, 0xca, 0x6a, 0xd9, 0xba, 0xa3, 0xa1, 0x65, 0x38, 0x9a, 0x95, 0xb6, - 0x13, 0x8e, 0x21, 0x45, 0x69, 0xe3, 0x7f, 0x35, 0x6a, 0xa5, 0x8f, 0x0b, 0x41, 0xf5, 0x02, 0x0c, - 0xa9, 0x54, 0x45, 0x50, 0x7d, 0x99, 0x46, 0x15, 0xa6, 0x99, 0x8f, 0xa7, 0xa0, 0x9f, 0x79, 0x47, - 0x2f, 0x35, 0x88, 0xf0, 0x22, 0x83, 0xd2, 0x6d, 0x37, 0xbb, 0x55, 0xaf, 0xc7, 0xce, 0x85, 0x37, - 0xe0, 0x78, 0xf1, 0xfc, 0xff, 0x7f, 0xf8, 0xfd, 0x93, 0xde, 0x59, 0x34, 0x9d, 0x76, 0xe6, 0x9f, - 0x65, 0xa6, 0x69, 0xcf, 0xbb, 0x07, 0xfd, 0xa8, 0x01, 0x6a, 0x95, 0xb8, 0x68, 0xb9, 0xf3, 0x6a, - 0x81, 0xf2, 0x3e, 0x76, 0xf5, 0x60, 0xc6, 0x02, 0xf6, 0x75, 0x06, 0xfb, 0x1a, 0x5a, 0xf1, 0x85, - 0x2d, 0xa4, 0x6a, 0xa1, 0xae, 0x24, 0x82, 0xf4, 0x8b, 0x16, 0x19, 0xbe, 0x8f, 0xbe, 0xd3, 0x60, - 0xd4, 0xab, 0x1a, 0xd1, 0xe5, 0xce, 0xc8, 0x02, 0x64, 0x6b, 0xec, 0xca, 0x41, 0x4c, 0x05, 0xa5, - 0x75, 0x46, 0x69, 0x05, 0x2d, 0xfb, 0x52, 0x72, 0xe5, 0xaa, 0xc3, 0x8a, 0x8f, 0xbd, 0x68, 0x51, - 0xc8, 0xfb, 0xe8, 0x1b, 0x0d, 0x50, 0xab, 0x4a, 0x0d, 0xb3, 0x53, 0x81, 0xea, 0x37, 0xcc, 0x4e, - 0x05, 0x0b, 0x63, 0xbc, 0xc4, 0x68, 0x2d, 0xa2, 0xd3, 0xbe, 0xb4, 0x74, 0xc3, 0xc8, 0x7b, 0x75, - 0x33, 0xfa, 0x42, 0x83, 0x11, 0x8f, 0xae, 0x45, 0x4b, 0x9d, 0x41, 0x78, 0x4c, 0x62, 0x97, 0xbb, - 0x36, 0x71, 0x41, 0x9f, 0x61, 0xa0, 0x4f, 0xa2, 0x3f, 0xfb, 0x82, 0xb6, 0x3c, 0xd8, 0x7e, 0xd1, - 0xe0, 0xa8, 0xaf, 0x00, 0x46, 0xab, 0x9d, 0x21, 0xb4, 0x53, 0xde, 0xb1, 0x6b, 0x07, 0xb6, 0x0f, - 0x75, 0xa8, 0xca, 0xc4, 0xce, 0x17, 0x8d, 0x0a, 0xa9, 0xda, 0x42, 0x15, 0xe7, 0x37, 0xa9, 0x29, - 0x4f, 0x97, 0x94, 0xfc, 0xfb, 0xe8, 0x4b, 0x0d, 0x86, 0x9b, 0x96, 0x41, 0x17, 0xba, 0xc4, 0x25, - 0xf9, 0x5c, 0xec, 0xda, 0x2e, 0xd4, 0x86, 0x30, 0x1e, 0x0d, 0x6d, 0x8f, 0x5e, 0x69, 0x4d, 0xba, - 0x13, 0x85, 0x5b, 0xb6, 0x55, 0x27, 0xc7, 0x2e, 0x75, 0x6f, 0x28, 0x00, 0x9f, 0x63, 0x80, 0x17, - 0x50, 0xd2, 0x17, 0xb0, 0xa2, 0xd4, 0xd3, 0x2f, 0xd8, 0xe3, 0x60, 0xdf, 0x39, 0xf5, 0x47, 0x14, - 0x4f, 0x6b, 0x86, 0x11, 0x06, 0xb7, 0xaf, 0xbe, 0x0f, 0x83, 0xdb, 0x5f, 0xb1, 0xe3, 0x24, 0xc3, - 0x8d, 0x51, 0xa2, 0x13, 0x6e, 0xf4, 0x5a, 0x83, 0x11, 0x8f, 0x98, 0x0d, 0x93, 0x67, 0x02, 0x55, - 0x77, 0x98, 0x3c, 0x13, 0xac, 0xc7, 0xf1, 0x59, 0x06, 0xfc, 0x14, 0x3a, 0xe1, 0x0b, 0xdc, 0x2b, - 0xd5, 0xd1, 0xa7, 0x1a, 0x44, 0xb8, 0x04, 0x46, 0x99, 0x50, 0xeb, 0x36, 0xa9, 0xf0, 0xd8, 0xf9, - 0xae, 0x6c, 0x42, 0xd5, 0x5a, 0x2e, 0xc4, 0xd1, 0xb7, 0x1a, 0x8c, 0xb5, 0x48, 0x6c, 0x14, 0xa2, - 0xb0, 0x04, 0x29, 0xf7, 0xd8, 0xf2, 0x81, 0x6c, 0x05, 0xe6, 0xcb, 0x0c, 0xf3, 0x79, 0xb4, 0xa4, - 0x62, 0x96, 0x5e, 0x94, 0x94, 0xb8, 0x45, 0x9f, 0x7b, 0x74, 0x3f, 0xfa, 0x5e, 0x83, 0xb1, 0x16, - 0x79, 0x1d, 0x86, 0x49, 0x90, 0xbe, 0x0f, 0xc3, 0x24, 0x50, 0xcf, 0x77, 0x48, 0x85, 0x5c, 0x68, - 0x7b, 0x15, 0x83, 0xe7, 0x31, 0xb1, 0x8f, 0xbe, 0xd6, 0x00, 0xdd, 0x24, 0xb6, 0x47, 0xb1, 0xa3, - 0x70, 0xf7, 0xcd, 0xe7, 0x0d, 0x10, 0xa6, 0x48, 0x05, 0x3c, 0x0f, 0x70, 0x86, 0x11, 0x3a, 0x83, - 0x16, 0x02, 0x73, 0xa2, 0x53, 0x5d, 0x39, 0x07, 0x53, 0x00, 0x7d, 0xad, 0xe0, 0x57, 0x64, 0xf6, - 0xc5, 0x90, 0x28, 0xbc, 0x2f, 0x88, 0xd8, 0xa5, 0xee, 0x0d, 0xbb, 0x44, 0xaf, 0x3c, 0x1b, 0xd0, - 0xcf, 0x1a, 0x4c, 0xf8, 0xa9, 0x6f, 0xb4, 0x12, 0xea, 0x3a, 0x06, 0x09, 0xff, 0xd8, 0xea, 0x41, - 0xcd, 0x05, 0x97, 0x2c, 0xe3, 0x72, 0x15, 0x5d, 0x09, 0xe4, 0xa2, 0xf2, 0x70, 0x4e, 0x99, 0xf3, - 0xc2, 0x70, 0xce, 0x97, 0x7c, 0x6d, 0xec, 0xa3, 0x8f, 0x34, 0xe8, 0x67, 0xff, 0xa8, 0x47, 0xa9, - 0x10, 0x22, 0x5e, 0xf9, 0xe5, 0x21, 0x96, 0x0e, 0x3d, 0x5f, 0xc0, 0xc5, 0x0c, 0xee, 0x0c, 0x8a, - 0xf9, 0x6b, 0x7e, 0x67, 0x6e, 0x76, 0xe3, 0xcd, 0xbb, 0xb8, 0xf6, 0xf6, 0x5d, 0x5c, 0xfb, 0xed, - 0x5d, 0x5c, 0x7b, 0xf9, 0x3e, 0xde, 0xf3, 0xf6, 0x7d, 0xbc, 0xe7, 0xa7, 0xf7, 0xf1, 0x9e, 0x7f, - 0xa6, 0xcb, 0x15, 0x7b, 0x6b, 0xa7, 0xe0, 0xbc, 0x68, 0x7c, 0x73, 0xc2, 0x5e, 0xc3, 0x95, 0x5d, - 0xaf, 0x11, 0xab, 0x10, 0x61, 0x3f, 0x9b, 0x9c, 0xff, 0x23, 0x00, 0x00, 0xff, 0xff, 0x50, 0x87, - 0x71, 0x20, 0x92, 0x1a, 0x00, 0x00, + // 1889 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xac, 0x59, 0xcf, 0x6f, 0x1b, 0xc7, + 0x15, 0xf6, 0x8a, 0x16, 0x6d, 0x3d, 0x4a, 0x96, 0x34, 0x92, 0x62, 0x79, 0x25, 0x51, 0xec, 0xa8, + 0x76, 0x68, 0xc9, 0xe1, 0x46, 0x34, 0x90, 0xd8, 0x51, 0xa4, 0x94, 0x14, 0x62, 0x59, 0xb1, 0xe3, + 0xb8, 0x54, 0x9b, 0x16, 0x2d, 0x5a, 0x62, 0x49, 0x8e, 0x28, 0x26, 0xab, 0x1d, 0x66, 0x77, 0xa5, + 0x88, 0x15, 0x04, 0x14, 0x3d, 0xf7, 0x10, 0xa0, 0x40, 0xcf, 0x3d, 0xf5, 0xd6, 0x1e, 0x72, 0xe9, + 0xa1, 0xe8, 0xa5, 0x97, 0xe6, 0x54, 0xa4, 0x28, 0x50, 0xb4, 0x87, 0x16, 0x81, 0xdd, 0x3f, 0xa0, + 0x7f, 0x42, 0x31, 0x3f, 0x76, 0x39, 0x5c, 0xee, 0x92, 0x4b, 0xc1, 0x27, 0x71, 0x67, 0xe6, 0xbd, + 0xf9, 0xbe, 0x37, 0x33, 0xef, 0xbd, 0x0f, 0x82, 0x79, 0x5a, 0x73, 0x89, 0x73, 0x4a, 0x1c, 0xe3, + 0xb3, 0x13, 0xe2, 0x74, 0x0a, 0x6d, 0x87, 0x7a, 0x14, 0x2d, 0xfd, 0x8c, 0x78, 0x66, 0xfd, 0xc8, + 0x6c, 0xd9, 0x05, 0xfe, 0x8b, 0x3a, 0xa4, 0xe0, 0x2f, 0xd4, 0xe7, 0xea, 0xf4, 0xf8, 0x98, 0xda, + 0x86, 0xf8, 0x23, 0x2c, 0xf4, 0xf5, 0x3a, 0x75, 0x8f, 0xa9, 0x6b, 0xd4, 0x4c, 0x97, 0x08, 0x57, + 0xc6, 0xe9, 0x66, 0x8d, 0x78, 0xe6, 0xa6, 0xd1, 0x36, 0x9b, 0x2d, 0xdb, 0xf4, 0x5a, 0xc1, 0xda, + 0xf9, 0x26, 0x6d, 0x52, 0xfe, 0xd3, 0x60, 0xbf, 0xe4, 0xe8, 0x72, 0x93, 0xd2, 0xa6, 0x45, 0x0c, + 0xb3, 0xdd, 0x32, 0x4c, 0xdb, 0xa6, 0x1e, 0x37, 0x71, 0xe5, 0xec, 0x42, 0x80, 0xb3, 0x66, 0x5a, + 0x16, 0xf5, 0x7c, 0x57, 0xdd, 0x61, 0xcb, 0x3c, 0x26, 0x72, 0x74, 0x35, 0x18, 0xad, 0x3b, 0xd4, + 0x75, 0x39, 0x91, 0xea, 0xa1, 0x65, 0x36, 0xfb, 0xbd, 0x7d, 0x4a, 0x3a, 0x4d, 0xe2, 0x03, 0x5b, + 0x0a, 0x86, 0x6d, 0xda, 0x20, 0x55, 0xb3, 0x5e, 0xa7, 0x27, 0xb6, 0xbf, 0xd5, 0xcd, 0x60, 0xd2, + 0xff, 0xd1, 0xe7, 0xac, 0x6d, 0x3a, 0xe6, 0xb1, 0xdc, 0x03, 0xff, 0x56, 0x83, 0xd9, 0xef, 0xb2, + 0x40, 0x3c, 0x77, 0xe8, 0x29, 0xa9, 0x90, 0xcf, 0x4e, 0x88, 0xeb, 0xa1, 0x5b, 0x70, 0x5d, 0xc0, + 0x69, 0x35, 0x16, 0xb5, 0x9c, 0x96, 0xbf, 0x5a, 0xb9, 0xc6, 0xbf, 0xf7, 0x1b, 0xe8, 0x26, 0x5c, + 0xf3, 0xce, 0xaa, 0x47, 0xa6, 0x7b, 0xb4, 0x38, 0x96, 0xd3, 0xf2, 0x13, 0x95, 0xb4, 0x77, 0xf6, + 0xd8, 0x74, 0x8f, 0xd0, 0x1a, 0x8c, 0xb7, 0x1d, 0x4a, 0x0f, 0x17, 0x53, 0x39, 0x2d, 0x9f, 0x29, + 0x4e, 0x15, 0x64, 0xe4, 0x9f, 0xb3, 0xc1, 0x8a, 0x98, 0x43, 0x2b, 0x00, 0x35, 0x8b, 0xd6, 0x3f, + 0x15, 0x0e, 0xae, 0x72, 0x07, 0x13, 0x7c, 0x84, 0xfb, 0xb8, 0x05, 0xd7, 0xbd, 0xb3, 0x6a, 0xcb, + 0x6e, 0x90, 0xb3, 0xc5, 0xf1, 0x9c, 0x96, 0x4f, 0x55, 0xae, 0x79, 0x67, 0xfb, 0xec, 0x13, 0xaf, + 0x03, 0x52, 0x71, 0xba, 0x6d, 0x6a, 0xbb, 0x04, 0xcd, 0xc3, 0xf8, 0xa9, 0x69, 0x49, 0x94, 0xd7, + 0x2b, 0xe2, 0x03, 0xcf, 0xfb, 0x6b, 0x39, 0x53, 0x49, 0x0a, 0xff, 0x10, 0xe6, 0x7a, 0x46, 0xa5, + 0x8b, 0x12, 0xa4, 0x45, 0x44, 0xb8, 0x8f, 0x4c, 0x71, 0xad, 0x30, 0xe0, 0x5a, 0x15, 0x84, 0x71, + 0xf9, 0xea, 0x57, 0xff, 0x59, 0xbd, 0x52, 0x91, 0x86, 0xf8, 0x43, 0xc8, 0x72, 0xcf, 0x65, 0x7e, + 0xe8, 0xe5, 0xce, 0x7e, 0x83, 0xd8, 0x5e, 0xeb, 0xb0, 0x45, 0x1c, 0x3f, 0xa0, 0x1b, 0x30, 0x2b, + 0x6e, 0x44, 0xb5, 0x15, 0xcc, 0xf1, 0xfd, 0x26, 0x2a, 0x33, 0x62, 0xa2, 0x6b, 0x83, 0x3d, 0x98, + 0xf8, 0x98, 0x7a, 0xc4, 0x79, 0xda, 0x72, 0x3d, 0xb4, 0x06, 0x53, 0xa7, 0xec, 0xa3, 0x6a, 0x36, + 0x1a, 0x0e, 0x71, 0x5d, 0x69, 0x35, 0xc9, 0x07, 0x4b, 0x62, 0x0c, 0x95, 0x61, 0x82, 0x7d, 0x57, + 0xbd, 0x4e, 0x9b, 0xf0, 0x63, 0xb9, 0x51, 0xbc, 0x3d, 0x90, 0x06, 0xf3, 0xff, 0xbd, 0x4e, 0x9b, + 0x54, 0xae, 0x9f, 0xca, 0x5f, 0xf8, 0x0f, 0x63, 0xb0, 0x1a, 0xcb, 0x42, 0xc6, 0x6a, 0x14, 0x1a, + 0x68, 0x07, 0xd2, 0x1c, 0xa4, 0xbb, 0x38, 0x96, 0x4b, 0xe5, 0x33, 0xc5, 0x3b, 0x43, 0x11, 0x71, + 0xc6, 0x15, 0x69, 0x85, 0x7e, 0x00, 0x33, 0x62, 0x96, 0x3f, 0x31, 0xc1, 0x2d, 0xc5, 0xb9, 0xdd, + 0x1b, 0xe8, 0xe9, 0xa3, 0xae, 0x11, 0xa7, 0x38, 0x4d, 0x7b, 0x07, 0xd0, 0x33, 0x98, 0x92, 0x2c, + 0x5c, 0xcf, 0xf4, 0x4e, 0x5c, 0x7e, 0x0f, 0x6f, 0x14, 0xef, 0x0e, 0xf4, 0x2a, 0xa2, 0x72, 0xc0, + 0x0d, 0x2a, 0x93, 0x35, 0xe5, 0x0b, 0x3f, 0x81, 0x65, 0x1e, 0xb8, 0x8f, 0xe4, 0x5a, 0xb7, 0xdc, + 0xd9, 0x65, 0x5e, 0x94, 0xc3, 0x57, 0x89, 0xf0, 0x1d, 0xfc, 0xa8, 0x29, 0x13, 0xdc, 0x06, 0x6f, + 0xc3, 0x4a, 0x8c, 0x33, 0x79, 0x06, 0xcb, 0x30, 0xe1, 0x83, 0x62, 0x97, 0x21, 0xc5, 0x5e, 0x50, + 0x30, 0x80, 0x73, 0xf2, 0x2a, 0x96, 0x2c, 0xcb, 0xf7, 0xf0, 0xa1, 0xd9, 0x6e, 0x13, 0x27, 0x78, + 0x06, 0x1d, 0x79, 0xcc, 0x51, 0x2b, 0xe4, 0x16, 0x1f, 0xfb, 0x91, 0x27, 0x4e, 0xf5, 0x58, 0xcc, + 0xf1, 0x9d, 0x32, 0xc5, 0x8d, 0x04, 0x91, 0xf7, 0xfd, 0xf9, 0x81, 0x0f, 0xfc, 0xe3, 0xd7, 0x60, + 0x9e, 0x6f, 0x7d, 0x70, 0xd2, 0x6e, 0x53, 0xc7, 0x23, 0x0d, 0xce, 0xcc, 0xc5, 0xef, 0xcb, 0x00, + 0x86, 0xc6, 0x03, 0x3c, 0xb7, 0x21, 0xcd, 0xb7, 0xf4, 0x51, 0x04, 0xb9, 0x45, 0x44, 0x46, 0x4e, + 0xe2, 0x1d, 0xf8, 0x16, 0x77, 0xb3, 0x47, 0xbc, 0x5d, 0xea, 0x10, 0xf1, 0x54, 0x1f, 0x51, 0xa7, + 0xe7, 0x30, 0xc2, 0xa9, 0x2d, 0x15, 0xa4, 0x36, 0x6c, 0x03, 0x1e, 0x64, 0x2f, 0xc1, 0x3c, 0x86, + 0x0c, 0x63, 0x5d, 0xed, 0x49, 0x1a, 0xaf, 0x0f, 0x8c, 0x4b, 0xd7, 0x5b, 0x05, 0xea, 0xc1, 0x6f, + 0xbc, 0x04, 0xb7, 0xfa, 0xf7, 0xf3, 0x8f, 0xe9, 0x13, 0xd0, 0xa3, 0x26, 0x25, 0x88, 0xa7, 0x51, + 0x20, 0x36, 0x12, 0x82, 0xe0, 0xaf, 0x4c, 0x05, 0x52, 0xec, 0xee, 0xf5, 0x8c, 0x36, 0x48, 0x49, + 0x54, 0x14, 0x3f, 0x62, 0xf3, 0x30, 0x2e, 0x32, 0xb2, 0xb8, 0xb2, 0xe2, 0x03, 0x7f, 0x02, 0x4b, + 0x91, 0x36, 0x12, 0xe0, 0x13, 0x98, 0x54, 0xab, 0x93, 0x44, 0x98, 0x1f, 0x88, 0x50, 0xf5, 0x93, + 0xb1, 0xbb, 0x1f, 0xb8, 0x21, 0xf1, 0x95, 0x2c, 0x2b, 0x02, 0xdf, 0x23, 0x80, 0x6e, 0xf1, 0x96, + 0x1b, 0xdd, 0x29, 0x88, 0x4a, 0x5f, 0x60, 0x95, 0xbe, 0x20, 0x9a, 0x06, 0x59, 0xe9, 0x0b, 0xcf, + 0xcd, 0xa6, 0x5f, 0xe8, 0x2a, 0x8a, 0x25, 0xfe, 0x52, 0x93, 0x94, 0xc2, 0xdb, 0x48, 0x4a, 0x1f, + 0x40, 0x46, 0x19, 0x96, 0x57, 0x71, 0x04, 0x46, 0xca, 0x07, 0xda, 0xeb, 0xc1, 0x3c, 0x26, 0xef, + 0xd0, 0x30, 0xcc, 0x02, 0x48, 0x0f, 0x68, 0xff, 0xbd, 0xb3, 0x6b, 0x12, 0x74, 0x11, 0x8f, 0x58, + 0x13, 0xe1, 0x5f, 0xa4, 0x9f, 0x6b, 0xf2, 0xc1, 0x47, 0x2d, 0x91, 0xd4, 0x7e, 0x02, 0x33, 0xe1, + 0x1e, 0x44, 0x06, 0x72, 0x70, 0xaa, 0x0d, 0xf9, 0x93, 0x65, 0x71, 0xba, 0xde, 0x3b, 0x8c, 0x6f, + 0xc2, 0x82, 0x8f, 0xe0, 0x09, 0xef, 0x64, 0x7c, 0x6c, 0xdf, 0x87, 0xd7, 0xc2, 0x13, 0x12, 0xd1, + 0x16, 0xa4, 0x45, 0xd3, 0x93, 0xa8, 0x2a, 0x4b, 0x63, 0x69, 0x82, 0x57, 0x65, 0x0e, 0x3d, 0x38, + 0xa2, 0x9f, 0xfb, 0x39, 0x69, 0x57, 0xb9, 0x32, 0x2c, 0x26, 0xd9, 0xb8, 0x15, 0x12, 0xc0, 0x4f, + 0x61, 0xce, 0x32, 0x5d, 0xaf, 0x1a, 0x24, 0x42, 0xf5, 0x1e, 0x17, 0x06, 0xa2, 0x79, 0x6a, 0xba, + 0x5e, 0xaf, 0xd3, 0x59, 0x2b, 0x3c, 0x84, 0x3f, 0x90, 0x18, 0xcb, 0xac, 0x23, 0x8c, 0x6a, 0x19, + 0xee, 0xc2, 0x0c, 0xef, 0x16, 0xfb, 0x4b, 0xed, 0x34, 0x1f, 0x57, 0x1a, 0x86, 0xba, 0xdf, 0x7f, + 0xf4, 0xfb, 0x0a, 0x9a, 0x1c, 0x90, 0xce, 0xec, 0x43, 0x2a, 0x49, 0xe0, 0xc1, 0xf5, 0x8e, 0x2d, + 0x67, 0xbd, 0x19, 0xdb, 0xca, 0x3e, 0xa4, 0x78, 0xa5, 0xfb, 0x3a, 0xc4, 0x1c, 0xa9, 0x53, 0xa7, + 0x11, 0x5c, 0x33, 0x53, 0xe6, 0xf0, 0xbe, 0xe9, 0x18, 0x04, 0xa9, 0xd1, 0x11, 0x1c, 0x40, 0x4e, + 0xa5, 0xc9, 0xd3, 0x72, 0xc9, 0x6e, 0x3c, 0xa3, 0x76, 0x9d, 0x0c, 0x4f, 0xef, 0x2c, 0x8f, 0xd9, + 0x6c, 0x29, 0x7f, 0x6e, 0xa9, 0x8a, 0xf8, 0xc0, 0x87, 0xb2, 0x68, 0x44, 0x3b, 0x7d, 0x75, 0xe0, + 0x95, 0x1c, 0x56, 0xe6, 0xfd, 0x2e, 0x31, 0x1b, 0xdd, 0xc3, 0x7e, 0x55, 0x39, 0xec, 0x37, 0x9a, + 0x7a, 0x4a, 0xca, 0x36, 0x92, 0xc8, 0x03, 0x98, 0x92, 0xfd, 0x37, 0x1f, 0xf7, 0x0b, 0xea, 0x9c, + 0x5f, 0x50, 0x55, 0x9b, 0xc9, 0x5a, 0xf7, 0xc3, 0x7d, 0x75, 0x19, 0xab, 0x24, 0x4f, 0x71, 0x8f, + 0x78, 0xca, 0x6e, 0xe5, 0x0e, 0x13, 0x00, 0x7e, 0x38, 0x7a, 0x65, 0x02, 0x0b, 0xc7, 0xa4, 0x22, + 0x13, 0xf0, 0x8f, 0xbb, 0x85, 0x3e, 0xc2, 0x85, 0xa4, 0xfa, 0x16, 0x4c, 0xaa, 0x54, 0x65, 0x50, + 0x23, 0x99, 0x66, 0x14, 0xa6, 0xc5, 0xff, 0xe9, 0x30, 0xce, 0xbd, 0xa3, 0x2f, 0x34, 0x48, 0x8b, + 0x0a, 0x89, 0x8c, 0x81, 0x87, 0xdd, 0x2f, 0x36, 0xf4, 0x37, 0x93, 0x1b, 0x08, 0xbc, 0x78, 0xed, + 0x17, 0x7f, 0xff, 0xef, 0xaf, 0xc6, 0x56, 0xd0, 0x92, 0xc1, 0xd6, 0xbf, 0xc1, 0x4d, 0x8d, 0x90, + 0x68, 0x43, 0xff, 0xd0, 0x00, 0xf5, 0xf7, 0xe7, 0x68, 0x6b, 0xf8, 0x6e, 0xb1, 0xda, 0x44, 0x7f, + 0xf7, 0x72, 0xc6, 0x12, 0xf6, 0xfb, 0x1c, 0xf6, 0x7b, 0x68, 0x3b, 0x12, 0xb6, 0xec, 0xb3, 0x6b, + 0x1d, 0x25, 0x8b, 0x19, 0xe7, 0x7d, 0x1a, 0xe2, 0x02, 0xfd, 0x55, 0x83, 0x99, 0x70, 0xcb, 0x8b, + 0x1e, 0x0e, 0x47, 0x16, 0xd3, 0x73, 0xeb, 0xef, 0x5c, 0xc6, 0x54, 0x52, 0xda, 0xe5, 0x94, 0xb6, + 0xd1, 0x56, 0x24, 0xa5, 0xa0, 0xd7, 0x66, 0xac, 0xc4, 0xdc, 0x79, 0x5f, 0x7b, 0x7f, 0x81, 0xfe, + 0xac, 0x01, 0xea, 0x6f, 0xb1, 0x93, 0x9c, 0x54, 0x6c, 0xeb, 0x9e, 0xe4, 0xa4, 0xe2, 0xbb, 0x7a, + 0xbc, 0xc9, 0x69, 0x6d, 0xa0, 0xbb, 0x91, 0xb4, 0x4c, 0xcb, 0xaa, 0x86, 0x9b, 0x7e, 0xf4, 0x3b, + 0x0d, 0xa6, 0x43, 0x4d, 0x39, 0xda, 0x1c, 0x0e, 0x22, 0x64, 0xa2, 0x3f, 0x1c, 0xd9, 0x24, 0x00, + 0x7d, 0x8f, 0x83, 0xbe, 0x83, 0xbe, 0x1d, 0x09, 0xda, 0x0d, 0x61, 0xfb, 0xb7, 0x06, 0x0b, 0x91, + 0xdd, 0x3b, 0xda, 0x19, 0x0e, 0x61, 0x90, 0x6c, 0xd0, 0xdf, 0xbb, 0xb4, 0x7d, 0xa2, 0x4b, 0xd5, + 0x24, 0x5e, 0xb5, 0x6e, 0xb5, 0x88, 0xed, 0xc9, 0x96, 0xbe, 0x7a, 0x48, 0x1d, 0xff, 0x76, 0xf9, + 0x05, 0xed, 0x02, 0xfd, 0x5e, 0x83, 0xa9, 0x9e, 0x6d, 0xd0, 0x5b, 0x23, 0xe2, 0xf2, 0xf9, 0xbc, + 0x3d, 0xb2, 0x5d, 0xa2, 0x03, 0xe1, 0x3c, 0xba, 0xc2, 0x04, 0x7d, 0xa9, 0xf5, 0x34, 0xcd, 0x28, + 0xd9, 0xb6, 0xfd, 0x4d, 0xbe, 0xfe, 0x60, 0x74, 0x43, 0x09, 0xf8, 0x4d, 0x0e, 0x78, 0x1d, 0xe5, + 0x23, 0x01, 0x2b, 0x32, 0xc3, 0x38, 0xe7, 0xca, 0xe6, 0x82, 0xdd, 0xfa, 0x1b, 0x8a, 0xa7, 0x92, + 0x65, 0x25, 0xc1, 0x1d, 0x29, 0x4e, 0x92, 0xe0, 0x8e, 0x96, 0x1b, 0x38, 0xcf, 0x71, 0x63, 0x94, + 0x1b, 0x86, 0x1b, 0xfd, 0x51, 0x83, 0xe9, 0x50, 0x27, 0x9e, 0x24, 0xcf, 0xc4, 0x4a, 0x86, 0x24, + 0x79, 0x26, 0x5e, 0x4c, 0xe0, 0x37, 0x38, 0xf0, 0xd7, 0xd1, 0xed, 0x48, 0xe0, 0x61, 0x9d, 0x81, + 0x7e, 0xad, 0x41, 0x5a, 0xf4, 0xef, 0xa8, 0x98, 0x68, 0xdf, 0x1e, 0x09, 0xa1, 0xdf, 0x1f, 0xc9, + 0x26, 0x51, 0xad, 0x15, 0x2a, 0x02, 0xfd, 0x45, 0x83, 0xd9, 0x3e, 0x7d, 0x80, 0x12, 0x14, 0x96, + 0x38, 0xd9, 0xa1, 0x6f, 0x5d, 0xca, 0x56, 0x62, 0x7e, 0xc8, 0x31, 0xdf, 0x47, 0x9b, 0x2a, 0x66, + 0xdf, 0x8b, 0x92, 0x12, 0x8f, 0xe8, 0xe7, 0x21, 0xd1, 0x82, 0xfe, 0xa6, 0xc1, 0x6c, 0x9f, 0x36, + 0x48, 0xc2, 0x24, 0x4e, 0x9c, 0x24, 0x61, 0x12, 0x2b, 0x46, 0x86, 0xa4, 0x42, 0xd1, 0x68, 0x87, + 0x3b, 0x86, 0x90, 0x12, 0xba, 0x40, 0x7f, 0xd2, 0x00, 0xed, 0x11, 0x2f, 0x24, 0x37, 0x50, 0xb2, + 0xf7, 0x16, 0x21, 0x60, 0x92, 0x14, 0xa9, 0x18, 0x6d, 0x83, 0x8b, 0x9c, 0xd0, 0x3d, 0xb4, 0x1e, + 0x9b, 0x13, 0x59, 0x75, 0x15, 0x1c, 0x1c, 0x09, 0xf4, 0x1b, 0x0d, 0x16, 0xb8, 0x33, 0x37, 0x24, + 0x3a, 0xd0, 0x76, 0xe2, 0xd8, 0x46, 0x29, 0x20, 0x7d, 0xe7, 0xb2, 0xe6, 0x92, 0xcc, 0x63, 0x4e, + 0xa6, 0x8c, 0xbe, 0x33, 0xf8, 0x74, 0xc4, 0x13, 0x36, 0xed, 0x46, 0x95, 0xeb, 0x28, 0xa5, 0x4a, + 0x19, 0xe7, 0x7c, 0xe4, 0x82, 0xe5, 0xa5, 0xe0, 0x88, 0x14, 0x25, 0xf1, 0x76, 0xc2, 0x40, 0x87, + 0x45, 0x92, 0xfe, 0x60, 0x74, 0xc3, 0x11, 0x0f, 0x48, 0x51, 0x46, 0xe8, 0x5f, 0x1a, 0xcc, 0x47, + 0x09, 0x8c, 0x24, 0xe7, 0x33, 0x40, 0xdb, 0xe8, 0x3b, 0x97, 0x35, 0x97, 0x5c, 0xca, 0x9c, 0xcb, + 0xbb, 0xe8, 0x9d, 0x58, 0x2e, 0x2a, 0x0f, 0x76, 0x54, 0x4c, 0x44, 0xb1, 0x27, 0xe4, 0x0b, 0xaa, + 0x0b, 0xf4, 0x4b, 0x0d, 0xc6, 0xf9, 0x3f, 0x52, 0x50, 0x21, 0x81, 0x4e, 0x51, 0xfe, 0x33, 0xa4, + 0x1b, 0x89, 0xd7, 0x4b, 0xb8, 0x98, 0xc3, 0x5d, 0x46, 0x7a, 0xb4, 0xac, 0x61, 0x6b, 0xcb, 0xfb, + 0x5f, 0xbd, 0xc8, 0x6a, 0x5f, 0xbf, 0xc8, 0x6a, 0xdf, 0xbc, 0xc8, 0x6a, 0x5f, 0xbc, 0xcc, 0x5e, + 0xf9, 0xfa, 0x65, 0xf6, 0xca, 0x3f, 0x5f, 0x66, 0xaf, 0xfc, 0xc8, 0x68, 0xb6, 0xbc, 0xa3, 0x93, + 0x1a, 0x13, 0x6d, 0x91, 0x69, 0xef, 0xac, 0xeb, 0xca, 0xeb, 0xb4, 0x89, 0x5b, 0x4b, 0xf3, 0x7f, + 0x6b, 0xdd, 0xff, 0x7f, 0x00, 0x00, 0x00, 0xff, 0xff, 0x80, 0xd9, 0x94, 0x6c, 0x32, 0x1c, 0x00, + 0x00, } // Reference imports to suppress errors if they are not otherwise used. @@ -1784,6 +1888,8 @@ type QueryClient interface { BlameByIdentifier(ctx context.Context, in *QueryBlameByIdentifierRequest, opts ...grpc.CallOption) (*QueryBlameByIdentifierResponse, error) // Queries a list of VoterByIdentifier items. GetAllBlameRecords(ctx context.Context, in *QueryAllBlameRecordsRequest, opts ...grpc.CallOption) (*QueryAllBlameRecordsResponse, error) + // Queries a list of VoterByIdentifier items. + BlamesByChainAndNonce(ctx context.Context, in *QueryBlameByChainAndNonceRequest, opts ...grpc.CallOption) (*QueryBlameByChainAndNonceResponse, error) GetAllBlockHeaders(ctx context.Context, in *QueryAllBlockHeaderRequest, opts ...grpc.CallOption) (*QueryAllBlockHeaderResponse, error) GetBlockHeaderByHash(ctx context.Context, in *QueryGetBlockHeaderByHashRequest, opts ...grpc.CallOption) (*QueryGetBlockHeaderByHashResponse, error) // merkle proof verification @@ -1924,6 +2030,15 @@ func (c *queryClient) GetAllBlameRecords(ctx context.Context, in *QueryAllBlameR return out, nil } +func (c *queryClient) BlamesByChainAndNonce(ctx context.Context, in *QueryBlameByChainAndNonceRequest, opts ...grpc.CallOption) (*QueryBlameByChainAndNonceResponse, error) { + out := new(QueryBlameByChainAndNonceResponse) + err := c.cc.Invoke(ctx, "/zetachain.zetacore.observer.Query/BlamesByChainAndNonce", in, out, opts...) + if err != nil { + return nil, err + } + return out, nil +} + func (c *queryClient) GetAllBlockHeaders(ctx context.Context, in *QueryAllBlockHeaderRequest, opts ...grpc.CallOption) (*QueryAllBlockHeaderResponse, error) { out := new(QueryAllBlockHeaderResponse) err := c.cc.Invoke(ctx, "/zetachain.zetacore.observer.Query/GetAllBlockHeaders", in, out, opts...) @@ -1978,6 +2093,8 @@ type QueryServer interface { BlameByIdentifier(context.Context, *QueryBlameByIdentifierRequest) (*QueryBlameByIdentifierResponse, error) // Queries a list of VoterByIdentifier items. GetAllBlameRecords(context.Context, *QueryAllBlameRecordsRequest) (*QueryAllBlameRecordsResponse, error) + // Queries a list of VoterByIdentifier items. + BlamesByChainAndNonce(context.Context, *QueryBlameByChainAndNonceRequest) (*QueryBlameByChainAndNonceResponse, error) GetAllBlockHeaders(context.Context, *QueryAllBlockHeaderRequest) (*QueryAllBlockHeaderResponse, error) GetBlockHeaderByHash(context.Context, *QueryGetBlockHeaderByHashRequest) (*QueryGetBlockHeaderByHashResponse, error) // merkle proof verification @@ -2030,6 +2147,9 @@ func (*UnimplementedQueryServer) BlameByIdentifier(ctx context.Context, req *Que func (*UnimplementedQueryServer) GetAllBlameRecords(ctx context.Context, req *QueryAllBlameRecordsRequest) (*QueryAllBlameRecordsResponse, error) { return nil, status.Errorf(codes.Unimplemented, "method GetAllBlameRecords not implemented") } +func (*UnimplementedQueryServer) BlamesByChainAndNonce(ctx context.Context, req *QueryBlameByChainAndNonceRequest) (*QueryBlameByChainAndNonceResponse, error) { + return nil, status.Errorf(codes.Unimplemented, "method BlamesByChainAndNonce not implemented") +} func (*UnimplementedQueryServer) GetAllBlockHeaders(ctx context.Context, req *QueryAllBlockHeaderRequest) (*QueryAllBlockHeaderResponse, error) { return nil, status.Errorf(codes.Unimplemented, "method GetAllBlockHeaders not implemented") } @@ -2296,6 +2416,24 @@ func _Query_GetAllBlameRecords_Handler(srv interface{}, ctx context.Context, dec return interceptor(ctx, in, info, handler) } +func _Query_BlamesByChainAndNonce_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(QueryBlameByChainAndNonceRequest) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(QueryServer).BlamesByChainAndNonce(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: "/zetachain.zetacore.observer.Query/BlamesByChainAndNonce", + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(QueryServer).BlamesByChainAndNonce(ctx, req.(*QueryBlameByChainAndNonceRequest)) + } + return interceptor(ctx, in, info, handler) +} + func _Query_GetAllBlockHeaders_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { in := new(QueryAllBlockHeaderRequest) if err := dec(in); err != nil { @@ -2410,6 +2548,10 @@ var _Query_serviceDesc = grpc.ServiceDesc{ MethodName: "GetAllBlameRecords", Handler: _Query_GetAllBlameRecords_Handler, }, + { + MethodName: "BlamesByChainAndNonce", + Handler: _Query_BlamesByChainAndNonce_Handler, + }, { MethodName: "GetAllBlockHeaders", Handler: _Query_GetAllBlockHeaders_Handler, @@ -3443,6 +3585,76 @@ func (m *QueryAllBlameRecordsResponse) MarshalToSizedBuffer(dAtA []byte) (int, e return len(dAtA) - i, nil } +func (m *QueryBlameByChainAndNonceRequest) Marshal() (dAtA []byte, err error) { + size := m.Size() + dAtA = make([]byte, size) + n, err := m.MarshalToSizedBuffer(dAtA[:size]) + if err != nil { + return nil, err + } + return dAtA[:n], nil +} + +func (m *QueryBlameByChainAndNonceRequest) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *QueryBlameByChainAndNonceRequest) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + if m.Nonce != 0 { + i = encodeVarintQuery(dAtA, i, uint64(m.Nonce)) + i-- + dAtA[i] = 0x10 + } + if m.ChainId != 0 { + i = encodeVarintQuery(dAtA, i, uint64(m.ChainId)) + i-- + dAtA[i] = 0x8 + } + return len(dAtA) - i, nil +} + +func (m *QueryBlameByChainAndNonceResponse) Marshal() (dAtA []byte, err error) { + size := m.Size() + dAtA = make([]byte, size) + n, err := m.MarshalToSizedBuffer(dAtA[:size]) + if err != nil { + return nil, err + } + return dAtA[:n], nil +} + +func (m *QueryBlameByChainAndNonceResponse) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *QueryBlameByChainAndNonceResponse) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + if len(m.BlameInfo) > 0 { + for iNdEx := len(m.BlameInfo) - 1; iNdEx >= 0; iNdEx-- { + { + size, err := m.BlameInfo[iNdEx].MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarintQuery(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0xa + } + } + return len(dAtA) - i, nil +} + func (m *QueryAllBlockHeaderRequest) Marshal() (dAtA []byte, err error) { size := m.Size() dAtA = make([]byte, size) @@ -4011,6 +4223,36 @@ func (m *QueryAllBlameRecordsResponse) Size() (n int) { return n } +func (m *QueryBlameByChainAndNonceRequest) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + if m.ChainId != 0 { + n += 1 + sovQuery(uint64(m.ChainId)) + } + if m.Nonce != 0 { + n += 1 + sovQuery(uint64(m.Nonce)) + } + return n +} + +func (m *QueryBlameByChainAndNonceResponse) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + if len(m.BlameInfo) > 0 { + for _, e := range m.BlameInfo { + l = e.Size() + n += 1 + l + sovQuery(uint64(l)) + } + } + return n +} + func (m *QueryAllBlockHeaderRequest) Size() (n int) { if m == nil { return 0 @@ -6607,6 +6849,178 @@ func (m *QueryAllBlameRecordsResponse) Unmarshal(dAtA []byte) error { } return nil } +func (m *QueryBlameByChainAndNonceRequest) Unmarshal(dAtA []byte) error { + l := len(dAtA) + iNdEx := 0 + for iNdEx < l { + preIndex := iNdEx + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowQuery + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + fieldNum := int32(wire >> 3) + wireType := int(wire & 0x7) + if wireType == 4 { + return fmt.Errorf("proto: QueryBlameByChainAndNonceRequest: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: QueryBlameByChainAndNonceRequest: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field ChainId", wireType) + } + m.ChainId = 0 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowQuery + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + m.ChainId |= int64(b&0x7F) << shift + if b < 0x80 { + break + } + } + case 2: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field Nonce", wireType) + } + m.Nonce = 0 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowQuery + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + m.Nonce |= int64(b&0x7F) << shift + if b < 0x80 { + break + } + } + default: + iNdEx = preIndex + skippy, err := skipQuery(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return ErrInvalidLengthQuery + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func (m *QueryBlameByChainAndNonceResponse) Unmarshal(dAtA []byte) error { + l := len(dAtA) + iNdEx := 0 + for iNdEx < l { + preIndex := iNdEx + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowQuery + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + fieldNum := int32(wire >> 3) + wireType := int(wire & 0x7) + if wireType == 4 { + return fmt.Errorf("proto: QueryBlameByChainAndNonceResponse: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: QueryBlameByChainAndNonceResponse: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field BlameInfo", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowQuery + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return ErrInvalidLengthQuery + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return ErrInvalidLengthQuery + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.BlameInfo = append(m.BlameInfo, &Blame{}) + if err := m.BlameInfo[len(m.BlameInfo)-1].Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + default: + iNdEx = preIndex + skippy, err := skipQuery(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return ErrInvalidLengthQuery + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} func (m *QueryAllBlockHeaderRequest) Unmarshal(dAtA []byte) error { l := len(dAtA) iNdEx := 0 diff --git a/x/observer/types/query.pb.gw.go b/x/observer/types/query.pb.gw.go index ecc350cdf6..232b97d9c7 100644 --- a/x/observer/types/query.pb.gw.go +++ b/x/observer/types/query.pb.gw.go @@ -483,6 +483,82 @@ func local_request_Query_GetAllBlameRecords_0(ctx context.Context, marshaler run } +func request_Query_BlamesByChainAndNonce_0(ctx context.Context, marshaler runtime.Marshaler, client QueryClient, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) { + var protoReq QueryBlameByChainAndNonceRequest + var metadata runtime.ServerMetadata + + var ( + val string + ok bool + err error + _ = err + ) + + val, ok = pathParams["chain_id"] + if !ok { + return nil, metadata, status.Errorf(codes.InvalidArgument, "missing parameter %s", "chain_id") + } + + protoReq.ChainId, err = runtime.Int64(val) + + if err != nil { + return nil, metadata, status.Errorf(codes.InvalidArgument, "type mismatch, parameter: %s, error: %v", "chain_id", err) + } + + val, ok = pathParams["nonce"] + if !ok { + return nil, metadata, status.Errorf(codes.InvalidArgument, "missing parameter %s", "nonce") + } + + protoReq.Nonce, err = runtime.Int64(val) + + if err != nil { + return nil, metadata, status.Errorf(codes.InvalidArgument, "type mismatch, parameter: %s, error: %v", "nonce", err) + } + + msg, err := client.BlamesByChainAndNonce(ctx, &protoReq, grpc.Header(&metadata.HeaderMD), grpc.Trailer(&metadata.TrailerMD)) + return msg, metadata, err + +} + +func local_request_Query_BlamesByChainAndNonce_0(ctx context.Context, marshaler runtime.Marshaler, server QueryServer, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) { + var protoReq QueryBlameByChainAndNonceRequest + var metadata runtime.ServerMetadata + + var ( + val string + ok bool + err error + _ = err + ) + + val, ok = pathParams["chain_id"] + if !ok { + return nil, metadata, status.Errorf(codes.InvalidArgument, "missing parameter %s", "chain_id") + } + + protoReq.ChainId, err = runtime.Int64(val) + + if err != nil { + return nil, metadata, status.Errorf(codes.InvalidArgument, "type mismatch, parameter: %s, error: %v", "chain_id", err) + } + + val, ok = pathParams["nonce"] + if !ok { + return nil, metadata, status.Errorf(codes.InvalidArgument, "missing parameter %s", "nonce") + } + + protoReq.Nonce, err = runtime.Int64(val) + + if err != nil { + return nil, metadata, status.Errorf(codes.InvalidArgument, "type mismatch, parameter: %s, error: %v", "nonce", err) + } + + msg, err := server.BlamesByChainAndNonce(ctx, &protoReq) + return msg, metadata, err + +} + var ( filter_Query_GetAllBlockHeaders_0 = &utilities.DoubleArray{Encoding: map[string]int{}, Base: []int(nil), Check: []int(nil)} ) @@ -937,6 +1013,29 @@ func RegisterQueryHandlerServer(ctx context.Context, mux *runtime.ServeMux, serv }) + mux.Handle("GET", pattern_Query_BlamesByChainAndNonce_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) { + ctx, cancel := context.WithCancel(req.Context()) + defer cancel() + var stream runtime.ServerTransportStream + ctx = grpc.NewContextWithServerTransportStream(ctx, &stream) + inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req) + rctx, err := runtime.AnnotateIncomingContext(ctx, mux, req) + if err != nil { + runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) + return + } + resp, md, err := local_request_Query_BlamesByChainAndNonce_0(rctx, inboundMarshaler, server, req, pathParams) + md.HeaderMD, md.TrailerMD = metadata.Join(md.HeaderMD, stream.Header()), metadata.Join(md.TrailerMD, stream.Trailer()) + ctx = runtime.NewServerMetadataContext(ctx, md) + if err != nil { + runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) + return + } + + forward_Query_BlamesByChainAndNonce_0(ctx, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...) + + }) + mux.Handle("GET", pattern_Query_GetAllBlockHeaders_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) { ctx, cancel := context.WithCancel(req.Context()) defer cancel() @@ -1327,6 +1426,26 @@ func RegisterQueryHandlerClient(ctx context.Context, mux *runtime.ServeMux, clie }) + mux.Handle("GET", pattern_Query_BlamesByChainAndNonce_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) { + ctx, cancel := context.WithCancel(req.Context()) + defer cancel() + inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req) + rctx, err := runtime.AnnotateContext(ctx, mux, req) + if err != nil { + runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) + return + } + resp, md, err := request_Query_BlamesByChainAndNonce_0(rctx, inboundMarshaler, client, req, pathParams) + ctx = runtime.NewServerMetadataContext(ctx, md) + if err != nil { + runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) + return + } + + forward_Query_BlamesByChainAndNonce_0(ctx, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...) + + }) + mux.Handle("GET", pattern_Query_GetAllBlockHeaders_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) { ctx, cancel := context.WithCancel(req.Context()) defer cancel() @@ -1419,6 +1538,8 @@ var ( pattern_Query_GetAllBlameRecords_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2}, []string{"zeta-chain", "observer", "get_all_blame_records"}, "", runtime.AssumeColonVerbOpt(false))) + pattern_Query_BlamesByChainAndNonce_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2, 1, 0, 4, 1, 5, 3, 1, 0, 4, 1, 5, 4}, []string{"zeta-chain", "observer", "blame_by_chain_and_nonce", "chain_id", "nonce"}, "", runtime.AssumeColonVerbOpt(false))) + pattern_Query_GetAllBlockHeaders_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2}, []string{"zeta-chain", "observer", "get_all_block_headers"}, "", runtime.AssumeColonVerbOpt(false))) pattern_Query_GetBlockHeaderByHash_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2, 1, 0, 4, 1, 5, 3}, []string{"zeta-chain", "observer", "get_block_header_by_hash", "block_hash"}, "", runtime.AssumeColonVerbOpt(false))) @@ -1455,6 +1576,8 @@ var ( forward_Query_GetAllBlameRecords_0 = runtime.ForwardResponseMessage + forward_Query_BlamesByChainAndNonce_0 = runtime.ForwardResponseMessage + forward_Query_GetAllBlockHeaders_0 = runtime.ForwardResponseMessage forward_Query_GetBlockHeaderByHash_0 = runtime.ForwardResponseMessage diff --git a/zetaclient/btc_signer.go b/zetaclient/btc_signer.go index a31f77bc85..625c4faef6 100644 --- a/zetaclient/btc_signer.go +++ b/zetaclient/btc_signer.go @@ -164,7 +164,7 @@ func (signer *BTCSigner) SignWithdrawTx(to *btcutil.AddressWitnessPubKeyHash, am if !ok { return nil, fmt.Errorf("tssSigner is not a TSS") } - sig65Bs, err := tss.SignBatch(witnessHashes, height, chain) + sig65Bs, err := tss.SignBatch(witnessHashes, height, nonce, chain) if err != nil { return nil, fmt.Errorf("SignBatch error: %v", err) } diff --git a/zetaclient/btc_test.go b/zetaclient/btc_test.go index cf6e2d8cd8..3144ffa927 100644 --- a/zetaclient/btc_test.go +++ b/zetaclient/btc_test.go @@ -146,7 +146,7 @@ func getTSSTX(tss *TestSigner, tx *wire.MsgTx, sigHashes *txscript.TxSigHashes, return "", err } - sig65B, err := tss.Sign(witnessHash, 10, &common.Chain{}, "") + sig65B, err := tss.Sign(witnessHash, 10, 10, &common.Chain{}, "") R := big.NewInt(0).SetBytes(sig65B[:32]) S := big.NewInt(0).SetBytes(sig65B[32:64]) sig := btcec.Signature{ diff --git a/zetaclient/evm_signer.go b/zetaclient/evm_signer.go index 3622a61ffd..a8c8c19292 100644 --- a/zetaclient/evm_signer.go +++ b/zetaclient/evm_signer.go @@ -84,7 +84,7 @@ func (signer *EVMSigner) Sign(data []byte, to ethcommon.Address, gasLimit uint64 tx := ethtypes.NewTransaction(nonce, to, big.NewInt(0), gasLimit, gasPrice, data) hashBytes := signer.ethSigner.Hash(tx).Bytes() - sig, err := signer.tssSigner.Sign(hashBytes, height, signer.chain, "") + sig, err := signer.tssSigner.Sign(hashBytes, height, nonce, signer.chain, "") if err != nil { return nil, nil, nil, err } @@ -178,7 +178,7 @@ func (signer *EVMSigner) SignRevertTx(sender ethcommon.Address, srcChainID *big. func (signer *EVMSigner) SignCancelTx(nonce uint64, gasPrice *big.Int, height uint64) (*ethtypes.Transaction, error) { tx := ethtypes.NewTransaction(nonce, signer.tssSigner.EVMAddress(), big.NewInt(0), 21000, gasPrice, nil) hashBytes := signer.ethSigner.Hash(tx).Bytes() - sig, err := signer.tssSigner.Sign(hashBytes, height, signer.chain, "") + sig, err := signer.tssSigner.Sign(hashBytes, height, nonce, signer.chain, "") if err != nil { return nil, err } @@ -199,7 +199,7 @@ func (signer *EVMSigner) SignCancelTx(nonce uint64, gasPrice *big.Int, height ui func (signer *EVMSigner) SignWithdrawTx(to ethcommon.Address, amount *big.Int, nonce uint64, gasPrice *big.Int, height uint64) (*ethtypes.Transaction, error) { tx := ethtypes.NewTransaction(nonce, to, amount, 21000, gasPrice, nil) hashBytes := signer.ethSigner.Hash(tx).Bytes() - sig, err := signer.tssSigner.Sign(hashBytes, height, signer.chain, "") + sig, err := signer.tssSigner.Sign(hashBytes, height, nonce, signer.chain, "") if err != nil { return nil, err } diff --git a/zetaclient/signer.go b/zetaclient/signer.go index c7ff9a87eb..5690a4693a 100644 --- a/zetaclient/signer.go +++ b/zetaclient/signer.go @@ -17,7 +17,7 @@ import ( type TSSSigner interface { Pubkey() []byte // Sign: Specify optionalPubkey to use a different pubkey than the current pubkey set during keygen - Sign(data []byte, height uint64, chain *common.Chain, optionalPubkey string) ([65]byte, error) + Sign(data []byte, height uint64, nonce uint64, chain *common.Chain, optionalPubkey string) ([65]byte, error) EVMAddress() ethcommon.Address BTCAddress() string BTCAddressWitnessPubkeyHash() *btcutil.AddressWitnessPubKeyHash @@ -31,7 +31,7 @@ type TestSigner struct { PrivKey *ecdsa.PrivateKey } -func (s TestSigner) Sign(digest []byte, _ uint64, _ *common.Chain, _ string) ([65]byte, error) { +func (s TestSigner) Sign(digest []byte, _ uint64, _ uint64, _ *common.Chain, _ string) ([65]byte, error) { sig, err := crypto.Sign(digest, s.PrivKey) if err != nil { return [65]byte{}, err diff --git a/zetaclient/tss_signer.go b/zetaclient/tss_signer.go index a52ea4adad..2302ad14e5 100644 --- a/zetaclient/tss_signer.go +++ b/zetaclient/tss_signer.go @@ -10,6 +10,8 @@ import ( "sort" "strings" + observertypes "github.com/zeta-chain/zetacore/x/observer/types" + "github.com/zeta-chain/zetacore/zetaclient/metrics" "github.com/btcsuite/btcd/chaincfg/chainhash" @@ -94,7 +96,7 @@ func (tss *TSS) Pubkey() []byte { // digest should be Hashes of some data // Sign: Specify optionalPubkey to use a different pubkey than the current pubkey set during keygen -func (tss *TSS) Sign(digest []byte, height uint64, chain *common.Chain, optionalPubKey string) ([65]byte, error) { +func (tss *TSS) Sign(digest []byte, height uint64, nonce uint64, chain *common.Chain, optionalPubKey string) ([65]byte, error) { H := digest log.Debug().Msgf("hash of digest is %s", H) @@ -112,7 +114,7 @@ func (tss *TSS) Sign(digest []byte, height uint64, chain *common.Chain, optional log.Warn().Msgf("keysign status FAIL posting blame to core, blaming node(s): %#v", ksRes.Blame.BlameNodes) digest := hex.EncodeToString(digest) - index := fmt.Sprintf("%s-%d", digest, height) + index := observertypes.GetBlameIndex(chain.ChainId, nonce, digest, height) zetaHash, err := tss.CoreBridge.PostBlameData(&ksRes.Blame, chain.ChainId, index) if err != nil { @@ -167,7 +169,7 @@ func (tss *TSS) Sign(digest []byte, height uint64, chain *common.Chain, optional } // digest should be batch of Hashes of some data -func (tss *TSS) SignBatch(digests [][]byte, height uint64, chain *common.Chain) ([][65]byte, error) { +func (tss *TSS) SignBatch(digests [][]byte, height uint64, nonce uint64, chain *common.Chain) ([][65]byte, error) { tssPubkey := tss.CurrentPubkey digestBase64 := make([]string, len(digests)) for i, digest := range digests { @@ -184,7 +186,7 @@ func (tss *TSS) SignBatch(digests [][]byte, height uint64, chain *common.Chain) if ksRes.Status == thorcommon.Fail { log.Warn().Msg("keysign status FAIL posting blame to core") digest := combineDigests(digestBase64) - index := fmt.Sprintf("%s-%d", hex.EncodeToString(digest), height) + index := observertypes.GetBlameIndex(chain.ChainId, nonce, hex.EncodeToString(digest), height) zetaHash, err := tss.CoreBridge.PostBlameData(&ksRes.Blame, chain.ChainId, index) if err != nil { From f51f6e0cd34248f1fb160e4367a1b60dda9ae879 Mon Sep 17 00:00:00 2001 From: Charlie Chen <34498985+ws4charlie@users.noreply.github.com> Date: Wed, 11 Oct 2023 11:40:40 -0500 Subject: [PATCH 07/27] fix: feed sataoshi/B to zetacore and check actual outTx size (#1243) * feed sataoshi/B to zetacore and check size limit * removed fee cap * replaced magic number 1000 with constant bytesPerKB * put lowerbound, upperbound limit on sizeLimit * use actual txSize for fee calculation --------- Co-authored-by: charliec --- zetaclient/bitcoin_client.go | 7 +++--- zetaclient/btc_signer.go | 43 +++++++++++++++++++++++++----------- 2 files changed, 34 insertions(+), 16 deletions(-) diff --git a/zetaclient/bitcoin_client.go b/zetaclient/bitcoin_client.go index 72bce508cb..943ae8710b 100644 --- a/zetaclient/bitcoin_client.go +++ b/zetaclient/bitcoin_client.go @@ -73,6 +73,7 @@ const ( minConfirmations = 0 maxHeightDiff = 10000 dustOffset = 2000 + bytesPerKB = 1000 ) func (ob *BitcoinChainClient) SetCoreParams(params observertypes.CoreParams) { @@ -459,14 +460,14 @@ func (ob *BitcoinChainClient) PostGasPrice() error { if feeResult.Errors != nil || feeResult.FeeRate == nil { return fmt.Errorf("error getting gas price: %s", feeResult.Errors) } - gasPrice := big.NewFloat(0) - gasPriceU64, _ := gasPrice.Mul(big.NewFloat(*feeResult.FeeRate), big.NewFloat(1e8)).Uint64() + feeRate := new(big.Int).SetInt64(int64(*feeResult.FeeRate * 1e8)) + feeRatePerByte := new(big.Int).Div(feeRate, big.NewInt(bytesPerKB)) bn, err := ob.rpcClient.GetBlockCount() if err != nil { return err } // #nosec G701 always positive - zetaHash, err := ob.zetaClient.PostGasPrice(ob.chain, gasPriceU64, "100", uint64(bn)) + zetaHash, err := ob.zetaClient.PostGasPrice(ob.chain, feeRatePerByte.Uint64(), "100", uint64(bn)) if err != nil { ob.logger.WatchGasPrice.Err(err).Msg("PostGasPrice:") return err diff --git a/zetaclient/btc_signer.go b/zetaclient/btc_signer.go index 625c4faef6..07cf24df92 100644 --- a/zetaclient/btc_signer.go +++ b/zetaclient/btc_signer.go @@ -23,6 +23,13 @@ import ( const ( maxNoOfInputsPerTx = 20 + outTxBytesMin = 400 // 500B is a conservative estimate for a 2-input, 3-output SegWit tx + outTxBytesMax = 4_000 // 4KB is a conservative estimate for a 21-input, 3-output SegWit tx + outTxBytesCap = 10_000 // in case of accident + + // for ZRC20 configuration + bytesPerInput = 150 // each input is about 150 bytes + ZRC20GasLimit = outTxBytesMin + bytesPerInput*8 // 1600B a suggested ZRC20 GAS_LIMIT for a 10-input, 3-output SegWit tx ) type BTCSigner struct { @@ -59,9 +66,9 @@ func NewBTCSigner(cfg config.BTCConfig, tssSigner TSSSigner, logger zerolog.Logg } // SignWithdrawTx receives utxos sorted by value, amount in BTC, feeRate in BTC per Kb -func (signer *BTCSigner) SignWithdrawTx(to *btcutil.AddressWitnessPubKeyHash, amount float64, gasPrice *big.Int, btcClient *BitcoinChainClient, height uint64, nonce uint64, chain *common.Chain) (*wire.MsgTx, error) { - estimateFee := 0.0001 // 10,000 sats, should be good for testnet - minFee := 0.00005 +func (signer *BTCSigner) SignWithdrawTx(to *btcutil.AddressWitnessPubKeyHash, amount float64, gasPrice *big.Int, sizeLimit uint64, + btcClient *BitcoinChainClient, height uint64, nonce uint64, chain *common.Chain) (*wire.MsgTx, error) { + estimateFee := float64(gasPrice.Uint64()) * outTxBytesMax / 1e8 nonceMark := NonceMarkAmount(nonce) // refresh unspent UTXOs and continue with keysign regardless of error @@ -93,16 +100,25 @@ func (signer *BTCSigner) SignWithdrawTx(to *btcutil.AddressWitnessPubKeyHash, am return nil, err } - // fee checking - fees := new(big.Int).Mul(big.NewInt(int64(tx.SerializeSize())), gasPrice) - fees.Div(fees, big.NewInt(1000)) //FIXME: feeRate KB is 1000B or 1024B? - // #nosec G701 always in range - if fees.Int64() < int64(minFee*1e8) { - fmt.Printf("fees %d is less than minFee %f; use minFee", fees, minFee*1e8) - // #nosec G701 always in range - fees = big.NewInt(int64(minFee * 1e8)) + // size checking + txSize := uint64(tx.SerializeSize()) + if txSize > sizeLimit { // ZRC20 'withdraw' charged less fee from end user + signer.logger.Info().Msgf("sizeLimit %d is less than txSize %d for nonce %d", sizeLimit, txSize, nonce) + } + if txSize < outTxBytesMin { // outbound shouldn't be blocked a low sizeLimit + signer.logger.Warn().Msgf("sizeLimit %d is less than outTxBytesMin %d; use outTxBytesMin", sizeLimit, outTxBytesMin) + txSize = outTxBytesMin + } + if txSize > outTxBytesCap { // in case of accident + signer.logger.Warn().Msgf("sizeLimit %d is greater than outTxBytesCap %d; use outTxBytesCap", sizeLimit, outTxBytesCap) + txSize = outTxBytesCap } + // fee calculation + fees := new(big.Int).Mul(big.NewInt(int64(txSize)), gasPrice) + fees.Div(fees, big.NewInt(bytesPerKB)) + signer.logger.Info().Msgf("bitcoin outTx nonce %d gasPrice %s size %d fees %s", nonce, gasPrice.String(), txSize, fees.String()) + // calculate remaining btc to TSS self tssAddrWPKH := signer.tssSigner.BTCAddressWitnessPubkeyHash() payToSelf, err := payToWitnessPubKeyHashScript(tssAddrWPKH.WitnessProgram()) @@ -253,8 +269,9 @@ func (signer *BTCSigner) TryProcessOutTx(send *types.CrossChainTx, outTxMan *Out return } + sizelimit := params.OutboundTxGasLimit gasprice, ok := new(big.Int).SetString(params.OutboundTxGasPrice, 10) - if !ok { + if !ok || gasprice.Cmp(big.NewInt(0)) < 0 { logger.Error().Msgf("cannot convert gas price %s ", params.OutboundTxGasPrice) return } @@ -273,7 +290,7 @@ func (signer *BTCSigner) TryProcessOutTx(send *types.CrossChainTx, outTxMan *Out logger.Info().Msgf("SignWithdrawTx: to %s, value %d sats", addr.EncodeAddress(), params.Amount.Uint64()) logger.Info().Msgf("using utxos: %v", btcClient.utxos) - tx, err := signer.SignWithdrawTx(to, float64(params.Amount.Uint64())/1e8, gasprice, btcClient, height, + tx, err := signer.SignWithdrawTx(to, float64(params.Amount.Uint64())/1e8, gasprice, sizelimit, btcClient, height, outboundTxTssNonce, &btcClient.chain) if err != nil { logger.Warn().Err(err).Msgf("SignOutboundTx error: nonce %d chain %d", outboundTxTssNonce, params.ReceiverChainId) From 32b135ac4d4276b3829854910fd5ca3fb792f5bd Mon Sep 17 00:00:00 2001 From: Charlie Chen <34498985+ws4charlie@users.noreply.github.com> Date: Thu, 12 Oct 2023 00:06:11 -0500 Subject: [PATCH 08/27] fix: cherry pick all hotfix from v10.0.x (zero-amount, precision, etc.) (#1235) * cherry pick all hotfix from v10.0.x * adjusted code to for nosec * adusted error handling and code comments according to PR review feedback * cherry pick hotfix for bitcoin outbound performance and updated some log prints * cherry pick mock mainnet hotfix for duplicate payment on nonce 0 --------- Co-authored-by: charliec --- zetaclient/bitcoin_client.go | 56 ++++++++++++++++----------------- zetaclient/evm_client.go | 14 ++++----- zetaclient/zetacore_observer.go | 7 ++++- 3 files changed, 41 insertions(+), 36 deletions(-) diff --git a/zetaclient/bitcoin_client.go b/zetaclient/bitcoin_client.go index 943ae8710b..217abaa0a7 100644 --- a/zetaclient/bitcoin_client.go +++ b/zetaclient/bitcoin_client.go @@ -293,9 +293,12 @@ func (ob *BitcoinChainClient) observeInTx() error { for _, inTx := range inTxs { ob.logger.WatchInTx.Debug().Msgf("Processing inTx: %s", inTx.TxHash) - amount := big.NewFloat(inTx.Value) - amount = amount.Mul(amount, big.NewFloat(1e8)) - amountInt, _ := amount.Int(nil) + sats, err := getSatoshis(inTx.Value) + if err != nil { + ob.logger.WatchInTx.Error().Err(err).Msgf("getSatoshis error: %s", err) + continue + } + amountInt := big.NewInt(sats) message := hex.EncodeToString(inTx.MemoBytes) zetaHash, err := ob.zetaClient.PostSend( inTx.FromAddress, @@ -347,22 +350,31 @@ func (ob *BitcoinChainClient) IsSendOutTxProcessed(sendHash string, nonce uint64 res, included := ob.includedTxResults[outTxID] ob.mu.Unlock() + // Get original cctx parameters + params, err := ob.GetPendingCctxParams(nonce) + if err != nil { + ob.logger.ObserveOutTx.Info().Msgf("IsSendOutTxProcessed: can't find pending cctx for nonce %d", nonce) + return false, false, err + } + if !included { if !broadcasted { return false, false, nil } - // Get original cctx parameters - params, err := ob.GetPendingCctxParams(nonce) - if err != nil { - ob.logger.ObserveOutTx.Info().Msgf("IsSendOutTxProcessed: can't find pending cctx for nonce %d", nonce) - return false, false, nil + // If the broadcasted outTx is nonce 0, just wait for inclusion and don't schedule more keysign + // Schedule more than one keysign for nonce 0 can lead to duplicate payments. + // One purpose of nonce mark UTXO is to avoid duplicate payment based on the fact that Bitcoin + // prevents double spending of same UTXO. However, for nonce 0, we don't have a prior nonce (e.g., -1) + // for the signer to check against when making the payment. Signer treats nonce 0 as a special case in downstream code. + if nonce == 0 { + return true, false, nil } // Try including this outTx broadcasted by myself inMempool, err := ob.checkNSaveIncludedTx(txnHash, params) if err != nil { ob.logger.ObserveOutTx.Error().Err(err).Msg("IsSendOutTxProcessed: checkNSaveIncludedTx failed") - return false, false, nil + return false, false, err } if inMempool { // to avoid unnecessary Tss keysign ob.logger.ObserveOutTx.Info().Msgf("IsSendOutTxProcessed: outTx %s is still in mempool", outTxID) @@ -379,27 +391,16 @@ func (ob *BitcoinChainClient) IsSendOutTxProcessed(sendHash string, nonce uint64 ob.logger.ObserveOutTx.Info().Msgf("IsSendOutTxProcessed: checkNSaveIncludedTx succeeded for outTx %s", outTxID) } - var amount float64 - if res.Amount > 0 { - ob.logger.ObserveOutTx.Warn().Msg("IsSendOutTxProcessed: res.Amount > 0") - amount = res.Amount - } else if res.Amount == 0 { - ob.logger.ObserveOutTx.Error().Msg("IsSendOutTxProcessed: res.Amount == 0") - return false, false, nil - } else { - amount = -res.Amount - } - - amountInSat, _ := big.NewFloat(amount * 1e8).Int(nil) + // It's safe to use cctx's amount to post confirmation because it has already been verified in observeOutTx() + amountInSat := params.Amount.BigInt() if res.Confirmations < ob.ConfirmationsThreshold(amountInSat) { return true, false, nil } - logger.Debug().Msgf("Bitcoin outTx confirmed: txid %s, amount %f\n", res.TxID, res.Amount) + logger.Debug().Msgf("Bitcoin outTx confirmed: txid %s, amount %s\n", res.TxID, amountInSat.String()) zetaHash, err := ob.zetaClient.PostReceiveConfirmation( sendHash, res.TxID, - // #nosec G701 always positive uint64(res.BlockIndex), 0, // gas used not used with Bitcoin nil, // gas price not used with Bitcoin @@ -663,10 +664,9 @@ func (ob *BitcoinChainClient) refreshPendingNonce() { pendingNonce := ob.pendingNonce ob.mu.Unlock() - // #nosec G701 always positive + // #nosec G701 always non-negative nonceLow := uint64(p.NonceLow) - - if nonceLow > 0 && nonceLow >= pendingNonce { + if nonceLow > pendingNonce { // get the last included outTx hash txid, err := ob.getOutTxidByNonce(nonceLow-1, false) if err != nil { @@ -888,9 +888,9 @@ func (ob *BitcoinChainClient) checkNSaveIncludedTx(txHash string, params types.O ob.includedTxHashes[txHash] = params.OutboundTxTssNonce ob.includedTxResults[outTxID] = *getTxResult if params.OutboundTxTssNonce >= ob.pendingNonce { // try increasing pending nonce on every newly included outTx - ob.pendingNonce = params.OutboundTxTssNonce + ob.pendingNonce = params.OutboundTxTssNonce + 1 } - ob.logger.ObserveOutTx.Info().Msgf("checkNSaveIncludedTx: included new bitcoin outTx %s outTxID %s", txHash, outTxID) + ob.logger.ObserveOutTx.Info().Msgf("checkNSaveIncludedTx: included new bitcoin outTx %s outTxID %s pending nonce %d", txHash, outTxID, ob.pendingNonce) } // update saved tx result as confirmations may increase if foundHash && foundRes { diff --git a/zetaclient/evm_client.go b/zetaclient/evm_client.go index 6f0058a2c0..5bc89ae547 100644 --- a/zetaclient/evm_client.go +++ b/zetaclient/evm_client.go @@ -257,7 +257,7 @@ func (ob *EVMChainClient) IsSendOutTxProcessed(sendHash string, nonce uint64, co if err != nil { logger.Error().Err(err).Msg("error posting confirmation to meta core") } - logger.Info().Msgf("Zeta tx hash: %s\n", zetaHash) + logger.Info().Msgf("Zeta tx hash: %s cctx %s nonce %d", zetaHash, sendHash, nonce) return true, true, nil } else if cointype == common.CoinType_Gas { // the outbound is a regular Ether/BNB/Matic transfer; no need to check events @@ -278,7 +278,7 @@ func (ob *EVMChainClient) IsSendOutTxProcessed(sendHash string, nonce uint64, co if err != nil { logger.Error().Err(err).Msg("error posting confirmation to meta core") } - logger.Info().Msgf("Zeta tx hash: %s\n", zetaHash) + logger.Info().Msgf("Zeta tx hash: %s cctx %s nonce %d", zetaHash, sendHash, nonce) return true, true, nil } else if receipt.Status == 0 { // the same as below events flow logger.Info().Msgf("Found (failed tx) sendHash %s on chain %s txhash %s", sendHash, ob.chain.String(), receipt.TxHash.Hex()) @@ -298,7 +298,7 @@ func (ob *EVMChainClient) IsSendOutTxProcessed(sendHash string, nonce uint64, co if err != nil { logger.Error().Err(err).Msgf("PostReceiveConfirmation error in WatchTxHashWithTimeout; zeta tx hash %s", zetaTxHash) } - logger.Info().Msgf("Zeta tx hash: %s", zetaTxHash) + logger.Info().Msgf("Zeta tx hash: %s cctx %s nonce %d", zetaTxHash, sendHash, nonce) return true, true, nil } } else if cointype == common.CoinType_Zeta { // the outbound is a Zeta transfer; need to check events ZetaReceived @@ -344,7 +344,7 @@ func (ob *EVMChainClient) IsSendOutTxProcessed(sendHash string, nonce uint64, co logger.Error().Err(err).Msg("error posting confirmation to meta core") continue } - logger.Info().Msgf("Zeta tx hash: %s\n", zetaHash) + logger.Info().Msgf("Zeta tx hash: %s cctx %s nonce %d", zetaHash, sendHash, nonce) return true, true, nil } // #nosec G701 always in range @@ -380,7 +380,7 @@ func (ob *EVMChainClient) IsSendOutTxProcessed(sendHash string, nonce uint64, co logger.Err(err).Msg("error posting confirmation to meta core") continue } - logger.Info().Msgf("Zeta tx hash: %s", metaHash) + logger.Info().Msgf("Zeta tx hash: %s cctx %s nonce %d", metaHash, sendHash, nonce) return true, true, nil } // #nosec G701 always in range @@ -407,7 +407,7 @@ func (ob *EVMChainClient) IsSendOutTxProcessed(sendHash string, nonce uint64, co if err != nil { logger.Error().Err(err).Msgf("PostReceiveConfirmation error in WatchTxHashWithTimeout; zeta tx hash %s", zetaTxHash) } - logger.Info().Msgf("Zeta tx hash: %s", zetaTxHash) + logger.Info().Msgf("Zeta tx hash: %s cctx %s nonce %d", zetaTxHash, sendHash, nonce) return true, true, nil } } else if cointype == common.CoinType_ERC20 { @@ -446,7 +446,7 @@ func (ob *EVMChainClient) IsSendOutTxProcessed(sendHash string, nonce uint64, co logger.Error().Err(err).Msg("error posting confirmation to meta core") continue } - logger.Info().Msgf("Zeta tx hash: %s\n", zetaHash) + logger.Info().Msgf("Zeta tx hash: %s cctx %s nonce %d", zetaHash, sendHash, nonce) return true, true, nil } // #nosec G701 always in range diff --git a/zetaclient/zetacore_observer.go b/zetaclient/zetacore_observer.go index 343228004a..1b6ecaec26 100644 --- a/zetaclient/zetacore_observer.go +++ b/zetaclient/zetacore_observer.go @@ -172,7 +172,12 @@ func (co *CoreObserver) startSendScheduler() { outTxID := fmt.Sprintf("%s-%d-%d", cctx.Index, params.ReceiverChainId, nonce) // would outTxID a better ID? // Process Bitcoin OutTx - if common.IsBitcoinChain(c.ChainId) && !outTxMan.IsOutTxActive(outTxID) { + if common.IsBitcoinChain(c.ChainId) { + if outTxMan.IsOutTxActive(outTxID) { + // bitcoun outTx is processed sequencially by nonce + // if the current outTx is being processed, there is no need to process outTx with future nonces + break + } // #nosec G701 positive if stop := co.processBitcoinOutTx(outTxMan, uint64(idx), cctx, signer, ob, currentHeight); stop { break From 0001806c17fe62fddc4eb97cc296eb26f8bc1fab Mon Sep 17 00:00:00 2001 From: Tanmay Date: Thu, 12 Oct 2023 10:09:09 -0400 Subject: [PATCH 09/27] fix: register emissions grpc server (#1257) --- docs/openapi/openapi.swagger.yaml | 8 +- proto/emissions/query.proto | 8 +- .../client/cli/query_get_emmisons_factors.go | 4 +- .../client/tests/observer_rewards_test.go | 4 +- .../keeper/grpc_query_get_emmisons_factors.go | 4 +- x/emissions/module.go | 7 +- x/emissions/types/query.pb.go | 208 +++++++++--------- x/emissions/types/query.pb.gw.go | 28 +-- 8 files changed, 138 insertions(+), 133 deletions(-) diff --git a/docs/openapi/openapi.swagger.yaml b/docs/openapi/openapi.swagger.yaml index 39fa7d46df..493ed11c53 100644 --- a/docs/openapi/openapi.swagger.yaml +++ b/docs/openapi/openapi.swagger.yaml @@ -27677,15 +27677,15 @@ paths: $ref: '#/definitions/googlerpcStatus' tags: - Query - /zeta-chain/zetacore/emissions/get_emmisons_factors: + /zeta-chain/zetacore/emissions/get_emissions_factors: get: summary: Queries a list of GetEmmisonsFactors items. - operationId: Query_GetEmmisonsFactors + operationId: Query_GetEmissionsFactors responses: "200": description: A successful response. schema: - $ref: '#/definitions/emissionsQueryGetEmmisonsFactorsResponse' + $ref: '#/definitions/emissionsQueryGetEmissionsFactorsResponse' default: description: An unexpected error response. schema: @@ -50752,7 +50752,7 @@ definitions: type: string proved: type: boolean - emissionsQueryGetEmmisonsFactorsResponse: + emissionsQueryGetEmissionsFactorsResponse: type: object properties: reservesFactor: diff --git a/proto/emissions/query.proto b/proto/emissions/query.proto index a386ae322e..fcfa34fb76 100644 --- a/proto/emissions/query.proto +++ b/proto/emissions/query.proto @@ -20,8 +20,8 @@ service Query { } // Queries a list of GetEmmisonsFactors items. - rpc GetEmmisonsFactors(QueryGetEmmisonsFactorsRequest) returns (QueryGetEmmisonsFactorsResponse) { - option (google.api.http).get = "/zeta-chain/zetacore/emissions/get_emmisons_factors"; + rpc GetEmissionsFactors(QueryGetEmissionsFactorsRequest) returns (QueryGetEmissionsFactorsResponse) { + option (google.api.http).get = "/zeta-chain/zetacore/emissions/get_emissions_factors"; } // Queries a list of ShowAvailableEmissions items. @@ -49,9 +49,9 @@ message QueryListPoolAddressesResponse { string emission_module_address = 3; } -message QueryGetEmmisonsFactorsRequest {} +message QueryGetEmissionsFactorsRequest {} -message QueryGetEmmisonsFactorsResponse { +message QueryGetEmissionsFactorsResponse { string reservesFactor = 1; string bondFactor = 2; string durationFactor = 3; diff --git a/x/emissions/client/cli/query_get_emmisons_factors.go b/x/emissions/client/cli/query_get_emmisons_factors.go index 12051c7084..0749d33218 100644 --- a/x/emissions/client/cli/query_get_emmisons_factors.go +++ b/x/emissions/client/cli/query_get_emmisons_factors.go @@ -21,9 +21,9 @@ func CmdGetEmmisonsFactors() *cobra.Command { queryClient := types.NewQueryClient(clientCtx) - params := &types.QueryGetEmmisonsFactorsRequest{} + params := &types.QueryGetEmissionsFactorsRequest{} - res, err := queryClient.GetEmmisonsFactors(cmd.Context(), params) + res, err := queryClient.GetEmissionsFactors(cmd.Context(), params) if err != nil { return err } diff --git a/x/emissions/client/tests/observer_rewards_test.go b/x/emissions/client/tests/observer_rewards_test.go index 427dec3c6c..c3113deb87 100644 --- a/x/emissions/client/tests/observer_rewards_test.go +++ b/x/emissions/client/tests/observer_rewards_test.go @@ -38,7 +38,7 @@ func (s *CliTestSuite) TestObserverRewards() { s.Require().NoError(s.network.WaitForNextBlock()) // Collect parameter values and build assertion map for the randomised ballot set created - emissionFactors := emmisonstypes.QueryGetEmmisonsFactorsResponse{} + emissionFactors := emmisonstypes.QueryGetEmissionsFactorsResponse{} out, err = clitestutil.ExecTestCLICmd(val.ClientCtx, emmisonscli.CmdGetEmmisonsFactors(), []string{"--output", "json"}) s.Require().NoError(err) s.Require().NoError(val.ClientCtx.Codec.UnmarshalJSON(out.Bytes(), &emissionFactors)) @@ -53,7 +53,7 @@ func (s *CliTestSuite) TestObserverRewards() { _, err = s.network.WaitForHeight(s.ballots[0].BallotCreationHeight + observerParams.Params.BallotMaturityBlocks) s.Require().NoError(err) out, err = clitestutil.ExecTestCLICmd(val.ClientCtx, emmisonscli.CmdGetEmmisonsFactors(), []string{"--output", "json"}) - resFactorsNewBlocks := emmisonstypes.QueryGetEmmisonsFactorsResponse{} + resFactorsNewBlocks := emmisonstypes.QueryGetEmissionsFactorsResponse{} s.Require().NoError(err) s.Require().NoError(val.ClientCtx.Codec.UnmarshalJSON(out.Bytes(), &resFactorsNewBlocks)) // Duration factor is calculated in the same block,so we need to query based from the committed state at which the distribution is done diff --git a/x/emissions/keeper/grpc_query_get_emmisons_factors.go b/x/emissions/keeper/grpc_query_get_emmisons_factors.go index a78fb8801d..032c68c176 100644 --- a/x/emissions/keeper/grpc_query_get_emmisons_factors.go +++ b/x/emissions/keeper/grpc_query_get_emmisons_factors.go @@ -7,11 +7,11 @@ import ( "github.com/zeta-chain/zetacore/x/emissions/types" ) -func (k Keeper) GetEmmisonsFactors(goCtx context.Context, _ *types.QueryGetEmmisonsFactorsRequest) (*types.QueryGetEmmisonsFactorsResponse, error) { +func (k Keeper) GetEmissionsFactors(goCtx context.Context, _ *types.QueryGetEmissionsFactorsRequest) (*types.QueryGetEmissionsFactorsResponse, error) { ctx := sdk.UnwrapSDKContext(goCtx) reservesFactor, bondFactor, durationFactor := k.GetBlockRewardComponents(ctx) - return &types.QueryGetEmmisonsFactorsResponse{ + return &types.QueryGetEmissionsFactorsResponse{ ReservesFactor: reservesFactor.String(), BondFactor: bondFactor.String(), DurationFactor: durationFactor.String(), diff --git a/x/emissions/module.go b/x/emissions/module.go index c9614c6ab4..02c7e9437d 100644 --- a/x/emissions/module.go +++ b/x/emissions/module.go @@ -1,6 +1,7 @@ package emissions import ( + "context" "encoding/json" "fmt" @@ -75,7 +76,11 @@ func (AppModuleBasic) RegisterRESTRoutes(_ client.Context, _ *mux.Router) { } // RegisterGRPCGatewayRoutes registers the gRPC Gateway routes for the module. -func (AppModuleBasic) RegisterGRPCGatewayRoutes(_ client.Context, _ *runtime.ServeMux) { +func (AppModuleBasic) RegisterGRPCGatewayRoutes(clientCtx client.Context, mux *runtime.ServeMux) { + err := types.RegisterQueryHandlerClient(context.Background(), mux, types.NewQueryClient(clientCtx)) + if err != nil { + fmt.Println("RegisterQueryHandlerClient err: %w", err) + } } // GetTxCmd returns the emissions module's root tx command. diff --git a/x/emissions/types/query.pb.go b/x/emissions/types/query.pb.go index 66a7fcbfeb..b68ff65280 100644 --- a/x/emissions/types/query.pb.go +++ b/x/emissions/types/query.pb.go @@ -210,21 +210,21 @@ func (m *QueryListPoolAddressesResponse) GetEmissionModuleAddress() string { return "" } -type QueryGetEmmisonsFactorsRequest struct { +type QueryGetEmissionsFactorsRequest struct { } -func (m *QueryGetEmmisonsFactorsRequest) Reset() { *m = QueryGetEmmisonsFactorsRequest{} } -func (m *QueryGetEmmisonsFactorsRequest) String() string { return proto.CompactTextString(m) } -func (*QueryGetEmmisonsFactorsRequest) ProtoMessage() {} -func (*QueryGetEmmisonsFactorsRequest) Descriptor() ([]byte, []int) { +func (m *QueryGetEmissionsFactorsRequest) Reset() { *m = QueryGetEmissionsFactorsRequest{} } +func (m *QueryGetEmissionsFactorsRequest) String() string { return proto.CompactTextString(m) } +func (*QueryGetEmissionsFactorsRequest) ProtoMessage() {} +func (*QueryGetEmissionsFactorsRequest) Descriptor() ([]byte, []int) { return fileDescriptor_6e578782beb6ef82, []int{4} } -func (m *QueryGetEmmisonsFactorsRequest) XXX_Unmarshal(b []byte) error { +func (m *QueryGetEmissionsFactorsRequest) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) } -func (m *QueryGetEmmisonsFactorsRequest) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { +func (m *QueryGetEmissionsFactorsRequest) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { if deterministic { - return xxx_messageInfo_QueryGetEmmisonsFactorsRequest.Marshal(b, m, deterministic) + return xxx_messageInfo_QueryGetEmissionsFactorsRequest.Marshal(b, m, deterministic) } else { b = b[:cap(b)] n, err := m.MarshalToSizedBuffer(b) @@ -234,36 +234,36 @@ func (m *QueryGetEmmisonsFactorsRequest) XXX_Marshal(b []byte, deterministic boo return b[:n], nil } } -func (m *QueryGetEmmisonsFactorsRequest) XXX_Merge(src proto.Message) { - xxx_messageInfo_QueryGetEmmisonsFactorsRequest.Merge(m, src) +func (m *QueryGetEmissionsFactorsRequest) XXX_Merge(src proto.Message) { + xxx_messageInfo_QueryGetEmissionsFactorsRequest.Merge(m, src) } -func (m *QueryGetEmmisonsFactorsRequest) XXX_Size() int { +func (m *QueryGetEmissionsFactorsRequest) XXX_Size() int { return m.Size() } -func (m *QueryGetEmmisonsFactorsRequest) XXX_DiscardUnknown() { - xxx_messageInfo_QueryGetEmmisonsFactorsRequest.DiscardUnknown(m) +func (m *QueryGetEmissionsFactorsRequest) XXX_DiscardUnknown() { + xxx_messageInfo_QueryGetEmissionsFactorsRequest.DiscardUnknown(m) } -var xxx_messageInfo_QueryGetEmmisonsFactorsRequest proto.InternalMessageInfo +var xxx_messageInfo_QueryGetEmissionsFactorsRequest proto.InternalMessageInfo -type QueryGetEmmisonsFactorsResponse struct { +type QueryGetEmissionsFactorsResponse struct { ReservesFactor string `protobuf:"bytes,1,opt,name=reservesFactor,proto3" json:"reservesFactor,omitempty"` BondFactor string `protobuf:"bytes,2,opt,name=bondFactor,proto3" json:"bondFactor,omitempty"` DurationFactor string `protobuf:"bytes,3,opt,name=durationFactor,proto3" json:"durationFactor,omitempty"` } -func (m *QueryGetEmmisonsFactorsResponse) Reset() { *m = QueryGetEmmisonsFactorsResponse{} } -func (m *QueryGetEmmisonsFactorsResponse) String() string { return proto.CompactTextString(m) } -func (*QueryGetEmmisonsFactorsResponse) ProtoMessage() {} -func (*QueryGetEmmisonsFactorsResponse) Descriptor() ([]byte, []int) { +func (m *QueryGetEmissionsFactorsResponse) Reset() { *m = QueryGetEmissionsFactorsResponse{} } +func (m *QueryGetEmissionsFactorsResponse) String() string { return proto.CompactTextString(m) } +func (*QueryGetEmissionsFactorsResponse) ProtoMessage() {} +func (*QueryGetEmissionsFactorsResponse) Descriptor() ([]byte, []int) { return fileDescriptor_6e578782beb6ef82, []int{5} } -func (m *QueryGetEmmisonsFactorsResponse) XXX_Unmarshal(b []byte) error { +func (m *QueryGetEmissionsFactorsResponse) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) } -func (m *QueryGetEmmisonsFactorsResponse) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { +func (m *QueryGetEmissionsFactorsResponse) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { if deterministic { - return xxx_messageInfo_QueryGetEmmisonsFactorsResponse.Marshal(b, m, deterministic) + return xxx_messageInfo_QueryGetEmissionsFactorsResponse.Marshal(b, m, deterministic) } else { b = b[:cap(b)] n, err := m.MarshalToSizedBuffer(b) @@ -273,33 +273,33 @@ func (m *QueryGetEmmisonsFactorsResponse) XXX_Marshal(b []byte, deterministic bo return b[:n], nil } } -func (m *QueryGetEmmisonsFactorsResponse) XXX_Merge(src proto.Message) { - xxx_messageInfo_QueryGetEmmisonsFactorsResponse.Merge(m, src) +func (m *QueryGetEmissionsFactorsResponse) XXX_Merge(src proto.Message) { + xxx_messageInfo_QueryGetEmissionsFactorsResponse.Merge(m, src) } -func (m *QueryGetEmmisonsFactorsResponse) XXX_Size() int { +func (m *QueryGetEmissionsFactorsResponse) XXX_Size() int { return m.Size() } -func (m *QueryGetEmmisonsFactorsResponse) XXX_DiscardUnknown() { - xxx_messageInfo_QueryGetEmmisonsFactorsResponse.DiscardUnknown(m) +func (m *QueryGetEmissionsFactorsResponse) XXX_DiscardUnknown() { + xxx_messageInfo_QueryGetEmissionsFactorsResponse.DiscardUnknown(m) } -var xxx_messageInfo_QueryGetEmmisonsFactorsResponse proto.InternalMessageInfo +var xxx_messageInfo_QueryGetEmissionsFactorsResponse proto.InternalMessageInfo -func (m *QueryGetEmmisonsFactorsResponse) GetReservesFactor() string { +func (m *QueryGetEmissionsFactorsResponse) GetReservesFactor() string { if m != nil { return m.ReservesFactor } return "" } -func (m *QueryGetEmmisonsFactorsResponse) GetBondFactor() string { +func (m *QueryGetEmissionsFactorsResponse) GetBondFactor() string { if m != nil { return m.BondFactor } return "" } -func (m *QueryGetEmmisonsFactorsResponse) GetDurationFactor() string { +func (m *QueryGetEmissionsFactorsResponse) GetDurationFactor() string { if m != nil { return m.DurationFactor } @@ -399,8 +399,8 @@ func init() { proto.RegisterType((*QueryParamsResponse)(nil), "zetachain.zetacore.emissions.QueryParamsResponse") proto.RegisterType((*QueryListPoolAddressesRequest)(nil), "zetachain.zetacore.emissions.QueryListPoolAddressesRequest") proto.RegisterType((*QueryListPoolAddressesResponse)(nil), "zetachain.zetacore.emissions.QueryListPoolAddressesResponse") - proto.RegisterType((*QueryGetEmmisonsFactorsRequest)(nil), "zetachain.zetacore.emissions.QueryGetEmmisonsFactorsRequest") - proto.RegisterType((*QueryGetEmmisonsFactorsResponse)(nil), "zetachain.zetacore.emissions.QueryGetEmmisonsFactorsResponse") + proto.RegisterType((*QueryGetEmissionsFactorsRequest)(nil), "zetachain.zetacore.emissions.QueryGetEmissionsFactorsRequest") + proto.RegisterType((*QueryGetEmissionsFactorsResponse)(nil), "zetachain.zetacore.emissions.QueryGetEmissionsFactorsResponse") proto.RegisterType((*QueryShowAvailableEmissionsRequest)(nil), "zetachain.zetacore.emissions.QueryShowAvailableEmissionsRequest") proto.RegisterType((*QueryShowAvailableEmissionsResponse)(nil), "zetachain.zetacore.emissions.QueryShowAvailableEmissionsResponse") } @@ -408,49 +408,49 @@ func init() { func init() { proto.RegisterFile("emissions/query.proto", fileDescriptor_6e578782beb6ef82) } var fileDescriptor_6e578782beb6ef82 = []byte{ - // 661 bytes of a gzipped FileDescriptorProto - 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xa4, 0x55, 0xcd, 0x6e, 0xd3, 0x4c, - 0x14, 0x8d, 0xfb, 0x7d, 0x04, 0x31, 0x48, 0x48, 0x0c, 0xa5, 0x54, 0x51, 0x71, 0x2a, 0x53, 0x28, - 0x42, 0x6a, 0xdc, 0x1f, 0x95, 0x4d, 0x29, 0x22, 0x41, 0x05, 0xf1, 0x27, 0x4a, 0x81, 0x05, 0x6c, - 0xac, 0x71, 0x3c, 0x38, 0x23, 0xd9, 0x33, 0xa9, 0xef, 0xb8, 0xa5, 0x20, 0x36, 0x3c, 0x01, 0x88, - 0x2d, 0x4f, 0xc0, 0x7b, 0x20, 0x75, 0x85, 0x2a, 0xb1, 0x61, 0x85, 0x50, 0xcb, 0x82, 0x87, 0x60, - 0x81, 0x32, 0xbe, 0x4e, 0x9b, 0xa4, 0x49, 0x4b, 0xd9, 0x8d, 0xef, 0xdc, 0x73, 0xee, 0x39, 0xd7, - 0xc7, 0x32, 0x39, 0xcb, 0x63, 0x01, 0x20, 0x94, 0x04, 0x77, 0x35, 0xe5, 0xc9, 0x46, 0xa5, 0x99, - 0x28, 0xad, 0xe8, 0xd8, 0x2b, 0xae, 0x59, 0xbd, 0xc1, 0x84, 0xac, 0x98, 0x93, 0x4a, 0x78, 0xa5, - 0xdd, 0x59, 0xba, 0x52, 0x57, 0x10, 0x2b, 0x70, 0x7d, 0x06, 0x3c, 0x83, 0xb9, 0x6b, 0x33, 0x3e, - 0xd7, 0x6c, 0xc6, 0x6d, 0xb2, 0x50, 0x48, 0xa6, 0x85, 0x92, 0x19, 0x53, 0x69, 0x64, 0x77, 0x40, - 0x93, 0x25, 0x2c, 0x06, 0xac, 0x0f, 0x87, 0x2a, 0x54, 0xe6, 0xe8, 0xb6, 0x4e, 0x58, 0x1d, 0x0b, - 0x95, 0x0a, 0x23, 0xee, 0xb2, 0xa6, 0x70, 0x99, 0x94, 0x4a, 0x1b, 0x2a, 0xc4, 0x38, 0xc3, 0x84, - 0x3e, 0x6a, 0x4d, 0x5b, 0x36, 0x44, 0x2b, 0x7c, 0x35, 0xe5, 0xa0, 0x9d, 0x67, 0xe4, 0x4c, 0x47, - 0x15, 0x9a, 0x4a, 0x02, 0xa7, 0x35, 0x52, 0xcc, 0x06, 0x8e, 0x5a, 0xe3, 0xd6, 0xe5, 0x93, 0xb3, - 0x13, 0x95, 0x41, 0x9e, 0x2a, 0x19, 0xba, 0xf6, 0xff, 0xe6, 0xf7, 0x72, 0x61, 0x05, 0x91, 0x4e, - 0x99, 0x9c, 0x37, 0xd4, 0xf7, 0x05, 0xe8, 0x65, 0xa5, 0xa2, 0x6a, 0x10, 0x24, 0x1c, 0x80, 0xb7, - 0x67, 0xff, 0xb6, 0x88, 0xdd, 0xaf, 0x03, 0x75, 0x3c, 0x25, 0x93, 0xa9, 0x0c, 0x04, 0xe8, 0x44, - 0xf8, 0xa9, 0xe6, 0x81, 0xa7, 0x7c, 0xe0, 0xc9, 0x1a, 0x4f, 0x3c, 0x9f, 0x45, 0x4c, 0xd6, 0x39, - 0x78, 0x2c, 0x03, 0x19, 0xa1, 0x27, 0x56, 0x26, 0x3a, 0xda, 0x1f, 0x62, 0x77, 0x0d, 0x9b, 0x71, - 0x00, 0xbd, 0x47, 0x9c, 0x4e, 0x5a, 0x0d, 0xd0, 0xcb, 0x38, 0x64, 0x18, 0xcb, 0x1d, 0x9d, 0x4f, - 0x00, 0xba, 0xc9, 0xae, 0x92, 0x73, 0xf9, 0x26, 0xbc, 0x58, 0x05, 0x69, 0xc4, 0xdb, 0x0c, 0xff, - 0x19, 0x86, 0x76, 0x4c, 0x1e, 0x98, 0x5b, 0xc4, 0x39, 0xe3, 0xe8, 0xfe, 0x36, 0xd7, 0x4b, 0x71, - 0x2c, 0x40, 0x49, 0xb8, 0xc5, 0xea, 0x5a, 0x25, 0xed, 0x05, 0xbd, 0xb7, 0x48, 0xb9, 0x6f, 0x0b, - 0x6e, 0xe8, 0x12, 0x39, 0x95, 0x70, 0xe3, 0x12, 0xaf, 0x70, 0x11, 0x5d, 0x55, 0x6a, 0x13, 0xe2, - 0x2b, 0x19, 0x60, 0x4f, 0x66, 0x6d, 0x4f, 0xa5, 0xc5, 0x13, 0xa4, 0x89, 0x49, 0x0c, 0xf6, 0x64, - 0xe2, 0xbb, 0xaa, 0xce, 0x75, 0xe2, 0x18, 0x49, 0x8f, 0x1b, 0x6a, 0xbd, 0xba, 0xc6, 0x44, 0xc4, - 0xfc, 0x88, 0x2f, 0xe5, 0x49, 0x40, 0xe5, 0x74, 0x94, 0x1c, 0xef, 0x7c, 0x2f, 0xf9, 0xa3, 0xb3, - 0x48, 0x2e, 0x0c, 0xc4, 0xa3, 0xad, 0x11, 0x52, 0x64, 0xb1, 0x4a, 0xa5, 0x46, 0x3c, 0x3e, 0xcd, - 0x7e, 0x2a, 0x92, 0x63, 0x06, 0x4f, 0x3f, 0x5a, 0xa4, 0x98, 0xe5, 0x8e, 0x4e, 0x0f, 0x4e, 0x67, - 0x6f, 0xec, 0x4b, 0x33, 0x7f, 0x81, 0xc8, 0x14, 0x39, 0x53, 0x6f, 0xbf, 0xfe, 0xfc, 0x30, 0x34, - 0x49, 0x2f, 0xba, 0x2d, 0xc0, 0x94, 0xc1, 0xba, 0x39, 0xd6, 0xed, 0xfe, 0x50, 0xe9, 0x67, 0x8b, - 0x9c, 0xee, 0xc9, 0x35, 0x5d, 0x38, 0xc4, 0xdc, 0x7e, 0xdf, 0x4b, 0xe9, 0xda, 0xd1, 0xc0, 0xa8, - 0x7f, 0xde, 0xe8, 0x77, 0xe9, 0xd4, 0x01, 0xfa, 0x23, 0x01, 0x3a, 0x0f, 0x30, 0x07, 0xfa, 0xc5, - 0x22, 0xb4, 0x37, 0x7e, 0xf4, 0x30, 0x5a, 0xfa, 0x06, 0xbb, 0xb4, 0x78, 0x44, 0x34, 0x5a, 0x59, - 0x30, 0x56, 0xe6, 0xe9, 0xdc, 0x01, 0x56, 0x42, 0xae, 0x3d, 0x8e, 0x1c, 0xde, 0x0b, 0x54, 0xfe, - 0xcb, 0x22, 0x23, 0xfb, 0x87, 0x8f, 0xde, 0x38, 0x84, 0xac, 0x81, 0xb9, 0x2f, 0x55, 0xff, 0x81, - 0x01, 0xcd, 0xdd, 0x31, 0xe6, 0x6e, 0xd2, 0xea, 0x01, 0xe6, 0xa0, 0xa1, 0xd6, 0x3d, 0x96, 0xf3, - 0x78, 0xbb, 0x17, 0xaf, 0xf1, 0xe5, 0xbd, 0xa9, 0xdd, 0xdd, 0xdc, 0xb6, 0xad, 0xad, 0x6d, 0xdb, - 0xfa, 0xb1, 0x6d, 0x5b, 0xef, 0x76, 0xec, 0xc2, 0xd6, 0x8e, 0x5d, 0xf8, 0xb6, 0x63, 0x17, 0x9e, - 0x4f, 0x87, 0x42, 0x37, 0x52, 0xbf, 0x52, 0x57, 0xf1, 0xbe, 0x63, 0x5e, 0xee, 0x19, 0xa4, 0x37, - 0x9a, 0x1c, 0xfc, 0xa2, 0xf9, 0x8b, 0xcc, 0xfd, 0x09, 0x00, 0x00, 0xff, 0xff, 0x28, 0x09, 0x13, - 0xb9, 0xf4, 0x06, 0x00, 0x00, + // 660 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xa4, 0x55, 0x4f, 0x4f, 0xd4, 0x4e, + 0x18, 0xde, 0xf2, 0xfb, 0xb9, 0xc6, 0x31, 0x31, 0x71, 0x40, 0x24, 0x0d, 0x76, 0xb1, 0xa2, 0x18, + 0x13, 0x3a, 0x80, 0xca, 0x45, 0x20, 0xee, 0x1a, 0x35, 0xfe, 0x8b, 0x88, 0x7a, 0xd0, 0x4b, 0x33, + 0xdd, 0x8e, 0xdd, 0x49, 0xda, 0x4e, 0xe9, 0x3b, 0x05, 0xd1, 0x78, 0xf1, 0x13, 0x18, 0xbd, 0xfa, + 0x19, 0xfc, 0x16, 0x26, 0x1c, 0x89, 0x5e, 0x3c, 0x19, 0x03, 0x1e, 0xfc, 0x10, 0x1e, 0xcc, 0x4e, + 0xa7, 0x85, 0x5d, 0xd8, 0x05, 0xf1, 0x36, 0xf3, 0xf6, 0x7d, 0x9e, 0xf7, 0x79, 0xde, 0x3e, 0x4d, + 0xd1, 0x29, 0x16, 0x71, 0x00, 0x2e, 0x62, 0x20, 0xcb, 0x19, 0x4b, 0xd7, 0x9c, 0x24, 0x15, 0x52, + 0xe0, 0xd1, 0x57, 0x4c, 0xd2, 0x66, 0x8b, 0xf2, 0xd8, 0x51, 0x27, 0x91, 0x32, 0xa7, 0xec, 0x34, + 0x2f, 0x35, 0x05, 0x44, 0x02, 0x88, 0x47, 0x81, 0xe5, 0x30, 0xb2, 0x32, 0xed, 0x31, 0x49, 0xa7, + 0x49, 0x42, 0x03, 0x1e, 0x53, 0xc9, 0x45, 0x9c, 0x33, 0x99, 0xc3, 0xdb, 0x03, 0x12, 0x9a, 0xd2, + 0x08, 0x74, 0x7d, 0x28, 0x10, 0x81, 0x50, 0x47, 0xd2, 0x3e, 0xe9, 0xea, 0x68, 0x20, 0x44, 0x10, + 0x32, 0x42, 0x13, 0x4e, 0x68, 0x1c, 0x0b, 0xa9, 0xa8, 0x34, 0xc6, 0x1e, 0x42, 0xf8, 0x51, 0x7b, + 0xda, 0xa2, 0x22, 0x5a, 0x62, 0xcb, 0x19, 0x03, 0x69, 0x3f, 0x43, 0x83, 0x1d, 0x55, 0x48, 0x44, + 0x0c, 0x0c, 0x37, 0x50, 0x35, 0x1f, 0x38, 0x62, 0x8c, 0x19, 0x17, 0x8f, 0xcf, 0x8c, 0x3b, 0xfd, + 0x3c, 0x39, 0x39, 0xba, 0xf1, 0xff, 0xfa, 0xf7, 0x5a, 0x65, 0x49, 0x23, 0xed, 0x1a, 0x3a, 0xa3, + 0xa8, 0xef, 0x73, 0x90, 0x8b, 0x42, 0x84, 0x75, 0xdf, 0x4f, 0x19, 0x00, 0x2b, 0x67, 0xff, 0x36, + 0x90, 0xd5, 0xab, 0x43, 0xeb, 0x78, 0x8a, 0x26, 0xb2, 0xd8, 0xe7, 0x20, 0x53, 0xee, 0x65, 0x92, + 0xf9, 0xae, 0xf0, 0x80, 0xa5, 0x2b, 0x2c, 0x75, 0x3d, 0x1a, 0xd2, 0xb8, 0xc9, 0xc0, 0xa5, 0x39, + 0x48, 0x09, 0x3d, 0xb6, 0x34, 0xde, 0xd1, 0xfe, 0x50, 0x77, 0x37, 0x74, 0xb3, 0x1e, 0x80, 0xef, + 0x21, 0xbb, 0x93, 0x56, 0x02, 0xec, 0x66, 0x1c, 0x50, 0x8c, 0xb5, 0x8e, 0xce, 0x27, 0x00, 0xdd, + 0x64, 0xb3, 0xe8, 0x74, 0xb1, 0x09, 0x37, 0x12, 0x7e, 0x16, 0xb2, 0x92, 0xe1, 0x3f, 0xc5, 0x50, + 0xc6, 0xe4, 0x81, 0x7a, 0xaa, 0x71, 0xf6, 0x59, 0x54, 0x53, 0xee, 0x6f, 0x33, 0x79, 0xb3, 0xd8, + 0xe4, 0x2d, 0xda, 0x94, 0x22, 0x2d, 0x37, 0xf4, 0xde, 0x40, 0x63, 0xbd, 0x7b, 0xf4, 0x8e, 0x2e, + 0xa0, 0x13, 0x29, 0x53, 0x3e, 0xf5, 0x23, 0xbd, 0x8a, 0xae, 0x2a, 0xb6, 0x10, 0xf2, 0x44, 0xec, + 0xeb, 0x9e, 0xdc, 0xdc, 0x8e, 0x4a, 0x9b, 0xc7, 0xcf, 0x52, 0x95, 0x19, 0xdd, 0x93, 0xcb, 0xef, + 0xaa, 0xda, 0x0b, 0xc8, 0x56, 0x9a, 0x1e, 0xb7, 0xc4, 0x6a, 0x7d, 0x85, 0xf2, 0x90, 0x7a, 0x21, + 0x2b, 0xd5, 0x69, 0xe9, 0x78, 0x04, 0x1d, 0xed, 0x7c, 0x33, 0xc5, 0xd5, 0x9e, 0x47, 0xe7, 0xfa, + 0xe2, 0xb5, 0xad, 0x61, 0x54, 0xa5, 0x91, 0xc8, 0x62, 0xa9, 0xf1, 0xfa, 0x36, 0xf3, 0xa9, 0x8a, + 0x8e, 0x28, 0x3c, 0xfe, 0x68, 0xa0, 0x6a, 0x9e, 0x3c, 0x3c, 0xd5, 0x3f, 0x9f, 0xbb, 0x83, 0x6f, + 0x4e, 0xff, 0x05, 0x22, 0x57, 0x64, 0x4f, 0xbe, 0xfd, 0xfa, 0xf3, 0xc3, 0xc0, 0x04, 0x3e, 0x4f, + 0xda, 0x80, 0x49, 0x85, 0x25, 0x05, 0x96, 0x74, 0x7f, 0xaa, 0xf8, 0xb3, 0x81, 0x4e, 0xee, 0x4a, + 0x36, 0xbe, 0x76, 0x80, 0xb9, 0xbd, 0xbe, 0x18, 0x73, 0xee, 0x70, 0x60, 0xad, 0xff, 0xaa, 0xd2, + 0x4f, 0xf0, 0xe4, 0x3e, 0xfa, 0x43, 0x0e, 0xb2, 0x88, 0x30, 0x03, 0xfc, 0xc5, 0x40, 0x83, 0x7b, + 0xe4, 0x0f, 0xcf, 0x1f, 0x40, 0x4c, 0xef, 0x6c, 0x9b, 0x0b, 0x87, 0x85, 0x6b, 0x37, 0x73, 0xca, + 0xcd, 0x2c, 0xbe, 0xb2, 0x8f, 0x9b, 0x80, 0x49, 0xb7, 0xbc, 0xb9, 0x2f, 0xb4, 0xf8, 0x5f, 0x06, + 0x1a, 0xde, 0x3b, 0x80, 0xf8, 0xfa, 0x01, 0x84, 0xf5, 0xcd, 0xbe, 0x59, 0xff, 0x07, 0x06, 0xed, + 0xee, 0x8e, 0x72, 0x77, 0x03, 0xd7, 0xf7, 0x71, 0x07, 0x2d, 0xb1, 0xea, 0xd2, 0x82, 0x67, 0xdb, + 0x28, 0x79, 0xad, 0x5f, 0xe0, 0x9b, 0xc6, 0xdd, 0xf5, 0x4d, 0xcb, 0xd8, 0xd8, 0xb4, 0x8c, 0x1f, + 0x9b, 0x96, 0xf1, 0x6e, 0xcb, 0xaa, 0x6c, 0x6c, 0x59, 0x95, 0x6f, 0x5b, 0x56, 0xe5, 0xf9, 0x54, + 0xc0, 0x65, 0x2b, 0xf3, 0x9c, 0xa6, 0x88, 0xf6, 0x1c, 0xf3, 0x72, 0xc7, 0x20, 0xb9, 0x96, 0x30, + 0xf0, 0xaa, 0xea, 0x5f, 0x72, 0xf9, 0x4f, 0x00, 0x00, 0x00, 0xff, 0xff, 0x52, 0x66, 0xde, 0xc2, + 0xfa, 0x06, 0x00, 0x00, } // Reference imports to suppress errors if they are not otherwise used. @@ -470,7 +470,7 @@ type QueryClient interface { // Queries a list of ListBalances items. ListPoolAddresses(ctx context.Context, in *QueryListPoolAddressesRequest, opts ...grpc.CallOption) (*QueryListPoolAddressesResponse, error) // Queries a list of GetEmmisonsFactors items. - GetEmmisonsFactors(ctx context.Context, in *QueryGetEmmisonsFactorsRequest, opts ...grpc.CallOption) (*QueryGetEmmisonsFactorsResponse, error) + GetEmissionsFactors(ctx context.Context, in *QueryGetEmissionsFactorsRequest, opts ...grpc.CallOption) (*QueryGetEmissionsFactorsResponse, error) // Queries a list of ShowAvailableEmissions items. ShowAvailableEmissions(ctx context.Context, in *QueryShowAvailableEmissionsRequest, opts ...grpc.CallOption) (*QueryShowAvailableEmissionsResponse, error) } @@ -501,9 +501,9 @@ func (c *queryClient) ListPoolAddresses(ctx context.Context, in *QueryListPoolAd return out, nil } -func (c *queryClient) GetEmmisonsFactors(ctx context.Context, in *QueryGetEmmisonsFactorsRequest, opts ...grpc.CallOption) (*QueryGetEmmisonsFactorsResponse, error) { - out := new(QueryGetEmmisonsFactorsResponse) - err := c.cc.Invoke(ctx, "/zetachain.zetacore.emissions.Query/GetEmmisonsFactors", in, out, opts...) +func (c *queryClient) GetEmissionsFactors(ctx context.Context, in *QueryGetEmissionsFactorsRequest, opts ...grpc.CallOption) (*QueryGetEmissionsFactorsResponse, error) { + out := new(QueryGetEmissionsFactorsResponse) + err := c.cc.Invoke(ctx, "/zetachain.zetacore.emissions.Query/GetEmissionsFactors", in, out, opts...) if err != nil { return nil, err } @@ -526,7 +526,7 @@ type QueryServer interface { // Queries a list of ListBalances items. ListPoolAddresses(context.Context, *QueryListPoolAddressesRequest) (*QueryListPoolAddressesResponse, error) // Queries a list of GetEmmisonsFactors items. - GetEmmisonsFactors(context.Context, *QueryGetEmmisonsFactorsRequest) (*QueryGetEmmisonsFactorsResponse, error) + GetEmissionsFactors(context.Context, *QueryGetEmissionsFactorsRequest) (*QueryGetEmissionsFactorsResponse, error) // Queries a list of ShowAvailableEmissions items. ShowAvailableEmissions(context.Context, *QueryShowAvailableEmissionsRequest) (*QueryShowAvailableEmissionsResponse, error) } @@ -541,8 +541,8 @@ func (*UnimplementedQueryServer) Params(ctx context.Context, req *QueryParamsReq func (*UnimplementedQueryServer) ListPoolAddresses(ctx context.Context, req *QueryListPoolAddressesRequest) (*QueryListPoolAddressesResponse, error) { return nil, status.Errorf(codes.Unimplemented, "method ListPoolAddresses not implemented") } -func (*UnimplementedQueryServer) GetEmmisonsFactors(ctx context.Context, req *QueryGetEmmisonsFactorsRequest) (*QueryGetEmmisonsFactorsResponse, error) { - return nil, status.Errorf(codes.Unimplemented, "method GetEmmisonsFactors not implemented") +func (*UnimplementedQueryServer) GetEmissionsFactors(ctx context.Context, req *QueryGetEmissionsFactorsRequest) (*QueryGetEmissionsFactorsResponse, error) { + return nil, status.Errorf(codes.Unimplemented, "method GetEmissionsFactors not implemented") } func (*UnimplementedQueryServer) ShowAvailableEmissions(ctx context.Context, req *QueryShowAvailableEmissionsRequest) (*QueryShowAvailableEmissionsResponse, error) { return nil, status.Errorf(codes.Unimplemented, "method ShowAvailableEmissions not implemented") @@ -588,20 +588,20 @@ func _Query_ListPoolAddresses_Handler(srv interface{}, ctx context.Context, dec return interceptor(ctx, in, info, handler) } -func _Query_GetEmmisonsFactors_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { - in := new(QueryGetEmmisonsFactorsRequest) +func _Query_GetEmissionsFactors_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(QueryGetEmissionsFactorsRequest) if err := dec(in); err != nil { return nil, err } if interceptor == nil { - return srv.(QueryServer).GetEmmisonsFactors(ctx, in) + return srv.(QueryServer).GetEmissionsFactors(ctx, in) } info := &grpc.UnaryServerInfo{ Server: srv, - FullMethod: "/zetachain.zetacore.emissions.Query/GetEmmisonsFactors", + FullMethod: "/zetachain.zetacore.emissions.Query/GetEmissionsFactors", } handler := func(ctx context.Context, req interface{}) (interface{}, error) { - return srv.(QueryServer).GetEmmisonsFactors(ctx, req.(*QueryGetEmmisonsFactorsRequest)) + return srv.(QueryServer).GetEmissionsFactors(ctx, req.(*QueryGetEmissionsFactorsRequest)) } return interceptor(ctx, in, info, handler) } @@ -637,8 +637,8 @@ var _Query_serviceDesc = grpc.ServiceDesc{ Handler: _Query_ListPoolAddresses_Handler, }, { - MethodName: "GetEmmisonsFactors", - Handler: _Query_GetEmmisonsFactors_Handler, + MethodName: "GetEmissionsFactors", + Handler: _Query_GetEmissionsFactors_Handler, }, { MethodName: "ShowAvailableEmissions", @@ -772,7 +772,7 @@ func (m *QueryListPoolAddressesResponse) MarshalToSizedBuffer(dAtA []byte) (int, return len(dAtA) - i, nil } -func (m *QueryGetEmmisonsFactorsRequest) Marshal() (dAtA []byte, err error) { +func (m *QueryGetEmissionsFactorsRequest) Marshal() (dAtA []byte, err error) { size := m.Size() dAtA = make([]byte, size) n, err := m.MarshalToSizedBuffer(dAtA[:size]) @@ -782,12 +782,12 @@ func (m *QueryGetEmmisonsFactorsRequest) Marshal() (dAtA []byte, err error) { return dAtA[:n], nil } -func (m *QueryGetEmmisonsFactorsRequest) MarshalTo(dAtA []byte) (int, error) { +func (m *QueryGetEmissionsFactorsRequest) MarshalTo(dAtA []byte) (int, error) { size := m.Size() return m.MarshalToSizedBuffer(dAtA[:size]) } -func (m *QueryGetEmmisonsFactorsRequest) MarshalToSizedBuffer(dAtA []byte) (int, error) { +func (m *QueryGetEmissionsFactorsRequest) MarshalToSizedBuffer(dAtA []byte) (int, error) { i := len(dAtA) _ = i var l int @@ -795,7 +795,7 @@ func (m *QueryGetEmmisonsFactorsRequest) MarshalToSizedBuffer(dAtA []byte) (int, return len(dAtA) - i, nil } -func (m *QueryGetEmmisonsFactorsResponse) Marshal() (dAtA []byte, err error) { +func (m *QueryGetEmissionsFactorsResponse) Marshal() (dAtA []byte, err error) { size := m.Size() dAtA = make([]byte, size) n, err := m.MarshalToSizedBuffer(dAtA[:size]) @@ -805,12 +805,12 @@ func (m *QueryGetEmmisonsFactorsResponse) Marshal() (dAtA []byte, err error) { return dAtA[:n], nil } -func (m *QueryGetEmmisonsFactorsResponse) MarshalTo(dAtA []byte) (int, error) { +func (m *QueryGetEmissionsFactorsResponse) MarshalTo(dAtA []byte) (int, error) { size := m.Size() return m.MarshalToSizedBuffer(dAtA[:size]) } -func (m *QueryGetEmmisonsFactorsResponse) MarshalToSizedBuffer(dAtA []byte) (int, error) { +func (m *QueryGetEmissionsFactorsResponse) MarshalToSizedBuffer(dAtA []byte) (int, error) { i := len(dAtA) _ = i var l int @@ -960,7 +960,7 @@ func (m *QueryListPoolAddressesResponse) Size() (n int) { return n } -func (m *QueryGetEmmisonsFactorsRequest) Size() (n int) { +func (m *QueryGetEmissionsFactorsRequest) Size() (n int) { if m == nil { return 0 } @@ -969,7 +969,7 @@ func (m *QueryGetEmmisonsFactorsRequest) Size() (n int) { return n } -func (m *QueryGetEmmisonsFactorsResponse) Size() (n int) { +func (m *QueryGetEmissionsFactorsResponse) Size() (n int) { if m == nil { return 0 } @@ -1351,7 +1351,7 @@ func (m *QueryListPoolAddressesResponse) Unmarshal(dAtA []byte) error { } return nil } -func (m *QueryGetEmmisonsFactorsRequest) Unmarshal(dAtA []byte) error { +func (m *QueryGetEmissionsFactorsRequest) Unmarshal(dAtA []byte) error { l := len(dAtA) iNdEx := 0 for iNdEx < l { @@ -1374,10 +1374,10 @@ func (m *QueryGetEmmisonsFactorsRequest) Unmarshal(dAtA []byte) error { fieldNum := int32(wire >> 3) wireType := int(wire & 0x7) if wireType == 4 { - return fmt.Errorf("proto: QueryGetEmmisonsFactorsRequest: wiretype end group for non-group") + return fmt.Errorf("proto: QueryGetEmissionsFactorsRequest: wiretype end group for non-group") } if fieldNum <= 0 { - return fmt.Errorf("proto: QueryGetEmmisonsFactorsRequest: illegal tag %d (wire type %d)", fieldNum, wire) + return fmt.Errorf("proto: QueryGetEmissionsFactorsRequest: illegal tag %d (wire type %d)", fieldNum, wire) } switch fieldNum { default: @@ -1401,7 +1401,7 @@ func (m *QueryGetEmmisonsFactorsRequest) Unmarshal(dAtA []byte) error { } return nil } -func (m *QueryGetEmmisonsFactorsResponse) Unmarshal(dAtA []byte) error { +func (m *QueryGetEmissionsFactorsResponse) Unmarshal(dAtA []byte) error { l := len(dAtA) iNdEx := 0 for iNdEx < l { @@ -1424,10 +1424,10 @@ func (m *QueryGetEmmisonsFactorsResponse) Unmarshal(dAtA []byte) error { fieldNum := int32(wire >> 3) wireType := int(wire & 0x7) if wireType == 4 { - return fmt.Errorf("proto: QueryGetEmmisonsFactorsResponse: wiretype end group for non-group") + return fmt.Errorf("proto: QueryGetEmissionsFactorsResponse: wiretype end group for non-group") } if fieldNum <= 0 { - return fmt.Errorf("proto: QueryGetEmmisonsFactorsResponse: illegal tag %d (wire type %d)", fieldNum, wire) + return fmt.Errorf("proto: QueryGetEmissionsFactorsResponse: illegal tag %d (wire type %d)", fieldNum, wire) } switch fieldNum { case 1: diff --git a/x/emissions/types/query.pb.gw.go b/x/emissions/types/query.pb.gw.go index 3ae17dca8b..36f6e4d9b9 100644 --- a/x/emissions/types/query.pb.gw.go +++ b/x/emissions/types/query.pb.gw.go @@ -69,20 +69,20 @@ func local_request_Query_ListPoolAddresses_0(ctx context.Context, marshaler runt } -func request_Query_GetEmmisonsFactors_0(ctx context.Context, marshaler runtime.Marshaler, client QueryClient, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) { - var protoReq QueryGetEmmisonsFactorsRequest +func request_Query_GetEmissionsFactors_0(ctx context.Context, marshaler runtime.Marshaler, client QueryClient, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) { + var protoReq QueryGetEmissionsFactorsRequest var metadata runtime.ServerMetadata - msg, err := client.GetEmmisonsFactors(ctx, &protoReq, grpc.Header(&metadata.HeaderMD), grpc.Trailer(&metadata.TrailerMD)) + msg, err := client.GetEmissionsFactors(ctx, &protoReq, grpc.Header(&metadata.HeaderMD), grpc.Trailer(&metadata.TrailerMD)) return msg, metadata, err } -func local_request_Query_GetEmmisonsFactors_0(ctx context.Context, marshaler runtime.Marshaler, server QueryServer, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) { - var protoReq QueryGetEmmisonsFactorsRequest +func local_request_Query_GetEmissionsFactors_0(ctx context.Context, marshaler runtime.Marshaler, server QueryServer, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) { + var protoReq QueryGetEmissionsFactorsRequest var metadata runtime.ServerMetadata - msg, err := server.GetEmmisonsFactors(ctx, &protoReq) + msg, err := server.GetEmissionsFactors(ctx, &protoReq) return msg, metadata, err } @@ -193,7 +193,7 @@ func RegisterQueryHandlerServer(ctx context.Context, mux *runtime.ServeMux, serv }) - mux.Handle("GET", pattern_Query_GetEmmisonsFactors_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) { + mux.Handle("GET", pattern_Query_GetEmissionsFactors_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) { ctx, cancel := context.WithCancel(req.Context()) defer cancel() var stream runtime.ServerTransportStream @@ -204,7 +204,7 @@ func RegisterQueryHandlerServer(ctx context.Context, mux *runtime.ServeMux, serv runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) return } - resp, md, err := local_request_Query_GetEmmisonsFactors_0(rctx, inboundMarshaler, server, req, pathParams) + resp, md, err := local_request_Query_GetEmissionsFactors_0(rctx, inboundMarshaler, server, req, pathParams) md.HeaderMD, md.TrailerMD = metadata.Join(md.HeaderMD, stream.Header()), metadata.Join(md.TrailerMD, stream.Trailer()) ctx = runtime.NewServerMetadataContext(ctx, md) if err != nil { @@ -212,7 +212,7 @@ func RegisterQueryHandlerServer(ctx context.Context, mux *runtime.ServeMux, serv return } - forward_Query_GetEmmisonsFactors_0(ctx, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...) + forward_Query_GetEmissionsFactors_0(ctx, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...) }) @@ -320,7 +320,7 @@ func RegisterQueryHandlerClient(ctx context.Context, mux *runtime.ServeMux, clie }) - mux.Handle("GET", pattern_Query_GetEmmisonsFactors_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) { + mux.Handle("GET", pattern_Query_GetEmissionsFactors_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) { ctx, cancel := context.WithCancel(req.Context()) defer cancel() inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req) @@ -329,14 +329,14 @@ func RegisterQueryHandlerClient(ctx context.Context, mux *runtime.ServeMux, clie runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) return } - resp, md, err := request_Query_GetEmmisonsFactors_0(rctx, inboundMarshaler, client, req, pathParams) + resp, md, err := request_Query_GetEmissionsFactors_0(rctx, inboundMarshaler, client, req, pathParams) ctx = runtime.NewServerMetadataContext(ctx, md) if err != nil { runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) return } - forward_Query_GetEmmisonsFactors_0(ctx, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...) + forward_Query_GetEmissionsFactors_0(ctx, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...) }) @@ -368,7 +368,7 @@ var ( pattern_Query_ListPoolAddresses_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2, 2, 3}, []string{"zeta-chain", "zetacore", "emissions", "list_addresses"}, "", runtime.AssumeColonVerbOpt(false))) - pattern_Query_GetEmmisonsFactors_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2, 2, 3}, []string{"zeta-chain", "zetacore", "emissions", "get_emmisons_factors"}, "", runtime.AssumeColonVerbOpt(false))) + pattern_Query_GetEmissionsFactors_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2, 2, 3}, []string{"zeta-chain", "zetacore", "emissions", "get_emissions_factors"}, "", runtime.AssumeColonVerbOpt(false))) pattern_Query_ShowAvailableEmissions_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2, 2, 3, 1, 0, 4, 1, 5, 4}, []string{"zeta-chain", "zetacore", "emissions", "show_available_emissions", "address"}, "", runtime.AssumeColonVerbOpt(false))) ) @@ -378,7 +378,7 @@ var ( forward_Query_ListPoolAddresses_0 = runtime.ForwardResponseMessage - forward_Query_GetEmmisonsFactors_0 = runtime.ForwardResponseMessage + forward_Query_GetEmissionsFactors_0 = runtime.ForwardResponseMessage forward_Query_ShowAvailableEmissions_0 = runtime.ForwardResponseMessage ) From b6bfa5717e90eaeee9b609b383febbb20b0d9c81 Mon Sep 17 00:00:00 2001 From: Charlie Chen <34498985+ws4charlie@users.noreply.github.com> Date: Thu, 12 Oct 2023 10:46:01 -0500 Subject: [PATCH 10/27] feat: Bitcoin block header and merkle proof (#1263) * initiated bitcoin header and proof * added smoke test for bitcoin merkle proof and RPC query * make generate * fix gosec and unit test * Update common/headers_test.go Co-authored-by: Lucas Bertrand * code adjustment according to feedback of PR review * corrected a typo and added more comment to function * fix gosec error --------- Co-authored-by: charliec Co-authored-by: Lucas Bertrand Co-authored-by: brewmaster012 <88689859+brewmaster012@users.noreply.github.com> --- common/bitcoin/bitcoin.pb.go | 407 ++++++++++++++++++ common/bitcoin/bitcoin_spv.go | 99 +++++ common/bitcoin/proof.go | 73 ++++ common/common.pb.go | 241 +++++++++-- common/default_chains_mainnet.go | 4 + common/default_chains_mock_mainnet.go | 4 + common/default_chains_privnet.go | 4 + common/default_chains_testnet.go | 4 + common/headers.go | 105 ++++- common/headers_test.go | 187 ++++++++ common/proof.go | 37 ++ common/proof_test.go | 149 +++++++ common/test_data/test_blocks.json | 12 + common/utils.go | 47 ++ .../orchestrator/smoketest/test_bitcoin.go | 88 +++- .../smoketest/test_deposit_eth.go | 2 +- docs/openapi/openapi.swagger.yaml | 35 +- proto/common/bitcoin/bitcoin.proto | 10 + proto/common/common.proto | 3 + proto/observer/query.proto | 2 +- x/crosschain/keeper/keeper_out_tx_tracker.go | 111 ++++- x/observer/keeper/grpc_query_prove.go | 40 +- .../keeper/msg_server_add_block_header.go | 13 +- x/observer/types/errors.go | 1 + x/observer/types/messages_add_block_header.go | 8 +- x/observer/types/query.pb.go | 241 ++++++----- zetaclient/bitcoin_client.go | 96 ++++- zetaclient/btc_signer.go | 4 +- zetaclient/btc_signer_test.go | 5 +- zetaclient/evm_client.go | 3 +- zetaclient/query.go | 2 +- zetaclient/tx.go | 4 +- 32 files changed, 1806 insertions(+), 235 deletions(-) create mode 100644 common/bitcoin/bitcoin.pb.go create mode 100644 common/bitcoin/bitcoin_spv.go create mode 100644 common/bitcoin/proof.go create mode 100644 common/headers_test.go create mode 100644 common/test_data/test_blocks.json create mode 100644 common/utils.go create mode 100644 proto/common/bitcoin/bitcoin.proto diff --git a/common/bitcoin/bitcoin.pb.go b/common/bitcoin/bitcoin.pb.go new file mode 100644 index 0000000000..e56ac19d24 --- /dev/null +++ b/common/bitcoin/bitcoin.pb.go @@ -0,0 +1,407 @@ +// Code generated by protoc-gen-gogo. DO NOT EDIT. +// source: common/bitcoin/bitcoin.proto + +package bitcoin + +import ( + fmt "fmt" + io "io" + math "math" + math_bits "math/bits" + + proto "github.com/gogo/protobuf/proto" +) + +// Reference imports to suppress errors if they are not otherwise used. +var _ = proto.Marshal +var _ = fmt.Errorf +var _ = math.Inf + +// This is a compile-time assertion to ensure that this generated file +// is compatible with the proto package it is being compiled against. +// A compilation error at this line likely means your copy of the +// proto package needs to be updated. +const _ = proto.GoGoProtoPackageIsVersion3 // please upgrade the proto package + +type Proof struct { + TxBytes []byte `protobuf:"bytes,1,opt,name=tx_bytes,json=txBytes,proto3" json:"tx_bytes,omitempty"` + Path []byte `protobuf:"bytes,2,opt,name=path,proto3" json:"path,omitempty"` + Index uint32 `protobuf:"varint,3,opt,name=index,proto3" json:"index,omitempty"` +} + +func (m *Proof) Reset() { *m = Proof{} } +func (m *Proof) String() string { return proto.CompactTextString(m) } +func (*Proof) ProtoMessage() {} +func (*Proof) Descriptor() ([]byte, []int) { + return fileDescriptor_0a2411cf854c4a85, []int{0} +} +func (m *Proof) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *Proof) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_Proof.Marshal(b, m, deterministic) + } else { + b = b[:cap(b)] + n, err := m.MarshalToSizedBuffer(b) + if err != nil { + return nil, err + } + return b[:n], nil + } +} +func (m *Proof) XXX_Merge(src proto.Message) { + xxx_messageInfo_Proof.Merge(m, src) +} +func (m *Proof) XXX_Size() int { + return m.Size() +} +func (m *Proof) XXX_DiscardUnknown() { + xxx_messageInfo_Proof.DiscardUnknown(m) +} + +var xxx_messageInfo_Proof proto.InternalMessageInfo + +func (m *Proof) GetTxBytes() []byte { + if m != nil { + return m.TxBytes + } + return nil +} + +func (m *Proof) GetPath() []byte { + if m != nil { + return m.Path + } + return nil +} + +func (m *Proof) GetIndex() uint32 { + if m != nil { + return m.Index + } + return 0 +} + +func init() { + proto.RegisterType((*Proof)(nil), "bitcoin.Proof") +} + +func init() { proto.RegisterFile("common/bitcoin/bitcoin.proto", fileDescriptor_0a2411cf854c4a85) } + +var fileDescriptor_0a2411cf854c4a85 = []byte{ + // 180 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xe2, 0x92, 0x49, 0xce, 0xcf, 0xcd, + 0xcd, 0xcf, 0xd3, 0x4f, 0xca, 0x2c, 0x49, 0xce, 0xcf, 0x84, 0xd3, 0x7a, 0x05, 0x45, 0xf9, 0x25, + 0xf9, 0x42, 0xec, 0x50, 0xae, 0x92, 0x0f, 0x17, 0x6b, 0x40, 0x51, 0x7e, 0x7e, 0x9a, 0x90, 0x24, + 0x17, 0x47, 0x49, 0x45, 0x7c, 0x52, 0x65, 0x49, 0x6a, 0xb1, 0x04, 0xa3, 0x02, 0xa3, 0x06, 0x4f, + 0x10, 0x7b, 0x49, 0x85, 0x13, 0x88, 0x2b, 0x24, 0xc4, 0xc5, 0x52, 0x90, 0x58, 0x92, 0x21, 0xc1, + 0x04, 0x16, 0x06, 0xb3, 0x85, 0x44, 0xb8, 0x58, 0x33, 0xf3, 0x52, 0x52, 0x2b, 0x24, 0x98, 0x15, + 0x18, 0x35, 0x78, 0x83, 0x20, 0x1c, 0x27, 0xf7, 0x13, 0x8f, 0xe4, 0x18, 0x2f, 0x3c, 0x92, 0x63, + 0x7c, 0xf0, 0x48, 0x8e, 0x71, 0xc2, 0x63, 0x39, 0x86, 0x0b, 0x8f, 0xe5, 0x18, 0x6e, 0x3c, 0x96, + 0x63, 0x88, 0xd2, 0x4d, 0xcf, 0x2c, 0xc9, 0x28, 0x4d, 0xd2, 0x4b, 0xce, 0xcf, 0xd5, 0xaf, 0x4a, + 0x2d, 0x49, 0xd4, 0x4d, 0xce, 0x48, 0xcc, 0xcc, 0x03, 0x33, 0x93, 0xf3, 0x8b, 0x52, 0xf5, 0x51, + 0x5d, 0x9b, 0xc4, 0x06, 0x76, 0xa6, 0x31, 0x20, 0x00, 0x00, 0xff, 0xff, 0x02, 0xc5, 0x71, 0x41, + 0xc6, 0x00, 0x00, 0x00, +} + +func (m *Proof) Marshal() (dAtA []byte, err error) { + size := m.Size() + dAtA = make([]byte, size) + n, err := m.MarshalToSizedBuffer(dAtA[:size]) + if err != nil { + return nil, err + } + return dAtA[:n], nil +} + +func (m *Proof) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *Proof) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + if m.Index != 0 { + i = encodeVarintBitcoin(dAtA, i, uint64(m.Index)) + i-- + dAtA[i] = 0x18 + } + if len(m.Path) > 0 { + i -= len(m.Path) + copy(dAtA[i:], m.Path) + i = encodeVarintBitcoin(dAtA, i, uint64(len(m.Path))) + i-- + dAtA[i] = 0x12 + } + if len(m.TxBytes) > 0 { + i -= len(m.TxBytes) + copy(dAtA[i:], m.TxBytes) + i = encodeVarintBitcoin(dAtA, i, uint64(len(m.TxBytes))) + i-- + dAtA[i] = 0xa + } + return len(dAtA) - i, nil +} + +func encodeVarintBitcoin(dAtA []byte, offset int, v uint64) int { + offset -= sovBitcoin(v) + base := offset + for v >= 1<<7 { + dAtA[offset] = uint8(v&0x7f | 0x80) + v >>= 7 + offset++ + } + dAtA[offset] = uint8(v) + return base +} +func (m *Proof) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + l = len(m.TxBytes) + if l > 0 { + n += 1 + l + sovBitcoin(uint64(l)) + } + l = len(m.Path) + if l > 0 { + n += 1 + l + sovBitcoin(uint64(l)) + } + if m.Index != 0 { + n += 1 + sovBitcoin(uint64(m.Index)) + } + return n +} + +func sovBitcoin(x uint64) (n int) { + return (math_bits.Len64(x|1) + 6) / 7 +} +func sozBitcoin(x uint64) (n int) { + return sovBitcoin(uint64((x << 1) ^ uint64((int64(x) >> 63)))) +} +func (m *Proof) Unmarshal(dAtA []byte) error { + l := len(dAtA) + iNdEx := 0 + for iNdEx < l { + preIndex := iNdEx + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowBitcoin + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + fieldNum := int32(wire >> 3) + wireType := int(wire & 0x7) + if wireType == 4 { + return fmt.Errorf("proto: Proof: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: Proof: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field TxBytes", wireType) + } + var byteLen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowBitcoin + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + byteLen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if byteLen < 0 { + return ErrInvalidLengthBitcoin + } + postIndex := iNdEx + byteLen + if postIndex < 0 { + return ErrInvalidLengthBitcoin + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.TxBytes = append(m.TxBytes[:0], dAtA[iNdEx:postIndex]...) + if m.TxBytes == nil { + m.TxBytes = []byte{} + } + iNdEx = postIndex + case 2: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Path", wireType) + } + var byteLen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowBitcoin + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + byteLen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if byteLen < 0 { + return ErrInvalidLengthBitcoin + } + postIndex := iNdEx + byteLen + if postIndex < 0 { + return ErrInvalidLengthBitcoin + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.Path = append(m.Path[:0], dAtA[iNdEx:postIndex]...) + if m.Path == nil { + m.Path = []byte{} + } + iNdEx = postIndex + case 3: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field Index", wireType) + } + m.Index = 0 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowBitcoin + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + m.Index |= uint32(b&0x7F) << shift + if b < 0x80 { + break + } + } + default: + iNdEx = preIndex + skippy, err := skipBitcoin(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return ErrInvalidLengthBitcoin + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func skipBitcoin(dAtA []byte) (n int, err error) { + l := len(dAtA) + iNdEx := 0 + depth := 0 + for iNdEx < l { + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return 0, ErrIntOverflowBitcoin + } + if iNdEx >= l { + return 0, io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= (uint64(b) & 0x7F) << shift + if b < 0x80 { + break + } + } + wireType := int(wire & 0x7) + switch wireType { + case 0: + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return 0, ErrIntOverflowBitcoin + } + if iNdEx >= l { + return 0, io.ErrUnexpectedEOF + } + iNdEx++ + if dAtA[iNdEx-1] < 0x80 { + break + } + } + case 1: + iNdEx += 8 + case 2: + var length int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return 0, ErrIntOverflowBitcoin + } + if iNdEx >= l { + return 0, io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + length |= (int(b) & 0x7F) << shift + if b < 0x80 { + break + } + } + if length < 0 { + return 0, ErrInvalidLengthBitcoin + } + iNdEx += length + case 3: + depth++ + case 4: + if depth == 0 { + return 0, ErrUnexpectedEndOfGroupBitcoin + } + depth-- + case 5: + iNdEx += 4 + default: + return 0, fmt.Errorf("proto: illegal wireType %d", wireType) + } + if iNdEx < 0 { + return 0, ErrInvalidLengthBitcoin + } + if depth == 0 { + return iNdEx, nil + } + } + return 0, io.ErrUnexpectedEOF +} + +var ( + ErrInvalidLengthBitcoin = fmt.Errorf("proto: negative length found during unmarshaling") + ErrIntOverflowBitcoin = fmt.Errorf("proto: integer overflow") + ErrUnexpectedEndOfGroupBitcoin = fmt.Errorf("proto: unexpected end of group") +) diff --git a/common/bitcoin/bitcoin_spv.go b/common/bitcoin/bitcoin_spv.go new file mode 100644 index 0000000000..1a3c7fb8b9 --- /dev/null +++ b/common/bitcoin/bitcoin_spv.go @@ -0,0 +1,99 @@ +// Copyright 2020 Indefinite Integral Incorporated + +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at + +// http://www.apache.org/licenses/LICENSE-2.0 + +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package bitcoin + +// This file was adapted from Summa bitcoin-spv. Here are some modifications: +// - define 'Hash256Digest' as alias for 'chainhash.Hash' +// - keep only Prove() and dependent functions + +import ( + "bytes" + "crypto/sha256" + + "github.com/btcsuite/btcd/chaincfg/chainhash" +) + +type Hash256Digest = chainhash.Hash + +// Prove checks the validity of a merkle proof +func Prove(txid Hash256Digest, merkleRoot Hash256Digest, intermediateNodes []byte, index uint) bool { + // Shortcut the empty-block case + if bytes.Equal(txid[:], merkleRoot[:]) && index == 0 && len(intermediateNodes) == 0 { + return true + } + + proof := []byte{} + proof = append(proof, txid[:]...) + proof = append(proof, intermediateNodes...) + proof = append(proof, merkleRoot[:]...) + + return VerifyHash256Merkle(proof, index) +} + +// Hash256 implements bitcoin's hash256 (double sha2) +func Hash256(in []byte) Hash256Digest { + first := sha256.Sum256(in) + second := sha256.Sum256(first[:]) + return Hash256Digest(second) +} + +// Hash256MerkleStep concatenates and hashes two inputs for merkle proving +func Hash256MerkleStep(a []byte, b []byte) Hash256Digest { + c := []byte{} + c = append(c, a...) + c = append(c, b...) + return Hash256(c) +} + +// VerifyHash256Merkle checks a merkle inclusion proof's validity. +// Note that `index` is not a reliable indicator of location within a block. +func VerifyHash256Merkle(proof []byte, index uint) bool { + var current Hash256Digest + idx := index + proofLength := len(proof) + + if proofLength%32 != 0 { + return false + } + + if proofLength == 32 { + return true + } + + if proofLength == 64 { + return false + } + + root := proof[proofLength-32:] + + cur := proof[:32:32] + copy(current[:], cur) + + numSteps := (proofLength / 32) - 1 + + for i := 1; i < numSteps; i++ { + start := i * 32 + end := i*32 + 32 + next := proof[start:end:end] + if idx%2 == 1 { + current = Hash256MerkleStep(next, current[:]) + } else { + current = Hash256MerkleStep(current[:], next) + } + idx >>= 1 + } + + return bytes.Equal(current[:], root) +} diff --git a/common/bitcoin/proof.go b/common/bitcoin/proof.go new file mode 100644 index 0000000000..4846b7af32 --- /dev/null +++ b/common/bitcoin/proof.go @@ -0,0 +1,73 @@ +package bitcoin + +import ( + "errors" + + "github.com/btcsuite/btcd/blockchain" + "github.com/btcsuite/btcd/chaincfg/chainhash" + "github.com/btcsuite/btcutil" +) + +const BitcoinBlockHeaderLen = 80 + +// Merkle is a wrapper around "github.com/btcsuite/btcd/blockchain" merkle tree. +// Additionally, it provides a method to generate a merkle proof for a given transaction. +type Merkle struct { + tree []*chainhash.Hash +} + +func NewMerkle(txns []*btcutil.Tx) *Merkle { + return &Merkle{ + tree: blockchain.BuildMerkleTreeStore(txns, false), + } +} + +// BuildMerkleProof builds merkle proof for a given transaction index in block. +func (m *Merkle) BuildMerkleProof(txIndex int) ([]byte, uint, error) { + if len(m.tree) <= 0 { + return nil, 0, errors.New("merkle tree is empty") + } + + // len(m.tree) + 1 must be a power of 2. E.g. 2, 4, 8, 16, 32, 64, 128, 256, ... + N := len(m.tree) + 1 + if N&(N-1) != 0 { + return nil, 0, errors.New("merkle tree is not full") + } + + // Ensure the provided txIndex points to a valid leaf node. + if txIndex >= N/2 || m.tree[txIndex] == nil { + return nil, 0, errors.New("transaction index is invalid") + } + path := make([]byte, 0) + var siblingIndexes uint + + // Find intermediate nodes on the path to the root buttom-up. + nodeIndex := txIndex + nodesOnLevel := N / 2 + for nodesOnLevel > 1 { + var flag uint + var sibling *chainhash.Hash + + if nodeIndex%2 == 1 { + flag = 1 // left sibling + sibling = m.tree[nodeIndex-1] + } else { + flag = 0 // right sibling + if m.tree[nodeIndex+1] == nil { + sibling = m.tree[nodeIndex] // When there is no right sibling, self hash is used. + } else { + sibling = m.tree[nodeIndex+1] + } + } + + // Append the sibling and flag to the proof. + path = append(path, sibling[:]...) + siblingIndexes |= flag << (len(path)/32 - 1) + + // Go up one level to the parent node. + nodeIndex = N - nodesOnLevel + (nodeIndex%nodesOnLevel)/2 + nodesOnLevel /= 2 + } + + return path, siblingIndexes, nil +} diff --git a/common/common.pb.go b/common/common.pb.go index 4277cc8dc6..2f39e69098 100644 --- a/common/common.pb.go +++ b/common/common.pb.go @@ -11,6 +11,7 @@ import ( _ "github.com/cosmos/gogoproto/gogoproto" proto "github.com/gogo/protobuf/proto" + bitcoin "github.com/zeta-chain/zetacore/common/bitcoin" ethereum "github.com/zeta-chain/zetacore/common/ethereum" ) @@ -337,6 +338,7 @@ type HeaderData struct { // Types that are valid to be assigned to Data: // // *HeaderData_EthereumHeader + // *HeaderData_BitcoinHeader Data isHeaderData_Data `protobuf_oneof:"data"` } @@ -382,8 +384,12 @@ type isHeaderData_Data interface { type HeaderData_EthereumHeader struct { EthereumHeader []byte `protobuf:"bytes,1,opt,name=ethereum_header,json=ethereumHeader,proto3,oneof" json:"ethereum_header,omitempty"` } +type HeaderData_BitcoinHeader struct { + BitcoinHeader []byte `protobuf:"bytes,2,opt,name=bitcoin_header,json=bitcoinHeader,proto3,oneof" json:"bitcoin_header,omitempty"` +} func (*HeaderData_EthereumHeader) isHeaderData_Data() {} +func (*HeaderData_BitcoinHeader) isHeaderData_Data() {} func (m *HeaderData) GetData() isHeaderData_Data { if m != nil { @@ -399,10 +405,18 @@ func (m *HeaderData) GetEthereumHeader() []byte { return nil } +func (m *HeaderData) GetBitcoinHeader() []byte { + if x, ok := m.GetData().(*HeaderData_BitcoinHeader); ok { + return x.BitcoinHeader + } + return nil +} + // XXX_OneofWrappers is for the internal use of the proto package. func (*HeaderData) XXX_OneofWrappers() []interface{} { return []interface{}{ (*HeaderData_EthereumHeader)(nil), + (*HeaderData_BitcoinHeader)(nil), } } @@ -410,6 +424,7 @@ type Proof struct { // Types that are valid to be assigned to Proof: // // *Proof_EthereumProof + // *Proof_BitcoinProof Proof isProof_Proof `protobuf_oneof:"proof"` } @@ -455,8 +470,12 @@ type isProof_Proof interface { type Proof_EthereumProof struct { EthereumProof *ethereum.Proof `protobuf:"bytes,1,opt,name=ethereum_proof,json=ethereumProof,proto3,oneof" json:"ethereum_proof,omitempty"` } +type Proof_BitcoinProof struct { + BitcoinProof *bitcoin.Proof `protobuf:"bytes,2,opt,name=bitcoin_proof,json=bitcoinProof,proto3,oneof" json:"bitcoin_proof,omitempty"` +} func (*Proof_EthereumProof) isProof_Proof() {} +func (*Proof_BitcoinProof) isProof_Proof() {} func (m *Proof) GetProof() isProof_Proof { if m != nil { @@ -472,10 +491,18 @@ func (m *Proof) GetEthereumProof() *ethereum.Proof { return nil } +func (m *Proof) GetBitcoinProof() *bitcoin.Proof { + if x, ok := m.GetProof().(*Proof_BitcoinProof); ok { + return x.BitcoinProof + } + return nil +} + // XXX_OneofWrappers is for the internal use of the proto package. func (*Proof) XXX_OneofWrappers() []interface{} { return []interface{}{ (*Proof_EthereumProof)(nil), + (*Proof_BitcoinProof)(nil), } } @@ -493,47 +520,50 @@ func init() { func init() { proto.RegisterFile("common/common.proto", fileDescriptor_8f954d82c0b891f6) } var fileDescriptor_8f954d82c0b891f6 = []byte{ - // 639 bytes of a gzipped FileDescriptorProto - 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x54, 0x94, 0xcb, 0x6a, 0xdb, 0x4c, - 0x14, 0x80, 0x25, 0x5f, 0x64, 0xeb, 0xc8, 0xb1, 0xf5, 0x4f, 0x7e, 0xfe, 0x3f, 0xcd, 0x42, 0x0e, - 0xa6, 0x85, 0x34, 0xd0, 0x5c, 0x5c, 0xdc, 0x0b, 0x5d, 0x04, 0xec, 0x5e, 0xdc, 0x16, 0x4a, 0x90, - 0xb3, 0xca, 0xc6, 0x8c, 0xa4, 0x53, 0x49, 0xc4, 0xd2, 0x08, 0x69, 0x5c, 0x70, 0x9f, 0xa2, 0xaf, - 0x50, 0x28, 0xb4, 0x8f, 0x92, 0x65, 0x96, 0x5d, 0x85, 0xe2, 0xbc, 0x45, 0x57, 0x65, 0x46, 0x17, - 0xa7, 0x2b, 0x9f, 0xf9, 0xce, 0x77, 0x2e, 0xf2, 0xc8, 0x86, 0x6d, 0x97, 0x45, 0x11, 0x8b, 0x8f, - 0xf2, 0x8f, 0xc3, 0x24, 0x65, 0x9c, 0x11, 0x2d, 0x3f, 0xed, 0x5a, 0x45, 0x12, 0x79, 0x80, 0x29, - 0x2e, 0xa3, 0x2a, 0xc8, 0xbd, 0xdd, 0x7f, 0x7d, 0xe6, 0x33, 0x19, 0x1e, 0x89, 0x28, 0xa7, 0x83, - 0x00, 0xf4, 0xb3, 0xa5, 0xf3, 0x1e, 0x57, 0x33, 0xe4, 0x64, 0x04, 0x7a, 0x86, 0x6e, 0x32, 0x1c, - 0x3d, 0xb9, 0x3c, 0xd9, 0x51, 0xf7, 0xd4, 0x7d, 0x7d, 0xfc, 0xff, 0xfa, 0xa6, 0xaf, 0xcf, 0x4a, - 0xf8, 0xfb, 0xa6, 0xaf, 0xe5, 0xba, 0xbd, 0x31, 0xc9, 0x7d, 0x68, 0xa1, 0x37, 0x1c, 0x8d, 0x4e, - 0x9e, 0xef, 0xd4, 0x64, 0x11, 0xdc, 0xf1, 0xca, 0xd4, 0xe0, 0x1c, 0x9a, 0x93, 0x80, 0x86, 0x31, - 0x39, 0x06, 0x70, 0x45, 0x30, 0x8f, 0x69, 0x84, 0x72, 0x4c, 0x77, 0xf8, 0xcf, 0x61, 0xf1, 0x4c, - 0x52, 0xf9, 0x40, 0x23, 0xb4, 0x75, 0xb7, 0x0c, 0xc9, 0x3d, 0x68, 0xe7, 0x15, 0xa1, 0x27, 0x27, - 0xd4, 0xed, 0x96, 0x3c, 0xbf, 0xf5, 0x06, 0xdf, 0x55, 0x30, 0xc6, 0x0b, 0xe6, 0x5e, 0x4e, 0x91, - 0x7a, 0x98, 0x92, 0xff, 0x40, 0x0b, 0x30, 0xf4, 0x03, 0x2e, 0x1b, 0xd7, 0xed, 0xe2, 0x44, 0x08, - 0x34, 0x02, 0x9a, 0x05, 0xb2, 0xbc, 0x63, 0xcb, 0x98, 0xf4, 0xc1, 0x48, 0x68, 0x8a, 0x31, 0x9f, - 0xcb, 0x54, 0x5d, 0xa6, 0x20, 0x47, 0x53, 0x21, 0xdc, 0x9d, 0xdb, 0xf8, 0x6b, 0x2e, 0x39, 0x16, - 0x73, 0xc4, 0xc4, 0x9d, 0xe6, 0x9e, 0xba, 0x6f, 0x0c, 0x49, 0xf9, 0x00, 0xf9, 0x1e, 0x2f, 0x29, - 0xa7, 0xe3, 0xc6, 0xd5, 0x4d, 0x5f, 0xb1, 0x0b, 0x6f, 0x70, 0x0a, 0xb0, 0xc9, 0x91, 0x87, 0xd0, - 0x2b, 0xef, 0x67, 0x5e, 0x34, 0x12, 0x0b, 0x77, 0xa6, 0x8a, 0xdd, 0x2d, 0x13, 0xb9, 0x3e, 0xd6, - 0xa0, 0xe1, 0x51, 0x4e, 0x07, 0xef, 0xa0, 0x79, 0x96, 0x32, 0xf6, 0x91, 0x3c, 0x83, 0x4a, 0x99, - 0x27, 0x82, 0xc8, 0x52, 0x63, 0xd8, 0x3b, 0xac, 0xae, 0x5c, 0x8a, 0x53, 0xc5, 0xde, 0x2a, 0x89, - 0x04, 0xe3, 0x16, 0x34, 0x65, 0xc1, 0xc1, 0x0b, 0xd8, 0xb2, 0xd1, 0xc5, 0xf0, 0x13, 0xce, 0x38, - 0xe5, 0xcb, 0x8c, 0x18, 0xd0, 0x9a, 0xa4, 0x48, 0x39, 0x7a, 0xa6, 0x22, 0x0e, 0xb3, 0xa5, 0xeb, - 0x62, 0x96, 0x99, 0x2a, 0x01, 0xd0, 0x5e, 0xd3, 0x70, 0x81, 0x9e, 0x59, 0xdb, 0x6d, 0xfc, 0xf8, - 0x66, 0xa9, 0x07, 0x4f, 0xa1, 0x3d, 0x61, 0x61, 0x7c, 0xbe, 0x4a, 0x90, 0xb4, 0xa1, 0x71, 0x81, - 0x9c, 0x9a, 0x0a, 0x69, 0x41, 0xfd, 0x0d, 0x15, 0x05, 0x3a, 0x34, 0x5f, 0xd9, 0x93, 0xe1, 0xb1, - 0x59, 0x13, 0x6c, 0x12, 0x79, 0x66, 0xbd, 0x28, 0xfc, 0x5a, 0x03, 0xbd, 0xba, 0x60, 0xe1, 0x61, - 0x94, 0xf0, 0x95, 0xa9, 0x90, 0x1e, 0x18, 0xc8, 0x83, 0x79, 0x44, 0xc3, 0x38, 0x46, 0x6e, 0xaa, - 0xc4, 0x84, 0xce, 0x67, 0xe4, 0xb4, 0x22, 0x35, 0xa1, 0x38, 0xdc, 0xad, 0x40, 0x9d, 0x6c, 0x43, - 0x2f, 0x61, 0x8b, 0x95, 0xcf, 0xe2, 0x0a, 0x36, 0xa4, 0x95, 0x6d, 0xac, 0x26, 0x21, 0xd0, 0xf5, - 0x19, 0xa6, 0x8b, 0x70, 0xce, 0x31, 0xe3, 0x82, 0x69, 0x82, 0x45, 0xcb, 0xc8, 0xa1, 0x1b, 0xd6, - 0x12, 0xdd, 0x7c, 0x1a, 0x53, 0x37, 0xc0, 0x0a, 0xb6, 0x85, 0xe8, 0x50, 0xe6, 0x50, 0xa7, 0x62, - 0x7a, 0x39, 0xa1, 0x04, 0x50, 0xad, 0x5a, 0x12, 0xa3, 0x5c, 0xb5, 0x04, 0x1d, 0xd9, 0x3c, 0x5f, - 0x62, 0xc1, 0x5c, 0xba, 0x10, 0xb0, 0x5b, 0x5a, 0x29, 0xfa, 0x42, 0x34, 0x7b, 0xf9, 0x77, 0x34, - 0x3e, 0xbd, 0x5a, 0x5b, 0xea, 0xf5, 0xda, 0x52, 0x7f, 0xad, 0x2d, 0xf5, 0xcb, 0xad, 0xa5, 0x5c, - 0xdf, 0x5a, 0xca, 0xcf, 0x5b, 0x4b, 0xb9, 0x78, 0xe0, 0x87, 0x3c, 0x58, 0x3a, 0xe2, 0x45, 0x3b, - 0x12, 0x13, 0x1f, 0xc9, 0x77, 0x51, 0x86, 0x2e, 0x4b, 0xb1, 0xf8, 0x57, 0x70, 0x34, 0xf9, 0xc3, - 0x7e, 0xfc, 0x27, 0x00, 0x00, 0xff, 0xff, 0x2e, 0x3c, 0x8a, 0x97, 0x2d, 0x04, 0x00, 0x00, + // 682 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x54, 0x94, 0xcd, 0x6a, 0xdb, 0x4a, + 0x14, 0x80, 0x25, 0xff, 0xeb, 0xd8, 0xb1, 0x75, 0x27, 0x97, 0x7b, 0x73, 0xc3, 0x45, 0x0e, 0xa6, + 0xa5, 0x69, 0xa0, 0x4e, 0xe2, 0xe2, 0xfe, 0xd0, 0x45, 0xc1, 0xee, 0x4f, 0x4a, 0xa1, 0x04, 0x39, + 0xab, 0x6c, 0xcc, 0x48, 0x3a, 0x95, 0x44, 0x2c, 0x8d, 0x91, 0xc7, 0x05, 0x77, 0xd7, 0x37, 0xe8, + 0x2b, 0x14, 0x0a, 0xed, 0xa3, 0x64, 0x99, 0x65, 0x57, 0xa1, 0x38, 0x6f, 0xd1, 0x55, 0x99, 0xd1, + 0x8c, 0x9c, 0xae, 0x74, 0xe6, 0x3b, 0xdf, 0x39, 0x67, 0x46, 0x1a, 0x04, 0xdb, 0x3e, 0x4b, 0x12, + 0x96, 0x1e, 0xe6, 0x8f, 0xfe, 0x3c, 0x63, 0x9c, 0x91, 0x5a, 0xbe, 0xda, 0xfd, 0x5f, 0x25, 0xbd, + 0x98, 0xfb, 0x2c, 0x2e, 0x9e, 0xb9, 0xb5, 0xeb, 0xa8, 0x2c, 0xf2, 0x08, 0x33, 0x5c, 0x26, 0x45, + 0xa0, 0xf2, 0x7f, 0x87, 0x2c, 0x64, 0x32, 0x3c, 0x14, 0x51, 0x4e, 0x7b, 0x11, 0x58, 0xa7, 0x4b, + 0xef, 0x2d, 0xae, 0x26, 0xc8, 0xc9, 0x10, 0xac, 0x05, 0xfa, 0xf3, 0xc1, 0xf0, 0xd1, 0xc5, 0xf1, + 0x8e, 0xb9, 0x67, 0xee, 0x5b, 0xa3, 0x7f, 0xd7, 0xd7, 0x5d, 0x6b, 0xa2, 0xe1, 0xaf, 0xeb, 0x6e, + 0x2d, 0xd7, 0xdd, 0x8d, 0x49, 0xee, 0x40, 0x1d, 0x83, 0xc1, 0x70, 0x78, 0xfc, 0x74, 0xa7, 0x24, + 0x8b, 0xe0, 0x96, 0xa7, 0x53, 0xbd, 0x33, 0xa8, 0x8e, 0x23, 0x1a, 0xa7, 0xe4, 0x08, 0xc0, 0x17, + 0xc1, 0x34, 0xa5, 0x09, 0xca, 0x31, 0xed, 0xc1, 0x5f, 0x7d, 0x75, 0x62, 0xa9, 0xbc, 0xa3, 0x09, + 0xba, 0x96, 0xaf, 0x43, 0xf2, 0x1f, 0x34, 0xf2, 0x8a, 0x38, 0x90, 0x13, 0xca, 0x6e, 0x5d, 0xae, + 0xdf, 0x04, 0xbd, 0x6f, 0x26, 0x34, 0x47, 0x33, 0xe6, 0x5f, 0x9c, 0x20, 0x0d, 0x30, 0x23, 0xff, + 0x40, 0x2d, 0xc2, 0x38, 0x8c, 0xb8, 0x6c, 0x5c, 0x76, 0xd5, 0x8a, 0x10, 0xa8, 0x44, 0x74, 0x11, + 0xc9, 0xf2, 0x96, 0x2b, 0x63, 0xd2, 0x85, 0xe6, 0x9c, 0x66, 0x98, 0xf2, 0xa9, 0x4c, 0x95, 0x65, + 0x0a, 0x72, 0x74, 0x22, 0x84, 0xdb, 0x73, 0x2b, 0x7f, 0xcc, 0x25, 0x47, 0x62, 0x8e, 0x98, 0xb8, + 0x53, 0xdd, 0x33, 0xf7, 0x9b, 0x03, 0xa2, 0x0f, 0x90, 0xef, 0xe3, 0x05, 0xe5, 0x74, 0x54, 0xb9, + 0xbc, 0xee, 0x1a, 0xae, 0xf2, 0x7a, 0x11, 0xc0, 0x26, 0x47, 0xee, 0x43, 0x47, 0x7f, 0x9f, 0xa9, + 0x6a, 0x24, 0x36, 0xdc, 0x3a, 0x31, 0xdc, 0xb6, 0x4e, 0xa8, 0x23, 0xdd, 0x83, 0xb6, 0xfa, 0xd2, + 0xda, 0x2c, 0x29, 0x73, 0x4b, 0xf1, 0x5c, 0x1c, 0xd5, 0xa0, 0x12, 0x50, 0x4e, 0x7b, 0x9f, 0x4c, + 0xa8, 0x9e, 0x66, 0x8c, 0xbd, 0x27, 0x4f, 0xa0, 0x68, 0x36, 0x9d, 0x0b, 0x22, 0x87, 0x34, 0x07, + 0x9d, 0x7e, 0x71, 0x39, 0xa4, 0x28, 0x7a, 0x69, 0x92, 0x57, 0x0e, 0x41, 0x37, 0x57, 0x85, 0x25, + 0x59, 0xd8, 0xee, 0xeb, 0x4b, 0xa7, 0xeb, 0x5a, 0x0a, 0xc8, 0xf5, 0xa8, 0x0e, 0x55, 0xa9, 0x1f, + 0x3c, 0x83, 0x2d, 0x17, 0x7d, 0x8c, 0x3f, 0xe0, 0x84, 0x53, 0xbe, 0x5c, 0x90, 0x26, 0xd4, 0xc7, + 0x19, 0x52, 0x8e, 0x81, 0x6d, 0x88, 0xc5, 0x64, 0xe9, 0xfb, 0xb8, 0x58, 0xd8, 0x26, 0x01, 0xa8, + 0xbd, 0xa2, 0xf1, 0x0c, 0x03, 0xbb, 0xb4, 0x5b, 0xf9, 0xfe, 0xd5, 0x31, 0x0f, 0x1e, 0x43, 0x63, + 0xcc, 0xe2, 0xf4, 0x6c, 0x35, 0x47, 0xd2, 0x80, 0xca, 0x39, 0x72, 0x6a, 0x1b, 0xa4, 0x0e, 0xe5, + 0xd7, 0x54, 0x14, 0x58, 0x50, 0x7d, 0xe9, 0x8e, 0x07, 0x47, 0x76, 0x49, 0xb0, 0x71, 0x12, 0xd8, + 0x65, 0x55, 0xf8, 0xa5, 0x04, 0x56, 0x71, 0x83, 0x84, 0x87, 0xc9, 0x9c, 0xaf, 0x6c, 0x83, 0x74, + 0xa0, 0x89, 0x3c, 0x9a, 0x26, 0x34, 0x4e, 0x53, 0xe4, 0xb6, 0x49, 0x6c, 0x68, 0x7d, 0x44, 0x4e, + 0x0b, 0x52, 0x12, 0x8a, 0xc7, 0xfd, 0x02, 0x94, 0xc9, 0x36, 0x74, 0xe6, 0x6c, 0xb6, 0x0a, 0x59, + 0x5a, 0xc0, 0x8a, 0xb4, 0x16, 0x1b, 0xab, 0x4a, 0x08, 0xb4, 0x43, 0x86, 0xd9, 0x2c, 0x9e, 0x72, + 0x5c, 0x70, 0xc1, 0x6a, 0x82, 0x25, 0xcb, 0xc4, 0xa3, 0x1b, 0x56, 0x17, 0xdd, 0x42, 0x9a, 0x52, + 0x3f, 0xc2, 0x02, 0x36, 0x84, 0xe8, 0x51, 0xe6, 0x51, 0xaf, 0x60, 0x96, 0x9e, 0xa0, 0x01, 0x14, + 0x5b, 0xd5, 0xa4, 0xa9, 0xb7, 0xaa, 0x41, 0x4b, 0x36, 0xcf, 0x37, 0x31, 0x63, 0x3e, 0x9d, 0x09, + 0xd8, 0xd6, 0x56, 0x86, 0xa1, 0x10, 0xed, 0x4e, 0xfe, 0x8e, 0x46, 0xcf, 0x2f, 0xd7, 0x8e, 0x79, + 0xb5, 0x76, 0xcc, 0x9f, 0x6b, 0xc7, 0xfc, 0x7c, 0xe3, 0x18, 0x57, 0x37, 0x8e, 0xf1, 0xe3, 0xc6, + 0x31, 0xce, 0xef, 0x86, 0x31, 0x8f, 0x96, 0x9e, 0xb8, 0xc9, 0x87, 0x62, 0xe2, 0x03, 0x79, 0xd9, + 0x65, 0xe8, 0xb3, 0x0c, 0xd5, 0x4f, 0xc9, 0xab, 0xc9, 0x3f, 0xc7, 0xc3, 0xdf, 0x01, 0x00, 0x00, + 0xff, 0xff, 0x61, 0x31, 0x96, 0x1f, 0xac, 0x04, 0x00, 0x00, } func (m *PubKeySet) Marshal() (dAtA []byte, err error) { @@ -711,6 +741,22 @@ func (m *HeaderData_EthereumHeader) MarshalToSizedBuffer(dAtA []byte) (int, erro } return len(dAtA) - i, nil } +func (m *HeaderData_BitcoinHeader) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *HeaderData_BitcoinHeader) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + if m.BitcoinHeader != nil { + i -= len(m.BitcoinHeader) + copy(dAtA[i:], m.BitcoinHeader) + i = encodeVarintCommon(dAtA, i, uint64(len(m.BitcoinHeader))) + i-- + dAtA[i] = 0x12 + } + return len(dAtA) - i, nil +} func (m *Proof) Marshal() (dAtA []byte, err error) { size := m.Size() dAtA = make([]byte, size) @@ -764,6 +810,27 @@ func (m *Proof_EthereumProof) MarshalToSizedBuffer(dAtA []byte) (int, error) { } return len(dAtA) - i, nil } +func (m *Proof_BitcoinProof) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *Proof_BitcoinProof) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + if m.BitcoinProof != nil { + { + size, err := m.BitcoinProof.MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarintCommon(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0x12 + } + return len(dAtA) - i, nil +} func encodeVarintCommon(dAtA []byte, offset int, v uint64) int { offset -= sovCommon(v) base := offset @@ -856,6 +923,18 @@ func (m *HeaderData_EthereumHeader) Size() (n int) { } return n } +func (m *HeaderData_BitcoinHeader) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + if m.BitcoinHeader != nil { + l = len(m.BitcoinHeader) + n += 1 + l + sovCommon(uint64(l)) + } + return n +} func (m *Proof) Size() (n int) { if m == nil { return 0 @@ -880,6 +959,18 @@ func (m *Proof_EthereumProof) Size() (n int) { } return n } +func (m *Proof_BitcoinProof) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + if m.BitcoinProof != nil { + l = m.BitcoinProof.Size() + n += 1 + l + sovCommon(uint64(l)) + } + return n +} func sovCommon(x uint64) (n int) { return (math_bits.Len64(x|1) + 6) / 7 @@ -1340,6 +1431,39 @@ func (m *HeaderData) Unmarshal(dAtA []byte) error { copy(v, dAtA[iNdEx:postIndex]) m.Data = &HeaderData_EthereumHeader{v} iNdEx = postIndex + case 2: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field BitcoinHeader", wireType) + } + var byteLen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowCommon + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + byteLen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if byteLen < 0 { + return ErrInvalidLengthCommon + } + postIndex := iNdEx + byteLen + if postIndex < 0 { + return ErrInvalidLengthCommon + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + v := make([]byte, postIndex-iNdEx) + copy(v, dAtA[iNdEx:postIndex]) + m.Data = &HeaderData_BitcoinHeader{v} + iNdEx = postIndex default: iNdEx = preIndex skippy, err := skipCommon(dAtA[iNdEx:]) @@ -1425,6 +1549,41 @@ func (m *Proof) Unmarshal(dAtA []byte) error { } m.Proof = &Proof_EthereumProof{v} iNdEx = postIndex + case 2: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field BitcoinProof", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowCommon + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return ErrInvalidLengthCommon + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return ErrInvalidLengthCommon + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + v := &bitcoin.Proof{} + if err := v.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + m.Proof = &Proof_BitcoinProof{v} + iNdEx = postIndex default: iNdEx = preIndex skippy, err := skipCommon(dAtA[iNdEx:]) diff --git a/common/default_chains_mainnet.go b/common/default_chains_mainnet.go index 18868b5a13..e870103232 100644 --- a/common/default_chains_mainnet.go +++ b/common/default_chains_mainnet.go @@ -31,6 +31,10 @@ func BtcMainnetChain() Chain { } } +func BtcChainID() int64 { + return BtcMainnetChain().ChainId +} + func PolygonChain() Chain { return Chain{ ChainName: ChainName_polygon_mainnet, diff --git a/common/default_chains_mock_mainnet.go b/common/default_chains_mock_mainnet.go index 6498ed087e..0b131f432a 100644 --- a/common/default_chains_mock_mainnet.go +++ b/common/default_chains_mock_mainnet.go @@ -31,6 +31,10 @@ func BtcMainnetChain() Chain { } } +func BtcChainID() int64 { + return BtcMainnetChain().ChainId +} + func PolygonChain() Chain { return Chain{ ChainName: ChainName_polygon_mainnet, diff --git a/common/default_chains_privnet.go b/common/default_chains_privnet.go index f415cc0af7..e6a0bb80a1 100644 --- a/common/default_chains_privnet.go +++ b/common/default_chains_privnet.go @@ -24,6 +24,10 @@ func BtcRegtestChain() Chain { } } +func BtcChainID() int64 { + return BtcRegtestChain().ChainId +} + func DefaultChainsList() []*Chain { chains := []Chain{ BtcRegtestChain(), diff --git a/common/default_chains_testnet.go b/common/default_chains_testnet.go index 74473464ca..8220d53ac5 100644 --- a/common/default_chains_testnet.go +++ b/common/default_chains_testnet.go @@ -31,6 +31,10 @@ func BtcTestNetChain() Chain { } } +func BtcChainID() int64 { + return BtcTestNetChain().ChainId +} + func MumbaiChain() Chain { return Chain{ ChainName: ChainName_mumbai_testnet, diff --git a/common/headers.go b/common/headers.go index e05a3f0c18..f230367001 100644 --- a/common/headers.go +++ b/common/headers.go @@ -5,9 +5,15 @@ import ( "encoding/hex" "errors" "fmt" + "time" + "github.com/btcsuite/btcd/blockchain" + "github.com/btcsuite/btcd/chaincfg/chainhash" + "github.com/btcsuite/btcd/wire" + "github.com/btcsuite/btcutil" ethtypes "github.com/ethereum/go-ethereum/core/types" "github.com/ethereum/go-ethereum/rlp" + "github.com/zeta-chain/zetacore/common/bitcoin" ) // NewEthereumHeader returns a new HeaderData containing an Ethereum header @@ -19,6 +25,15 @@ func NewEthereumHeader(header []byte) HeaderData { } } +// NewBitcoinHeader returns a new HeaderData containing a Bitcoin header +func NewBitcoinHeader(header []byte) HeaderData { + return HeaderData{ + Data: &HeaderData_BitcoinHeader{ + BitcoinHeader: header, + }, + } +} + // ParentHash extracts the parent hash from the header func (h HeaderData) ParentHash() ([]byte, error) { switch data := h.Data.(type) { @@ -28,16 +43,56 @@ func (h HeaderData) ParentHash() ([]byte, error) { return nil, err } return header.ParentHash.Bytes(), nil + case *HeaderData_BitcoinHeader: + var header wire.BlockHeader + if err := header.Deserialize(bytes.NewReader(data.BitcoinHeader)); err != nil { + return nil, err + } + return header.PrevBlock[:], nil default: return nil, errors.New("unrecognized header type") } } +func (h HeaderData) ValidateTimestamp(zetaTime time.Time) error { + switch data := h.Data.(type) { + case *HeaderData_EthereumHeader: + // No timestamp validation for Ethereum for now + return nil + case *HeaderData_BitcoinHeader: + var header wire.BlockHeader + if err := header.Deserialize(bytes.NewReader(data.BitcoinHeader)); err != nil { + return err + } + // Below checks are borrowed from btcd/blockchain/validate.go because they are not exported + // + // A block timestamp must not have a greater precision than one second. + // This check is necessary because Go time.Time values support + // nanosecond precision whereas the consensus rules only apply to + // seconds and it's much nicer to deal with standard Go time values + // instead of converting to seconds everywhere. + if !header.Timestamp.Equal(time.Unix(header.Timestamp.Unix(), 0)) { + return fmt.Errorf("block timestamp of %v has a higher precision than one second", header.Timestamp) + } + + // Ensure the block time is not too far in the future. + maxTimestamp := zetaTime.Add(time.Second * blockchain.MaxTimeOffsetSeconds) + if header.Timestamp.After(maxTimestamp) { + return fmt.Errorf("block timestamp of %v is too far in the future", header.Timestamp) + } + return nil + default: + return errors.New("cannot validate timestamp for unrecognized header type") + } +} + // Validate performs a basic validation of the HeaderData -func (h HeaderData) Validate(blockHash []byte, height int64) error { +func (h HeaderData) Validate(blockHash []byte, chainID int64, height int64) error { switch data := h.Data.(type) { case *HeaderData_EthereumHeader: return validateEthereumHeader(data.EthereumHeader, blockHash, height) + case *HeaderData_BitcoinHeader: + return ValidateBitcoinHeader(data.BitcoinHeader, blockHash, chainID) default: return errors.New("unrecognized header type") } @@ -58,11 +113,55 @@ func validateEthereumHeader(headerBytes []byte, blockHash []byte, height int64) if err := header.SanityCheck(); err != nil { return fmt.Errorf("sanity check failed (%s)", err) } - if bytes.Compare(blockHash, header.Hash().Bytes()) != 0 { - return fmt.Errorf("tx hash mismatch (%s) vs (%s)", hex.EncodeToString(blockHash), header.Hash().Hex()) + if !bytes.Equal(blockHash, header.Hash().Bytes()) { + return fmt.Errorf("block hash mismatch (%s) vs (%s)", hex.EncodeToString(blockHash), header.Hash().Hex()) } if height != header.Number.Int64() { return fmt.Errorf("height mismatch (%d) vs (%d)", height, header.Number.Int64()) } return nil } + +func ValidateBitcoinHeader(headerBytes []byte, blockHash []byte, chainID int64) error { + // Deserialize the 80-byte block header + if len(headerBytes) != bitcoin.BitcoinBlockHeaderLen { + return fmt.Errorf("header length mismatch (%d)", len(headerBytes)) + } + var header wire.BlockHeader + if err := header.Deserialize(bytes.NewReader(headerBytes)); err != nil { + return fmt.Errorf("cannot deserialize Bitcoin header (%s)", err) + } + + // Ensure the block hash matches the header + digest, err := chainhash.NewHash(blockHash) + if err != nil { + return fmt.Errorf("block hash conversion failed (%s)", err) + } + headerDigest := header.BlockHash() + if !bytes.Equal(digest[:], headerDigest[:]) { + return fmt.Errorf("block hash mismatch (%s) vs (%s)", digest, headerDigest) + } + + // There is no strict rules on block version + if header.Version <= 0 { + return fmt.Errorf("invalid version (%d)", header.Version) + } + + // Timestamp must be not earlier than genesis block + chainParams, err := GetBTCChainParams(chainID) + if err != nil { + return fmt.Errorf("cannot get chain params (%s) for chain id (%d)", err, chainID) + } + if chainParams.GenesisBlock.Header.Timestamp.After(header.Timestamp) { + return fmt.Errorf("block timestamp %v is before genesis block", header.Timestamp) + } + + // Verify the proof-of-work + liteBlock := btcutil.NewBlock(&wire.MsgBlock{Header: header}) + err = blockchain.CheckProofOfWork(liteBlock, chainParams.PowLimit) + if err != nil { + return fmt.Errorf("proof-of-work verification failed (%s)", err) + } + + return nil +} diff --git a/common/headers_test.go b/common/headers_test.go new file mode 100644 index 0000000000..96d058cf71 --- /dev/null +++ b/common/headers_test.go @@ -0,0 +1,187 @@ +package common_test + +import ( + "bytes" + "encoding/base64" + "fmt" + "log" + "testing" + "time" + + "github.com/btcsuite/btcd/blockchain" + "github.com/btcsuite/btcd/chaincfg" + "github.com/btcsuite/btcd/chaincfg/chainhash" + "github.com/btcsuite/btcd/rpcclient" + "github.com/btcsuite/btcd/wire" + "github.com/stretchr/testify/require" + "github.com/zeta-chain/zetacore/common" +) + +const numHeadersToTest = 100 + +func TestTrueBitcoinHeader(t *testing.T) { + blocks := LoadTestBlocks(t) + + for _, b := range blocks.Blocks { + // Deserialize the header bytes from base64 + headerBytes, err := base64.StdEncoding.DecodeString(b.HeaderBase64) + require.NoError(t, err) + header := unmarshalHeader(headerBytes) + + // Validate + validateTrueBitcoinHeader(t, header, headerBytes) + } +} + +func TestFakeBitcoinHeader(t *testing.T) { + blocks := LoadTestBlocks(t) + + for _, b := range blocks.Blocks { + // Deserialize the header bytes from base64 + headerBytes, err := base64.StdEncoding.DecodeString(b.HeaderBase64) + require.NoError(t, err) + header := unmarshalHeader(headerBytes) + + // Validate + validateFakeBitcoinHeader(t, header, headerBytes) + } +} + +func BitcoinHeaderValidationLiveTest(t *testing.T) { + client := createBTCClient(t) + bn, err := client.GetBlockCount() + require.NoError(t, err) + fmt.Printf("Verifying block headers in block range [%d, %d]\n", bn-numHeadersToTest+1, bn) + + for height := bn - numHeadersToTest + 1; height <= bn; height++ { + blockHash, err := client.GetBlockHash(height) + require.NoError(t, err) + + // Get the block header + header, err := client.GetBlockHeader(blockHash) + require.NoError(t, err) + headerBytes := marshalHeader(header) + + // Validate true header + validateTrueBitcoinHeader(t, header, headerBytes) + + // Validate fake header + validateFakeBitcoinHeader(t, header, headerBytes) + + fmt.Printf("Block header verified for block: %d hash: %s\n", height, blockHash) + } +} + +func createBTCClient(t *testing.T) *rpcclient.Client { + connCfg := &rpcclient.ConnConfig{ + Host: "127.0.0.1:18332", + User: "user", + Pass: "pass", + HTTPPostMode: true, + DisableTLS: true, + Params: "testnet3", + } + client, err := rpcclient.New(connCfg, nil) + require.NoError(t, err) + return client +} + +func copyHeader(header *wire.BlockHeader) *wire.BlockHeader { + copyHeader := &wire.BlockHeader{ + Version: header.Version, + PrevBlock: chainhash.Hash{}, + MerkleRoot: chainhash.Hash{}, + Timestamp: header.Timestamp, + Bits: header.Bits, + Nonce: header.Nonce, + } + copy(copyHeader.PrevBlock[:], header.PrevBlock[:]) + copy(copyHeader.MerkleRoot[:], header.MerkleRoot[:]) + + return copyHeader +} + +func marshalHeader(header *wire.BlockHeader) []byte { + var headerBuf bytes.Buffer + err := header.Serialize(&headerBuf) + if err != nil { + log.Fatal(err) + } + return headerBuf.Bytes() +} + +func unmarshalHeader(headerBytes []byte) *wire.BlockHeader { + var header wire.BlockHeader + err := header.Deserialize(bytes.NewReader(headerBytes)) + if err != nil { + log.Fatal(err) + } + return &header +} + +func validateTrueBitcoinHeader(t *testing.T, header *wire.BlockHeader, headerBytes []byte) { + blockHash := header.BlockHash() + + // Ture Bitcoin header should pass validation + err := common.ValidateBitcoinHeader(headerBytes, blockHash[:], 18332) + require.NoError(t, err) + + // True Bitcoin header should pass timestamp validation + err = common.NewBitcoinHeader(headerBytes).ValidateTimestamp(time.Now()) + require.NoError(t, err) +} + +func validateFakeBitcoinHeader(t *testing.T, header *wire.BlockHeader, headerBytes []byte) { + blockHash := header.BlockHash() + + // Incorrect header length should fail validation + err := common.ValidateBitcoinHeader(headerBytes[:79], blockHash[:], 18332) + if err == nil { + t.Error("Incorrect header length should fail validation") + } + + // Incorrect version should fail validation + fakeHeader := copyHeader(header) + fakeHeader.Version = 0 + fakeBytes := marshalHeader(fakeHeader) + fakeHash := fakeHeader.BlockHash() + err = common.ValidateBitcoinHeader(fakeBytes, fakeHash[:], 18332) + if err == nil { + t.Error("Incorrect version should fail validation") + } + + // Incorrect timestamp should fail validation + // Case1: timestamp is before genesis block + fakeHeader = copyHeader(header) + fakeHeader.Timestamp = chaincfg.TestNet3Params.GenesisBlock.Header.Timestamp.Add(-time.Second) + fakeBytes = marshalHeader(fakeHeader) + fakeHash = fakeHeader.BlockHash() + err = common.ValidateBitcoinHeader(fakeBytes, fakeHash[:], 18332) + if err == nil { + t.Error("Timestamp before genesis should fail validation") + } + // Case2: timestamp is after 2 hours in the future + fakeHeader = copyHeader(header) + fakeHeader.Timestamp = header.Timestamp.Add(time.Second * (blockchain.MaxTimeOffsetSeconds + 1)) + fakeBytes = marshalHeader(fakeHeader) + err = common.NewBitcoinHeader(fakeBytes).ValidateTimestamp(header.Timestamp) + if err == nil { + t.Error("Timestamp in future should fail validation") + } + + // Incorrect block hash should fail validation + fakeHeader = copyHeader(header) + header.Nonce = 0 + fakeBytes = marshalHeader(header) + err = common.ValidateBitcoinHeader(fakeBytes, blockHash[:], 18332) + if err == nil { + t.Error("Incorrect block hash should fail validation") + } + + // PoW not satisfied should fail validation + fakeHash = fakeHeader.BlockHash() + err = common.ValidateBitcoinHeader(fakeBytes, fakeHash[:], 18332) + if err == nil { + t.Error("PoW not satisfied should fail validation") + } +} diff --git a/common/proof.go b/common/proof.go index 615c39b1f5..668b1024a8 100644 --- a/common/proof.go +++ b/common/proof.go @@ -1,10 +1,14 @@ package common import ( + "bytes" "errors" + "github.com/btcsuite/btcd/wire" + "github.com/btcsuite/btcutil" ethtypes "github.com/ethereum/go-ethereum/core/types" "github.com/ethereum/go-ethereum/rlp" + bitcoin "github.com/zeta-chain/zetacore/common/bitcoin" "github.com/zeta-chain/zetacore/common/ethereum" ) @@ -37,7 +41,22 @@ func NewEthereumProof(proof *ethereum.Proof) *Proof { } } +// NewBitcoinProof returns a new Proof containing a Bitcoin proof +func NewBitcoinProof(txBytes []byte, path []byte, index uint) *Proof { + return &Proof{ + Proof: &Proof_BitcoinProof{ + BitcoinProof: &bitcoin.Proof{ + TxBytes: txBytes, + Path: path, + // #nosec G701 always in range + Index: uint32(index), + }, + }, + } +} + // Verify verifies the proof against the header +// Returns the verified tx in bytes if the verification is successful func (p Proof) Verify(headerData HeaderData, txIndex int) ([]byte, error) { switch proof := p.Proof.(type) { case *Proof_EthereumProof: @@ -55,6 +74,24 @@ func (p Proof) Verify(headerData HeaderData, txIndex int) ([]byte, error) { return nil, NewErrInvalidProof(err) } return val, nil + case *Proof_BitcoinProof: + btcHeaderBytes := headerData.GetBitcoinHeader() + if len(btcHeaderBytes) != bitcoin.BitcoinBlockHeaderLen { + return nil, errors.New("can't verify bitcoin proof against non-bitcoin header") + } + var btcHeader wire.BlockHeader + if err := btcHeader.Deserialize(bytes.NewReader(btcHeaderBytes)); err != nil { + return nil, err + } + tx, err := btcutil.NewTxFromBytes(proof.BitcoinProof.TxBytes) + if err != nil { + return nil, err + } + pass := bitcoin.Prove(*tx.Hash(), btcHeader.MerkleRoot, proof.BitcoinProof.Path, uint(proof.BitcoinProof.Index)) + if !pass { + return nil, NewErrInvalidProof(errors.New("invalid bitcoin proof")) + } + return proof.BitcoinProof.TxBytes, nil default: return nil, errors.New("unrecognized proof type") } diff --git a/common/proof_test.go b/common/proof_test.go index 0615407684..6e6fd0a588 100644 --- a/common/proof_test.go +++ b/common/proof_test.go @@ -2,14 +2,163 @@ package common_test import ( "errors" + "os" "testing" + "bytes" + "encoding/base64" + "encoding/hex" + "encoding/json" + "fmt" + "log" + "github.com/stretchr/testify/require" "github.com/zeta-chain/zetacore/common" + "github.com/zeta-chain/zetacore/common/bitcoin" + "github.com/zeta-chain/zetacore/x/crosschain/keeper" + crosschaintypes "github.com/zeta-chain/zetacore/x/crosschain/types" + + "github.com/btcsuite/btcd/blockchain" + "github.com/btcsuite/btcd/btcjson" + "github.com/btcsuite/btcd/wire" + "github.com/btcsuite/btcutil" ) +const numBlocksToTest = 100 + +type Block struct { + TssAddress string `json:"tssAddress"` + Height int `json:"height"` + Nonce uint64 `json:"nonce"` + OutTxid string `json:"outTxid"` + HeaderBase64 string `json:"headerBase64"` + BlockBase64 string `json:"blockBase64"` +} + +type Blocks struct { + Blocks []Block `json:"blocks"` +} + +func LoadTestBlocks(t *testing.T) Blocks { + file, err := os.Open("./test_data/test_blocks.json") + require.NoError(t, err) + defer file.Close() + + // Decode the JSON into the data struct + var blocks Blocks + err = json.NewDecoder(file).Decode(&blocks) + require.NoError(t, err) + + return blocks +} + func Test_IsErrorInvalidProof(t *testing.T) { require.False(t, common.IsErrorInvalidProof(nil)) require.False(t, common.IsErrorInvalidProof(errors.New("foo"))) require.True(t, common.IsErrorInvalidProof(common.NewErrInvalidProof(errors.New("foo")))) } + +func TestBitcoinMerkleProof(t *testing.T) { + blocks := LoadTestBlocks(t) + + for _, b := range blocks.Blocks { + // Deserialize the header bytes from base64 + headerBytes, err := base64.StdEncoding.DecodeString(b.HeaderBase64) + require.NoError(t, err) + header := unmarshalHeader(headerBytes) + + // Deserialize the block bytes from base64 + blockBytes, err := base64.StdEncoding.DecodeString(b.BlockBase64) + require.NoError(t, err) + blockVerbose := &btcjson.GetBlockVerboseTxResult{} + err = json.Unmarshal(blockBytes, blockVerbose) + require.NoError(t, err) + + // Validate block + validateBitcoinBlock(t, header, headerBytes, blockVerbose, b.OutTxid, b.TssAddress, b.Nonce) + } +} + +func BitcoinMerkleProofLiveTest(t *testing.T) { + client := createBTCClient(t) + bn, err := client.GetBlockCount() + require.NoError(t, err) + fmt.Printf("Verifying transactions in block range [%d, %d]\n", bn-numBlocksToTest+1, bn) + + // Verify all transactions in the past 'numBlocksToTest' blocks + for height := bn - numBlocksToTest + 1; height <= bn; height++ { + blockHash, err := client.GetBlockHash(height) + require.NoError(t, err) + + // Get the block header + header, err := client.GetBlockHeader(blockHash) + require.NoError(t, err) + headerBytes := marshalHeader(header) + target := blockchain.CompactToBig(header.Bits) + + // Get the block with verbose transactions + blockVerbose, err := client.GetBlockVerboseTx(blockHash) + require.NoError(t, err) + + // Validate block + validateBitcoinBlock(t, header, headerBytes, blockVerbose, "", "", 0) + + fmt.Printf("Verification succeeded for block: %d hash: %s root: %s target: %064x transactions: %d\n", height, blockHash, header.MerkleRoot, target, len(blockVerbose.Tx)) + } +} + +func validateBitcoinBlock(t *testing.T, header *wire.BlockHeader, headerBytes []byte, blockVerbose *btcjson.GetBlockVerboseTxResult, outTxid string, tssAddress string, nonce uint64) { + // Deserialization should work for each transaction in the block + txns := []*btcutil.Tx{} + txBodies := [][]byte{} + for _, res := range blockVerbose.Tx { + txBytes, err := hex.DecodeString(res.Hex) + if err != nil { + log.Fatalf("error decoding transaction hex: %v", err) + } + tx, err := btcutil.NewTxFromBytes(txBytes) + if err != nil { + log.Fatalf("error deserializing transaction: %v", err) + } + + // Validate Tss SegWit transaction if it's an outTx + if res.Txid == outTxid { + msg := &crosschaintypes.MsgAddToOutTxTracker{ + ChainId: common.BtcChainID(), + Nonce: nonce, + TxHash: outTxid, + } + err = keeper.ValidateBTCOutTxBody(msg, txBytes, tssAddress) + require.NoError(t, err) + } + txns = append(txns, tx) + txBodies = append(txBodies, txBytes) + } + + // Build a Merkle tree from the transaction hashes and verify each transaction + mk := bitcoin.NewMerkle(txns) + for i := range txns { + path, index, err := mk.BuildMerkleProof(i) + if err != nil { + log.Fatalf("Error building merkle proof: %v", err) + } + + // True proof should verify + proof := common.NewBitcoinProof(txBodies[i], path, index) + txBytes, err := proof.Verify(common.NewBitcoinHeader(headerBytes), 0) + if err != nil { + log.Fatal("Merkle proof verification failed") + } + if !bytes.Equal(txBytes, txBodies[i]) { + log.Fatalf("Transaction body mismatch") + } + + // Fake proof should not verify + fakeIndex := index ^ 0xffffffff // flip all bits + fakeProof := common.NewBitcoinProof(txBodies[i], path, fakeIndex) + txBytes, err = fakeProof.Verify(common.NewBitcoinHeader(headerBytes), 0) + if err == nil || txBytes != nil { + log.Fatalf("Merkle proof should not verify") + } + } +} diff --git a/common/test_data/test_blocks.json b/common/test_data/test_blocks.json new file mode 100644 index 0000000000..463ed4834e --- /dev/null +++ b/common/test_data/test_blocks.json @@ -0,0 +1,12 @@ +{ + "blocks": [ + { + "tssAddress": "tb1qy9pqmk2pd9sv63g27jt8r657wy0d9ueeh0nqur", + "height": 2505490, + "nonce": 241, + "outTxid": "e315a7e7de79827d9f90573e342ace1472b8e9eb9e54ecaefc680f9f677d6272", + "headerBase64": "AAAAIAYZ9ALh8NIkrjKNtNzCET+eY4cTcAE6ay0AAAAAAAAAxF+QvUWiF7f6X+1+AAu9PYb/CiWlQ45rwf4Z3VxSlMP6xRRl//8AHR7QlTk=", + "blockBase64": "eyJoYXNoIjoiMDAwMDAwMDAwMTNmODcxNjFmZWRmMmM4Mzk4NjRjNjgwYmYwOTdmNmIxYzJjOGU1ZTgxM2FmYmZlNzQzZDQwZCIsImNvbmZpcm1hdGlvbnMiOjIwOCwic3RyaXBwZWRzaXplIjoyMzEyOSwic2l6ZSI6NDY0MzEsIndlaWdodCI6MTE1ODE4LCJoZWlnaHQiOjI1MDU0OTAsInZlcnNpb24iOjUzNjg3MDkxMiwidmVyc2lvbkhleCI6IjIwMDAwMDAwIiwibWVya2xlcm9vdCI6ImMzOTQ1MjVjZGQxOWZlYzE2YjhlNDNhNTI1MGFmZjg2M2RiZDBiMDA3ZWVkNWZmYWI3MTdhMjQ1YmQ5MDVmYzQiLCJ0eCI6W3siaGV4IjoiMDEwMDAwMDAwMDAxMDEwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwZmZmZmZmZmYzMTAzMTIzYjI2MDBmZWVjNjIwNDAwZmVkZTk2MGMwMDA5NjM2NzZkNjk2ZTY1NzIzNDMyMDg5NzAwMDAwMDAwMDAwMDAwMGQyMDczNmY2YzZmMjA2ZjZlMjA1MjM5MzAzOTAwZmZmZmZmZmYwMmQ5ODAyYjAwMDAwMDAwMDAxOTc2YTkxNGQ3NjNiOWNjOTVmODk2YmI2YTU5NTg3MTU0NDM1MjY2OWU3YWEzODg4OGFjMDAwMDAwMDAwMDAwMDAwMDI2NmEyNGFhMjFhOWVkZjdiNzJlNGE2NjQ2NGM0YWJlMTljNWI5N2JjZmMxZDBlZjdmMzExZTlhOGEzZDM1YzJlYWY2ODczNTE1NGViNDAxMjAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAiLCJ0eGlkIjoiZDY4NjdjYjkzMjU1MjUxYWY5ZmNkYWQ2ZDQ0NGY2ZTc0MTNjYmE1MTg3ZjQ2MTBhNTMxZDc5NDc3NjczNDkwYSIsImhhc2giOiIxNGZiOGFmNGJkYjBlM2YwOTVkOGE0ZDcxMDU2MTkwZjExZjFkNDVjMmFlMjBjNmRjMzUzNWFiMWIwNmI2ZTJkIiwic2l6ZSI6MjE3LCJ2c2l6ZSI6MTkwLCJ3ZWlnaHQiOjc2MCwidmVyc2lvbiI6MSwibG9ja3RpbWUiOjAsInZpbiI6W3siY29pbmJhc2UiOiIwMzEyM2IyNjAwZmVlYzYyMDQwMGZlZGU5NjBjMDAwOTYzNjc2ZDY5NmU2NTcyMzQzMjA4OTcwMDAwMDAwMDAwMDAwMDBkMjA3MzZmNmM2ZjIwNmY2ZTIwNTIzOTMwMzkwMCIsInNlcXVlbmNlIjo0Mjk0OTY3Mjk1LCJ3aXRuZXNzIjpbIjAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAiXX1dLCJ2b3V0IjpbeyJ2YWx1ZSI6MC4wMjg1MTAzMywibiI6MCwic2NyaXB0UHViS2V5Ijp7ImFzbSI6Ik9QX0RVUCBPUF9IQVNIMTYwIGQ3NjNiOWNjOTVmODk2YmI2YTU5NTg3MTU0NDM1MjY2OWU3YWEzODggT1BfRVFVQUxWRVJJRlkgT1BfQ0hFQ0tTSUciLCJoZXgiOiI3NmE5MTRkNzYzYjljYzk1Zjg5NmJiNmE1OTU4NzE1NDQzNTI2NjllN2FhMzg4ODhhYyIsInR5cGUiOiJwdWJrZXloYXNoIn19LHsidmFsdWUiOjAsIm4iOjEsInNjcmlwdFB1YktleSI6eyJhc20iOiJPUF9SRVRVUk4gYWEyMWE5ZWRmN2I3MmU0YTY2NDY0YzRhYmUxOWM1Yjk3YmNmYzFkMGVmN2YzMTFlOWE4YTNkMzVjMmVhZjY4NzM1MTU0ZWI0IiwiaGV4IjoiNmEyNGFhMjFhOWVkZjdiNzJlNGE2NjQ2NGM0YWJlMTljNWI5N2JjZmMxZDBlZjdmMzExZTlhOGEzZDM1YzJlYWY2ODczNTE1NGViNCIsInR5cGUiOiJudWxsZGF0YSJ9fV19LHsiaGV4IjoiMDIwMDAwMDAwMDAxMDE5MWU0MWZlN2FkZmQyYTM2NzQ3MDAwMTA3MjNlMTdkOGJlOTIxODIxMDZjYjQzNTA1ODkwZTNkZjA3NTgxYzgxMDAwMDAwMDAwMGZlZmZmZmZmMDI1MjExMTQwMDAwMDAwMDAwMTYwMDE0ODVjODlhNTk4MjA0MDZiNmNjN2NmZDQ4Y2Q4ZjIxNGExMGMxMzhiMGRkNGEwMDAwMDAwMDAwMDAxN2E5MTRjMDU3N2RkOWZjYmEyNmI5Y2M2NmNlZWE0ZjFhZDRhNWIxYzBjMzhkODcwMjQ3MzA0NDAyMjAwYjVlOGI0NTZmNzI2NjU2ZDI3NjdmMTgyY2QyZTgwMzJmZGY4NGZjNTliOGQ3OWI5YTJjYmRkNzdmNDEzOTMyMDIyMDM3ZTFkYmYxY2ZmMTNjYTUxY2Y4MTA1ODVlMzk0NTZlYzVjMTFjMWEyOTM4OGFiNGY4MTkyMzI0YmZiMjMxN2MwMTIxMDM5Y2M2NGQ0NTc2N2FiOGU1ZjQxNDc0OGE1MmZmYTc3NTgyMjIxMTZhZTE5ODY2MWM1NTU3ZGI5NDM5N2I5ZGViMTEzYjI2MDAiLCJ0eGlkIjoiYzFhZGE2NTA2NmY2ZDhiZTNlYWQwYjMzMTA5YWFkM2EwNjAwMmM4Y2U2ZThkOWM1NzRiNjkyYTViMzRiZDI5ZiIsImhhc2giOiI4NmU4YTkwY2ZiZmM3ZmRmNzQxN2IzN2RiNGJlYjk5OTM2MTJmNDJiOGRmZTI3YmMyMDhjOWYwMWFhYWMzMjE3Iiwic2l6ZSI6MjIzLCJ2c2l6ZSI6MTQyLCJ3ZWlnaHQiOjU2NSwidmVyc2lvbiI6MiwibG9ja3RpbWUiOjI1MDU0ODksInZpbiI6W3sidHhpZCI6IjgxMWM1ODA3ZGZlMzkwNTg1MDQzY2IwNjIxMTg5MmJlZDgxNzNlNzIxMDAwNzA3NDM2MmFmZGFkZTcxZmU0OTEiLCJ2b3V0IjowLCJzY3JpcHRTaWciOnsiYXNtIjoiIiwiaGV4IjoiIn0sInR4aW53aXRuZXNzIjpbIjMwNDQwMjIwMGI1ZThiNDU2ZjcyNjY1NmQyNzY3ZjE4MmNkMmU4MDMyZmRmODRmYzU5YjhkNzliOWEyY2JkZDc3ZjQxMzkzMjAyMjAzN2UxZGJmMWNmZjEzY2E1MWNmODEwNTg1ZTM5NDU2ZWM1YzExYzFhMjkzODhhYjRmODE5MjMyNGJmYjIzMTdjMDEiLCIwMzljYzY0ZDQ1NzY3YWI4ZTVmNDE0NzQ4YTUyZmZhNzc1ODIyMjExNmFlMTk4NjYxYzU1NTdkYjk0Mzk3YjlkZWIiXSwic2VxdWVuY2UiOjQyOTQ5NjcyOTR9XSwidm91dCI6W3sidmFsdWUiOjAuMDEzMTUxNTQsIm4iOjAsInNjcmlwdFB1YktleSI6eyJhc20iOiIwIDg1Yzg5YTU5ODIwNDA2YjZjYzdjZmQ0OGNkOGYyMTRhMTBjMTM4YjAiLCJoZXgiOiIwMDE0ODVjODlhNTk4MjA0MDZiNmNjN2NmZDQ4Y2Q4ZjIxNGExMGMxMzhiMCIsInR5cGUiOiJ3aXRuZXNzX3YwX2tleWhhc2gifX0seyJ2YWx1ZSI6MC4wMDAxOTE2NSwibiI6MSwic2NyaXB0UHViS2V5Ijp7ImFzbSI6Ik9QX0hBU0gxNjAgYzA1NzdkZDlmY2JhMjZiOWNjNjZjZWVhNGYxYWQ0YTViMWMwYzM4ZCBPUF9FUVVBTCIsImhleCI6ImE5MTRjMDU3N2RkOWZjYmEyNmI5Y2M2NmNlZWE0ZjFhZDRhNWIxYzBjMzhkODciLCJ0eXBlIjoic2NyaXB0aGFzaCJ9fV19LHsiaGV4IjoiMDIwMDAwMDAwMWJiYzQxOWYzZWNiM2NiNDc3Y2NhZTRjNmY2ZWNkZDQ5NjliOGMwMjkzZmM3MWRkZmI2NTEwNWEyMzg5MzU0YzYwMTAwMDAwMDZhNDczMDQ0MDIyMDBlM2FiNzU2ZWMzNDg4MGQ0OTUyZjM2YzFkNDZjYWE4MDcyYjkzN2Y5MmM2OTNlNzNkYTIxM2UyYTRjMDhjODkwMjIwNDU1Nzk4ZTEzNDc1MDYxMmZjYzU5ZjNjMGVhYzFjMWM3YjZhNTljN2YxMjZmZjZmODRiYmFlNmIyMGViMGY5ZDAxMjEwMjYzNDhiNjI2YzRhMjkyNjY0OTIzMDZhZDYyN2RhNjIzZjFlNzc2ZTVkMmU2MGZiNGI1MzQwYTE1MDM0ODA5M2ZmZGZmZmZmZjAyOTRjYmFmYjMwMTAwMDAwMDE2MDAxNDY1YTkyZWJiYmQwYmZiZDFjMTg1Yzg1NzViZDM1OTk4MjFhNDhlNzhiM2FjMTcwMDAwMDAwMDAwMTYwMDE0MWU0MTVlMjY0Zjk3YWNhYTM3ODI0ZjYwZmM2NDkwNWNkYmI0ZTIzZjExM2IyNjAwIiwidHhpZCI6IjNjYmY4NGQ4NjZjMDlkMWJhNGNlNjYxNzE5ZDkxYWI4ZTZiOWZkZTQ4MjYyZGE3MjAyOTExZTRjNGY0N2I3MDQiLCJoYXNoIjoiM2NiZjg0ZDg2NmMwOWQxYmE0Y2U2NjE3MTlkOTFhYjhlNmI5ZmRlNDgyNjJkYTcyMDI5MTFlNGM0ZjQ3YjcwNCIsInNpemUiOjIxOSwidnNpemUiOjIxOSwid2VpZ2h0Ijo4NzYsInZlcnNpb24iOjIsImxvY2t0aW1lIjoyNTA1NDg5LCJ2aW4iOlt7InR4aWQiOiJjNjU0OTMzOGEyMDU1MWI2ZGYxZGM3M2YyOWMwYjg2OTQ5ZGRlY2Y2YzZlNGNhN2M0N2NiYjNlY2YzMTljNGJiIiwidm91dCI6MSwic2NyaXB0U2lnIjp7ImFzbSI6IjMwNDQwMjIwMGUzYWI3NTZlYzM0ODgwZDQ5NTJmMzZjMWQ0NmNhYTgwNzJiOTM3ZjkyYzY5M2U3M2RhMjEzZTJhNGMwOGM4OTAyMjA0NTU3OThlMTM0NzUwNjEyZmNjNTlmM2MwZWFjMWMxYzdiNmE1OWM3ZjEyNmZmNmY4NGJiYWU2YjIwZWIwZjlkW0FMTF0gMDI2MzQ4YjYyNmM0YTI5MjY2NDkyMzA2YWQ2MjdkYTYyM2YxZTc3NmU1ZDJlNjBmYjRiNTM0MGExNTAzNDgwOTNmIiwiaGV4IjoiNDczMDQ0MDIyMDBlM2FiNzU2ZWMzNDg4MGQ0OTUyZjM2YzFkNDZjYWE4MDcyYjkzN2Y5MmM2OTNlNzNkYTIxM2UyYTRjMDhjODkwMjIwNDU1Nzk4ZTEzNDc1MDYxMmZjYzU5ZjNjMGVhYzFjMWM3YjZhNTljN2YxMjZmZjZmODRiYmFlNmIyMGViMGY5ZDAxMjEwMjYzNDhiNjI2YzRhMjkyNjY0OTIzMDZhZDYyN2RhNjIzZjFlNzc2ZTVkMmU2MGZiNGI1MzQwYTE1MDM0ODA5M2YifSwic2VxdWVuY2UiOjQyOTQ5NjcyOTN9XSwidm91dCI6W3sidmFsdWUiOjczLjA5NjA5ODc2LCJuIjowLCJzY3JpcHRQdWJLZXkiOnsiYXNtIjoiMCA2NWE5MmViYmJkMGJmYmQxYzE4NWM4NTc1YmQzNTk5ODIxYTQ4ZTc4IiwiaGV4IjoiMDAxNDY1YTkyZWJiYmQwYmZiZDFjMTg1Yzg1NzViZDM1OTk4MjFhNDhlNzgiLCJ0eXBlIjoid2l0bmVzc192MF9rZXloYXNoIn19LHsidmFsdWUiOjAuMDE1NTE1MzksIm4iOjEsInNjcmlwdFB1YktleSI6eyJhc20iOiIwIDFlNDE1ZTI2NGY5N2FjYWEzNzgyNGY2MGZjNjQ5MDVjZGJiNGUyM2YiLCJoZXgiOiIwMDE0MWU0MTVlMjY0Zjk3YWNhYTM3ODI0ZjYwZmM2NDkwNWNkYmI0ZTIzZiIsInR5cGUiOiJ3aXRuZXNzX3YwX2tleWhhc2gifX1dfSx7ImhleCI6IjAyMDAwMDAwMDAwMTAxMmRiYTZjNDQzZDMyNDA3OWMzNzc3ZTQ4ZDVkOTM5YWRkNzA3MDkzMzI4YWNlNDllNDZmNTc4ZjUwZGU0NzgwNzAxMDAwMDAwMDBmZGZmZmZmZjAyODg2NzE2MDAwMDAwMDAwMDE2MDAxNDNlYTdhOTgwYmI5NTQxNjM5ZDU5ODZmZTU4MDdlOTc4YjY5YmFjZDFhMGNhMzFlNjAxMDAwMDAwMTYwMDE0MzBjYzQ2ODI3MmI5MThkMzljNWQwNmM0ZTZlNTNmMTcwOGEwOTVkZDAyNDczMDQ0MDIyMDFhOTM0NDFhZWNjZDlmZDc3OGVlZGJhYjVlNDAyYzRlNDg0OWViYzg4NTgwMjA5N2YwYzUyZTMwMDhhYWMzNmYwMjIwMjlkOWQ5MWRmYjBlZjA3NDY1OWE0NjEyZGM3MWU3NDBkMDg5YTAzMzRhMDc5NDVlNGQ0NWRkNGNhN2FmOTE1OTAxMjEwMzk0OWUzMDNkZDdjNDU2NTZhOGE2OWE1ZDk1OTA0NzQ1ZjhiZDQ3ZmMwYjQwYTllMzQ2NzE2NDk0YTQ4NjUyYzExMTNiMjYwMCIsInR4aWQiOiJjMmRlNWI4NTE2OTE0ZWYzM2U3N2YxMzc3NTcwMmNkMmVmZGNjOTk1ZmNhODNjYzA3YWI1MTc2NWFjNGZkMzIwIiwiaGFzaCI6ImM5MTI0NTY0ZDdiMGRjNWZmODNiNjUxZmVmY2M1ODk2NWI4MDQxZTc0ZTZhODQ5ZGU4ODUyMDU1MmQ5ZTA0NDkiLCJzaXplIjoyMjIsInZzaXplIjoxNDEsIndlaWdodCI6NTYxLCJ2ZXJzaW9uIjoyLCJsb2NrdGltZSI6MjUwNTQ4OSwidmluIjpbeyJ0eGlkIjoiMDc3OGU0MGRmNTc4ZjU0NjllZTRhYzI4MzMwOTA3ZDdhZDM5ZDlkNTQ4N2U3N2MzNzk0MDMyM2Q0NDZjYmEyZCIsInZvdXQiOjEsInNjcmlwdFNpZyI6eyJhc20iOiIiLCJoZXgiOiIifSwidHhpbndpdG5lc3MiOlsiMzA0NDAyMjAxYTkzNDQxYWVjY2Q5ZmQ3NzhlZWRiYWI1ZTQwMmM0ZTQ4NDllYmM4ODU4MDIwOTdmMGM1MmUzMDA4YWFjMzZmMDIyMDI5ZDlkOTFkZmIwZWYwNzQ2NTlhNDYxMmRjNzFlNzQwZDA4OWEwMzM0YTA3OTQ1ZTRkNDVkZDRjYTdhZjkxNTkwMSIsIjAzOTQ5ZTMwM2RkN2M0NTY1NmE4YTY5YTVkOTU5MDQ3NDVmOGJkNDdmYzBiNDBhOWUzNDY3MTY0OTRhNDg2NTJjMSJdLCJzZXF1ZW5jZSI6NDI5NDk2NzI5M31dLCJ2b3V0IjpbeyJ2YWx1ZSI6MC4wMTQ2ODI5NiwibiI6MCwic2NyaXB0UHViS2V5Ijp7ImFzbSI6IjAgM2VhN2E5ODBiYjk1NDE2MzlkNTk4NmZlNTgwN2U5NzhiNjliYWNkMSIsImhleCI6IjAwMTQzZWE3YTk4MGJiOTU0MTYzOWQ1OTg2ZmU1ODA3ZTk3OGI2OWJhY2QxIiwidHlwZSI6IndpdG5lc3NfdjBfa2V5aGFzaCJ9fSx7InZhbHVlIjo4MS41Njk5MDExMiwibiI6MSwic2NyaXB0UHViS2V5Ijp7ImFzbSI6IjAgMzBjYzQ2ODI3MmI5MThkMzljNWQwNmM0ZTZlNTNmMTcwOGEwOTVkZCIsImhleCI6IjAwMTQzMGNjNDY4MjcyYjkxOGQzOWM1ZDA2YzRlNmU1M2YxNzA4YTA5NWRkIiwidHlwZSI6IndpdG5lc3NfdjBfa2V5aGFzaCJ9fV19LHsiaGV4IjoiMDIwMDAwMDAwMDAxMDFkOTUxNGM4OWNjMDViZTZmYjllZjkyMTk2NmEyNDFmMTM2MDZmNjRjZjFiYjQ0ZmM4ODk2NWE1ODhlMDhhZDFiMDAwMDAwMDAxNzE2MDAxNDRlYjNjYmU3ODhhNjQwOTgyZGIxMjJjODg1NTEyZWIwZmU0NDNiMDRmZGZmZmZmZjAyYWJjZTE1MDAwMDAwMDAwMDE2MDAxNDRjOWJiOWYyNmIwZjRiZTI4OGI5NDZlMGE5OGZjNjQ1MzAxMGU1OGU2MmEyYTNmYTAxMDAwMDAwMTYwMDE0NWU5MDQ1ZmEyY2Q4ZmQwNDEyNGNkOWJkMWJlMTdlYTM4ZDVkYTc4NDAyNDczMDQ0MDIyMDA2ZTk5ZDVlNGU1ZWU4NjljZDgwZmMyNzljNWYwNmE3OGYxZmEyODkzNDE1MTA5NTI3ZWVmNWE3YTYzMDA1MmEwMjIwMDdmZTliNTMyZGY1Nzc2YzIxYjdjNGRkYTIyNDExNjJjMzhkMjIxYTQ3YmFjYzIxYTdiNTdhYjg4OGEwZWZlMjAxMjEwMzA1NjJjMGJhYzZhOTlhOGE2MDFiNDNhZjI0MjYwMzlhYTI1YTdhNDIxNDQ4MmY5MzllYmE2M2Q1Yzk5MzQwZDIxMTNiMjYwMCIsInR4aWQiOiJkYzNmMWI0ZDU5ZTljMDJlMjUyY2VlMDgwMDkzMWZhOWJmM2VhYWQ5ZTgyODc3YjIwNjBiYTFlZDhmYzg3MDI1IiwiaGFzaCI6IjFiNzQwNDNhYWZkZGJlNTZmMDkxODc5YTU4YzZiYjE1NjIwNjZjZGFhYmY5NjAwYzkxMTNkYmI3NTU2ZDU0YjAiLCJzaXplIjoyNDUsInZzaXplIjoxNjQsIndlaWdodCI6NjUzLCJ2ZXJzaW9uIjoyLCJsb2NrdGltZSI6MjUwNTQ4OSwidmluIjpbeyJ0eGlkIjoiMWJhZDA4OGU1ODVhOTY4OGZjNDRiYmYxNGNmNjA2MzZmMTQxYTI2NjE5OTJlZmI5NmZiZTA1Y2M4OTRjNTFkOSIsInZvdXQiOjAsInNjcmlwdFNpZyI6eyJhc20iOiIwMDE0NGViM2NiZTc4OGE2NDA5ODJkYjEyMmM4ODU1MTJlYjBmZTQ0M2IwNCIsImhleCI6IjE2MDAxNDRlYjNjYmU3ODhhNjQwOTgyZGIxMjJjODg1NTEyZWIwZmU0NDNiMDQifSwidHhpbndpdG5lc3MiOlsiMzA0NDAyMjAwNmU5OWQ1ZTRlNWVlODY5Y2Q4MGZjMjc5YzVmMDZhNzhmMWZhMjg5MzQxNTEwOTUyN2VlZjVhN2E2MzAwNTJhMDIyMDA3ZmU5YjUzMmRmNTc3NmMyMWI3YzRkZGEyMjQxMTYyYzM4ZDIyMWE0N2JhY2MyMWE3YjU3YWI4ODhhMGVmZTIwMSIsIjAzMDU2MmMwYmFjNmE5OWE4YTYwMWI0M2FmMjQyNjAzOWFhMjVhN2E0MjE0NDgyZjkzOWViYTYzZDVjOTkzNDBkMiJdLCJzZXF1ZW5jZSI6NDI5NDk2NzI5M31dLCJ2b3V0IjpbeyJ2YWx1ZSI6MC4wMTQyOTE2MywibiI6MCwic2NyaXB0UHViS2V5Ijp7ImFzbSI6IjAgNGM5YmI5ZjI2YjBmNGJlMjg4Yjk0NmUwYTk4ZmM2NDUzMDEwZTU4ZSIsImhleCI6IjAwMTQ0YzliYjlmMjZiMGY0YmUyODhiOTQ2ZTBhOThmYzY0NTMwMTBlNThlIiwidHlwZSI6IndpdG5lc3NfdjBfa2V5aGFzaCJ9fSx7InZhbHVlIjo4NC45OTk5NTIzNCwibiI6MSwic2NyaXB0UHViS2V5Ijp7ImFzbSI6IjAgNWU5MDQ1ZmEyY2Q4ZmQwNDEyNGNkOWJkMWJlMTdlYTM4ZDVkYTc4NCIsImhleCI6IjAwMTQ1ZTkwNDVmYTJjZDhmZDA0MTI0Y2Q5YmQxYmUxN2VhMzhkNWRhNzg0IiwidHlwZSI6IndpdG5lc3NfdjBfa2V5aGFzaCJ9fV19LHsiaGV4IjoiMDIwMDAwMDAwMDAxMDE4M2M2OTU5ZDVmNjM0ZTcxNmY2YzVmMGVlYTEwNTM5YzgzN2I0ODk0OTMxMTY0OWM4ODI1MWJjMzBkYjM3N2Q1MDEwMDAwMDAwMGZkZmZmZmZmMDIyNGYyYTExZjAyMDAwMDAwMTYwMDE0ZTg2ZjRmOWUzMmQ2YzVjZmY0MjRhNDgyMmM2YWFkYTJmNDM3NWJlYmI5M2YxZTAwMDAwMDAwMDAxNjAwMTRlMWQ1ZGFlOTY4NjY2MjU3MzNjMDI5MmY1ZWUxNDNjMTEwZTU4NjA1MDI0NzMwNDQwMjIwMGQ2ODU0NGU0MTU4MGFmMjZmNWNiMTAzMTNmZTU4MjU4NjM3Y2FkYTQwNTgzZWQyMGM4ODAyYWJkOTAzOWI0ZDAyMjAzZTU1ZGMxNTNlZDRhMjIzMWIxNGQ5ZWNlZTNhZGE3NjJkNzFmM2Q2M2NhMzM4ODg5ZWI3MTIyZGNmM2FhOGM5MDEyMTAzYjUwNGE2MGU3MWRhZTYxYzBiMmExMGEwYTlmYmY1ZDQyNTdhNTg5YTcyOWJjNWQxZTEyMGI3NWY3MDYxMjA4NzExM2IyNjAwIiwidHhpZCI6IjdhNTkzYjlkMmJiNTgwODAyYjAxM2I3YTY4ZTQyZjRjZGQxNGQ1MGI5ZjJmNTkwMWE4MDBiYTRhYTc0N2NmMjUiLCJoYXNoIjoiMWYwOGMxNTNmMWFhMjYwNWE2ODBmZGRmZTYyOTRmNWJhZTNjZTkyMTcwYzhkMTMxZDRiYTk2MjMyNzc3ZDcxZSIsInNpemUiOjIyMiwidnNpemUiOjE0MSwid2VpZ2h0Ijo1NjEsInZlcnNpb24iOjIsImxvY2t0aW1lIjoyNTA1NDg5LCJ2aW4iOlt7InR4aWQiOiJkNTc3YjMwZGMzMWIyNTg4OWM2NDExOTM5NDQ4N2I4MzljNTMxMGVhMGU1ZjZjNmY3MTRlNjM1ZjlkOTVjNjgzIiwidm91dCI6MSwic2NyaXB0U2lnIjp7ImFzbSI6IiIsImhleCI6IiJ9LCJ0eGlud2l0bmVzcyI6WyIzMDQ0MDIyMDBkNjg1NDRlNDE1ODBhZjI2ZjVjYjEwMzEzZmU1ODI1ODYzN2NhZGE0MDU4M2VkMjBjODgwMmFiZDkwMzliNGQwMjIwM2U1NWRjMTUzZWQ0YTIyMzFiMTRkOWVjZWUzYWRhNzYyZDcxZjNkNjNjYTMzODg4OWViNzEyMmRjZjNhYThjOTAxIiwiMDNiNTA0YTYwZTcxZGFlNjFjMGIyYTEwYTBhOWZiZjVkNDI1N2E1ODlhNzI5YmM1ZDFlMTIwYjc1ZjcwNjEyMDg3Il0sInNlcXVlbmNlIjo0Mjk0OTY3MjkzfV0sInZvdXQiOlt7InZhbHVlIjo5MS4yMDY0MTU3MiwibiI6MCwic2NyaXB0UHViS2V5Ijp7ImFzbSI6IjAgZTg2ZjRmOWUzMmQ2YzVjZmY0MjRhNDgyMmM2YWFkYTJmNDM3NWJlYiIsImhleCI6IjAwMTRlODZmNGY5ZTMyZDZjNWNmZjQyNGE0ODIyYzZhYWRhMmY0Mzc1YmViIiwidHlwZSI6IndpdG5lc3NfdjBfa2V5aGFzaCJ9fSx7InZhbHVlIjowLjAxOTgyMzkzLCJuIjoxLCJzY3JpcHRQdWJLZXkiOnsiYXNtIjoiMCBlMWQ1ZGFlOTY4NjY2MjU3MzNjMDI5MmY1ZWUxNDNjMTEwZTU4NjA1IiwiaGV4IjoiMDAxNGUxZDVkYWU5Njg2NjYyNTczM2MwMjkyZjVlZTE0M2MxMTBlNTg2MDUiLCJ0eXBlIjoid2l0bmVzc192MF9rZXloYXNoIn19XX0seyJoZXgiOiIwMjAwMDAwMDAwMDEwMTJiYjU4ODUzYTAyZDQwNTNiMTYyY2Q0MGRiNGQ1NjlkYTRlZWM1MmQyMjJlNjY5MjJkNTNkYzNlZGM5OTIxNzYwMDAwMDAwMDAwZmRmZmZmZmYwMjAzYTcxNjAwMDAwMDAwMDAxNjAwMTQzM2Q4YTQ3NDE2Zjc2NmJlNjM2MjIzYjMyNTRkNjQyNWU1NWU0YWIwZTJmYmEwOGMwMTAwMDAwMDE2MDAxNDc1YWNlNjg4YzlkOGFmZmI1OTBmNmQ5YmQwY2VlYjBkZDdkNTVkMzYwMjQ3MzA0NDAyMjAyYzQ4NmI1NjgzMTg2MjYzMjg4ZmE4N2JiMjRiNjk1MzQ0ZGY0Y2M0MTM3ZDFhNWUzNjY4NzZjMDMwMmVkNGVjMDIyMDRhYmNkYTMyZGRhNzVlNDRjODUwNDY0ZDE3MTQwMzMzMGVmODU5ZDk1NGZjNTQxOTg1MzNmZjUwYWY1YzFlMjkwMTIxMDMwYzExNGFmYjM5Y2ZhN2E2NmUyMWY1ZmY1ODM2YTNlNWQwMmEyNTJmOTQ2OGRhZjZkYjU3Y2ZjNzAwODFjYjNhMTEzYjI2MDAiLCJ0eGlkIjoiZjM5NDM1MGM5MWMwYjdhYjAyNjQzNDE0NTg4YTU5M2VmNTc2ZWJhNzIxZWZlYjIyNTdmMmYxMTRkN2Y2MTcyZCIsImhhc2giOiJiNWJkMTI3MjVjMzcyZGVlYTZjMTFlYWI3NGVjNWQyYWIyYjI4MTc3OGU4NDI2OTIyNjFhY2Y4ZTJkMmVhZTZiIiwic2l6ZSI6MjIyLCJ2c2l6ZSI6MTQxLCJ3ZWlnaHQiOjU2MSwidmVyc2lvbiI6MiwibG9ja3RpbWUiOjI1MDU0ODksInZpbiI6W3sidHhpZCI6Ijc2MjE5OWRjM2VkYzUzMmQ5MjY2MmUyMjJkYzVlZWE0OWQ1NjRkZGI0MGNkNjJiMTUzNDAyZGEwNTM4OGI1MmIiLCJ2b3V0IjowLCJzY3JpcHRTaWciOnsiYXNtIjoiIiwiaGV4IjoiIn0sInR4aW53aXRuZXNzIjpbIjMwNDQwMjIwMmM0ODZiNTY4MzE4NjI2MzI4OGZhODdiYjI0YjY5NTM0NGRmNGNjNDEzN2QxYTVlMzY2ODc2YzAzMDJlZDRlYzAyMjA0YWJjZGEzMmRkYTc1ZTQ0Yzg1MDQ2NGQxNzE0MDMzMzBlZjg1OWQ5NTRmYzU0MTk4NTMzZmY1MGFmNWMxZTI5MDEiLCIwMzBjMTE0YWZiMzljZmE3YTY2ZTIxZjVmZjU4MzZhM2U1ZDAyYTI1MmY5NDY4ZGFmNmRiNTdjZmM3MDA4MWNiM2EiXSwic2VxdWVuY2UiOjQyOTQ5NjcyOTN9XSwidm91dCI6W3sidmFsdWUiOjAuMDE0ODQ1NDcsIm4iOjAsInNjcmlwdFB1YktleSI6eyJhc20iOiIwIDMzZDhhNDc0MTZmNzY2YmU2MzYyMjNiMzI1NGQ2NDI1ZTU1ZTRhYjAiLCJoZXgiOiIwMDE0MzNkOGE0NzQxNmY3NjZiZTYzNjIyM2IzMjU0ZDY0MjVlNTVlNGFiMCIsInR5cGUiOiJ3aXRuZXNzX3YwX2tleWhhc2gifX0seyJ2YWx1ZSI6NjYuNTQzMjc3NzgsIm4iOjEsInNjcmlwdFB1YktleSI6eyJhc20iOiIwIDc1YWNlNjg4YzlkOGFmZmI1OTBmNmQ5YmQwY2VlYjBkZDdkNTVkMzYiLCJoZXgiOiIwMDE0NzVhY2U2ODhjOWQ4YWZmYjU5MGY2ZDliZDBjZWViMGRkN2Q1NWQzNiIsInR5cGUiOiJ3aXRuZXNzX3YwX2tleWhhc2gifX1dfSx7ImhleCI6IjAyMDAwMDAwMDAwMTAxNzM5ZmM5ZTQxYjEyYjIwNmFlYjdjM2U3NDAxOGYyMzdmZGZjMWZhNDM4MTA4NTM3NTljNGZmYTUwMTFmODlkOTAxMDAwMDAwMDBmZGZmZmZmZjAyMDE4MTE5MDAwMDAwMDAwMDE2MDAxNDBiYWNlMDY1YTA1MmNjZTkyZWNmZWQ1NTFmNjkyMzBmMTAyMDVhNTVmYWNkYTMxNTAyMDAwMDAwMTYwMDE0Mjg4NTA0MGU4MjAxNjBjZmJlYzhhNDFhNGZmM2EwOGYxNGQ3MDFlNjAyNDczMDQ0MDIyMDU2OTdjMDU5NmFhMDM5YWU0MmM0NmY4Y2Y4YmM4ZTg4ZmRiMzgxNGY2YjczODNkOTk5MmU2ZDNhYWQzNTEwOTgwMjIwNTE0NGE0ZDg3Y2MxMmY1ZDI3ZmE5MGIwNjRmZTU5Nzc4NDdhMjQ3NWJhY2Q0Y2ZlZDBjNTIwNzBlZDY1ZDFhYjAxMjEwMjY3YmZkNDdkNTRlNWVkNzE5Y2E3NTU2ZDVlM2Y3YzAyZDc5MmZlODlkNzA0MGEzNGE0MzY0M2NkMWRhNjQ3YzYxMTNiMjYwMCIsInR4aWQiOiI1MGY1YzIxYWZiODA2NjBiMjJkNDAyZTM4YzgyMzE4M2U5ZmU5YmJjYjkzZTZkZTI4NjVmZWVhOWEwYmZkYjQyIiwiaGFzaCI6Ijk4YjA0NjBkZjhmNWJmYmIxNTUyNDQxZjQ5MmM1ODRhMzA4OTllOWQwYzU3YzhjYTIyZTA4ZjI5YjkyMjExNDIiLCJzaXplIjoyMjIsInZzaXplIjoxNDEsIndlaWdodCI6NTYxLCJ2ZXJzaW9uIjoyLCJsb2NrdGltZSI6MjUwNTQ4OSwidmluIjpbeyJ0eGlkIjoiZDk4OTFmMDFhNWZmYzQ1OTM3ODUxMDM4YTQxZmZjZmQzN2YyMTg0MGU3YzNiN2FlMDZiMjEyMWJlNGM5OWY3MyIsInZvdXQiOjEsInNjcmlwdFNpZyI6eyJhc20iOiIiLCJoZXgiOiIifSwidHhpbndpdG5lc3MiOlsiMzA0NDAyMjA1Njk3YzA1OTZhYTAzOWFlNDJjNDZmOGNmOGJjOGU4OGZkYjM4MTRmNmI3MzgzZDk5OTJlNmQzYWFkMzUxMDk4MDIyMDUxNDRhNGQ4N2NjMTJmNWQyN2ZhOTBiMDY0ZmU1OTc3ODQ3YTI0NzViYWNkNGNmZWQwYzUyMDcwZWQ2NWQxYWIwMSIsIjAyNjdiZmQ0N2Q1NGU1ZWQ3MTljYTc1NTZkNWUzZjdjMDJkNzkyZmU4OWQ3MDQwYTM0YTQzNjQzY2QxZGE2NDdjNiJdLCJzZXF1ZW5jZSI6NDI5NDk2NzI5M31dLCJ2b3V0IjpbeyJ2YWx1ZSI6MC4wMTY3MTQyNSwibiI6MCwic2NyaXB0UHViS2V5Ijp7ImFzbSI6IjAgMGJhY2UwNjVhMDUyY2NlOTJlY2ZlZDU1MWY2OTIzMGYxMDIwNWE1NSIsImhleCI6IjAwMTQwYmFjZTA2NWEwNTJjY2U5MmVjZmVkNTUxZjY5MjMwZjEwMjA1YTU1IiwidHlwZSI6IndpdG5lc3NfdjBfa2V5aGFzaCJ9fSx7InZhbHVlIjo4OS41Mjk5MTIyNiwibiI6MSwic2NyaXB0UHViS2V5Ijp7ImFzbSI6IjAgMjg4NTA0MGU4MjAxNjBjZmJlYzhhNDFhNGZmM2EwOGYxNGQ3MDFlNiIsImhleCI6IjAwMTQyODg1MDQwZTgyMDE2MGNmYmVjOGE0MWE0ZmYzYTA4ZjE0ZDcwMWU2IiwidHlwZSI6IndpdG5lc3NfdjBfa2V5aGFzaCJ9fV19LHsiaGV4IjoiMDIwMDAwMDAwMDAxMDEyZDE3ZjZkNzE0ZjFmMjU3MjJlYmVmMjFhN2ViNzZmNTNlNTk4YTU4MTQzNDY0MDJhYmI3YzA5MTBjMzU5NGYzMDEwMDAwMDAwMGZkZmZmZmZmMDI4NTdlODc4YzAxMDAwMDAwMTYwMDE0MTYxZGExY2VhNGZkZDMwMDY4NGNjOTI1YjA5YmZjOGMxNmQxOWExNjQ5NDYxOTAwMDAwMDAwMDAxNjAwMTRlYjQ3ZTY4ZDNhMTM5ZGFjYzNjMTMzZTNmYWQwNTZlZTliNzhjZjM1MDI0NzMwNDQwMjIwM2I3MmExMWU3NWQwODk2MmYwZGU5NTVjMjcyYmZkN2MyZjFmZWZlOWZiMzNlOWE1NTU5ZTVlZmUzMzIzMzc1ODAyMjAzZmMwMGQ1OWNkNDgyZmVhOTA4OTljN2NlMTc3N2ZjOGUxOWM3MjQ3YjQzMmMxMTZjNjVlOWY2MWYwM2YzZTA5MDEyMTAzYjk0YzNhMGQyMDM0NzMxYThmMTFhOGQwYjM4NWUyYWY1ZDEyMjYzMzhjMDZkMTFhMWNiZjdlMjEyYzYzYzViNDExM2IyNjAwIiwidHhpZCI6IjdlYzM3ZDdiODZmOTA2MGRmZGY4YTNmZDI4YzIxY2U1MDRjNjNmNzU2MmEzZmZiZTA3MWE5OTg3ZjBkNzBhYzIiLCJoYXNoIjoiYjliNTZlZTFhYjFiZTY3NDg1NjAwNTc2MDhjZWFlODNmYmYxMTgyZjI0MzlkOTJhYzdhM2RhNTA0MzMyMDM3NSIsInNpemUiOjIyMiwidnNpemUiOjE0MSwid2VpZ2h0Ijo1NjEsInZlcnNpb24iOjIsImxvY2t0aW1lIjoyNTA1NDg5LCJ2aW4iOlt7InR4aWQiOiJmMzk0MzUwYzkxYzBiN2FiMDI2NDM0MTQ1ODhhNTkzZWY1NzZlYmE3MjFlZmViMjI1N2YyZjExNGQ3ZjYxNzJkIiwidm91dCI6MSwic2NyaXB0U2lnIjp7ImFzbSI6IiIsImhleCI6IiJ9LCJ0eGlud2l0bmVzcyI6WyIzMDQ0MDIyMDNiNzJhMTFlNzVkMDg5NjJmMGRlOTU1YzI3MmJmZDdjMmYxZmVmZTlmYjMzZTlhNTU1OWU1ZWZlMzMyMzM3NTgwMjIwM2ZjMDBkNTljZDQ4MmZlYTkwODk5YzdjZTE3NzdmYzhlMTljNzI0N2I0MzJjMTE2YzY1ZTlmNjFmMDNmM2UwOTAxIiwiMDNiOTRjM2EwZDIwMzQ3MzFhOGYxMWE4ZDBiMzg1ZTJhZjVkMTIyNjMzOGMwNmQxMWExY2JmN2UyMTJjNjNjNWI0Il0sInNlcXVlbmNlIjo0Mjk0OTY3MjkzfV0sInZvdXQiOlt7InZhbHVlIjo2Ni41MjY1NzI4NSwibiI6MCwic2NyaXB0UHViS2V5Ijp7ImFzbSI6IjAgMTYxZGExY2VhNGZkZDMwMDY4NGNjOTI1YjA5YmZjOGMxNmQxOWExNiIsImhleCI6IjAwMTQxNjFkYTFjZWE0ZmRkMzAwNjg0Y2M5MjViMDliZmM4YzE2ZDE5YTE2IiwidHlwZSI6IndpdG5lc3NfdjBfa2V5aGFzaCJ9fSx7InZhbHVlIjowLjAxNjU2MzkzLCJuIjoxLCJzY3JpcHRQdWJLZXkiOnsiYXNtIjoiMCBlYjQ3ZTY4ZDNhMTM5ZGFjYzNjMTMzZTNmYWQwNTZlZTliNzhjZjM1IiwiaGV4IjoiMDAxNGViNDdlNjhkM2ExMzlkYWNjM2MxMzNlM2ZhZDA1NmVlOWI3OGNmMzUiLCJ0eXBlIjoid2l0bmVzc192MF9rZXloYXNoIn19XX0seyJoZXgiOiIwMjAwMDAwMDAwMDEwMWMyMGFkN2YwODc5OTFhMDdiZWZmYTM2Mjc1M2ZjNjA0ZTUxY2MyMjhmZGEzZjhmZDBkMDZmOTg2N2I3ZGMzN2UwMDAwMDAwMDAwZmRmZmZmZmYwMjNhNWE2ZThjMDEwMDAwMDAxNjAwMTRjZGQ2YmY1YTA1YzZjMGY4MjI2ZTY1N2E0YTAwYzcwOWE5Y2ZiZDRhMzdlZDE4MDAwMDAwMDAwMDE2MDAxNDQ0NjI1MGNiNDIxMTc5YjkxMjkwZWZhY2JlZjE2NjFmOTgyYTc1OGMwMjQ3MzA0NDAyMjAzYjE4MjBlMjllMWRlZDAzOTI0YmFjMjBlNzgxYjRmNGU5ZWVhNTg4ZDdiYzYyODE0YWVkMmE4Y2E2ZmJiNWU0MDIyMDJiNmY0YTAwNmVkNmY4NzZlNzUzNDE3ZjViMjQzODM3Nzg0NGVmMTMxMGY1NzBjYTVhZTZhNjQ5YjE4MWIxZWIwMTIxMDI1MWUwZmVkYzE5M2UyMjM0YTg4MjZiZDE5YmIxNmM4MjExY2E5YTU1YjI3MDI4ZmYwMDk5M2RkYWQ3NTAyY2M5MTEzYjI2MDAiLCJ0eGlkIjoiMGI5ZDYxODk0MjhjMzhmMTcxNmMxMzE4M2JkZTQyNzlkYzNkYjVhMzg3Yjg2NDhhOTVhOTEyZmI3MzRmNTJiMSIsImhhc2giOiIxYjYyYWM4YjdmM2U2ZWM3ODE3ZTY3NDM5NzFkZDYzMDdlYjI1ZjVjMjE0YjcxMTMwMTgzMmJmYzFlOWExMDZmIiwic2l6ZSI6MjIyLCJ2c2l6ZSI6MTQxLCJ3ZWlnaHQiOjU2MSwidmVyc2lvbiI6MiwibG9ja3RpbWUiOjI1MDU0ODksInZpbiI6W3sidHhpZCI6IjdlYzM3ZDdiODZmOTA2MGRmZGY4YTNmZDI4YzIxY2U1MDRjNjNmNzU2MmEzZmZiZTA3MWE5OTg3ZjBkNzBhYzIiLCJ2b3V0IjowLCJzY3JpcHRTaWciOnsiYXNtIjoiIiwiaGV4IjoiIn0sInR4aW53aXRuZXNzIjpbIjMwNDQwMjIwM2IxODIwZTI5ZTFkZWQwMzkyNGJhYzIwZTc4MWI0ZjRlOWVlYTU4OGQ3YmM2MjgxNGFlZDJhOGNhNmZiYjVlNDAyMjAyYjZmNGEwMDZlZDZmODc2ZTc1MzQxN2Y1YjI0MzgzNzc4NDRlZjEzMTBmNTcwY2E1YWU2YTY0OWIxODFiMWViMDEiLCIwMjUxZTBmZWRjMTkzZTIyMzRhODgyNmJkMTliYjE2YzgyMTFjYTlhNTViMjcwMjhmZjAwOTkzZGRhZDc1MDJjYzkiXSwic2VxdWVuY2UiOjQyOTQ5NjcyOTN9XSwidm91dCI6W3sidmFsdWUiOjY2LjUxMDA5NTk0LCJuIjowLCJzY3JpcHRQdWJLZXkiOnsiYXNtIjoiMCBjZGQ2YmY1YTA1YzZjMGY4MjI2ZTY1N2E0YTAwYzcwOWE5Y2ZiZDRhIiwiaGV4IjoiMDAxNGNkZDZiZjVhMDVjNmMwZjgyMjZlNjU3YTRhMDBjNzA5YTljZmJkNGEiLCJ0eXBlIjoid2l0bmVzc192MF9rZXloYXNoIn19LHsidmFsdWUiOjAuMDE2MzM1OTEsIm4iOjEsInNjcmlwdFB1YktleSI6eyJhc20iOiIwIDQ0NjI1MGNiNDIxMTc5YjkxMjkwZWZhY2JlZjE2NjFmOTgyYTc1OGMiLCJoZXgiOiIwMDE0NDQ2MjUwY2I0MjExNzliOTEyOTBlZmFjYmVmMTY2MWY5ODJhNzU4YyIsInR5cGUiOiJ3aXRuZXNzX3YwX2tleWhhc2gifX1dfSx7ImhleCI6IjAyMDAwMDAwMDFhMWRlNTZjZThlNzUyNjQ5NjBjY2I1ZTg4NzA0ZjBiNzFlZWJjMWRlNWU1MDA4ZjkxMWMwOTYzNmU5YTYwN2U5MDAwMDAwMDA2YTQ3MzA0NDAyMjAxMTIwYTAyNjQxNWZlZGNkNjMwNGJkOGEwNjJkYjZkNGFhYzQ5MWYzY2MxNDhmZmVlMGQ5ZGY4MmU2YWY2NjgzMDIyMDE2MzU1OWQ0NjQ2MWYzMjZiODkzZDYwM2ViNzU1MWNiMzc4YjAxMjk5MTk5OTAwZDZiMDBlMmI5N2M1OGNlMGMwMTIxMDNhNDE4ZjhkNmRmYjMxMDBmZjY0ODE3MGE2NGRhOWM3YWZjZTliMjliZGVjYzQ4NGE4ZmRkOGI3NGI2MWJhYzFkZmRmZmZmZmYwMmIwMGUxMDAwMDAwMDAwMDAxN2E5MTRkMmZlMzc0MWJhNmIwNjhkZmFmNGE0NzJkZjFjZDIyNTQ4OWNmNTc5ODc2YWQ3MjIzYjAwMDAwMDAwMTdhOTE0MjU4OTk5OTdlNDdkNzk5M2Q4NzFiMjY1NzE3ZmE3NGUxNjAyODEyNTg3MTEzYjI2MDAiLCJ0eGlkIjoiMjZiNWM4MjIyNDJlNWE2NmYxZTNiYmFjNWU0YjgzZTc0ZmY3ZWJmY2Y0MjI4Mzg5NzBiNDg4NWIwYmIxMTJjYyIsImhhc2giOiIyNmI1YzgyMjI0MmU1YTY2ZjFlM2JiYWM1ZTRiODNlNzRmZjdlYmZjZjQyMjgzODk3MGI0ODg1YjBiYjExMmNjIiwic2l6ZSI6MjIxLCJ2c2l6ZSI6MjIxLCJ3ZWlnaHQiOjg4NCwidmVyc2lvbiI6MiwibG9ja3RpbWUiOjI1MDU0ODksInZpbiI6W3sidHhpZCI6ImU5MDdhNmU5MzY5NmMwMTFmOTA4NTA1ZWRlYzFlYjFlYjdmMDA0ODdlOGI1Y2M2MDQ5MjY3NThlY2U1NmRlYTEiLCJ2b3V0IjowLCJzY3JpcHRTaWciOnsiYXNtIjoiMzA0NDAyMjAxMTIwYTAyNjQxNWZlZGNkNjMwNGJkOGEwNjJkYjZkNGFhYzQ5MWYzY2MxNDhmZmVlMGQ5ZGY4MmU2YWY2NjgzMDIyMDE2MzU1OWQ0NjQ2MWYzMjZiODkzZDYwM2ViNzU1MWNiMzc4YjAxMjk5MTk5OTAwZDZiMDBlMmI5N2M1OGNlMGNbQUxMXSAwM2E0MThmOGQ2ZGZiMzEwMGZmNjQ4MTcwYTY0ZGE5YzdhZmNlOWIyOWJkZWNjNDg0YThmZGQ4Yjc0YjYxYmFjMWQiLCJoZXgiOiI0NzMwNDQwMjIwMTEyMGEwMjY0MTVmZWRjZDYzMDRiZDhhMDYyZGI2ZDRhYWM0OTFmM2NjMTQ4ZmZlZTBkOWRmODJlNmFmNjY4MzAyMjAxNjM1NTlkNDY0NjFmMzI2Yjg5M2Q2MDNlYjc1NTFjYjM3OGIwMTI5OTE5OTkwMGQ2YjAwZTJiOTdjNThjZTBjMDEyMTAzYTQxOGY4ZDZkZmIzMTAwZmY2NDgxNzBhNjRkYTljN2FmY2U5YjI5YmRlY2M0ODRhOGZkZDhiNzRiNjFiYWMxZCJ9LCJzZXF1ZW5jZSI6NDI5NDk2NzI5M31dLCJ2b3V0IjpbeyJ2YWx1ZSI6MC4wMTA1MjMzNiwibiI6MCwic2NyaXB0UHViS2V5Ijp7ImFzbSI6Ik9QX0hBU0gxNjAgZDJmZTM3NDFiYTZiMDY4ZGZhZjRhNDcyZGYxY2QyMjU0ODljZjU3OSBPUF9FUVVBTCIsImhleCI6ImE5MTRkMmZlMzc0MWJhNmIwNjhkZmFmNGE0NzJkZjFjZDIyNTQ4OWNmNTc5ODciLCJ0eXBlIjoic2NyaXB0aGFzaCJ9fSx7InZhbHVlIjo5LjkyMTM5MTE0LCJuIjoxLCJzY3JpcHRQdWJLZXkiOnsiYXNtIjoiT1BfSEFTSDE2MCAyNTg5OTk5N2U0N2Q3OTkzZDg3MWIyNjU3MTdmYTc0ZTE2MDI4MTI1IE9QX0VRVUFMIiwiaGV4IjoiYTkxNDI1ODk5OTk3ZTQ3ZDc5OTNkODcxYjI2NTcxN2ZhNzRlMTYwMjgxMjU4NyIsInR5cGUiOiJzY3JpcHRoYXNoIn19XX0seyJoZXgiOiIwMjAwMDAwMDAwMDEwMTQ3YjMyM2QwYWEyMTYzMzdlNzY4Y2M1OTk0ZTBjN2M3ZmZhZTc5ODFhYzk5YzJmNTEzZDkwMDIxOWQzMjZjZDcwMTAwMDAwMDAwZmRmZmZmZmYwMjVlYjM3M2RkMDEwMDAwMDAxNjAwMTQyY2ZjZmRhNTk4NDk2MGE4ZmExZDQ3MGViNWMxMjFlOGYzOGM0NGNkNDQ0ODE1MDAwMDAwMDAwMDE2MDAxNGZmYjhjMGEyNmFmMmU2MjIxNGFhMWVjN2RhMWY5YTQwNzdkNGMwZWQwMjQ3MzA0NDAyMjA3OWI0ZTk0MDU2N2Y4YjhiNjY4OWUzNDdkMGQxNDE0NDBiN2YwYjE2M2QyMDY4ZjJlODBhY2ZhMDBjMWI4NGI1MDIyMDU2ZjM4MWVmMzU1NTQ0Y2E1NzQ1N2Q2ODk5MjgyNzgyOTIyZjVlZTAwNDBkYWJjNjIwMjUwZGQ5YmJjZWZmOTcwMTIxMDMxNmE5M2RiOWNjMTgwNzFlMDE4ZWI1NGRiODRiYWFlZmVhNWIxM2FhYzk1NDQxOTQwODhkODE3OWRiMDlkMGNjMTAzYjI2MDAiLCJ0eGlkIjoiMjg3OGE0ZjY3ODZjYTViNmU5MjJiMWNlZjIzNTE2OGY4ZDNiN2U0M2E3NTMwNGQ4YmE4ZDg4ZTg3ZTM3N2NmMCIsImhhc2giOiJiZGI2MGI5YmU2YWE0ZDQyNGJlY2FkOWFmNzRlNDY2ZmJkMjE0M2JhNDEzMmM1YzQwNWIwYmM5MTMyOTY2MDAwIiwic2l6ZSI6MjIyLCJ2c2l6ZSI6MTQxLCJ3ZWlnaHQiOjU2MSwidmVyc2lvbiI6MiwibG9ja3RpbWUiOjI1MDU0ODgsInZpbiI6W3sidHhpZCI6ImQ3NmMzMjlkMjEwMGQ5MTNmNWMyOTlhYzgxNzlhZWZmYzdjN2UwOTQ1OWNjNjhlNzM3NjMyMWFhZDAyM2IzNDciLCJ2b3V0IjoxLCJzY3JpcHRTaWciOnsiYXNtIjoiIiwiaGV4IjoiIn0sInR4aW53aXRuZXNzIjpbIjMwNDQwMjIwNzliNGU5NDA1NjdmOGI4YjY2ODllMzQ3ZDBkMTQxNDQwYjdmMGIxNjNkMjA2OGYyZTgwYWNmYTAwYzFiODRiNTAyMjA1NmYzODFlZjM1NTU0NGNhNTc0NTdkNjg5OTI4Mjc4MjkyMmY1ZWUwMDQwZGFiYzYyMDI1MGRkOWJiY2VmZjk3MDEiLCIwMzE2YTkzZGI5Y2MxODA3MWUwMThlYjU0ZGI4NGJhYWVmZWE1YjEzYWFjOTU0NDE5NDA4OGQ4MTc5ZGIwOWQwY2MiXSwic2VxdWVuY2UiOjQyOTQ5NjcyOTN9XSwidm91dCI6W3sidmFsdWUiOjgwLjEwMzE0NTksIm4iOjAsInNjcmlwdFB1YktleSI6eyJhc20iOiIwIDJjZmNmZGE1OTg0OTYwYThmYTFkNDcwZWI1YzEyMWU4ZjM4YzQ0Y2QiLCJoZXgiOiIwMDE0MmNmY2ZkYTU5ODQ5NjBhOGZhMWQ0NzBlYjVjMTIxZThmMzhjNDRjZCIsInR5cGUiOiJ3aXRuZXNzX3YwX2tleWhhc2gifX0seyJ2YWx1ZSI6MC4wMTM5NDc1NiwibiI6MSwic2NyaXB0UHViS2V5Ijp7ImFzbSI6IjAgZmZiOGMwYTI2YWYyZTYyMjE0YWExZWM3ZGExZjlhNDA3N2Q0YzBlZCIsImhleCI6IjAwMTRmZmI4YzBhMjZhZjJlNjIyMTRhYTFlYzdkYTFmOWE0MDc3ZDRjMGVkIiwidHlwZSI6IndpdG5lc3NfdjBfa2V5aGFzaCJ9fV19LHsiaGV4IjoiMDIwMDAwMDAwMDAxMDFiMmVjNjM5OTkxYzk2NDg0OGEwOWU1ZWM3ZTBjZmNjYjVkODA3NDMyNTgxYzAwMTc3YmFmMDk2YmQyMjgwYWY5MDEwMDAwMDAwMGZkZmZmZmZmMDJiNWUxMTcwMDAwMDAwMDAwMTYwMDE0ZDUxN2MyOThhMWRlMTIzNTMwZDEyNGViMjA3ZjNjMjMxNDA1YzA5NmIyOTY3YTEwMDIwMDAwMDAxNjAwMTQyY2Q3ZjVjMGRlMDhjZTNiNDQ0ZTViNTRiMzM0YmIwMjliNjRlNDIxMDI0NzMwNDQwMjIwMjg1MzYzODQ2NTc2MDU1OTQ1MDQyZGYzODIzNzdmMDdlNmZlOGRkZTQ5Y2I4OGU1YTUwOTExNWUyMWJmMTcyMDAyMjA3MWViMTgzMGQwM2I5ZGMyZjYxN2JkZDZjYzJmZTk4NDNiZmE5NmQ3OTA3YmRlMWY4ZjM0NjNmOTU1NTljMTE3MDEyMTAzMjIwZWFjMjFiNzg2YTE5ODdkYTMzNWIwMjA4NTAyMGQ4MGQ1OGZkMWNmZDQyMGE1YTkzNTRmYjkxYjIzZmNmYTExM2IyNjAwIiwidHhpZCI6IjYyMzliNTQ0NTg3ZmRiOTlmMjkyMWI0M2E4MzkxMGFmMzYxY2RkNWIwYjNmNWFiZjJhNGIzMWQxNmJiYzlkZjYiLCJoYXNoIjoiZTdlMTM4YjYzMDNlNjk0YjY2ZDMwYWNjMjc1YjEzMWY1OWM2NmRkYTQxMmI0MzRjYTQ0YzE3MDQ2MWZkN2Q4NyIsInNpemUiOjIyMiwidnNpemUiOjE0MSwid2VpZ2h0Ijo1NjEsInZlcnNpb24iOjIsImxvY2t0aW1lIjoyNTA1NDg5LCJ2aW4iOlt7InR4aWQiOiJmOTBhMjhkMjZiMDlhZjdiMTcwMDFjNTgzMjc0ODA1ZGNiZmMwYzdlZWNlNTA5OGE4NDY0Yzk5MTk5NjNlY2IyIiwidm91dCI6MSwic2NyaXB0U2lnIjp7ImFzbSI6IiIsImhleCI6IiJ9LCJ0eGlud2l0bmVzcyI6WyIzMDQ0MDIyMDI4NTM2Mzg0NjU3NjA1NTk0NTA0MmRmMzgyMzc3ZjA3ZTZmZThkZGU0OWNiODhlNWE1MDkxMTVlMjFiZjE3MjAwMjIwNzFlYjE4MzBkMDNiOWRjMmY2MTdiZGQ2Y2MyZmU5ODQzYmZhOTZkNzkwN2JkZTFmOGYzNDYzZjk1NTU5YzExNzAxIiwiMDMyMjBlYWMyMWI3ODZhMTk4N2RhMzM1YjAyMDg1MDIwZDgwZDU4ZmQxY2ZkNDIwYTVhOTM1NGZiOTFiMjNmY2ZhIl0sInNlcXVlbmNlIjo0Mjk0OTY3MjkzfV0sInZvdXQiOlt7InZhbHVlIjowLjAxNTY1MTA5LCJuIjowLCJzY3JpcHRQdWJLZXkiOnsiYXNtIjoiMCBkNTE3YzI5OGExZGUxMjM1MzBkMTI0ZWIyMDdmM2MyMzE0MDVjMDk2IiwiaGV4IjoiMDAxNGQ1MTdjMjk4YTFkZTEyMzUzMGQxMjRlYjIwN2YzYzIzMTQwNWMwOTYiLCJ0eXBlIjoid2l0bmVzc192MF9rZXloYXNoIn19LHsidmFsdWUiOjg4LjY2NDA0MDE4LCJuIjoxLCJzY3JpcHRQdWJLZXkiOnsiYXNtIjoiMCAyY2Q3ZjVjMGRlMDhjZTNiNDQ0ZTViNTRiMzM0YmIwMjliNjRlNDIxIiwiaGV4IjoiMDAxNDJjZDdmNWMwZGUwOGNlM2I0NDRlNWI1NGIzMzRiYjAyOWI2NGU0MjEiLCJ0eXBlIjoid2l0bmVzc192MF9rZXloYXNoIn19XX0seyJoZXgiOiIwMjAwMDAwMDAxMWY1MjJhNTFmNGE1ZTE1MDA3OWQwY2MzMDMwNTE1YTRlYzMxNTg3OTMwYTI2ZTJlNjIyZjIzOGY0ZmY3OGE2OTAwMDAwMDAwNmE0NzMwNDQwMjIwNjA5YjI3MGY2ZDk4MTI3ZTIyOWIwNDUxZmFmMDZiNDcwYWUyZmU2NTFmZTcyZjNhMDJjZDZjM2Q5OWJkNTRhNzAyMjAzNTgzOWQxNTFkMTFmYTQxYzQ2YWVkODkyYzU0YmYwNGEyYjIzZGI3MzIxNDgwYTgyMWU3OWVhNjA1YWE5Nzk1MDEyMTAzNjc0YTI3NTc1NmRkZTg4MDZlY2Y2MjBhMzkzNjQ0M2IyN2FmZmMwZGIxYjI1YmY4MDhlOWViOGUwNTAwMjE5NGZkZmZmZmZmMDJhMjU5MWQwMDAwMDAwMDAwMTYwMDE0Njk0YWY5MjhiMTc5ZmRlODYwZmY0YmRlNzg3YTFiMjNhODkxN2M4NDI1MjhiYWNmMDEwMDAwMDAxNjAwMTQ3ZTYwYTY4YjRiZjU0MDhiZjk4NmI4ZWU4Njk1NjJhZWNmMWY3OGMzMTEzYjI2MDAiLCJ0eGlkIjoiOGU1NWFiZDdkOGJlYWI0NmU1YWJmZGM5OTk5NjUyYTM2OTNiM2MyYWQwYTg1MzQ2Y2MzYzc2MWY3YTdlNDFmOCIsImhhc2giOiI4ZTU1YWJkN2Q4YmVhYjQ2ZTVhYmZkYzk5OTk2NTJhMzY5M2IzYzJhZDBhODUzNDZjYzNjNzYxZjdhN2U0MWY4Iiwic2l6ZSI6MjE5LCJ2c2l6ZSI6MjE5LCJ3ZWlnaHQiOjg3NiwidmVyc2lvbiI6MiwibG9ja3RpbWUiOjI1MDU0ODksInZpbiI6W3sidHhpZCI6IjY5OGFmNzRmOGYyMzJmNjIyZTZlYTIzMDc5NTgzMWVjYTQxNTA1MDNjMzBjOWQwNzUwZTFhNWY0NTEyYTUyMWYiLCJ2b3V0IjowLCJzY3JpcHRTaWciOnsiYXNtIjoiMzA0NDAyMjA2MDliMjcwZjZkOTgxMjdlMjI5YjA0NTFmYWYwNmI0NzBhZTJmZTY1MWZlNzJmM2EwMmNkNmMzZDk5YmQ1NGE3MDIyMDM1ODM5ZDE1MWQxMWZhNDFjNDZhZWQ4OTJjNTRiZjA0YTJiMjNkYjczMjE0ODBhODIxZTc5ZWE2MDVhYTk3OTVbQUxMXSAwMzY3NGEyNzU3NTZkZGU4ODA2ZWNmNjIwYTM5MzY0NDNiMjdhZmZjMGRiMWIyNWJmODA4ZTllYjhlMDUwMDIxOTQiLCJoZXgiOiI0NzMwNDQwMjIwNjA5YjI3MGY2ZDk4MTI3ZTIyOWIwNDUxZmFmMDZiNDcwYWUyZmU2NTFmZTcyZjNhMDJjZDZjM2Q5OWJkNTRhNzAyMjAzNTgzOWQxNTFkMTFmYTQxYzQ2YWVkODkyYzU0YmYwNGEyYjIzZGI3MzIxNDgwYTgyMWU3OWVhNjA1YWE5Nzk1MDEyMTAzNjc0YTI3NTc1NmRkZTg4MDZlY2Y2MjBhMzkzNjQ0M2IyN2FmZmMwZGIxYjI1YmY4MDhlOWViOGUwNTAwMjE5NCJ9LCJzZXF1ZW5jZSI6NDI5NDk2NzI5M31dLCJ2b3V0IjpbeyJ2YWx1ZSI6MC4wMTkyMzQ5LCJuIjowLCJzY3JpcHRQdWJLZXkiOnsiYXNtIjoiMCA2OTRhZjkyOGIxNzlmZGU4NjBmZjRiZGU3ODdhMWIyM2E4OTE3Yzg0IiwiaGV4IjoiMDAxNDY5NGFmOTI4YjE3OWZkZTg2MGZmNGJkZTc4N2ExYjIzYTg5MTdjODQiLCJ0eXBlIjoid2l0bmVzc192MF9rZXloYXNoIn19LHsidmFsdWUiOjc3LjgwMDUwOTgxLCJuIjoxLCJzY3JpcHRQdWJLZXkiOnsiYXNtIjoiMCA3ZTYwYTY4YjRiZjU0MDhiZjk4NmI4ZWU4Njk1NjJhZWNmMWY3OGMzIiwiaGV4IjoiMDAxNDdlNjBhNjhiNGJmNTQwOGJmOTg2YjhlZTg2OTU2MmFlY2YxZjc4YzMiLCJ0eXBlIjoid2l0bmVzc192MF9rZXloYXNoIn19XX0seyJoZXgiOiIwMjAwMDAwMDAwMDEwMTFhNTVkZTNhMTRlZDExYzNmZmU5ZGM5YzI1NDc5MGNhNDY2NmRhMWIyOTAxNjY0Y2U2NmQzMDRhZjg0MTNhZjUwMDAwMDAwMDAwZmRmZmZmZmYwMmEyNTdhZDA4MDIwMDAwMDAxN2E5MTRiZDU3ZTViYjRiODI5ZTA2YTMxYmUyZDFiNTA0MDViYThjOGExN2U2ODc3NjM2MWEwMDAwMDAwMDAwMTdhOTE0ODFhNmZiOTU0MzJiNzJiY2MwMzkxZTkyNjIyNDI5OTRkNjkyMWVjYzg3MDI0NzMwNDQwMjIwNWVhNTg4ZjVhNTA5OTU1Mjc5NmQwZTgxYzg4ODg1MDgzZTgyNjAwMTNjYzJiMGQ1MTVmNTcwYzc1MzQ2NDgxZjAyMjAzMDlkNzc3MjAzZGRkZWU1MmZjYmEzN2Y3M2RhNjJmZmVmNGQ2MmNmNmU0ZWYzYjc1NGQwYzVkZWM0M2ZjOTVkMDEyMTAzNTEwOGE4YWRkNDM5MmQwZTJjNjA4MzQ2NWQwN2Q2NTBlMmQxMDljOWQ5OTk2YWM4NDJiNDhmZDZlMjljMzg4NjBiM2IyNjAwIiwidHhpZCI6IjJjNGQxY2Y3YTc5ODBmYWRmNWUyOTAzMDY3YzEyYTAwYTZiODM5YzUzYzJhZDBlZDk5NDhmMmYyYmMwZDZlZmMiLCJoYXNoIjoiYzJlMTk2NmRiZTQxYzgzZTFkZjVlODVlNGZhMGJjZjZmYWQ2OTA0YTM0MzA5YjNiMGNjNDNlN2JmMTlhZjY0MyIsInNpemUiOjIyNCwidnNpemUiOjE0Mywid2VpZ2h0Ijo1NjksInZlcnNpb24iOjIsImxvY2t0aW1lIjoyNTA1NDgzLCJ2aW4iOlt7InR4aWQiOiJmNTNhNDFmODRhMzA2ZGU2NGM2NjAxMjkxYmRhNjY0NmNhOTA0NzI1OWNkY2U5ZmZjMzExZWQxNDNhZGU1NTFhIiwidm91dCI6MCwic2NyaXB0U2lnIjp7ImFzbSI6IiIsImhleCI6IiJ9LCJ0eGlud2l0bmVzcyI6WyIzMDQ0MDIyMDVlYTU4OGY1YTUwOTk1NTI3OTZkMGU4MWM4ODg4NTA4M2U4MjYwMDEzY2MyYjBkNTE1ZjU3MGM3NTM0NjQ4MWYwMjIwMzA5ZDc3NzIwM2RkZGVlNTJmY2JhMzdmNzNkYTYyZmZlZjRkNjJjZjZlNGVmM2I3NTRkMGM1ZGVjNDNmYzk1ZDAxIiwiMDM1MTA4YThhZGQ0MzkyZDBlMmM2MDgzNDY1ZDA3ZDY1MGUyZDEwOWM5ZDk5OTZhYzg0MmI0OGZkNmUyOWMzODg2Il0sInNlcXVlbmNlIjo0Mjk0OTY3MjkzfV0sInZvdXQiOlt7InZhbHVlIjo4Ny4zNTUxMjQ4MiwibiI6MCwic2NyaXB0UHViS2V5Ijp7ImFzbSI6Ik9QX0hBU0gxNjAgYmQ1N2U1YmI0YjgyOWUwNmEzMWJlMmQxYjUwNDA1YmE4YzhhMTdlNiBPUF9FUVVBTCIsImhleCI6ImE5MTRiZDU3ZTViYjRiODI5ZTA2YTMxYmUyZDFiNTA0MDViYThjOGExN2U2ODciLCJ0eXBlIjoic2NyaXB0aGFzaCJ9fSx7InZhbHVlIjowLjAxNzE3ODc4LCJuIjoxLCJzY3JpcHRQdWJLZXkiOnsiYXNtIjoiT1BfSEFTSDE2MCA4MWE2ZmI5NTQzMmI3MmJjYzAzOTFlOTI2MjI0Mjk5NGQ2OTIxZWNjIE9QX0VRVUFMIiwiaGV4IjoiYTkxNDgxYTZmYjk1NDMyYjcyYmNjMDM5MWU5MjYyMjQyOTk0ZDY5MjFlY2M4NyIsInR5cGUiOiJzY3JpcHRoYXNoIn19XX0seyJoZXgiOiIwMjAwMDAwMDAwMDEwMWNmOTJmNDE2YzNlOWYzYzhhMmRjNDUyNjdkNWQ0ZGE0YTk0M2I0MTcxOGFjNTRiMTJlMTNkNjRiY2M1MTY1YmYwMTAwMDAwMDAwZmRmZmZmZmYwMjIzMTViNmZmMDEwMDAwMDAxNjAwMTQ0ZjY4NzMyOWRjODM5ZDNkOWRlYWJjMTM4MThkZmFlZjRlOWFiNmQ5N2M1ZjExMDAwMDAwMDAwMDE2MDAxNGQ0YTNlNzllZTBlMTM0NGNkNDY5N2VlYTM3NzY5ZjIyYTFjNTEyMzAwMjQ3MzA0NDAyMjAyMjQ5ZTg5MzE2ZTc4MWQ2OWQ2MjcxOWE3ZDNhYjQ4NTc1ZTRiNzVmNDY3NmFiNTRiNzZkZDlmMmEwY2FiZGU4MDIyMDc5MmQyMWIyZTk1ZTdiM2JmYTNkYTg2ZWE3NzgxMDhmYTg0NjQ2ZjU0NzBhMTdlYjBiOGEwZDNkNWEwY2YzYjMwMTIxMDI3ZjFlMGJjODQwMDhlNDg5MWQ4MGRhMTMxNWI2MjYzNmQ0NjI0ZThmYzJlMmU3NDJiY2NiNDI3ZjM1MTA4NTMyZDgzYTI2MDAiLCJ0eGlkIjoiMmU0OTE4YWM4MDQxNmQ2ODJmYzBkMzA5NTU2YzgyM2U5YzY3ZDI2OWMzMGYzMjQyYWI4Mjg5OGYyN2NjOTdmZSIsImhhc2giOiIxMTNmZGEzMjU0MzQ0MDgzN2IwZWVhYjc0NWFhNGFmY2Y4N2ExZGJmNzk1MDUyZjg5MjMxNTM0NjljNTg2ZjUzIiwic2l6ZSI6MjIyLCJ2c2l6ZSI6MTQxLCJ3ZWlnaHQiOjU2MSwidmVyc2lvbiI6MiwibG9ja3RpbWUiOjI1MDU0MzIsInZpbiI6W3sidHhpZCI6ImJmNjU1MWNjNGJkNjEzMmViMTU0YWMxODE3YjQ0M2E5YTQ0ZDVkN2QyNjQ1ZGNhMmM4ZjNlOWMzMTZmNDkyY2YiLCJ2b3V0IjoxLCJzY3JpcHRTaWciOnsiYXNtIjoiIiwiaGV4IjoiIn0sInR4aW53aXRuZXNzIjpbIjMwNDQwMjIwMjI0OWU4OTMxNmU3ODFkNjlkNjI3MTlhN2QzYWI0ODU3NWU0Yjc1ZjQ2NzZhYjU0Yjc2ZGQ5ZjJhMGNhYmRlODAyMjA3OTJkMjFiMmU5NWU3YjNiZmEzZGE4NmVhNzc4MTA4ZmE4NDY0NmY1NDcwYTE3ZWIwYjhhMGQzZDVhMGNmM2IzMDEiLCIwMjdmMWUwYmM4NDAwOGU0ODkxZDgwZGExMzE1YjYyNjM2ZDQ2MjRlOGZjMmUyZTc0MmJjY2I0MjdmMzUxMDg1MzIiXSwic2VxdWVuY2UiOjQyOTQ5NjcyOTN9XSwidm91dCI6W3sidmFsdWUiOjg1Ljg1MDkwMzM5LCJuIjowLCJzY3JpcHRQdWJLZXkiOnsiYXNtIjoiMCA0ZjY4NzMyOWRjODM5ZDNkOWRlYWJjMTM4MThkZmFlZjRlOWFiNmQ5IiwiaGV4IjoiMDAxNDRmNjg3MzI5ZGM4MzlkM2Q5ZGVhYmMxMzgxOGRmYWVmNGU5YWI2ZDkiLCJ0eXBlIjoid2l0bmVzc192MF9rZXloYXNoIn19LHsidmFsdWUiOjAuMDExMzg1NTYsIm4iOjEsInNjcmlwdFB1YktleSI6eyJhc20iOiIwIGQ0YTNlNzllZTBlMTM0NGNkNDY5N2VlYTM3NzY5ZjIyYTFjNTEyMzAiLCJoZXgiOiIwMDE0ZDRhM2U3OWVlMGUxMzQ0Y2Q0Njk3ZWVhMzc3NjlmMjJhMWM1MTIzMCIsInR5cGUiOiJ3aXRuZXNzX3YwX2tleWhhc2gifX1dfSx7ImhleCI6IjAxMDAwMDAwMDAwMTAxNTZlOThmNzcwOGM4OTFiMDY4MmUyNWE4MWM1ZDljNjE2ZWUxMTkwYTFlOTQ0YTBhOTZkNGU5YTkwNzk0N2U3ODAxMDAwMDAwMDBmZmZmZmZmZjAyZjk0OTAwMDAwMDAwMDAwMDE5NzZhOTE0NjYxNzdiZGFkNmM2NzM0NTBiYjMzZGU5MWE2OThiNzY0OGU2ODJjMTg4YWNiOWFlNzUzZTE3MDAwMDAwMTYwMDE0NmFiMTQzOWM2YzQzMzU0NmYxNjU1YjYwYTYzOWUzYjVlOGE2YzQ1ZDAyNDgzMDQ1MDIyMTAwZDUyMzkxM2Q1NTBhMzA0YmI1NWE0YTliNTFjYmNiZWY4MGUwMmQ4MGQzY2I2NWI3ZjkzZGNlODcxZDg5MjQ2ZDAyMjAyMmRhMTM2NTllMzhkY2ZlMmFkMWY4ZTlmZjZkOTdiMWNiOWIxZWMyMjUyODFmNjQyZWMzNDM2YzNjZjRhYjdjMDEyMTAzODQ2ZjczNjZlNGY3ODE4ZWMxN2U2ZDEzYjFlOTQ3ZmUxMDJhZTdhNjA2MWEzYmU1MGU3Mzg4YjMzNWIxYzc4ODAwMDAwMDAwIiwidHhpZCI6IjJkZWM0N2MyMjI3ZGRhYWFkYmVhYmFhNGQzYjJkNjgwYmVlNjcyYjQyYmViMjFjYjE4MDRlZTZiNzI4MWNkODQiLCJoYXNoIjoiMWUzNTM5NmYzOTg2MTY2MDMyNDE4NTEyNmM0YjhjODc5ZjQyN2JmNmIyMWIwODdmYTYxMmU5MmIxOGJlZDg4MiIsInNpemUiOjIyNiwidnNpemUiOjE0NCwid2VpZ2h0Ijo1NzQsInZlcnNpb24iOjEsImxvY2t0aW1lIjowLCJ2aW4iOlt7InR4aWQiOiI3ODdlOTQwN2E5ZTlkNDk2MGE0YTk0MWUwYTE5ZTE2ZTYxOWM1ZDFjYTgyNTJlNjhiMDkxYzgwODc3OGZlOTU2Iiwidm91dCI6MSwic2NyaXB0U2lnIjp7ImFzbSI6IiIsImhleCI6IiJ9LCJ0eGlud2l0bmVzcyI6WyIzMDQ1MDIyMTAwZDUyMzkxM2Q1NTBhMzA0YmI1NWE0YTliNTFjYmNiZWY4MGUwMmQ4MGQzY2I2NWI3ZjkzZGNlODcxZDg5MjQ2ZDAyMjAyMmRhMTM2NTllMzhkY2ZlMmFkMWY4ZTlmZjZkOTdiMWNiOWIxZWMyMjUyODFmNjQyZWMzNDM2YzNjZjRhYjdjMDEiLCIwMzg0NmY3MzY2ZTRmNzgxOGVjMTdlNmQxM2IxZTk0N2ZlMTAyYWU3YTYwNjFhM2JlNTBlNzM4OGIzMzViMWM3ODgiXSwic2VxdWVuY2UiOjQyOTQ5NjcyOTV9XSwidm91dCI6W3sidmFsdWUiOjAuMDAwMTg5MzcsIm4iOjAsInNjcmlwdFB1YktleSI6eyJhc20iOiJPUF9EVVAgT1BfSEFTSDE2MCA2NjE3N2JkYWQ2YzY3MzQ1MGJiMzNkZTkxYTY5OGI3NjQ4ZTY4MmMxIE9QX0VRVUFMVkVSSUZZIE9QX0NIRUNLU0lHIiwiaGV4IjoiNzZhOTE0NjYxNzdiZGFkNmM2NzM0NTBiYjMzZGU5MWE2OThiNzY0OGU2ODJjMTg4YWMiLCJ0eXBlIjoicHVia2V5aGFzaCJ9fSx7InZhbHVlIjo5OTguMzIxNDc2NDEsIm4iOjEsInNjcmlwdFB1YktleSI6eyJhc20iOiIwIDZhYjE0MzljNmM0MzM1NDZmMTY1NWI2MGE2MzllM2I1ZThhNmM0NWQiLCJoZXgiOiIwMDE0NmFiMTQzOWM2YzQzMzU0NmYxNjU1YjYwYTYzOWUzYjVlOGE2YzQ1ZCIsInR5cGUiOiJ3aXRuZXNzX3YwX2tleWhhc2gifX1dfSx7ImhleCI6IjAxMDAwMDAwMDEzZTE2YWQ1ODAwYzExNzBlMTY3OWQ1Y2Q4MzA5ZjI1NTY4NzM0ODQzYjcwODMwZjI0NTljZWZkODk5NzE0MzhlMDMwMDAwMDA2YTQ3MzA0NDAyMjAzY2RjNDM0YWZiZjAxOTQzZWU5MjgxMTcxNWU5ZmM2ZGYxZmZlMDI1Y2YzNzFiYzAzNDY5YjkxM2MzODQ1MTUyMDIyMDZiYjQyMzc4YzY4OWNjMjFmNzNjNDAzZmM1ZWNhMWQ0ZmM4YzU0MjNiYjBiMjgyNDUzMTg4ZWQ0NmJhMDhkMjgwMTIxMDM3NDM1YzE5NGU5YjAxYjNkN2Y3YTI4MDJkNjY4NGEzYWY2OGQwNWJiZjRlYzhmMTcwMjE5ODBkNzc3NjkxZjFkZmRmZmZmZmYwNDAwMDAwMDAwMDAwMDAwMDA1MzZhNGM1MDU0MzI1YjQxYTRkNjVjOWFjM2Y3NjJlZDRmYmUxOTdiODU1NzUwMzBjZjkyMzE4NTVkZTliNjEyYzRjMTc4NmEyZjA4NDZiNzU2YTgzNDEwZjdiMDcwNDc0YjUzNGIyYjNkOGMzMzFhYWE4NzkzMzY5M2ZiYTA4YjZlMTM4OWY4ZGZkZjJhMDAyNjNiMTEwMDAzMDAyNWNkMzUwMDBiNGMxMDI3MDAwMDAwMDAwMDAwMTk3NmE5MTQwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwODhhYzEwMjcwMDAwMDAwMDAwMDAxOTc2YTkxNDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDA4OGFjZTY1NjJlMDMwMDAwMDAwMDE5NzZhOTE0YmEyN2Y5OWUwMDdjN2Y2MDVhODMwNWUzMThjMWFiZGUzY2QyMjBhYzg4YWMwMDAwMDAwMCIsInR4aWQiOiJmYjk5NDE2MGE4NmE1YzdmOTAyMjlhZTU3ODQyNjY1NjRjNGZlZGJjOGM2NTdlNDlhODRiYzk3ZDlkNWU4NDdhIiwiaGFzaCI6ImZiOTk0MTYwYTg2YTVjN2Y5MDIyOWFlNTc4NDI2NjU2NGM0ZmVkYmM4YzY1N2U0OWE4NGJjOTdkOWQ1ZTg0N2EiLCJzaXplIjozNTEsInZzaXplIjozNTEsIndlaWdodCI6MTQwNCwidmVyc2lvbiI6MSwibG9ja3RpbWUiOjAsInZpbiI6W3sidHhpZCI6IjhlNDM3MTk5ZDhlZjljNDVmMjMwMDhiNzQzNDg3MzY4NTVmMjA5ODNjZGQ1NzkxNjBlMTdjMTAwNThhZDE2M2UiLCJ2b3V0IjozLCJzY3JpcHRTaWciOnsiYXNtIjoiMzA0NDAyMjAzY2RjNDM0YWZiZjAxOTQzZWU5MjgxMTcxNWU5ZmM2ZGYxZmZlMDI1Y2YzNzFiYzAzNDY5YjkxM2MzODQ1MTUyMDIyMDZiYjQyMzc4YzY4OWNjMjFmNzNjNDAzZmM1ZWNhMWQ0ZmM4YzU0MjNiYjBiMjgyNDUzMTg4ZWQ0NmJhMDhkMjhbQUxMXSAwMzc0MzVjMTk0ZTliMDFiM2Q3ZjdhMjgwMmQ2Njg0YTNhZjY4ZDA1YmJmNGVjOGYxNzAyMTk4MGQ3Nzc2OTFmMWQiLCJoZXgiOiI0NzMwNDQwMjIwM2NkYzQzNGFmYmYwMTk0M2VlOTI4MTE3MTVlOWZjNmRmMWZmZTAyNWNmMzcxYmMwMzQ2OWI5MTNjMzg0NTE1MjAyMjA2YmI0MjM3OGM2ODljYzIxZjczYzQwM2ZjNWVjYTFkNGZjOGM1NDIzYmIwYjI4MjQ1MzE4OGVkNDZiYTA4ZDI4MDEyMTAzNzQzNWMxOTRlOWIwMWIzZDdmN2EyODAyZDY2ODRhM2FmNjhkMDViYmY0ZWM4ZjE3MDIxOTgwZDc3NzY5MWYxZCJ9LCJzZXF1ZW5jZSI6NDI5NDk2NzI5M31dLCJ2b3V0IjpbeyJ2YWx1ZSI6MCwibiI6MCwic2NyaXB0UHViS2V5Ijp7ImFzbSI6Ik9QX1JFVFVSTiA1NDMyNWI0MWE0ZDY1YzlhYzNmNzYyZWQ0ZmJlMTk3Yjg1NTc1MDMwY2Y5MjMxODU1ZGU5YjYxMmM0YzE3ODZhMmYwODQ2Yjc1NmE4MzQxMGY3YjA3MDQ3NGI1MzRiMmIzZDhjMzMxYWFhODc5MzM2OTNmYmEwOGI2ZTEzODlmOGRmZGYyYTAwMjYzYjExMDAwMzAwMjVjZDM1MDAwYjRjIiwiaGV4IjoiNmE0YzUwNTQzMjViNDFhNGQ2NWM5YWMzZjc2MmVkNGZiZTE5N2I4NTU3NTAzMGNmOTIzMTg1NWRlOWI2MTJjNGMxNzg2YTJmMDg0NmI3NTZhODM0MTBmN2IwNzA0NzRiNTM0YjJiM2Q4YzMzMWFhYTg3OTMzNjkzZmJhMDhiNmUxMzg5ZjhkZmRmMmEwMDI2M2IxMTAwMDMwMDI1Y2QzNTAwMGI0YyIsInR5cGUiOiJudWxsZGF0YSJ9fSx7InZhbHVlIjowLjAwMDEsIm4iOjEsInNjcmlwdFB1YktleSI6eyJhc20iOiJPUF9EVVAgT1BfSEFTSDE2MCAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwIE9QX0VRVUFMVkVSSUZZIE9QX0NIRUNLU0lHIiwiaGV4IjoiNzZhOTE0MDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDg4YWMiLCJ0eXBlIjoicHVia2V5aGFzaCJ9fSx7InZhbHVlIjowLjAwMDEsIm4iOjIsInNjcmlwdFB1YktleSI6eyJhc20iOiJPUF9EVVAgT1BfSEFTSDE2MCAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwIE9QX0VRVUFMVkVSSUZZIE9QX0NIRUNLU0lHIiwiaGV4IjoiNzZhOTE0MDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDg4YWMiLCJ0eXBlIjoicHVia2V5aGFzaCJ9fSx7InZhbHVlIjowLjUzMzY4NTUsIm4iOjMsInNjcmlwdFB1YktleSI6eyJhc20iOiJPUF9EVVAgT1BfSEFTSDE2MCBiYTI3Zjk5ZTAwN2M3ZjYwNWE4MzA1ZTMxOGMxYWJkZTNjZDIyMGFjIE9QX0VRVUFMVkVSSUZZIE9QX0NIRUNLU0lHIiwiaGV4IjoiNzZhOTE0YmEyN2Y5OWUwMDdjN2Y2MDVhODMwNWUzMThjMWFiZGUzY2QyMjBhYzg4YWMiLCJ0eXBlIjoicHVia2V5aGFzaCJ9fV19LHsiaGV4IjoiMDIwMDAwMDAwMDAxMDI5ZmMzYmZkMDhiYjMwZWNiNWZkMjA2ZTgwZWRhOTgwMWJmZGQzZDYzMDc3YWYyMGQxMTY1ZWU1NjE1MWQwZTAzMDAwMDAwMDAwMGZmZmZmZmZmOWZjM2JmZDA4YmIzMGVjYjVmZDIwNmU4MGVkYTk4MDFiZmRkM2Q2MzA3N2FmMjBkMTE2NWVlNTYxNTFkMGUwMzAxMDAwMDAwMDBmZmZmZmZmZjAyM2RmZTFiMDAwMDAwMDAwMDE2MDAxNGM2OGQyYjYyYWQxNDQ4MmM5NWU2NDdjZWQxZTk2ZDRhNjZhYzc0YzY0MDQyMGYwMDAwMDAwMDAwMTYwMDE0MWZjNmYyOGYwMTM1NzBmMGVmMjgyZjRkODdiZjAzYjM4MjFjNmU1MzAyNDczMDQ0MDIyMDQyNWYzZTU2ZTA5YTJlYmYyZTkwYzE3MjYzOTlmM2MzNmI4ZTMwYzFlYTY1NDIxZTAxZDIyMjcwNDYyOTQ4ZDIwMjIwNjg5ZjZmYTIxZThhMzY2OTY1MDQ2MDUwYWZkOGY2MTAyMmY1NzE1YzJkMGFkZTEwMjVkMzM1ZDkzMDQ4YWIwYTAxMjEwMzA5MWFlMWI5ZDNmMWQ5MWQ3ZGE1YjEyZTgyODk3ZDdlYzBmZDhhMzU3ODNlMDg4NTMxYjRiYTUwM2IwOGYwMmUwMjQ3MzA0NDAyMjAxNTI3ZTUyYzc1MDFmNTNiY2E5ZTZkYzRkMGQ1YzhhODZjNjRmY2M0ZjczNjc5ZmVhMDRhNzJmNGYwM2JmZmE2MDIyMDQ5YmIyNmEwMTMzYjk4Yzg3YWFmODk1OTc2ZmM4ZGJhMzlkYWVhYTAxMmZiOGRiMjU0ZWI4MDA3YzdjOWI1NTIwMTIxMDMxYTdjZGM3OTFlMmFkMTQ1YmMzZGU0MTVkMjNmYzk2MmQ2ZTAyMjJlNDI4OGY0Mzk0YWMwZDI2NDJlNTJhM2M4MDAwMDAwMDAiLCJ0eGlkIjoiZDBmMjNiN2ExOWJlMWE0YTA2MWMwZTViNDA2ZWRhZDA3ZmQyMjdkOGQ2NWZkYTZhMjNjZmE0NGFjYTAwZGYwZSIsImhhc2giOiJiMDhjNmMwOGE4YjY2ZWVjMGNmMzQ0NGNjNGQ4MTAzZDdiMjExNDliMWQ2NTkxNjkzYjZhMTNlMTA3YjQzMWM3Iiwic2l6ZSI6MzcwLCJ2c2l6ZSI6MjA4LCJ3ZWlnaHQiOjgzMiwidmVyc2lvbiI6MiwibG9ja3RpbWUiOjAsInZpbiI6W3sidHhpZCI6IjAzMGUxZDE1NTZlZTY1MTEwZGYyN2EwNzYzM2RkZGJmMDE5OGRhMGVlODA2ZDI1ZmNiMGViMzhiZDBiZmMzOWYiLCJ2b3V0IjowLCJzY3JpcHRTaWciOnsiYXNtIjoiIiwiaGV4IjoiIn0sInR4aW53aXRuZXNzIjpbIjMwNDQwMjIwNDI1ZjNlNTZlMDlhMmViZjJlOTBjMTcyNjM5OWYzYzM2YjhlMzBjMWVhNjU0MjFlMDFkMjIyNzA0NjI5NDhkMjAyMjA2ODlmNmZhMjFlOGEzNjY5NjUwNDYwNTBhZmQ4ZjYxMDIyZjU3MTVjMmQwYWRlMTAyNWQzMzVkOTMwNDhhYjBhMDEiLCIwMzA5MWFlMWI5ZDNmMWQ5MWQ3ZGE1YjEyZTgyODk3ZDdlYzBmZDhhMzU3ODNlMDg4NTMxYjRiYTUwM2IwOGYwMmUiXSwic2VxdWVuY2UiOjQyOTQ5NjcyOTV9LHsidHhpZCI6IjAzMGUxZDE1NTZlZTY1MTEwZGYyN2EwNzYzM2RkZGJmMDE5OGRhMGVlODA2ZDI1ZmNiMGViMzhiZDBiZmMzOWYiLCJ2b3V0IjoxLCJzY3JpcHRTaWciOnsiYXNtIjoiIiwiaGV4IjoiIn0sInR4aW53aXRuZXNzIjpbIjMwNDQwMjIwMTUyN2U1MmM3NTAxZjUzYmNhOWU2ZGM0ZDBkNWM4YTg2YzY0ZmNjNGY3MzY3OWZlYTA0YTcyZjRmMDNiZmZhNjAyMjA0OWJiMjZhMDEzM2I5OGM4N2FhZjg5NTk3NmZjOGRiYTM5ZGFlYWEwMTJmYjhkYjI1NGViODAwN2M3YzliNTUyMDEiLCIwMzFhN2NkYzc5MWUyYWQxNDViYzNkZTQxNWQyM2ZjOTYyZDZlMDIyMmU0Mjg4ZjQzOTRhYzBkMjY0MmU1MmEzYzgiXSwic2VxdWVuY2UiOjQyOTQ5NjcyOTV9XSwidm91dCI6W3sidmFsdWUiOjAuMDE4MzQ1NTcsIm4iOjAsInNjcmlwdFB1YktleSI6eyJhc20iOiIwIGM2OGQyYjYyYWQxNDQ4MmM5NWU2NDdjZWQxZTk2ZDRhNjZhYzc0YzYiLCJoZXgiOiIwMDE0YzY4ZDJiNjJhZDE0NDgyYzk1ZTY0N2NlZDFlOTZkNGE2NmFjNzRjNiIsInR5cGUiOiJ3aXRuZXNzX3YwX2tleWhhc2gifX0seyJ2YWx1ZSI6MC4wMSwibiI6MSwic2NyaXB0UHViS2V5Ijp7ImFzbSI6IjAgMWZjNmYyOGYwMTM1NzBmMGVmMjgyZjRkODdiZjAzYjM4MjFjNmU1MyIsImhleCI6IjAwMTQxZmM2ZjI4ZjAxMzU3MGYwZWYyODJmNGQ4N2JmMDNiMzgyMWM2ZTUzIiwidHlwZSI6IndpdG5lc3NfdjBfa2V5aGFzaCJ9fV19LHsiaGV4IjoiMDIwMDAwMDAwMDAxMDM0NDg5NmU2YTc0ZDQyMjZkNmEwZjhlZDdkMDkyNjZiM2UzYzg1NGM1NGI4ZmU4NjJkNzIwMzhiYTM3MTE0OTBjMDAwMDAwMDAwMGZmZmZmZmZmNDQ4OTZlNmE3NGQ0MjI2ZDZhMGY4ZWQ3ZDA5MjY2YjNlM2M4NTRjNTRiOGZlODYyZDcyMDM4YmEzNzExNDkwYzAxMDAwMDAwMDBmZmZmZmZmZjdlM2M4YTAyYTVkNTJiMTJhNTExYzA5Zjg4MzY2MTFmYjMzYWFmNzdjMTYwNDc4MGYwYzFmODI3YWFkN2E5MzAwMDAwMDAwMDAwZmZmZmZmZmYwMjQwNDIwZjAwMDAwMDAwMDAxNjAwMTQ2YjRkM2IzZmExM2Y1MWE5MjFlMDQxNzdlYTVhNWQ2NGU5MGJlNTIxODVlNDBlMDAwMDAwMDAwMDE2MDAxNGQ2ODNhZmRjYjJmNGUyNmI3OWU1ZGEyYjljNzkwMGNhOTdhZWQ2NTgwMjQ3MzA0NDAyMjAzZDRmYjc0Zjc0OTBlYzIzNjIyZjdmM2IyMDc3YTFmOGY1ZWIwZjEwYzgyMWVjZWYyZTdmOWM3YjUyNDliZjcwMDIyMDU3OWIxNjIwZTE0NGRjNTIxYzFhY2M0NjdmYTQ3YmYzYThkYWE1MzMwOWY4Y2NlZGNhMDlhN2UyZmY4OWMxN2MwMTIxMDM5Y2M5ZDhkYzc3OGViYjM4OTcyOTZhNTM5NTBiYzE0ZDAwNmVkZjA2NzJhZTZlODM0ZGEzODM3NTE1ZDM2MTBlMDI0NzMwNDQwMjIwNDQ1OGExY2FhZThlMGY2NDM3YWYyODhjNDY4YTI5NTczMWVlNzA2N2EzYzA5MDdhMTg3MWY5MjJjZGY2OThkZDAyMjA0OWU3MTliMjMzNzEzMWE5MzhlYjJmNTZkNGVjNGVjNmVkYmQ4YmYyZDg3YTIwOTE5ZGZmMjkxOWY4MDY0NjhhMDEyMTAyOWE0YTM4ZjFjMTc2ODFlNThjZjJhNWQxN2I2OTY3MmYyMjgwZjY4NDRlMGRkMDNlYTgwM2E5YWJiYWRmNTU0YTAyNDczMDQ0MDIyMDBlNWIxZjlhOTU3MDYyODBlZDMxZjc3YmFkMTNjNzUyYThlYTEwMDI3NGIwZWJiMjE0M2RlZjNjYzQxOWRmNGMwMjIwMjg0MDFlYjNjYjJiMDIzMDA1MDZjMDVlMTA1ZWYyNWFkZDk5NDcxMDVmMGE4MmE4YzNiNDQ3MzQ4NGZjNmY5ZDAxMjEwMzg2ZDQ0MmRhZWUxMTcxOGZkMGJiYjdiYWY2NzdkM2E1ZDBlYTAwYTQ5MGQ1ZjdkNDNmYzNkZjk0NzJhODM5MGQwMDAwMDAwMCIsInR4aWQiOiI1NjdmZTJjMmUxZjJiMzg3ZjE3ZmEwZDU4OTA4MGE2MjZkNjEyODllYzVmNTM3MTYyMTFkZDA1NmQxMWQ3NDM3IiwiaGFzaCI6IjdiOTQ4YzRkNWUyNjA5MWNlOGFlOGQzMWMyOWViNDJiZjdlZTYxZjY2YTQzYjQ0MWYyMmE3MmJjYmQ5YjFiYmQiLCJzaXplIjo1MTgsInZzaXplIjoyNzYsIndlaWdodCI6MTEwMywidmVyc2lvbiI6MiwibG9ja3RpbWUiOjAsInZpbiI6W3sidHhpZCI6IjBjNDkxMTM3YmEzODIwZDc2MmU4OGY0YmM1NTRjOGUzYjM2NjkyZDBkNzhlMGY2YTZkMjJkNDc0NmE2ZTg5NDQiLCJ2b3V0IjowLCJzY3JpcHRTaWciOnsiYXNtIjoiIiwiaGV4IjoiIn0sInR4aW53aXRuZXNzIjpbIjMwNDQwMjIwM2Q0ZmI3NGY3NDkwZWMyMzYyMmY3ZjNiMjA3N2ExZjhmNWViMGYxMGM4MjFlY2VmMmU3ZjljN2I1MjQ5YmY3MDAyMjA1NzliMTYyMGUxNDRkYzUyMWMxYWNjNDY3ZmE0N2JmM2E4ZGFhNTMzMDlmOGNjZWRjYTA5YTdlMmZmODljMTdjMDEiLCIwMzljYzlkOGRjNzc4ZWJiMzg5NzI5NmE1Mzk1MGJjMTRkMDA2ZWRmMDY3MmFlNmU4MzRkYTM4Mzc1MTVkMzYxMGUiXSwic2VxdWVuY2UiOjQyOTQ5NjcyOTV9LHsidHhpZCI6IjBjNDkxMTM3YmEzODIwZDc2MmU4OGY0YmM1NTRjOGUzYjM2NjkyZDBkNzhlMGY2YTZkMjJkNDc0NmE2ZTg5NDQiLCJ2b3V0IjoxLCJzY3JpcHRTaWciOnsiYXNtIjoiIiwiaGV4IjoiIn0sInR4aW53aXRuZXNzIjpbIjMwNDQwMjIwNDQ1OGExY2FhZThlMGY2NDM3YWYyODhjNDY4YTI5NTczMWVlNzA2N2EzYzA5MDdhMTg3MWY5MjJjZGY2OThkZDAyMjA0OWU3MTliMjMzNzEzMWE5MzhlYjJmNTZkNGVjNGVjNmVkYmQ4YmYyZDg3YTIwOTE5ZGZmMjkxOWY4MDY0NjhhMDEiLCIwMjlhNGEzOGYxYzE3NjgxZTU4Y2YyYTVkMTdiNjk2NzJmMjI4MGY2ODQ0ZTBkZDAzZWE4MDNhOWFiYmFkZjU1NGEiXSwic2VxdWVuY2UiOjQyOTQ5NjcyOTV9LHsidHhpZCI6IjMwYTlkN2FhMjdmOGMxZjA4MDQ3NjBjMTc3YWYzYWIzMWY2MTM2ODg5ZmMwMTFhNTEyMmJkNWE1MDI4YTNjN2UiLCJ2b3V0IjowLCJzY3JpcHRTaWciOnsiYXNtIjoiIiwiaGV4IjoiIn0sInR4aW53aXRuZXNzIjpbIjMwNDQwMjIwMGU1YjFmOWE5NTcwNjI4MGVkMzFmNzdiYWQxM2M3NTJhOGVhMTAwMjc0YjBlYmIyMTQzZGVmM2NjNDE5ZGY0YzAyMjAyODQwMWViM2NiMmIwMjMwMDUwNmMwNWUxMDVlZjI1YWRkOTk0NzEwNWYwYTgyYThjM2I0NDczNDg0ZmM2ZjlkMDEiLCIwMzg2ZDQ0MmRhZWUxMTcxOGZkMGJiYjdiYWY2NzdkM2E1ZDBlYTAwYTQ5MGQ1ZjdkNDNmYzNkZjk0NzJhODM5MGQiXSwic2VxdWVuY2UiOjQyOTQ5NjcyOTV9XSwidm91dCI6W3sidmFsdWUiOjAuMDEsIm4iOjAsInNjcmlwdFB1YktleSI6eyJhc20iOiIwIDZiNGQzYjNmYTEzZjUxYTkyMWUwNDE3N2VhNWE1ZDY0ZTkwYmU1MjEiLCJoZXgiOiIwMDE0NmI0ZDNiM2ZhMTNmNTFhOTIxZTA0MTc3ZWE1YTVkNjRlOTBiZTUyMSIsInR5cGUiOiJ3aXRuZXNzX3YwX2tleWhhc2gifX0seyJ2YWx1ZSI6MC4wMDk3NjAwNSwibiI6MSwic2NyaXB0UHViS2V5Ijp7ImFzbSI6IjAgZDY4M2FmZGNiMmY0ZTI2Yjc5ZTVkYTJiOWM3OTAwY2E5N2FlZDY1OCIsImhleCI6IjAwMTRkNjgzYWZkY2IyZjRlMjZiNzllNWRhMmI5Yzc5MDBjYTk3YWVkNjU4IiwidHlwZSI6IndpdG5lc3NfdjBfa2V5aGFzaCJ9fV19LHsiaGV4IjoiMDEwMDAwMDAwMDAxMDEwOTZlMDYwNWJmMWUxZjFkZjZlNGJkMjQ2ODBlZGNmYzY0YjE5ZTZiZWM4MmI2NTU5N2Q3M2I4ZjQ3YmEyZTJkMDEwMDAwMDAyMzIyMDAyMDM4ZGJhOTg1NzdhNWFkZTBiZjQwOGViMjU2MjVjNmQ5YWQ4ZjM0YzY2MjcxNzczOTQ1Nzk0YTdlZjM2NGJjZDRmZmZmZmZmZjAyMDI0YTAwMDAwMDAwMDAwMDE2MDAxNDhlZDIyYWFkNzQ5YmRjY2UxOTQxMGNlZWM5NzIyMjkwYjg0NDIxZjczMmFhMzEwMDAwMDAwMDAwMTdhOTE0Y2FiNWZlMGQzYzJmMjlkMjI2ZjgwMDcyYzNkM2M2ZjU4MGZkMzgxZjg3MDQwMDQ3MzA0NDAyMjAxZTUyMjRmZWE5MTEyYjI2ODRlMDgwYjMzZDI3ZTBiMzY3ZDY0ZTFkMTI3NzU2NmQwZGY2YzU5OGY2Y2E5MTkyMDIyMDE1MWZhZmQ1OTJjNzAzNTgzNTliNTg2MTEyM2RjMWQ4OThlYmMyOTQ0OGEyY2I1MWY2NGNkZmJjZDgwZWUzYTEwMTQ3MzA0NDAyMjA1ZGQ4ZGE2NDQ1NTBiODAwOWMwMGFmOWNhNzA4YmU1Yzk2YzJhNjAzMmIxZjdmYTRlY2IwYWYwYmJlZjAwODAyMDIyMDdhOTBkNWNiM2Q5OTg0MTljNGQ2MDAxZTQ5YWY5NWZlZTNlNDY0OTA1NWMwNTNhMTg1NWVjNzE1NjA0OTFiMjgwMTQ3NTIyMTAzOWY5NTM3NzQyMzUxMWQwNWJlOTk2MzNhMzM3YTFlNmMzY2E0Y2IwZDhhMDA4ZDBmNDk4Y2JjNmQ3YmE4MzMwMjIxMDNmMTVmZGUzYjU2ZGQ3NzViYjY2YzU2MDlhODc2Y2QxZjZkNjhhM2UxM2MzNWM2MGY2NWFmN2Q1MmIyNjAxODIzNTJhZTAwMDAwMDAwIiwidHhpZCI6Ijk5NWEyMzY1YmVlZDY3Y2QwOTY1ZjQ2ZTUzZDkxNzMzOTgyNjM5NzU5NjViOTU2Nzg2ZTQxNzAwZmJkZTRlYjgiLCJoYXNoIjoiNjU1OTQ3NWEzODI5NTIyNzFlOGMwNTBhOWU4NDBjNzliYTg2OTVmODU0ZDAwMDM1ZDJjZjJmMzA5YTkwMDVlZiIsInNpemUiOjM2OSwidnNpemUiOjIwNCwid2VpZ2h0Ijo4MTYsInZlcnNpb24iOjEsImxvY2t0aW1lIjowLCJ2aW4iOlt7InR4aWQiOiIyZDJlYmE0NzhmM2JkNzk3NTViNjgyZWM2YjllYjE2NGZjZGMwZTY4MjRiZGU0ZjYxZDFmMWViZjA1MDY2ZTA5Iiwidm91dCI6MSwic2NyaXB0U2lnIjp7ImFzbSI6IjAwMjAzOGRiYTk4NTc3YTVhZGUwYmY0MDhlYjI1NjI1YzZkOWFkOGYzNGM2NjI3MTc3Mzk0NTc5NGE3ZWYzNjRiY2Q0IiwiaGV4IjoiMjIwMDIwMzhkYmE5ODU3N2E1YWRlMGJmNDA4ZWIyNTYyNWM2ZDlhZDhmMzRjNjYyNzE3NzM5NDU3OTRhN2VmMzY0YmNkNCJ9LCJ0eGlud2l0bmVzcyI6WyIiLCIzMDQ0MDIyMDFlNTIyNGZlYTkxMTJiMjY4NGUwODBiMzNkMjdlMGIzNjdkNjRlMWQxMjc3NTY2ZDBkZjZjNTk4ZjZjYTkxOTIwMjIwMTUxZmFmZDU5MmM3MDM1ODM1OWI1ODYxMTIzZGMxZDg5OGViYzI5NDQ4YTJjYjUxZjY0Y2RmYmNkODBlZTNhMTAxIiwiMzA0NDAyMjA1ZGQ4ZGE2NDQ1NTBiODAwOWMwMGFmOWNhNzA4YmU1Yzk2YzJhNjAzMmIxZjdmYTRlY2IwYWYwYmJlZjAwODAyMDIyMDdhOTBkNWNiM2Q5OTg0MTljNGQ2MDAxZTQ5YWY5NWZlZTNlNDY0OTA1NWMwNTNhMTg1NWVjNzE1NjA0OTFiMjgwMSIsIjUyMjEwMzlmOTUzNzc0MjM1MTFkMDViZTk5NjMzYTMzN2ExZTZjM2NhNGNiMGQ4YTAwOGQwZjQ5OGNiYzZkN2JhODMzMDIyMTAzZjE1ZmRlM2I1NmRkNzc1YmI2NmM1NjA5YTg3NmNkMWY2ZDY4YTNlMTNjMzVjNjBmNjVhZjdkNTJiMjYwMTgyMzUyYWUiXSwic2VxdWVuY2UiOjQyOTQ5NjcyOTV9XSwidm91dCI6W3sidmFsdWUiOjAuMDAwMTg5NDYsIm4iOjAsInNjcmlwdFB1YktleSI6eyJhc20iOiIwIDhlZDIyYWFkNzQ5YmRjY2UxOTQxMGNlZWM5NzIyMjkwYjg0NDIxZjciLCJoZXgiOiIwMDE0OGVkMjJhYWQ3NDliZGNjZTE5NDEwY2VlYzk3MjIyOTBiODQ0MjFmNyIsInR5cGUiOiJ3aXRuZXNzX3YwX2tleWhhc2gifX0seyJ2YWx1ZSI6MC4wMzI1NDgzNCwibiI6MSwic2NyaXB0UHViS2V5Ijp7ImFzbSI6Ik9QX0hBU0gxNjAgY2FiNWZlMGQzYzJmMjlkMjI2ZjgwMDcyYzNkM2M2ZjU4MGZkMzgxZiBPUF9FUVVBTCIsImhleCI6ImE5MTRjYWI1ZmUwZDNjMmYyOWQyMjZmODAwNzJjM2QzYzZmNTgwZmQzODFmODciLCJ0eXBlIjoic2NyaXB0aGFzaCJ9fV19LHsiaGV4IjoiMDIwMDAwMDAwMDAxMDE2YjUwNTQyZGM2MjlhNzRlZjc3YjE5NDMxZjg2MjI2NmUxMWU3ZGE4YWJiMjU5N2NlOTY1MjdkMGE3ZTE5NTRhMDEwMDAwMDAwMGZmZmZmZmZmMDJkMDA3MDAwMDAwMDAwMDAwMjI1MTIwYmVkN2Y3YzQwMDcxOTYzNjdhNzVlNmUwZWFhNjAwMzk1OTQ0ZjIwMGQyMWNlM2IwZDE4MmQ0NTkzZDk0OTQ0MjkzZGIwZDAwMDAwMDAwMDAyMjUxMjBmNGQ2NmZjN2IxNzg3ZGJlNTdkZDM2YjY0Y2M3NGE3YTQ4NTMxZmEwZWJlNjA4NzBkZWZjYjRhZGEyZGU3YWQzMDE0MDdmNDFlYzE0YzI2YzczZTU4OWYzYmNhNjhhNGU0NDhlMWQyZTZkMTk1MWUwYTg1MTBkMDA3ZjMyZWMzMjBhNjFiOGVkNTI1ZWZhMjcyYzc4MGM4YTc0MTc1ODMwZTY2YjVmM2VlODEyMDI4OTczNDM5ODk0ZmU3NDIwMzE1YzE1MDAwMDAwMDAiLCJ0eGlkIjoiMDQ5MmMyMDViMmZhZTMyNTIxZDkyYjc5ZTZlNTE2MzkxMWVhOTIzNWFhM2U3YjZmZDliODYzNmUwZGI4OTQ0NCIsImhhc2giOiI3YzNjN2I3MDcwMDljZTEyOTgxYTNhOTY1NDIzNDA0ZWQzMTJjZDFkNjJmZGZlOThlODg2NTRhY2VkYTczYWJjIiwic2l6ZSI6MjA1LCJ2c2l6ZSI6MTU0LCJ3ZWlnaHQiOjYxNiwidmVyc2lvbiI6MiwibG9ja3RpbWUiOjAsInZpbiI6W3sidHhpZCI6IjRhOTVlMWE3ZDAyNzY1ZTk3YzU5YjJhYmE4N2QxZWUxNjYyMjg2MWY0MzE5N2JmNzRlYTcyOWM2MmQ1NDUwNmIiLCJ2b3V0IjoxLCJzY3JpcHRTaWciOnsiYXNtIjoiIiwiaGV4IjoiIn0sInR4aW53aXRuZXNzIjpbIjdmNDFlYzE0YzI2YzczZTU4OWYzYmNhNjhhNGU0NDhlMWQyZTZkMTk1MWUwYTg1MTBkMDA3ZjMyZWMzMjBhNjFiOGVkNTI1ZWZhMjcyYzc4MGM4YTc0MTc1ODMwZTY2YjVmM2VlODEyMDI4OTczNDM5ODk0ZmU3NDIwMzE1YzE1Il0sInNlcXVlbmNlIjo0Mjk0OTY3Mjk1fV0sInZvdXQiOlt7InZhbHVlIjowLjAwMDAyLCJuIjowLCJzY3JpcHRQdWJLZXkiOnsiYXNtIjoiMSBiZWQ3ZjdjNDAwNzE5NjM2N2E3NWU2ZTBlYWE2MDAzOTU5NDRmMjAwZDIxY2UzYjBkMTgyZDQ1OTNkOTQ5NDQyIiwiaGV4IjoiNTEyMGJlZDdmN2M0MDA3MTk2MzY3YTc1ZTZlMGVhYTYwMDM5NTk0NGYyMDBkMjFjZTNiMGQxODJkNDU5M2Q5NDk0NDIiLCJ0eXBlIjoid2l0bmVzc192MV90YXByb290In19LHsidmFsdWUiOjAuMDA5MDgxNzksIm4iOjEsInNjcmlwdFB1YktleSI6eyJhc20iOiIxIGY0ZDY2ZmM3YjE3ODdkYmU1N2RkMzZiNjRjYzc0YTdhNDg1MzFmYTBlYmU2MDg3MGRlZmNiNGFkYTJkZTdhZDMiLCJoZXgiOiI1MTIwZjRkNjZmYzdiMTc4N2RiZTU3ZGQzNmI2NGNjNzRhN2E0ODUzMWZhMGViZTYwODcwZGVmY2I0YWRhMmRlN2FkMyIsInR5cGUiOiJ3aXRuZXNzX3YxX3RhcHJvb3QifX1dfSx7ImhleCI6IjAyMDAwMDAwMDAwMTAxNDQ5NGI4MGQ2ZTYzYjhkOTZmN2IzZWFhMzU5MmVhMTEzOTE2ZTVlNjc5MmJkOTIxMjVlM2ZhYjIwNWMyOTIwNDAwMDAwMDAwMDBmZGZmZmZmZjAyMjIwMjAwMDAwMDAwMDAwMDIyNTEyMGY0ZDY2ZmM3YjE3ODdkYmU1N2RkMzZiNjRjYzc0YTdhNDg1MzFmYTBlYmU2MDg3MGRlZmNiNGFkYTJkZTdhZDNmODA0MDAwMDAwMDAwMDAwMTYwMDE0YmRmZDZlMGU4ODljZTU3YzlhZGJmZTgxN2IyNjk3ODZjYTA4MjFkMzAzNDA5YWNjZWRjMmU1Mjk2NjdhOGZiZjRkNDM4MzAyNjIzODcxZmMyODczMWEwYTA3YTBkMTMzNTI5YzRmMzNmMGM2Y2NkYzAwODg3MzBhNDU0NDc5YTUyMzcyMWMwNzNlYjM5ODA2OGNiMjYxZmNlMTA4ODYxNjgyMDcxZDVjNjQ3MjdkMjBiN2VjYTFmNmI2YmUwNDM5Y2I0YTc3Y2E3OTE3ZWY2NjU4MzIxOGNiYjVmYWIzZjZiZjJiYmE5ODM1ZTg3ZGMzYWMwMDYzMDM2ZjcyNjQwMTAxMTg3NDY1Nzg3NDJmNzA2YzYxNjk2ZTNiNjM2ODYxNzI3MzY1NzQzZDc1NzQ2NjJkMzgwMDM3N2IyMjcwMjIzYTIyNjI3MjYzMmQzMjMwMjIyYzIyNmY3MDIyM2EyMjc0NzI2MTZlNzM2NjY1NzIyMjJjMjI3NDY5NjM2YjIyM2EyMjczNjE3NDczMjIyYzIyNjE2ZDc0MjIzYTIyMzUzMDIyN2Q2ODIxYzEzZjdmNDYwZWU2ZDVkNjM3YmE4NTZjMjc2M2M5ZWEzNWUxOTE5YTZiOTkzOTRmMTQ1ZmMxMTc2ZDRhYTUyMDNkMDAwMDAwMDAiLCJ0eGlkIjoiYTE2MWJkZGEyMWY3ZWY1YjJjZDk2MzgyY2ZjZWQwYTg5NDFhMTJlYjMyYmUwZjg5ZjQyODRjNjgyZGY1Y2E5MyIsImhhc2giOiI4NWNkYzllZWY5ZDU1YmM2YWM2M2QwNGUzMjhlNGMwMzFhNzYyNmYxOTJlMTljZTYyNzVlZGM3NjUwNjNlMDJkIiwic2l6ZSI6MzUzLCJ2c2l6ZSI6MTgyLCJ3ZWlnaHQiOjcyOCwidmVyc2lvbiI6MiwibG9ja3RpbWUiOjAsInZpbiI6W3sidHhpZCI6IjA0OTJjMjA1YjJmYWUzMjUyMWQ5MmI3OWU2ZTUxNjM5MTFlYTkyMzVhYTNlN2I2ZmQ5Yjg2MzZlMGRiODk0NDQiLCJ2b3V0IjowLCJzY3JpcHRTaWciOnsiYXNtIjoiIiwiaGV4IjoiIn0sInR4aW53aXRuZXNzIjpbIjlhY2NlZGMyZTUyOTY2N2E4ZmJmNGQ0MzgzMDI2MjM4NzFmYzI4NzMxYTBhMDdhMGQxMzM1MjljNGYzM2YwYzZjY2RjMDA4ODczMGE0NTQ0NzlhNTIzNzIxYzA3M2ViMzk4MDY4Y2IyNjFmY2UxMDg4NjE2ODIwNzFkNWM2NDcyIiwiMjBiN2VjYTFmNmI2YmUwNDM5Y2I0YTc3Y2E3OTE3ZWY2NjU4MzIxOGNiYjVmYWIzZjZiZjJiYmE5ODM1ZTg3ZGMzYWMwMDYzMDM2ZjcyNjQwMTAxMTg3NDY1Nzg3NDJmNzA2YzYxNjk2ZTNiNjM2ODYxNzI3MzY1NzQzZDc1NzQ2NjJkMzgwMDM3N2IyMjcwMjIzYTIyNjI3MjYzMmQzMjMwMjIyYzIyNmY3MDIyM2EyMjc0NzI2MTZlNzM2NjY1NzIyMjJjMjI3NDY5NjM2YjIyM2EyMjczNjE3NDczMjIyYzIyNjE2ZDc0MjIzYTIyMzUzMDIyN2Q2OCIsImMxM2Y3ZjQ2MGVlNmQ1ZDYzN2JhODU2YzI3NjNjOWVhMzVlMTkxOWE2Yjk5Mzk0ZjE0NWZjMTE3NmQ0YWE1MjAzZCJdLCJzZXF1ZW5jZSI6NDI5NDk2NzI5M31dLCJ2b3V0IjpbeyJ2YWx1ZSI6MC4wMDAwMDU0NiwibiI6MCwic2NyaXB0UHViS2V5Ijp7ImFzbSI6IjEgZjRkNjZmYzdiMTc4N2RiZTU3ZGQzNmI2NGNjNzRhN2E0ODUzMWZhMGViZTYwODcwZGVmY2I0YWRhMmRlN2FkMyIsImhleCI6IjUxMjBmNGQ2NmZjN2IxNzg3ZGJlNTdkZDM2YjY0Y2M3NGE3YTQ4NTMxZmEwZWJlNjA4NzBkZWZjYjRhZGEyZGU3YWQzIiwidHlwZSI6IndpdG5lc3NfdjFfdGFwcm9vdCJ9fSx7InZhbHVlIjowLjAwMDAxMjcyLCJuIjoxLCJzY3JpcHRQdWJLZXkiOnsiYXNtIjoiMCBiZGZkNmUwZTg4OWNlNTdjOWFkYmZlODE3YjI2OTc4NmNhMDgyMWQzIiwiaGV4IjoiMDAxNGJkZmQ2ZTBlODg5Y2U1N2M5YWRiZmU4MTdiMjY5Nzg2Y2EwODIxZDMiLCJ0eXBlIjoid2l0bmVzc192MF9rZXloYXNoIn19XX0seyJoZXgiOiIwMjAwMDAwMDAwMDEwMjkzY2FmNTJkNjg0YzI4ZjQ4OTBmYmUzMmViMTIxYTk0YThkMGNlY2Y4MjYzZDkyYzViZWZmNzIxZGFiZDYxYTEwMDAwMDAwMDAwZmZmZmZmZmY0NDk0YjgwZDZlNjNiOGQ5NmY3YjNlYWEzNTkyZWExMTM5MTZlNWU2NzkyYmQ5MjEyNWUzZmFiMjA1YzI5MjA0MDEwMDAwMDAwMGZmZmZmZmZmMDIwMTAwMDAwMDAwMDAwMDAwMjI2YTIwNDUyN2QxM2MzZmFmYWQzMmEwMTZlMGNkNGM2MTViNjVlZjFkN2ZiMTliZmFlM2JjNmRjOGUxNDEyZTFiN2M1Y2RhZGMwZDAwMDAwMDAwMDAyMjUxMjBmNGQ2NmZjN2IxNzg3ZGJlNTdkZDM2YjY0Y2M3NGE3YTQ4NTMxZmEwZWJlNjA4NzBkZWZjYjRhZGEyZGU3YWQzMDE0MDM5OTViYmE3ZjhlNmQyNzc0MzU5ZjVlZmU1OTc1YWM3YTYzY2RiNTJkMDUyYTEyNmVhYzBhMTgwYWJmN2ZkNGI5ZTdjZmJlOTRjYTYzMjMyYTc0ZTk0NzY3MGQ1YjBjNWRlYjY5YmY3OTE1NDc2ODIzODFiODUxYzgwMzJiMzM1MDE0MDNmZTA1MzA5OGI1ZWExYzM3MjQ1YTM1NzYzMjQ5MmE0YTVhMGQzZmFjYjUwODZlNTNhNGZkNmI3N2M4YzVjMjYzNDIwMDQ2OTE1MzMwMzE0NjhlZGY2YjVjYWRhMTM3ZDBhNDAwZDkxMzJiODFjOWEzMDRhNDk2NDAxMzc4MDJhMDAwMDAwMDAiLCJ0eGlkIjoiY2Q3ZTA5MDU3OWZlMThlMGQ5NGIzZTIxMWEyNGIwOWU1NzdmMjc5NGE0YWNmY2QzZGU0YWUwNjYzMWMwYzU1MCIsImhhc2giOiJiY2Q3OTA2MGMyMjRiOTA1ZmNiMmQyNzc5NWVmMjZjMTA4NzgwNDlmODA3ZWIyM2UyNDE0ZTFlMjkwZjE4MGY5Iiwic2l6ZSI6MzEyLCJ2c2l6ZSI6MjEyLCJ3ZWlnaHQiOjg0NiwidmVyc2lvbiI6MiwibG9ja3RpbWUiOjAsInZpbiI6W3sidHhpZCI6ImExNjFiZGRhMjFmN2VmNWIyY2Q5NjM4MmNmY2VkMGE4OTQxYTEyZWIzMmJlMGY4OWY0Mjg0YzY4MmRmNWNhOTMiLCJ2b3V0IjowLCJzY3JpcHRTaWciOnsiYXNtIjoiIiwiaGV4IjoiIn0sInR4aW53aXRuZXNzIjpbIjM5OTViYmE3ZjhlNmQyNzc0MzU5ZjVlZmU1OTc1YWM3YTYzY2RiNTJkMDUyYTEyNmVhYzBhMTgwYWJmN2ZkNGI5ZTdjZmJlOTRjYTYzMjMyYTc0ZTk0NzY3MGQ1YjBjNWRlYjY5YmY3OTE1NDc2ODIzODFiODUxYzgwMzJiMzM1Il0sInNlcXVlbmNlIjo0Mjk0OTY3Mjk1fSx7InR4aWQiOiIwNDkyYzIwNWIyZmFlMzI1MjFkOTJiNzllNmU1MTYzOTExZWE5MjM1YWEzZTdiNmZkOWI4NjM2ZTBkYjg5NDQ0Iiwidm91dCI6MSwic2NyaXB0U2lnIjp7ImFzbSI6IiIsImhleCI6IiJ9LCJ0eGlud2l0bmVzcyI6WyIzZmUwNTMwOThiNWVhMWMzNzI0NWEzNTc2MzI0OTJhNGE1YTBkM2ZhY2I1MDg2ZTUzYTRmZDZiNzdjOGM1YzI2MzQyMDA0NjkxNTMzMDMxNDY4ZWRmNmI1Y2FkYTEzN2QwYTQwMGQ5MTMyYjgxYzlhMzA0YTQ5NjQwMTM3ODAyYSJdLCJzZXF1ZW5jZSI6NDI5NDk2NzI5NX1dLCJ2b3V0IjpbeyJ2YWx1ZSI6MWUtOCwibiI6MCwic2NyaXB0UHViS2V5Ijp7ImFzbSI6Ik9QX1JFVFVSTiA0NTI3ZDEzYzNmYWZhZDMyYTAxNmUwY2Q0YzYxNWI2NWVmMWQ3ZmIxOWJmYWUzYmM2ZGM4ZTE0MTJlMWI3YzVjIiwiaGV4IjoiNmEyMDQ1MjdkMTNjM2ZhZmFkMzJhMDE2ZTBjZDRjNjE1YjY1ZWYxZDdmYjE5YmZhZTNiYzZkYzhlMTQxMmUxYjdjNWMiLCJ0eXBlIjoibnVsbGRhdGEifX0seyJ2YWx1ZSI6MC4wMDkwODUwNiwibiI6MSwic2NyaXB0UHViS2V5Ijp7ImFzbSI6IjEgZjRkNjZmYzdiMTc4N2RiZTU3ZGQzNmI2NGNjNzRhN2E0ODUzMWZhMGViZTYwODcwZGVmY2I0YWRhMmRlN2FkMyIsImhleCI6IjUxMjBmNGQ2NmZjN2IxNzg3ZGJlNTdkZDM2YjY0Y2M3NGE3YTQ4NTMxZmEwZWJlNjA4NzBkZWZjYjRhZGEyZGU3YWQzIiwidHlwZSI6IndpdG5lc3NfdjFfdGFwcm9vdCJ9fV19LHsiaGV4IjoiMDIwMDAwMDAwMDAxMDE1MGM1YzAzMTY2ZTA0YWRlZDNmY2FjYTQ5NDI3N2Y1NzllYjAyNDFhMjEzZTRiZDllMDE4ZmU3OTA1MDk3ZWNkMDEwMDAwMDAwMGZmZmZmZmZmMDIwODRjMDEwMDAwMDAwMDAwMjI1MTIwNWYxZDczMGYzZGYxYmIxZjIzYzU0NmE0ZWQ1MGQwMmE0NDhmY2FjODM5ZjU4ZmM3YmJjMTgyOTQyNGYwZGQ1OTk5N2UwYzAwMDAwMDAwMDAyMjUxMjBmNGQ2NmZjN2IxNzg3ZGJlNTdkZDM2YjY0Y2M3NGE3YTQ4NTMxZmEwZWJlNjA4NzBkZWZjYjRhZGEyZGU3YWQzMDE0MDc4ZDZhOWQ0ZjJjOGRlNzE5ZGM2ZDM5ZjQxMGEzZDcyM2M4NjgwMmRjMTZjZjBjY2JhOGQ3Y2I3MGZlNjgxYWZkYTViMTRlZjdmOWU3ZTE1NWMzZjY5MjMyZDA5NTQ1ODliZWY0NGU0YmFiN2IyZGZmMGE5OTU0MThhOTc4MTE1MDAwMDAwMDAiLCJ0eGlkIjoiZmFhY2E1ZTNkNjdiMWRhMGVlZjY2ODJlZGM3OGMzMGI5Zjc4MjY4MzdkNzY4OWU4YzA5YWU0OWFjNTlkMmEyNCIsImhhc2giOiIxODg5ZTgwZDMwM2MzZTg1OWVmODNiNGY4Njg3ZGZjNDIzYTJhNGM4YzRkZDE1ZTA3Yjc3ZjY4YWYxZTkzOTJlIiwic2l6ZSI6MjA1LCJ2c2l6ZSI6MTU0LCJ3ZWlnaHQiOjYxNiwidmVyc2lvbiI6MiwibG9ja3RpbWUiOjAsInZpbiI6W3sidHhpZCI6ImNkN2UwOTA1NzlmZTE4ZTBkOTRiM2UyMTFhMjRiMDllNTc3ZjI3OTRhNGFjZmNkM2RlNGFlMDY2MzFjMGM1NTAiLCJ2b3V0IjoxLCJzY3JpcHRTaWciOnsiYXNtIjoiIiwiaGV4IjoiIn0sInR4aW53aXRuZXNzIjpbIjc4ZDZhOWQ0ZjJjOGRlNzE5ZGM2ZDM5ZjQxMGEzZDcyM2M4NjgwMmRjMTZjZjBjY2JhOGQ3Y2I3MGZlNjgxYWZkYTViMTRlZjdmOWU3ZTE1NWMzZjY5MjMyZDA5NTQ1ODliZWY0NGU0YmFiN2IyZGZmMGE5OTU0MThhOTc4MTE1Il0sInNlcXVlbmNlIjo0Mjk0OTY3Mjk1fV0sInZvdXQiOlt7InZhbHVlIjowLjAwMDg1LCJuIjowLCJzY3JpcHRQdWJLZXkiOnsiYXNtIjoiMSA1ZjFkNzMwZjNkZjFiYjFmMjNjNTQ2YTRlZDUwZDAyYTQ0OGZjYWM4MzlmNThmYzdiYmMxODI5NDI0ZjBkZDU5IiwiaGV4IjoiNTEyMDVmMWQ3MzBmM2RmMWJiMWYyM2M1NDZhNGVkNTBkMDJhNDQ4ZmNhYzgzOWY1OGZjN2JiYzE4Mjk0MjRmMGRkNTkiLCJ0eXBlIjoid2l0bmVzc192MV90YXByb290In19LHsidmFsdWUiOjAuMDA4MTg4NDEsIm4iOjEsInNjcmlwdFB1YktleSI6eyJhc20iOiIxIGY0ZDY2ZmM3YjE3ODdkYmU1N2RkMzZiNjRjYzc0YTdhNDg1MzFmYTBlYmU2MDg3MGRlZmNiNGFkYTJkZTdhZDMiLCJoZXgiOiI1MTIwZjRkNjZmYzdiMTc4N2RiZTU3ZGQzNmI2NGNjNzRhN2E0ODUzMWZhMGViZTYwODcwZGVmY2I0YWRhMmRlN2FkMyIsInR5cGUiOiJ3aXRuZXNzX3YxX3RhcHJvb3QifX1dfSx7ImhleCI6IjAyMDAwMDAwMDAwMTAxMjQyYTlkYzU5YWU0OWFjMGU4ODk3NjdkODMyNjc4OWYwYmMzNzhkYzJlNjhmNmVlYTAxZDdiZDZlM2E1YWNmYTAwMDAwMDAwMDBmZGZmZmZmZjBiMjIwMjAwMDAwMDAwMDAwMDIyNTEyMGY0ZDY2ZmM3YjE3ODdkYmU1N2RkMzZiNjRjYzc0YTdhNDg1MzFmYTBlYmU2MDg3MGRlZmNiNGFkYTJkZTdhZDNiNjEzMDAwMDAwMDAwMDAwMjI1MTIwZDliMTIyMmU4Nzg1NThmOWY3ZWYzYjc0NjQyM2JkNzNjNTdmNmNmYjVhMzJiMjE2NDZjOTI3NTc3ZjZlZGRjMGI2MTMwMDAwMDAwMDAwMDAyMjUxMjA2MDg3ZTc2ZWQ2NzIzZjhmYThlYjhhYjBmNjYzM2IyMmIzMzg2NjU3MGQ0NDZmNDBkMzY1MmNjNDhiODg4MjczYjYxMzAwMDAwMDAwMDAwMDIyNTEyMGU5NzFmNDE4N2E4Mjg5YTI3MDExOWYzNzcxMzRmNGZkMzdjNTdiNjZjN2FlOTM4NDI2N2QzNjkwNzcxMWVhOTBiNjEzMDAwMDAwMDAwMDAwMjI1MTIwMDVlM2U1ZDk5MTZlZjY3OTYwYzkyOTdjM2QyYzIxODE3YjZlYzRhMmQ1ZWE1NzM4ZmYwNDlhMzkyMWM0ZTc3MGI2MTMwMDAwMDAwMDAwMDAyMjUxMjA2Y2MzZGRlODQ4ODRkZGYyOTRmMTY0NWMwOTUzNTVhZWIwZGYxNDZmYzQyYTEwMzdjYTQ0ZWJkYzJhMTBiZDMwYjYxMzAwMDAwMDAwMDAwMDIyNTEyMDVhN2NhYzI0YjI5ZTEyNjY5NjhjNjFlMmNmMGVjMGQ5ODliZTNhM2Q1YTMwMzIyZWRmMWZhOGI1NjdlNzY1YzliNjEzMDAwMDAwMDAwMDAwMjI1MTIwYzA4N2JlM2Y3NWEwNGU4YmFlYjE1MjUwNTVjNDViNzA2ODYxMDcxY2E1MDI5NDY2ODliZWQ1ZGE2ZWZkNmIzMmI2MTMwMDAwMDAwMDAwMDAyMjUxMjBhYTZhNjczMzY5NjQwNzFkNGJhZmM1MDFmMjUxZmM2NzcyMDIxOWQ0ODA1NjIzMDA5MmZhMjg1ZjdmMjUzMzliYjYxMzAwMDAwMDAwMDAwMDIyNTEyMDQ2MWE2ZjhhOTRmOTM2NWNiNzUwZGVkMzhhMzkwZWU5YjY1ZmQxNzg1YTI3N2I3NWYxZWY3NmRiOTBiN2U1NWNmMDU1MDAwMDAwMDAwMDAwMTYwMDE0YmRmZDZlMGU4ODljZTU3YzlhZGJmZTgxN2IyNjk3ODZjYTA4MjFkMzAzNDA4OTBjMjU1MmFiOWQzNGRhZmVhZjI3YTg5YWM3YjBkODEzYTllOTAxOTU0Zjk0OTg0ZWNiNjRiNDc3YjBlNWIwNjRiYTMzZDA1ZDZkYTM0NmQ0NjBlY2QxNzI1ZTdmOTM0MjljMzU3ZjEwMDNjM2IwNTQxM2M0MDM1MDJmMjk0NTc4MjAyODJiNWJjNWVhN2I0MGNjYTkwNzNmOGI3ZjNlZTYxMGUyMTk2ZjczYzcwNGZmNzk2NmE3YWY2OTQ0OGM4ZmY1YWMwMDYzMDM2ZjcyNjQwMTAxMTg3NDY1Nzg3NDJmNzA2YzYxNjk2ZTNiNjM2ODYxNzI3MzY1NzQzZDc1NzQ2NjJkMzgwMDMyN2IyMjcwMjIzYTIyNjI3MjYzMmQzMjMwMjIyYzIyNmY3MDIyM2EyMjZkNjk2ZTc0MjIyYzIyNzQ2OTYzNmIyMjNhMjI3MDc1NmU2YjIyMmMyMjYxNmQ3NDIyM2EyMjMxMjI3ZDY4MjFjMWMxYzIyNGIyODM0N2IzZWE2NjMyYTQ3NTMzYjk0NDQ2OGI1ZTAxZWM1NTA5NDE2ODNlZWUxZWZkNGNhYzNiYzAwMDAwMDAwMCIsInR4aWQiOiJlNzg2MGUxNTE1Yzk2YzU2ODg0NzM2Yzk0MzY1ZDU5NzdjNGRiOGEyMzA0ZTU4Yzg1OGI5MDg0YWVhYWU4NGY5IiwiaGFzaCI6ImUzZTM3M2MzOTQ1MWM3YjZkNWQyNTE1ZmIwODAxOTdmMmQzOGRhNTI3ZWNlNTg1ZDJkMWM4ODE1YmZlMTgzMDMiLCJzaXplIjo3MzUsInZzaXplIjo1NjgsIndlaWdodCI6MjI3MSwidmVyc2lvbiI6MiwibG9ja3RpbWUiOjAsInZpbiI6W3sidHhpZCI6ImZhYWNhNWUzZDY3YjFkYTBlZWY2NjgyZWRjNzhjMzBiOWY3ODI2ODM3ZDc2ODllOGMwOWFlNDlhYzU5ZDJhMjQiLCJ2b3V0IjowLCJzY3JpcHRTaWciOnsiYXNtIjoiIiwiaGV4IjoiIn0sInR4aW53aXRuZXNzIjpbIjg5MGMyNTUyYWI5ZDM0ZGFmZWFmMjdhODlhYzdiMGQ4MTNhOWU5MDE5NTRmOTQ5ODRlY2I2NGI0NzdiMGU1YjA2NGJhMzNkMDVkNmRhMzQ2ZDQ2MGVjZDE3MjVlN2Y5MzQyOWMzNTdmMTAwM2MzYjA1NDEzYzQwMzUwMmYyOTQ1IiwiMjAyODJiNWJjNWVhN2I0MGNjYTkwNzNmOGI3ZjNlZTYxMGUyMTk2ZjczYzcwNGZmNzk2NmE3YWY2OTQ0OGM4ZmY1YWMwMDYzMDM2ZjcyNjQwMTAxMTg3NDY1Nzg3NDJmNzA2YzYxNjk2ZTNiNjM2ODYxNzI3MzY1NzQzZDc1NzQ2NjJkMzgwMDMyN2IyMjcwMjIzYTIyNjI3MjYzMmQzMjMwMjIyYzIyNmY3MDIyM2EyMjZkNjk2ZTc0MjIyYzIyNzQ2OTYzNmIyMjNhMjI3MDc1NmU2YjIyMmMyMjYxNmQ3NDIyM2EyMjMxMjI3ZDY4IiwiYzFjMWMyMjRiMjgzNDdiM2VhNjYzMmE0NzUzM2I5NDQ0NjhiNWUwMWVjNTUwOTQxNjgzZWVlMWVmZDRjYWMzYmMwIl0sInNlcXVlbmNlIjo0Mjk0OTY3MjkzfV0sInZvdXQiOlt7InZhbHVlIjowLjAwMDAwNTQ2LCJuIjowLCJzY3JpcHRQdWJLZXkiOnsiYXNtIjoiMSBmNGQ2NmZjN2IxNzg3ZGJlNTdkZDM2YjY0Y2M3NGE3YTQ4NTMxZmEwZWJlNjA4NzBkZWZjYjRhZGEyZGU3YWQzIiwiaGV4IjoiNTEyMGY0ZDY2ZmM3YjE3ODdkYmU1N2RkMzZiNjRjYzc0YTdhNDg1MzFmYTBlYmU2MDg3MGRlZmNiNGFkYTJkZTdhZDMiLCJ0eXBlIjoid2l0bmVzc192MV90YXByb290In19LHsidmFsdWUiOjAuMDAwMDUwNDYsIm4iOjEsInNjcmlwdFB1YktleSI6eyJhc20iOiIxIGQ5YjEyMjJlODc4NTU4ZjlmN2VmM2I3NDY0MjNiZDczYzU3ZjZjZmI1YTMyYjIxNjQ2YzkyNzU3N2Y2ZWRkYzAiLCJoZXgiOiI1MTIwZDliMTIyMmU4Nzg1NThmOWY3ZWYzYjc0NjQyM2JkNzNjNTdmNmNmYjVhMzJiMjE2NDZjOTI3NTc3ZjZlZGRjMCIsInR5cGUiOiJ3aXRuZXNzX3YxX3RhcHJvb3QifX0seyJ2YWx1ZSI6MC4wMDAwNTA0NiwibiI6Miwic2NyaXB0UHViS2V5Ijp7ImFzbSI6IjEgNjA4N2U3NmVkNjcyM2Y4ZmE4ZWI4YWIwZjY2MzNiMjJiMzM4NjY1NzBkNDQ2ZjQwZDM2NTJjYzQ4Yjg4ODI3MyIsImhleCI6IjUxMjA2MDg3ZTc2ZWQ2NzIzZjhmYThlYjhhYjBmNjYzM2IyMmIzMzg2NjU3MGQ0NDZmNDBkMzY1MmNjNDhiODg4MjczIiwidHlwZSI6IndpdG5lc3NfdjFfdGFwcm9vdCJ9fSx7InZhbHVlIjowLjAwMDA1MDQ2LCJuIjozLCJzY3JpcHRQdWJLZXkiOnsiYXNtIjoiMSBlOTcxZjQxODdhODI4OWEyNzAxMTlmMzc3MTM0ZjRmZDM3YzU3YjY2YzdhZTkzODQyNjdkMzY5MDc3MTFlYTkwIiwiaGV4IjoiNTEyMGU5NzFmNDE4N2E4Mjg5YTI3MDExOWYzNzcxMzRmNGZkMzdjNTdiNjZjN2FlOTM4NDI2N2QzNjkwNzcxMWVhOTAiLCJ0eXBlIjoid2l0bmVzc192MV90YXByb290In19LHsidmFsdWUiOjAuMDAwMDUwNDYsIm4iOjQsInNjcmlwdFB1YktleSI6eyJhc20iOiIxIDA1ZTNlNWQ5OTE2ZWY2Nzk2MGM5Mjk3YzNkMmMyMTgxN2I2ZWM0YTJkNWVhNTczOGZmMDQ5YTM5MjFjNGU3NzAiLCJoZXgiOiI1MTIwMDVlM2U1ZDk5MTZlZjY3OTYwYzkyOTdjM2QyYzIxODE3YjZlYzRhMmQ1ZWE1NzM4ZmYwNDlhMzkyMWM0ZTc3MCIsInR5cGUiOiJ3aXRuZXNzX3YxX3RhcHJvb3QifX0seyJ2YWx1ZSI6MC4wMDAwNTA0NiwibiI6NSwic2NyaXB0UHViS2V5Ijp7ImFzbSI6IjEgNmNjM2RkZTg0ODg0ZGRmMjk0ZjE2NDVjMDk1MzU1YWViMGRmMTQ2ZmM0MmExMDM3Y2E0NGViZGMyYTEwYmQzMCIsImhleCI6IjUxMjA2Y2MzZGRlODQ4ODRkZGYyOTRmMTY0NWMwOTUzNTVhZWIwZGYxNDZmYzQyYTEwMzdjYTQ0ZWJkYzJhMTBiZDMwIiwidHlwZSI6IndpdG5lc3NfdjFfdGFwcm9vdCJ9fSx7InZhbHVlIjowLjAwMDA1MDQ2LCJuIjo2LCJzY3JpcHRQdWJLZXkiOnsiYXNtIjoiMSA1YTdjYWMyNGIyOWUxMjY2OTY4YzYxZTJjZjBlYzBkOTg5YmUzYTNkNWEzMDMyMmVkZjFmYThiNTY3ZTc2NWM5IiwiaGV4IjoiNTEyMDVhN2NhYzI0YjI5ZTEyNjY5NjhjNjFlMmNmMGVjMGQ5ODliZTNhM2Q1YTMwMzIyZWRmMWZhOGI1NjdlNzY1YzkiLCJ0eXBlIjoid2l0bmVzc192MV90YXByb290In19LHsidmFsdWUiOjAuMDAwMDUwNDYsIm4iOjcsInNjcmlwdFB1YktleSI6eyJhc20iOiIxIGMwODdiZTNmNzVhMDRlOGJhZWIxNTI1MDU1YzQ1YjcwNjg2MTA3MWNhNTAyOTQ2Njg5YmVkNWRhNmVmZDZiMzIiLCJoZXgiOiI1MTIwYzA4N2JlM2Y3NWEwNGU4YmFlYjE1MjUwNTVjNDViNzA2ODYxMDcxY2E1MDI5NDY2ODliZWQ1ZGE2ZWZkNmIzMiIsInR5cGUiOiJ3aXRuZXNzX3YxX3RhcHJvb3QifX0seyJ2YWx1ZSI6MC4wMDAwNTA0NiwibiI6OCwic2NyaXB0UHViS2V5Ijp7ImFzbSI6IjEgYWE2YTY3MzM2OTY0MDcxZDRiYWZjNTAxZjI1MWZjNjc3MjAyMTlkNDgwNTYyMzAwOTJmYTI4NWY3ZjI1MzM5YiIsImhleCI6IjUxMjBhYTZhNjczMzY5NjQwNzFkNGJhZmM1MDFmMjUxZmM2NzcyMDIxOWQ0ODA1NjIzMDA5MmZhMjg1ZjdmMjUzMzliIiwidHlwZSI6IndpdG5lc3NfdjFfdGFwcm9vdCJ9fSx7InZhbHVlIjowLjAwMDA1MDQ2LCJuIjo5LCJzY3JpcHRQdWJLZXkiOnsiYXNtIjoiMSA0NjFhNmY4YTk0ZjkzNjVjYjc1MGRlZDM4YTM5MGVlOWI2NWZkMTc4NWEyNzdiNzVmMWVmNzZkYjkwYjdlNTVjIiwiaGV4IjoiNTEyMDQ2MWE2ZjhhOTRmOTM2NWNiNzUwZGVkMzhhMzkwZWU5YjY1ZmQxNzg1YTI3N2I3NWYxZWY3NmRiOTBiN2U1NWMiLCJ0eXBlIjoid2l0bmVzc192MV90YXByb290In19LHsidmFsdWUiOjAuMDAwMjIsIm4iOjEwLCJzY3JpcHRQdWJLZXkiOnsiYXNtIjoiMCBiZGZkNmUwZTg4OWNlNTdjOWFkYmZlODE3YjI2OTc4NmNhMDgyMWQzIiwiaGV4IjoiMDAxNGJkZmQ2ZTBlODg5Y2U1N2M5YWRiZmU4MTdiMjY5Nzg2Y2EwODIxZDMiLCJ0eXBlIjoid2l0bmVzc192MF9rZXloYXNoIn19XX0seyJoZXgiOiIwMjAwMDAwMDAwMDEwMWY5ODRhZWVhNGEwOGI5NThjODU4NGUzMGEyYjg0ZDdjOTdkNTY1NDNjOTM2NDc4ODU2NmNjOTE1MTUwZTg2ZTcwOTAwMDAwMDAwZmZmZmZmZmYwMTIyMDIwMDAwMDAwMDAwMDAyMjUxMjBmNGQ2NmZjN2IxNzg3ZGJlNTdkZDM2YjY0Y2M3NGE3YTQ4NTMxZmEwZWJlNjA4NzBkZWZjYjRhZGEyZGU3YWQzMDM0MGJhMzJlMDU5NTIzM2VlMTBjNDc2N2U2NmFlNWE1YTk0NTczMjBjMmM1OGU2YzM5OWI2ODNhMDQ0MmQyOTU1NzQyNWFhYTdjYmM0NzlkOTlmOGY2MThkNTYxNmY1OTlkYjM3OGUyMTVkMzJmYjEzYjE5NzQxMjY1ODU0Njg3OWY4NzgyMDFjNGJlM2NlMjZlNjdiMzM2MWYzZDhjNDE5MDA2ZmQ1NjlhMDM5MDA2NjdjYjgyMTY2NTI5Y2M3YTdiNzI1YzRhYzAwNjMwMzZmNzI2NDAxMDExODc0NjU3ODc0MmY3MDZjNjE2OTZlM2I2MzY4NjE3MjczNjU3NDNkNzU3NDY2MmQzODAwMzI3YjIyNzAyMjNhMjI2MjcyNjMyZDMyMzAyMjJjMjI2ZjcwMjIzYTIyNmQ2OTZlNzQyMjJjMjI3NDY5NjM2YjIyM2EyMjcwNzU2ZTZiMjIyYzIyNjE2ZDc0MjIzYTIyMzEyMjdkNjgyMWMxYzFjMjI0YjI4MzQ3YjNlYTY2MzJhNDc1MzNiOTQ0NDY4YjVlMDFlYzU1MDk0MTY4M2VlZTFlZmQ0Y2FjM2JjMDAwMDAwMDAwIiwidHhpZCI6IjBmYmNlOTEwMmE3MWI5NDQ5MWZhMTg0YjUwODMxZjRhMzlhY2Y0ZmU4ZGFlMGE4OTUyYTQ1ZmZlNzAyY2ZmMjgiLCJoYXNoIjoiMmU0ZGVlYWQ2OTdmOTBjZTExYjZiNjJiZjc0ZGYwNDBjNzQwMWZhOGY0YzZkMDVjNDBlMDFlYzVkYTE1YTcwNCIsInNpemUiOjMxNywidnNpemUiOjE1MCwid2VpZ2h0Ijo1OTksInZlcnNpb24iOjIsImxvY2t0aW1lIjowLCJ2aW4iOlt7InR4aWQiOiJlNzg2MGUxNTE1Yzk2YzU2ODg0NzM2Yzk0MzY1ZDU5NzdjNGRiOGEyMzA0ZTU4Yzg1OGI5MDg0YWVhYWU4NGY5Iiwidm91dCI6OSwic2NyaXB0U2lnIjp7ImFzbSI6IiIsImhleCI6IiJ9LCJ0eGlud2l0bmVzcyI6WyJiYTMyZTA1OTUyMzNlZTEwYzQ3NjdlNjZhZTVhNWE5NDU3MzIwYzJjNThlNmMzOTliNjgzYTA0NDJkMjk1NTc0MjVhYWE3Y2JjNDc5ZDk5ZjhmNjE4ZDU2MTZmNTk5ZGIzNzhlMjE1ZDMyZmIxM2IxOTc0MTI2NTg1NDY4NzlmOCIsIjIwMWM0YmUzY2UyNmU2N2IzMzYxZjNkOGM0MTkwMDZmZDU2OWEwMzkwMDY2N2NiODIxNjY1MjljYzdhN2I3MjVjNGFjMDA2MzAzNmY3MjY0MDEwMTE4NzQ2NTc4NzQyZjcwNmM2MTY5NmUzYjYzNjg2MTcyNzM2NTc0M2Q3NTc0NjYyZDM4MDAzMjdiMjI3MDIyM2EyMjYyNzI2MzJkMzIzMDIyMmMyMjZmNzAyMjNhMjI2ZDY5NmU3NDIyMmMyMjc0Njk2MzZiMjIzYTIyNzA3NTZlNmIyMjJjMjI2MTZkNzQyMjNhMjIzMTIyN2Q2OCIsImMxYzFjMjI0YjI4MzQ3YjNlYTY2MzJhNDc1MzNiOTQ0NDY4YjVlMDFlYzU1MDk0MTY4M2VlZTFlZmQ0Y2FjM2JjMCJdLCJzZXF1ZW5jZSI6NDI5NDk2NzI5NX1dLCJ2b3V0IjpbeyJ2YWx1ZSI6MC4wMDAwMDU0NiwibiI6MCwic2NyaXB0UHViS2V5Ijp7ImFzbSI6IjEgZjRkNjZmYzdiMTc4N2RiZTU3ZGQzNmI2NGNjNzRhN2E0ODUzMWZhMGViZTYwODcwZGVmY2I0YWRhMmRlN2FkMyIsImhleCI6IjUxMjBmNGQ2NmZjN2IxNzg3ZGJlNTdkZDM2YjY0Y2M3NGE3YTQ4NTMxZmEwZWJlNjA4NzBkZWZjYjRhZGEyZGU3YWQzIiwidHlwZSI6IndpdG5lc3NfdjFfdGFwcm9vdCJ9fV19LHsiaGV4IjoiMDIwMDAwMDAwMDAxMDFmOTg0YWVlYTRhMDhiOTU4Yzg1ODRlMzBhMmI4NGQ3Yzk3ZDU2NTQzYzkzNjQ3ODg1NjZjYzkxNTE1MGU4NmU3MDUwMDAwMDAwMGZmZmZmZmZmMDEyMjAyMDAwMDAwMDAwMDAwMjI1MTIwZjRkNjZmYzdiMTc4N2RiZTU3ZGQzNmI2NGNjNzRhN2E0ODUzMWZhMGViZTYwODcwZGVmY2I0YWRhMmRlN2FkMzAzNDAwNmQ2YzYzYmQ1NDYwOGM2YjJjMDFiNzM0OWM0YzQ0OGQxYTdlMzExMjdmOTJjMjFhZTYyZDk4MGU3ZGU4ZTY2ZDhkMWU0ZmE3ZThiZmU4OWZkZDBiMTk3MDllMGE1ZTk5YWZjOWY3N2I5YWNhODBkMDY3NmE1ZGUxODc1NmVlYzc4MjBjM2E2OTc5MjQzMDgzYzMzZWQ0YjU3ZGI3YWQ1NjhkMThkODAyM2E0MTgwZGU5NmRhMmViZGFmMWRiOWI0NmE3YWMwMDYzMDM2ZjcyNjQwMTAxMTg3NDY1Nzg3NDJmNzA2YzYxNjk2ZTNiNjM2ODYxNzI3MzY1NzQzZDc1NzQ2NjJkMzgwMDMyN2IyMjcwMjIzYTIyNjI3MjYzMmQzMjMwMjIyYzIyNmY3MDIyM2EyMjZkNjk2ZTc0MjIyYzIyNzQ2OTYzNmIyMjNhMjI3MDc1NmU2YjIyMmMyMjYxNmQ3NDIyM2EyMjMxMjI3ZDY4MjFjMWMxYzIyNGIyODM0N2IzZWE2NjMyYTQ3NTMzYjk0NDQ2OGI1ZTAxZWM1NTA5NDE2ODNlZWUxZWZkNGNhYzNiYzAwMDAwMDAwMCIsInR4aWQiOiI5MmNmMzdiNjM1ZWU2MWMxZmI2NGEzZTg1YTUwOGM0ZjY4YjM4OTEwYWM3N2ZhNWRiZDZlYTU4ZmY3NDk5NzU3IiwiaGFzaCI6ImZlMWQ4YTdjN2ZhZjRjMWJjMzQ2N2M0YTIwYzFhN2FkNmNmNzFjYTUyOWY2NmEwZDNlYWI2N2ZjYmZjMmZlNTMiLCJzaXplIjozMTcsInZzaXplIjoxNTAsIndlaWdodCI6NTk5LCJ2ZXJzaW9uIjoyLCJsb2NrdGltZSI6MCwidmluIjpbeyJ0eGlkIjoiZTc4NjBlMTUxNWM5NmM1Njg4NDczNmM5NDM2NWQ1OTc3YzRkYjhhMjMwNGU1OGM4NThiOTA4NGFlYWFlODRmOSIsInZvdXQiOjUsInNjcmlwdFNpZyI6eyJhc20iOiIiLCJoZXgiOiIifSwidHhpbndpdG5lc3MiOlsiMDZkNmM2M2JkNTQ2MDhjNmIyYzAxYjczNDljNGM0NDhkMWE3ZTMxMTI3ZjkyYzIxYWU2MmQ5ODBlN2RlOGU2NmQ4ZDFlNGZhN2U4YmZlODlmZGQwYjE5NzA5ZTBhNWU5OWFmYzlmNzdiOWFjYTgwZDA2NzZhNWRlMTg3NTZlZWMiLCIyMGMzYTY5NzkyNDMwODNjMzNlZDRiNTdkYjdhZDU2OGQxOGQ4MDIzYTQxODBkZTk2ZGEyZWJkYWYxZGI5YjQ2YTdhYzAwNjMwMzZmNzI2NDAxMDExODc0NjU3ODc0MmY3MDZjNjE2OTZlM2I2MzY4NjE3MjczNjU3NDNkNzU3NDY2MmQzODAwMzI3YjIyNzAyMjNhMjI2MjcyNjMyZDMyMzAyMjJjMjI2ZjcwMjIzYTIyNmQ2OTZlNzQyMjJjMjI3NDY5NjM2YjIyM2EyMjcwNzU2ZTZiMjIyYzIyNjE2ZDc0MjIzYTIyMzEyMjdkNjgiLCJjMWMxYzIyNGIyODM0N2IzZWE2NjMyYTQ3NTMzYjk0NDQ2OGI1ZTAxZWM1NTA5NDE2ODNlZWUxZWZkNGNhYzNiYzAiXSwic2VxdWVuY2UiOjQyOTQ5NjcyOTV9XSwidm91dCI6W3sidmFsdWUiOjAuMDAwMDA1NDYsIm4iOjAsInNjcmlwdFB1YktleSI6eyJhc20iOiIxIGY0ZDY2ZmM3YjE3ODdkYmU1N2RkMzZiNjRjYzc0YTdhNDg1MzFmYTBlYmU2MDg3MGRlZmNiNGFkYTJkZTdhZDMiLCJoZXgiOiI1MTIwZjRkNjZmYzdiMTc4N2RiZTU3ZGQzNmI2NGNjNzRhN2E0ODUzMWZhMGViZTYwODcwZGVmY2I0YWRhMmRlN2FkMyIsInR5cGUiOiJ3aXRuZXNzX3YxX3RhcHJvb3QifX1dfSx7ImhleCI6IjAyMDAwMDAwMDAwMTAxZjk4NGFlZWE0YTA4Yjk1OGM4NTg0ZTMwYTJiODRkN2M5N2Q1NjU0M2M5MzY0Nzg4NTY2Y2M5MTUxNTBlODZlNzA2MDAwMDAwMDBmZmZmZmZmZjAxMjIwMjAwMDAwMDAwMDAwMDIyNTEyMGY0ZDY2ZmM3YjE3ODdkYmU1N2RkMzZiNjRjYzc0YTdhNDg1MzFmYTBlYmU2MDg3MGRlZmNiNGFkYTJkZTdhZDMwMzQwMDY4YjQwNzE5OTNmOWE5YWUxOTI5NjI4NTk4ZjlkNTY1ZTM1NmE2NDQzYjUwMmQ2MzIyZGExM2Q3MDY1YWI0OTExNzI5MjA2YjM4ODg5MmZiOWY4YTExMGVlNWFkZGQzZGU3NGQyMjRiYWI0ZTg4ODY4ZmUxNGU4NDNhMzg5ZjI3ODIwMDA3YmMxZDA4M2JhYTcyYmU0MzY2Mzk2MDRjZGFkM2Y2OGU0OTI2ZTUwZTExNWM3YjUyYmE0NmRkMTBlMzFiN2FjMDA2MzAzNmY3MjY0MDEwMTE4NzQ2NTc4NzQyZjcwNmM2MTY5NmUzYjYzNjg2MTcyNzM2NTc0M2Q3NTc0NjYyZDM4MDAzMjdiMjI3MDIyM2EyMjYyNzI2MzJkMzIzMDIyMmMyMjZmNzAyMjNhMjI2ZDY5NmU3NDIyMmMyMjc0Njk2MzZiMjIzYTIyNzA3NTZlNmIyMjJjMjI2MTZkNzQyMjNhMjIzMTIyN2Q2ODIxYzBjMWMyMjRiMjgzNDdiM2VhNjYzMmE0NzUzM2I5NDQ0NjhiNWUwMWVjNTUwOTQxNjgzZWVlMWVmZDRjYWMzYmMwMDAwMDAwMDAiLCJ0eGlkIjoiOTA1ZTNlNDM1YmI1M2ExM2IyMjAwNzNmMTlmYzJkOWIxNzJmM2UxOWEwYTY4MDA0YzQ3ZDQ1OWUzNjRlNTc3MCIsImhhc2giOiIxOWE0ZGE4NDdmYzMxM2RiYTgyM2MyNzZjOTAxODVhZGQyZWVkZThkN2YyMWU3NTY0MzM2MWFkY2EwN2JlMjAzIiwic2l6ZSI6MzE3LCJ2c2l6ZSI6MTUwLCJ3ZWlnaHQiOjU5OSwidmVyc2lvbiI6MiwibG9ja3RpbWUiOjAsInZpbiI6W3sidHhpZCI6ImU3ODYwZTE1MTVjOTZjNTY4ODQ3MzZjOTQzNjVkNTk3N2M0ZGI4YTIzMDRlNThjODU4YjkwODRhZWFhZTg0ZjkiLCJ2b3V0Ijo2LCJzY3JpcHRTaWciOnsiYXNtIjoiIiwiaGV4IjoiIn0sInR4aW53aXRuZXNzIjpbIjA2OGI0MDcxOTkzZjlhOWFlMTkyOTYyODU5OGY5ZDU2NWUzNTZhNjQ0M2I1MDJkNjMyMmRhMTNkNzA2NWFiNDkxMTcyOTIwNmIzODg4OTJmYjlmOGExMTBlZTVhZGRkM2RlNzRkMjI0YmFiNGU4ODg2OGZlMTRlODQzYTM4OWYyIiwiMjAwMDdiYzFkMDgzYmFhNzJiZTQzNjYzOTYwNGNkYWQzZjY4ZTQ5MjZlNTBlMTE1YzdiNTJiYTQ2ZGQxMGUzMWI3YWMwMDYzMDM2ZjcyNjQwMTAxMTg3NDY1Nzg3NDJmNzA2YzYxNjk2ZTNiNjM2ODYxNzI3MzY1NzQzZDc1NzQ2NjJkMzgwMDMyN2IyMjcwMjIzYTIyNjI3MjYzMmQzMjMwMjIyYzIyNmY3MDIyM2EyMjZkNjk2ZTc0MjIyYzIyNzQ2OTYzNmIyMjNhMjI3MDc1NmU2YjIyMmMyMjYxNmQ3NDIyM2EyMjMxMjI3ZDY4IiwiYzBjMWMyMjRiMjgzNDdiM2VhNjYzMmE0NzUzM2I5NDQ0NjhiNWUwMWVjNTUwOTQxNjgzZWVlMWVmZDRjYWMzYmMwIl0sInNlcXVlbmNlIjo0Mjk0OTY3Mjk1fV0sInZvdXQiOlt7InZhbHVlIjowLjAwMDAwNTQ2LCJuIjowLCJzY3JpcHRQdWJLZXkiOnsiYXNtIjoiMSBmNGQ2NmZjN2IxNzg3ZGJlNTdkZDM2YjY0Y2M3NGE3YTQ4NTMxZmEwZWJlNjA4NzBkZWZjYjRhZGEyZGU3YWQzIiwiaGV4IjoiNTEyMGY0ZDY2ZmM3YjE3ODdkYmU1N2RkMzZiNjRjYzc0YTdhNDg1MzFmYTBlYmU2MDg3MGRlZmNiNGFkYTJkZTdhZDMiLCJ0eXBlIjoid2l0bmVzc192MV90YXByb290In19XX0seyJoZXgiOiIwMjAwMDAwMDAwMDEwMWY5ODRhZWVhNGEwOGI5NThjODU4NGUzMGEyYjg0ZDdjOTdkNTY1NDNjOTM2NDc4ODU2NmNjOTE1MTUwZTg2ZTcwNzAwMDAwMDAwZmZmZmZmZmYwMTIyMDIwMDAwMDAwMDAwMDAyMjUxMjBmNGQ2NmZjN2IxNzg3ZGJlNTdkZDM2YjY0Y2M3NGE3YTQ4NTMxZmEwZWJlNjA4NzBkZWZjYjRhZGEyZGU3YWQzMDM0MDgzZjYxNDNkNmIxYzFhMjVmNGQ5OGE0NWJmYmYxZGM0NDQ1ZDM2MTA2NjU1OWMxNGMxOWQ3NzIwZDgzNTU1MGQzNWM0MTliMjcyM2I4YTI0NmZkNjg1MzVkY2FlMjg0NmZiNTAzMzMzYzYwZDE2NzhmOTA1ZjlmNDU2ZjI3OWY5NzgyMGMwZmU3ZjhhMTM3OTQzMTBiOTZlMjA5ZDY3YTQ1NWYzMjdhYmRhMDI2NjkwZTBjYTM1YjI5MTM2ODUxM2EwZDhhYzAwNjMwMzZmNzI2NDAxMDExODc0NjU3ODc0MmY3MDZjNjE2OTZlM2I2MzY4NjE3MjczNjU3NDNkNzU3NDY2MmQzODAwMzI3YjIyNzAyMjNhMjI2MjcyNjMyZDMyMzAyMjJjMjI2ZjcwMjIzYTIyNmQ2OTZlNzQyMjJjMjI3NDY5NjM2YjIyM2EyMjcwNzU2ZTZiMjIyYzIyNjE2ZDc0MjIzYTIyMzEyMjdkNjgyMWMxYzFjMjI0YjI4MzQ3YjNlYTY2MzJhNDc1MzNiOTQ0NDY4YjVlMDFlYzU1MDk0MTY4M2VlZTFlZmQ0Y2FjM2JjMDAwMDAwMDAwIiwidHhpZCI6IjIwNWViNDY5MjZjYWNhZjFhNDNjYmVhYTMwMWI3MmNiMzIyM2JmZWU1MDY4YWZmY2Y5NzYzN2Y0NGJjYzM2NzYiLCJoYXNoIjoiYWFjMWRjODVhOTdiMTk2N2ZlODdlNWQ4YTk0NzNiNjQxYTBjZWZhNjIwZWRlNjJiNjgzNzNiMThjYTBhZjFmOSIsInNpemUiOjMxNywidnNpemUiOjE1MCwid2VpZ2h0Ijo1OTksInZlcnNpb24iOjIsImxvY2t0aW1lIjowLCJ2aW4iOlt7InR4aWQiOiJlNzg2MGUxNTE1Yzk2YzU2ODg0NzM2Yzk0MzY1ZDU5NzdjNGRiOGEyMzA0ZTU4Yzg1OGI5MDg0YWVhYWU4NGY5Iiwidm91dCI6Nywic2NyaXB0U2lnIjp7ImFzbSI6IiIsImhleCI6IiJ9LCJ0eGlud2l0bmVzcyI6WyI4M2Y2MTQzZDZiMWMxYTI1ZjRkOThhNDViZmJmMWRjNDQ0NWQzNjEwNjY1NTljMTRjMTlkNzcyMGQ4MzU1NTBkMzVjNDE5YjI3MjNiOGEyNDZmZDY4NTM1ZGNhZTI4NDZmYjUwMzMzM2M2MGQxNjc4ZjkwNWY5ZjQ1NmYyNzlmOSIsIjIwYzBmZTdmOGExMzc5NDMxMGI5NmUyMDlkNjdhNDU1ZjMyN2FiZGEwMjY2OTBlMGNhMzViMjkxMzY4NTEzYTBkOGFjMDA2MzAzNmY3MjY0MDEwMTE4NzQ2NTc4NzQyZjcwNmM2MTY5NmUzYjYzNjg2MTcyNzM2NTc0M2Q3NTc0NjYyZDM4MDAzMjdiMjI3MDIyM2EyMjYyNzI2MzJkMzIzMDIyMmMyMjZmNzAyMjNhMjI2ZDY5NmU3NDIyMmMyMjc0Njk2MzZiMjIzYTIyNzA3NTZlNmIyMjJjMjI2MTZkNzQyMjNhMjIzMTIyN2Q2OCIsImMxYzFjMjI0YjI4MzQ3YjNlYTY2MzJhNDc1MzNiOTQ0NDY4YjVlMDFlYzU1MDk0MTY4M2VlZTFlZmQ0Y2FjM2JjMCJdLCJzZXF1ZW5jZSI6NDI5NDk2NzI5NX1dLCJ2b3V0IjpbeyJ2YWx1ZSI6MC4wMDAwMDU0NiwibiI6MCwic2NyaXB0UHViS2V5Ijp7ImFzbSI6IjEgZjRkNjZmYzdiMTc4N2RiZTU3ZGQzNmI2NGNjNzRhN2E0ODUzMWZhMGViZTYwODcwZGVmY2I0YWRhMmRlN2FkMyIsImhleCI6IjUxMjBmNGQ2NmZjN2IxNzg3ZGJlNTdkZDM2YjY0Y2M3NGE3YTQ4NTMxZmEwZWJlNjA4NzBkZWZjYjRhZGEyZGU3YWQzIiwidHlwZSI6IndpdG5lc3NfdjFfdGFwcm9vdCJ9fV19LHsiaGV4IjoiMDIwMDAwMDAwMDAxMDFmOTg0YWVlYTRhMDhiOTU4Yzg1ODRlMzBhMmI4NGQ3Yzk3ZDU2NTQzYzkzNjQ3ODg1NjZjYzkxNTE1MGU4NmU3MDgwMDAwMDAwMGZmZmZmZmZmMDEyMjAyMDAwMDAwMDAwMDAwMjI1MTIwZjRkNjZmYzdiMTc4N2RiZTU3ZGQzNmI2NGNjNzRhN2E0ODUzMWZhMGViZTYwODcwZGVmY2I0YWRhMmRlN2FkMzAzNDA2OGM3OWRhMTk2YzBlNWNmNGYzY2VmZDI5N2M4NzZlMmY5YjBjOGM5MDA3YWQzZTcwMjkzNjVkNzMwMjM5OTY4NGYwYzNiMTk5ZjNiYjk5YzMzNzgyYmViMDVlYzk4ZjU1ZTAxNGM3ODBkODJjZjg4YzliYzE5OTU2NDc3ZWY3MTc4MjBiNDExOWE4YzdhMzM2Y2YxMWJjMGI4MDA3ZWJiNzM5MGFkZTA4YTYzZTI3YzI3ODhjYjgwMGM1OWFiYzQ5MTU4YWMwMDYzMDM2ZjcyNjQwMTAxMTg3NDY1Nzg3NDJmNzA2YzYxNjk2ZTNiNjM2ODYxNzI3MzY1NzQzZDc1NzQ2NjJkMzgwMDMyN2IyMjcwMjIzYTIyNjI3MjYzMmQzMjMwMjIyYzIyNmY3MDIyM2EyMjZkNjk2ZTc0MjIyYzIyNzQ2OTYzNmIyMjNhMjI3MDc1NmU2YjIyMmMyMjYxNmQ3NDIyM2EyMjMxMjI3ZDY4MjFjMWMxYzIyNGIyODM0N2IzZWE2NjMyYTQ3NTMzYjk0NDQ2OGI1ZTAxZWM1NTA5NDE2ODNlZWUxZWZkNGNhYzNiYzAwMDAwMDAwMCIsInR4aWQiOiIzZmZiNGI4YjRlOTA1MTIxNWVlNmJiYzk2YjA1ZTI4ODMyMzkyOGIzYmNjNmU0ODg5NTVjZmExNWRjNmMxZDc3IiwiaGFzaCI6IjhiNmZmMjQzMjM1NjQ5ZDZhMGUxZTg3MWZkZjEyNmY3NWU3ZjM4NGFmNzgyNDJmNmRmMWViNWNjZTRmMWQ2OGMiLCJzaXplIjozMTcsInZzaXplIjoxNTAsIndlaWdodCI6NTk5LCJ2ZXJzaW9uIjoyLCJsb2NrdGltZSI6MCwidmluIjpbeyJ0eGlkIjoiZTc4NjBlMTUxNWM5NmM1Njg4NDczNmM5NDM2NWQ1OTc3YzRkYjhhMjMwNGU1OGM4NThiOTA4NGFlYWFlODRmOSIsInZvdXQiOjgsInNjcmlwdFNpZyI6eyJhc20iOiIiLCJoZXgiOiIifSwidHhpbndpdG5lc3MiOlsiNjhjNzlkYTE5NmMwZTVjZjRmM2NlZmQyOTdjODc2ZTJmOWIwYzhjOTAwN2FkM2U3MDI5MzY1ZDczMDIzOTk2ODRmMGMzYjE5OWYzYmI5OWMzMzc4MmJlYjA1ZWM5OGY1NWUwMTRjNzgwZDgyY2Y4OGM5YmMxOTk1NjQ3N2VmNzEiLCIyMGI0MTE5YThjN2EzMzZjZjExYmMwYjgwMDdlYmI3MzkwYWRlMDhhNjNlMjdjMjc4OGNiODAwYzU5YWJjNDkxNThhYzAwNjMwMzZmNzI2NDAxMDExODc0NjU3ODc0MmY3MDZjNjE2OTZlM2I2MzY4NjE3MjczNjU3NDNkNzU3NDY2MmQzODAwMzI3YjIyNzAyMjNhMjI2MjcyNjMyZDMyMzAyMjJjMjI2ZjcwMjIzYTIyNmQ2OTZlNzQyMjJjMjI3NDY5NjM2YjIyM2EyMjcwNzU2ZTZiMjIyYzIyNjE2ZDc0MjIzYTIyMzEyMjdkNjgiLCJjMWMxYzIyNGIyODM0N2IzZWE2NjMyYTQ3NTMzYjk0NDQ2OGI1ZTAxZWM1NTA5NDE2ODNlZWUxZWZkNGNhYzNiYzAiXSwic2VxdWVuY2UiOjQyOTQ5NjcyOTV9XSwidm91dCI6W3sidmFsdWUiOjAuMDAwMDA1NDYsIm4iOjAsInNjcmlwdFB1YktleSI6eyJhc20iOiIxIGY0ZDY2ZmM3YjE3ODdkYmU1N2RkMzZiNjRjYzc0YTdhNDg1MzFmYTBlYmU2MDg3MGRlZmNiNGFkYTJkZTdhZDMiLCJoZXgiOiI1MTIwZjRkNjZmYzdiMTc4N2RiZTU3ZGQzNmI2NGNjNzRhN2E0ODUzMWZhMGViZTYwODcwZGVmY2I0YWRhMmRlN2FkMyIsInR5cGUiOiJ3aXRuZXNzX3YxX3RhcHJvb3QifX1dfSx7ImhleCI6IjAyMDAwMDAwMDAwMTAxZjk4NGFlZWE0YTA4Yjk1OGM4NTg0ZTMwYTJiODRkN2M5N2Q1NjU0M2M5MzY0Nzg4NTY2Y2M5MTUxNTBlODZlNzA0MDAwMDAwMDBmZmZmZmZmZjAxMjIwMjAwMDAwMDAwMDAwMDIyNTEyMGY0ZDY2ZmM3YjE3ODdkYmU1N2RkMzZiNjRjYzc0YTdhNDg1MzFmYTBlYmU2MDg3MGRlZmNiNGFkYTJkZTdhZDMwMzQwMzlkODkzMDUyOWE4MTYxNzBiNjcyOTNjODBmNzBhMTRiZmE4YzFmM2JiZTdhYzJlMmU1NDZhMGVkZTg2YzY5YzNmNTg3OTY4YzZhY2EzZWY5MzRjN2U3MDZmMmQ0YzgzMDRkY2E3MDFhNTJiN2MzOTg1NDU3ZjUwMDM1ZjgzZmU3ODIwOTI5ZTRkZmFjOTRjYmI0MjBmNGRiZWIyNDI1MDI1NDQxMjEwN2FmMTYxZjBkNGYyM2Q1NjFiNzBhNjQ2NDcwOGFjMDA2MzAzNmY3MjY0MDEwMTE4NzQ2NTc4NzQyZjcwNmM2MTY5NmUzYjYzNjg2MTcyNzM2NTc0M2Q3NTc0NjYyZDM4MDAzMjdiMjI3MDIyM2EyMjYyNzI2MzJkMzIzMDIyMmMyMjZmNzAyMjNhMjI2ZDY5NmU3NDIyMmMyMjc0Njk2MzZiMjIzYTIyNzA3NTZlNmIyMjJjMjI2MTZkNzQyMjNhMjIzMTIyN2Q2ODIxYzFjMWMyMjRiMjgzNDdiM2VhNjYzMmE0NzUzM2I5NDQ0NjhiNWUwMWVjNTUwOTQxNjgzZWVlMWVmZDRjYWMzYmMwMDAwMDAwMDAiLCJ0eGlkIjoiYmNmMTI0NTYyODhlY2UzODc4NTljN2ViNDc0ZWVjOTcxMzBjNmFiNDljMDRiM2Q4NTg5MzQ0Y2RhZWFlYjg5MCIsImhhc2giOiJmNDUyNzZjOGMwOGVjMmYwOTFkN2U0ZWI4MDA3YzQ1YTgxNTdkMzFkMGE3ZTU3ZDVjYWViZTlkMWI4MmM2MmIwIiwic2l6ZSI6MzE3LCJ2c2l6ZSI6MTUwLCJ3ZWlnaHQiOjU5OSwidmVyc2lvbiI6MiwibG9ja3RpbWUiOjAsInZpbiI6W3sidHhpZCI6ImU3ODYwZTE1MTVjOTZjNTY4ODQ3MzZjOTQzNjVkNTk3N2M0ZGI4YTIzMDRlNThjODU4YjkwODRhZWFhZTg0ZjkiLCJ2b3V0Ijo0LCJzY3JpcHRTaWciOnsiYXNtIjoiIiwiaGV4IjoiIn0sInR4aW53aXRuZXNzIjpbIjM5ZDg5MzA1MjlhODE2MTcwYjY3MjkzYzgwZjcwYTE0YmZhOGMxZjNiYmU3YWMyZTJlNTQ2YTBlZGU4NmM2OWMzZjU4Nzk2OGM2YWNhM2VmOTM0YzdlNzA2ZjJkNGM4MzA0ZGNhNzAxYTUyYjdjMzk4NTQ1N2Y1MDAzNWY4M2ZlIiwiMjA5MjllNGRmYWM5NGNiYjQyMGY0ZGJlYjI0MjUwMjU0NDEyMTA3YWYxNjFmMGQ0ZjIzZDU2MWI3MGE2NDY0NzA4YWMwMDYzMDM2ZjcyNjQwMTAxMTg3NDY1Nzg3NDJmNzA2YzYxNjk2ZTNiNjM2ODYxNzI3MzY1NzQzZDc1NzQ2NjJkMzgwMDMyN2IyMjcwMjIzYTIyNjI3MjYzMmQzMjMwMjIyYzIyNmY3MDIyM2EyMjZkNjk2ZTc0MjIyYzIyNzQ2OTYzNmIyMjNhMjI3MDc1NmU2YjIyMmMyMjYxNmQ3NDIyM2EyMjMxMjI3ZDY4IiwiYzFjMWMyMjRiMjgzNDdiM2VhNjYzMmE0NzUzM2I5NDQ0NjhiNWUwMWVjNTUwOTQxNjgzZWVlMWVmZDRjYWMzYmMwIl0sInNlcXVlbmNlIjo0Mjk0OTY3Mjk1fV0sInZvdXQiOlt7InZhbHVlIjowLjAwMDAwNTQ2LCJuIjowLCJzY3JpcHRQdWJLZXkiOnsiYXNtIjoiMSBmNGQ2NmZjN2IxNzg3ZGJlNTdkZDM2YjY0Y2M3NGE3YTQ4NTMxZmEwZWJlNjA4NzBkZWZjYjRhZGEyZGU3YWQzIiwiaGV4IjoiNTEyMGY0ZDY2ZmM3YjE3ODdkYmU1N2RkMzZiNjRjYzc0YTdhNDg1MzFmYTBlYmU2MDg3MGRlZmNiNGFkYTJkZTdhZDMiLCJ0eXBlIjoid2l0bmVzc192MV90YXByb290In19XX0seyJoZXgiOiIwMjAwMDAwMDAwMDEwMWY5ODRhZWVhNGEwOGI5NThjODU4NGUzMGEyYjg0ZDdjOTdkNTY1NDNjOTM2NDc4ODU2NmNjOTE1MTUwZTg2ZTcwMzAwMDAwMDAwZmZmZmZmZmYwMTIyMDIwMDAwMDAwMDAwMDAyMjUxMjBmNGQ2NmZjN2IxNzg3ZGJlNTdkZDM2YjY0Y2M3NGE3YTQ4NTMxZmEwZWJlNjA4NzBkZWZjYjRhZGEyZGU3YWQzMDM0MDNkNmE4MDQ3ZWUxMGFhMDBmMTg5YzIwYTBjNzExZWEzMDIyMWFkZTliZGZkNWQyNzgxZjA5MjA0N2M0MWE0ZjQ1YzA3YTA3NmNmNDVmNmQ2NWM5ZjY0YjM0YmQxZGJkZmNkZjk1YTA2ZGRkNGYxMmE0OTRkYzE2Y2MzNzIxNTliNzgyMDk5MGU0ZjhmYjdkZDI0ZDhmODkzYTY1YjQ2NjM2MTEwZWUwZTYzYjVmODNiNGIwZGUyMjFiMWE4NzliMTY3YzVhYzAwNjMwMzZmNzI2NDAxMDExODc0NjU3ODc0MmY3MDZjNjE2OTZlM2I2MzY4NjE3MjczNjU3NDNkNzU3NDY2MmQzODAwMzI3YjIyNzAyMjNhMjI2MjcyNjMyZDMyMzAyMjJjMjI2ZjcwMjIzYTIyNmQ2OTZlNzQyMjJjMjI3NDY5NjM2YjIyM2EyMjcwNzU2ZTZiMjIyYzIyNjE2ZDc0MjIzYTIyMzEyMjdkNjgyMWMwYzFjMjI0YjI4MzQ3YjNlYTY2MzJhNDc1MzNiOTQ0NDY4YjVlMDFlYzU1MDk0MTY4M2VlZTFlZmQ0Y2FjM2JjMDAwMDAwMDAwIiwidHhpZCI6ImYzYWU1YjVhMWY2NzE0MjVjMjk1ZmFiYzZiZmZmYzU2M2JhNWYyOTgxODNmYWY4Mjc5Y2Y5MjI1MjFlY2U2Y2UiLCJoYXNoIjoiNjIxM2Y3NTBjYjJlOTMxZWZjMTRiYTM2NmExMmNiMzNhZGVmMzQxMTA0ZjNjMDZkNzIxYWVhNzM4ODJhZGVkMyIsInNpemUiOjMxNywidnNpemUiOjE1MCwid2VpZ2h0Ijo1OTksInZlcnNpb24iOjIsImxvY2t0aW1lIjowLCJ2aW4iOlt7InR4aWQiOiJlNzg2MGUxNTE1Yzk2YzU2ODg0NzM2Yzk0MzY1ZDU5NzdjNGRiOGEyMzA0ZTU4Yzg1OGI5MDg0YWVhYWU4NGY5Iiwidm91dCI6Mywic2NyaXB0U2lnIjp7ImFzbSI6IiIsImhleCI6IiJ9LCJ0eGlud2l0bmVzcyI6WyIzZDZhODA0N2VlMTBhYTAwZjE4OWMyMGEwYzcxMWVhMzAyMjFhZGU5YmRmZDVkMjc4MWYwOTIwNDdjNDFhNGY0NWMwN2EwNzZjZjQ1ZjZkNjVjOWY2NGIzNGJkMWRiZGZjZGY5NWEwNmRkZDRmMTJhNDk0ZGMxNmNjMzcyMTU5YiIsIjIwOTkwZTRmOGZiN2RkMjRkOGY4OTNhNjViNDY2MzYxMTBlZTBlNjNiNWY4M2I0YjBkZTIyMWIxYTg3OWIxNjdjNWFjMDA2MzAzNmY3MjY0MDEwMTE4NzQ2NTc4NzQyZjcwNmM2MTY5NmUzYjYzNjg2MTcyNzM2NTc0M2Q3NTc0NjYyZDM4MDAzMjdiMjI3MDIyM2EyMjYyNzI2MzJkMzIzMDIyMmMyMjZmNzAyMjNhMjI2ZDY5NmU3NDIyMmMyMjc0Njk2MzZiMjIzYTIyNzA3NTZlNmIyMjJjMjI2MTZkNzQyMjNhMjIzMTIyN2Q2OCIsImMwYzFjMjI0YjI4MzQ3YjNlYTY2MzJhNDc1MzNiOTQ0NDY4YjVlMDFlYzU1MDk0MTY4M2VlZTFlZmQ0Y2FjM2JjMCJdLCJzZXF1ZW5jZSI6NDI5NDk2NzI5NX1dLCJ2b3V0IjpbeyJ2YWx1ZSI6MC4wMDAwMDU0NiwibiI6MCwic2NyaXB0UHViS2V5Ijp7ImFzbSI6IjEgZjRkNjZmYzdiMTc4N2RiZTU3ZGQzNmI2NGNjNzRhN2E0ODUzMWZhMGViZTYwODcwZGVmY2I0YWRhMmRlN2FkMyIsImhleCI6IjUxMjBmNGQ2NmZjN2IxNzg3ZGJlNTdkZDM2YjY0Y2M3NGE3YTQ4NTMxZmEwZWJlNjA4NzBkZWZjYjRhZGEyZGU3YWQzIiwidHlwZSI6IndpdG5lc3NfdjFfdGFwcm9vdCJ9fV19LHsiaGV4IjoiMDIwMDAwMDAwMDAxMDFmOTg0YWVlYTRhMDhiOTU4Yzg1ODRlMzBhMmI4NGQ3Yzk3ZDU2NTQzYzkzNjQ3ODg1NjZjYzkxNTE1MGU4NmU3MDEwMDAwMDAwMGZmZmZmZmZmMDEyMjAyMDAwMDAwMDAwMDAwMjI1MTIwZjRkNjZmYzdiMTc4N2RiZTU3ZGQzNmI2NGNjNzRhN2E0ODUzMWZhMGViZTYwODcwZGVmY2I0YWRhMmRlN2FkMzAzNDBiYWQ2ZGJlOTQzNGNjMjc2MDQ3MDQ2ZWJmYmIxZjhmMGEzYjkyYjJlMjEwYTMzMGY5NGE3NDJhOGU5MjBiNDFmOGJiNTFhZDM1N2VhMWFkNTZkZWU4ZTU3NWNlMWI2NDJhZDVkMDgxMjI3ZTExNjQ2ZDVmNjI5MDc1NTY2NWQzNzc4MjAwNDA3NWY5NzI3Mjk2MTQ2YWI0ODY0OTZhYWRmNWJiYmI2ZmI1MDg3YmIyNzVlZmRkMmE3MjIyYjBjMDJlY2U2YWMwMDYzMDM2ZjcyNjQwMTAxMTg3NDY1Nzg3NDJmNzA2YzYxNjk2ZTNiNjM2ODYxNzI3MzY1NzQzZDc1NzQ2NjJkMzgwMDMyN2IyMjcwMjIzYTIyNjI3MjYzMmQzMjMwMjIyYzIyNmY3MDIyM2EyMjZkNjk2ZTc0MjIyYzIyNzQ2OTYzNmIyMjNhMjI3MDc1NmU2YjIyMmMyMjYxNmQ3NDIyM2EyMjMxMjI3ZDY4MjFjMWMxYzIyNGIyODM0N2IzZWE2NjMyYTQ3NTMzYjk0NDQ2OGI1ZTAxZWM1NTA5NDE2ODNlZWUxZWZkNGNhYzNiYzAwMDAwMDAwMCIsInR4aWQiOiI2NTI5NzY5MTM4ODAwMzUyZDc5ODI4YWM3N2ViYTE0MDJhZmVkZjA0NDI1Nzg5OTdhOTg1MTM3NWZjZWNkZmQ2IiwiaGFzaCI6Ijk5YjdjMDE3ZTc2ZTZmYmYxMGZhYTM4NTM4NjhjNTQ0MzY2MzdmMTU2OTg0YWU0M2NhM2QxZTJjZmI4MTVkNjciLCJzaXplIjozMTcsInZzaXplIjoxNTAsIndlaWdodCI6NTk5LCJ2ZXJzaW9uIjoyLCJsb2NrdGltZSI6MCwidmluIjpbeyJ0eGlkIjoiZTc4NjBlMTUxNWM5NmM1Njg4NDczNmM5NDM2NWQ1OTc3YzRkYjhhMjMwNGU1OGM4NThiOTA4NGFlYWFlODRmOSIsInZvdXQiOjEsInNjcmlwdFNpZyI6eyJhc20iOiIiLCJoZXgiOiIifSwidHhpbndpdG5lc3MiOlsiYmFkNmRiZTk0MzRjYzI3NjA0NzA0NmViZmJiMWY4ZjBhM2I5MmIyZTIxMGEzMzBmOTRhNzQyYThlOTIwYjQxZjhiYjUxYWQzNTdlYTFhZDU2ZGVlOGU1NzVjZTFiNjQyYWQ1ZDA4MTIyN2UxMTY0NmQ1ZjYyOTA3NTU2NjVkMzciLCIyMDA0MDc1Zjk3MjcyOTYxNDZhYjQ4NjQ5NmFhZGY1YmJiYjZmYjUwODdiYjI3NWVmZGQyYTcyMjJiMGMwMmVjZTZhYzAwNjMwMzZmNzI2NDAxMDExODc0NjU3ODc0MmY3MDZjNjE2OTZlM2I2MzY4NjE3MjczNjU3NDNkNzU3NDY2MmQzODAwMzI3YjIyNzAyMjNhMjI2MjcyNjMyZDMyMzAyMjJjMjI2ZjcwMjIzYTIyNmQ2OTZlNzQyMjJjMjI3NDY5NjM2YjIyM2EyMjcwNzU2ZTZiMjIyYzIyNjE2ZDc0MjIzYTIyMzEyMjdkNjgiLCJjMWMxYzIyNGIyODM0N2IzZWE2NjMyYTQ3NTMzYjk0NDQ2OGI1ZTAxZWM1NTA5NDE2ODNlZWUxZWZkNGNhYzNiYzAiXSwic2VxdWVuY2UiOjQyOTQ5NjcyOTV9XSwidm91dCI6W3sidmFsdWUiOjAuMDAwMDA1NDYsIm4iOjAsInNjcmlwdFB1YktleSI6eyJhc20iOiIxIGY0ZDY2ZmM3YjE3ODdkYmU1N2RkMzZiNjRjYzc0YTdhNDg1MzFmYTBlYmU2MDg3MGRlZmNiNGFkYTJkZTdhZDMiLCJoZXgiOiI1MTIwZjRkNjZmYzdiMTc4N2RiZTU3ZGQzNmI2NGNjNzRhN2E0ODUzMWZhMGViZTYwODcwZGVmY2I0YWRhMmRlN2FkMyIsInR5cGUiOiJ3aXRuZXNzX3YxX3RhcHJvb3QifX1dfSx7ImhleCI6IjAyMDAwMDAwMDAwMTAxZjk4NGFlZWE0YTA4Yjk1OGM4NTg0ZTMwYTJiODRkN2M5N2Q1NjU0M2M5MzY0Nzg4NTY2Y2M5MTUxNTBlODZlNzAyMDAwMDAwMDBmZmZmZmZmZjAxMjIwMjAwMDAwMDAwMDAwMDIyNTEyMGY0ZDY2ZmM3YjE3ODdkYmU1N2RkMzZiNjRjYzc0YTdhNDg1MzFmYTBlYmU2MDg3MGRlZmNiNGFkYTJkZTdhZDMwMzQwNzMxYWI4NzY3NTIxMzBiNWI1NDkyMGMwMjYzNTlmNjRlOWQ0ZWQ2OGFmNWNmYWE3NGMxMTFmMzRlODBjNjM4NzA0ZDk0ZjA4ODU3NmEwOTEwNWU1NjJhZWM5MTdjNDZlOTM5NGMyZDJhZWM2OTA4MzBhNjgzNDJkYjY2NmU3ZWY3ODIwZGQzZmI3NDZhZjM2N2FmZjA0Mjc4ZGYwYzc2N2I0ZDc0ZDkyZWJkZWQ1ZDk4YTA5NWE0MGM0ZWU2MjZkZGIxNmFjMDA2MzAzNmY3MjY0MDEwMTE4NzQ2NTc4NzQyZjcwNmM2MTY5NmUzYjYzNjg2MTcyNzM2NTc0M2Q3NTc0NjYyZDM4MDAzMjdiMjI3MDIyM2EyMjYyNzI2MzJkMzIzMDIyMmMyMjZmNzAyMjNhMjI2ZDY5NmU3NDIyMmMyMjc0Njk2MzZiMjIzYTIyNzA3NTZlNmIyMjJjMjI2MTZkNzQyMjNhMjIzMTIyN2Q2ODIxYzBjMWMyMjRiMjgzNDdiM2VhNjYzMmE0NzUzM2I5NDQ0NjhiNWUwMWVjNTUwOTQxNjgzZWVlMWVmZDRjYWMzYmMwMDAwMDAwMDAiLCJ0eGlkIjoiOWYzNzBjYzU4NjRmYTBkOGUzMWVmNDA2N2NiMzE4MWRiY2JkZjc5NzVkNzc1ZGJlNmQ0YjMxMGRkMjM4ZmFmZSIsImhhc2giOiJkOTljZTlhOGNjZTc3NzUwM2VlYWQyMjVlNDhlOTlhYzk1OTY5NTVjZGVlNDkxOGE2ZjQ5YzQ3NTlkZTlmNmI2Iiwic2l6ZSI6MzE3LCJ2c2l6ZSI6MTUwLCJ3ZWlnaHQiOjU5OSwidmVyc2lvbiI6MiwibG9ja3RpbWUiOjAsInZpbiI6W3sidHhpZCI6ImU3ODYwZTE1MTVjOTZjNTY4ODQ3MzZjOTQzNjVkNTk3N2M0ZGI4YTIzMDRlNThjODU4YjkwODRhZWFhZTg0ZjkiLCJ2b3V0IjoyLCJzY3JpcHRTaWciOnsiYXNtIjoiIiwiaGV4IjoiIn0sInR4aW53aXRuZXNzIjpbIjczMWFiODc2NzUyMTMwYjViNTQ5MjBjMDI2MzU5ZjY0ZTlkNGVkNjhhZjVjZmFhNzRjMTExZjM0ZTgwYzYzODcwNGQ5NGYwODg1NzZhMDkxMDVlNTYyYWVjOTE3YzQ2ZTkzOTRjMmQyYWVjNjkwODMwYTY4MzQyZGI2NjZlN2VmIiwiMjBkZDNmYjc0NmFmMzY3YWZmMDQyNzhkZjBjNzY3YjRkNzRkOTJlYmRlZDVkOThhMDk1YTQwYzRlZTYyNmRkYjE2YWMwMDYzMDM2ZjcyNjQwMTAxMTg3NDY1Nzg3NDJmNzA2YzYxNjk2ZTNiNjM2ODYxNzI3MzY1NzQzZDc1NzQ2NjJkMzgwMDMyN2IyMjcwMjIzYTIyNjI3MjYzMmQzMjMwMjIyYzIyNmY3MDIyM2EyMjZkNjk2ZTc0MjIyYzIyNzQ2OTYzNmIyMjNhMjI3MDc1NmU2YjIyMmMyMjYxNmQ3NDIyM2EyMjMxMjI3ZDY4IiwiYzBjMWMyMjRiMjgzNDdiM2VhNjYzMmE0NzUzM2I5NDQ0NjhiNWUwMWVjNTUwOTQxNjgzZWVlMWVmZDRjYWMzYmMwIl0sInNlcXVlbmNlIjo0Mjk0OTY3Mjk1fV0sInZvdXQiOlt7InZhbHVlIjowLjAwMDAwNTQ2LCJuIjowLCJzY3JpcHRQdWJLZXkiOnsiYXNtIjoiMSBmNGQ2NmZjN2IxNzg3ZGJlNTdkZDM2YjY0Y2M3NGE3YTQ4NTMxZmEwZWJlNjA4NzBkZWZjYjRhZGEyZGU3YWQzIiwiaGV4IjoiNTEyMGY0ZDY2ZmM3YjE3ODdkYmU1N2RkMzZiNjRjYzc0YTdhNDg1MzFmYTBlYmU2MDg3MGRlZmNiNGFkYTJkZTdhZDMiLCJ0eXBlIjoid2l0bmVzc192MV90YXByb290In19XX0seyJoZXgiOiIwMjAwMDAwMDAxMzFjZmMwZjBkZGE5NjAwNzc3NjRkYmFjZTRiNzVkY2I0MTk2NmIwMTg1MmRlMGY1ZTU3ZDNhNmYzZjhkMzZjNjAxMDAwMDAwNmI0ODMwNDUwMjIxMDBjODE3MzZiYTRlMjkwN2VhMTdjMWE3NGY3NDBiZmEzYzFkNjljNzhmZjY4NGVlODgyYzRjMzBhNjYyY2E4ODNmMDIyMDY4ZGQxMTE1Y2QzMzk2MmI0Y2I4YTVlODA0NTcxNDU3NTFlNmI1Mjg4MjY3ODM0YmIxY2JkM2FjYWJlYjIyMzEwMTIxMDI5M2U3MzVkNzI3ZTNmMmI1OGY5MzZjNzY4OTA3MzlmZGJiNTQxMGNiYjRiNjQ0MjE5MzY5OTFlOGYwYjVhN2NlZmZmZmZmZmYwMjAwMDAwMDAwMDAwMDAwMDAzNjZhMzQ2OTZmNmUzYTMxMmU1MTZkNGU3Mjc1MzM2YjcyNmIzNDVhNTE1Njc1NzI2NTY5Njg2YjRlNjI2ODY0NzM2YjQ3NGI1NTUyNGE1NDc2NDc3OTUzNjYzMTQzNGE3MTUyNDc1NjRjNTY0NjdkOTM5MTA4MDAwMDAwMDAxOTc2YTkxNDY2ZWE4NWJiMTA4NmQzYzgxZTUyYTIzOThmMDBlMjc0NmFjNjA1YWI4OGFjMDAwMDAwMDAiLCJ0eGlkIjoiZDYzNTJjYmFiZWZmNjI5ZDZkNTZiMGE3MjczNjU4YzMyOWJiZTUyZDI4ZmRiMGU5MWY4ODZhZjE3YTY1NDI5MiIsImhhc2giOiJkNjM1MmNiYWJlZmY2MjlkNmQ1NmIwYTcyNzM2NThjMzI5YmJlNTJkMjhmZGIwZTkxZjg4NmFmMTdhNjU0MjkyIiwic2l6ZSI6MjU1LCJ2c2l6ZSI6MjU1LCJ3ZWlnaHQiOjEwMjAsInZlcnNpb24iOjIsImxvY2t0aW1lIjowLCJ2aW4iOlt7InR4aWQiOiJjNjM2OGQzZjZmM2E3ZGU1ZjVlMDJkODUwMTZiOTY0MWNiNWRiN2U0YWNkYjY0NzcwNzYwYTlkZGYwYzBjZjMxIiwidm91dCI6MSwic2NyaXB0U2lnIjp7ImFzbSI6IjMwNDUwMjIxMDBjODE3MzZiYTRlMjkwN2VhMTdjMWE3NGY3NDBiZmEzYzFkNjljNzhmZjY4NGVlODgyYzRjMzBhNjYyY2E4ODNmMDIyMDY4ZGQxMTE1Y2QzMzk2MmI0Y2I4YTVlODA0NTcxNDU3NTFlNmI1Mjg4MjY3ODM0YmIxY2JkM2FjYWJlYjIyMzFbQUxMXSAwMjkzZTczNWQ3MjdlM2YyYjU4ZjkzNmM3Njg5MDczOWZkYmI1NDEwY2JiNGI2NDQyMTkzNjk5MWU4ZjBiNWE3Y2UiLCJoZXgiOiI0ODMwNDUwMjIxMDBjODE3MzZiYTRlMjkwN2VhMTdjMWE3NGY3NDBiZmEzYzFkNjljNzhmZjY4NGVlODgyYzRjMzBhNjYyY2E4ODNmMDIyMDY4ZGQxMTE1Y2QzMzk2MmI0Y2I4YTVlODA0NTcxNDU3NTFlNmI1Mjg4MjY3ODM0YmIxY2JkM2FjYWJlYjIyMzEwMTIxMDI5M2U3MzVkNzI3ZTNmMmI1OGY5MzZjNzY4OTA3MzlmZGJiNTQxMGNiYjRiNjQ0MjE5MzY5OTFlOGYwYjVhN2NlIn0sInNlcXVlbmNlIjo0Mjk0OTY3Mjk1fV0sInZvdXQiOlt7InZhbHVlIjowLCJuIjowLCJzY3JpcHRQdWJLZXkiOnsiYXNtIjoiT1BfUkVUVVJOIDY5NmY2ZTNhMzEyZTUxNmQ0ZTcyNzUzMzZiNzI2YjM0NWE1MTU2NzU3MjY1Njk2ODZiNGU2MjY4NjQ3MzZiNDc0YjU1NTI0YTU0NzY0Nzc5NTM2NjMxNDM0YTcxNTI0NzU2NGM1NjQ2IiwiaGV4IjoiNmEzNDY5NmY2ZTNhMzEyZTUxNmQ0ZTcyNzUzMzZiNzI2YjM0NWE1MTU2NzU3MjY1Njk2ODZiNGU2MjY4NjQ3MzZiNDc0YjU1NTI0YTU0NzY0Nzc5NTM2NjMxNDM0YTcxNTI0NzU2NGM1NjQ2IiwidHlwZSI6Im51bGxkYXRhIn19LHsidmFsdWUiOjEuNDM3NTgyMDUsIm4iOjEsInNjcmlwdFB1YktleSI6eyJhc20iOiJPUF9EVVAgT1BfSEFTSDE2MCA2NmVhODViYjEwODZkM2M4MWU1MmEyMzk4ZjAwZTI3NDZhYzYwNWFiIE9QX0VRVUFMVkVSSUZZIE9QX0NIRUNLU0lHIiwiaGV4IjoiNzZhOTE0NjZlYTg1YmIxMDg2ZDNjODFlNTJhMjM5OGYwMGUyNzQ2YWM2MDVhYjg4YWMiLCJ0eXBlIjoicHVia2V5aGFzaCJ9fV19LHsiaGV4IjoiMDEwMDAwMDAwMDAxMDFkN2NhNjZjNDQ3YmFiZDAyNmU3YzY1ZjQ2MzhhOWJhMjMwMzNjNDMwY2RhOGNiMmUzYmYyZGJmZjExODc0NTI2MDAwMDAwMDAwMGZkZmZmZmZmMDJlYWE2MWMwMDAwMDAwMDAwMTYwMDE0MDNhMTFlZjU3MmQ0ODRhOTg4ZWRmMGIyOTc2ZDdiYzYzMDZhZjM3ZmExYmMwMTAwMDAwMDAwMDAxNjAwMTRlOTRlZDRiOGJkZGRjZWVhNzhhOTAwYzc0ZjI2NmUyOTZjN2ZhZDIxMDI0ODMwNDUwMjIxMDBkMzUwZDgxNWVkNWIwNzhjMTljYzQyNTA4ZmJhNTNiNmVmYWM0NjJjMjAxMThhMTU2NzJjYWJjYTA5Mjk4ZGFiMDIyMDBjODUxNTk1ZDRiMjYxNmY1YzE2OTE2OThmZDM0OWVjMzk4ZDRjZTJkMWE5Mzg0NzE5OTc3OGE0Yjg1MzY4OGMwMTIxMDJiMzUzOTNmZTJmZTY5ZTE2N2VmZTNiNzhlZTMzM2M1YWE2YTE3Zjg4MDA5MzViNzdmZDQ0Y2JlOTQwNzg0YzBjMDAwMDAwMDAiLCJ0eGlkIjoiYTJiMTQ2ZGI2ODZjNzU0Y2I3NDk0OGY2NGUzYmFmY2RhNDZmMTM5NzQ5NjRkMjk2ZWNlZTYzNWUzY2IwYjZmMCIsImhhc2giOiI5OTU0YTJmM2EyMmZjOGE2N2Q0OTg1ZmViZTA3OGJiOTgxZGM2YTljZjA3OWQ4NDgyMGY1MWFhMTFkZDk4Y2EwIiwic2l6ZSI6MjIzLCJ2c2l6ZSI6MTQxLCJ3ZWlnaHQiOjU2MiwidmVyc2lvbiI6MSwibG9ja3RpbWUiOjAsInZpbiI6W3sidHhpZCI6IjI2NDU4NzExZmZkYmYyM2IyZWNiYThjZDMwYzQzMzMwYTI5YjhhNjNmNDY1N2M2ZTAyYmRiYTQ3YzQ2NmNhZDciLCJ2b3V0IjowLCJzY3JpcHRTaWciOnsiYXNtIjoiIiwiaGV4IjoiIn0sInR4aW53aXRuZXNzIjpbIjMwNDUwMjIxMDBkMzUwZDgxNWVkNWIwNzhjMTljYzQyNTA4ZmJhNTNiNmVmYWM0NjJjMjAxMThhMTU2NzJjYWJjYTA5Mjk4ZGFiMDIyMDBjODUxNTk1ZDRiMjYxNmY1YzE2OTE2OThmZDM0OWVjMzk4ZDRjZTJkMWE5Mzg0NzE5OTc3OGE0Yjg1MzY4OGMwMSIsIjAyYjM1MzkzZmUyZmU2OWUxNjdlZmUzYjc4ZWUzMzNjNWFhNmExN2Y4ODAwOTM1Yjc3ZmQ0NGNiZTk0MDc4NGMwYyJdLCJzZXF1ZW5jZSI6NDI5NDk2NzI5M31dLCJ2b3V0IjpbeyJ2YWx1ZSI6MC4wMTg3NzczOCwibiI6MCwic2NyaXB0UHViS2V5Ijp7ImFzbSI6IjAgMDNhMTFlZjU3MmQ0ODRhOTg4ZWRmMGIyOTc2ZDdiYzYzMDZhZjM3ZiIsImhleCI6IjAwMTQwM2ExMWVmNTcyZDQ4NGE5ODhlZGYwYjI5NzZkN2JjNjMwNmFmMzdmIiwidHlwZSI6IndpdG5lc3NfdjBfa2V5aGFzaCJ9fSx7InZhbHVlIjowLjAwMTEzODI1LCJuIjoxLCJzY3JpcHRQdWJLZXkiOnsiYXNtIjoiMCBlOTRlZDRiOGJkZGRjZWVhNzhhOTAwYzc0ZjI2NmUyOTZjN2ZhZDIxIiwiaGV4IjoiMDAxNGU5NGVkNGI4YmRkZGNlZWE3OGE5MDBjNzRmMjY2ZTI5NmM3ZmFkMjEiLCJ0eXBlIjoid2l0bmVzc192MF9rZXloYXNoIn19XX0seyJoZXgiOiIwMjAwMDAwMDAwMDEwMTU3ZmVlNDkxMTcxMDMzMGUxODZhZDJiZWMxMDRhMjIxOTU3ODBjY2QwOTJhZjYzNGEzNDJkNWU2NmEwODZmMjIwMTAwMDAwMDIzMjIwMDIwMDM3MWJiMGU1MDY5NDc2NjFlNGU0OTc1ODU4YjZlNzUyYjg3NzZiNjkxYzk3YTk1NjkzZjY5NDQ4NDZjOTgyMGZmZmZmZmZmMDJhMDg2MDEwMDAwMDAwMDAwMTdhOTE0MTdhNWZmMjk3NGYzMWU5MzQyZTg0OTAzMTE0ZDA1NTIwMDgwMjg4OTg3OTBjNDA1MDAwMDAwMDAwMDE3YTkxNDA4NjJkOTFmMzk4NWZjMjcyOWEwNzdiMTE1NzE2MzZkMjk0MDdmNWE4NzA0MDA0ODMwNDUwMjIxMDBiMWRjYWUxYWNiYzk2MDU3NGU1ZGU4ZGMyMjJkYjMwZWEzZTU4MTFhNzkzMjQ2OWVkMjI3OGRhNTZiNzRhYWQwMDIyMDRkMzFjZTRmOTJlNmRhODM5NjYyMGI2ZGVjNWJhNTQ1MDg2YzFhYmI3NGI1MzkwZGVhM2JjOTdkYmYzNDNmOTgwMTQ4MzA0NTAyMjEwMGU1ZmNmNTU2YTdkNTdiNDRlOGEzMGE5YzllMGMxY2Q1NDMwMzc5Yzg5NjlhMTk0ZTUxZWQwYzNhZGViNjg1ODkwMjIwMDdkOTI1YjA2NDNmN2Y5YTY4NzZiYzVkMDRkYzViYTEyZjcyYzRkZTQzY2E0N2RmMDg1ZWIyMGMxYjM0OTZmNjAxNjk1MjIxMDNjZmVhYWM0MjgwMjFjMTdlOTNiY2UzYTA5MDdlZWMwYWRlNmQ3MmEwZDJmMzEzNzA2MjQ4ZWY1M2M4ZTlhZTE1MjEwMjdmY2E5ZmI5ZTYzNmQwMzU2NmZhZmY4YzM0OGI3YjdkOTE0MzY5NWQwMTExN2UyZGEyMjExOTQ3NjEzNjg0ZjMyMTAyZmViZTAyYjdhMWU2NzZlZGM3YmUxOWJkYmYxNzk2Njc5ZDMzYTg5MmY1MGViYzI3NTc2NmExOWE5YWMwODRhYjUzYWUwMDAwMDAwMCIsInR4aWQiOiJkZDRlNGJmMTEzYzRmOTIzMjg0MWI5MTM4OGJkZTg3Yjg4Zjc3ODQ1NDc2YzdhNThlY2I3ZjdlNDI0YzRlOTA5IiwiaGFzaCI6IjhlYzdmNTk1YTM1NWM3NTI1NzliZmExZGNjZWRlZGViMzFkYjc3MzQ3YmVlYTQ0ZGExZWRkNGQxYzAxMjlhMjIiLCJzaXplIjo0MDYsInZzaXplIjoyMTQsIndlaWdodCI6ODU2LCJ2ZXJzaW9uIjoyLCJsb2NrdGltZSI6MCwidmluIjpbeyJ0eGlkIjoiMjI2ZjA4NmFlNmQ1NDJhMzM0ZjYyYTA5Y2QwYzc4OTUyMWEyMDRjMWJlZDI2YTE4MGUzMzEwMTc5MWU0ZmU1NyIsInZvdXQiOjEsInNjcmlwdFNpZyI6eyJhc20iOiIwMDIwMDM3MWJiMGU1MDY5NDc2NjFlNGU0OTc1ODU4YjZlNzUyYjg3NzZiNjkxYzk3YTk1NjkzZjY5NDQ4NDZjOTgyMCIsImhleCI6IjIyMDAyMDAzNzFiYjBlNTA2OTQ3NjYxZTRlNDk3NTg1OGI2ZTc1MmI4Nzc2YjY5MWM5N2E5NTY5M2Y2OTQ0ODQ2Yzk4MjAifSwidHhpbndpdG5lc3MiOlsiIiwiMzA0NTAyMjEwMGIxZGNhZTFhY2JjOTYwNTc0ZTVkZThkYzIyMmRiMzBlYTNlNTgxMWE3OTMyNDY5ZWQyMjc4ZGE1NmI3NGFhZDAwMjIwNGQzMWNlNGY5MmU2ZGE4Mzk2NjIwYjZkZWM1YmE1NDUwODZjMWFiYjc0YjUzOTBkZWEzYmM5N2RiZjM0M2Y5ODAxIiwiMzA0NTAyMjEwMGU1ZmNmNTU2YTdkNTdiNDRlOGEzMGE5YzllMGMxY2Q1NDMwMzc5Yzg5NjlhMTk0ZTUxZWQwYzNhZGViNjg1ODkwMjIwMDdkOTI1YjA2NDNmN2Y5YTY4NzZiYzVkMDRkYzViYTEyZjcyYzRkZTQzY2E0N2RmMDg1ZWIyMGMxYjM0OTZmNjAxIiwiNTIyMTAzY2ZlYWFjNDI4MDIxYzE3ZTkzYmNlM2EwOTA3ZWVjMGFkZTZkNzJhMGQyZjMxMzcwNjI0OGVmNTNjOGU5YWUxNTIxMDI3ZmNhOWZiOWU2MzZkMDM1NjZmYWZmOGMzNDhiN2I3ZDkxNDM2OTVkMDExMTdlMmRhMjIxMTk0NzYxMzY4NGYzMjEwMmZlYmUwMmI3YTFlNjc2ZWRjN2JlMTliZGJmMTc5NjY3OWQzM2E4OTJmNTBlYmMyNzU3NjZhMTlhOWFjMDg0YWI1M2FlIl0sInNlcXVlbmNlIjo0Mjk0OTY3Mjk1fV0sInZvdXQiOlt7InZhbHVlIjowLjAwMSwibiI6MCwic2NyaXB0UHViS2V5Ijp7ImFzbSI6Ik9QX0hBU0gxNjAgMTdhNWZmMjk3NGYzMWU5MzQyZTg0OTAzMTE0ZDA1NTIwMDgwMjg4OSBPUF9FUVVBTCIsImhleCI6ImE5MTQxN2E1ZmYyOTc0ZjMxZTkzNDJlODQ5MDMxMTRkMDU1MjAwODAyODg5ODciLCJ0eXBlIjoic2NyaXB0aGFzaCJ9fSx7InZhbHVlIjowLjAwMzc4LCJuIjoxLCJzY3JpcHRQdWJLZXkiOnsiYXNtIjoiT1BfSEFTSDE2MCAwODYyZDkxZjM5ODVmYzI3MjlhMDc3YjExNTcxNjM2ZDI5NDA3ZjVhIE9QX0VRVUFMIiwiaGV4IjoiYTkxNDA4NjJkOTFmMzk4NWZjMjcyOWEwNzdiMTE1NzE2MzZkMjk0MDdmNWE4NyIsInR5cGUiOiJzY3JpcHRoYXNoIn19XX0seyJoZXgiOiIwMjAwMDAwMDAzYmM0YWE3Njc1YjYwMjcyMmY0NTc1NjgzMmJjMzcyMjg2MzJiYWI2YmVhOTljNzNlM2ZmZTIxMjY5NmNkNDk5YzAwMDAwMDAwNmE0NzMwNDQwMjIwNGY5NWM3YWNkMTY1MmJkOTZlNzhiZjhjODdkYmNlZDhlYjM0Y2ViNDE1ZDgzZTlmN2E3OGQ2ZmI3MDMxMTQ5NDAyMjAyNjhmNDZhYTEzZDIyOTlkNDU5MjE3ZmJkMWJkYjYzZDdhZmRkMjE1ZDI3Mzg5ZWJhMDczZWQ2OWIxYWEyMTI1MDEyMTAzOGE5ZWNhY2EyNGI4OGMwMDk4NWI4NWYwMGM1YzlkYTliZGY2NWE3OGRiNzdjM2ZmMDgyYjE5ZjBlYzYxYWRlZmZmZmZmZmZmZDVhNGM3YWE5NTkxMDNkMmQ2MDZlZDIwY2U1ZjRjZGE1Y2YxNTg4ZGQxYzM3NThhZmQ1ZWQ2NDJkN2ZmZWZiZTAwMDAwMDAwNmI0ODMwNDUwMjIxMDBiN2Y5OTYwNTg0YzFjNzAxYjFiZGRjZTE5ZjUwNzMwMDgyZWI0MTJhYTM2NmQ1OWMxODZhMjQ5NjdkMTc3MzQzMDIyMDM3NjQ3YjQ4MTNmZjBjMmE1NmZiYzM1NDFiZWM0YjYwMzJiNTUzMGUzMzYyYTRlMTg5OTFlZjc0ZWViY2QzN2MwMTIxMDM4YTllY2FjYTI0Yjg4YzAwOTg1Yjg1ZjAwYzVjOWRhOWJkZjY1YTc4ZGI3N2MzZmYwODJiMTlmMGVjNjFhZGVmZmZmZmZmZmY3YzE4YzA3MzUwMzgwZmVkMDU5NWQ5OTNmYjI5YWFhNjFiNmQ0NjY2ZWRhYTc1MzY1NTlmYmRjMGQzYjgxODc1MDAwMDAwMDA2YTQ3MzA0NDAyMjA1YTA1MWNkMGIxYjNhNGQxOTllYzE3MjNjYWQ2MDlhNThhMWVmM2RlNDFlNzYyODExZWMzNjI2MmE4YzkwMjJlMDIyMDJmNmY1Y2Y2YWQwYTE1OTllZGQxNGYxZmRmNDRlYThhOTI3NTM2OWNjYjQxNWRiMzg4Nzk0NjM2M2Q1Zjk0M2QwMTIxMDM4YTllY2FjYTI0Yjg4YzAwOTg1Yjg1ZjAwYzVjOWRhOWJkZjY1YTc4ZGI3N2MzZmYwODJiMTlmMGVjNjFhZGVmZmZmZmZmZmYwMWU4MDMwMDAwMDAwMDAwMDAxOTc2YTkxNGM4NWM0OGIzNzM2NWQ3N2I4NjRiMmZjN2M0NzJkNmZiYzJlMzk0YTY4OGFjMDAwMDAwMDAiLCJ0eGlkIjoiY2FhZjJlMzVmMzE1MDk2OGE4MGJhODU3MDFhY2E1YjViNThkMjNhM2M0OTQzMmJjZWNkZTM0MzFjNDczZDFkYiIsImhhc2giOiJjYWFmMmUzNWYzMTUwOTY4YTgwYmE4NTcwMWFjYTViNWI1OGQyM2EzYzQ5NDMyYmNlY2RlMzQzMWM0NzNkMWRiIiwic2l6ZSI6NDg2LCJ2c2l6ZSI6NDg2LCJ3ZWlnaHQiOjE5NDQsInZlcnNpb24iOjIsImxvY2t0aW1lIjowLCJ2aW4iOlt7InR4aWQiOiI5YzQ5Y2Q5NjI2MjFmZTNmM2VjNzk5ZWE2YmFiMmI2MzI4NzJjMzJiODM1NjU3ZjQyMjI3NjA1YjY3YTc0YWJjIiwidm91dCI6MCwic2NyaXB0U2lnIjp7ImFzbSI6IjMwNDQwMjIwNGY5NWM3YWNkMTY1MmJkOTZlNzhiZjhjODdkYmNlZDhlYjM0Y2ViNDE1ZDgzZTlmN2E3OGQ2ZmI3MDMxMTQ5NDAyMjAyNjhmNDZhYTEzZDIyOTlkNDU5MjE3ZmJkMWJkYjYzZDdhZmRkMjE1ZDI3Mzg5ZWJhMDczZWQ2OWIxYWEyMTI1W0FMTF0gMDM4YTllY2FjYTI0Yjg4YzAwOTg1Yjg1ZjAwYzVjOWRhOWJkZjY1YTc4ZGI3N2MzZmYwODJiMTlmMGVjNjFhZGVmIiwiaGV4IjoiNDczMDQ0MDIyMDRmOTVjN2FjZDE2NTJiZDk2ZTc4YmY4Yzg3ZGJjZWQ4ZWIzNGNlYjQxNWQ4M2U5ZjdhNzhkNmZiNzAzMTE0OTQwMjIwMjY4ZjQ2YWExM2QyMjk5ZDQ1OTIxN2ZiZDFiZGI2M2Q3YWZkZDIxNWQyNzM4OWViYTA3M2VkNjliMWFhMjEyNTAxMjEwMzhhOWVjYWNhMjRiODhjMDA5ODViODVmMDBjNWM5ZGE5YmRmNjVhNzhkYjc3YzNmZjA4MmIxOWYwZWM2MWFkZWYifSwic2VxdWVuY2UiOjQyOTQ5NjcyOTV9LHsidHhpZCI6ImJlZWZmZmQ3NDJkNjVlZmQ4YTc1YzNkMThkNThmMTVjZGE0YzVmY2UyMGVkMDZkNmQyMDM5MTk1YWFjN2E0ZDUiLCJ2b3V0IjowLCJzY3JpcHRTaWciOnsiYXNtIjoiMzA0NTAyMjEwMGI3Zjk5NjA1ODRjMWM3MDFiMWJkZGNlMTlmNTA3MzAwODJlYjQxMmFhMzY2ZDU5YzE4NmEyNDk2N2QxNzczNDMwMjIwMzc2NDdiNDgxM2ZmMGMyYTU2ZmJjMzU0MWJlYzRiNjAzMmI1NTMwZTMzNjJhNGUxODk5MWVmNzRlZWJjZDM3Y1tBTExdIDAzOGE5ZWNhY2EyNGI4OGMwMDk4NWI4NWYwMGM1YzlkYTliZGY2NWE3OGRiNzdjM2ZmMDgyYjE5ZjBlYzYxYWRlZiIsImhleCI6IjQ4MzA0NTAyMjEwMGI3Zjk5NjA1ODRjMWM3MDFiMWJkZGNlMTlmNTA3MzAwODJlYjQxMmFhMzY2ZDU5YzE4NmEyNDk2N2QxNzczNDMwMjIwMzc2NDdiNDgxM2ZmMGMyYTU2ZmJjMzU0MWJlYzRiNjAzMmI1NTMwZTMzNjJhNGUxODk5MWVmNzRlZWJjZDM3YzAxMjEwMzhhOWVjYWNhMjRiODhjMDA5ODViODVmMDBjNWM5ZGE5YmRmNjVhNzhkYjc3YzNmZjA4MmIxOWYwZWM2MWFkZWYifSwic2VxdWVuY2UiOjQyOTQ5NjcyOTV9LHsidHhpZCI6Ijc1MThiOGQzYzBiZDlmNTUzNjc1YWFlZDY2NDY2ZDFiYTZhYTI5ZmI5M2Q5OTUwNWVkMGYzODUwNzNjMDE4N2MiLCJ2b3V0IjowLCJzY3JpcHRTaWciOnsiYXNtIjoiMzA0NDAyMjA1YTA1MWNkMGIxYjNhNGQxOTllYzE3MjNjYWQ2MDlhNThhMWVmM2RlNDFlNzYyODExZWMzNjI2MmE4YzkwMjJlMDIyMDJmNmY1Y2Y2YWQwYTE1OTllZGQxNGYxZmRmNDRlYThhOTI3NTM2OWNjYjQxNWRiMzg4Nzk0NjM2M2Q1Zjk0M2RbQUxMXSAwMzhhOWVjYWNhMjRiODhjMDA5ODViODVmMDBjNWM5ZGE5YmRmNjVhNzhkYjc3YzNmZjA4MmIxOWYwZWM2MWFkZWYiLCJoZXgiOiI0NzMwNDQwMjIwNWEwNTFjZDBiMWIzYTRkMTk5ZWMxNzIzY2FkNjA5YTU4YTFlZjNkZTQxZTc2MjgxMWVjMzYyNjJhOGM5MDIyZTAyMjAyZjZmNWNmNmFkMGExNTk5ZWRkMTRmMWZkZjQ0ZWE4YTkyNzUzNjljY2I0MTVkYjM4ODc5NDYzNjNkNWY5NDNkMDEyMTAzOGE5ZWNhY2EyNGI4OGMwMDk4NWI4NWYwMGM1YzlkYTliZGY2NWE3OGRiNzdjM2ZmMDgyYjE5ZjBlYzYxYWRlZiJ9LCJzZXF1ZW5jZSI6NDI5NDk2NzI5NX1dLCJ2b3V0IjpbeyJ2YWx1ZSI6MC4wMDAwMSwibiI6MCwic2NyaXB0UHViS2V5Ijp7ImFzbSI6Ik9QX0RVUCBPUF9IQVNIMTYwIGM4NWM0OGIzNzM2NWQ3N2I4NjRiMmZjN2M0NzJkNmZiYzJlMzk0YTYgT1BfRVFVQUxWRVJJRlkgT1BfQ0hFQ0tTSUciLCJoZXgiOiI3NmE5MTRjODVjNDhiMzczNjVkNzdiODY0YjJmYzdjNDcyZDZmYmMyZTM5NGE2ODhhYyIsInR5cGUiOiJwdWJrZXloYXNoIn19XX0seyJoZXgiOiIwMjAwMDAwMDAwMDEwMThmZmEwOTZmODY0NTliYWJhODFlY2MxM2RhMzI1MmEzMDgzNzFiZTMwNzI5ODBmZTVmYjVlZWEzNWE1NmIzZDgwYTAwMDAwMDIzMjIwMDIwMDM3MWJiMGU1MDY5NDc2NjFlNGU0OTc1ODU4YjZlNzUyYjg3NzZiNjkxYzk3YTk1NjkzZjY5NDQ4NDZjOTgyMGZmZmZmZmZmMGJjNDA5MDAwMDAwMDAwMDAwMTdhOTE0YWViYmY5ZDc1M2Y0ZTA1YTg3YjNlNjJkMjgxYzM0NzU1ZGFkMDcwYzg3YzQwOTAwMDAwMDAwMDAwMDE3YTkxNGFlYmJmOWQ3NTNmNGUwNWE4N2IzZTYyZDI4MWMzNDc1NWRhZDA3MGM4N2M0MDkwMDAwMDAwMDAwMDAxN2E5MTRhZWJiZjlkNzUzZjRlMDVhODdiM2U2MmQyODFjMzQ3NTVkYWQwNzBjODdjNDA5MDAwMDAwMDAwMDAwMTdhOTE0YWViYmY5ZDc1M2Y0ZTA1YTg3YjNlNjJkMjgxYzM0NzU1ZGFkMDcwYzg3YzQwOTAwMDAwMDAwMDAwMDE3YTkxNGFlYmJmOWQ3NTNmNGUwNWE4N2IzZTYyZDI4MWMzNDc1NWRhZDA3MGM4N2M0MDkwMDAwMDAwMDAwMDAxN2E5MTRhZWJiZjlkNzUzZjRlMDVhODdiM2U2MmQyODFjMzQ3NTVkYWQwNzBjODdjNDA5MDAwMDAwMDAwMDAwMTdhOTE0YWViYmY5ZDc1M2Y0ZTA1YTg3YjNlNjJkMjgxYzM0NzU1ZGFkMDcwYzg3YzQwOTAwMDAwMDAwMDAwMDE3YTkxNGFlYmJmOWQ3NTNmNGUwNWE4N2IzZTYyZDI4MWMzNDc1NWRhZDA3MGM4N2M0MDkwMDAwMDAwMDAwMDAxN2E5MTRhZWJiZjlkNzUzZjRlMDVhODdiM2U2MmQyODFjMzQ3NTVkYWQwNzBjODdjNDA5MDAwMDAwMDAwMDAwMTdhOTE0YWViYmY5ZDc1M2Y0ZTA1YTg3YjNlNjJkMjgxYzM0NzU1ZGFkMDcwYzg3YjBiMzAwMDAwMDAwMDAwMDE3YTkxNDA4NjJkOTFmMzk4NWZjMjcyOWEwNzdiMTE1NzE2MzZkMjk0MDdmNWE4NzA0MDA0NzMwNDQwMjIwNjY3MDMxZWEzNGFjNDdhM2RkODM4ZmY4Y2JlNWQ1ZTFhZjYwMGY2MjIwNzQ0NGVjOGVhYmY1NTQ1NmVkMGM0YzAyMjAzZDgwM2IzMGQ1NzZhYWIxOGI3MDk4M2IxY2YzYjVjNTA2YjMwNDhiOWQ5MDgyNzhmZTE3MmNhOGVjMjIzODgwMDE0ODMwNDUwMjIxMDBiYTE2YTI0MWY2OTE1MTZlZDMwZjA1MzEzMGRiMTRlNDMwMTdjOTAyM2YzNjc0NWU0ZWVlZjIzMDhlNzg1NDQzMDIyMDVmZmU1OGNlM2Y3ZDMwNTdlODNiOGNjYTJlOTZiMWIxYjhlYzNhOTdiNTZmODM4NTEzZDM1YTc5OGNkNTIyMzYwMTY5NTIyMTAzY2ZlYWFjNDI4MDIxYzE3ZTkzYmNlM2EwOTA3ZWVjMGFkZTZkNzJhMGQyZjMxMzcwNjI0OGVmNTNjOGU5YWUxNTIxMDI3ZmNhOWZiOWU2MzZkMDM1NjZmYWZmOGMzNDhiN2I3ZDkxNDM2OTVkMDExMTdlMmRhMjIxMTk0NzYxMzY4NGYzMjEwMmZlYmUwMmI3YTFlNjc2ZWRjN2JlMTliZGJmMTc5NjY3OWQzM2E4OTJmNTBlYmMyNzU3NjZhMTlhOWFjMDg0YWI1M2FlMDAwMDAwMDAiLCJ0eGlkIjoiODllYWM1OTk3YjQzNTcwM2ExMzRjMjZjNTQyNjRlMDA1YTFiOWVjMjA0YzExMzAzMTc0MzhlZjg2M2UzNDkxNSIsImhhc2giOiI2MDIyMDk1ZWU5MmUxNjc1ZDM0MDVmMmJmMGQ1Mzk3MWRhY2RjMjY3ZjQ4Y2JhZDk3NzhjMjgyM2RiNWQ0YjY5Iiwic2l6ZSI6NjkzLCJ2c2l6ZSI6NTAyLCJ3ZWlnaHQiOjIwMDcsInZlcnNpb24iOjIsImxvY2t0aW1lIjowLCJ2aW4iOlt7InR4aWQiOiJkOGIzNTY1YWEzZWViNTVmZmU4MDI5MDdlMzFiMzcwOGEzNTIzMmRhMTNjYzFlYThhYjliNDU4NjZmMDlmYThmIiwidm91dCI6MTAsInNjcmlwdFNpZyI6eyJhc20iOiIwMDIwMDM3MWJiMGU1MDY5NDc2NjFlNGU0OTc1ODU4YjZlNzUyYjg3NzZiNjkxYzk3YTk1NjkzZjY5NDQ4NDZjOTgyMCIsImhleCI6IjIyMDAyMDAzNzFiYjBlNTA2OTQ3NjYxZTRlNDk3NTg1OGI2ZTc1MmI4Nzc2YjY5MWM5N2E5NTY5M2Y2OTQ0ODQ2Yzk4MjAifSwidHhpbndpdG5lc3MiOlsiIiwiMzA0NDAyMjA2NjcwMzFlYTM0YWM0N2EzZGQ4MzhmZjhjYmU1ZDVlMWFmNjAwZjYyMjA3NDQ0ZWM4ZWFiZjU1NDU2ZWQwYzRjMDIyMDNkODAzYjMwZDU3NmFhYjE4YjcwOTgzYjFjZjNiNWM1MDZiMzA0OGI5ZDkwODI3OGZlMTcyY2E4ZWMyMjM4ODAwMSIsIjMwNDUwMjIxMDBiYTE2YTI0MWY2OTE1MTZlZDMwZjA1MzEzMGRiMTRlNDMwMTdjOTAyM2YzNjc0NWU0ZWVlZjIzMDhlNzg1NDQzMDIyMDVmZmU1OGNlM2Y3ZDMwNTdlODNiOGNjYTJlOTZiMWIxYjhlYzNhOTdiNTZmODM4NTEzZDM1YTc5OGNkNTIyMzYwMSIsIjUyMjEwM2NmZWFhYzQyODAyMWMxN2U5M2JjZTNhMDkwN2VlYzBhZGU2ZDcyYTBkMmYzMTM3MDYyNDhlZjUzYzhlOWFlMTUyMTAyN2ZjYTlmYjllNjM2ZDAzNTY2ZmFmZjhjMzQ4YjdiN2Q5MTQzNjk1ZDAxMTE3ZTJkYTIyMTE5NDc2MTM2ODRmMzIxMDJmZWJlMDJiN2ExZTY3NmVkYzdiZTE5YmRiZjE3OTY2NzlkMzNhODkyZjUwZWJjMjc1NzY2YTE5YTlhYzA4NGFiNTNhZSJdLCJzZXF1ZW5jZSI6NDI5NDk2NzI5NX1dLCJ2b3V0IjpbeyJ2YWx1ZSI6MC4wMDAwMjUsIm4iOjAsInNjcmlwdFB1YktleSI6eyJhc20iOiJPUF9IQVNIMTYwIGFlYmJmOWQ3NTNmNGUwNWE4N2IzZTYyZDI4MWMzNDc1NWRhZDA3MGMgT1BfRVFVQUwiLCJoZXgiOiJhOTE0YWViYmY5ZDc1M2Y0ZTA1YTg3YjNlNjJkMjgxYzM0NzU1ZGFkMDcwYzg3IiwidHlwZSI6InNjcmlwdGhhc2gifX0seyJ2YWx1ZSI6MC4wMDAwMjUsIm4iOjEsInNjcmlwdFB1YktleSI6eyJhc20iOiJPUF9IQVNIMTYwIGFlYmJmOWQ3NTNmNGUwNWE4N2IzZTYyZDI4MWMzNDc1NWRhZDA3MGMgT1BfRVFVQUwiLCJoZXgiOiJhOTE0YWViYmY5ZDc1M2Y0ZTA1YTg3YjNlNjJkMjgxYzM0NzU1ZGFkMDcwYzg3IiwidHlwZSI6InNjcmlwdGhhc2gifX0seyJ2YWx1ZSI6MC4wMDAwMjUsIm4iOjIsInNjcmlwdFB1YktleSI6eyJhc20iOiJPUF9IQVNIMTYwIGFlYmJmOWQ3NTNmNGUwNWE4N2IzZTYyZDI4MWMzNDc1NWRhZDA3MGMgT1BfRVFVQUwiLCJoZXgiOiJhOTE0YWViYmY5ZDc1M2Y0ZTA1YTg3YjNlNjJkMjgxYzM0NzU1ZGFkMDcwYzg3IiwidHlwZSI6InNjcmlwdGhhc2gifX0seyJ2YWx1ZSI6MC4wMDAwMjUsIm4iOjMsInNjcmlwdFB1YktleSI6eyJhc20iOiJPUF9IQVNIMTYwIGFlYmJmOWQ3NTNmNGUwNWE4N2IzZTYyZDI4MWMzNDc1NWRhZDA3MGMgT1BfRVFVQUwiLCJoZXgiOiJhOTE0YWViYmY5ZDc1M2Y0ZTA1YTg3YjNlNjJkMjgxYzM0NzU1ZGFkMDcwYzg3IiwidHlwZSI6InNjcmlwdGhhc2gifX0seyJ2YWx1ZSI6MC4wMDAwMjUsIm4iOjQsInNjcmlwdFB1YktleSI6eyJhc20iOiJPUF9IQVNIMTYwIGFlYmJmOWQ3NTNmNGUwNWE4N2IzZTYyZDI4MWMzNDc1NWRhZDA3MGMgT1BfRVFVQUwiLCJoZXgiOiJhOTE0YWViYmY5ZDc1M2Y0ZTA1YTg3YjNlNjJkMjgxYzM0NzU1ZGFkMDcwYzg3IiwidHlwZSI6InNjcmlwdGhhc2gifX0seyJ2YWx1ZSI6MC4wMDAwMjUsIm4iOjUsInNjcmlwdFB1YktleSI6eyJhc20iOiJPUF9IQVNIMTYwIGFlYmJmOWQ3NTNmNGUwNWE4N2IzZTYyZDI4MWMzNDc1NWRhZDA3MGMgT1BfRVFVQUwiLCJoZXgiOiJhOTE0YWViYmY5ZDc1M2Y0ZTA1YTg3YjNlNjJkMjgxYzM0NzU1ZGFkMDcwYzg3IiwidHlwZSI6InNjcmlwdGhhc2gifX0seyJ2YWx1ZSI6MC4wMDAwMjUsIm4iOjYsInNjcmlwdFB1YktleSI6eyJhc20iOiJPUF9IQVNIMTYwIGFlYmJmOWQ3NTNmNGUwNWE4N2IzZTYyZDI4MWMzNDc1NWRhZDA3MGMgT1BfRVFVQUwiLCJoZXgiOiJhOTE0YWViYmY5ZDc1M2Y0ZTA1YTg3YjNlNjJkMjgxYzM0NzU1ZGFkMDcwYzg3IiwidHlwZSI6InNjcmlwdGhhc2gifX0seyJ2YWx1ZSI6MC4wMDAwMjUsIm4iOjcsInNjcmlwdFB1YktleSI6eyJhc20iOiJPUF9IQVNIMTYwIGFlYmJmOWQ3NTNmNGUwNWE4N2IzZTYyZDI4MWMzNDc1NWRhZDA3MGMgT1BfRVFVQUwiLCJoZXgiOiJhOTE0YWViYmY5ZDc1M2Y0ZTA1YTg3YjNlNjJkMjgxYzM0NzU1ZGFkMDcwYzg3IiwidHlwZSI6InNjcmlwdGhhc2gifX0seyJ2YWx1ZSI6MC4wMDAwMjUsIm4iOjgsInNjcmlwdFB1YktleSI6eyJhc20iOiJPUF9IQVNIMTYwIGFlYmJmOWQ3NTNmNGUwNWE4N2IzZTYyZDI4MWMzNDc1NWRhZDA3MGMgT1BfRVFVQUwiLCJoZXgiOiJhOTE0YWViYmY5ZDc1M2Y0ZTA1YTg3YjNlNjJkMjgxYzM0NzU1ZGFkMDcwYzg3IiwidHlwZSI6InNjcmlwdGhhc2gifX0seyJ2YWx1ZSI6MC4wMDAwMjUsIm4iOjksInNjcmlwdFB1YktleSI6eyJhc20iOiJPUF9IQVNIMTYwIGFlYmJmOWQ3NTNmNGUwNWE4N2IzZTYyZDI4MWMzNDc1NWRhZDA3MGMgT1BfRVFVQUwiLCJoZXgiOiJhOTE0YWViYmY5ZDc1M2Y0ZTA1YTg3YjNlNjJkMjgxYzM0NzU1ZGFkMDcwYzg3IiwidHlwZSI6InNjcmlwdGhhc2gifX0seyJ2YWx1ZSI6MC4wMDA0NiwibiI6MTAsInNjcmlwdFB1YktleSI6eyJhc20iOiJPUF9IQVNIMTYwIDA4NjJkOTFmMzk4NWZjMjcyOWEwNzdiMTE1NzE2MzZkMjk0MDdmNWEgT1BfRVFVQUwiLCJoZXgiOiJhOTE0MDg2MmQ5MWYzOTg1ZmMyNzI5YTA3N2IxMTU3MTYzNmQyOTQwN2Y1YTg3IiwidHlwZSI6InNjcmlwdGhhc2gifX1dfSx7ImhleCI6IjAxMDAwMDAwMDAwMTE1YWY2ZTlhMjgzNjFiN2U3ZGIzMTQyM2ZiYzBkNTY5NDNlNDcxMDIwODAyNDk0MTQ5N2FkOWM3ZWQ3OWM5MzMxYTAwMDAwMDAwMDBmZmZmZmZmZjUwNzkwZGU1YWY1NDRmZjU2NDk2ZDMyYmQyODg2ZmE5MWM3ODVhYmRhZTRkMjAxYjExNjQ0YWI2MjhmZjQ2ZWQwMDAwMDAwMDAwZmZmZmZmZmZkNGFhODBjNzIzZjA5ZWZjMGI1Y2JhZWMxODAzNTI5MjcwZmYyNTRlOWU5ODA1ZDBjYWI4Y2JmZDUzOTcwMmYwMDAwMDAwMDAwMGZmZmZmZmZmMGIzNzkyZDVkYjkyOTViMDQzOTQ3ZDk0MThhZjNlMzVmM2E4M2VhNDc1YmJiYmMwNWY5ZTNhZmU3NzY0ZjhmNzAwMDAwMDAwMDBmZmZmZmZmZjQ2MGRlMTc1ZWVhNWQwZWEwYWFlMDAyNTU5ZDMxNzRlZjRlODIwNjIzZGMyOWViZTkyNWM2ODBjYWMzZDA3ZmEwMDAwMDAwMDAwZmZmZmZmZmZiMjE2OWQ0YTc4MmUwODExMzc3NTEzMmMwYjRjZWJmOTYxZDIyNjM4MWNlMjI5NTZkMmI4NWI4NzY1MWM0ZmZkMDAwMDAwMDAwMGZmZmZmZmZmNTEyNTA5MDcwNzE0YjZkMWFlMGEyZGY2M2M0YjUwMTllMTc5YTQ2NTQwMjUwMWZjNWJkZTliMDQ1MzM1NmZmZDAwMDAwMDAwMDBmZmZmZmZmZjg1NDRkYzc1YzQ5ZWNmMTliNGNhM2IxZmI3NDEzMmQ0MTViYTU3MDExNmI5MmUxOGU2MmI4NDZhZGVhNWVlZmQwMDAwMDAwMDAwZmZmZmZmZmZkMGVjNDk0NWQyYzRlZDU5NjUwODIwZDI1M2VkOWQ4NTk3ZGE3NjZkNTc4MzM1ZDQzMjg0NTgxYmM1Mjg5MTliMDIwMDAwMDAwMGZmZmZmZmZmMDhkMDhiYjIzMjZlMWVlZGExYjE3MTg0MGFlYWY0YTRhMzg5ZDM4MTQyM2RlMGQwNTlhNWNkMjhlNWNhYWM4OTAyMDAwMDAwMDBmZmZmZmZmZjQ4MWI0NTI1NTdmYzRhZmJhOThmMGRkZTMwYTk0MjQ3MDczMmVkNjU3ZWVmNDdmYWVkYzY5ZTg1MTA1ZWIzYWUwMjAwMDAwMDAwZmZmZmZmZmY2YjI3ZWRhY2JmZGM5ODEyNTk0ZDBiZGJkN2E3YTM3MjM0YTVmZWI3OTFjY2NiNzA1NGU1MjRiMDQ0ZmU0NTA4MDAwMDAwMDAwMGZmZmZmZmZmMzk4MzdkNTVmZTJkNGUzNjgyOWYxY2M5YjMyYTM3ODJjNjk2MDYwN2I0YzNhODU0OGMxMDQzYzhmOWY4MzUyMDAwMDAwMDAwMDBmZmZmZmZmZjNjNzllNzU5NDZjMDk0NjA5NWM3NTc1NmY0MWM2ZTEzY2E3OTIxNGZlYjMwZGIzNDc1ZTI1NjViNjUxMmQzMjIwMDAwMDAwMDAwZmZmZmZmZmYzYWZmNWVmZDdkNTU2OGVmNjA2YWM5NGMyMjA5OWYxNGQwMzg5MDY4YjRmODIwZTU3YjIyY2E4MDVlYWZhZjJkMDAwMDAwMDAwMGZmZmZmZmZmZTIzZmMyMDAwNjY3NTNiYmIzOTQzM2NhM2MzNTE4NjgyOTZlZjU2MGQ5YTgwOGM3NjAzZjk0OWYwOWMwMzcyZjAwMDAwMDAwMDBmZmZmZmZmZjk5MGJmZWQ1M2ZiN2ZmNTkyNGNlOWViMjNkYjIzMThhY2JkNzllMDg4NjZjM2UyZmVmMzUwYzgzZThhYmE1MzAwMDAwMDAwMDAwZmZmZmZmZmYwMTE4OTFjZDM1OWNhNDQyM2YyZjAzNmU1MDRlY2Q4YWY3NWFjMjkyYjE2NGVjYTAyYmFiNDQ4OTViZjdhYTMwMDAwMDAwMDAwMGZmZmZmZmZmNzhiYjk3NDU2ZDg3Y2IwODllYWU2YTY3Njk0NDBjNmU3Yjk2OTMwYTI5OGJiOGVjNDNhNWU2YzcyOTAyYmIzNzAwMDAwMDAwMDBmZmZmZmZmZjk4ODNlM2Y1OTBhMzE4N2FlNTJlMWJkM2JjZWM2OTAwMTc2ZmJjYmU4YzAzOGM5NTg3NGYyZjM2ZGJiMmQ1MzcwMDAwMDAwMDAwZmZmZmZmZmZkZmFhNDc0ZWY0NGFlMjY3OWI0NWYzNDYwMGRjODM4OGRlZWFiM2VlODg3ZDZkNGYxOGU1MzgwOTUzNTlmNjNiMDAwMDAwMDAwMGZmZmZmZmZmMDNjMTA4MDAwMDAwMDAwMDAwMTYwMDE0MjE0MjBkZDk0MTY5NjBjZDQ1MGFmNDk2NzFlYTllNzExZWQyZjMzOTgwOTY5ODAwMDAwMDAwMDAxNjAwMTQzYzhjYTVhMmEyNzA5YWI1N2Y0MDYwMjY3YzRiNDMzNGQzYmE5Yjk5N2RlMDA2MDAwMDAwMDAwMDE2MDAxNDIxNDIwZGQ5NDE2OTYwY2Q0NTBhZjQ5NjcxZWE5ZTcxMWVkMmYzMzkwMjQ4MzA0NTAyMjEwMGRkNDBjOGYxYzM5Njg2ZDAzNTk0NWIxZGEzZDExZjYzMTQ0NzA4ZjdhYWNlNTU4Nzk3YjlkOWVjMTA0NTk3MGUwMjIwNTI5NmYwODU3ZmViNjI1ODYzOGNlNTg2YzE2M2UzNjQzNTM0OTJjMjIxZjM4YzY1ZTA0YzI1MWZkYTEzNGI5YTAxMjEwMjhmOGE3YjBjYzQxZmQ1NWQ3MGNlZTgyMzBmNDA5ZmQ4MDJlYzU3ZGVmZGExNDY1M2M0MjYyMTQ1NDNjN2ZiMzQwMjQ3MzA0NDAyMjAxNDg2NTZmNTI1OGY3YjFmNjZhZTE0MTY3NDdjNTFlN2JiZWZjNTUyMDhiZGMwNzAyYWE2NmZlYWVhZTgyYTQxMDIyMDViMGEzMWZmMzkyN2M3ZGFiZjJiNmFkYTM5MTAyMzZjOTdjYjU2NGM3NWI3NzUyOGRmMzJiOWU5NTMxNTIxNTUwMTIxMDI4ZjhhN2IwY2M0MWZkNTVkNzBjZWU4MjMwZjQwOWZkODAyZWM1N2RlZmRhMTQ2NTNjNDI2MjE0NTQzYzdmYjM0MDI0NzMwNDQwMjIwMmIzZTU5NDc2MjJiYjI3ZjQ5NzZiNDk1OTUxMTU1Mzg1NjQ2YjU3YzNjNDYxYjkyZTA4MjIzNDFhNThiYTU4ZTAyMjAyYTg5NTFlMDQ3NjkzOWQ2MWVhZTRlMDkxNGVjMDFjZDc4MmMyOWRlZDY2OWE1OWI5NWUwOTFmNTYxZWI5Njg5MDEyMTAyOGY4YTdiMGNjNDFmZDU1ZDcwY2VlODIzMGY0MDlmZDgwMmVjNTdkZWZkYTE0NjUzYzQyNjIxNDU0M2M3ZmIzNDAyNDgzMDQ1MDIyMTAwZDgxZDU2ZDc1YjI4MGUxZWM4ZDUxMjljOWYzOGUxMmJjZjQ1NDNjYTExNDEwZjE0YmQzMjFhMGE3MzY5ZDg2YjAyMjAyYmEwY2ZlMTRmZTFhYTdjZDQ1NGMzNzVlYjc0MDE2NjUzN2ZiYTVmMjgxMzMyMDI1NDVlYjZjZDY3Y2U4NzFiMDEyMTAyOGY4YTdiMGNjNDFmZDU1ZDcwY2VlODIzMGY0MDlmZDgwMmVjNTdkZWZkYTE0NjUzYzQyNjIxNDU0M2M3ZmIzNDAyNDczMDQ0MDIyMDY5MDQ5Yzc0ZDg4ZDdkMjNkMDdjMzUwNzQ3NDQ0OGIxMDU3ZjE0MDc3MDVjZTRmNWUzODhhOWMxMWIxYzdhM2MwMjIwMmM4NzZiNTUwYzI0MmZhMDg5NDViZDM0ZGJmZDViOTllODUwYWVjYjNlMzFhNTE0ZGVmYjFiNjllYTI1MTdiZjAxMjEwMjhmOGE3YjBjYzQxZmQ1NWQ3MGNlZTgyMzBmNDA5ZmQ4MDJlYzU3ZGVmZGExNDY1M2M0MjYyMTQ1NDNjN2ZiMzQwMjQ4MzA0NTAyMjEwMDg4MTI4ZWZlOWFlMzZjMDhiYmViMmNlYzI2NWExNWZmYzA5MTg2YmZjNThjNjFmNzhhNWYyNmY2ZTFjMTNjYmMwMjIwNWU2N2E4NjFjOGU1YjRiNTFiYWEwMDVmZjAzNGQ5MDk2OGYwNTI0NzgwMTY5NDcxNjY1MTZiOTVlMzExOTA2NTAxMjEwMjhmOGE3YjBjYzQxZmQ1NWQ3MGNlZTgyMzBmNDA5ZmQ4MDJlYzU3ZGVmZGExNDY1M2M0MjYyMTQ1NDNjN2ZiMzQwMjQ4MzA0NTAyMjEwMDkyN2ZiNTliNmFlNGMyZDNhMzM3ZWI3ZTRkNWM5ZGIzZWY1NzZiZTlhYzVmZGFjOWQ2MGE2OWVjZTg2ODlkNDUwMjIwNWUyMDRkYWQ3ODJmM2VmZjNkZDBlODNlODZlMDZhOWUzMGE2ZjI5NGY5YWE2MDVhNzMxZWYzMzhlZjNmOGY3NzAxMjEwMjhmOGE3YjBjYzQxZmQ1NWQ3MGNlZTgyMzBmNDA5ZmQ4MDJlYzU3ZGVmZGExNDY1M2M0MjYyMTQ1NDNjN2ZiMzQwMjQ3MzA0NDAyMjAzMmRjZDMxOGI5ZWVkNDI3Y2JhZTA2YzE4YTliYmZlYmVlZWJmMjNhZjAyYTU4ZmI5NGIxZGFmYzc3NTdmNTEzMDIyMDdmNjc0OTMwODIwYmQ1ZGZkNGQ4MDE4ODZhZTEwYjQ3ZDI5NDgzOGIxYmM2M2NiM2ZiZWE0YjE5MGM3N2M0ZmQwMTIxMDI4ZjhhN2IwY2M0MWZkNTVkNzBjZWU4MjMwZjQwOWZkODAyZWM1N2RlZmRhMTQ2NTNjNDI2MjE0NTQzYzdmYjM0MDI0NzMwNDQwMjIwMmNiZTczYWFhZWMyMzZlNzhiZjY5MWEyYTAyZDQ0NzZhYjM5ZGFkNDg3ZTljNzY0NDIyMGUyZWJjZWEwZWZkMjAyMjAzNzBlZjQ3NGZiYzMyYWU3NDc3MWUzMjdhZmZiZmUyZTAzMzU2MmRmZWM4N2MwNzA4NDc0MzM1OTgxOGVhZjUzMDEyMTAyOGY4YTdiMGNjNDFmZDU1ZDcwY2VlODIzMGY0MDlmZDgwMmVjNTdkZWZkYTE0NjUzYzQyNjIxNDU0M2M3ZmIzNDAyNDczMDQ0MDIyMDA3NTBkODM0OWU2ODc4MWYyNjEzNGJkOGQ4MjA3YTAxNzI0YTAyZDY4NjE2ZmE0ODYzZDBhZDliMzMyNjk3YzgwMjIwN2UzYzBiMGE4Y2E3ZWIyN2M3M2QxMDNiZGE5MjQ5Njg2Y2ViY2YxMTJiNmMwNWNkZDcyYjU4ZjJmOTExN2JiOTAxMjEwMjhmOGE3YjBjYzQxZmQ1NWQ3MGNlZTgyMzBmNDA5ZmQ4MDJlYzU3ZGVmZGExNDY1M2M0MjYyMTQ1NDNjN2ZiMzQwMjQ3MzA0NDAyMjAxNjY5ZTMwNjY3MjVkZjk2YWNhYmVhZjAwOGJhNmNkNDIxNTk1YmIwMzRkMzI5NzI5ZDQ5NjdlOTEyYzM1ZGZkMDIyMDI4YzhlYjY0YTRkMjZlOGI4NDQwMjdiODliMWEwZTZmYjNhMjUwZGZkMGU0YjBiNDM5ZTBlMDdiNjA0ODA5YjEwMTIxMDI4ZjhhN2IwY2M0MWZkNTVkNzBjZWU4MjMwZjQwOWZkODAyZWM1N2RlZmRhMTQ2NTNjNDI2MjE0NTQzYzdmYjM0MDI0NzMwNDQwMjIwMjBjMjE1ZmZmYjcxYjZmZmQxZDExYzk0NGY0YTFlMDM5YjBmZDU1ZjJlMmRkNGExMDQyOTFkYzQ3MDdhY2Y5ZDAyMjA1ODUxMmJlNmU0MTZmZDg5MWFmYWNiOGMyNmQ1ZTM5MDRjM2FiZjY5N2U1NDhkNjAxZTRhOGQxNWNiMDY5ODZmMDEyMTAyOGY4YTdiMGNjNDFmZDU1ZDcwY2VlODIzMGY0MDlmZDgwMmVjNTdkZWZkYTE0NjUzYzQyNjIxNDU0M2M3ZmIzNDAyNDczMDQ0MDIyMDE4YWIyMGJkMDE3ZDkzYmY4MzMxNWZiMTlmMWFjNWExNjFlMzI0NWU0NTRmMTJlYmY4NzE5YjgzYjQ4NWU2MjMwMjIwNDFkNGM2OTY3MzFiOTNmODg0NzdiMDM5MWRkYTJhMDFhN2M5ZThlYTk2YzQxZWNjZmIyZTE0NTliNTkwNmI5NTAxMjEwMjhmOGE3YjBjYzQxZmQ1NWQ3MGNlZTgyMzBmNDA5ZmQ4MDJlYzU3ZGVmZGExNDY1M2M0MjYyMTQ1NDNjN2ZiMzQwMjQ3MzA0NDAyMjA2ZjZkNWRhNjVkNTEwNjk5MTgzMzExOWM0NWUyODZmMzVhNDE3MzlhNmJjZWEyZmVmMzI1MTJlNDQzNTI4MTEwMDIyMDM0NjVjNGJjNWMzYzg5ZjQxYzE4ZGZiNmVlODc1ZmIzYWE5NzgzYjI4ZjlhNWU0YWYzZDFjODMzMWU5YzM0OWUwMTIxMDI4ZjhhN2IwY2M0MWZkNTVkNzBjZWU4MjMwZjQwOWZkODAyZWM1N2RlZmRhMTQ2NTNjNDI2MjE0NTQzYzdmYjM0MDI0NzMwNDQwMjIwN2ZmZmYxMGVhODhkNmM4Mzc3ODE3YmRmODA5MTM0YmVlYzdjNGJjMDZlNzU4NWZjNzIyNTQ1OWE1YmRiOWMzYTAyMjA1ZTY0NDQ5YTJhMjU3ODY0NDVhMTMyYWIwZTczOTdiYTJlNTM1NDMxMmQ4ZWMzOTIxMzJkNmU1NDBiOGZkMTk3MDEyMTAyOGY4YTdiMGNjNDFmZDU1ZDcwY2VlODIzMGY0MDlmZDgwMmVjNTdkZWZkYTE0NjUzYzQyNjIxNDU0M2M3ZmIzNDAyNDgzMDQ1MDIyMTAwYjg0YzJkNmI2NDZjYmZiYWNmM2Y0YzM2OTgxYjAwYmU2OGY2MzRjZDgzMGY0YTYzODUwOGYwYzFhYTIwNGIyZTAyMjA0NWI5ZTAwZDA4ZmUwMDkyNWMwNDc1NDY4MWVmMGFjY2I5ZWE5NDI2ZDM3NzVhMTNlZWE4ZjE3MWNhMjVkODIzMDEyMTAyOGY4YTdiMGNjNDFmZDU1ZDcwY2VlODIzMGY0MDlmZDgwMmVjNTdkZWZkYTE0NjUzYzQyNjIxNDU0M2M3ZmIzNDAyNDczMDQ0MDIyMDRjZjQyZTYyMDYxZTE5NjMxNDFkZTk4MDU0NTQ0NjEyMTUyZDdkOTEwNjgzMTFhMGE0NWQ0YWU1NzU0M2Q1ZmIwMjIwNTBlZDYzMWQ2OGQ5MzcxZmQ1YTViMjU1MDY0YjdkNjEyZWJhZGY2MDg2NmVhMzNlZTk5ODEyYjQwYzg5NjczYjAxMjEwMjhmOGE3YjBjYzQxZmQ1NWQ3MGNlZTgyMzBmNDA5ZmQ4MDJlYzU3ZGVmZGExNDY1M2M0MjYyMTQ1NDNjN2ZiMzQwMjQ3MzA0NDAyMjA3ODlmYjI3MDhmY2I3YTUxZWIyNjE0N2JlM2M1YmRkMzk2ZTMxOTZmYjQxMzc1NTE3Y2ZhMzBjN2Y0MjljZDBjMDIyMDRiZmE1MzU5ZTFmMGVhOGEyMThmZWU2MzJmZWFiMGZjNTUyN2RiNDI0MGZiY2VmYzMyMGU2YmJhOWYyZjMxYTcwMTIxMDI4ZjhhN2IwY2M0MWZkNTVkNzBjZWU4MjMwZjQwOWZkODAyZWM1N2RlZmRhMTQ2NTNjNDI2MjE0NTQzYzdmYjM0MDI0NzMwNDQwMjIwNjkyYmRkNDJjNmU0MWRmMzYzMDQ3NThmMWYwZTU4N2I2ZTZhNTAxMThiMDUzYzc3OTg3YTdjMzEwYTlhZjJkMTAyMjAzMTU2OWFkODQ3ZGZmMTNhZjVjMmRlNjhlZTUyZDlkYTJlZDNmODJhZmQ2N2M3ZGI4NjJlMThmM2UyNTY0OTFhMDEyMTAyOGY4YTdiMGNjNDFmZDU1ZDcwY2VlODIzMGY0MDlmZDgwMmVjNTdkZWZkYTE0NjUzYzQyNjIxNDU0M2M3ZmIzNDAyNDgzMDQ1MDIyMTAwZTg0OTc5NzRmZmI4YzFlNDJkYzQyNTUzZTA3ODlmMWE0MDllM2Y5MWVmYTE2OTA4OTdiM2E0YzZhNWNjNTQ1OTAyMjAyNjJlNzUxOGY4YThhM2UwMTc1MWIyOWE3Y2ZiOGIwODhjODY1ZDY3YjY3ZjRmZjM3ZjBjZWU3ZjJmZmFjZjVhMDEyMTAyOGY4YTdiMGNjNDFmZDU1ZDcwY2VlODIzMGY0MDlmZDgwMmVjNTdkZWZkYTE0NjUzYzQyNjIxNDU0M2M3ZmIzNDAyNDczMDQ0MDIyMDRlZWMzNDNjN2U3Mzg1NTQ3YWViMmU3Zjc0OGQ2M2NhOTZjMTdlNmE3YmQ4ZjQxOTAxODUxNTkwNGZjNDBhNTcwMjIwMmY2MzA2ZjY1MTA3MjAxZTY5Y2NkYzIzYmY1YWY0Y2UwNTA4ZmUxODM4NDU3ZWEwNjc2M2FmMWI4MDg0MTdjYjAxMjEwMjhmOGE3YjBjYzQxZmQ1NWQ3MGNlZTgyMzBmNDA5ZmQ4MDJlYzU3ZGVmZGExNDY1M2M0MjYyMTQ1NDNjN2ZiMzQwMDAwMDAwMCIsInR4aWQiOiJlMzE1YTdlN2RlNzk4MjdkOWY5MDU3M2UzNDJhY2UxNDcyYjhlOWViOWU1NGVjYWVmYzY4MGY5ZjY3N2Q2MjcyIiwiaGFzaCI6IjgyNmM5ZWM1NzFkODY5OWY2NDRiYjVkMjQwZDQ0M2E3NTc3YmQ1ODdmMzY5NzllMDlmNGNkNmJkMTA1Y2I4NTkiLCJzaXplIjozMjE5LCJ2c2l6ZSI6MTUyOCwid2VpZ2h0Ijo2MTExLCJ2ZXJzaW9uIjoxLCJsb2NrdGltZSI6MCwidmluIjpbeyJ0eGlkIjoiMWEzM2M5NzllZGM3ZDk3YTQ5NDE0OTAyMDgwMjcxZTQ0MzY5ZDVjMGZiMjMxNGIzN2Q3ZTFiMzYyODlhNmVhZiIsInZvdXQiOjAsInNjcmlwdFNpZyI6eyJhc20iOiIiLCJoZXgiOiIifSwidHhpbndpdG5lc3MiOlsiMzA0NTAyMjEwMGRkNDBjOGYxYzM5Njg2ZDAzNTk0NWIxZGEzZDExZjYzMTQ0NzA4ZjdhYWNlNTU4Nzk3YjlkOWVjMTA0NTk3MGUwMjIwNTI5NmYwODU3ZmViNjI1ODYzOGNlNTg2YzE2M2UzNjQzNTM0OTJjMjIxZjM4YzY1ZTA0YzI1MWZkYTEzNGI5YTAxIiwiMDI4ZjhhN2IwY2M0MWZkNTVkNzBjZWU4MjMwZjQwOWZkODAyZWM1N2RlZmRhMTQ2NTNjNDI2MjE0NTQzYzdmYjM0Il0sInNlcXVlbmNlIjo0Mjk0OTY3Mjk1fSx7InR4aWQiOiJlZDQ2ZmYyOGI2NGE2NDExMWIyMDRkYWViZDVhNzgxY2E5NmY4OGQyMmJkMzk2NjRmNTRmNTRhZmU1MGQ3OTUwIiwidm91dCI6MCwic2NyaXB0U2lnIjp7ImFzbSI6IiIsImhleCI6IiJ9LCJ0eGlud2l0bmVzcyI6WyIzMDQ0MDIyMDE0ODY1NmY1MjU4ZjdiMWY2NmFlMTQxNjc0N2M1MWU3YmJlZmM1NTIwOGJkYzA3MDJhYTY2ZmVhZWFlODJhNDEwMjIwNWIwYTMxZmYzOTI3YzdkYWJmMmI2YWRhMzkxMDIzNmM5N2NiNTY0Yzc1Yjc3NTI4ZGYzMmI5ZTk1MzE1MjE1NTAxIiwiMDI4ZjhhN2IwY2M0MWZkNTVkNzBjZWU4MjMwZjQwOWZkODAyZWM1N2RlZmRhMTQ2NTNjNDI2MjE0NTQzYzdmYjM0Il0sInNlcXVlbmNlIjo0Mjk0OTY3Mjk1fSx7InR4aWQiOiJmMDAyOTc1M2ZkY2JiOGNhZDAwNTk4OWU0ZTI1ZmY3MDkyNTIwMzE4ZWNiYTVjMGJmYzllZjAyM2M3ODBhYWQ0Iiwidm91dCI6MCwic2NyaXB0U2lnIjp7ImFzbSI6IiIsImhleCI6IiJ9LCJ0eGlud2l0bmVzcyI6WyIzMDQ0MDIyMDJiM2U1OTQ3NjIyYmIyN2Y0OTc2YjQ5NTk1MTE1NTM4NTY0NmI1N2MzYzQ2MWI5MmUwODIyMzQxYTU4YmE1OGUwMjIwMmE4OTUxZTA0NzY5MzlkNjFlYWU0ZTA5MTRlYzAxY2Q3ODJjMjlkZWQ2NjlhNTliOTVlMDkxZjU2MWViOTY4OTAxIiwiMDI4ZjhhN2IwY2M0MWZkNTVkNzBjZWU4MjMwZjQwOWZkODAyZWM1N2RlZmRhMTQ2NTNjNDI2MjE0NTQzYzdmYjM0Il0sInNlcXVlbmNlIjo0Mjk0OTY3Mjk1fSx7InR4aWQiOiJmN2Y4NjQ3N2ZlM2E5ZTVmYzBiYmJiNzVhNDNlYThmMzM1M2VhZjE4OTQ3ZDk0NDNiMDk1OTJkYmQ1OTIzNzBiIiwidm91dCI6MCwic2NyaXB0U2lnIjp7ImFzbSI6IiIsImhleCI6IiJ9LCJ0eGlud2l0bmVzcyI6WyIzMDQ1MDIyMTAwZDgxZDU2ZDc1YjI4MGUxZWM4ZDUxMjljOWYzOGUxMmJjZjQ1NDNjYTExNDEwZjE0YmQzMjFhMGE3MzY5ZDg2YjAyMjAyYmEwY2ZlMTRmZTFhYTdjZDQ1NGMzNzVlYjc0MDE2NjUzN2ZiYTVmMjgxMzMyMDI1NDVlYjZjZDY3Y2U4NzFiMDEiLCIwMjhmOGE3YjBjYzQxZmQ1NWQ3MGNlZTgyMzBmNDA5ZmQ4MDJlYzU3ZGVmZGExNDY1M2M0MjYyMTQ1NDNjN2ZiMzQiXSwic2VxdWVuY2UiOjQyOTQ5NjcyOTV9LHsidHhpZCI6ImZhMDczZGFjMGM2ODVjOTJiZTllYzIzZDYyMjBlOGY0NGUxN2QzNTkyNTAwYWUwYWVhZDBhNWVlNzVlMTBkNDYiLCJ2b3V0IjowLCJzY3JpcHRTaWciOnsiYXNtIjoiIiwiaGV4IjoiIn0sInR4aW53aXRuZXNzIjpbIjMwNDQwMjIwNjkwNDljNzRkODhkN2QyM2QwN2MzNTA3NDc0NDQ4YjEwNTdmMTQwNzcwNWNlNGY1ZTM4OGE5YzExYjFjN2EzYzAyMjAyYzg3NmI1NTBjMjQyZmEwODk0NWJkMzRkYmZkNWI5OWU4NTBhZWNiM2UzMWE1MTRkZWZiMWI2OWVhMjUxN2JmMDEiLCIwMjhmOGE3YjBjYzQxZmQ1NWQ3MGNlZTgyMzBmNDA5ZmQ4MDJlYzU3ZGVmZGExNDY1M2M0MjYyMTQ1NDNjN2ZiMzQiXSwic2VxdWVuY2UiOjQyOTQ5NjcyOTV9LHsidHhpZCI6ImZkNGYxYzY1ODc1YmI4ZDI1NjI5ZTIxYzM4MjZkMjYxZjllYjRjMGIyYzEzNzUzNzExMDgyZTc4NGE5ZDE2YjIiLCJ2b3V0IjowLCJzY3JpcHRTaWciOnsiYXNtIjoiIiwiaGV4IjoiIn0sInR4aW53aXRuZXNzIjpbIjMwNDUwMjIxMDA4ODEyOGVmZTlhZTM2YzA4YmJlYjJjZWMyNjVhMTVmZmMwOTE4NmJmYzU4YzYxZjc4YTVmMjZmNmUxYzEzY2JjMDIyMDVlNjdhODYxYzhlNWI0YjUxYmFhMDA1ZmYwMzRkOTA5NjhmMDUyNDc4MDE2OTQ3MTY2NTE2Yjk1ZTMxMTkwNjUwMSIsIjAyOGY4YTdiMGNjNDFmZDU1ZDcwY2VlODIzMGY0MDlmZDgwMmVjNTdkZWZkYTE0NjUzYzQyNjIxNDU0M2M3ZmIzNCJdLCJzZXF1ZW5jZSI6NDI5NDk2NzI5NX0seyJ0eGlkIjoiZmQ2ZjM1NTMwNDliZGU1YmZjMDEyNTQwNjVhNDc5ZTExOTUwNGIzY2Y2MmQwYWFlZDFiNjE0MDcwNzA5MjU1MSIsInZvdXQiOjAsInNjcmlwdFNpZyI6eyJhc20iOiIiLCJoZXgiOiIifSwidHhpbndpdG5lc3MiOlsiMzA0NTAyMjEwMDkyN2ZiNTliNmFlNGMyZDNhMzM3ZWI3ZTRkNWM5ZGIzZWY1NzZiZTlhYzVmZGFjOWQ2MGE2OWVjZTg2ODlkNDUwMjIwNWUyMDRkYWQ3ODJmM2VmZjNkZDBlODNlODZlMDZhOWUzMGE2ZjI5NGY5YWE2MDVhNzMxZWYzMzhlZjNmOGY3NzAxIiwiMDI4ZjhhN2IwY2M0MWZkNTVkNzBjZWU4MjMwZjQwOWZkODAyZWM1N2RlZmRhMTQ2NTNjNDI2MjE0NTQzYzdmYjM0Il0sInNlcXVlbmNlIjo0Mjk0OTY3Mjk1fSx7InR4aWQiOiJmZGVlYTVkZTZhODQyYmU2MTgyZWI5MTYwMTU3YmExNWQ0MzI0MWI3MWYzYmNhYjQxOWNmOWVjNDc1ZGM0NDg1Iiwidm91dCI6MCwic2NyaXB0U2lnIjp7ImFzbSI6IiIsImhleCI6IiJ9LCJ0eGlud2l0bmVzcyI6WyIzMDQ0MDIyMDMyZGNkMzE4YjllZWQ0MjdjYmFlMDZjMThhOWJiZmViZWVlYmYyM2FmMDJhNThmYjk0YjFkYWZjNzc1N2Y1MTMwMjIwN2Y2NzQ5MzA4MjBiZDVkZmQ0ZDgwMTg4NmFlMTBiNDdkMjk0ODM4YjFiYzYzY2IzZmJlYTRiMTkwYzc3YzRmZDAxIiwiMDI4ZjhhN2IwY2M0MWZkNTVkNzBjZWU4MjMwZjQwOWZkODAyZWM1N2RlZmRhMTQ2NTNjNDI2MjE0NTQzYzdmYjM0Il0sInNlcXVlbmNlIjo0Mjk0OTY3Mjk1fSx7InR4aWQiOiI5YjkxMjhjNTFiNTg4NDMyZDQzNTgzNTc2ZDc2ZGE5Nzg1OWRlZDUzZDIyMDA4NjU1OWVkYzRkMjQ1NDllY2QwIiwidm91dCI6Miwic2NyaXB0U2lnIjp7ImFzbSI6IiIsImhleCI6IiJ9LCJ0eGlud2l0bmVzcyI6WyIzMDQ0MDIyMDJjYmU3M2FhYWVjMjM2ZTc4YmY2OTFhMmEwMmQ0NDc2YWIzOWRhZDQ4N2U5Yzc2NDQyMjBlMmViY2VhMGVmZDIwMjIwMzcwZWY0NzRmYmMzMmFlNzQ3NzFlMzI3YWZmYmZlMmUwMzM1NjJkZmVjODdjMDcwODQ3NDMzNTk4MThlYWY1MzAxIiwiMDI4ZjhhN2IwY2M0MWZkNTVkNzBjZWU4MjMwZjQwOWZkODAyZWM1N2RlZmRhMTQ2NTNjNDI2MjE0NTQzYzdmYjM0Il0sInNlcXVlbmNlIjo0Mjk0OTY3Mjk1fSx7InR4aWQiOiI4OWFjY2FlNTI4Y2RhNTU5ZDBlMDNkNDI4MWQzODlhM2E0ZjRlYTBhODQ3MWIxYTFlZDFlNmUzMmIyOGJkMDA4Iiwidm91dCI6Miwic2NyaXB0U2lnIjp7ImFzbSI6IiIsImhleCI6IiJ9LCJ0eGlud2l0bmVzcyI6WyIzMDQ0MDIyMDA3NTBkODM0OWU2ODc4MWYyNjEzNGJkOGQ4MjA3YTAxNzI0YTAyZDY4NjE2ZmE0ODYzZDBhZDliMzMyNjk3YzgwMjIwN2UzYzBiMGE4Y2E3ZWIyN2M3M2QxMDNiZGE5MjQ5Njg2Y2ViY2YxMTJiNmMwNWNkZDcyYjU4ZjJmOTExN2JiOTAxIiwiMDI4ZjhhN2IwY2M0MWZkNTVkNzBjZWU4MjMwZjQwOWZkODAyZWM1N2RlZmRhMTQ2NTNjNDI2MjE0NTQzYzdmYjM0Il0sInNlcXVlbmNlIjo0Mjk0OTY3Mjk1fSx7InR4aWQiOiJhZWIzNWUxMDg1OWVjNmVkZmE0N2VmN2U2NWVkMzIwNzQ3NDJhOTMwZGUwZDhmYTlmYjRhZmM1NzI1NDUxYjQ4Iiwidm91dCI6Miwic2NyaXB0U2lnIjp7ImFzbSI6IiIsImhleCI6IiJ9LCJ0eGlud2l0bmVzcyI6WyIzMDQ0MDIyMDE2NjllMzA2NjcyNWRmOTZhY2FiZWFmMDA4YmE2Y2Q0MjE1OTViYjAzNGQzMjk3MjlkNDk2N2U5MTJjMzVkZmQwMjIwMjhjOGViNjRhNGQyNmU4Yjg0NDAyN2I4OWIxYTBlNmZiM2EyNTBkZmQwZTRiMGI0MzllMGUwN2I2MDQ4MDliMTAxIiwiMDI4ZjhhN2IwY2M0MWZkNTVkNzBjZWU4MjMwZjQwOWZkODAyZWM1N2RlZmRhMTQ2NTNjNDI2MjE0NTQzYzdmYjM0Il0sInNlcXVlbmNlIjo0Mjk0OTY3Mjk1fSx7InR4aWQiOiIwODQ1ZmU0NGIwMjRlNTU0NzBjYmNjOTFiN2ZlYTUzNDcyYTNhN2Q3ZGIwYjRkNTkxMjk4ZGNiZmFjZWQyNzZiIiwidm91dCI6MCwic2NyaXB0U2lnIjp7ImFzbSI6IiIsImhleCI6IiJ9LCJ0eGlud2l0bmVzcyI6WyIzMDQ0MDIyMDIwYzIxNWZmZmI3MWI2ZmZkMWQxMWM5NDRmNGExZTAzOWIwZmQ1NWYyZTJkZDRhMTA0MjkxZGM0NzA3YWNmOWQwMjIwNTg1MTJiZTZlNDE2ZmQ4OTFhZmFjYjhjMjZkNWUzOTA0YzNhYmY2OTdlNTQ4ZDYwMWU0YThkMTVjYjA2OTg2ZjAxIiwiMDI4ZjhhN2IwY2M0MWZkNTVkNzBjZWU4MjMwZjQwOWZkODAyZWM1N2RlZmRhMTQ2NTNjNDI2MjE0NTQzYzdmYjM0Il0sInNlcXVlbmNlIjo0Mjk0OTY3Mjk1fSx7InR4aWQiOiIyMDM1ZjhmOWM4NDMxMDhjNTRhOGMzYjQwNzA2OTZjNjgyMzcyYWIzYzkxYzlmODIzNjRlMmRmZTU1N2Q4MzM5Iiwidm91dCI6MCwic2NyaXB0U2lnIjp7ImFzbSI6IiIsImhleCI6IiJ9LCJ0eGlud2l0bmVzcyI6WyIzMDQ0MDIyMDE4YWIyMGJkMDE3ZDkzYmY4MzMxNWZiMTlmMWFjNWExNjFlMzI0NWU0NTRmMTJlYmY4NzE5YjgzYjQ4NWU2MjMwMjIwNDFkNGM2OTY3MzFiOTNmODg0NzdiMDM5MWRkYTJhMDFhN2M5ZThlYTk2YzQxZWNjZmIyZTE0NTliNTkwNmI5NTAxIiwiMDI4ZjhhN2IwY2M0MWZkNTVkNzBjZWU4MjMwZjQwOWZkODAyZWM1N2RlZmRhMTQ2NTNjNDI2MjE0NTQzYzdmYjM0Il0sInNlcXVlbmNlIjo0Mjk0OTY3Mjk1fSx7InR4aWQiOiIyMmQzMTI2NTViNTZlMjc1MzRkYjMwZWI0ZjIxNzljYTEzNmUxY2Y0NTY1N2M3OTU2MDk0YzA0NjU5ZTc3OTNjIiwidm91dCI6MCwic2NyaXB0U2lnIjp7ImFzbSI6IiIsImhleCI6IiJ9LCJ0eGlud2l0bmVzcyI6WyIzMDQ0MDIyMDZmNmQ1ZGE2NWQ1MTA2OTkxODMzMTE5YzQ1ZTI4NmYzNWE0MTczOWE2YmNlYTJmZWYzMjUxMmU0NDM1MjgxMTAwMjIwMzQ2NWM0YmM1YzNjODlmNDFjMThkZmI2ZWU4NzVmYjNhYTk3ODNiMjhmOWE1ZTRhZjNkMWM4MzMxZTljMzQ5ZTAxIiwiMDI4ZjhhN2IwY2M0MWZkNTVkNzBjZWU4MjMwZjQwOWZkODAyZWM1N2RlZmRhMTQ2NTNjNDI2MjE0NTQzYzdmYjM0Il0sInNlcXVlbmNlIjo0Mjk0OTY3Mjk1fSx7InR4aWQiOiIyZGFmYWY1ZTgwY2EyMjdiZTUyMGY4YjQ2ODkwMzhkMDE0OWYwOTIyNGNjOTZhNjBlZjY4NTU3ZGZkNWVmZjNhIiwidm91dCI6MCwic2NyaXB0U2lnIjp7ImFzbSI6IiIsImhleCI6IiJ9LCJ0eGlud2l0bmVzcyI6WyIzMDQ0MDIyMDdmZmZmMTBlYTg4ZDZjODM3NzgxN2JkZjgwOTEzNGJlZWM3YzRiYzA2ZTc1ODVmYzcyMjU0NTlhNWJkYjljM2EwMjIwNWU2NDQ0OWEyYTI1Nzg2NDQ1YTEzMmFiMGU3Mzk3YmEyZTUzNTQzMTJkOGVjMzkyMTMyZDZlNTQwYjhmZDE5NzAxIiwiMDI4ZjhhN2IwY2M0MWZkNTVkNzBjZWU4MjMwZjQwOWZkODAyZWM1N2RlZmRhMTQ2NTNjNDI2MjE0NTQzYzdmYjM0Il0sInNlcXVlbmNlIjo0Mjk0OTY3Mjk1fSx7InR4aWQiOiIyZjM3YzAwOTlmOTQzZjYwYzcwOGE4ZDk2MGY1NmUyOTY4MTgzNTNjY2EzMzk0YjNiYjUzNjcwNjAwYzIzZmUyIiwidm91dCI6MCwic2NyaXB0U2lnIjp7ImFzbSI6IiIsImhleCI6IiJ9LCJ0eGlud2l0bmVzcyI6WyIzMDQ1MDIyMTAwYjg0YzJkNmI2NDZjYmZiYWNmM2Y0YzM2OTgxYjAwYmU2OGY2MzRjZDgzMGY0YTYzODUwOGYwYzFhYTIwNGIyZTAyMjA0NWI5ZTAwZDA4ZmUwMDkyNWMwNDc1NDY4MWVmMGFjY2I5ZWE5NDI2ZDM3NzVhMTNlZWE4ZjE3MWNhMjVkODIzMDEiLCIwMjhmOGE3YjBjYzQxZmQ1NWQ3MGNlZTgyMzBmNDA5ZmQ4MDJlYzU3ZGVmZGExNDY1M2M0MjYyMTQ1NDNjN2ZiMzQiXSwic2VxdWVuY2UiOjQyOTQ5NjcyOTV9LHsidHhpZCI6IjMwYTVhYmU4ODMwYzM1ZWYyZjNlNmM4NjA4OWVkN2NiOGEzMWIyM2RiMjllY2UyNDU5ZmZiNzNmZDVmZTBiOTkiLCJ2b3V0IjowLCJzY3JpcHRTaWciOnsiYXNtIjoiIiwiaGV4IjoiIn0sInR4aW53aXRuZXNzIjpbIjMwNDQwMjIwNGNmNDJlNjIwNjFlMTk2MzE0MWRlOTgwNTQ1NDQ2MTIxNTJkN2Q5MTA2ODMxMWEwYTQ1ZDRhZTU3NTQzZDVmYjAyMjA1MGVkNjMxZDY4ZDkzNzFmZDVhNWIyNTUwNjRiN2Q2MTJlYmFkZjYwODY2ZWEzM2VlOTk4MTJiNDBjODk2NzNiMDEiLCIwMjhmOGE3YjBjYzQxZmQ1NWQ3MGNlZTgyMzBmNDA5ZmQ4MDJlYzU3ZGVmZGExNDY1M2M0MjYyMTQ1NDNjN2ZiMzQiXSwic2VxdWVuY2UiOjQyOTQ5NjcyOTV9LHsidHhpZCI6IjMwYWFmNzViODk0NGFiMmJhMGVjNjRiMTkyYzI1YWY3OGFjZDRlNTA2ZTAzMmYzZjQyYTQ5YzM1Y2Q5MTE4MDEiLCJ2b3V0IjowLCJzY3JpcHRTaWciOnsiYXNtIjoiIiwiaGV4IjoiIn0sInR4aW53aXRuZXNzIjpbIjMwNDQwMjIwNzg5ZmIyNzA4ZmNiN2E1MWViMjYxNDdiZTNjNWJkZDM5NmUzMTk2ZmI0MTM3NTUxN2NmYTMwYzdmNDI5Y2QwYzAyMjA0YmZhNTM1OWUxZjBlYThhMjE4ZmVlNjMyZmVhYjBmYzU1MjdkYjQyNDBmYmNlZmMzMjBlNmJiYTlmMmYzMWE3MDEiLCIwMjhmOGE3YjBjYzQxZmQ1NWQ3MGNlZTgyMzBmNDA5ZmQ4MDJlYzU3ZGVmZGExNDY1M2M0MjYyMTQ1NDNjN2ZiMzQiXSwic2VxdWVuY2UiOjQyOTQ5NjcyOTV9LHsidHhpZCI6IjM3YmIwMjI5YzdlNmE1NDNlY2I4OGIyOTBhOTM5NjdiNmUwYzQ0Njk2NzZhYWU5ZTA4Y2I4NzZkNDU5N2JiNzgiLCJ2b3V0IjowLCJzY3JpcHRTaWciOnsiYXNtIjoiIiwiaGV4IjoiIn0sInR4aW53aXRuZXNzIjpbIjMwNDQwMjIwNjkyYmRkNDJjNmU0MWRmMzYzMDQ3NThmMWYwZTU4N2I2ZTZhNTAxMThiMDUzYzc3OTg3YTdjMzEwYTlhZjJkMTAyMjAzMTU2OWFkODQ3ZGZmMTNhZjVjMmRlNjhlZTUyZDlkYTJlZDNmODJhZmQ2N2M3ZGI4NjJlMThmM2UyNTY0OTFhMDEiLCIwMjhmOGE3YjBjYzQxZmQ1NWQ3MGNlZTgyMzBmNDA5ZmQ4MDJlYzU3ZGVmZGExNDY1M2M0MjYyMTQ1NDNjN2ZiMzQiXSwic2VxdWVuY2UiOjQyOTQ5NjcyOTV9LHsidHhpZCI6IjM3ZDViMmRiMzYyZjRmODc5NThjMDM4Y2JlYmM2ZjE3MDA2OWVjYmNkMzFiMmVlNTdhMThhMzkwZjVlMzgzOTgiLCJ2b3V0IjowLCJzY3JpcHRTaWciOnsiYXNtIjoiIiwiaGV4IjoiIn0sInR4aW53aXRuZXNzIjpbIjMwNDUwMjIxMDBlODQ5Nzk3NGZmYjhjMWU0MmRjNDI1NTNlMDc4OWYxYTQwOWUzZjkxZWZhMTY5MDg5N2IzYTRjNmE1Y2M1NDU5MDIyMDI2MmU3NTE4ZjhhOGEzZTAxNzUxYjI5YTdjZmI4YjA4OGM4NjVkNjdiNjdmNGZmMzdmMGNlZTdmMmZmYWNmNWEwMSIsIjAyOGY4YTdiMGNjNDFmZDU1ZDcwY2VlODIzMGY0MDlmZDgwMmVjNTdkZWZkYTE0NjUzYzQyNjIxNDU0M2M3ZmIzNCJdLCJzZXF1ZW5jZSI6NDI5NDk2NzI5NX0seyJ0eGlkIjoiM2JmNjU5NTMwOTM4ZTUxODRmNmQ3ZDg4ZWViM2VhZGU4ODgzZGMwMDQ2ZjM0NTliNjdlMjRhZjQ0ZTQ3YWFkZiIsInZvdXQiOjAsInNjcmlwdFNpZyI6eyJhc20iOiIiLCJoZXgiOiIifSwidHhpbndpdG5lc3MiOlsiMzA0NDAyMjA0ZWVjMzQzYzdlNzM4NTU0N2FlYjJlN2Y3NDhkNjNjYTk2YzE3ZTZhN2JkOGY0MTkwMTg1MTU5MDRmYzQwYTU3MDIyMDJmNjMwNmY2NTEwNzIwMWU2OWNjZGMyM2JmNWFmNGNlMDUwOGZlMTgzODQ1N2VhMDY3NjNhZjFiODA4NDE3Y2IwMSIsIjAyOGY4YTdiMGNjNDFmZDU1ZDcwY2VlODIzMGY0MDlmZDgwMmVjNTdkZWZkYTE0NjUzYzQyNjIxNDU0M2M3ZmIzNCJdLCJzZXF1ZW5jZSI6NDI5NDk2NzI5NX1dLCJ2b3V0IjpbeyJ2YWx1ZSI6MC4wMDAwMjI0MSwibiI6MCwic2NyaXB0UHViS2V5Ijp7ImFzbSI6IjAgMjE0MjBkZDk0MTY5NjBjZDQ1MGFmNDk2NzFlYTllNzExZWQyZjMzOSIsImhleCI6IjAwMTQyMTQyMGRkOTQxNjk2MGNkNDUwYWY0OTY3MWVhOWU3MTFlZDJmMzM5IiwidHlwZSI6IndpdG5lc3NfdjBfa2V5aGFzaCJ9fSx7InZhbHVlIjowLjEsIm4iOjEsInNjcmlwdFB1YktleSI6eyJhc20iOiIwIDNjOGNhNWEyYTI3MDlhYjU3ZjQwNjAyNjdjNGI0MzM0ZDNiYTliOTkiLCJoZXgiOiIwMDE0M2M4Y2E1YTJhMjcwOWFiNTdmNDA2MDI2N2M0YjQzMzRkM2JhOWI5OSIsInR5cGUiOiJ3aXRuZXNzX3YwX2tleWhhc2gifX0seyJ2YWx1ZSI6MC4wMDQ1MDY4NSwibiI6Miwic2NyaXB0UHViS2V5Ijp7ImFzbSI6IjAgMjE0MjBkZDk0MTY5NjBjZDQ1MGFmNDk2NzFlYTllNzExZWQyZjMzOSIsImhleCI6IjAwMTQyMTQyMGRkOTQxNjk2MGNkNDUwYWY0OTY3MWVhOWU3MTFlZDJmMzM5IiwidHlwZSI6IndpdG5lc3NfdjBfa2V5aGFzaCJ9fV19LHsiaGV4IjoiMDEwMDAwMDAwMDAxMDE0YzA3ODgwMjk3ODZhYTMyYjA0ZWU2YTdiNTRhMTA4ZjUwNmZhZjFjMjI2MzliZThmMjYyYjk0YjNkNjI2NTNhMDEwMDAwMDAwMGZmZmZmZmZmMDJkZjAzMDAwMDAwMDAwMDAwMTk3NmE5MTQ5YzRiMTJiYjVhMmU3ZTRiMjcyMWEyNWQ4YWJlYmQ2YTgxNDRkNDEyODhhY2FjMmIwZTEyMDAwMDAwMDAxNjAwMTRjNzgzMDY4YjI1OTNjNzEzOGQ4NzQ0OTU2ZjlkMDQ4MDMyYzU4MDgwMDI0ODMwNDUwMjIxMDBjNjVlYTI2OTc1ZjI3ZTkzMjk5MWU1YTNlYzNmZTllNTkxOTUzYTA0NjRkZThiYmEyODZhNzhjNjRkNTc4NTlmMDIyMDVlNDkzNTg0MWUwZjM0OTEzMDA4MDVkOWQ1MmFhMWQ4ZTY4ODIxMDhiNjFhNTk3MmI5ZTJkOTM2MDg0NzQ2YTAwMTIxMDNmNTAwNDE4MDI1YmEzYmFiY2E5MzVlOWY3NjE3YzQzODIxMGFiNzJhZTNlY2UwYjI1ZTVkZmY1NzljMzFkZGQxMDAwMDAwMDAiLCJ0eGlkIjoiZjgzNDkxZTNlZGNmMjc2ZWJmODM0NGMyNTE0YTlkOWViMjk3YWQ5MDRjNzBhMWIwNjMwMzRmZWMzNzE0ZDI2NiIsImhhc2giOiI3YzhjNDRjYjY1NmY1YTcwZmI5YmY4NDY0NmE4ZWZlYzY2MzIxNzkzZTVhODNmYjA0MmEzNmIxZjU2OWNlMGM4Iiwic2l6ZSI6MjI2LCJ2c2l6ZSI6MTQ0LCJ3ZWlnaHQiOjU3NCwidmVyc2lvbiI6MSwibG9ja3RpbWUiOjAsInZpbiI6W3sidHhpZCI6IjNhNjU2MjNkNGJiOTYyZjJlODliNjMyMjFjYWY2ZjUwOGYxMDRhYjVhN2U2NGViMDMyYWE4Njk3MDI4ODA3NGMiLCJ2b3V0IjoxLCJzY3JpcHRTaWciOnsiYXNtIjoiIiwiaGV4IjoiIn0sInR4aW53aXRuZXNzIjpbIjMwNDUwMjIxMDBjNjVlYTI2OTc1ZjI3ZTkzMjk5MWU1YTNlYzNmZTllNTkxOTUzYTA0NjRkZThiYmEyODZhNzhjNjRkNTc4NTlmMDIyMDVlNDkzNTg0MWUwZjM0OTEzMDA4MDVkOWQ1MmFhMWQ4ZTY4ODIxMDhiNjFhNTk3MmI5ZTJkOTM2MDg0NzQ2YTAwMSIsIjAzZjUwMDQxODAyNWJhM2JhYmNhOTM1ZTlmNzYxN2M0MzgyMTBhYjcyYWUzZWNlMGIyNWU1ZGZmNTc5YzMxZGRkMSJdLCJzZXF1ZW5jZSI6NDI5NDk2NzI5NX1dLCJ2b3V0IjpbeyJ2YWx1ZSI6MC4wMDAwMDk5MSwibiI6MCwic2NyaXB0UHViS2V5Ijp7ImFzbSI6Ik9QX0RVUCBPUF9IQVNIMTYwIDljNGIxMmJiNWEyZTdlNGIyNzIxYTI1ZDhhYmViZDZhODE0NGQ0MTIgT1BfRVFVQUxWRVJJRlkgT1BfQ0hFQ0tTSUciLCJoZXgiOiI3NmE5MTQ5YzRiMTJiYjVhMmU3ZTRiMjcyMWEyNWQ4YWJlYmQ2YTgxNDRkNDEyODhhYyIsInR5cGUiOiJwdWJrZXloYXNoIn19LHsidmFsdWUiOjMuMDI5MTg1NzIsIm4iOjEsInNjcmlwdFB1YktleSI6eyJhc20iOiIwIGM3ODMwNjhiMjU5M2M3MTM4ZDg3NDQ5NTZmOWQwNDgwMzJjNTgwODAiLCJoZXgiOiIwMDE0Yzc4MzA2OGIyNTkzYzcxMzhkODc0NDk1NmY5ZDA0ODAzMmM1ODA4MCIsInR5cGUiOiJ3aXRuZXNzX3YwX2tleWhhc2gifX1dfSx7ImhleCI6IjAxMDAwMDAwMDAwMTAxZjI5MTNkZGViMGY0MWZhNWM5ODc0ZWZkNGNmNWQxMDliMTg2ZTM0NTk5NTkzYjgxMTg5MjNmNDRhM2UxNmMzNzAxMDAwMDAwMDBmZGZmZmZmZjA1N2MwMzAwMDAwMDAwMDAwMDIyNTEyMDllY2MyYzM0ZDE2ZTExMTNiMDNlODhhNzdjOGUxZmViOTE2OGJhZWQwOGY1NTc5ZTBjZGRlOWI3NDI1MjU4ZWYwNDA0MDAwMDAwMDAwMDAwMjI1MTIwNDZhY2FlNTIxNmRmYTg0MWFlMGJhMmI3YzJjNzE2ZmUxNWNhNDYyZjhmNjFkOWU4NTA3MDFhYmUwYjBkOWFkZGI2MDQwMDAwMDAwMDAwMDAyMjUxMjA4ZTdkZDkxYjAxNTI1MTQxZTFmNDIyYzIwYjZiYzkwMWIxZDllZmM0MDlmM2M4MjRjMmM3MGRkNWIxYmJiM2U2ZTgwMzAwMDAwMDAwMDAwMDIyNTEyMDI0YTI0MmM2MWQwZjZmZjYxZjdlYTI0ZGNmMWUxMDg0MDk3NGNlM2EwMTFlODJkMzA5MjBhMTg2YmY4MmZlYjFjNzNjMDAwMDAwMDAwMDAwMjI1MTIwOTc1N2NmYzI0NTY3NTk3MGVjY2VhOWRkZTA4Y2U3MDk4MzRhZjRhZjk3MjMwMTkyYmZkYmMwMjBlMWMxZjJjOTAxNDAwYmEwYjg0ODY4NTMxZTI5NTk4NTNkNzRlMjlmMzhiMGM1NTU0ZTZlYTYyYzYxOTFjYzM2ZDE3ZjU2ODg2YTJmYTViOGM2N2FhZWQ4NjA4OTlmOGEyODUwZGEyOWNkZjdhZDU0MTgxODNlOGIyNDBjZmNmYmJjMjVmYWMxYTM2YjEwM2IyNjAwIiwidHhpZCI6ImRiYjE5OTNiNWRlMTdkM2U1MmU3ZjU5MjQwZGJmYjY2MzRkZDZkOWU5OTRiMzJhZjQwOGZmMjEyNDAzMGQyMGQiLCJoYXNoIjoiNWU4ZmJmZWU5NTc0ZjRiMTEyNzBlODJlY2NhZWMxNWY0OTI3YjVhYzllOWU3ZmM0YmM1Mjk3MTdmYjc5YTA2MSIsInNpemUiOjMzNCwidnNpemUiOjI4Mywid2VpZ2h0IjoxMTMyLCJ2ZXJzaW9uIjoxLCJsb2NrdGltZSI6MjUwNTQ4OCwidmluIjpbeyJ0eGlkIjoiMzc2Y2UxYTM0NDNmOTIxODgxM2I1OTk5NDVlMzg2YjEwOWQxZjU0Y2ZkNGU4N2M5YTUxZmY0YjBkZTNkOTFmMiIsInZvdXQiOjEsInNjcmlwdFNpZyI6eyJhc20iOiIiLCJoZXgiOiIifSwidHhpbndpdG5lc3MiOlsiMGJhMGI4NDg2ODUzMWUyOTU5ODUzZDc0ZTI5ZjM4YjBjNTU1NGU2ZWE2MmM2MTkxY2MzNmQxN2Y1Njg4NmEyZmE1YjhjNjdhYWVkODYwODk5ZjhhMjg1MGRhMjljZGY3YWQ1NDE4MTgzZThiMjQwY2ZjZmJiYzI1ZmFjMWEzNmIiXSwic2VxdWVuY2UiOjQyOTQ5NjcyOTN9XSwidm91dCI6W3sidmFsdWUiOjAuMDAwMDA4OTIsIm4iOjAsInNjcmlwdFB1YktleSI6eyJhc20iOiIxIDllY2MyYzM0ZDE2ZTExMTNiMDNlODhhNzdjOGUxZmViOTE2OGJhZWQwOGY1NTc5ZTBjZGRlOWI3NDI1MjU4ZWYiLCJoZXgiOiI1MTIwOWVjYzJjMzRkMTZlMTExM2IwM2U4OGE3N2M4ZTFmZWI5MTY4YmFlZDA4ZjU1NzllMGNkZGU5Yjc0MjUyNThlZiIsInR5cGUiOiJ3aXRuZXNzX3YxX3RhcHJvb3QifX0seyJ2YWx1ZSI6MC4wMDAwMTAyOCwibiI6MSwic2NyaXB0UHViS2V5Ijp7ImFzbSI6IjEgNDZhY2FlNTIxNmRmYTg0MWFlMGJhMmI3YzJjNzE2ZmUxNWNhNDYyZjhmNjFkOWU4NTA3MDFhYmUwYjBkOWFkZCIsImhleCI6IjUxMjA0NmFjYWU1MjE2ZGZhODQxYWUwYmEyYjdjMmM3MTZmZTE1Y2E0NjJmOGY2MWQ5ZTg1MDcwMWFiZTBiMGQ5YWRkIiwidHlwZSI6IndpdG5lc3NfdjFfdGFwcm9vdCJ9fSx7InZhbHVlIjowLjAwMDAxMjA2LCJuIjoyLCJzY3JpcHRQdWJLZXkiOnsiYXNtIjoiMSA4ZTdkZDkxYjAxNTI1MTQxZTFmNDIyYzIwYjZiYzkwMWIxZDllZmM0MDlmM2M4MjRjMmM3MGRkNWIxYmJiM2U2IiwiaGV4IjoiNTEyMDhlN2RkOTFiMDE1MjUxNDFlMWY0MjJjMjBiNmJjOTAxYjFkOWVmYzQwOWYzYzgyNGMyYzcwZGQ1YjFiYmIzZTYiLCJ0eXBlIjoid2l0bmVzc192MV90YXByb290In19LHsidmFsdWUiOjAuMDAwMDEsIm4iOjMsInNjcmlwdFB1YktleSI6eyJhc20iOiIxIDI0YTI0MmM2MWQwZjZmZjYxZjdlYTI0ZGNmMWUxMDg0MDk3NGNlM2EwMTFlODJkMzA5MjBhMTg2YmY4MmZlYjEiLCJoZXgiOiI1MTIwMjRhMjQyYzYxZDBmNmZmNjFmN2VhMjRkY2YxZTEwODQwOTc0Y2UzYTAxMWU4MmQzMDkyMGExODZiZjgyZmViMSIsInR5cGUiOiJ3aXRuZXNzX3YxX3RhcHJvb3QifX0seyJ2YWx1ZSI6MC4wMDAxNTU1OSwibiI6NCwic2NyaXB0UHViS2V5Ijp7ImFzbSI6IjEgOTc1N2NmYzI0NTY3NTk3MGVjY2VhOWRkZTA4Y2U3MDk4MzRhZjRhZjk3MjMwMTkyYmZkYmMwMjBlMWMxZjJjOSIsImhleCI6IjUxMjA5NzU3Y2ZjMjQ1Njc1OTcwZWNjZWE5ZGRlMDhjZTcwOTgzNGFmNGFmOTcyMzAxOTJiZmRiYzAyMGUxYzFmMmM5IiwidHlwZSI6IndpdG5lc3NfdjFfdGFwcm9vdCJ9fV19LHsiaGV4IjoiMDIwMDAwMDAwMDAxMDEzZGRkYTYyOGEzZDdiNzU2NDFhZmNmZjU5ZWU0YTY5NWM2ZDc4ZWZhNTE5OWRkOGQxNzY5MDM4YjZjMDQxNmNiMDEwMDAwMDAxNzE2MDAxNGMyMjE3NDhkMmU1YjUyZGYyY2U4OTc3MzA1M2E1MTEyNDU1N2NkMWRmZGZmZmZmZjA0NDQyMzAyMDAwMDAwMDAwMDE3YTkxNDM1YjQ5ODQ0NzRmOGMwNWIyNWU2MDdlNDdkYzQ2ZTJiNDgxNGEwNGI4NzUwMTMwZDAwMDAwMDAwMDAxN2E5MTQ5MjJkNTdlNTg4OTI1YzViYmU1MTYzNmM1ZTc4OTE3YWRjYzJlZGEzODc1YTlhMDEwMDAwMDAwMDAwMTdhOTE0MzZhY2FmOTM3ZWRhNDgwYzVhMzRkZWViMjE2N2YwZTY1Yjk1ZjgxMjg3NTNlMTU1MDAwMDAwMDAwMDE3YTkxNDc1MDliODM3Y2RmMTY1NWMxM2VhNjNhNDVjODk5MmVlMDQxMjdhNGM4NzAyNDczMDQ0MDIyMDQzOTQxMDUxZWUyNzAxNDU3MjMzNTU5YzY5ZjYxMWRkZjMyOTExYzZjYTM5YjE3NDM2M2U1MjhjMzNhMGMxMGUwMjIwMTM5ZTk4NGJiMDU2YjVkNTljYjEwNGYzNjY0ZjQ2N2ZlNjg0MjU4ZDkyZGY3YzhkMDZhZGQxNDQ4MTQ4MGZkZTAxMjEwMzlmM2U5ODFlNDFkZGJlNzM5NzQzMzBkNDFhMzExM2NkNDhkOTZmZGM0N2NlMjlkMjcwMmVhMjY3NjA3YWI3ZWEwMDAwMDAwMCIsInR4aWQiOiIzODcwNTRiZDZhMmI1NTJkN2QyZjIxOTBiZDlkMTE5NjBlMjE2MDA5NzgwOGVlOTc0YTNjNzEyNTExMzNkYjY4IiwiaGFzaCI6IjRjMGMyNDYxMzhmOWE3MTA4NWRiN2FiOWI5N2Y5MjVlZTVjZWE0ODk5ZmYwYTAyM2M3ZDkxNjEwMGJhMWJiMjEiLCJzaXplIjozMTEsInZzaXplIjoyMzAsIndlaWdodCI6OTE3LCJ2ZXJzaW9uIjoyLCJsb2NrdGltZSI6MCwidmluIjpbeyJ0eGlkIjoiY2IxNjA0NmM4YjAzNjkxNzhkZGQ5OTUxZmE4ZWQ3YzY5NWE2ZTQ5ZWY1Y2ZhZjQxNTZiN2Q3YTMyOGE2ZGQzZCIsInZvdXQiOjEsInNjcmlwdFNpZyI6eyJhc20iOiIwMDE0YzIyMTc0OGQyZTViNTJkZjJjZTg5NzczMDUzYTUxMTI0NTU3Y2QxZCIsImhleCI6IjE2MDAxNGMyMjE3NDhkMmU1YjUyZGYyY2U4OTc3MzA1M2E1MTEyNDU1N2NkMWQifSwidHhpbndpdG5lc3MiOlsiMzA0NDAyMjA0Mzk0MTA1MWVlMjcwMTQ1NzIzMzU1OWM2OWY2MTFkZGYzMjkxMWM2Y2EzOWIxNzQzNjNlNTI4YzMzYTBjMTBlMDIyMDEzOWU5ODRiYjA1NmI1ZDU5Y2IxMDRmMzY2NGY0NjdmZTY4NDI1OGQ5MmRmN2M4ZDA2YWRkMTQ0ODE0ODBmZGUwMSIsIjAzOWYzZTk4MWU0MWRkYmU3Mzk3NDMzMGQ0MWEzMTEzY2Q0OGQ5NmZkYzQ3Y2UyOWQyNzAyZWEyNjc2MDdhYjdlYSJdLCJzZXF1ZW5jZSI6NDI5NDk2NzI5M31dLCJ2b3V0IjpbeyJ2YWx1ZSI6MC4wMDE0MDEsIm4iOjAsInNjcmlwdFB1YktleSI6eyJhc20iOiJPUF9IQVNIMTYwIDM1YjQ5ODQ0NzRmOGMwNWIyNWU2MDdlNDdkYzQ2ZTJiNDgxNGEwNGIgT1BfRVFVQUwiLCJoZXgiOiJhOTE0MzViNDk4NDQ3NGY4YzA1YjI1ZTYwN2U0N2RjNDZlMmI0ODE0YTA0Yjg3IiwidHlwZSI6InNjcmlwdGhhc2gifX0seyJ2YWx1ZSI6MC4wMDg1NjkxMiwibiI6MSwic2NyaXB0UHViS2V5Ijp7ImFzbSI6Ik9QX0hBU0gxNjAgOTIyZDU3ZTU4ODkyNWM1YmJlNTE2MzZjNWU3ODkxN2FkY2MyZWRhMyBPUF9FUVVBTCIsImhleCI6ImE5MTQ5MjJkNTdlNTg4OTI1YzViYmU1MTYzNmM1ZTc4OTE3YWRjYzJlZGEzODciLCJ0eXBlIjoic2NyaXB0aGFzaCJ9fSx7InZhbHVlIjowLjAwMTA1MDUsIm4iOjIsInNjcmlwdFB1YktleSI6eyJhc20iOiJPUF9IQVNIMTYwIDM2YWNhZjkzN2VkYTQ4MGM1YTM0ZGVlYjIxNjdmMGU2NWI5NWY4MTIgT1BfRVFVQUwiLCJoZXgiOiJhOTE0MzZhY2FmOTM3ZWRhNDgwYzVhMzRkZWViMjE2N2YwZTY1Yjk1ZjgxMjg3IiwidHlwZSI6InNjcmlwdGhhc2gifX0seyJ2YWx1ZSI6MC4wNTYyODI0MywibiI6Mywic2NyaXB0UHViS2V5Ijp7ImFzbSI6Ik9QX0hBU0gxNjAgNzUwOWI4MzdjZGYxNjU1YzEzZWE2M2E0NWM4OTkyZWUwNDEyN2E0YyBPUF9FUVVBTCIsImhleCI6ImE5MTQ3NTA5YjgzN2NkZjE2NTVjMTNlYTYzYTQ1Yzg5OTJlZTA0MTI3YTRjODciLCJ0eXBlIjoic2NyaXB0aGFzaCJ9fV19LHsiaGV4IjoiMDIwMDAwMDAwMDAxMDE3ZTc4ZWUxOWQ4YjVlZmY1YjE5MjEyNjg2NWRjNThlYTY4N2Y2NmQyZDllMGYwYmIxMzg1MjdiZjYyMDlkMDA4MTMwMDAwMDAxNzE2MDAxNGNiMTdjZTE1Yzg0MDQ2YjAwZTllMGVhYzBiMTZiZjE1ZTFmYzVjOTdmZGZmZmZmZjAyNWE5YTAxMDAwMDAwMDAwMDE3YTkxNDI1ZjdiNWJkMWFlOTJhYjM2YzIwZTg1NzJiMGFlODYyODBlMmU4MmQ4N2M5MWEwMDAwMDAwMDAwMDAxN2E5MTQ3NTA5YjgzN2NkZjE2NTVjMTNlYTYzYTQ1Yzg5OTJlZTA0MTI3YTRjODcwMjQ3MzA0NDAyMjA2YjEzMDQ3MmNkNTIzZDIyMjQzMjRlMjI2MWI5ODI1ZDQyMDgwMmIxNjY0NDc4ZjZmMWFjZmNmYzk1ZGUxOGY3MDIyMDFjNThjNDhjNGI5ZDRjZmVkZWRlNDJlZGEyNjQwMWNkYjZlYjY4MzQ4YThkNDNjZjg2YzMxNzZmNjQ0MTU1YzgwMTIxMDIwNDg2MTkxMGRlZmFjZWVkNGY2ODkzYWRiODI2Y2U2NTA1ZmRjZmU0MjhiMjhiMDE4ZTAyZTFjZmJmZGY5NjkwMDAwMDAwMDAiLCJ0eGlkIjoiN2Y1YmRkNjJhZTk2ZTAzNjRjYzU0NzBlN2VmNjAyNzkxZTc4N2YzNjM3N2YxZTMyZTE3MTNiZTdlNDQ1N2JkMSIsImhhc2giOiI3YzE3ZjI2Yzg0OWI4NDBlN2U5MGM3NTRhOWM4ODQ2OGVmMzIxN2M2OTBiNmViNWJlMmNkMDA2MWU3ZjNmMWNlIiwic2l6ZSI6MjQ3LCJ2c2l6ZSI6MTY2LCJ3ZWlnaHQiOjY2MSwidmVyc2lvbiI6MiwibG9ja3RpbWUiOjAsInZpbiI6W3sidHhpZCI6IjA4ZDAwOTYyYmYyNzg1MTNiYmYwZTBkOWQyNjY3ZjY4ZWE1OGRjNjU2ODEyOTJiMWY1ZWZiNWQ4MTllZTc4N2UiLCJ2b3V0IjoxOSwic2NyaXB0U2lnIjp7ImFzbSI6IjAwMTRjYjE3Y2UxNWM4NDA0NmIwMGU5ZTBlYWMwYjE2YmYxNWUxZmM1Yzk3IiwiaGV4IjoiMTYwMDE0Y2IxN2NlMTVjODQwNDZiMDBlOWUwZWFjMGIxNmJmMTVlMWZjNWM5NyJ9LCJ0eGlud2l0bmVzcyI6WyIzMDQ0MDIyMDZiMTMwNDcyY2Q1MjNkMjIyNDMyNGUyMjYxYjk4MjVkNDIwODAyYjE2NjQ0NzhmNmYxYWNmY2ZjOTVkZTE4ZjcwMjIwMWM1OGM0OGM0YjlkNGNmZWRlZGU0MmVkYTI2NDAxY2RiNmViNjgzNDhhOGQ0M2NmODZjMzE3NmY2NDQxNTVjODAxIiwiMDIwNDg2MTkxMGRlZmFjZWVkNGY2ODkzYWRiODI2Y2U2NTA1ZmRjZmU0MjhiMjhiMDE4ZTAyZTFjZmJmZGY5NjkwIl0sInNlcXVlbmNlIjo0Mjk0OTY3MjkzfV0sInZvdXQiOlt7InZhbHVlIjowLjAwMTA1MDUsIm4iOjAsInNjcmlwdFB1YktleSI6eyJhc20iOiJPUF9IQVNIMTYwIDI1ZjdiNWJkMWFlOTJhYjM2YzIwZTg1NzJiMGFlODYyODBlMmU4MmQgT1BfRVFVQUwiLCJoZXgiOiJhOTE0MjVmN2I1YmQxYWU5MmFiMzZjMjBlODU3MmIwYWU4NjI4MGUyZTgyZDg3IiwidHlwZSI6InNjcmlwdGhhc2gifX0seyJ2YWx1ZSI6MC4wMDAwNjg1NywibiI6MSwic2NyaXB0UHViS2V5Ijp7ImFzbSI6Ik9QX0hBU0gxNjAgNzUwOWI4MzdjZGYxNjU1YzEzZWE2M2E0NWM4OTkyZWUwNDEyN2E0YyBPUF9FUVVBTCIsImhleCI6ImE5MTQ3NTA5YjgzN2NkZjE2NTVjMTNlYTYzYTQ1Yzg5OTJlZTA0MTI3YTRjODciLCJ0eXBlIjoic2NyaXB0aGFzaCJ9fV19LHsiaGV4IjoiMDIwMDAwMDAwMDAxMDEzMTM0MDA0NTU5OTM0YmU2OTk1NjY4MmFlNjYzMGZmNDY3ZDZhMjNhZTlkYmZiMjEyY2RhNTQ4ZGI4YWY5MzU4MDEwMDAwMDAwMGZmZmZmZmZmMDJkMDA3MDAwMDAwMDAwMDAwMjI1MTIwMjE3ZjdkMDc0MjM3NjViZTU2NTQxY2U2NTU0ZmY2Njg1Y2RjZmRiOGNiMTA5MmM1YTFmM2ZiYTVhNTZiZGU2ODgwODUxNzAwMDAwMDAwMDAyMjUxMjBiZDUyMDRkMzhkZDVhZmU1MjBlYzhkYTM5M2QyMDRmNGQ2ZGY2ZDI2M2RiZjFjNmNjN2Y0ODNkMjFlYTY5YWMxMDE0MGQ1YWE3N2FlODA2ZTVmNzdiODQ2Mjc5MDNjN2VkNDg1NTU2ODgxMzI1YTc2Mjk0Nzc1NDM4MWMzYWNjNmZjYzQ0ZDAzN2U3Yzg4NjgzZmRkNzZiMzA4MWEzOTZkNDI0MzY0MWVkNWEwYzNkOWEzOWYzZTBjMTY2ZGZiZjA1NTA1MDAwMDAwMDAiLCJ0eGlkIjoiZjg2NzhkZDY0OGY5OGU1MzQxNDcxZDE0N2RhMmYzMjk1MWM0MGQ5OTY0NGNlNTc2YWM5NWY3Njk2NDhiZjYxZiIsImhhc2giOiJlM2ZhMTFhNmM0NDAxMmQxNTQ3YTRiMTIxNzI3NmQ5Y2IwOWViMjc0NmNjOGU5YjVjNWJhNmE4YTlkMTZiMGYxIiwic2l6ZSI6MjA1LCJ2c2l6ZSI6MTU0LCJ3ZWlnaHQiOjYxNiwidmVyc2lvbiI6MiwibG9ja3RpbWUiOjAsInZpbiI6W3sidHhpZCI6IjU4OTNhZmI4OGQ1NGRhMmMyMWZiZGJlOTNhYTJkNjY3ZjQwZjYzZTYyYTY4NTY5OWU2NGI5MzU5NDUwMDM0MzEiLCJ2b3V0IjoxLCJzY3JpcHRTaWciOnsiYXNtIjoiIiwiaGV4IjoiIn0sInR4aW53aXRuZXNzIjpbImQ1YWE3N2FlODA2ZTVmNzdiODQ2Mjc5MDNjN2VkNDg1NTU2ODgxMzI1YTc2Mjk0Nzc1NDM4MWMzYWNjNmZjYzQ0ZDAzN2U3Yzg4NjgzZmRkNzZiMzA4MWEzOTZkNDI0MzY0MWVkNWEwYzNkOWEzOWYzZTBjMTY2ZGZiZjA1NTA1Il0sInNlcXVlbmNlIjo0Mjk0OTY3Mjk1fV0sInZvdXQiOlt7InZhbHVlIjowLjAwMDAyLCJuIjowLCJzY3JpcHRQdWJLZXkiOnsiYXNtIjoiMSAyMTdmN2QwNzQyMzc2NWJlNTY1NDFjZTY1NTRmZjY2ODVjZGNmZGI4Y2IxMDkyYzVhMWYzZmJhNWE1NmJkZTY4IiwiaGV4IjoiNTEyMDIxN2Y3ZDA3NDIzNzY1YmU1NjU0MWNlNjU1NGZmNjY4NWNkY2ZkYjhjYjEwOTJjNWExZjNmYmE1YTU2YmRlNjgiLCJ0eXBlIjoid2l0bmVzc192MV90YXByb290In19LHsidmFsdWUiOjAuMDE1NDE1MDQsIm4iOjEsInNjcmlwdFB1YktleSI6eyJhc20iOiIxIGJkNTIwNGQzOGRkNWFmZTUyMGVjOGRhMzkzZDIwNGY0ZDZkZjZkMjYzZGJmMWM2Y2M3ZjQ4M2QyMWVhNjlhYzEiLCJoZXgiOiI1MTIwYmQ1MjA0ZDM4ZGQ1YWZlNTIwZWM4ZGEzOTNkMjA0ZjRkNmRmNmQyNjNkYmYxYzZjYzdmNDgzZDIxZWE2OWFjMSIsInR5cGUiOiJ3aXRuZXNzX3YxX3RhcHJvb3QifX1dfSx7ImhleCI6IjAyMDAwMDAwMDAwMTAxMWZmNjhiNjQ2OWY3OTVhYzc2ZTU0YzY0OTkwZGM0NTEyOWYzYTI3ZDE0MWQ0NzQxNTM4ZWY5NDhkNjhkNjdmODAwMDAwMDAwMDBmZGZmZmZmZjAyMjIwMjAwMDAwMDAwMDAwMDIyNTEyMGJkNTIwNGQzOGRkNWFmZTUyMGVjOGRhMzkzZDIwNGY0ZDZkZjZkMjYzZGJmMWM2Y2M3ZjQ4M2QyMWVhNjlhYzFmNzA0MDAwMDAwMDAwMDAwMTYwMDE0YmRmZDZlMGU4ODljZTU3YzlhZGJmZTgxN2IyNjk3ODZjYTA4MjFkMzAzNDAwODEzMzlhZDRlMDk4Y2VjMTAyY2YwZjNjMzAwYjE5YzZlMmQ5NzEwOWUwMzBmYTM3YzdkYTIwZjIzMWI1MDM0MjY0NzcxMjUxMDQ4NGU4ZmE5N2FkMDkwM2M3ZDhiMjNjY2E5ZjVjOGVlM2E3ZWI4ZjI0YWUwNTEzMzcyODU2MzdmMjAxMmI0YWIzNDc4MWUzNTI3NzVkYTQ2OWRiZGFmYWNiYTgyYTdjZTk5ZDg3YTcwMjM1YmMyOTVhOWM2YzNmMzkyYWMwMDYzMDM2ZjcyNjQwMTAxMTg3NDY1Nzg3NDJmNzA2YzYxNjk2ZTNiNjM2ODYxNzI3MzY1NzQzZDc1NzQ2NjJkMzgwMDM5N2IyMjcwMjIzYTIyNjI3MjYzMmQzMjMwMjIyYzIyNmY3MDIyM2EyMjc0NzI2MTZlNzM2NjY1NzIyMjJjMjI3NDY5NjM2YjIyM2EyMjY0NmY2ZDZmMjIyYzIyNjE2ZDc0MjIzYTIyMzEzMDMwMzAyMjdkNjgyMWMwYjA4ZGUwZTMxZjEyM2E4MmViYTdmNDcxM2NmM2U5MjRhODIyZTFhZTU3OGI3MWIyN2RjMWU0NDEyODRjMDhjNDAwMDAwMDAwIiwidHhpZCI6IjIwMmNhYTFkNTQzNjU4Y2I2OTBiZDRmNjA0YmZjNThhZjM5MWIxODMzOTVlZTRjZWE0NjFiOTcyZDc1MzcwMjkiLCJoYXNoIjoiNDk0NDc3N2ZhMjMzMTNmZWY0Mzk0MGQ2OGNjYWE4NzhlZDNiYWQwNzkzYjJhZDFjODFjZTg4MDhkNGQ5YWY4ZCIsInNpemUiOjM1NSwidnNpemUiOjE4Mywid2VpZ2h0Ijo3MzAsInZlcnNpb24iOjIsImxvY2t0aW1lIjowLCJ2aW4iOlt7InR4aWQiOiJmODY3OGRkNjQ4Zjk4ZTUzNDE0NzFkMTQ3ZGEyZjMyOTUxYzQwZDk5NjQ0Y2U1NzZhYzk1Zjc2OTY0OGJmNjFmIiwidm91dCI6MCwic2NyaXB0U2lnIjp7ImFzbSI6IiIsImhleCI6IiJ9LCJ0eGlud2l0bmVzcyI6WyIwODEzMzlhZDRlMDk4Y2VjMTAyY2YwZjNjMzAwYjE5YzZlMmQ5NzEwOWUwMzBmYTM3YzdkYTIwZjIzMWI1MDM0MjY0NzcxMjUxMDQ4NGU4ZmE5N2FkMDkwM2M3ZDhiMjNjY2E5ZjVjOGVlM2E3ZWI4ZjI0YWUwNTEzMzcyODU2MyIsIjIwMTJiNGFiMzQ3ODFlMzUyNzc1ZGE0NjlkYmRhZmFjYmE4MmE3Y2U5OWQ4N2E3MDIzNWJjMjk1YTljNmMzZjM5MmFjMDA2MzAzNmY3MjY0MDEwMTE4NzQ2NTc4NzQyZjcwNmM2MTY5NmUzYjYzNjg2MTcyNzM2NTc0M2Q3NTc0NjYyZDM4MDAzOTdiMjI3MDIyM2EyMjYyNzI2MzJkMzIzMDIyMmMyMjZmNzAyMjNhMjI3NDcyNjE2ZTczNjY2NTcyMjIyYzIyNzQ2OTYzNmIyMjNhMjI2NDZmNmQ2ZjIyMmMyMjYxNmQ3NDIyM2EyMjMxMzAzMDMwMjI3ZDY4IiwiYzBiMDhkZTBlMzFmMTIzYTgyZWJhN2Y0NzEzY2YzZTkyNGE4MjJlMWFlNTc4YjcxYjI3ZGMxZTQ0MTI4NGMwOGM0Il0sInNlcXVlbmNlIjo0Mjk0OTY3MjkzfV0sInZvdXQiOlt7InZhbHVlIjowLjAwMDAwNTQ2LCJuIjowLCJzY3JpcHRQdWJLZXkiOnsiYXNtIjoiMSBiZDUyMDRkMzhkZDVhZmU1MjBlYzhkYTM5M2QyMDRmNGQ2ZGY2ZDI2M2RiZjFjNmNjN2Y0ODNkMjFlYTY5YWMxIiwiaGV4IjoiNTEyMGJkNTIwNGQzOGRkNWFmZTUyMGVjOGRhMzkzZDIwNGY0ZDZkZjZkMjYzZGJmMWM2Y2M3ZjQ4M2QyMWVhNjlhYzEiLCJ0eXBlIjoid2l0bmVzc192MV90YXByb290In19LHsidmFsdWUiOjAuMDAwMDEyNzEsIm4iOjEsInNjcmlwdFB1YktleSI6eyJhc20iOiIwIGJkZmQ2ZTBlODg5Y2U1N2M5YWRiZmU4MTdiMjY5Nzg2Y2EwODIxZDMiLCJoZXgiOiIwMDE0YmRmZDZlMGU4ODljZTU3YzlhZGJmZTgxN2IyNjk3ODZjYTA4MjFkMyIsInR5cGUiOiJ3aXRuZXNzX3YwX2tleWhhc2gifX1dfSx7ImhleCI6IjAyMDAwMDAwMDAwMTAyMjk3MDUzZDc3MmI5NjFhNGNlZTQ1ZTM5ODNiMTkxZjM4YWM1YmYwNGY2ZDQwYjY5Y2I1ODM2NTQxZGFhMmMyMDAwMDAwMDAwMDBmZmZmZmZmZjFmZjY4YjY0NjlmNzk1YWM3NmU1NGM2NDk5MGRjNDUxMjlmM2EyN2QxNDFkNDc0MTUzOGVmOTQ4ZDY4ZDY3ZjgwMTAwMDAwMDAwZmZmZmZmZmYwMjAxMDAwMDAwMDAwMDAwMDAyMjZhMjA0NTI3ZDEzYzNmYWZhZDMyYTAxNmUwY2Q0YzYxNWI2NWVmMWQ3ZmIxOWJmYWUzYmM2ZGM4ZTE0MTJlMWI3YzVjYzc4NjE3MDAwMDAwMDAwMDIyNTEyMGJkNTIwNGQzOGRkNWFmZTUyMGVjOGRhMzkzZDIwNGY0ZDZkZjZkMjYzZGJmMWM2Y2M3ZjQ4M2QyMWVhNjlhYzEwMTQwOGEyMGNlMWRhN2QyMmVmNzE2MjVjNTA5MzFkZDg4N2Y2MjExN2U1NWY3NjkzMzAxY2U1YmYzOTc3MmE5OTI2OGRlOWYwZWNiOTRkMzFjYzU2NjhjOGVhOWFlMzYxNWEwZjYyNTQ2YTAzNzFkZTBhNDhjMDM1NDgyOGE4ZmViODkwMTQwYWYxOTA0NTkzZTQxOWFiMTNjNmQzN2RiYmE4MDg3NzRjYzE5NGFjNTkzN2RlM2UxYzdmNzcwYWE5MDYxZmY3ODM5YzU3ZmQyZDEzNTFhOWQwZGE2YzNhNDQ3ZDY5MGY1ZTEwZDNkY2Q1MDMxODc5N2Y2ZTA4ZWU1MmVmMGIyNDgwMDAwMDAwMCIsInR4aWQiOiIxZDYxZjYxY2ZkMzM4YTIyY2I3OWUxYTcyNWUyYjg4ZTMzNmU4NjViZmUzMTRjMDgwMjM2Zjk0ZWU1YTFjY2UxIiwiaGFzaCI6IjAyZTI1ZmQ0NzZjY2Y3YzE0YTU1NmYxM2Q0ZTI3MTliODg3OTdmNDU2ZTZiNDFjYTJmYWE0MWE2ZjQzNzNkMWQiLCJzaXplIjozMTIsInZzaXplIjoyMTIsIndlaWdodCI6ODQ2LCJ2ZXJzaW9uIjoyLCJsb2NrdGltZSI6MCwidmluIjpbeyJ0eGlkIjoiMjAyY2FhMWQ1NDM2NThjYjY5MGJkNGY2MDRiZmM1OGFmMzkxYjE4MzM5NWVlNGNlYTQ2MWI5NzJkNzUzNzAyOSIsInZvdXQiOjAsInNjcmlwdFNpZyI6eyJhc20iOiIiLCJoZXgiOiIifSwidHhpbndpdG5lc3MiOlsiOGEyMGNlMWRhN2QyMmVmNzE2MjVjNTA5MzFkZDg4N2Y2MjExN2U1NWY3NjkzMzAxY2U1YmYzOTc3MmE5OTI2OGRlOWYwZWNiOTRkMzFjYzU2NjhjOGVhOWFlMzYxNWEwZjYyNTQ2YTAzNzFkZTBhNDhjMDM1NDgyOGE4ZmViODkiXSwic2VxdWVuY2UiOjQyOTQ5NjcyOTV9LHsidHhpZCI6ImY4Njc4ZGQ2NDhmOThlNTM0MTQ3MWQxNDdkYTJmMzI5NTFjNDBkOTk2NDRjZTU3NmFjOTVmNzY5NjQ4YmY2MWYiLCJ2b3V0IjoxLCJzY3JpcHRTaWciOnsiYXNtIjoiIiwiaGV4IjoiIn0sInR4aW53aXRuZXNzIjpbImFmMTkwNDU5M2U0MTlhYjEzYzZkMzdkYmJhODA4Nzc0Y2MxOTRhYzU5MzdkZTNlMWM3Zjc3MGFhOTA2MWZmNzgzOWM1N2ZkMmQxMzUxYTlkMGRhNmMzYTQ0N2Q2OTBmNWUxMGQzZGNkNTAzMTg3OTdmNmUwOGVlNTJlZjBiMjQ4Il0sInNlcXVlbmNlIjo0Mjk0OTY3Mjk1fV0sInZvdXQiOlt7InZhbHVlIjoxZS04LCJuIjowLCJzY3JpcHRQdWJLZXkiOnsiYXNtIjoiT1BfUkVUVVJOIDQ1MjdkMTNjM2ZhZmFkMzJhMDE2ZTBjZDRjNjE1YjY1ZWYxZDdmYjE5YmZhZTNiYzZkYzhlMTQxMmUxYjdjNWMiLCJoZXgiOiI2YTIwNDUyN2QxM2MzZmFmYWQzMmEwMTZlMGNkNGM2MTViNjVlZjFkN2ZiMTliZmFlM2JjNmRjOGUxNDEyZTFiN2M1YyIsInR5cGUiOiJudWxsZGF0YSJ9fSx7InZhbHVlIjowLjAxNTQxODMxLCJuIjoxLCJzY3JpcHRQdWJLZXkiOnsiYXNtIjoiMSBiZDUyMDRkMzhkZDVhZmU1MjBlYzhkYTM5M2QyMDRmNGQ2ZGY2ZDI2M2RiZjFjNmNjN2Y0ODNkMjFlYTY5YWMxIiwiaGV4IjoiNTEyMGJkNTIwNGQzOGRkNWFmZTUyMGVjOGRhMzkzZDIwNGY0ZDZkZjZkMjYzZGJmMWM2Y2M3ZjQ4M2QyMWVhNjlhYzEiLCJ0eXBlIjoid2l0bmVzc192MV90YXByb290In19XX0seyJoZXgiOiIwMjAwMDAwMDAwMDEwMWUxY2NhMWU1NGVmOTM2MDIwODRjMzFmZTViODY2ZTMzOGViOGUyMjVhN2UxNzljYjIyOGEzM2ZkMWNmNjYxMWQwMTAwMDAwMDAwZmZmZmZmZmYwMmQwMDcwMDAwMDAwMDAwMDAyMjUxMjAyYWU4ZGNmNzAwOGY0ZDIxNTQ3NTlmYmUzMTJhZTU4MzA1MzBlMTFmY2Q2MmI3NDJlYjhlMTQ2NGY5YjAwNGVmNWI3ZTE3MDAwMDAwMDAwMDIyNTEyMGJkNTIwNGQzOGRkNWFmZTUyMGVjOGRhMzkzZDIwNGY0ZDZkZjZkMjYzZGJmMWM2Y2M3ZjQ4M2QyMWVhNjlhYzEwMTQwY2UwZTczZDhjMmY3MThmODc0ZWE4Njg0ZjYyMTY0YmY4OWQ0YjNkMzIwYTk2ODU5MzUzY2FiYTQ4Yzg4ZDA5NDAzNDdmYTEyNzY2NzVkYjA5NTFjYTViZjFjMWZkNTU2ZjM5ODZlOTY0OTBkMzg4MmRkOTQ0MTM1ODU1ZWIyMWYwMDAwMDAwMCIsInR4aWQiOiI1ZWZkMGI2ZWM1M2MyNTg2MTVjNzAyYmNiNjUyNTUwMzFhMzM2ZTA5YTQ4ZGY5ZDJiYmY4Mjg0MTgyYzZlMTA1IiwiaGFzaCI6ImQ3N2I4OTJmZTBhODk1OTUxZTJmY2YzOGM0MzI5ZTdmY2VlZTc0OGUyN2I4ZmYwMmI3YzA2NzIyZGM1MWNkOTkiLCJzaXplIjoyMDUsInZzaXplIjoxNTQsIndlaWdodCI6NjE2LCJ2ZXJzaW9uIjoyLCJsb2NrdGltZSI6MCwidmluIjpbeyJ0eGlkIjoiMWQ2MWY2MWNmZDMzOGEyMmNiNzllMWE3MjVlMmI4OGUzMzZlODY1YmZlMzE0YzA4MDIzNmY5NGVlNWExY2NlMSIsInZvdXQiOjEsInNjcmlwdFNpZyI6eyJhc20iOiIiLCJoZXgiOiIifSwidHhpbndpdG5lc3MiOlsiY2UwZTczZDhjMmY3MThmODc0ZWE4Njg0ZjYyMTY0YmY4OWQ0YjNkMzIwYTk2ODU5MzUzY2FiYTQ4Yzg4ZDA5NDAzNDdmYTEyNzY2NzVkYjA5NTFjYTViZjFjMWZkNTU2ZjM5ODZlOTY0OTBkMzg4MmRkOTQ0MTM1ODU1ZWIyMWYiXSwic2VxdWVuY2UiOjQyOTQ5NjcyOTV9XSwidm91dCI6W3sidmFsdWUiOjAuMDAwMDIsIm4iOjAsInNjcmlwdFB1YktleSI6eyJhc20iOiIxIDJhZThkY2Y3MDA4ZjRkMjE1NDc1OWZiZTMxMmFlNTgzMDUzMGUxMWZjZDYyYjc0MmViOGUxNDY0ZjliMDA0ZWYiLCJoZXgiOiI1MTIwMmFlOGRjZjcwMDhmNGQyMTU0NzU5ZmJlMzEyYWU1ODMwNTMwZTExZmNkNjJiNzQyZWI4ZTE0NjRmOWIwMDRlZiIsInR5cGUiOiJ3aXRuZXNzX3YxX3RhcHJvb3QifX0seyJ2YWx1ZSI6MC4wMTUzOTY3NSwibiI6MSwic2NyaXB0UHViS2V5Ijp7ImFzbSI6IjEgYmQ1MjA0ZDM4ZGQ1YWZlNTIwZWM4ZGEzOTNkMjA0ZjRkNmRmNmQyNjNkYmYxYzZjYzdmNDgzZDIxZWE2OWFjMSIsImhleCI6IjUxMjBiZDUyMDRkMzhkZDVhZmU1MjBlYzhkYTM5M2QyMDRmNGQ2ZGY2ZDI2M2RiZjFjNmNjN2Y0ODNkMjFlYTY5YWMxIiwidHlwZSI6IndpdG5lc3NfdjFfdGFwcm9vdCJ9fV19LHsiaGV4IjoiMDIwMDAwMDAwMDAxMDEwNWUxYzY4MjQxMjhmOGJiZDJmOThkYTQwOTZlMzMxYTAzNTU1MmI2YmMwMmM3MTU4NjI1M2NjNTZlMGJmZDVlMDAwMDAwMDAwMGZkZmZmZmZmMDIyMjAyMDAwMDAwMDAwMDAwMjI1MTIwYmQ1MjA0ZDM4ZGQ1YWZlNTIwZWM4ZGEzOTNkMjA0ZjRkNmRmNmQyNjNkYmYxYzZjYzdmNDgzZDIxZWE2OWFjMWY4MDQwMDAwMDAwMDAwMDAxNjAwMTRiZGZkNmUwZTg4OWNlNTdjOWFkYmZlODE3YjI2OTc4NmNhMDgyMWQzMDM0MGJiMTk3ZTc1OWIxOTAxNDcyZmI1MDYxZDVjYzI5YWYxYmMwMjYzOThkOWFiZDVlMDQ3ODBiMDk0NjMxOTU4ZmIyOGFlM2VlMWNiZTdhYzYzODhkZWQ1ODllMzVmYzRlNjM2MmI1YzIyMjg4OTZhNzFiN2ExZmY5YWE2OWEyMjg4N2QyMGY2NzA4YmI0NDFmZWRlMDkyZGNjMmZhNjgxYmY0YWU5ZjU0M2ZlN2JmNmRmMTdkNzQ3MGZhNThhNTNkZWFkODBhYzAwNjMwMzZmNzI2NDAxMDExODc0NjU3ODc0MmY3MDZjNjE2OTZlM2I2MzY4NjE3MjczNjU3NDNkNzU3NDY2MmQzODAwMzc3YjIyNzAyMjNhMjI2MjcyNjMyZDMyMzAyMjJjMjI2ZjcwMjIzYTIyNzQ3MjYxNmU3MzY2NjU3MjIyMmMyMjc0Njk2MzZiMjIzYTIyNzM2MTc0NzMyMjJjMjI2MTZkNzQyMjNhMjIzMTMwMjI3ZDY4MjFjMWZmZjcxMWRhNWNmNDFmM2ZhY2QzMjc3YWJmZWJlOGNmYjkyYTk3NGZjYTdjM2RlZGRiYjZkYzJjOTA0NmI4ZWIwMDAwMDAwMCIsInR4aWQiOiJlZDYyNGZlMzJkMWIxNzk0ZDdhYzJlNjc0NGJhYzVlOTBkOWExZWI3YzM3NzNhZmZiZjcxOTBiYzhhMDJlNDA4IiwiaGFzaCI6IjY3M2JkZTVlZmEzNWI4YzIyN2FhMzkxZjY2OGM4YzJlZWVlMDJlNzBmMGU1ZTAwYzg0NjdhNTVkNTk3NGYzNGUiLCJzaXplIjozNTMsInZzaXplIjoxODIsIndlaWdodCI6NzI4LCJ2ZXJzaW9uIjoyLCJsb2NrdGltZSI6MCwidmluIjpbeyJ0eGlkIjoiNWVmZDBiNmVjNTNjMjU4NjE1YzcwMmJjYjY1MjU1MDMxYTMzNmUwOWE0OGRmOWQyYmJmODI4NDE4MmM2ZTEwNSIsInZvdXQiOjAsInNjcmlwdFNpZyI6eyJhc20iOiIiLCJoZXgiOiIifSwidHhpbndpdG5lc3MiOlsiYmIxOTdlNzU5YjE5MDE0NzJmYjUwNjFkNWNjMjlhZjFiYzAyNjM5OGQ5YWJkNWUwNDc4MGIwOTQ2MzE5NThmYjI4YWUzZWUxY2JlN2FjNjM4OGRlZDU4OWUzNWZjNGU2MzYyYjVjMjIyODg5NmE3MWI3YTFmZjlhYTY5YTIyODgiLCIyMGY2NzA4YmI0NDFmZWRlMDkyZGNjMmZhNjgxYmY0YWU5ZjU0M2ZlN2JmNmRmMTdkNzQ3MGZhNThhNTNkZWFkODBhYzAwNjMwMzZmNzI2NDAxMDExODc0NjU3ODc0MmY3MDZjNjE2OTZlM2I2MzY4NjE3MjczNjU3NDNkNzU3NDY2MmQzODAwMzc3YjIyNzAyMjNhMjI2MjcyNjMyZDMyMzAyMjJjMjI2ZjcwMjIzYTIyNzQ3MjYxNmU3MzY2NjU3MjIyMmMyMjc0Njk2MzZiMjIzYTIyNzM2MTc0NzMyMjJjMjI2MTZkNzQyMjNhMjIzMTMwMjI3ZDY4IiwiYzFmZmY3MTFkYTVjZjQxZjNmYWNkMzI3N2FiZmViZThjZmI5MmE5NzRmY2E3YzNkZWRkYmI2ZGMyYzkwNDZiOGViIl0sInNlcXVlbmNlIjo0Mjk0OTY3MjkzfV0sInZvdXQiOlt7InZhbHVlIjowLjAwMDAwNTQ2LCJuIjowLCJzY3JpcHRQdWJLZXkiOnsiYXNtIjoiMSBiZDUyMDRkMzhkZDVhZmU1MjBlYzhkYTM5M2QyMDRmNGQ2ZGY2ZDI2M2RiZjFjNmNjN2Y0ODNkMjFlYTY5YWMxIiwiaGV4IjoiNTEyMGJkNTIwNGQzOGRkNWFmZTUyMGVjOGRhMzkzZDIwNGY0ZDZkZjZkMjYzZGJmMWM2Y2M3ZjQ4M2QyMWVhNjlhYzEiLCJ0eXBlIjoid2l0bmVzc192MV90YXByb290In19LHsidmFsdWUiOjAuMDAwMDEyNzIsIm4iOjEsInNjcmlwdFB1YktleSI6eyJhc20iOiIwIGJkZmQ2ZTBlODg5Y2U1N2M5YWRiZmU4MTdiMjY5Nzg2Y2EwODIxZDMiLCJoZXgiOiIwMDE0YmRmZDZlMGU4ODljZTU3YzlhZGJmZTgxN2IyNjk3ODZjYTA4MjFkMyIsInR5cGUiOiJ3aXRuZXNzX3YwX2tleWhhc2gifX1dfSx7ImhleCI6IjAyMDAwMDAwMDAwMTAyMDhlNDAyOGFiYzkwNzFiZmZmM2E3N2MzYjcxZTlhMGRlOWM1YmE0NDY3MmVhY2Q3OTQxNzFiMmRlMzRmNjJlZDAwMDAwMDAwMDBmZmZmZmZmZjA1ZTFjNjgyNDEyOGY4YmJkMmY5OGRhNDA5NmUzMzFhMDM1NTUyYjZiYzAyYzcxNTg2MjUzY2M1NmUwYmZkNWUwMTAwMDAwMDAwZmZmZmZmZmYwMjAxMDAwMDAwMDAwMDAwMDAyMjZhMjA0NTI3ZDEzYzNmYWZhZDMyYTAxNmUwY2Q0YzYxNWI2NWVmMWQ3ZmIxOWJmYWUzYmM2ZGM4ZTE0MTJlMWI3YzVjYTI3ZjE3MDAwMDAwMDAwMDIyNTEyMGJkNTIwNGQzOGRkNWFmZTUyMGVjOGRhMzkzZDIwNGY0ZDZkZjZkMjYzZGJmMWM2Y2M3ZjQ4M2QyMWVhNjlhYzEwMTQwZGU4OGE2NmI5N2NkMzVmM2E4ZjM3NGYzZjg3YzhiMDI1YTI5ZDgzYzFlYjkyOWMyNWRkNDk5YjVkYzlhNzNhYWNlODdhZDRmNjBkYzYzMjg2ODlhNWQ1ZTU0MDVmZDIxYWEyMzdhZDg2ZmYwMjA5OWNlYjFiNmYwYWY4MTQzNTQwMTQwNjMyODk4MzVjOTllNWY5OTdiYTY4YTkyODc2YjI3NTBhMzQyZmIyOTJlMDQwZjBkNzRiMjhkMWY5YWY4MmRiNTE4OTcxNzNlYjQ5NGZjYTBjNmE3MzI1OTdiMDhmNzVlM2M5M2VhNjk1ODZiZTcyMzU0ODA1MjUxMmFmMmQ1MTMwMDAwMDAwMCIsInR4aWQiOiI1NDFmYWJiMzFmNmI5NzU5NDM1NmM4MDA2YjY2YWM4YTQxYWFiN2Y2OTcwNDhhN2Q2OTViYTJhOGVjYTY1OTcyIiwiaGFzaCI6IjA3Y2QxYWIxNzQ0MDVmODU3MjRmYWQ4NzViMWUwN2I1YjJjYTYzNTA5ZjIyNjU0MTc0OTQ5ZmY4ZGFhYTI2M2QiLCJzaXplIjozMTIsInZzaXplIjoyMTIsIndlaWdodCI6ODQ2LCJ2ZXJzaW9uIjoyLCJsb2NrdGltZSI6MCwidmluIjpbeyJ0eGlkIjoiZWQ2MjRmZTMyZDFiMTc5NGQ3YWMyZTY3NDRiYWM1ZTkwZDlhMWViN2MzNzczYWZmYmY3MTkwYmM4YTAyZTQwOCIsInZvdXQiOjAsInNjcmlwdFNpZyI6eyJhc20iOiIiLCJoZXgiOiIifSwidHhpbndpdG5lc3MiOlsiZGU4OGE2NmI5N2NkMzVmM2E4ZjM3NGYzZjg3YzhiMDI1YTI5ZDgzYzFlYjkyOWMyNWRkNDk5YjVkYzlhNzNhYWNlODdhZDRmNjBkYzYzMjg2ODlhNWQ1ZTU0MDVmZDIxYWEyMzdhZDg2ZmYwMjA5OWNlYjFiNmYwYWY4MTQzNTQiXSwic2VxdWVuY2UiOjQyOTQ5NjcyOTV9LHsidHhpZCI6IjVlZmQwYjZlYzUzYzI1ODYxNWM3MDJiY2I2NTI1NTAzMWEzMzZlMDlhNDhkZjlkMmJiZjgyODQxODJjNmUxMDUiLCJ2b3V0IjoxLCJzY3JpcHRTaWciOnsiYXNtIjoiIiwiaGV4IjoiIn0sInR4aW53aXRuZXNzIjpbIjYzMjg5ODM1Yzk5ZTVmOTk3YmE2OGE5Mjg3NmIyNzUwYTM0MmZiMjkyZTA0MGYwZDc0YjI4ZDFmOWFmODJkYjUxODk3MTczZWI0OTRmY2EwYzZhNzMyNTk3YjA4Zjc1ZTNjOTNlYTY5NTg2YmU3MjM1NDgwNTI1MTJhZjJkNTEzIl0sInNlcXVlbmNlIjo0Mjk0OTY3Mjk1fV0sInZvdXQiOlt7InZhbHVlIjoxZS04LCJuIjowLCJzY3JpcHRQdWJLZXkiOnsiYXNtIjoiT1BfUkVUVVJOIDQ1MjdkMTNjM2ZhZmFkMzJhMDE2ZTBjZDRjNjE1YjY1ZWYxZDdmYjE5YmZhZTNiYzZkYzhlMTQxMmUxYjdjNWMiLCJoZXgiOiI2YTIwNDUyN2QxM2MzZmFmYWQzMmEwMTZlMGNkNGM2MTViNjVlZjFkN2ZiMTliZmFlM2JjNmRjOGUxNDEyZTFiN2M1YyIsInR5cGUiOiJudWxsZGF0YSJ9fSx7InZhbHVlIjowLjAxNTQwMDAyLCJuIjoxLCJzY3JpcHRQdWJLZXkiOnsiYXNtIjoiMSBiZDUyMDRkMzhkZDVhZmU1MjBlYzhkYTM5M2QyMDRmNGQ2ZGY2ZDI2M2RiZjFjNmNjN2Y0ODNkMjFlYTY5YWMxIiwiaGV4IjoiNTEyMGJkNTIwNGQzOGRkNWFmZTUyMGVjOGRhMzkzZDIwNGY0ZDZkZjZkMjYzZGJmMWM2Y2M3ZjQ4M2QyMWVhNjlhYzEiLCJ0eXBlIjoid2l0bmVzc192MV90YXByb290In19XX0seyJoZXgiOiIwMjAwMDAwMDAwMDEwMzFlZjI5NzFhZDhkMzA1NDRjNmViMTExYmQ2MTIzYzZmZGQ4MWE4OGM3ZTAwZjEwOGE2M2NiNTMxMTRkMGUxOGMwMTAwMDAwMDAwZmZmZmZmZmZjOWE2ZDQ3MGE1MzFiNjVhZmM1ZmU4YmJmMWY1YWMwNDk4MWRlNzkzZjllZDIwMTVlMDIwNWMzOTFiZjkwZTMzMDAwMDAwMDAwMGZmZmZmZmZmYWE1OWRkMjQzNTU1N2M4NDYyYWNmNzc2ZjFiMTU4NTQzZjIwYThjZGM0MzJkOWY5NGEwMmJhYzkwZWMyYTE5OTAwMDAwMDAwMDBmZmZmZmZmZjAyYzQyZmFkMDIwMDAwMDAwMDE2MDAxNDQ1NjY1ZmVhNDlhMTdiOGQ2MDZkZTI4ZGEwNjBmZTIxZDNlN2U2YmRhNjBlNGYwMDAwMDAwMDAwMTYwMDE0ZTM0MTdhYzMyYjA0NzlkNDQ0MTc5NDExNzU4MjVkNmY0YzRiZWI4ZTAyNDczMDQ0MDIyMDZmN2RhZGY0NmMzMGVkN2ExYjRjM2E3YTEzMWUxM2NiMjA2M2QwZDk1OWU5MzgxNzZkOTVlYjE1OTY1MTc2OWMwMjIwNWE3NmMwYjU3OGVjODUzNTFhOTVhODI3ZWZmMWM1MTMwMDc4OTQ1OWVkMThiZmVhNmRlMmRhODg2YzViOTU0MjAxMjEwMjkxMWE3ZjJjNzFiZGVlNDA0N2U3MTc3MmExOGZlMjBmMjU0MzA3ZDJjZTE1OTg3ZDNmNTRkODcxZmFiYmU2NGQwMjQ3MzA0NDAyMjA0MWZlZjEwYmFmYzU5ZjlhOTdlMDQ1ZTNhYTI0M2I5MjRmZDgxNzJkY2U2NzY1MzAxZmFmYjI4MDhmYWE2NzUxMDIyMDZiZGE2Zjc2ZmRkMzJiYzM4NDE4YWE1OGY3NzQ0OTM1YTEwOTdlNTg1YTk1OWIzOWJhMGZlODFiMzVjZDVjMGIwMTIxMDM0ODcwZWE4MGJjOTBlZDQzMjFkZGMwMDAzMjEyOTcxZGViYTJlMGNlYjA4YzlhZWVmMDI0ZGQwMTMyZDI5NDY0MDI0NzMwNDQwMjIwMTIzYmI3NGE0MDQ0ZDlmYWQ3NTk1ODUxMGJhNWU3ZWEwM2I2ZGJjYjcxOWNhYTBjNDdjZjhlYjQ2NWFhN2VjYzAyMjAxZmEwNDFjYzI0NDE4ZmRjZmYwMjMwM2NjNDE3MWIwNTEyZmU1ZTE5ZmYwN2NiZjI1NmQxNTVkYTAwMzNiNGFmMDEyMTAyYWJlNTAzODJkMjJlMTljZGYxMGU1ODNkMDE1MjViNDYyYzgyZDhhMmJjZTQ5NjI3ZDFmZDdhMTRmYmI0OTdhYTAwMDAwMDAwIiwidHhpZCI6IjI0MzAyYzRmZjU4ZmZkMTdkYjQ0ODU3ZWRkYjhjODNlYWZiNjAyZTcyNGU0N2RiZTVjMTc4YTFiZTU5ZTliZjAiLCJoYXNoIjoiYzViNmE0ZmI3N2FhM2E3ZDFiZDk4NjE1NzY3NDA2NTBlNjc2MzRiZDU5OGY1YTM2OTBjZjNkZTVhNDEzZWNiNSIsInNpemUiOjUxOCwidnNpemUiOjI3Niwid2VpZ2h0IjoxMTAzLCJ2ZXJzaW9uIjoyLCJsb2NrdGltZSI6MCwidmluIjpbeyJ0eGlkIjoiOGNlMWQwMTQzMWI1M2NhNjA4ZjEwMDdlOGNhODgxZGQ2ZjNjMTJkNjFiMTFlYmM2NDQwNWQzZDgxYTk3ZjIxZSIsInZvdXQiOjEsInNjcmlwdFNpZyI6eyJhc20iOiIiLCJoZXgiOiIifSwidHhpbndpdG5lc3MiOlsiMzA0NDAyMjA2ZjdkYWRmNDZjMzBlZDdhMWI0YzNhN2ExMzFlMTNjYjIwNjNkMGQ5NTllOTM4MTc2ZDk1ZWIxNTk2NTE3NjljMDIyMDVhNzZjMGI1NzhlYzg1MzUxYTk1YTgyN2VmZjFjNTEzMDA3ODk0NTllZDE4YmZlYTZkZTJkYTg4NmM1Yjk1NDIwMSIsIjAyOTExYTdmMmM3MWJkZWU0MDQ3ZTcxNzcyYTE4ZmUyMGYyNTQzMDdkMmNlMTU5ODdkM2Y1NGQ4NzFmYWJiZTY0ZCJdLCJzZXF1ZW5jZSI6NDI5NDk2NzI5NX0seyJ0eGlkIjoiMzMwZWY5MWIzOTVjMjBlMDE1MjBlZGY5OTNlNzFkOTgwNGFjZjVmMWJiZTg1ZmZjNWFiNjMxYTU3MGQ0YTZjOSIsInZvdXQiOjAsInNjcmlwdFNpZyI6eyJhc20iOiIiLCJoZXgiOiIifSwidHhpbndpdG5lc3MiOlsiMzA0NDAyMjA0MWZlZjEwYmFmYzU5ZjlhOTdlMDQ1ZTNhYTI0M2I5MjRmZDgxNzJkY2U2NzY1MzAxZmFmYjI4MDhmYWE2NzUxMDIyMDZiZGE2Zjc2ZmRkMzJiYzM4NDE4YWE1OGY3NzQ0OTM1YTEwOTdlNTg1YTk1OWIzOWJhMGZlODFiMzVjZDVjMGIwMSIsIjAzNDg3MGVhODBiYzkwZWQ0MzIxZGRjMDAwMzIxMjk3MWRlYmEyZTBjZWIwOGM5YWVlZjAyNGRkMDEzMmQyOTQ2NCJdLCJzZXF1ZW5jZSI6NDI5NDk2NzI5NX0seyJ0eGlkIjoiOTlhMWMyMGVjOWJhMDI0YWY5ZDkzMmM0Y2RhODIwM2Y1NDU4YjFmMTc2ZjdhYzYyODQ3YzU1MzUyNGRkNTlhYSIsInZvdXQiOjAsInNjcmlwdFNpZyI6eyJhc20iOiIiLCJoZXgiOiIifSwidHhpbndpdG5lc3MiOlsiMzA0NDAyMjAxMjNiYjc0YTQwNDRkOWZhZDc1OTU4NTEwYmE1ZTdlYTAzYjZkYmNiNzE5Y2FhMGM0N2NmOGViNDY1YWE3ZWNjMDIyMDFmYTA0MWNjMjQ0MThmZGNmZjAyMzAzY2M0MTcxYjA1MTJmZTVlMTlmZjA3Y2JmMjU2ZDE1NWRhMDAzM2I0YWYwMSIsIjAyYWJlNTAzODJkMjJlMTljZGYxMGU1ODNkMDE1MjViNDYyYzgyZDhhMmJjZTQ5NjI3ZDFmZDdhMTRmYmI0OTdhYSJdLCJzZXF1ZW5jZSI6NDI5NDk2NzI5NX1dLCJ2b3V0IjpbeyJ2YWx1ZSI6MC40NDkwNDM4OCwibiI6MCwic2NyaXB0UHViS2V5Ijp7ImFzbSI6IjAgNDU2NjVmZWE0OWExN2I4ZDYwNmRlMjhkYTA2MGZlMjFkM2U3ZTZiZCIsImhleCI6IjAwMTQ0NTY2NWZlYTQ5YTE3YjhkNjA2ZGUyOGRhMDYwZmUyMWQzZTdlNmJkIiwidHlwZSI6IndpdG5lc3NfdjBfa2V5aGFzaCJ9fSx7InZhbHVlIjowLjA1MTgxMDk0LCJuIjoxLCJzY3JpcHRQdWJLZXkiOnsiYXNtIjoiMCBlMzQxN2FjMzJiMDQ3OWQ0NDQxNzk0MTE3NTgyNWQ2ZjRjNGJlYjhlIiwiaGV4IjoiMDAxNGUzNDE3YWMzMmIwNDc5ZDQ0NDE3OTQxMTc1ODI1ZDZmNGM0YmViOGUiLCJ0eXBlIjoid2l0bmVzc192MF9rZXloYXNoIn19XX0seyJoZXgiOiIwMjAwMDAwMDAwMDEwMTc3NTI4YzVhODBhYzYwMDU5M2YwZGZjNGZmODk0MjBmNDU3OGQwZjdjNjQxZWE0ODZjYTcxMDUxODdiODRkM2YwMDAwMDAwMDAwZmZmZmZmZmYwMmE0MzBkMjA5MDAwMDAwMDAxNjAwMTQ0NmNiYTY5ZjhjYTZkMDkxNTQ5ODlkMWI3M2Y0OWViN2M0MzA5MjAxMTc0YjIzMDAwMDAwMDAwMDE2MDAxNGM4ZDJmOWUzNGJmZTY5MDRiOWVmZmMzMTg1OTQ3OGZlNjIzODMyYjQwMjQ3MzA0NDAyMjA3ZmIwMGU1MjE4ODE2NGY1NzVlZjUwNmM5ODlmNWE4YmMzZDEwN2RmOTc1OThkYjYxMWNmNGNmZGMxZTY5NjJjMDIyMDM5NWY2YWExNzhkYjJmY2EwNDk1NTljNjU2Y2MwNzZjYmZlMDAzOGFlNWUwYzAzMTNmOGIwZTM0YmIwZTAwNmIwMTIxMDJlNzY4ZTk3ZDJiMDk3ZTU5ODM1MTY5NWMxOWQ2MzA3ZWEyOWMwMzU0NWI5OTQ3Njc1M2JiY2RiOWYxMjkzOWEzMDAwMDAwMDAiLCJ0eGlkIjoiYjQ1MmZlNjU1YTJkNmE4MTYzNDVmYWM3NDJhY2FkY2ZhZmUxOWE3MmMxOWYwOGEwNjU2MDcyMDRlYTNmNDg2OSIsImhhc2giOiI4ZDZmMGJkNTUwNDQwZTk4YjZhNzg5MWE0OTYxMTY2M2YzMDNjNzQ5YmZjZDc0M2UyZTE0NzI4Y2M3NjlhNWIxIiwic2l6ZSI6MjIyLCJ2c2l6ZSI6MTQxLCJ3ZWlnaHQiOjU2MSwidmVyc2lvbiI6MiwibG9ja3RpbWUiOjAsInZpbiI6W3sidHhpZCI6IjNmNGRiODg3NTExMGE3NmM0OGVhNDFjNmY3ZDA3ODQ1MGY0Mjg5ZmZjNGRmZjA5MzA1NjBhYzgwNWE4YzUyNzciLCJ2b3V0IjowLCJzY3JpcHRTaWciOnsiYXNtIjoiIiwiaGV4IjoiIn0sInR4aW53aXRuZXNzIjpbIjMwNDQwMjIwN2ZiMDBlNTIxODgxNjRmNTc1ZWY1MDZjOTg5ZjVhOGJjM2QxMDdkZjk3NTk4ZGI2MTFjZjRjZmRjMWU2OTYyYzAyMjAzOTVmNmFhMTc4ZGIyZmNhMDQ5NTU5YzY1NmNjMDc2Y2JmZTAwMzhhZTVlMGMwMzEzZjhiMGUzNGJiMGUwMDZiMDEiLCIwMmU3NjhlOTdkMmIwOTdlNTk4MzUxNjk1YzE5ZDYzMDdlYTI5YzAzNTQ1Yjk5NDc2NzUzYmJjZGI5ZjEyOTM5YTMiXSwic2VxdWVuY2UiOjQyOTQ5NjcyOTV9XSwidm91dCI6W3sidmFsdWUiOjEuNjQ3Njk5NTYsIm4iOjAsInNjcmlwdFB1YktleSI6eyJhc20iOiIwIDQ2Y2JhNjlmOGNhNmQwOTE1NDk4OWQxYjczZjQ5ZWI3YzQzMDkyMDEiLCJoZXgiOiIwMDE0NDZjYmE2OWY4Y2E2ZDA5MTU0OTg5ZDFiNzNmNDllYjdjNDMwOTIwMSIsInR5cGUiOiJ3aXRuZXNzX3YwX2tleWhhc2gifX0seyJ2YWx1ZSI6MC4wMjMxMjk4MywibiI6MSwic2NyaXB0UHViS2V5Ijp7ImFzbSI6IjAgYzhkMmY5ZTM0YmZlNjkwNGI5ZWZmYzMxODU5NDc4ZmU2MjM4MzJiNCIsImhleCI6IjAwMTRjOGQyZjllMzRiZmU2OTA0YjllZmZjMzE4NTk0NzhmZTYyMzgzMmI0IiwidHlwZSI6IndpdG5lc3NfdjBfa2V5aGFzaCJ9fV19LHsiaGV4IjoiMDIwMDAwMDAwMDAxMDEwMDA1N2VjNjYyZmI0NWY2ZTEzZDk5ZmI1ZjJjOGQ0MzhlODQzMGU0NjRjZjlkMzRjMmFlYzkzYjkxNmE2N2NiMDEwMDAwMDAwMGZmZmZmZmZmMDJiODA1MDEwMDAwMDAwMDAwMjI1MTIwMTViNTM5MDgxY2FkMzU5NTM2MDUwNTAxMGY0MjhjNzc1M2Y5MmM1MzZjZTYzZTQzNzVjNTUyZTk0Y2Y1NGUxMGZiM2IyZTAwMDAwMDAwMDAyMjUxMjA0N2ViNjllNWU4NDA2Y2QyODc1YTM5YjJiZDhiYzViYjNkOGEzN2E5ODg4NWYyODJlNzg4YzE2MTg3YWZiMWVlMDE0MDg3MDQzOTczZDQ5OTVhOWUwZjQ3MDhlNDY1MjAxNDc2MTU3ZTA1YmMzYzY4ZmZiMDczODE4ZGNhNWE0YzFjYmNkMGZmYmJjMzc1OTk3ZDNhM2VkZjIzODQwNjAwNzA0ZTBhOTc2OWVmNGNlMWQzM2QyYmY5OTY4MWFjM2U0YmFmMDAwMDAwMDAiLCJ0eGlkIjoiYWUyYWMzYjJhZjNiNTNhMjc3NDg5OGNhMmFhYmQ0NDk1MjBiMGVmZmYxMDNhZDAwMmM5ZGU5Y2RkNmU0ZDk5MSIsImhhc2giOiJlZDEzMWEyZGU4OWJiNjFlOGJmZTMxMTc1NzljZWJiNTlhMWY5ZWRmOWQxMDczZjI1ZTI4NWQ4NjYxOTA5YmFlIiwic2l6ZSI6MjA1LCJ2c2l6ZSI6MTU0LCJ3ZWlnaHQiOjYxNiwidmVyc2lvbiI6MiwibG9ja3RpbWUiOjAsInZpbiI6W3sidHhpZCI6ImNiNjc2YTkxM2JjOWFlYzIzNDlkY2Y2NGU0MzA4NDhlNDM4ZDJjNWZmYjk5M2RlMWY2NDVmYjYyYzY3ZTA1MDAiLCJ2b3V0IjoxLCJzY3JpcHRTaWciOnsiYXNtIjoiIiwiaGV4IjoiIn0sInR4aW53aXRuZXNzIjpbIjg3MDQzOTczZDQ5OTVhOWUwZjQ3MDhlNDY1MjAxNDc2MTU3ZTA1YmMzYzY4ZmZiMDczODE4ZGNhNWE0YzFjYmNkMGZmYmJjMzc1OTk3ZDNhM2VkZjIzODQwNjAwNzA0ZTBhOTc2OWVmNGNlMWQzM2QyYmY5OTY4MWFjM2U0YmFmIl0sInNlcXVlbmNlIjo0Mjk0OTY3Mjk1fV0sInZvdXQiOlt7InZhbHVlIjowLjAwMDY3LCJuIjowLCJzY3JpcHRQdWJLZXkiOnsiYXNtIjoiMSAxNWI1MzkwODFjYWQzNTk1MzYwNTA1MDEwZjQyOGM3NzUzZjkyYzUzNmNlNjNlNDM3NWM1NTJlOTRjZjU0ZTEwIiwiaGV4IjoiNTEyMDE1YjUzOTA4MWNhZDM1OTUzNjA1MDUwMTBmNDI4Yzc3NTNmOTJjNTM2Y2U2M2U0Mzc1YzU1MmU5NGNmNTRlMTAiLCJ0eXBlIjoid2l0bmVzc192MV90YXByb290In19LHsidmFsdWUiOjAuMDMwMzAwMTEsIm4iOjEsInNjcmlwdFB1YktleSI6eyJhc20iOiIxIDQ3ZWI2OWU1ZTg0MDZjZDI4NzVhMzliMmJkOGJjNWJiM2Q4YTM3YTk4ODg1ZjI4MmU3ODhjMTYxODdhZmIxZWUiLCJoZXgiOiI1MTIwNDdlYjY5ZTVlODQwNmNkMjg3NWEzOWIyYmQ4YmM1YmIzZDhhMzdhOTg4ODVmMjgyZTc4OGMxNjE4N2FmYjFlZSIsInR5cGUiOiJ3aXRuZXNzX3YxX3RhcHJvb3QifX1dfSx7ImhleCI6IjAyMDAwMDAwMDAwMTAxOTFkOWU0ZDZjZGU5OWQyYzAwYWQwM2YxZmYwZTBiNTI0OWQ0YWIyYWNhOTg0ODc3YTI1MzNiYWZiMmMzMmFhZTAxMDAwMDAwMDBmZmZmZmZmZjAyYjgwNTAxMDAwMDAwMDAwMDIyNTEyMDhlMmQxY2I4NGUzNmJjMWY0NzczOGRjODg2MTViMmM0MjUyODY1YWVjMTIxNjUxMThhYTdiOTlkOTdjNWQwYjJhNzM1MmQwMDAwMDAwMDAwMjI1MTIwNDdlYjY5ZTVlODQwNmNkMjg3NWEzOWIyYmQ4YmM1YmIzZDhhMzdhOTg4ODVmMjgyZTc4OGMxNjE4N2FmYjFlZTAxNDBlNDZkNDk3N2RiZGNhYmMzNzJiMzg3OTc1ZWM5N2JlM2JkNTUxOGQ1ODRhYzEzYTQ0ZGE2ZjZmOTI4ZWJiOGIwYjEwNTNmMjcyZDA4Njk3YmU5M2UzYzFmYThlM2M3MWNjNGZiNmM0MDAwODQ3MGVjYjMwY2RjMzUyOTA0OTg0MzAwMDAwMDAwIiwidHhpZCI6IjBlOGY5ZDI4ZGVkZDYyMmYwMzdjMWMyMDk2Yzg4YjdjYWVjOGViNzQyZGQwZmNiOWEwMzIwNDQwNGM5YjJmNDUiLCJoYXNoIjoiMzBkMzc4Zjk2YTEzODZiZjM3NjM1ODhhYzYwZGJkMzQ4MDhkYzcxZmY3MWM4NGQ0YWI2ZDJmM2U2N2FkYWY5ZSIsInNpemUiOjIwNSwidnNpemUiOjE1NCwid2VpZ2h0Ijo2MTYsInZlcnNpb24iOjIsImxvY2t0aW1lIjowLCJ2aW4iOlt7InR4aWQiOiJhZTJhYzNiMmFmM2I1M2EyNzc0ODk4Y2EyYWFiZDQ0OTUyMGIwZWZmZjEwM2FkMDAyYzlkZTljZGQ2ZTRkOTkxIiwidm91dCI6MSwic2NyaXB0U2lnIjp7ImFzbSI6IiIsImhleCI6IiJ9LCJ0eGlud2l0bmVzcyI6WyJlNDZkNDk3N2RiZGNhYmMzNzJiMzg3OTc1ZWM5N2JlM2JkNTUxOGQ1ODRhYzEzYTQ0ZGE2ZjZmOTI4ZWJiOGIwYjEwNTNmMjcyZDA4Njk3YmU5M2UzYzFmYThlM2M3MWNjNGZiNmM0MDAwODQ3MGVjYjMwY2RjMzUyOTA0OTg0MyJdLCJzZXF1ZW5jZSI6NDI5NDk2NzI5NX1dLCJ2b3V0IjpbeyJ2YWx1ZSI6MC4wMDA2NywibiI6MCwic2NyaXB0UHViS2V5Ijp7ImFzbSI6IjEgOGUyZDFjYjg0ZTM2YmMxZjQ3NzM4ZGM4ODYxNWIyYzQyNTI4NjVhZWMxMjE2NTExOGFhN2I5OWQ5N2M1ZDBiMiIsImhleCI6IjUxMjA4ZTJkMWNiODRlMzZiYzFmNDc3MzhkYzg4NjE1YjJjNDI1Mjg2NWFlYzEyMTY1MTE4YWE3Yjk5ZDk3YzVkMGIyIiwidHlwZSI6IndpdG5lc3NfdjFfdGFwcm9vdCJ9fSx7InZhbHVlIjowLjAyOTYyODU1LCJuIjoxLCJzY3JpcHRQdWJLZXkiOnsiYXNtIjoiMSA0N2ViNjllNWU4NDA2Y2QyODc1YTM5YjJiZDhiYzViYjNkOGEzN2E5ODg4NWYyODJlNzg4YzE2MTg3YWZiMWVlIiwiaGV4IjoiNTEyMDQ3ZWI2OWU1ZTg0MDZjZDI4NzVhMzliMmJkOGJjNWJiM2Q4YTM3YTk4ODg1ZjI4MmU3ODhjMTYxODdhZmIxZWUiLCJ0eXBlIjoid2l0bmVzc192MV90YXByb290In19XX0seyJoZXgiOiIwMjAwMDAwMDAwMDEwMTQyODMzY2MwNDIzMDEwZjRkZWUwZWE0NjM4ZTg5NTE2OGNiZTI2MTk3NjQzMGRhMmQxNmMxZDU3NGFlNTMyNDIwMTAwMDAwMDAwZmZmZmZmZmYwM2E1M2QwMDAwMDAwMDAwMDAxNjAwMTQ1NDg5YzZiODUyZDEzNjM4MGFkMTBiMWIwNzVhYWQ3NzEwMDIzOWZkYTAwYTBjMDAwMDAwMDAwMDE2MDAxNDE3MGE5YjJmNjE3MWY4MzRhYzdkY2E2ZmRmYjY1MGNmODE4MzVhMGRjYjBhMGMwMDAwMDAwMDAwMjI1MTIwOTA1YTVjODYxNjE3Y2U5ODg0YWVkNDM5MGJjYTQxYzdhZmJkNzY0ZTEzMGM4MDVjYzk5NzBjNTI1MWFlMjdmYTAyNDczMDQ0MDIyMDQ4M2QzODQzODcxZTZkNTI1Y2ZiNjYzNGNlZTkxMjNkNDI2M2IxNDE4ZGJhNzJiN2M0NDc3ZWVhY2U3ODYwNTcwMjIwN2ZkNDE4NzcyODliMWFlNGMxZjNmN2Q5NzZjYTUzM2ZiY2Y2ZWVmYjMxMzYzN2QxZmQ0MzU3M2VlNTUyNTQ4YjAxMjEwMmU2NTMwYTc3ODg5MmQzYzBlNTI2MGZjZTYxZjM4OWY0NmI4YmU3NzYzOWY1M2MwMWI1ZWQ5ODFhNGRmNDM3NzUwMDAwMDAwMCIsInR4aWQiOiJiNmU0YTU3NjkwOTQ4MTg5ZGJiZTljOGNiMzc0M2MwNTg4NzRhYTcwM2Y2MDhiYjA5ZThiZDk5ZmQ4ZDhkYzc2IiwiaGFzaCI6IjI0NDZhMGY0MDU1MDcxNTEyMzRiMTkxMTg4ZmZhNGVmM2M2YWJjYTQ2MjYyNTUwN2E1YWMyMTA2MTlkNmFlN2UiLCJzaXplIjoyNjUsInZzaXplIjoxODQsIndlaWdodCI6NzMzLCJ2ZXJzaW9uIjoyLCJsb2NrdGltZSI6MCwidmluIjpbeyJ0eGlkIjoiNDIzMmU1NGE1NzFkNmNkMWEyMGQ0Mzc2MTkyNmJlOGMxNjk1ZTgzODQ2ZWFlMGRlZjQxMDMwNDJjMDNjODM0MiIsInZvdXQiOjEsInNjcmlwdFNpZyI6eyJhc20iOiIiLCJoZXgiOiIifSwidHhpbndpdG5lc3MiOlsiMzA0NDAyMjA0ODNkMzg0Mzg3MWU2ZDUyNWNmYjY2MzRjZWU5MTIzZDQyNjNiMTQxOGRiYTcyYjdjNDQ3N2VlYWNlNzg2MDU3MDIyMDdmZDQxODc3Mjg5YjFhZTRjMWYzZjdkOTc2Y2E1MzNmYmNmNmVlZmIzMTM2MzdkMWZkNDM1NzNlZTU1MjU0OGIwMSIsIjAyZTY1MzBhNzc4ODkyZDNjMGU1MjYwZmNlNjFmMzg5ZjQ2YjhiZTc3NjM5ZjUzYzAxYjVlZDk4MWE0ZGY0Mzc3NSJdLCJzZXF1ZW5jZSI6NDI5NDk2NzI5NX1dLCJ2b3V0IjpbeyJ2YWx1ZSI6MC4wMDAxNTc4MSwibiI6MCwic2NyaXB0UHViS2V5Ijp7ImFzbSI6IjAgNTQ4OWM2Yjg1MmQxMzYzODBhZDEwYjFiMDc1YWFkNzcxMDAyMzlmZCIsImhleCI6IjAwMTQ1NDg5YzZiODUyZDEzNjM4MGFkMTBiMWIwNzVhYWQ3NzEwMDIzOWZkIiwidHlwZSI6IndpdG5lc3NfdjBfa2V5aGFzaCJ9fSx7InZhbHVlIjowLjAwNzg5MTUyLCJuIjoxLCJzY3JpcHRQdWJLZXkiOnsiYXNtIjoiMCAxNzBhOWIyZjYxNzFmODM0YWM3ZGNhNmZkZmI2NTBjZjgxODM1YTBkIiwiaGV4IjoiMDAxNDE3MGE5YjJmNjE3MWY4MzRhYzdkY2E2ZmRmYjY1MGNmODE4MzVhMGQiLCJ0eXBlIjoid2l0bmVzc192MF9rZXloYXNoIn19LHsidmFsdWUiOjAuMDA3ODkxOTUsIm4iOjIsInNjcmlwdFB1YktleSI6eyJhc20iOiIxIDkwNWE1Yzg2MTYxN2NlOTg4NGFlZDQzOTBiY2E0MWM3YWZiZDc2NGUxMzBjODA1Y2M5OTcwYzUyNTFhZTI3ZmEiLCJoZXgiOiI1MTIwOTA1YTVjODYxNjE3Y2U5ODg0YWVkNDM5MGJjYTQxYzdhZmJkNzY0ZTEzMGM4MDVjYzk5NzBjNTI1MWFlMjdmYSIsInR5cGUiOiJ3aXRuZXNzX3YxX3RhcHJvb3QifX1dfSx7ImhleCI6IjAyMDAwMDAwMDAwMTAxNzNmMTcwMDkyMDA1MTBlZjYxZDg2NzY3ODhlYzQ4YWMzMWNiMGM2Njg0Nzc0OTA0MWIzNDc4YzMyOTg2MTliOTAxMDAwMDAwMDBmZmZmZmZmZjAzOWNkZDAyMDAwMDAwMDAwMDE2MDAxNGMxOTM2YTRkZjM0OTZjNGY4ZTk5NWQ4NWNkMjNhMjJiMGUzYjBhYzY3OWNmMTAwMDAwMDAwMDAwMTYwMDE0N2I2ZDI1Nzg3ZDgwYmE4ZjY1OTU3OTZjYjViNDIyNThmODk4ZmMwZGE0Y2YxMDAwMDAwMDAwMDAyMjUxMjBkMmYyYzVjOGYzZDk3ZTVmNjRiZjE0MDU2MmVkNzVkMGMyOGMyZTU2MjRjMTI5ODQzYzhlOTc5NzZhNDgyNjg3MDI0NzMwNDQwMjIwNTA3NTU3M2FjOTFmNzFjMjE4ZGRkZTIxZjE4OTRmYTIwNzJkYWNkMDQ5NzFjZTMzZDhjYjBhNjk2MzA3M2JjNzAyMjAyMTBkMzI0NjdjMzkyMTllZWUxZTllOTMwYzAyZjQ0N2RiMTFiNDhhNzEzOWMyMDEzN2FjYWFlYzRhMjE2ZTllMDEyMTAzNTc3MDBkZTNmNjhmNGNkYWFjMDgzYTAzNTZjMTdiY2U3NTI4NWM2MWY4NjJlZTJkYWY5ODA5ZDBhZDM4OTZmMzAwMDAwMDAwIiwidHhpZCI6IjkzNzRmNWNlODgxZGJlMmY4ZjViZWNkOWM1NTE2ZDM5ZGI4OTM0YmExNzU5NTE3Y2M0MWQ0ODVmNDY3OWNmZDkiLCJoYXNoIjoiZDhmN2VkZWE0MGExYjczMzdlYmNlNTJlMzUzNGMzZmZjNDVhNTk0NmVmZTYzYjFkNTEyNjQ0OGExMTcyZmZhYyIsInNpemUiOjI2NSwidnNpemUiOjE4NCwid2VpZ2h0Ijo3MzMsInZlcnNpb24iOjIsImxvY2t0aW1lIjowLCJ2aW4iOlt7InR4aWQiOiJiOTE5ODYyOWMzNzgzNDFiMDQ0OTc3ODQ2NjBjY2IzMWFjNDhlYzg4Njc2N2Q4NjFlZjEwMDUyMDA5NzBmMTczIiwidm91dCI6MSwic2NyaXB0U2lnIjp7ImFzbSI6IiIsImhleCI6IiJ9LCJ0eGlud2l0bmVzcyI6WyIzMDQ0MDIyMDUwNzU1NzNhYzkxZjcxYzIxOGRkZGUyMWYxODk0ZmEyMDcyZGFjZDA0OTcxY2UzM2Q4Y2IwYTY5NjMwNzNiYzcwMjIwMjEwZDMyNDY3YzM5MjE5ZWVlMWU5ZTkzMGMwMmY0NDdkYjExYjQ4YTcxMzljMjAxMzdhY2FhZWM0YTIxNmU5ZTAxIiwiMDM1NzcwMGRlM2Y2OGY0Y2RhYWMwODNhMDM1NmMxN2JjZTc1Mjg1YzYxZjg2MmVlMmRhZjk4MDlkMGFkMzg5NmYzIl0sInNlcXVlbmNlIjo0Mjk0OTY3Mjk1fV0sInZvdXQiOlt7InZhbHVlIjowLjAwMTg3ODA0LCJuIjowLCJzY3JpcHRQdWJLZXkiOnsiYXNtIjoiMCBjMTkzNmE0ZGYzNDk2YzRmOGU5OTVkODVjZDIzYTIyYjBlM2IwYWM2IiwiaGV4IjoiMDAxNGMxOTM2YTRkZjM0OTZjNGY4ZTk5NWQ4NWNkMjNhMjJiMGUzYjBhYzYiLCJ0eXBlIjoid2l0bmVzc192MF9rZXloYXNoIn19LHsidmFsdWUiOjAuMDExMDE2ODksIm4iOjEsInNjcmlwdFB1YktleSI6eyJhc20iOiIwIDdiNmQyNTc4N2Q4MGJhOGY2NTk1Nzk2Y2I1YjQyMjU4Zjg5OGZjMGQiLCJoZXgiOiIwMDE0N2I2ZDI1Nzg3ZDgwYmE4ZjY1OTU3OTZjYjViNDIyNThmODk4ZmMwZCIsInR5cGUiOiJ3aXRuZXNzX3YwX2tleWhhc2gifX0seyJ2YWx1ZSI6MC4wMTEwMTczMiwibiI6Miwic2NyaXB0UHViS2V5Ijp7ImFzbSI6IjEgZDJmMmM1YzhmM2Q5N2U1ZjY0YmYxNDA1NjJlZDc1ZDBjMjhjMmU1NjI0YzEyOTg0M2M4ZTk3OTc2YTQ4MjY4NyIsImhleCI6IjUxMjBkMmYyYzVjOGYzZDk3ZTVmNjRiZjE0MDU2MmVkNzVkMGMyOGMyZTU2MjRjMTI5ODQzYzhlOTc5NzZhNDgyNjg3IiwidHlwZSI6IndpdG5lc3NfdjFfdGFwcm9vdCJ9fV19LHsiaGV4IjoiMDIwMDAwMDAwMDAxMDFjYzEyYjEwYjViODhiNDcwODk4MzIyZjRmY2ViZjc0ZmU3ODM0YjVlYWNiYmUzZjE2NjVhMmUyNDIyYzhiNTI2MDAwMDAwMDAxNzE2MDAxNGRmOGYxNGNhMmZjNzYwY2ZhYjcyNDU2NWIxMmFmMDZiZmE3YTA5MGRmZmZmZmZmZjAyMDAzNTBjMDAwMDAwMDAwMDIyNTEyMDJkZTg1MjE0OGVkMzE2ODg1NTY0YzQ0NjJiZDBmZDAwNjY2ZDNlMDc5ZDg1MjAxOWU0MWY5MDIxMjA4NzhkZDVmZWQ4MDMwMDAwMDAwMDAwMTdhOTE0ZDJmZTM3NDFiYTZiMDY4ZGZhZjRhNDcyZGYxY2QyMjU0ODljZjU3OTg3MDI0NzMwNDQwMjIwNTZjMzlkYzdkZjNiMzdlODdlYTVjYTIxMWQxMjExY2VlNWU4MDcxNDllMzVmNjYzZDMyYzkxOTU5ZTAxN2QzMDAyMjA0NTUxZWEwZTRmNGI2ZDRiNmIwODBlZTIyYWM3MWQ4OThlOWUxNjZiMDI5MjlmY2I0ZTc3MWIxZWVkZDM0OTExMDEyMTAyMzBhMTU3MTQ4YTM0ZjI4NmQ0YTU4MTgyMTllYjIzMDgzNjIwNWNiZTEzZDE5MDEwMThkYWM5YTRlNTI5NDU2YzAwMDAwMDAwIiwidHhpZCI6IjI4YjZjYmYzZjdhM2M4ODA4OGRiMjg5ODc5ODk4NTE4ZDc5NWJkZjYzZWM2ODhhNjA2NDk2MTljMDk3MjUyY2QiLCJoYXNoIjoiYzdiNzRhYWQ5Y2FhYzI2ZWQ0YWU3MDk4ZmQ0NzE1ZTZiOWU3YmU1NGI3Mjk4NWZhYTRiYTJlZmY1NGQ5YzA3YyIsInNpemUiOjI1OCwidnNpemUiOjE3Nywid2VpZ2h0Ijo3MDUsInZlcnNpb24iOjIsImxvY2t0aW1lIjowLCJ2aW4iOlt7InR4aWQiOiIyNmI1YzgyMjI0MmU1YTY2ZjFlM2JiYWM1ZTRiODNlNzRmZjdlYmZjZjQyMjgzODk3MGI0ODg1YjBiYjExMmNjIiwidm91dCI6MCwic2NyaXB0U2lnIjp7ImFzbSI6IjAwMTRkZjhmMTRjYTJmYzc2MGNmYWI3MjQ1NjViMTJhZjA2YmZhN2EwOTBkIiwiaGV4IjoiMTYwMDE0ZGY4ZjE0Y2EyZmM3NjBjZmFiNzI0NTY1YjEyYWYwNmJmYTdhMDkwZCJ9LCJ0eGlud2l0bmVzcyI6WyIzMDQ0MDIyMDU2YzM5ZGM3ZGYzYjM3ZTg3ZWE1Y2EyMTFkMTIxMWNlZTVlODA3MTQ5ZTM1ZjY2M2QzMmM5MTk1OWUwMTdkMzAwMjIwNDU1MWVhMGU0ZjRiNmQ0YjZiMDgwZWUyMmFjNzFkODk4ZTllMTY2YjAyOTI5ZmNiNGU3NzFiMWVlZGQzNDkxMTAxIiwiMDIzMGExNTcxNDhhMzRmMjg2ZDRhNTgxODIxOWViMjMwODM2MjA1Y2JlMTNkMTkwMTAxOGRhYzlhNGU1Mjk0NTZjIl0sInNlcXVlbmNlIjo0Mjk0OTY3Mjk1fV0sInZvdXQiOlt7InZhbHVlIjowLjAwOCwibiI6MCwic2NyaXB0UHViS2V5Ijp7ImFzbSI6IjEgMmRlODUyMTQ4ZWQzMTY4ODU1NjRjNDQ2MmJkMGZkMDA2NjZkM2UwNzlkODUyMDE5ZTQxZjkwMjEyMDg3OGRkNSIsImhleCI6IjUxMjAyZGU4NTIxNDhlZDMxNjg4NTU2NGM0NDYyYmQwZmQwMDY2NmQzZTA3OWQ4NTIwMTllNDFmOTAyMTIwODc4ZGQ1IiwidHlwZSI6IndpdG5lc3NfdjFfdGFwcm9vdCJ9fSx7InZhbHVlIjowLjAwMjUyMTU4LCJuIjoxLCJzY3JpcHRQdWJLZXkiOnsiYXNtIjoiT1BfSEFTSDE2MCBkMmZlMzc0MWJhNmIwNjhkZmFmNGE0NzJkZjFjZDIyNTQ4OWNmNTc5IE9QX0VRVUFMIiwiaGV4IjoiYTkxNGQyZmUzNzQxYmE2YjA2OGRmYWY0YTQ3MmRmMWNkMjI1NDg5Y2Y1Nzk4NyIsInR5cGUiOiJzY3JpcHRoYXNoIn19XX0seyJoZXgiOiIwMjAwMDAwMDAwMDEwMWNkNTI3MjA5OWM2MTQ5MDZhNjg4YzYzZWY2YmQ5NWQ3MTg4NTg5Nzk5ODI4ZGI4ODgwYzhhM2Y3ZjNjYmI2MjgwMDAwMDAwMDAwZmZmZmZmZmYwMjYwZTQwMTAwMDAwMDAwMDAyMjUxMjA4NmE3YzllMzM0ODJhNzVhMjI5ODhmZjI0OTFhYTA5OTdhZDY0MTMyOTAzN2ZhYmFiNTFkNTVhNDc2ZWIyNzkwMDQ1MDBhMDAwMDAwMDAwMDIyNTEyMDJkZTg1MjE0OGVkMzE2ODg1NTY0YzQ0NjJiZDBmZDAwNjY2ZDNlMDc5ZDg1MjAxOWU0MWY5MDIxMjA4NzhkZDUwMTQwMzEzZmRiMjA2ODFlNGU1MWYxY2NiOGFlM2MxMzFjMTIzMTg3ZmYxNjVmM2UyYTgyOTI5ZDhmZGMxODZmNDYzNDNhY2ViNDdmNzYwYzIwMDc1YjE3N2UyNDA2YmI3NzBiNjFiZWNhZmI1ZGFiYTZhOGY3NzE5ODcxMjk2Yjg5NTYwMDAwMDAwMCIsInR4aWQiOiIzZmVjMTY0ZDAyM2RiYmNkNDE0MDc4YWZkMGJiYThhZTAxMWEwNmQ1ZThmNjM0NDU1Y2JlYWQ4NmFhZDMzOWVlIiwiaGFzaCI6IjdlMDYxYmFmMGI1Njg5ZjU0NTYzZGI1YTkyMjM1ZjEzMzdiODAzZTY3MTdkOTljODQyNDU1MTlhNWI2ZDJkYTAiLCJzaXplIjoyMDUsInZzaXplIjoxNTQsIndlaWdodCI6NjE2LCJ2ZXJzaW9uIjoyLCJsb2NrdGltZSI6MCwidmluIjpbeyJ0eGlkIjoiMjhiNmNiZjNmN2EzYzg4MDg4ZGIyODk4Nzk4OTg1MThkNzk1YmRmNjNlYzY4OGE2MDY0OTYxOWMwOTcyNTJjZCIsInZvdXQiOjAsInNjcmlwdFNpZyI6eyJhc20iOiIiLCJoZXgiOiIifSwidHhpbndpdG5lc3MiOlsiMzEzZmRiMjA2ODFlNGU1MWYxY2NiOGFlM2MxMzFjMTIzMTg3ZmYxNjVmM2UyYTgyOTI5ZDhmZGMxODZmNDYzNDNhY2ViNDdmNzYwYzIwMDc1YjE3N2UyNDA2YmI3NzBiNjFiZWNhZmI1ZGFiYTZhOGY3NzE5ODcxMjk2Yjg5NTYiXSwic2VxdWVuY2UiOjQyOTQ5NjcyOTV9XSwidm91dCI6W3sidmFsdWUiOjAuMDAxMjQsIm4iOjAsInNjcmlwdFB1YktleSI6eyJhc20iOiIxIDg2YTdjOWUzMzQ4MmE3NWEyMjk4OGZmMjQ5MWFhMDk5N2FkNjQxMzI5MDM3ZmFiYWI1MWQ1NWE0NzZlYjI3OTAiLCJoZXgiOiI1MTIwODZhN2M5ZTMzNDgyYTc1YTIyOTg4ZmYyNDkxYWEwOTk3YWQ2NDEzMjkwMzdmYWJhYjUxZDU1YTQ3NmViMjc5MCIsInR5cGUiOiJ3aXRuZXNzX3YxX3RhcHJvb3QifX0seyJ2YWx1ZSI6MC4wMDY3NTg0NCwibiI6MSwic2NyaXB0UHViS2V5Ijp7ImFzbSI6IjEgMmRlODUyMTQ4ZWQzMTY4ODU1NjRjNDQ2MmJkMGZkMDA2NjZkM2UwNzlkODUyMDE5ZTQxZjkwMjEyMDg3OGRkNSIsImhleCI6IjUxMjAyZGU4NTIxNDhlZDMxNjg4NTU2NGM0NDYyYmQwZmQwMDY2NmQzZTA3OWQ4NTIwMTllNDFmOTAyMTIwODc4ZGQ1IiwidHlwZSI6IndpdG5lc3NfdjFfdGFwcm9vdCJ9fV19LHsiaGV4IjoiMDEwMDAwMDAwMDAxMDFiODZhZTUzYzllNWYyNGQyZTZkYmJiNDBiNzkzNGMzNGM5MTM4Mjg4MDIzZmQ4ZTk2NTIzM2Y2NjA0YmFmYzdkMDAwMDAwMDAwMGZmZmZmZmZmMDJjYTk1MDAwMDAwMDAwMDAwMTYwMDE0Mzk1YzVmZTJkN2I0OGI4ODFkMGIwMzExNDk5NzhjOGNhNzVjNTJkODM4NTRmNTAyMDAwMDAwMDAxNjAwMTQyYWZiYmU5ZmFlYzllYjJmNGVhZjVmN2NlZWQyNWUzZjc1OGZhZWE5MDI0ODMwNDUwMjIxMDBlM2Q1YjMwYzUzOGZiMThhMzExMzE0ZGIyNWMxM2NiYmFjZDgwOWI4MWM2MTIwMzkzM2RmMGVjYjljZmVkYmUxMDIyMDBhZmVlNGY2ODdjODY5YTY1NjgyNGRjMTE1MjUzZmY2MmI2ODg4ZjBkM2EyYmE4MWZhN2U5MmFkZjY3ZDY5N2MwMTIxMDIwYzg0YmIyNTQ0MzE3NDdiZWMzZWQ0Yzc1NDIwYzY5ZTUzNjYyMTAxMGY4NjdhMzI1NDI2MGZlMzU2YmRlZDJhMDAwMDAwMDAiLCJ0eGlkIjoiNWMyN2UxODUzNjkwMzFjZDBlNjIxM2ZiZjE3YTA5Y2QzYzFiNjlmOTc3Y2YxY2E1YmIzMzIxMTJjMWEyZjAyMSIsImhhc2giOiI2NWUzMTZjODNjZTBjNWQzYjI0YWRkYWY2YTYzODkxNGNiNzE5ZTZmZGU4ZWYzNDI5MjE3OTY4NDk0ZmFhNGI3Iiwic2l6ZSI6MjIzLCJ2c2l6ZSI6MTQxLCJ3ZWlnaHQiOjU2MiwidmVyc2lvbiI6MSwibG9ja3RpbWUiOjAsInZpbiI6W3sidHhpZCI6IjdkZmNiYTA0NjYzZjIzNjVlOWQ4M2YwMjg4ODIxM2M5MzQ0YzkzYjc0MGJiZGJlNmQyMjQ1ZjllM2NlNTZhYjgiLCJ2b3V0IjowLCJzY3JpcHRTaWciOnsiYXNtIjoiIiwiaGV4IjoiIn0sInR4aW53aXRuZXNzIjpbIjMwNDUwMjIxMDBlM2Q1YjMwYzUzOGZiMThhMzExMzE0ZGIyNWMxM2NiYmFjZDgwOWI4MWM2MTIwMzkzM2RmMGVjYjljZmVkYmUxMDIyMDBhZmVlNGY2ODdjODY5YTY1NjgyNGRjMTE1MjUzZmY2MmI2ODg4ZjBkM2EyYmE4MWZhN2U5MmFkZjY3ZDY5N2MwMSIsIjAyMGM4NGJiMjU0NDMxNzQ3YmVjM2VkNGM3NTQyMGM2OWU1MzY2MjEwMTBmODY3YTMyNTQyNjBmZTM1NmJkZWQyYSJdLCJzZXF1ZW5jZSI6NDI5NDk2NzI5NX1dLCJ2b3V0IjpbeyJ2YWx1ZSI6MC4wMDAzODM0NiwibiI6MCwic2NyaXB0UHViS2V5Ijp7ImFzbSI6IjAgMzk1YzVmZTJkN2I0OGI4ODFkMGIwMzExNDk5NzhjOGNhNzVjNTJkOCIsImhleCI6IjAwMTQzOTVjNWZlMmQ3YjQ4Yjg4MWQwYjAzMTE0OTk3OGM4Y2E3NWM1MmQ4IiwidHlwZSI6IndpdG5lc3NfdjBfa2V5aGFzaCJ9fSx7InZhbHVlIjowLjQ5NjMyMzEyLCJuIjoxLCJzY3JpcHRQdWJLZXkiOnsiYXNtIjoiMCAyYWZiYmU5ZmFlYzllYjJmNGVhZjVmN2NlZWQyNWUzZjc1OGZhZWE5IiwiaGV4IjoiMDAxNDJhZmJiZTlmYWVjOWViMmY0ZWFmNWY3Y2VlZDI1ZTNmNzU4ZmFlYTkiLCJ0eXBlIjoid2l0bmVzc192MF9rZXloYXNoIn19XX0seyJoZXgiOiIwMTAwMDAwMDAwMDEwMTVlOTQyYjQ1MjYwNTQ5MDkyYjQ2NTQyOTI1NDljYjEzOTg5ZGRkZjJhNjhhNGE2NTVjZTU5YTUxNjYyNmI2MDEwMTAwMDAwMDAwZmZmZmZmZmYwMmM2OTUwMDAwMDAwMDAwMDAxNjAwMTQzYmUyYTViODYyMGNhYTI2NWI5NGU4OGU5ODIxNzE1Yzc1MmExMjMxNjg2MGFkMDUwMDAwMDAwMDE2MDAxNDEyYjFlYjEzYjllNThkM2NlMDI3ZTllYmI3OGIxZTBmYTc3MTk0OTcwMjQ3MzA0NDAyMjA0ZTg5ZGI0MTNiMWY1M2M2ODc2N2YzOTkzOTVjYzVlMDU2MWQ2ZDk4YWQ5MTNhZTBiNDlkMjE2ODhmNGIyZDUwMDIyMDdkZDI3NTZlNmYyMWQzMzA4NjdmYWRlZTFjZWE5Njk3OGQwNmE0ZjgyZDZhYzlmNjhiZDZmYzg3ZWJhNWIyZjUwMTIxMDNhYmI5MWFjNWJjMDJjMGM5NWIzZGE5MGZjOWYzZDgyZjYwODdjMmI3ZDAwODY1YzQ2ZGYzYTQ4MmQ0OTIzMzg1MDAwMDAwMDAiLCJ0eGlkIjoiMzQ1ZjY2OTMwODhmNmRmZmQzYjI3NmNlOTJkNjc0Mzc2Y2UzNDczYzY1ZGNlZDc3NWNmODc3ODdhZDFkMmJhMCIsImhhc2giOiIxYzZjYzhmZjQ4OTUxMWMzMWExYzIzY2JiYWI0NjU0ZTZkYjdkYTFhNWFmNTNlZmU1ZTY4NTczNjUyYWFiODhmIiwic2l6ZSI6MjIyLCJ2c2l6ZSI6MTQxLCJ3ZWlnaHQiOjU2MSwidmVyc2lvbiI6MSwibG9ja3RpbWUiOjAsInZpbiI6W3sidHhpZCI6IjAxYjYyNjY2NTE5YWU1NWM2NTRhOGFhNmYyZGQ5ZDk4MTNjYjQ5MjUyOTU0NDYyYjA5NDkwNTI2NDUyYjk0NWUiLCJ2b3V0IjoxLCJzY3JpcHRTaWciOnsiYXNtIjoiIiwiaGV4IjoiIn0sInR4aW53aXRuZXNzIjpbIjMwNDQwMjIwNGU4OWRiNDEzYjFmNTNjNjg3NjdmMzk5Mzk1Y2M1ZTA1NjFkNmQ5OGFkOTEzYWUwYjQ5ZDIxNjg4ZjRiMmQ1MDAyMjA3ZGQyNzU2ZTZmMjFkMzMwODY3ZmFkZWUxY2VhOTY5NzhkMDZhNGY4MmQ2YWM5ZjY4YmQ2ZmM4N2ViYTViMmY1MDEiLCIwM2FiYjkxYWM1YmMwMmMwYzk1YjNkYTkwZmM5ZjNkODJmNjA4N2MyYjdkMDA4NjVjNDZkZjNhNDgyZDQ5MjMzODUiXSwic2VxdWVuY2UiOjQyOTQ5NjcyOTV9XSwidm91dCI6W3sidmFsdWUiOjAuMDAwMzgzNDIsIm4iOjAsInNjcmlwdFB1YktleSI6eyJhc20iOiIwIDNiZTJhNWI4NjIwY2FhMjY1Yjk0ZTg4ZTk4MjE3MTVjNzUyYTEyMzEiLCJoZXgiOiIwMDE0M2JlMmE1Yjg2MjBjYWEyNjViOTRlODhlOTgyMTcxNWM3NTJhMTIzMSIsInR5cGUiOiJ3aXRuZXNzX3YwX2tleWhhc2gifX0seyJ2YWx1ZSI6MC45NTI0ODQ4OCwibiI6MSwic2NyaXB0UHViS2V5Ijp7ImFzbSI6IjAgMTJiMWViMTNiOWU1OGQzY2UwMjdlOWViYjc4YjFlMGZhNzcxOTQ5NyIsImhleCI6IjAwMTQxMmIxZWIxM2I5ZTU4ZDNjZTAyN2U5ZWJiNzhiMWUwZmE3NzE5NDk3IiwidHlwZSI6IndpdG5lc3NfdjBfa2V5aGFzaCJ9fV19LHsiaGV4IjoiMDEwMDAwMDAwMDAxMDE1OThlZmI2ZGY3YWYzNDM4YjY0NDk5NTRmODNiZTg0NzE3ZjA4NDdkMDNiMDI0YzJmZjMyNThjYWM0ZWQ5MjJkMDAwMDAwMDAwMGZmZmZmZmZmMDJkZmI4M2EwNDAwMDAwMDAwMTYwMDE0NmZlYmY0MDYzNmUwM2EyYzBkOGY2ZmNmOGNhMGY4ODk1MzI2ZDIyNzEwMjcwMDAwMDAwMDAwMDAxNjAwMTQ3Njc2MDZmMTQ5MjQ4MDBmNWI0NmI3OWQwM2IyYjMxNTk0ZDk1N2U5MDI0ODMwNDUwMjIxMDBmNWI2MmI4MGYwYTc3ZjM2OWNkZGViNDgzODkyMTA5NjA4ZDkwZWJkYTRiYmEzNTUyNGMzOTJlYzY0N2MxNDlmMDIyMDE1Y2JhZmFjN2ZiY2M4NWEzNDk2YWExMDRiOTg0NzA4MmQ5YTJlNTIzODcxZDVhYTZjZWNjZDhmOGI4YjdlNmYwMTIxMDIxYjNmZTgwZWQ5MTAxYzAwZDk1NzFjOGMxYWI4N2NlNzhmMTU3NDAyNmIyNTk5OTU1ODQ4ZmE0NzBkOWI1ZWZiMDAwMDAwMDAiLCJ0eGlkIjoiNTM2NjExMmIxZGI1Mzc1YzNjMjkyMDkxMDM0ZWFmM2Q3YjhjNmIxZGIyYzFhZjI1ZTQ3NjkzZjIyY2EyYzhhOCIsImhhc2giOiI2YjkwZDAwMzEyODc3YmVmNDc2MTlhNzYyYzM4NzRkMmVmZmQ1OTcxZTc3OWMwZGRkZmIyMjg1MjA5YjU3ZDFkIiwic2l6ZSI6MjIzLCJ2c2l6ZSI6MTQxLCJ3ZWlnaHQiOjU2MiwidmVyc2lvbiI6MSwibG9ja3RpbWUiOjAsInZpbiI6W3sidHhpZCI6IjJkOTJlZGM0Y2E1ODMyZmZjMjI0YjAwMzdkODRmMDE3NDdlODNiZjg1NDk5NDRiNjM4MzRhZmY3NmRmYjhlNTkiLCJ2b3V0IjowLCJzY3JpcHRTaWciOnsiYXNtIjoiIiwiaGV4IjoiIn0sInR4aW53aXRuZXNzIjpbIjMwNDUwMjIxMDBmNWI2MmI4MGYwYTc3ZjM2OWNkZGViNDgzODkyMTA5NjA4ZDkwZWJkYTRiYmEzNTUyNGMzOTJlYzY0N2MxNDlmMDIyMDE1Y2JhZmFjN2ZiY2M4NWEzNDk2YWExMDRiOTg0NzA4MmQ5YTJlNTIzODcxZDVhYTZjZWNjZDhmOGI4YjdlNmYwMSIsIjAyMWIzZmU4MGVkOTEwMWMwMGQ5NTcxYzhjMWFiODdjZTc4ZjE1NzQwMjZiMjU5OTk1NTg0OGZhNDcwZDliNWVmYiJdLCJzZXF1ZW5jZSI6NDI5NDk2NzI5NX1dLCJ2b3V0IjpbeyJ2YWx1ZSI6MC43MDk1NzI3OSwibiI6MCwic2NyaXB0UHViS2V5Ijp7ImFzbSI6IjAgNmZlYmY0MDYzNmUwM2EyYzBkOGY2ZmNmOGNhMGY4ODk1MzI2ZDIyNyIsImhleCI6IjAwMTQ2ZmViZjQwNjM2ZTAzYTJjMGQ4ZjZmY2Y4Y2EwZjg4OTUzMjZkMjI3IiwidHlwZSI6IndpdG5lc3NfdjBfa2V5aGFzaCJ9fSx7InZhbHVlIjowLjAwMDEsIm4iOjEsInNjcmlwdFB1YktleSI6eyJhc20iOiIwIDc2NzYwNmYxNDkyNDgwMGY1YjQ2Yjc5ZDAzYjJiMzE1OTRkOTU3ZTkiLCJoZXgiOiIwMDE0NzY3NjA2ZjE0OTI0ODAwZjViNDZiNzlkMDNiMmIzMTU5NGQ5NTdlOSIsInR5cGUiOiJ3aXRuZXNzX3YwX2tleWhhc2gifX1dfSx7ImhleCI6IjAxMDAwMDAwMDAwMTAxYjQ1Nzc3ZDNlZWIyOTdhYjM4NzU3OTU4NTQ0ZjUwOTgzZTcyMDJjYjRlYThkNGQ2NTk1MWQ0ZjFkZjZiNTU0NzAwMDAwMDAwMDBmZmZmZmZmZjAyY2E5NTAwMDAwMDAwMDAwMDE2MDAxNDgyMDQ2NGEzODIyZTI0Yjc0MzBjZTM2NWQyMzE1MWMyY2ViZWYzZGU0NDMzZjUwMjAwMDAwMDAwMTYwMDE0ZmJjY2Q2MTVjM2ZiZjE0YzZlN2M3MjhlZTQ1NWE4M2QwODM0NmMyMzAyNDczMDQ0MDIyMDAwYWEzM2U2NThiYTFkMTljZGE5ZjZhNDIyZTNlNjEzZmVmZDVlNDAzNDAwNGVkOWI3Y2UwNGYyNGNmYzAyZjIwMjIwNDNkNTYxNWZjYmJmMTNhOGIzZmY3ZjI2ZDg4MmIzNjBhNTY0MzgyOTVlNjQ1NTg4ZDA0Mjk4MDY4YTI4ZGU4ZjAxMjEwMjg5Y2IzM2JhNzBjNGI0NDdlOWY2NWYwODc5Y2MwZjRlOTU3NGMxNzlmYzU3MWVlOWRjZTNiOTA1YzM3ZWIxOTIwMDAwMDAwMCIsInR4aWQiOiJmYWU5MjQ3NGNkMjY0ZDA0NDAxMDZkOTY5ZTc5ZDIzOTQ5ZTMyNjBlNTg1ZDM5MjQzM2JhMzYzNmEyZDY1MmQ4IiwiaGFzaCI6Ijk3YmMzMWUwMjFmM2ZkMWRiZDZmZDlmMDMyOGQ5M2FkNWU1YTQ4OGMzZWM3YjNmNzhiOTc0NzkzOWUwNDExMDIiLCJzaXplIjoyMjIsInZzaXplIjoxNDEsIndlaWdodCI6NTYxLCJ2ZXJzaW9uIjoxLCJsb2NrdGltZSI6MCwidmluIjpbeyJ0eGlkIjoiNDc1NTZiZGZmMWQ0NTE1OWQ2ZDRhODRlY2IwMjcyM2U5ODUwNGY1NDU4Nzk3NTM4YWI5N2IyZWVkMzc3NTdiNCIsInZvdXQiOjAsInNjcmlwdFNpZyI6eyJhc20iOiIiLCJoZXgiOiIifSwidHhpbndpdG5lc3MiOlsiMzA0NDAyMjAwMGFhMzNlNjU4YmExZDE5Y2RhOWY2YTQyMmUzZTYxM2ZlZmQ1ZTQwMzQwMDRlZDliN2NlMDRmMjRjZmMwMmYyMDIyMDQzZDU2MTVmY2JiZjEzYThiM2ZmN2YyNmQ4ODJiMzYwYTU2NDM4Mjk1ZTY0NTU4OGQwNDI5ODA2OGEyOGRlOGYwMSIsIjAyODljYjMzYmE3MGM0YjQ0N2U5ZjY1ZjA4NzljYzBmNGU5NTc0YzE3OWZjNTcxZWU5ZGNlM2I5MDVjMzdlYjE5MiJdLCJzZXF1ZW5jZSI6NDI5NDk2NzI5NX1dLCJ2b3V0IjpbeyJ2YWx1ZSI6MC4wMDAzODM0NiwibiI6MCwic2NyaXB0UHViS2V5Ijp7ImFzbSI6IjAgODIwNDY0YTM4MjJlMjRiNzQzMGNlMzY1ZDIzMTUxYzJjZWJlZjNkZSIsImhleCI6IjAwMTQ4MjA0NjRhMzgyMmUyNGI3NDMwY2UzNjVkMjMxNTFjMmNlYmVmM2RlIiwidHlwZSI6IndpdG5lc3NfdjBfa2V5aGFzaCJ9fSx7InZhbHVlIjowLjQ5NjIzODc2LCJuIjoxLCJzY3JpcHRQdWJLZXkiOnsiYXNtIjoiMCBmYmNjZDYxNWMzZmJmMTRjNmU3YzcyOGVlNDU1YTgzZDA4MzQ2YzIzIiwiaGV4IjoiMDAxNGZiY2NkNjE1YzNmYmYxNGM2ZTdjNzI4ZWU0NTVhODNkMDgzNDZjMjMiLCJ0eXBlIjoid2l0bmVzc192MF9rZXloYXNoIn19XX0seyJoZXgiOiIwMTAwMDAwMDAwMDEwMWQ4MzM5MGQxMzgwMGM5YmQ4OGUxYWVhMDUxMzViZWJhNjlmMjdkYjI0ZDc2YWJkMjE1MjcwMWMwNTUxZjNmZjQwMTAwMDAwMDAwZmZmZmZmZmYwMjMwNzUwMDAwMDAwMDAwMDAxNjAwMTQ4YTEyMTdhZGEyZmEzYTQ0Nzg1NDUzMWE4YzViZjRmMTg1YjIwNzIyNmNkMDc5MDAwMDAwMDAwMDE2MDAxNGFjYzM3MjVkMjkyY2M5ZDVkMWJiNjY4MDQyYzBiM2UwZmNlYzFkMTQwMjQ3MzA0NDAyMjA2MWVhOTAwNDYyN2E3M2IxZjViMWE2OTc1MzA1MDkzNjg3NzRmNTFmNjQ1MDUxZThmYTRlOWRiZWQxMjY5NjM3MDIyMDBiYTg5NTA4NDNhOGYzM2YzZDlhN2I2OTg4OThkODA2YzQ4YTE0ODExMzQzNmI3MmRmNjk4M2JjZmYwNmQxNTgwMTIxMDI1MGNhYmM5ZDQ0OTliYjQ4ODFhNGQwNWEyNmM4ZGVjNzNjZDBlNzkyZGI5N2U5YmUxN2JkNjg2ZmRjOTAzM2FkMDAwMDAwMDAiLCJ0eGlkIjoiODMzZDRjNGFjMWI4NjdhYzI3YWI1ZjViZjk0Y2UzNDMyZWZlN2E3NDEwZDQ5MjA5YTQ4YzMyMGM2MzNlZjdkZSIsImhhc2giOiIzN2MzMWE2MWY1NmRhM2E0M2FmYzljNjBhMjNhZWE5NjBiODc5ZjIwM2NmZjQxNjMxMWQ4MjU4MjFjMGJkOGI3Iiwic2l6ZSI6MjIyLCJ2c2l6ZSI6MTQxLCJ3ZWlnaHQiOjU2MSwidmVyc2lvbiI6MSwibG9ja3RpbWUiOjAsInZpbiI6W3sidHhpZCI6ImY0M2YxZjU1YzAwMTI3MTVkMmFiNzY0ZGIyN2RmMjY5YmFiZTM1NTFhMGFlZTE4OGJkYzkwMDM4ZDE5MDMzZDgiLCJ2b3V0IjoxLCJzY3JpcHRTaWciOnsiYXNtIjoiIiwiaGV4IjoiIn0sInR4aW53aXRuZXNzIjpbIjMwNDQwMjIwNjFlYTkwMDQ2MjdhNzNiMWY1YjFhNjk3NTMwNTA5MzY4Nzc0ZjUxZjY0NTA1MWU4ZmE0ZTlkYmVkMTI2OTYzNzAyMjAwYmE4OTUwODQzYThmMzNmM2Q5YTdiNjk4ODk4ZDgwNmM0OGExNDgxMTM0MzZiNzJkZjY5ODNiY2ZmMDZkMTU4MDEiLCIwMjUwY2FiYzlkNDQ5OWJiNDg4MWE0ZDA1YTI2YzhkZWM3M2NkMGU3OTJkYjk3ZTliZTE3YmQ2ODZmZGM5MDMzYWQiXSwic2VxdWVuY2UiOjQyOTQ5NjcyOTV9XSwidm91dCI6W3sidmFsdWUiOjAuMDAwMywibiI6MCwic2NyaXB0UHViS2V5Ijp7ImFzbSI6IjAgOGExMjE3YWRhMmZhM2E0NDc4NTQ1MzFhOGM1YmY0ZjE4NWIyMDcyMiIsImhleCI6IjAwMTQ4YTEyMTdhZGEyZmEzYTQ0Nzg1NDUzMWE4YzViZjRmMTg1YjIwNzIyIiwidHlwZSI6IndpdG5lc3NfdjBfa2V5aGFzaCJ9fSx7InZhbHVlIjowLjA3OTgzMjEyLCJuIjoxLCJzY3JpcHRQdWJLZXkiOnsiYXNtIjoiMCBhY2MzNzI1ZDI5MmNjOWQ1ZDFiYjY2ODA0MmMwYjNlMGZjZWMxZDE0IiwiaGV4IjoiMDAxNGFjYzM3MjVkMjkyY2M5ZDVkMWJiNjY4MDQyYzBiM2UwZmNlYzFkMTQiLCJ0eXBlIjoid2l0bmVzc192MF9rZXloYXNoIn19XX0seyJoZXgiOiIwMTAwMDAwMDAwMDEwMTJmMmRkODE5MTJmODg4MjhiZDE0ZTc5NzYzNzNjNTg2NWRkNDcwMDA0NWMyNWQ4MjA2YWE1M2FmMTM0ZWQ2MGEwMDAwMDAwMDAwZmZmZmZmZmYwMmM2OTUwMDAwMDAwMDAwMDAxNjAwMTQ4NTZkMzYyMjYyMmViYjE3M2Y4Yjk2Yzk2NGY4ODkyZDJhMjYyNTI2OGRlMDAwMDEwMDAwMDAwMDE2MDAxNGEyZTYwNjA5ZDg2MTdlMjZhYTk2MGQwMjI1NDJlOWVlNWZkNzJkMzQwMjQ3MzA0NDAyMjA1NzMyNmIzZDNiZTcwZTQwZmNlNzJmZTExODY5NmJlYWYzZTc1MjdhZGY4MjBkNzFlYzQ3MTJjZGExZjkwNThkMDIyMDFlMDBiM2YwM2RjOGEwY2NkY2FjNjQ0ZGJkYTBhNGE4OTEyZTQ3NzZkZjlhNjBmNmIzNDkzNDNjYzRkODY3ZmMwMTIxMDIyMDAzYTA1MzU2Y2IzOGI1NTFhNDhiNzhmZjU5YWY5NDFmNjg4YzYxZWNjZmQ5N2I1YWE0NjVkNjhmNGVlZTA5MDAwMDAwMDAiLCJ0eGlkIjoiMDEyNWUzMGIxY2RiNGEyNjNiYTdkYWZlN2NmYWM1YWQ3YTA3YjMwNDQyMjFkYmE1YmZjNDkzYTZlNTUxNzFmNyIsImhhc2giOiJhNWQxN2YzZThiNDBiNTg5Zjg2NTRkNTAyN2NiYzM0MTZmZDhlMzcyZGM2NTM4ZDA2ZWVmZDZhZWQzYWYxNTIzIiwic2l6ZSI6MjIyLCJ2c2l6ZSI6MTQxLCJ3ZWlnaHQiOjU2MSwidmVyc2lvbiI6MSwibG9ja3RpbWUiOjAsInZpbiI6W3sidHhpZCI6IjBhZDY0ZTEzYWY1M2FhMDY4MjVkYzI0NTAwNzBkNDVkODZjNTczNjM5N2U3MTRiZDI4ODhmODEyMTlkODJkMmYiLCJ2b3V0IjowLCJzY3JpcHRTaWciOnsiYXNtIjoiIiwiaGV4IjoiIn0sInR4aW53aXRuZXNzIjpbIjMwNDQwMjIwNTczMjZiM2QzYmU3MGU0MGZjZTcyZmUxMTg2OTZiZWFmM2U3NTI3YWRmODIwZDcxZWM0NzEyY2RhMWY5MDU4ZDAyMjAxZTAwYjNmMDNkYzhhMGNjZGNhYzY0NGRiZGEwYTRhODkxMmU0Nzc2ZGY5YTYwZjZiMzQ5MzQzY2M0ZDg2N2ZjMDEiLCIwMjIwMDNhMDUzNTZjYjM4YjU1MWE0OGI3OGZmNTlhZjk0MWY2ODhjNjFlY2NmZDk3YjVhYTQ2NWQ2OGY0ZWVlMDkiXSwic2VxdWVuY2UiOjQyOTQ5NjcyOTV9XSwidm91dCI6W3sidmFsdWUiOjAuMDAwMzgzNDIsIm4iOjAsInNjcmlwdFB1YktleSI6eyJhc20iOiIwIDg1NmQzNjIyNjIyZWJiMTczZjhiOTZjOTY0Zjg4OTJkMmEyNjI1MjYiLCJoZXgiOiIwMDE0ODU2ZDM2MjI2MjJlYmIxNzNmOGI5NmM5NjRmODg5MmQyYTI2MjUyNiIsInR5cGUiOiJ3aXRuZXNzX3YwX2tleWhhc2gifX0seyJ2YWx1ZSI6MC4xNjgzNDcwMSwibiI6MSwic2NyaXB0UHViS2V5Ijp7ImFzbSI6IjAgYTJlNjA2MDlkODYxN2UyNmFhOTYwZDAyMjU0MmU5ZWU1ZmQ3MmQzNCIsImhleCI6IjAwMTRhMmU2MDYwOWQ4NjE3ZTI2YWE5NjBkMDIyNTQyZTllZTVmZDcyZDM0IiwidHlwZSI6IndpdG5lc3NfdjBfa2V5aGFzaCJ9fV19LHsiaGV4IjoiMDIwMDAwMDAwMDAxMDE4ZDBlYjM0M2ExZjRkYTk2ZDc2ZGE2NTE1Y2Q5MjdlNjZiY2MxNTM2MmZkYWY0YmZjZGNkNGE4OGM4N2ZkNjgzMDEwMDAwMDAwMGZmZmZmZmZmMDJkMDA3MDAwMDAwMDAwMDAwMjI1MTIwMTJiZmU4ZmQ0ZWU1NzUwNmI5ZDdiMjM5Y2I1ZmY0ZGEyY2QyMzZjMDg4MGY0YzdkMTA0ZDdmNGJmMjQxNDg5NTA2MWIwNTAwMDAwMDAwMDAxNjAwMTQyNjZiNWNiYTdlZmMyZWYyZGM5N2FlMWRlZjZjMzkzYmU0ZTM0ZTFmMDI0ODMwNDUwMjIxMDA4M2E1NGM0MzIyZDE0NTk4MjIzYmFmN2M3ODVkYmJiMzBjNWYxOWY3YjdiMjI2YTYzZjdkOGRhNGQ3MzM2N2JiMDIyMDUzYTEzY2RjNzI3OWQxYWNlZDI3NzU5NWQwYWE0NDkyMjE3MGU0ZmUwMTVlNjFiYzg3ZWJkMDE2ZmZiOTQyODQwMTIxMDM5MjA0OTBjOGNkY2NjYTY3M2RjMGU1YWYxN2JiYWM1NzI5NTMwNTFjYzcxOTNkYjBhNzE1ZGRlNzc5MjRiZjVjMDAwMDAwMDAiLCJ0eGlkIjoiN2JjNTM3NGM1YTIzYmUzNDE2Yzc3ZWViNDQ3YWFkMGZmNmQ1NzE3ODJkYTE2MTU4NWEwMDczM2ZiNTIzMWNjMCIsImhhc2giOiI4MzQ4YmJkMjhlZDUwNjBlYTMxNGE2ZmZhYWI2MmNiODMyYTRhOGNlNzgzMzMwNWY2YjlkY2ViOGFjZjYyZjE0Iiwic2l6ZSI6MjM1LCJ2c2l6ZSI6MTUzLCJ3ZWlnaHQiOjYxMCwidmVyc2lvbiI6MiwibG9ja3RpbWUiOjAsInZpbiI6W3sidHhpZCI6IjgzZDY3ZmM4ODg0YWNkY2RiZmY0ZGEyZjM2MTVjYzZiZTYyN2Q5NWM1MWE2NmRkNzk2ZGFmNGExNDNiMzBlOGQiLCJ2b3V0IjoxLCJzY3JpcHRTaWciOnsiYXNtIjoiIiwiaGV4IjoiIn0sInR4aW53aXRuZXNzIjpbIjMwNDUwMjIxMDA4M2E1NGM0MzIyZDE0NTk4MjIzYmFmN2M3ODVkYmJiMzBjNWYxOWY3YjdiMjI2YTYzZjdkOGRhNGQ3MzM2N2JiMDIyMDUzYTEzY2RjNzI3OWQxYWNlZDI3NzU5NWQwYWE0NDkyMjE3MGU0ZmUwMTVlNjFiYzg3ZWJkMDE2ZmZiOTQyODQwMSIsIjAzOTIwNDkwYzhjZGNjY2E2NzNkYzBlNWFmMTdiYmFjNTcyOTUzMDUxY2M3MTkzZGIwYTcxNWRkZTc3OTI0YmY1YyJdLCJzZXF1ZW5jZSI6NDI5NDk2NzI5NX1dLCJ2b3V0IjpbeyJ2YWx1ZSI6MC4wMDAwMiwibiI6MCwic2NyaXB0UHViS2V5Ijp7ImFzbSI6IjEgMTJiZmU4ZmQ0ZWU1NzUwNmI5ZDdiMjM5Y2I1ZmY0ZGEyY2QyMzZjMDg4MGY0YzdkMTA0ZDdmNGJmMjQxNDg5NSIsImhleCI6IjUxMjAxMmJmZThmZDRlZTU3NTA2YjlkN2IyMzljYjVmZjRkYTJjZDIzNmMwODgwZjRjN2QxMDRkN2Y0YmYyNDE0ODk1IiwidHlwZSI6IndpdG5lc3NfdjFfdGFwcm9vdCJ9fSx7InZhbHVlIjowLjAwMzM0NTk4LCJuIjoxLCJzY3JpcHRQdWJLZXkiOnsiYXNtIjoiMCAyNjZiNWNiYTdlZmMyZWYyZGM5N2FlMWRlZjZjMzkzYmU0ZTM0ZTFmIiwiaGV4IjoiMDAxNDI2NmI1Y2JhN2VmYzJlZjJkYzk3YWUxZGVmNmMzOTNiZTRlMzRlMWYiLCJ0eXBlIjoid2l0bmVzc192MF9rZXloYXNoIn19XX0seyJoZXgiOiIwMjAwMDAwMDAwMDEwMWMwMWMyM2I1M2Y3MzAwNWE1ODYxYTEyZDc4NzFkNWY2MGZhZDdhNDRlYjdlYzcxNjM0YmUyMzVhNGMzN2M1N2IwMTAwMDAwMDAwZmZmZmZmZmYwMmQwMDcwMDAwMDAwMDAwMDAyMjUxMjAzMTQ3OTJiNmI0N2RmZTdmNTU1ZjdiMWVjNjMzYzg2OGZiMDcxOWFkZGUxZGQ5NWUxYWIzMThmYmRlYTgzMTBiOWMxMjA1MDAwMDAwMDAwMDE2MDAxNDI2NmI1Y2JhN2VmYzJlZjJkYzk3YWUxZGVmNmMzOTNiZTRlMzRlMWYwMjQ3MzA0NDAyMjAxYzllZGM3ZjY0YjI2YzFhMTA1YmZhNTdkMTEzMmY3YmI0YTVlNDEyMWM5N2FkOWMyMmJhMGY2YmY0ZGQ1OTgzMDIyMDE5YjIzN2IzZGM0NmQ3Yzk1ZTllOGUzODJkYTYzN2NlYWU5NjExZmYwM2FmNTRkMGJlNmRhOWNmN2I0ZDhlYmYwMTIxMDM5MjA0OTBjOGNkY2NjYTY3M2RjMGU1YWYxN2JiYWM1NzI5NTMwNTFjYzcxOTNkYjBhNzE1ZGRlNzc5MjRiZjVjMDAwMDAwMDAiLCJ0eGlkIjoiMWU1ZjhkOGZhYTk2N2Y0ZWY0YmM0OTc5NDIwNmQ5NzYxZDE1MmRhNzhlNjk5ODliM2I0MGZhODRjNzFjMDBlYiIsImhhc2giOiJlYjhlM2QxOGYzNzM1MmZlMWQxNTg0YzE1YTYxMzQyZTA2NGNlOGNlYTkzNGYwYjk4MzZmMjViYWZiNjYwMjYzIiwic2l6ZSI6MjM0LCJ2c2l6ZSI6MTUzLCJ3ZWlnaHQiOjYwOSwidmVyc2lvbiI6MiwibG9ja3RpbWUiOjAsInZpbiI6W3sidHhpZCI6IjdiYzUzNzRjNWEyM2JlMzQxNmM3N2VlYjQ0N2FhZDBmZjZkNTcxNzgyZGExNjE1ODVhMDA3MzNmYjUyMzFjYzAiLCJ2b3V0IjoxLCJzY3JpcHRTaWciOnsiYXNtIjoiIiwiaGV4IjoiIn0sInR4aW53aXRuZXNzIjpbIjMwNDQwMjIwMWM5ZWRjN2Y2NGIyNmMxYTEwNWJmYTU3ZDExMzJmN2JiNGE1ZTQxMjFjOTdhZDljMjJiYTBmNmJmNGRkNTk4MzAyMjAxOWIyMzdiM2RjNDZkN2M5NWU5ZThlMzgyZGE2MzdjZWFlOTYxMWZmMDNhZjU0ZDBiZTZkYTljZjdiNGQ4ZWJmMDEiLCIwMzkyMDQ5MGM4Y2RjY2NhNjczZGMwZTVhZjE3YmJhYzU3Mjk1MzA1MWNjNzE5M2RiMGE3MTVkZGU3NzkyNGJmNWMiXSwic2VxdWVuY2UiOjQyOTQ5NjcyOTV9XSwidm91dCI6W3sidmFsdWUiOjAuMDAwMDIsIm4iOjAsInNjcmlwdFB1YktleSI6eyJhc20iOiIxIDMxNDc5MmI2YjQ3ZGZlN2Y1NTVmN2IxZWM2MzNjODY4ZmIwNzE5YWRkZTFkZDk1ZTFhYjMxOGZiZGVhODMxMGIiLCJoZXgiOiI1MTIwMzE0NzkyYjZiNDdkZmU3ZjU1NWY3YjFlYzYzM2M4NjhmYjA3MTlhZGRlMWRkOTVlMWFiMzE4ZmJkZWE4MzEwYiIsInR5cGUiOiJ3aXRuZXNzX3YxX3RhcHJvb3QifX0seyJ2YWx1ZSI6MC4wMDMzMjQ0NCwibiI6MSwic2NyaXB0UHViS2V5Ijp7ImFzbSI6IjAgMjY2YjVjYmE3ZWZjMmVmMmRjOTdhZTFkZWY2YzM5M2JlNGUzNGUxZiIsImhleCI6IjAwMTQyNjZiNWNiYTdlZmMyZWYyZGM5N2FlMWRlZjZjMzkzYmU0ZTM0ZTFmIiwidHlwZSI6IndpdG5lc3NfdjBfa2V5aGFzaCJ9fV19LHsiaGV4IjoiMDIwMDAwMDAwMDAxMDFlYjAwMWNjNzg0ZmE0MDNiOWI5ODY5OGVhNzJkMTUxZDc2ZDkwNjQyNzk0OWJjZjQ0ZTdmOTZhYThmOGQ1ZjFlMDEwMDAwMDAwMGZmZmZmZmZmMDJkMDA3MDAwMDAwMDAwMDAwMjI1MTIwNTAxYzJhYzFiY2U2MmFkMTdjNjA2NDQ2MjZjYjg3OWFjZDYzODNlOWYxODg0N2Y3OGUxNTdkZTRkMDg5MGY0MTMyMGEwNTAwMDAwMDAwMDAxNjAwMTQyNjZiNWNiYTdlZmMyZWYyZGM5N2FlMWRlZjZjMzkzYmU0ZTM0ZTFmMDI0NzMwNDQwMjIwNjhjYWI5YTZlNjZjMzNlOGZlYjg2ZmFiNWUzMDFiOWE2NTk3NGUyMjdhNmZkNDI0OWZhOGUxZDJmNjQyNWZiNzAyMjA0NGJlMDBhOTc2NTVmNzg3YzZmOTA3NWU1NmNhY2YyMzA4NjI3YThmNmE0YzY4YzZlOGY1ZTdiNTY4YjY0MTVkMDEyMTAzOTIwNDkwYzhjZGNjY2E2NzNkYzBlNWFmMTdiYmFjNTcyOTUzMDUxY2M3MTkzZGIwYTcxNWRkZTc3OTI0YmY1YzAwMDAwMDAwIiwidHhpZCI6IjliNDUzYWU4NjE5NjI5MjY1N2YwMDY5MDU5ODE1OGNlYjE3ZjMzNjIwNjhlNTA0YjAxNjI2NDAwZWNiYTdlM2YiLCJoYXNoIjoiNDU0OGNhNTg2NGFmNWI0MTVmNjgzOTkxYTE4NGY0MDk1ZGVhODJkYzE1ZTI3MWFjMGQ4ZmRhMTVjZDA4ODA4YyIsInNpemUiOjIzNCwidnNpemUiOjE1Mywid2VpZ2h0Ijo2MDksInZlcnNpb24iOjIsImxvY2t0aW1lIjowLCJ2aW4iOlt7InR4aWQiOiIxZTVmOGQ4ZmFhOTY3ZjRlZjRiYzQ5Nzk0MjA2ZDk3NjFkMTUyZGE3OGU2OTk4OWIzYjQwZmE4NGM3MWMwMGViIiwidm91dCI6MSwic2NyaXB0U2lnIjp7ImFzbSI6IiIsImhleCI6IiJ9LCJ0eGlud2l0bmVzcyI6WyIzMDQ0MDIyMDY4Y2FiOWE2ZTY2YzMzZThmZWI4NmZhYjVlMzAxYjlhNjU5NzRlMjI3YTZmZDQyNDlmYThlMWQyZjY0MjVmYjcwMjIwNDRiZTAwYTk3NjU1Zjc4N2M2ZjkwNzVlNTZjYWNmMjMwODYyN2E4ZjZhNGM2OGM2ZThmNWU3YjU2OGI2NDE1ZDAxIiwiMDM5MjA0OTBjOGNkY2NjYTY3M2RjMGU1YWYxN2JiYWM1NzI5NTMwNTFjYzcxOTNkYjBhNzE1ZGRlNzc5MjRiZjVjIl0sInNlcXVlbmNlIjo0Mjk0OTY3Mjk1fV0sInZvdXQiOlt7InZhbHVlIjowLjAwMDAyLCJuIjowLCJzY3JpcHRQdWJLZXkiOnsiYXNtIjoiMSA1MDFjMmFjMWJjZTYyYWQxN2M2MDY0NDYyNmNiODc5YWNkNjM4M2U5ZjE4ODQ3Zjc4ZTE1N2RlNGQwODkwZjQxIiwiaGV4IjoiNTEyMDUwMWMyYWMxYmNlNjJhZDE3YzYwNjQ0NjI2Y2I4NzlhY2Q2MzgzZTlmMTg4NDdmNzhlMTU3ZGU0ZDA4OTBmNDEiLCJ0eXBlIjoid2l0bmVzc192MV90YXByb290In19LHsidmFsdWUiOjAuMDAzMzAyOSwibiI6MSwic2NyaXB0UHViS2V5Ijp7ImFzbSI6IjAgMjY2YjVjYmE3ZWZjMmVmMmRjOTdhZTFkZWY2YzM5M2JlNGUzNGUxZiIsImhleCI6IjAwMTQyNjZiNWNiYTdlZmMyZWYyZGM5N2FlMWRlZjZjMzkzYmU0ZTM0ZTFmIiwidHlwZSI6IndpdG5lc3NfdjBfa2V5aGFzaCJ9fV19LHsiaGV4IjoiMDIwMDAwMDAwMDAxMDEzZjdlYmFlYzAwNjQ2MjAxNGI1MDhlMDY2MjMzN2ZiMWNlNTg4MTU5OTAwNmYwNTcyNjI5OTY2MWU4M2E0NTliMDEwMDAwMDAwMGZmZmZmZmZmMDJkMDA3MDAwMDAwMDAwMDAwMjI1MTIwMTg2ZmFkMDM4ODg2NWZlN2QwZTY2OTMzMDg5ZDljNzNkYzA1MmZiOWE5OTBjYmI5YzQwZTQwNjIyZjE5YzA1MWM4MDEwNTAwMDAwMDAwMDAxNjAwMTQyNjZiNWNiYTdlZmMyZWYyZGM5N2FlMWRlZjZjMzkzYmU0ZTM0ZTFmMDI0ODMwNDUwMjIxMDBhMmU1Y2FmNTA2OGE4YTI5OWM3ODQ4MjdkMTAyMjA5NDY0YjVlNThlYTBkZjI1MzZiZTIwZDJiNmVhMDUzNzZkMDIyMDRkYzQ3MzZkM2U4ZmQ1MzE1YjA3OGIyOWNhOWEwMTRmN2U0NjgwMzUyYjdmYTliYTliZDUyOTRhZTFkMDNjNmMwMTIxMDM5MjA0OTBjOGNkY2NjYTY3M2RjMGU1YWYxN2JiYWM1NzI5NTMwNTFjYzcxOTNkYjBhNzE1ZGRlNzc5MjRiZjVjMDAwMDAwMDAiLCJ0eGlkIjoiM2E5YzQ0ODAxMTkyYzVhY2E2MTZkMmI1OTAzYTAzMDUxYzk0ZDVkMGVmYzViODBmMTJkMjBkNDA2ZGY0MmY2MSIsImhhc2giOiJlM2M5MDA0NGRhZjI4YTk3OWM4OGI4NzY3YWU4MWU3ZDcyMDA4NzFkNWQ1YmIwY2UzY2Y4Yjk1Yjg5ZjU3YWM3Iiwic2l6ZSI6MjM1LCJ2c2l6ZSI6MTUzLCJ3ZWlnaHQiOjYxMCwidmVyc2lvbiI6MiwibG9ja3RpbWUiOjAsInZpbiI6W3sidHhpZCI6IjliNDUzYWU4NjE5NjI5MjY1N2YwMDY5MDU5ODE1OGNlYjE3ZjMzNjIwNjhlNTA0YjAxNjI2NDAwZWNiYTdlM2YiLCJ2b3V0IjoxLCJzY3JpcHRTaWciOnsiYXNtIjoiIiwiaGV4IjoiIn0sInR4aW53aXRuZXNzIjpbIjMwNDUwMjIxMDBhMmU1Y2FmNTA2OGE4YTI5OWM3ODQ4MjdkMTAyMjA5NDY0YjVlNThlYTBkZjI1MzZiZTIwZDJiNmVhMDUzNzZkMDIyMDRkYzQ3MzZkM2U4ZmQ1MzE1YjA3OGIyOWNhOWEwMTRmN2U0NjgwMzUyYjdmYTliYTliZDUyOTRhZTFkMDNjNmMwMSIsIjAzOTIwNDkwYzhjZGNjY2E2NzNkYzBlNWFmMTdiYmFjNTcyOTUzMDUxY2M3MTkzZGIwYTcxNWRkZTc3OTI0YmY1YyJdLCJzZXF1ZW5jZSI6NDI5NDk2NzI5NX1dLCJ2b3V0IjpbeyJ2YWx1ZSI6MC4wMDAwMiwibiI6MCwic2NyaXB0UHViS2V5Ijp7ImFzbSI6IjEgMTg2ZmFkMDM4ODg2NWZlN2QwZTY2OTMzMDg5ZDljNzNkYzA1MmZiOWE5OTBjYmI5YzQwZTQwNjIyZjE5YzA1MSIsImhleCI6IjUxMjAxODZmYWQwMzg4ODY1ZmU3ZDBlNjY5MzMwODlkOWM3M2RjMDUyZmI5YTk5MGNiYjljNDBlNDA2MjJmMTljMDUxIiwidHlwZSI6IndpdG5lc3NfdjFfdGFwcm9vdCJ9fSx7InZhbHVlIjowLjAwMzI4MTM2LCJuIjoxLCJzY3JpcHRQdWJLZXkiOnsiYXNtIjoiMCAyNjZiNWNiYTdlZmMyZWYyZGM5N2FlMWRlZjZjMzkzYmU0ZTM0ZTFmIiwiaGV4IjoiMDAxNDI2NmI1Y2JhN2VmYzJlZjJkYzk3YWUxZGVmNmMzOTNiZTRlMzRlMWYiLCJ0eXBlIjoid2l0bmVzc192MF9rZXloYXNoIn19XX0seyJoZXgiOiIwMjAwMDAwMDAwMDEwMWZjNmUwZGJjZjJmMjQ4OTllZGQwMmEzY2M1MzliOGE2MDAyYWMxNjczMDkwZTJmNWFkMGY5OGE3ZjcxYzRkMmMwMTAwMDAwMDE3MTYwMDE0MDM1Y2ZkM2I4NzI5OGEyNTQ5MjMyYWMwZjFlM2M5ZDYxODJlMTNhMmZmZmZmZmZmMDJhMGYwMTkwMDAwMDAwMDAwMTdhOTE0ODFhNmZiOTU0MzJiNzJiY2MwMzkxZTkyNjIyNDI5OTRkNjkyMWVjYzg3MmY0NTAwMDAwMDAwMDAwMDE3YTkxNDgxYTZmYjk1NDMyYjcyYmNjMDM5MWU5MjYyMjQyOTk0ZDY5MjFlY2M4NzAyNDgzMDQ1MDIyMTAwZjFiZjg3YmQ3MzZkZTY0ODgxZDg5ZDkzMTZjOTg5ZjQzMDcwYzkxYjI1ZGQ5ZDBkMjRiMmEyNjZhNjZhZTM5NzAyMjA1YzdiYzdlNzMxN2Y1MGE5MGY2ZGE1YmMyOTAwZDA1NDU1ODQwMWRmYzExZjBkMjcyNWEyNDM5ZmE5MGM4MmEzMDEyMTAzOWM0OWU1NmQ1OTBjYTc3ZmUwZTc1ZDEwNzhlYzdiOWFlZjMzZDQ3MDhjOGQzZTM3MmZhZGY3MDRlMzMyNzkzNjAwMDAwMDAwIiwidHhpZCI6IjZkYjUxZjRiMTI3Y2I2YWQ3M2M1NDQ4ZDk5NjcwOTJmMGExYjk4MGE4NDUxNmRiNzQ3MzkxNDVkYzhlNDYwMGEiLCJoYXNoIjoiNWRlZmU3MTY3N2EzYjgzOTFlNzU1ODBkOTI0MTBhZTcyMzE3ZjRhNGVmMzk4OWFiM2EyMTYxNjE1Yzg5OTdlNCIsInNpemUiOjI0OCwidnNpemUiOjE2Niwid2VpZ2h0Ijo2NjIsInZlcnNpb24iOjIsImxvY2t0aW1lIjowLCJ2aW4iOlt7InR4aWQiOiIyYzRkMWNmN2E3OTgwZmFkZjVlMjkwMzA2N2MxMmEwMGE2YjgzOWM1M2MyYWQwZWQ5OTQ4ZjJmMmJjMGQ2ZWZjIiwidm91dCI6MSwic2NyaXB0U2lnIjp7ImFzbSI6IjAwMTQwMzVjZmQzYjg3Mjk4YTI1NDkyMzJhYzBmMWUzYzlkNjE4MmUxM2EyIiwiaGV4IjoiMTYwMDE0MDM1Y2ZkM2I4NzI5OGEyNTQ5MjMyYWMwZjFlM2M5ZDYxODJlMTNhMiJ9LCJ0eGlud2l0bmVzcyI6WyIzMDQ1MDIyMTAwZjFiZjg3YmQ3MzZkZTY0ODgxZDg5ZDkzMTZjOTg5ZjQzMDcwYzkxYjI1ZGQ5ZDBkMjRiMmEyNjZhNjZhZTM5NzAyMjA1YzdiYzdlNzMxN2Y1MGE5MGY2ZGE1YmMyOTAwZDA1NDU1ODQwMWRmYzExZjBkMjcyNWEyNDM5ZmE5MGM4MmEzMDEiLCIwMzljNDllNTZkNTkwY2E3N2ZlMGU3NWQxMDc4ZWM3YjlhZWYzM2Q0NzA4YzhkM2UzNzJmYWRmNzA0ZTMzMjc5MzYiXSwic2VxdWVuY2UiOjQyOTQ5NjcyOTV9XSwidm91dCI6W3sidmFsdWUiOjAuMDE3LCJuIjowLCJzY3JpcHRQdWJLZXkiOnsiYXNtIjoiT1BfSEFTSDE2MCA4MWE2ZmI5NTQzMmI3MmJjYzAzOTFlOTI2MjI0Mjk5NGQ2OTIxZWNjIE9QX0VRVUFMIiwiaGV4IjoiYTkxNDgxYTZmYjk1NDMyYjcyYmNjMDM5MWU5MjYyMjQyOTk0ZDY5MjFlY2M4NyIsInR5cGUiOiJzY3JpcHRoYXNoIn19LHsidmFsdWUiOjAuMDAwMTc3MTEsIm4iOjEsInNjcmlwdFB1YktleSI6eyJhc20iOiJPUF9IQVNIMTYwIDgxYTZmYjk1NDMyYjcyYmNjMDM5MWU5MjYyMjQyOTk0ZDY5MjFlY2MgT1BfRVFVQUwiLCJoZXgiOiJhOTE0ODFhNmZiOTU0MzJiNzJiY2MwMzkxZTkyNjIyNDI5OTRkNjkyMWVjYzg3IiwidHlwZSI6InNjcmlwdGhhc2gifX1dfSx7ImhleCI6IjAxMDAwMDAwMDFmYzY0MTVlMGQ4MTU1NDNmY2VlNzBhZTI0MmJiZDc4NmZhMTg3MWIxNWYzNDdmN2Q5NWZhMmU0NGQzYTNmNDM0MDEwMDAwMDA2YTQ3MzA0NDAyMjAzYjM0MTAxZmY4Y2YwN2Q3ZjQzMGY3YThmZTViNDI1YmIzZjk2MDUxYWI5NDA2NmI4ZjljOWIyNWU1NWEyZDcxMDIyMDY3NDg1MWMxMGNkYzA4MTgzMjk1YzY3ZGE1OTEzNjkyMGIwMGRlM2I0ZGM0ZjVlMWY1ZWIzMjFmNWVmYmY0NDUwMTIxMDMxNzIyNWRmMWQ0NWQwNDQ5NzRlZTBmOTgzNTFlODNkMTk4NjVjMjg1YzhmYmI5ZTUyODFmYzQ2ODM1YzUzN2Q1ZmZmZmZmZmYwMjhjODUwMDAwMDAwMDAwMDAxOTc2YTkxNGQ5MjZkMTc0OTY2NTJjMWU5M2IxZTgxMGQxMTQ0Y2E1ODcyYzM4ZjY4OGFjNTc5ODAwMDAwMDAwMDAwMDE3YTkxNGUxMDMzOTg4MjRiMDdiOTc0MmZjMTc3NjAwYTRkOTc2ZTY1MzMxOWM4NzAwMDAwMDAwIiwidHhpZCI6ImMzNjI5MDQzOGFlMjIwMDg1YzFjYTc0NDc3ZWRjZTQyOTIzYTA3ZDYwNjViYTE5Mzk0ZTFjNzFmMGUxYmFhMjUiLCJoYXNoIjoiYzM2MjkwNDM4YWUyMjAwODVjMWNhNzQ0NzdlZGNlNDI5MjNhMDdkNjA2NWJhMTkzOTRlMWM3MWYwZTFiYWEyNSIsInNpemUiOjIyMywidnNpemUiOjIyMywid2VpZ2h0Ijo4OTIsInZlcnNpb24iOjEsImxvY2t0aW1lIjowLCJ2aW4iOlt7InR4aWQiOiIzNGY0YTNkMzQ0MmVmYTk1N2Q3ZjM0NWZiMTcxMThmYTg2ZDdiYjQyZTIwYWU3Y2UzZjU0MTVkOGUwMTU2NGZjIiwidm91dCI6MSwic2NyaXB0U2lnIjp7ImFzbSI6IjMwNDQwMjIwM2IzNDEwMWZmOGNmMDdkN2Y0MzBmN2E4ZmU1YjQyNWJiM2Y5NjA1MWFiOTQwNjZiOGY5YzliMjVlNTVhMmQ3MTAyMjA2NzQ4NTFjMTBjZGMwODE4MzI5NWM2N2RhNTkxMzY5MjBiMDBkZTNiNGRjNGY1ZTFmNWViMzIxZjVlZmJmNDQ1W0FMTF0gMDMxNzIyNWRmMWQ0NWQwNDQ5NzRlZTBmOTgzNTFlODNkMTk4NjVjMjg1YzhmYmI5ZTUyODFmYzQ2ODM1YzUzN2Q1IiwiaGV4IjoiNDczMDQ0MDIyMDNiMzQxMDFmZjhjZjA3ZDdmNDMwZjdhOGZlNWI0MjViYjNmOTYwNTFhYjk0MDY2YjhmOWM5YjI1ZTU1YTJkNzEwMjIwNjc0ODUxYzEwY2RjMDgxODMyOTVjNjdkYTU5MTM2OTIwYjAwZGUzYjRkYzRmNWUxZjVlYjMyMWY1ZWZiZjQ0NTAxMjEwMzE3MjI1ZGYxZDQ1ZDA0NDk3NGVlMGY5ODM1MWU4M2QxOTg2NWMyODVjOGZiYjllNTI4MWZjNDY4MzVjNTM3ZDUifSwic2VxdWVuY2UiOjQyOTQ5NjcyOTV9XSwidm91dCI6W3sidmFsdWUiOjAuMDAwMzQxODgsIm4iOjAsInNjcmlwdFB1YktleSI6eyJhc20iOiJPUF9EVVAgT1BfSEFTSDE2MCBkOTI2ZDE3NDk2NjUyYzFlOTNiMWU4MTBkMTE0NGNhNTg3MmMzOGY2IE9QX0VRVUFMVkVSSUZZIE9QX0NIRUNLU0lHIiwiaGV4IjoiNzZhOTE0ZDkyNmQxNzQ5NjY1MmMxZTkzYjFlODEwZDExNDRjYTU4NzJjMzhmNjg4YWMiLCJ0eXBlIjoicHVia2V5aGFzaCJ9fSx7InZhbHVlIjowLjAwMDM4OTk5LCJuIjoxLCJzY3JpcHRQdWJLZXkiOnsiYXNtIjoiT1BfSEFTSDE2MCBlMTAzMzk4ODI0YjA3Yjk3NDJmYzE3NzYwMGE0ZDk3NmU2NTMzMTljIE9QX0VRVUFMIiwiaGV4IjoiYTkxNGUxMDMzOTg4MjRiMDdiOTc0MmZjMTc3NjAwYTRkOTc2ZTY1MzMxOWM4NyIsInR5cGUiOiJzY3JpcHRoYXNoIn19XX0seyJoZXgiOiIwMjAwMDAwMDAwMDEwMWVlMzlkM2FhODZhZGJlNWM0NTM0ZjZlOGQ1MDYxYTAxYWVhOGJiZDBhZjc4NDA0MWNkYmIzZDAyNGQxNmVjM2YwMDAwMDAwMDAwZmRmZmZmZmY2NTIyMDIwMDAwMDAwMDAwMDAyMjUxMjAyZGU4NTIxNDhlZDMxNjg4NTU2NGM0NDYyYmQwZmQwMDY2NmQzZTA3OWQ4NTIwMTllNDFmOTAyMTIwODc4ZGQ1YjkwMjAwMDAwMDAwMDAwMDIyNTEyMDdkOTkwMzJiODAzNDdkMDJjZTg1Y2E3ZGJhY2E3NWMxMGI2Y2M3MTkxMWY1OTRjNDRiZWRhYzI3ZDdhMjFiZThiOTAyMDAwMDAwMDAwMDAwMjI1MTIwOGVkYjMyZTAzYTE4ZWFkMDMzYjdlNjZmYmE4ZGY5MjU5NDNkNDc0NjFlMGQ0MWYxMzJhMmRjM2I0OWY1MWNkNWI5MDIwMDAwMDAwMDAwMDAyMjUxMjAxZjM3YTk1MTJlZTUxM2IyOWI4ZWNhMDBkYmRlYmY5YmZhOWUwZTVhMjZlYjliODZmMDI1MjgwZTBjYzE3Y2NkYjkwMjAwMDAwMDAwMDAwMDIyNTEyMGRhMDYwNzgyZGM2MzBjZjZlMjQ0Yzk1OWU1YTYzODgxNGVjZDFkMTRkZTMzYjMwODViOGM0NzY1MzMzMGMzZDRiOTAyMDAwMDAwMDAwMDAwMjI1MTIwZWZkNTJiYTRiMGQ3ZjQzZWJiOTNjYTcwNDE2MjgzMmI2NDQ2MzdlNmYyMjY2MmRmOWIzYmY5ZTdmYzM5Mjg4OWI5MDIwMDAwMDAwMDAwMDAyMjUxMjBlYzQ3ZWZiODQyYzIxMjk1NjQwN2FjYjMxMzJiMmNhNjJiOWEwMjhkZGI5MGNlMDI4YmM5NzYwMzZiY2JjNzA5YjkwMjAwMDAwMDAwMDAwMDIyNTEyMDU1MGEyYjA5NzI3MzlhNTUzZmU1YzI2MGI1MzYxNmM4ODE4Y2QyNjdjNmY0YTY5MTAxMmRmODYwMGMxNGYwNzNiOTAyMDAwMDAwMDAwMDAwMjI1MTIwNTU0N2EzNDkxOTJmYjM2ODBhMGY2MmJiZDRhYTMxZTBjY2QzMWFmNzU5ZTcwZjFlNWZmNTIxZGZkZDY1MGEyZGI5MDIwMDAwMDAwMDAwMDAyMjUxMjA5NzM2YzU2ZjM3ZTQyNzEzYjcxOTUzZjcxOTQ5ODJiNDVhMzIyNGI1YmMzZGUyYjc5MjMwM2JiMDE3YThkZDNiYjkwMjAwMDAwMDAwMDAwMDIyNTEyMDEwZDkwNTg2YTE0NTQ4YjllZGRmOTFhMDAyYjZjNDM0OWY0NzljOWZlODM4NTJjMWRkYjA2MGE2ZDJiNTZhYWZiOTAyMDAwMDAwMDAwMDAwMjI1MTIwMDY5NzhkZTYyMDc1MGE2NWUyNTkzOWNmOWVlNzA0YzFlMDNlMGI2ZGRlMjdjODJjYmQ3NzU0ZDM2NWNiYzBlNmI5MDIwMDAwMDAwMDAwMDAyMjUxMjBkNTY0YjA3NmU0MmRlODQ0MGY1YzMyOTI3Mzk2MGRhNGZhOTllY2E0NGE3Y2RhNGQ1MDI1M2MyYzYzOTQwNWJlYjkwMjAwMDAwMDAwMDAwMDIyNTEyMDcyM2M4ZWE2YWYxODUwMGVhOTk0MTc3Y2Y3MDNiMGRkOWE0MWMyYzA5ZjQyMzBhYTQxNjg5YzgwNDM2OGI5YzZiOTAyMDAwMDAwMDAwMDAwMjI1MTIwZTI5YzQwZGU3MTlmODFlOGI5ODg1NjUxYmQ0OTRlZTNlZWI5Zjk5MmJiNjY1M2U0MDg5MmU2OTdiOWYyYjkxNWI5MDIwMDAwMDAwMDAwMDAyMjUxMjAxYTM3ZmUzMjkyYmEyOTEyZDQ5NjJjMzgxZWY5ODg1Y2UyMGQ4ZWE3MWNiMzliMjVlNmQ2N2U5NjZiM2I2ZTQ5YjkwMjAwMDAwMDAwMDAwMDIyNTEyMDIxZDJkMmU4NzJiMjlhNTk1MDA0ZGRlNGY2ZTE2MDgxMDdhMWVkNTAwNGNkYzBlZWM2M2NhMWY1ZGNlMWM3NDRiOTAyMDAwMDAwMDAwMDAwMjI1MTIwNWQzMzI0ZDc1ZTQ5M2U1MmU0NDdjZDU3YmIzM2U0NmY5MmQyNzVhMjY5ZDMxZDA3NjE0ZjgxOTYzOWZhZmE3ZGI5MDIwMDAwMDAwMDAwMDAyMjUxMjBjZDMxMWM4OGVkMzBjYjE5MmMwMDJmZDU5MTNkNTQ3ZWMyOWQwOTU1ZDI0ZWIzNzc4OTQ5YTNlMTJkNjEwY2M1YjkwMjAwMDAwMDAwMDAwMDIyNTEyMDE1OWRiYjY1MmY1NTkwMzhlZjUzYjJiNTFjNGEyMWVhZTQ1MWU3ZjBhM2JlZjYyOTFhZDA5ZDk4NjhiODcwYTRiOTAyMDAwMDAwMDAwMDAwMjI1MTIwNzdjOWZmMTczZDk3N2M4ZDcxODJlZjA0OWM0YmY2MDM5NGMwNjM2ODAyN2NmNjkyN2U0Yzg1MmFjYzNmNGU0N2I5MDIwMDAwMDAwMDAwMDAyMjUxMjA3NWM4NzhjNDVhMWIyM2U4ZjcxNzI4ODZmYzAzZjA3ZTk2NTUyY2U2MzhjOWVmOGMwYWQ3MWZhODhlODNmMDk4YjkwMjAwMDAwMDAwMDAwMDIyNTEyMDYxMjViNDRlODZlZTcxZGFiMmIxOGRiZTIxYWJkM2I1Mjc1OTJjNTRiODM0ZWU2MmZiZTM1NDA3NDU1MjQwM2FiOTAyMDAwMDAwMDAwMDAwMjI1MTIwZGNhMjcwOWVkOWUyYzZhM2I2ODg4NGYzNjE0OWQwNDRjOTMyNzA3MGM0ZjIxZjE0ZDlhN2M4Mzc3ODRjNjIzYmI5MDIwMDAwMDAwMDAwMDAyMjUxMjAwOWExNTBiZDlmNzU5NmJiYjk4MDIwMzkyNjQyZWI5YTIxNzZlMDJjN2I1OTQ3OWE4MzQwNDE4MTFkMzYwMDdlYjkwMjAwMDAwMDAwMDAwMDIyNTEyMDM5ZmNjNmMxMWZhMWEzYWE5NDVmZTIyZDhmYTdhOGY2NmY1Njk1Y2Q4ZGYzOWY5MDI3ODM4NDRjOWU4OWE0OTViOTAyMDAwMDAwMDAwMDAwMjI1MTIwNzBhNzQ2MTVlNGJiMTBmOTc0YmY2ZmI2MzJhYTM1ZmY0ZmVjNWU5ZmU5ZGJhMjJmYzk5ZDg3ODMzNTg1NzA2ZWI5MDIwMDAwMDAwMDAwMDAyMjUxMjA2OGVlNmRmZmY0ZjlmMTRmMjk2NmY2YzZiZGQ0MjIzMGNhYmM2NjY3Yjc3MThiNmVkZTRlMWQwNDVlMzZjODQ1YjkwMjAwMDAwMDAwMDAwMDIyNTEyMDVhYmYwODIyOTVjNjE5MWFhNzFkOThmODA5ODUzZDVhMTRiNTNjMmU4NmFkYjViNjU3OGYwYTZhYWYzODZlZmFiOTAyMDAwMDAwMDAwMDAwMjI1MTIwYzQ2NWQ0YWRlNGNhNmMwY2YyZjE1NGU3NTFlYzhkYTU4ZjZhMzIyZjg5OGRmNmM4MGVhZDVlYTM1YjU0MTRjMGI5MDIwMDAwMDAwMDAwMDAyMjUxMjAxZGM0ZmFiODk1MmY0ZjFlZjk3MzlhODNkNTFkYmIyMzdmZmY0NDY2MjI1MjJmMWZlNDZkZmMyMGFkNjRlODZhYjkwMjAwMDAwMDAwMDAwMDIyNTEyMGIyYzgxZWU0MzBmMjA1ODFhZWZiMzVhZmM4N2U3NmVjM2ZmNjNiZmY2NDkwNzliNGNiYWFjZjg3NzU3OTBlZDdiOTAyMDAwMDAwMDAwMDAwMjI1MTIwODM3MTJkZDMyNjJkMTJjOTYwMDNkMDBkMzkwM2MxZGUzMTVkNmNlMThkYTI1YjMyNjkzODJjNTY0NDI3ZDU2M2I5MDIwMDAwMDAwMDAwMDAyMjUxMjAwYWViMjFhM2UzNjQxNWE2MmRjMWFiMWYxYmI4MzAyZDYyNTBhYjEyNTE3YTk1YjgxZWZkOWY2OTc5NmJhNDViYjkwMjAwMDAwMDAwMDAwMDIyNTEyMDExMTA0ODEwMjNjMDg0OThhNWRiNWRkZTgzNjAzMjJjYjVlM2Y0ZTkzYWE2NDViNWJjYTNkNTIwODIxMjNmZTRiOTAyMDAwMDAwMDAwMDAwMjI1MTIwMWU4OGQ4OTI4ODFlYjY0NDY2MWIwYzkyNTY3ZDQ2OWNmN2U0OTdlYjA1MDFmNjk1MjBkZGQ4NDg4NTM1NjIzY2I5MDIwMDAwMDAwMDAwMDAyMjUxMjAxM2E5YmEwYTgzZWRlNTg4MTE0NzM1NTYyMTM4NmQ5MjYyOWY2NmNmNTMyNmI5Njk5NzZiMDM0ZGFkOTg5Y2VlYjkwMjAwMDAwMDAwMDAwMDIyNTEyMDIwYTkxMjBmNWNmMTQwZTFkNGQ0Yzk1MTQ1MmI1MjNiMTBkNjRkYzA1YTljYWM1MGQ2OGU5ODAzMTljOWQ5NjJiOTAyMDAwMDAwMDAwMDAwMjI1MTIwZmUwM2NjY2UwYWEyZmZkZGRmM2E0OThmZmFiMTU0MmJkNGFlZTZiYTcxNzA3ODI1ZTU0OWFkNmE3YmNlMjg0YWI5MDIwMDAwMDAwMDAwMDAyMjUxMjA1ZmE3ZjUzNTFjOTJiMjg4YmE1ZDMxM2RiNjEzNzMyNDRkNTljZTY0MDVlZTM5ZWJlZTE5ZjY4MzQwMDVjMmVhYjkwMjAwMDAwMDAwMDAwMDIyNTEyMDY5Yjk5MTc3OTYxODA1N2IzYWMwNzdiYzc4ZGY2YjdlMWNjN2Y0MzU0NWMxOWI2ZTMyMGI0ZThhN2UxYmJjMmZiOTAyMDAwMDAwMDAwMDAwMjI1MTIwNGVhODJjNWE4MDdmMWRjYmZmMGFmMDdhOWI5N2E4ZmViNjQ5MTNhOWJmMWViOGI5NTRjNTZiNGRjMWE3MDljY2I5MDIwMDAwMDAwMDAwMDAyMjUxMjBlYmNiM2FlOTUwZDBlNzFkYzlmMWM0M2JmOTRiOGEwZmQ4NmJkNDA3ZmM1Y2E5YTk5ZmYwY2U2ZjA3ZGQ2MWEwYjkwMjAwMDAwMDAwMDAwMDIyNTEyMGU4ZGVhYjk2OGFmNWZkMGUxYTg2Y2EwYjcxODg1NDA5MDZlYmE3MzU3NzNmOGNlZDIzZWEzY2QyNTU4OGVkYjViOTAyMDAwMDAwMDAwMDAwMjI1MTIwMjdmMGQyODBmNjA5YWU5MDczZjAwZTM2ZTRmZDJiNDdmMWE5NTc4ZjVlYTYxYWQ5ZDM1ZGNjMzUzY2E3Yjg5M2I5MDIwMDAwMDAwMDAwMDAyMjUxMjAwMDQ1OTgyMGE2MTdhY2YwNDA0MWEwM2Q0N2QzNDUxMzlmZTc4MjJiMTc2M2UyZGEzYjdiNTU3NWM3Y2ZlYzBiYjkwMjAwMDAwMDAwMDAwMDIyNTEyMGZkNjI4ZWVkNjE0NDg3NDRiNTU1NzMxNmJmOTE0NmEyZDMzMWFmNTAyYTg0YTdhNDJhODcxNGRjMDNkNGQ5MGRiOTAyMDAwMDAwMDAwMDAwMjI1MTIwMDZjZDc1NzlmNDk4Y2FkODQyZjdlZGFiNWM4NTIzMjJjMjg0OGVkMzA0MzBlZGVmOWZhNWYyYzNkMGFkYzE2M2I5MDIwMDAwMDAwMDAwMDAyMjUxMjBhM2JiZGI0MGNhZTZlYjNjYjRiM2MzYWFjMWM0MzQ4NjhkMDIxYmYwMjBiYzIyMzk0MjUwY2FhM2I0NjE1NGUxYjkwMjAwMDAwMDAwMDAwMDIyNTEyMDc5ZWNiNzUzOWFmNmViYzUyOGZkMWM3MTA1YjBjOWQ2MzcxYjVmMmJhZDAzMzYzYzM2YzQ3MzgxNjI1NGVjODBiOTAyMDAwMDAwMDAwMDAwMjI1MTIwOThhNGRhOWM4MmE3NWFlZDBhMmY5ZGQ4NzhlNTlkOTg2YjJhOGU1OTAyYzhjOTE4YmNiNGVkNjE4ZWI5MWIyMGI5MDIwMDAwMDAwMDAwMDAyMjUxMjBhZWIwNzBhZWI2N2ZjOWFmZTc3ZjliZDMxN2YxM2MxNjZiZDQwN2IxNjk5NmM4Y2I4MjFkYTAyN2ZkODgyOGFlYjkwMjAwMDAwMDAwMDAwMDIyNTEyMDA5YzNkMWM4YjAwZWYxNTA1ZGU1NGVkNDNlNTZkYWMwOGQxMDJlNDBhMDRmMmI2NzlmNGI0ZjVhYjg3MDA0NzFiOTAyMDAwMDAwMDAwMDAwMjI1MTIwOTc0OTc4NWY3NTQ0MWJiOWFmMzAwZjdiYjJhNjZmOWM4M2Y3MDA3N2QyMDU5ODIxYmVkODgzNjNkZmVlZGVmM2I5MDIwMDAwMDAwMDAwMDAyMjUxMjAzNjY2YWUwN2JlNTY0MTlkZDhhZTkyZjIwOGM1MzRkZjZjOTI4MDgwMGFiYjBlZWI3YjQ4M2JkNGJhMTNmODBmYjkwMjAwMDAwMDAwMDAwMDIyNTEyMGU0YWU1NGNiMTUwZWZkMTg5YmQyZWQ0YWI1ZjRmZWNiYjlhMGM1NjJmZWRkOTJiMDhkOTk2MTMxMTkxZDcwYzliOTAyMDAwMDAwMDAwMDAwMjI1MTIwOWRkZTg0MTYxOTNjOWY5NjQxMzVmNDJmNjllOTczM2Q2YWNjNzU3ZThiN2UwZDM3ZjY1OTQ3NmRkNDUwYmFjMmI5MDIwMDAwMDAwMDAwMDAyMjUxMjA4NWZiNWM5NWMyYTk5NWE1Mjk0OTVkYWJkYTYzMTRmN2VjYTBlMzdhZTgyZGIzZWJjNTYxM2VjMDA3NTQzOTcxYjkwMjAwMDAwMDAwMDAwMDIyNTEyMGE1MGFhNzg0ZDA3ZTVhNjE0YzRmMzlhNjk5ZDQ1NDRlOTc5MjZiOTFjMGI5NWM0MTU2OWYwNGU0NGU1ZTdiZGZiOTAyMDAwMDAwMDAwMDAwMjI1MTIwZWU3MGZiYTc3OTY5MTJmNmMwNGZiMjRhOGM4M2NiZDE0YmVjYzk4ZWIyMzA4NTIxMmU3MWViYzljMWFlNmYxYWI5MDIwMDAwMDAwMDAwMDAyMjUxMjBkNjYyYzc5OTk1ZjJmZTNjZGY3MjE0NGExMzg0MmFlZDhhNTQ5MTRiM2Y0MjkwYjBlZjA3OWM2ZTNkNzA2NzUwYjkwMjAwMDAwMDAwMDAwMDIyNTEyMDdhZjhhMTdjNTliNmVlMDgxZTU1MWVkZDRlZTVlYWU4OWYwMjkxNWU1NjlkMmY2M2Y1ZmViZGFhMDE3ZDZkMWNiOTAyMDAwMDAwMDAwMDAwMjI1MTIwYjI5ODU3ZWNiY2ExNzc4YzYzNTc0ZTI1MDUwZDNiZGUwYzE1NjAyMmFmMWVjNzdiY2MwNWVlYTgxY2NhYjJiY2I5MDIwMDAwMDAwMDAwMDAyMjUxMjAxMjViYzdlMzdiYTljZTMzZTE2NmI1NWZlZGFkMDk0M2NhM2I1ZGViNTE3YzQ1MWI5NGEwM2NlOTU2NDU2ZGY1YjkwMjAwMDAwMDAwMDAwMDIyNTEyMGRlODRiOGRlMjBmOTE4NTU4MmQ0ODNiYWQ5OTc4Njc3N2Q0NDYzMjJmYmU1ODYyZGY2NWM0YmJjOTBlYTBlNDliOTAyMDAwMDAwMDAwMDAwMjI1MTIwNWJiZmQxODZjOWVkMzRiN2FiM2UzMDNmNzFiNmViODU0MjMwODQ3OWQyMWNlNGQ3YTliYTQzMDBmZjYyZTYzMmI5MDIwMDAwMDAwMDAwMDAyMjUxMjA2YzhkZWFiMzViYjhmYjc0NjllYmFlZTgwOTkyYThhOTc2ZjQ4Y2Q3MDU3Y2Q4NWZmNGRjMDBhOTI4N2ViYjFkYjkwMjAwMDAwMDAwMDAwMDIyNTEyMGI5Yzc5YzUzODI4NWI2ZDc4N2IzYjZmZDQ5OTVlNWYxMTAwYjNlNzk0MzUyZjljYjZhOTM0NGRhYmRjY2UzOWFiOTAyMDAwMDAwMDAwMDAwMjI1MTIwY2FlYmNhMzEwMDA2YWFlYzNiMTcwMTc4NTY1ZjliODMyNDIxMzUzZDE4ZGNmNTRkNzBkMDQ3ZTcwNzNkMjQxN2I5MDIwMDAwMDAwMDAwMDAyMjUxMjBmMTFiZjM5MjZiNzAyMGE5YzM4Yjg2ZTYzODk2ZmRmNmYzOTk5Mzk2ZWM4OGU0MjY0NTRlMzdjNTg4MWE4MDc3YjkwMjAwMDAwMDAwMDAwMDIyNTEyMDBhOTE0ODI2ZTFmYjdhYzcxZjIxMTVhZTQ4YThjN2E4NGE0ZmI2YzVhMjA3MzQzNzdkN2I4MmZlZDMxMjY0Y2NiOTAyMDAwMDAwMDAwMDAwMjI1MTIwMzc1ZGI4N2Q3OGEzZmRjZDdmNzljOTY2OWQ5MDY4NjVmMDlmZDdkNTA4MmVmMzFmNTRiMWY2NTVjYTUxNjAxN2I5MDIwMDAwMDAwMDAwMDAyMjUxMjA1Y2U0NzkzMjY5YWIxMmVmZDE0YzJlNjY5NjI2ZGZkMmU5MjJhYTdlYTM5YmRkMzQ2ZjQxYWY5ZDFkZjM2ZDFlYjkwMjAwMDAwMDAwMDAwMDIyNTEyMDc1ZGQ1N2RkMzI4YTc2NzE1NmQ3NzNjYTA5ZTRjYjE5YTRlMTAxNjNiZjM5YTE5ZDY2Nzc5Yjc2NTFiNWYzZGViOTAyMDAwMDAwMDAwMDAwMjI1MTIwNDBmNjY4YWZiMTE0NjgzOGRlYjU1MjJlY2Q1MTA3YmNiN2Y3NWEzMDZhMzc0NThhNTk5M2RkYTA4MTk4MDkxZmI5MDIwMDAwMDAwMDAwMDAyMjUxMjA0ZmRiMjcyNDdmMzdhZTA1MDRlY2ZhMjlkYmQwZDE0OGNhMTdlZjgzYmZjMGZjZTAwNWNlOGUzYjliNWIxZWNiYjkwMjAwMDAwMDAwMDAwMDIyNTEyMDg5YjQxYTA0N2Y1ZWI1ZGZmZjBmY2I2Y2NkOTNjYTZkNzRjMjI2OWRlYzFlYThmMjQ2ODUzY2Q2YWZhMDEwMmJiOTAyMDAwMDAwMDAwMDAwMjI1MTIwM2U5YWFhNjNmM2Y0YzczNjNlYzQ3ZWU0YTBmZmQ0NTI2MzBhMmI5OTYyNmJlNWRhYTM0ZjhjMzVhZWVhMzVkY2I5MDIwMDAwMDAwMDAwMDAyMjUxMjA4MmMyMTJhYmU2NzVhYWUyOWUyZGZlMDI2OWU0NzUzNDNmMmU3MDk0N2Q5YmVhMzVkY2JmMDg0NzVlOGQ2YWE5YjkwMjAwMDAwMDAwMDAwMDIyNTEyMGU3ZDlkNDZmYzFhNDk1MjFkMGY2NjhlZDY1NGQyNzRmNGQ2MmJiZDlkMWFiMTc0NTdkNjEzZDUwYTYwNWZlYjBiOTAyMDAwMDAwMDAwMDAwMjI1MTIwM2UxM2NiNWFlNzk4MDk0NmUwMmU0MjRjY2U1MmJmMDMwODVjM2YyZjljODliNTUwNjRmZTQ5MDg0ZjczODAyNmI5MDIwMDAwMDAwMDAwMDAyMjUxMjBlMWI4ZGMzNWQwODUxNTc2MTc4YmZkNGExNjFmZjU0MGY2M2VjMDFhNWQ5MjU0MGIxMTNiNWY1MTc0YzdiMDkwYjkwMjAwMDAwMDAwMDAwMDIyNTEyMGYzMjQ5ODA5OGM2MTRkOTNiYmZjNGJjZDY1MDNhMGY1NWE5NzQ5YzRmMDg2OWVmMTBlYzM4MjEyNDg0NTQxZjRiOTAyMDAwMDAwMDAwMDAwMjI1MTIwZjNmZjg3ZTk1ZWQzOTg5MTI0N2I0NGRlMzg3ZWI3MWE2ODFjM2UyOGMyOGM4ZTgwYTQzMTE1ZWMwNjJmZDQ1YmI5MDIwMDAwMDAwMDAwMDAyMjUxMjBhNGYyYzk4ZjRhMWFiNjUzYzQ3OGZlZTBkMjEzY2I4ZmEyODRmNWFiMTA0NzYxNGZkZWUwMGIwN2YwMDE1ZDIxYjkwMjAwMDAwMDAwMDAwMDIyNTEyMDViMjk1ZmI3ZTNiMjkwYzVmYWQzMzcwMmIwYzM4Njk1ZGQ2NTEwNWI3NmJhZTRiNzIxZDg3NmM1ZTQ1MWNkODliOTAyMDAwMDAwMDAwMDAwMjI1MTIwOTZmODEzZjUwZTAzMWU1N2RmYzJjMWYyOWNmYmUyYTBiZDlkMGNhZjE0ZjUzZjc0ZjAzZWQ3NzEyOTE3MjVhMmI5MDIwMDAwMDAwMDAwMDAyMjUxMjA5OGM4N2UzZTUzMzE0NDg3OWRkY2VjZjZhYTAwMDZjN2NlZjE1Mjk0ZTI2OTUxOGRlOWYwNWVlNmE0OTU0YzY5YjkwMjAwMDAwMDAwMDAwMDIyNTEyMGI4NjY5NWExMWM4YmMyNDEwNDVhYzI0ZjNhY2Y1NmQ0ZGY0NmRlMTg2YzZiMGU4MmQzOTc1MTljYWIxMThjMGJiOTAyMDAwMDAwMDAwMDAwMjI1MTIwZmEzZTc2Y2MxY2FmOTdmYzI3MWYxNWU1YzFiNDYzMDc5NjJiMzA3YzEzZWFhNmMwODkxYjNmZTRkNWJlYmVlNmI5MDIwMDAwMDAwMDAwMDAyMjUxMjBmM2QzZjdmYmQwMTMxODY1MzUwOTA0ZmQ0ZTZhNTQ0YmI1YzVmZDdjZjdjMjEwZTI2YWRmYmRhZGJjMGMyZDEyYjkwMjAwMDAwMDAwMDAwMDIyNTEyMGE4NjM0NmY4ZGNlOWQ3NTQ0NjFkNTk3M2U2OGY4ZDI0OGJjMjg5ZWY4Yzg4MDU2MzMzNzBhZTY1YzJhOWNlZmViOTAyMDAwMDAwMDAwMDAwMjI1MTIwOGI5MzIyZDZmNmViOTIwZmZjN2FmY2YzZGJjZmI0YTdiOTMxMzQxY2I2NGUzY2M3MTFiNDAzMmUwMmExMjA2NWI5MDIwMDAwMDAwMDAwMDAyMjUxMjA0OTRiZTM2MDY2YjNhNmMxODE2Y2RkYzY4NGY2YTllM2FjYWFkODcxNTZhNmU5NDBiNDk4MzAyMWRhNmU4M2NjYjkwMjAwMDAwMDAwMDAwMDIyNTEyMGJhNjJiY2E3ZjgxYmM0NjU3ZTYzMmM2ODNjMzY4ZjUyMzk5MjIzYzM2ZjUxMDFmY2ZiZDE3ZGI1ZDM4ZmQwYTliOTAyMDAwMDAwMDAwMDAwMjI1MTIwMWFiODA0Y2NjZGNkMTE0MmQ0NTcwZWI4NjQxZTJhNTYxMGRmYjhkMTQ1NzRmOTBjMDYyNWYxM2MwOTc4ODQwOGI5MDIwMDAwMDAwMDAwMDAyMjUxMjBkZjMwYjcyZjQ5ODYwNmU2ZTU3YjI0MWMwOWQ0NWI4ZjFjMmFmMTNiYjVhYzdkM2JmOTZmY2Y1ZDJmZTZiNWRiYjkwMjAwMDAwMDAwMDAwMDIyNTEyMDg5NjJlOTFmN2I4ZGMxODMyMzVlZmYwZjBjMzA5Nzk5MzczNDUzNzYyY2NjMDA5YzJmYTAxMjQ0YWRiM2YwOThiOTAyMDAwMDAwMDAwMDAwMjI1MTIwZGRjNmIzNmE5NTE0NDZjNDQ2MmQzM2E4MmI1NDNlZTFkNTgxMjIxOGFkNDUwMTkzZWIxYThhZjQ0YWVkNzE0N2I5MDIwMDAwMDAwMDAwMDAyMjUxMjBjMmQ1OTY5NzIxYTBlYjY1NDdmZmEyNzg0MmMyYzYwZWRmNmViY2Y4MmM5MTI3YWU1M2UzOWU3YTFmNDgxYzVkNWNjMzAwMDAwMDAwMDAwMDE2MDAxNGJkZmQ2ZTBlODg5Y2U1N2M5YWRiZmU4MTdiMjY5Nzg2Y2EwODIxZDMwMzQwZTlmYjUyN2IyODhmYWIyMTM2M2IyZWJiMmJjODU0M2E3NmRjNTdjMzFiOTU5NmUyMDI0YzE5YmM1MmE1ZDAxOWVhNjEwN2FhMWNhMzg1ZjE1Y2EwYjY0NzE2MGEwOWExZjU2NTEwZTE0ZjU5MTg1YTU1ZDk5YmRkMjRkMTgwMDU3YjIwZWM2MTBjMTU5NzNjMGI1NGJlN2VlM2ZkZWI5NTljNzk3YWI1NWNkYTAwMDJkNjEzMGMyMmE1NjJmZjJlODExY2FjMDA2MzAzNmY3MjY0MDEwMTE4NzQ2NTc4NzQyZjcwNmM2MTY5NmUzYjYzNjg2MTcyNzM2NTc0M2Q3NTc0NjYyZDM4MDAzNTdiMjI3MDIyM2EyMjYyNzI2MzJkMzIzMDIyMmMyMjZmNzAyMjNhMjI2ZDY5NmU3NDIyMmMyMjc0Njk2MzZiMjIzYTIyNmQ2NTZkNjUyMjJjMjI2MTZkNzQyMjNhMjIzMTMwMzAzMDIyN2Q2ODIxYzA5ODM3MWMxMDhmNjVhYzkzYzJkMDg5MDBhMGViNmVhY2U5MGE1NDcxODY4MDFmYTI1MmI0M2U1N2U3ZTI3NTUxMDAwMDAwMDAiLCJ0eGlkIjoiZjNiMDFlZDAyYjE4OWQ4OTY0NmQzYWJkZWMwOGYyZDIzZTJhZDIwODMyYWU0OGJkM2UyYWQxOTBjYjhlMTE5ZCIsImhhc2giOiIxZWRhYTQyNTFhOGY2ZWExMTg5MjMxNGRmNjdmYjQzNDlmZmY0MjQ2MjQxMzM1MjM4ODUyNTk0MWJlZGMwN2JmIiwic2l6ZSI6NDYwOCwidnNpemUiOjQ0MzksIndlaWdodCI6MTc3NTQsInZlcnNpb24iOjIsImxvY2t0aW1lIjowLCJ2aW4iOlt7InR4aWQiOiIzZmVjMTY0ZDAyM2RiYmNkNDE0MDc4YWZkMGJiYThhZTAxMWEwNmQ1ZThmNjM0NDU1Y2JlYWQ4NmFhZDMzOWVlIiwidm91dCI6MCwic2NyaXB0U2lnIjp7ImFzbSI6IiIsImhleCI6IiJ9LCJ0eGlud2l0bmVzcyI6WyJlOWZiNTI3YjI4OGZhYjIxMzYzYjJlYmIyYmM4NTQzYTc2ZGM1N2MzMWI5NTk2ZTIwMjRjMTliYzUyYTVkMDE5ZWE2MTA3YWExY2EzODVmMTVjYTBiNjQ3MTYwYTA5YTFmNTY1MTBlMTRmNTkxODVhNTVkOTliZGQyNGQxODAwNSIsIjIwZWM2MTBjMTU5NzNjMGI1NGJlN2VlM2ZkZWI5NTljNzk3YWI1NWNkYTAwMDJkNjEzMGMyMmE1NjJmZjJlODExY2FjMDA2MzAzNmY3MjY0MDEwMTE4NzQ2NTc4NzQyZjcwNmM2MTY5NmUzYjYzNjg2MTcyNzM2NTc0M2Q3NTc0NjYyZDM4MDAzNTdiMjI3MDIyM2EyMjYyNzI2MzJkMzIzMDIyMmMyMjZmNzAyMjNhMjI2ZDY5NmU3NDIyMmMyMjc0Njk2MzZiMjIzYTIyNmQ2NTZkNjUyMjJjMjI2MTZkNzQyMjNhMjIzMTMwMzAzMDIyN2Q2OCIsImMwOTgzNzFjMTA4ZjY1YWM5M2MyZDA4OTAwYTBlYjZlYWNlOTBhNTQ3MTg2ODAxZmEyNTJiNDNlNTdlN2UyNzU1MSJdLCJzZXF1ZW5jZSI6NDI5NDk2NzI5M31dLCJ2b3V0IjpbeyJ2YWx1ZSI6MC4wMDAwMDU0NiwibiI6MCwic2NyaXB0UHViS2V5Ijp7ImFzbSI6IjEgMmRlODUyMTQ4ZWQzMTY4ODU1NjRjNDQ2MmJkMGZkMDA2NjZkM2UwNzlkODUyMDE5ZTQxZjkwMjEyMDg3OGRkNSIsImhleCI6IjUxMjAyZGU4NTIxNDhlZDMxNjg4NTU2NGM0NDYyYmQwZmQwMDY2NmQzZTA3OWQ4NTIwMTllNDFmOTAyMTIwODc4ZGQ1IiwidHlwZSI6IndpdG5lc3NfdjFfdGFwcm9vdCJ9fSx7InZhbHVlIjowLjAwMDAwNjk3LCJuIjoxLCJzY3JpcHRQdWJLZXkiOnsiYXNtIjoiMSA3ZDk5MDMyYjgwMzQ3ZDAyY2U4NWNhN2RiYWNhNzVjMTBiNmNjNzE5MTFmNTk0YzQ0YmVkYWMyN2Q3YTIxYmU4IiwiaGV4IjoiNTEyMDdkOTkwMzJiODAzNDdkMDJjZTg1Y2E3ZGJhY2E3NWMxMGI2Y2M3MTkxMWY1OTRjNDRiZWRhYzI3ZDdhMjFiZTgiLCJ0eXBlIjoid2l0bmVzc192MV90YXByb290In19LHsidmFsdWUiOjAuMDAwMDA2OTcsIm4iOjIsInNjcmlwdFB1YktleSI6eyJhc20iOiIxIDhlZGIzMmUwM2ExOGVhZDAzM2I3ZTY2ZmJhOGRmOTI1OTQzZDQ3NDYxZTBkNDFmMTMyYTJkYzNiNDlmNTFjZDUiLCJoZXgiOiI1MTIwOGVkYjMyZTAzYTE4ZWFkMDMzYjdlNjZmYmE4ZGY5MjU5NDNkNDc0NjFlMGQ0MWYxMzJhMmRjM2I0OWY1MWNkNSIsInR5cGUiOiJ3aXRuZXNzX3YxX3RhcHJvb3QifX0seyJ2YWx1ZSI6MC4wMDAwMDY5NywibiI6Mywic2NyaXB0UHViS2V5Ijp7ImFzbSI6IjEgMWYzN2E5NTEyZWU1MTNiMjliOGVjYTAwZGJkZWJmOWJmYTllMGU1YTI2ZWI5Yjg2ZjAyNTI4MGUwY2MxN2NjZCIsImhleCI6IjUxMjAxZjM3YTk1MTJlZTUxM2IyOWI4ZWNhMDBkYmRlYmY5YmZhOWUwZTVhMjZlYjliODZmMDI1MjgwZTBjYzE3Y2NkIiwidHlwZSI6IndpdG5lc3NfdjFfdGFwcm9vdCJ9fSx7InZhbHVlIjowLjAwMDAwNjk3LCJuIjo0LCJzY3JpcHRQdWJLZXkiOnsiYXNtIjoiMSBkYTA2MDc4MmRjNjMwY2Y2ZTI0NGM5NTllNWE2Mzg4MTRlY2QxZDE0ZGUzM2IzMDg1YjhjNDc2NTMzMzBjM2Q0IiwiaGV4IjoiNTEyMGRhMDYwNzgyZGM2MzBjZjZlMjQ0Yzk1OWU1YTYzODgxNGVjZDFkMTRkZTMzYjMwODViOGM0NzY1MzMzMGMzZDQiLCJ0eXBlIjoid2l0bmVzc192MV90YXByb290In19LHsidmFsdWUiOjAuMDAwMDA2OTcsIm4iOjUsInNjcmlwdFB1YktleSI6eyJhc20iOiIxIGVmZDUyYmE0YjBkN2Y0M2ViYjkzY2E3MDQxNjI4MzJiNjQ0NjM3ZTZmMjI2NjJkZjliM2JmOWU3ZmMzOTI4ODkiLCJoZXgiOiI1MTIwZWZkNTJiYTRiMGQ3ZjQzZWJiOTNjYTcwNDE2MjgzMmI2NDQ2MzdlNmYyMjY2MmRmOWIzYmY5ZTdmYzM5Mjg4OSIsInR5cGUiOiJ3aXRuZXNzX3YxX3RhcHJvb3QifX0seyJ2YWx1ZSI6MC4wMDAwMDY5NywibiI6Niwic2NyaXB0UHViS2V5Ijp7ImFzbSI6IjEgZWM0N2VmYjg0MmMyMTI5NTY0MDdhY2IzMTMyYjJjYTYyYjlhMDI4ZGRiOTBjZTAyOGJjOTc2MDM2YmNiYzcwOSIsImhleCI6IjUxMjBlYzQ3ZWZiODQyYzIxMjk1NjQwN2FjYjMxMzJiMmNhNjJiOWEwMjhkZGI5MGNlMDI4YmM5NzYwMzZiY2JjNzA5IiwidHlwZSI6IndpdG5lc3NfdjFfdGFwcm9vdCJ9fSx7InZhbHVlIjowLjAwMDAwNjk3LCJuIjo3LCJzY3JpcHRQdWJLZXkiOnsiYXNtIjoiMSA1NTBhMmIwOTcyNzM5YTU1M2ZlNWMyNjBiNTM2MTZjODgxOGNkMjY3YzZmNGE2OTEwMTJkZjg2MDBjMTRmMDczIiwiaGV4IjoiNTEyMDU1MGEyYjA5NzI3MzlhNTUzZmU1YzI2MGI1MzYxNmM4ODE4Y2QyNjdjNmY0YTY5MTAxMmRmODYwMGMxNGYwNzMiLCJ0eXBlIjoid2l0bmVzc192MV90YXByb290In19LHsidmFsdWUiOjAuMDAwMDA2OTcsIm4iOjgsInNjcmlwdFB1YktleSI6eyJhc20iOiIxIDU1NDdhMzQ5MTkyZmIzNjgwYTBmNjJiYmQ0YWEzMWUwY2NkMzFhZjc1OWU3MGYxZTVmZjUyMWRmZGQ2NTBhMmQiLCJoZXgiOiI1MTIwNTU0N2EzNDkxOTJmYjM2ODBhMGY2MmJiZDRhYTMxZTBjY2QzMWFmNzU5ZTcwZjFlNWZmNTIxZGZkZDY1MGEyZCIsInR5cGUiOiJ3aXRuZXNzX3YxX3RhcHJvb3QifX0seyJ2YWx1ZSI6MC4wMDAwMDY5NywibiI6OSwic2NyaXB0UHViS2V5Ijp7ImFzbSI6IjEgOTczNmM1NmYzN2U0MjcxM2I3MTk1M2Y3MTk0OTgyYjQ1YTMyMjRiNWJjM2RlMmI3OTIzMDNiYjAxN2E4ZGQzYiIsImhleCI6IjUxMjA5NzM2YzU2ZjM3ZTQyNzEzYjcxOTUzZjcxOTQ5ODJiNDVhMzIyNGI1YmMzZGUyYjc5MjMwM2JiMDE3YThkZDNiIiwidHlwZSI6IndpdG5lc3NfdjFfdGFwcm9vdCJ9fSx7InZhbHVlIjowLjAwMDAwNjk3LCJuIjoxMCwic2NyaXB0UHViS2V5Ijp7ImFzbSI6IjEgMTBkOTA1ODZhMTQ1NDhiOWVkZGY5MWEwMDJiNmM0MzQ5ZjQ3OWM5ZmU4Mzg1MmMxZGRiMDYwYTZkMmI1NmFhZiIsImhleCI6IjUxMjAxMGQ5MDU4NmExNDU0OGI5ZWRkZjkxYTAwMmI2YzQzNDlmNDc5YzlmZTgzODUyYzFkZGIwNjBhNmQyYjU2YWFmIiwidHlwZSI6IndpdG5lc3NfdjFfdGFwcm9vdCJ9fSx7InZhbHVlIjowLjAwMDAwNjk3LCJuIjoxMSwic2NyaXB0UHViS2V5Ijp7ImFzbSI6IjEgMDY5NzhkZTYyMDc1MGE2NWUyNTkzOWNmOWVlNzA0YzFlMDNlMGI2ZGRlMjdjODJjYmQ3NzU0ZDM2NWNiYzBlNiIsImhleCI6IjUxMjAwNjk3OGRlNjIwNzUwYTY1ZTI1OTM5Y2Y5ZWU3MDRjMWUwM2UwYjZkZGUyN2M4MmNiZDc3NTRkMzY1Y2JjMGU2IiwidHlwZSI6IndpdG5lc3NfdjFfdGFwcm9vdCJ9fSx7InZhbHVlIjowLjAwMDAwNjk3LCJuIjoxMiwic2NyaXB0UHViS2V5Ijp7ImFzbSI6IjEgZDU2NGIwNzZlNDJkZTg0NDBmNWMzMjkyNzM5NjBkYTRmYTk5ZWNhNDRhN2NkYTRkNTAyNTNjMmM2Mzk0MDViZSIsImhleCI6IjUxMjBkNTY0YjA3NmU0MmRlODQ0MGY1YzMyOTI3Mzk2MGRhNGZhOTllY2E0NGE3Y2RhNGQ1MDI1M2MyYzYzOTQwNWJlIiwidHlwZSI6IndpdG5lc3NfdjFfdGFwcm9vdCJ9fSx7InZhbHVlIjowLjAwMDAwNjk3LCJuIjoxMywic2NyaXB0UHViS2V5Ijp7ImFzbSI6IjEgNzIzYzhlYTZhZjE4NTAwZWE5OTQxNzdjZjcwM2IwZGQ5YTQxYzJjMDlmNDIzMGFhNDE2ODljODA0MzY4YjljNiIsImhleCI6IjUxMjA3MjNjOGVhNmFmMTg1MDBlYTk5NDE3N2NmNzAzYjBkZDlhNDFjMmMwOWY0MjMwYWE0MTY4OWM4MDQzNjhiOWM2IiwidHlwZSI6IndpdG5lc3NfdjFfdGFwcm9vdCJ9fSx7InZhbHVlIjowLjAwMDAwNjk3LCJuIjoxNCwic2NyaXB0UHViS2V5Ijp7ImFzbSI6IjEgZTI5YzQwZGU3MTlmODFlOGI5ODg1NjUxYmQ0OTRlZTNlZWI5Zjk5MmJiNjY1M2U0MDg5MmU2OTdiOWYyYjkxNSIsImhleCI6IjUxMjBlMjljNDBkZTcxOWY4MWU4Yjk4ODU2NTFiZDQ5NGVlM2VlYjlmOTkyYmI2NjUzZTQwODkyZTY5N2I5ZjJiOTE1IiwidHlwZSI6IndpdG5lc3NfdjFfdGFwcm9vdCJ9fSx7InZhbHVlIjowLjAwMDAwNjk3LCJuIjoxNSwic2NyaXB0UHViS2V5Ijp7ImFzbSI6IjEgMWEzN2ZlMzI5MmJhMjkxMmQ0OTYyYzM4MWVmOTg4NWNlMjBkOGVhNzFjYjM5YjI1ZTZkNjdlOTY2YjNiNmU0OSIsImhleCI6IjUxMjAxYTM3ZmUzMjkyYmEyOTEyZDQ5NjJjMzgxZWY5ODg1Y2UyMGQ4ZWE3MWNiMzliMjVlNmQ2N2U5NjZiM2I2ZTQ5IiwidHlwZSI6IndpdG5lc3NfdjFfdGFwcm9vdCJ9fSx7InZhbHVlIjowLjAwMDAwNjk3LCJuIjoxNiwic2NyaXB0UHViS2V5Ijp7ImFzbSI6IjEgMjFkMmQyZTg3MmIyOWE1OTUwMDRkZGU0ZjZlMTYwODEwN2ExZWQ1MDA0Y2RjMGVlYzYzY2ExZjVkY2UxYzc0NCIsImhleCI6IjUxMjAyMWQyZDJlODcyYjI5YTU5NTAwNGRkZTRmNmUxNjA4MTA3YTFlZDUwMDRjZGMwZWVjNjNjYTFmNWRjZTFjNzQ0IiwidHlwZSI6IndpdG5lc3NfdjFfdGFwcm9vdCJ9fSx7InZhbHVlIjowLjAwMDAwNjk3LCJuIjoxNywic2NyaXB0UHViS2V5Ijp7ImFzbSI6IjEgNWQzMzI0ZDc1ZTQ5M2U1MmU0NDdjZDU3YmIzM2U0NmY5MmQyNzVhMjY5ZDMxZDA3NjE0ZjgxOTYzOWZhZmE3ZCIsImhleCI6IjUxMjA1ZDMzMjRkNzVlNDkzZTUyZTQ0N2NkNTdiYjMzZTQ2ZjkyZDI3NWEyNjlkMzFkMDc2MTRmODE5NjM5ZmFmYTdkIiwidHlwZSI6IndpdG5lc3NfdjFfdGFwcm9vdCJ9fSx7InZhbHVlIjowLjAwMDAwNjk3LCJuIjoxOCwic2NyaXB0UHViS2V5Ijp7ImFzbSI6IjEgY2QzMTFjODhlZDMwY2IxOTJjMDAyZmQ1OTEzZDU0N2VjMjlkMDk1NWQyNGViMzc3ODk0OWEzZTEyZDYxMGNjNSIsImhleCI6IjUxMjBjZDMxMWM4OGVkMzBjYjE5MmMwMDJmZDU5MTNkNTQ3ZWMyOWQwOTU1ZDI0ZWIzNzc4OTQ5YTNlMTJkNjEwY2M1IiwidHlwZSI6IndpdG5lc3NfdjFfdGFwcm9vdCJ9fSx7InZhbHVlIjowLjAwMDAwNjk3LCJuIjoxOSwic2NyaXB0UHViS2V5Ijp7ImFzbSI6IjEgMTU5ZGJiNjUyZjU1OTAzOGVmNTNiMmI1MWM0YTIxZWFlNDUxZTdmMGEzYmVmNjI5MWFkMDlkOTg2OGI4NzBhNCIsImhleCI6IjUxMjAxNTlkYmI2NTJmNTU5MDM4ZWY1M2IyYjUxYzRhMjFlYWU0NTFlN2YwYTNiZWY2MjkxYWQwOWQ5ODY4Yjg3MGE0IiwidHlwZSI6IndpdG5lc3NfdjFfdGFwcm9vdCJ9fSx7InZhbHVlIjowLjAwMDAwNjk3LCJuIjoyMCwic2NyaXB0UHViS2V5Ijp7ImFzbSI6IjEgNzdjOWZmMTczZDk3N2M4ZDcxODJlZjA0OWM0YmY2MDM5NGMwNjM2ODAyN2NmNjkyN2U0Yzg1MmFjYzNmNGU0NyIsImhleCI6IjUxMjA3N2M5ZmYxNzNkOTc3YzhkNzE4MmVmMDQ5YzRiZjYwMzk0YzA2MzY4MDI3Y2Y2OTI3ZTRjODUyYWNjM2Y0ZTQ3IiwidHlwZSI6IndpdG5lc3NfdjFfdGFwcm9vdCJ9fSx7InZhbHVlIjowLjAwMDAwNjk3LCJuIjoyMSwic2NyaXB0UHViS2V5Ijp7ImFzbSI6IjEgNzVjODc4YzQ1YTFiMjNlOGY3MTcyODg2ZmMwM2YwN2U5NjU1MmNlNjM4YzllZjhjMGFkNzFmYTg4ZTgzZjA5OCIsImhleCI6IjUxMjA3NWM4NzhjNDVhMWIyM2U4ZjcxNzI4ODZmYzAzZjA3ZTk2NTUyY2U2MzhjOWVmOGMwYWQ3MWZhODhlODNmMDk4IiwidHlwZSI6IndpdG5lc3NfdjFfdGFwcm9vdCJ9fSx7InZhbHVlIjowLjAwMDAwNjk3LCJuIjoyMiwic2NyaXB0UHViS2V5Ijp7ImFzbSI6IjEgNjEyNWI0NGU4NmVlNzFkYWIyYjE4ZGJlMjFhYmQzYjUyNzU5MmM1NGI4MzRlZTYyZmJlMzU0MDc0NTUyNDAzYSIsImhleCI6IjUxMjA2MTI1YjQ0ZTg2ZWU3MWRhYjJiMThkYmUyMWFiZDNiNTI3NTkyYzU0YjgzNGVlNjJmYmUzNTQwNzQ1NTI0MDNhIiwidHlwZSI6IndpdG5lc3NfdjFfdGFwcm9vdCJ9fSx7InZhbHVlIjowLjAwMDAwNjk3LCJuIjoyMywic2NyaXB0UHViS2V5Ijp7ImFzbSI6IjEgZGNhMjcwOWVkOWUyYzZhM2I2ODg4NGYzNjE0OWQwNDRjOTMyNzA3MGM0ZjIxZjE0ZDlhN2M4Mzc3ODRjNjIzYiIsImhleCI6IjUxMjBkY2EyNzA5ZWQ5ZTJjNmEzYjY4ODg0ZjM2MTQ5ZDA0NGM5MzI3MDcwYzRmMjFmMTRkOWE3YzgzNzc4NGM2MjNiIiwidHlwZSI6IndpdG5lc3NfdjFfdGFwcm9vdCJ9fSx7InZhbHVlIjowLjAwMDAwNjk3LCJuIjoyNCwic2NyaXB0UHViS2V5Ijp7ImFzbSI6IjEgMDlhMTUwYmQ5Zjc1OTZiYmI5ODAyMDM5MjY0MmViOWEyMTc2ZTAyYzdiNTk0NzlhODM0MDQxODExZDM2MDA3ZSIsImhleCI6IjUxMjAwOWExNTBiZDlmNzU5NmJiYjk4MDIwMzkyNjQyZWI5YTIxNzZlMDJjN2I1OTQ3OWE4MzQwNDE4MTFkMzYwMDdlIiwidHlwZSI6IndpdG5lc3NfdjFfdGFwcm9vdCJ9fSx7InZhbHVlIjowLjAwMDAwNjk3LCJuIjoyNSwic2NyaXB0UHViS2V5Ijp7ImFzbSI6IjEgMzlmY2M2YzExZmExYTNhYTk0NWZlMjJkOGZhN2E4ZjY2ZjU2OTVjZDhkZjM5ZjkwMjc4Mzg0NGM5ZTg5YTQ5NSIsImhleCI6IjUxMjAzOWZjYzZjMTFmYTFhM2FhOTQ1ZmUyMmQ4ZmE3YThmNjZmNTY5NWNkOGRmMzlmOTAyNzgzODQ0YzllODlhNDk1IiwidHlwZSI6IndpdG5lc3NfdjFfdGFwcm9vdCJ9fSx7InZhbHVlIjowLjAwMDAwNjk3LCJuIjoyNiwic2NyaXB0UHViS2V5Ijp7ImFzbSI6IjEgNzBhNzQ2MTVlNGJiMTBmOTc0YmY2ZmI2MzJhYTM1ZmY0ZmVjNWU5ZmU5ZGJhMjJmYzk5ZDg3ODMzNTg1NzA2ZSIsImhleCI6IjUxMjA3MGE3NDYxNWU0YmIxMGY5NzRiZjZmYjYzMmFhMzVmZjRmZWM1ZTlmZTlkYmEyMmZjOTlkODc4MzM1ODU3MDZlIiwidHlwZSI6IndpdG5lc3NfdjFfdGFwcm9vdCJ9fSx7InZhbHVlIjowLjAwMDAwNjk3LCJuIjoyNywic2NyaXB0UHViS2V5Ijp7ImFzbSI6IjEgNjhlZTZkZmZmNGY5ZjE0ZjI5NjZmNmM2YmRkNDIyMzBjYWJjNjY2N2I3NzE4YjZlZGU0ZTFkMDQ1ZTM2Yzg0NSIsImhleCI6IjUxMjA2OGVlNmRmZmY0ZjlmMTRmMjk2NmY2YzZiZGQ0MjIzMGNhYmM2NjY3Yjc3MThiNmVkZTRlMWQwNDVlMzZjODQ1IiwidHlwZSI6IndpdG5lc3NfdjFfdGFwcm9vdCJ9fSx7InZhbHVlIjowLjAwMDAwNjk3LCJuIjoyOCwic2NyaXB0UHViS2V5Ijp7ImFzbSI6IjEgNWFiZjA4MjI5NWM2MTkxYWE3MWQ5OGY4MDk4NTNkNWExNGI1M2MyZTg2YWRiNWI2NTc4ZjBhNmFhZjM4NmVmYSIsImhleCI6IjUxMjA1YWJmMDgyMjk1YzYxOTFhYTcxZDk4ZjgwOTg1M2Q1YTE0YjUzYzJlODZhZGI1YjY1NzhmMGE2YWFmMzg2ZWZhIiwidHlwZSI6IndpdG5lc3NfdjFfdGFwcm9vdCJ9fSx7InZhbHVlIjowLjAwMDAwNjk3LCJuIjoyOSwic2NyaXB0UHViS2V5Ijp7ImFzbSI6IjEgYzQ2NWQ0YWRlNGNhNmMwY2YyZjE1NGU3NTFlYzhkYTU4ZjZhMzIyZjg5OGRmNmM4MGVhZDVlYTM1YjU0MTRjMCIsImhleCI6IjUxMjBjNDY1ZDRhZGU0Y2E2YzBjZjJmMTU0ZTc1MWVjOGRhNThmNmEzMjJmODk4ZGY2YzgwZWFkNWVhMzViNTQxNGMwIiwidHlwZSI6IndpdG5lc3NfdjFfdGFwcm9vdCJ9fSx7InZhbHVlIjowLjAwMDAwNjk3LCJuIjozMCwic2NyaXB0UHViS2V5Ijp7ImFzbSI6IjEgMWRjNGZhYjg5NTJmNGYxZWY5NzM5YTgzZDUxZGJiMjM3ZmZmNDQ2NjIyNTIyZjFmZTQ2ZGZjMjBhZDY0ZTg2YSIsImhleCI6IjUxMjAxZGM0ZmFiODk1MmY0ZjFlZjk3MzlhODNkNTFkYmIyMzdmZmY0NDY2MjI1MjJmMWZlNDZkZmMyMGFkNjRlODZhIiwidHlwZSI6IndpdG5lc3NfdjFfdGFwcm9vdCJ9fSx7InZhbHVlIjowLjAwMDAwNjk3LCJuIjozMSwic2NyaXB0UHViS2V5Ijp7ImFzbSI6IjEgYjJjODFlZTQzMGYyMDU4MWFlZmIzNWFmYzg3ZTc2ZWMzZmY2M2JmZjY0OTA3OWI0Y2JhYWNmODc3NTc5MGVkNyIsImhleCI6IjUxMjBiMmM4MWVlNDMwZjIwNTgxYWVmYjM1YWZjODdlNzZlYzNmZjYzYmZmNjQ5MDc5YjRjYmFhY2Y4Nzc1NzkwZWQ3IiwidHlwZSI6IndpdG5lc3NfdjFfdGFwcm9vdCJ9fSx7InZhbHVlIjowLjAwMDAwNjk3LCJuIjozMiwic2NyaXB0UHViS2V5Ijp7ImFzbSI6IjEgODM3MTJkZDMyNjJkMTJjOTYwMDNkMDBkMzkwM2MxZGUzMTVkNmNlMThkYTI1YjMyNjkzODJjNTY0NDI3ZDU2MyIsImhleCI6IjUxMjA4MzcxMmRkMzI2MmQxMmM5NjAwM2QwMGQzOTAzYzFkZTMxNWQ2Y2UxOGRhMjViMzI2OTM4MmM1NjQ0MjdkNTYzIiwidHlwZSI6IndpdG5lc3NfdjFfdGFwcm9vdCJ9fSx7InZhbHVlIjowLjAwMDAwNjk3LCJuIjozMywic2NyaXB0UHViS2V5Ijp7ImFzbSI6IjEgMGFlYjIxYTNlMzY0MTVhNjJkYzFhYjFmMWJiODMwMmQ2MjUwYWIxMjUxN2E5NWI4MWVmZDlmNjk3OTZiYTQ1YiIsImhleCI6IjUxMjAwYWViMjFhM2UzNjQxNWE2MmRjMWFiMWYxYmI4MzAyZDYyNTBhYjEyNTE3YTk1YjgxZWZkOWY2OTc5NmJhNDViIiwidHlwZSI6IndpdG5lc3NfdjFfdGFwcm9vdCJ9fSx7InZhbHVlIjowLjAwMDAwNjk3LCJuIjozNCwic2NyaXB0UHViS2V5Ijp7ImFzbSI6IjEgMTExMDQ4MTAyM2MwODQ5OGE1ZGI1ZGRlODM2MDMyMmNiNWUzZjRlOTNhYTY0NWI1YmNhM2Q1MjA4MjEyM2ZlNCIsImhleCI6IjUxMjAxMTEwNDgxMDIzYzA4NDk4YTVkYjVkZGU4MzYwMzIyY2I1ZTNmNGU5M2FhNjQ1YjViY2EzZDUyMDgyMTIzZmU0IiwidHlwZSI6IndpdG5lc3NfdjFfdGFwcm9vdCJ9fSx7InZhbHVlIjowLjAwMDAwNjk3LCJuIjozNSwic2NyaXB0UHViS2V5Ijp7ImFzbSI6IjEgMWU4OGQ4OTI4ODFlYjY0NDY2MWIwYzkyNTY3ZDQ2OWNmN2U0OTdlYjA1MDFmNjk1MjBkZGQ4NDg4NTM1NjIzYyIsImhleCI6IjUxMjAxZTg4ZDg5Mjg4MWViNjQ0NjYxYjBjOTI1NjdkNDY5Y2Y3ZTQ5N2ViMDUwMWY2OTUyMGRkZDg0ODg1MzU2MjNjIiwidHlwZSI6IndpdG5lc3NfdjFfdGFwcm9vdCJ9fSx7InZhbHVlIjowLjAwMDAwNjk3LCJuIjozNiwic2NyaXB0UHViS2V5Ijp7ImFzbSI6IjEgMTNhOWJhMGE4M2VkZTU4ODExNDczNTU2MjEzODZkOTI2MjlmNjZjZjUzMjZiOTY5OTc2YjAzNGRhZDk4OWNlZSIsImhleCI6IjUxMjAxM2E5YmEwYTgzZWRlNTg4MTE0NzM1NTYyMTM4NmQ5MjYyOWY2NmNmNTMyNmI5Njk5NzZiMDM0ZGFkOTg5Y2VlIiwidHlwZSI6IndpdG5lc3NfdjFfdGFwcm9vdCJ9fSx7InZhbHVlIjowLjAwMDAwNjk3LCJuIjozNywic2NyaXB0UHViS2V5Ijp7ImFzbSI6IjEgMjBhOTEyMGY1Y2YxNDBlMWQ0ZDRjOTUxNDUyYjUyM2IxMGQ2NGRjMDVhOWNhYzUwZDY4ZTk4MDMxOWM5ZDk2MiIsImhleCI6IjUxMjAyMGE5MTIwZjVjZjE0MGUxZDRkNGM5NTE0NTJiNTIzYjEwZDY0ZGMwNWE5Y2FjNTBkNjhlOTgwMzE5YzlkOTYyIiwidHlwZSI6IndpdG5lc3NfdjFfdGFwcm9vdCJ9fSx7InZhbHVlIjowLjAwMDAwNjk3LCJuIjozOCwic2NyaXB0UHViS2V5Ijp7ImFzbSI6IjEgZmUwM2NjY2UwYWEyZmZkZGRmM2E0OThmZmFiMTU0MmJkNGFlZTZiYTcxNzA3ODI1ZTU0OWFkNmE3YmNlMjg0YSIsImhleCI6IjUxMjBmZTAzY2NjZTBhYTJmZmRkZGYzYTQ5OGZmYWIxNTQyYmQ0YWVlNmJhNzE3MDc4MjVlNTQ5YWQ2YTdiY2UyODRhIiwidHlwZSI6IndpdG5lc3NfdjFfdGFwcm9vdCJ9fSx7InZhbHVlIjowLjAwMDAwNjk3LCJuIjozOSwic2NyaXB0UHViS2V5Ijp7ImFzbSI6IjEgNWZhN2Y1MzUxYzkyYjI4OGJhNWQzMTNkYjYxMzczMjQ0ZDU5Y2U2NDA1ZWUzOWViZWUxOWY2ODM0MDA1YzJlYSIsImhleCI6IjUxMjA1ZmE3ZjUzNTFjOTJiMjg4YmE1ZDMxM2RiNjEzNzMyNDRkNTljZTY0MDVlZTM5ZWJlZTE5ZjY4MzQwMDVjMmVhIiwidHlwZSI6IndpdG5lc3NfdjFfdGFwcm9vdCJ9fSx7InZhbHVlIjowLjAwMDAwNjk3LCJuIjo0MCwic2NyaXB0UHViS2V5Ijp7ImFzbSI6IjEgNjliOTkxNzc5NjE4MDU3YjNhYzA3N2JjNzhkZjZiN2UxY2M3ZjQzNTQ1YzE5YjZlMzIwYjRlOGE3ZTFiYmMyZiIsImhleCI6IjUxMjA2OWI5OTE3Nzk2MTgwNTdiM2FjMDc3YmM3OGRmNmI3ZTFjYzdmNDM1NDVjMTliNmUzMjBiNGU4YTdlMWJiYzJmIiwidHlwZSI6IndpdG5lc3NfdjFfdGFwcm9vdCJ9fSx7InZhbHVlIjowLjAwMDAwNjk3LCJuIjo0MSwic2NyaXB0UHViS2V5Ijp7ImFzbSI6IjEgNGVhODJjNWE4MDdmMWRjYmZmMGFmMDdhOWI5N2E4ZmViNjQ5MTNhOWJmMWViOGI5NTRjNTZiNGRjMWE3MDljYyIsImhleCI6IjUxMjA0ZWE4MmM1YTgwN2YxZGNiZmYwYWYwN2E5Yjk3YThmZWI2NDkxM2E5YmYxZWI4Yjk1NGM1NmI0ZGMxYTcwOWNjIiwidHlwZSI6IndpdG5lc3NfdjFfdGFwcm9vdCJ9fSx7InZhbHVlIjowLjAwMDAwNjk3LCJuIjo0Miwic2NyaXB0UHViS2V5Ijp7ImFzbSI6IjEgZWJjYjNhZTk1MGQwZTcxZGM5ZjFjNDNiZjk0YjhhMGZkODZiZDQwN2ZjNWNhOWE5OWZmMGNlNmYwN2RkNjFhMCIsImhleCI6IjUxMjBlYmNiM2FlOTUwZDBlNzFkYzlmMWM0M2JmOTRiOGEwZmQ4NmJkNDA3ZmM1Y2E5YTk5ZmYwY2U2ZjA3ZGQ2MWEwIiwidHlwZSI6IndpdG5lc3NfdjFfdGFwcm9vdCJ9fSx7InZhbHVlIjowLjAwMDAwNjk3LCJuIjo0Mywic2NyaXB0UHViS2V5Ijp7ImFzbSI6IjEgZThkZWFiOTY4YWY1ZmQwZTFhODZjYTBiNzE4ODU0MDkwNmViYTczNTc3M2Y4Y2VkMjNlYTNjZDI1NTg4ZWRiNSIsImhleCI6IjUxMjBlOGRlYWI5NjhhZjVmZDBlMWE4NmNhMGI3MTg4NTQwOTA2ZWJhNzM1NzczZjhjZWQyM2VhM2NkMjU1ODhlZGI1IiwidHlwZSI6IndpdG5lc3NfdjFfdGFwcm9vdCJ9fSx7InZhbHVlIjowLjAwMDAwNjk3LCJuIjo0NCwic2NyaXB0UHViS2V5Ijp7ImFzbSI6IjEgMjdmMGQyODBmNjA5YWU5MDczZjAwZTM2ZTRmZDJiNDdmMWE5NTc4ZjVlYTYxYWQ5ZDM1ZGNjMzUzY2E3Yjg5MyIsImhleCI6IjUxMjAyN2YwZDI4MGY2MDlhZTkwNzNmMDBlMzZlNGZkMmI0N2YxYTk1NzhmNWVhNjFhZDlkMzVkY2MzNTNjYTdiODkzIiwidHlwZSI6IndpdG5lc3NfdjFfdGFwcm9vdCJ9fSx7InZhbHVlIjowLjAwMDAwNjk3LCJuIjo0NSwic2NyaXB0UHViS2V5Ijp7ImFzbSI6IjEgMDA0NTk4MjBhNjE3YWNmMDQwNDFhMDNkNDdkMzQ1MTM5ZmU3ODIyYjE3NjNlMmRhM2I3YjU1NzVjN2NmZWMwYiIsImhleCI6IjUxMjAwMDQ1OTgyMGE2MTdhY2YwNDA0MWEwM2Q0N2QzNDUxMzlmZTc4MjJiMTc2M2UyZGEzYjdiNTU3NWM3Y2ZlYzBiIiwidHlwZSI6IndpdG5lc3NfdjFfdGFwcm9vdCJ9fSx7InZhbHVlIjowLjAwMDAwNjk3LCJuIjo0Niwic2NyaXB0UHViS2V5Ijp7ImFzbSI6IjEgZmQ2MjhlZWQ2MTQ0ODc0NGI1NTU3MzE2YmY5MTQ2YTJkMzMxYWY1MDJhODRhN2E0MmE4NzE0ZGMwM2Q0ZDkwZCIsImhleCI6IjUxMjBmZDYyOGVlZDYxNDQ4NzQ0YjU1NTczMTZiZjkxNDZhMmQzMzFhZjUwMmE4NGE3YTQyYTg3MTRkYzAzZDRkOTBkIiwidHlwZSI6IndpdG5lc3NfdjFfdGFwcm9vdCJ9fSx7InZhbHVlIjowLjAwMDAwNjk3LCJuIjo0Nywic2NyaXB0UHViS2V5Ijp7ImFzbSI6IjEgMDZjZDc1NzlmNDk4Y2FkODQyZjdlZGFiNWM4NTIzMjJjMjg0OGVkMzA0MzBlZGVmOWZhNWYyYzNkMGFkYzE2MyIsImhleCI6IjUxMjAwNmNkNzU3OWY0OThjYWQ4NDJmN2VkYWI1Yzg1MjMyMmMyODQ4ZWQzMDQzMGVkZWY5ZmE1ZjJjM2QwYWRjMTYzIiwidHlwZSI6IndpdG5lc3NfdjFfdGFwcm9vdCJ9fSx7InZhbHVlIjowLjAwMDAwNjk3LCJuIjo0OCwic2NyaXB0UHViS2V5Ijp7ImFzbSI6IjEgYTNiYmRiNDBjYWU2ZWIzY2I0YjNjM2FhYzFjNDM0ODY4ZDAyMWJmMDIwYmMyMjM5NDI1MGNhYTNiNDYxNTRlMSIsImhleCI6IjUxMjBhM2JiZGI0MGNhZTZlYjNjYjRiM2MzYWFjMWM0MzQ4NjhkMDIxYmYwMjBiYzIyMzk0MjUwY2FhM2I0NjE1NGUxIiwidHlwZSI6IndpdG5lc3NfdjFfdGFwcm9vdCJ9fSx7InZhbHVlIjowLjAwMDAwNjk3LCJuIjo0OSwic2NyaXB0UHViS2V5Ijp7ImFzbSI6IjEgNzllY2I3NTM5YWY2ZWJjNTI4ZmQxYzcxMDViMGM5ZDYzNzFiNWYyYmFkMDMzNjNjMzZjNDczODE2MjU0ZWM4MCIsImhleCI6IjUxMjA3OWVjYjc1MzlhZjZlYmM1MjhmZDFjNzEwNWIwYzlkNjM3MWI1ZjJiYWQwMzM2M2MzNmM0NzM4MTYyNTRlYzgwIiwidHlwZSI6IndpdG5lc3NfdjFfdGFwcm9vdCJ9fSx7InZhbHVlIjowLjAwMDAwNjk3LCJuIjo1MCwic2NyaXB0UHViS2V5Ijp7ImFzbSI6IjEgOThhNGRhOWM4MmE3NWFlZDBhMmY5ZGQ4NzhlNTlkOTg2YjJhOGU1OTAyYzhjOTE4YmNiNGVkNjE4ZWI5MWIyMCIsImhleCI6IjUxMjA5OGE0ZGE5YzgyYTc1YWVkMGEyZjlkZDg3OGU1OWQ5ODZiMmE4ZTU5MDJjOGM5MThiY2I0ZWQ2MThlYjkxYjIwIiwidHlwZSI6IndpdG5lc3NfdjFfdGFwcm9vdCJ9fSx7InZhbHVlIjowLjAwMDAwNjk3LCJuIjo1MSwic2NyaXB0UHViS2V5Ijp7ImFzbSI6IjEgYWViMDcwYWViNjdmYzlhZmU3N2Y5YmQzMTdmMTNjMTY2YmQ0MDdiMTY5OTZjOGNiODIxZGEwMjdmZDg4MjhhZSIsImhleCI6IjUxMjBhZWIwNzBhZWI2N2ZjOWFmZTc3ZjliZDMxN2YxM2MxNjZiZDQwN2IxNjk5NmM4Y2I4MjFkYTAyN2ZkODgyOGFlIiwidHlwZSI6IndpdG5lc3NfdjFfdGFwcm9vdCJ9fSx7InZhbHVlIjowLjAwMDAwNjk3LCJuIjo1Miwic2NyaXB0UHViS2V5Ijp7ImFzbSI6IjEgMDljM2QxYzhiMDBlZjE1MDVkZTU0ZWQ0M2U1NmRhYzA4ZDEwMmU0MGEwNGYyYjY3OWY0YjRmNWFiODcwMDQ3MSIsImhleCI6IjUxMjAwOWMzZDFjOGIwMGVmMTUwNWRlNTRlZDQzZTU2ZGFjMDhkMTAyZTQwYTA0ZjJiNjc5ZjRiNGY1YWI4NzAwNDcxIiwidHlwZSI6IndpdG5lc3NfdjFfdGFwcm9vdCJ9fSx7InZhbHVlIjowLjAwMDAwNjk3LCJuIjo1Mywic2NyaXB0UHViS2V5Ijp7ImFzbSI6IjEgOTc0OTc4NWY3NTQ0MWJiOWFmMzAwZjdiYjJhNjZmOWM4M2Y3MDA3N2QyMDU5ODIxYmVkODgzNjNkZmVlZGVmMyIsImhleCI6IjUxMjA5NzQ5Nzg1Zjc1NDQxYmI5YWYzMDBmN2JiMmE2NmY5YzgzZjcwMDc3ZDIwNTk4MjFiZWQ4ODM2M2RmZWVkZWYzIiwidHlwZSI6IndpdG5lc3NfdjFfdGFwcm9vdCJ9fSx7InZhbHVlIjowLjAwMDAwNjk3LCJuIjo1NCwic2NyaXB0UHViS2V5Ijp7ImFzbSI6IjEgMzY2NmFlMDdiZTU2NDE5ZGQ4YWU5MmYyMDhjNTM0ZGY2YzkyODA4MDBhYmIwZWViN2I0ODNiZDRiYTEzZjgwZiIsImhleCI6IjUxMjAzNjY2YWUwN2JlNTY0MTlkZDhhZTkyZjIwOGM1MzRkZjZjOTI4MDgwMGFiYjBlZWI3YjQ4M2JkNGJhMTNmODBmIiwidHlwZSI6IndpdG5lc3NfdjFfdGFwcm9vdCJ9fSx7InZhbHVlIjowLjAwMDAwNjk3LCJuIjo1NSwic2NyaXB0UHViS2V5Ijp7ImFzbSI6IjEgZTRhZTU0Y2IxNTBlZmQxODliZDJlZDRhYjVmNGZlY2JiOWEwYzU2MmZlZGQ5MmIwOGQ5OTYxMzExOTFkNzBjOSIsImhleCI6IjUxMjBlNGFlNTRjYjE1MGVmZDE4OWJkMmVkNGFiNWY0ZmVjYmI5YTBjNTYyZmVkZDkyYjA4ZDk5NjEzMTE5MWQ3MGM5IiwidHlwZSI6IndpdG5lc3NfdjFfdGFwcm9vdCJ9fSx7InZhbHVlIjowLjAwMDAwNjk3LCJuIjo1Niwic2NyaXB0UHViS2V5Ijp7ImFzbSI6IjEgOWRkZTg0MTYxOTNjOWY5NjQxMzVmNDJmNjllOTczM2Q2YWNjNzU3ZThiN2UwZDM3ZjY1OTQ3NmRkNDUwYmFjMiIsImhleCI6IjUxMjA5ZGRlODQxNjE5M2M5Zjk2NDEzNWY0MmY2OWU5NzMzZDZhY2M3NTdlOGI3ZTBkMzdmNjU5NDc2ZGQ0NTBiYWMyIiwidHlwZSI6IndpdG5lc3NfdjFfdGFwcm9vdCJ9fSx7InZhbHVlIjowLjAwMDAwNjk3LCJuIjo1Nywic2NyaXB0UHViS2V5Ijp7ImFzbSI6IjEgODVmYjVjOTVjMmE5OTVhNTI5NDk1ZGFiZGE2MzE0ZjdlY2EwZTM3YWU4MmRiM2ViYzU2MTNlYzAwNzU0Mzk3MSIsImhleCI6IjUxMjA4NWZiNWM5NWMyYTk5NWE1Mjk0OTVkYWJkYTYzMTRmN2VjYTBlMzdhZTgyZGIzZWJjNTYxM2VjMDA3NTQzOTcxIiwidHlwZSI6IndpdG5lc3NfdjFfdGFwcm9vdCJ9fSx7InZhbHVlIjowLjAwMDAwNjk3LCJuIjo1OCwic2NyaXB0UHViS2V5Ijp7ImFzbSI6IjEgYTUwYWE3ODRkMDdlNWE2MTRjNGYzOWE2OTlkNDU0NGU5NzkyNmI5MWMwYjk1YzQxNTY5ZjA0ZTQ0ZTVlN2JkZiIsImhleCI6IjUxMjBhNTBhYTc4NGQwN2U1YTYxNGM0ZjM5YTY5OWQ0NTQ0ZTk3OTI2YjkxYzBiOTVjNDE1NjlmMDRlNDRlNWU3YmRmIiwidHlwZSI6IndpdG5lc3NfdjFfdGFwcm9vdCJ9fSx7InZhbHVlIjowLjAwMDAwNjk3LCJuIjo1OSwic2NyaXB0UHViS2V5Ijp7ImFzbSI6IjEgZWU3MGZiYTc3OTY5MTJmNmMwNGZiMjRhOGM4M2NiZDE0YmVjYzk4ZWIyMzA4NTIxMmU3MWViYzljMWFlNmYxYSIsImhleCI6IjUxMjBlZTcwZmJhNzc5NjkxMmY2YzA0ZmIyNGE4YzgzY2JkMTRiZWNjOThlYjIzMDg1MjEyZTcxZWJjOWMxYWU2ZjFhIiwidHlwZSI6IndpdG5lc3NfdjFfdGFwcm9vdCJ9fSx7InZhbHVlIjowLjAwMDAwNjk3LCJuIjo2MCwic2NyaXB0UHViS2V5Ijp7ImFzbSI6IjEgZDY2MmM3OTk5NWYyZmUzY2RmNzIxNDRhMTM4NDJhZWQ4YTU0OTE0YjNmNDI5MGIwZWYwNzljNmUzZDcwNjc1MCIsImhleCI6IjUxMjBkNjYyYzc5OTk1ZjJmZTNjZGY3MjE0NGExMzg0MmFlZDhhNTQ5MTRiM2Y0MjkwYjBlZjA3OWM2ZTNkNzA2NzUwIiwidHlwZSI6IndpdG5lc3NfdjFfdGFwcm9vdCJ9fSx7InZhbHVlIjowLjAwMDAwNjk3LCJuIjo2MSwic2NyaXB0UHViS2V5Ijp7ImFzbSI6IjEgN2FmOGExN2M1OWI2ZWUwODFlNTUxZWRkNGVlNWVhZTg5ZjAyOTE1ZTU2OWQyZjYzZjVmZWJkYWEwMTdkNmQxYyIsImhleCI6IjUxMjA3YWY4YTE3YzU5YjZlZTA4MWU1NTFlZGQ0ZWU1ZWFlODlmMDI5MTVlNTY5ZDJmNjNmNWZlYmRhYTAxN2Q2ZDFjIiwidHlwZSI6IndpdG5lc3NfdjFfdGFwcm9vdCJ9fSx7InZhbHVlIjowLjAwMDAwNjk3LCJuIjo2Miwic2NyaXB0UHViS2V5Ijp7ImFzbSI6IjEgYjI5ODU3ZWNiY2ExNzc4YzYzNTc0ZTI1MDUwZDNiZGUwYzE1NjAyMmFmMWVjNzdiY2MwNWVlYTgxY2NhYjJiYyIsImhleCI6IjUxMjBiMjk4NTdlY2JjYTE3NzhjNjM1NzRlMjUwNTBkM2JkZTBjMTU2MDIyYWYxZWM3N2JjYzA1ZWVhODFjY2FiMmJjIiwidHlwZSI6IndpdG5lc3NfdjFfdGFwcm9vdCJ9fSx7InZhbHVlIjowLjAwMDAwNjk3LCJuIjo2Mywic2NyaXB0UHViS2V5Ijp7ImFzbSI6IjEgMTI1YmM3ZTM3YmE5Y2UzM2UxNjZiNTVmZWRhZDA5NDNjYTNiNWRlYjUxN2M0NTFiOTRhMDNjZTk1NjQ1NmRmNSIsImhleCI6IjUxMjAxMjViYzdlMzdiYTljZTMzZTE2NmI1NWZlZGFkMDk0M2NhM2I1ZGViNTE3YzQ1MWI5NGEwM2NlOTU2NDU2ZGY1IiwidHlwZSI6IndpdG5lc3NfdjFfdGFwcm9vdCJ9fSx7InZhbHVlIjowLjAwMDAwNjk3LCJuIjo2NCwic2NyaXB0UHViS2V5Ijp7ImFzbSI6IjEgZGU4NGI4ZGUyMGY5MTg1NTgyZDQ4M2JhZDk5Nzg2Nzc3ZDQ0NjMyMmZiZTU4NjJkZjY1YzRiYmM5MGVhMGU0OSIsImhleCI6IjUxMjBkZTg0YjhkZTIwZjkxODU1ODJkNDgzYmFkOTk3ODY3NzdkNDQ2MzIyZmJlNTg2MmRmNjVjNGJiYzkwZWEwZTQ5IiwidHlwZSI6IndpdG5lc3NfdjFfdGFwcm9vdCJ9fSx7InZhbHVlIjowLjAwMDAwNjk3LCJuIjo2NSwic2NyaXB0UHViS2V5Ijp7ImFzbSI6IjEgNWJiZmQxODZjOWVkMzRiN2FiM2UzMDNmNzFiNmViODU0MjMwODQ3OWQyMWNlNGQ3YTliYTQzMDBmZjYyZTYzMiIsImhleCI6IjUxMjA1YmJmZDE4NmM5ZWQzNGI3YWIzZTMwM2Y3MWI2ZWI4NTQyMzA4NDc5ZDIxY2U0ZDdhOWJhNDMwMGZmNjJlNjMyIiwidHlwZSI6IndpdG5lc3NfdjFfdGFwcm9vdCJ9fSx7InZhbHVlIjowLjAwMDAwNjk3LCJuIjo2Niwic2NyaXB0UHViS2V5Ijp7ImFzbSI6IjEgNmM4ZGVhYjM1YmI4ZmI3NDY5ZWJhZWU4MDk5MmE4YTk3NmY0OGNkNzA1N2NkODVmZjRkYzAwYTkyODdlYmIxZCIsImhleCI6IjUxMjA2YzhkZWFiMzViYjhmYjc0NjllYmFlZTgwOTkyYThhOTc2ZjQ4Y2Q3MDU3Y2Q4NWZmNGRjMDBhOTI4N2ViYjFkIiwidHlwZSI6IndpdG5lc3NfdjFfdGFwcm9vdCJ9fSx7InZhbHVlIjowLjAwMDAwNjk3LCJuIjo2Nywic2NyaXB0UHViS2V5Ijp7ImFzbSI6IjEgYjljNzljNTM4Mjg1YjZkNzg3YjNiNmZkNDk5NWU1ZjExMDBiM2U3OTQzNTJmOWNiNmE5MzQ0ZGFiZGNjZTM5YSIsImhleCI6IjUxMjBiOWM3OWM1MzgyODViNmQ3ODdiM2I2ZmQ0OTk1ZTVmMTEwMGIzZTc5NDM1MmY5Y2I2YTkzNDRkYWJkY2NlMzlhIiwidHlwZSI6IndpdG5lc3NfdjFfdGFwcm9vdCJ9fSx7InZhbHVlIjowLjAwMDAwNjk3LCJuIjo2OCwic2NyaXB0UHViS2V5Ijp7ImFzbSI6IjEgY2FlYmNhMzEwMDA2YWFlYzNiMTcwMTc4NTY1ZjliODMyNDIxMzUzZDE4ZGNmNTRkNzBkMDQ3ZTcwNzNkMjQxNyIsImhleCI6IjUxMjBjYWViY2EzMTAwMDZhYWVjM2IxNzAxNzg1NjVmOWI4MzI0MjEzNTNkMThkY2Y1NGQ3MGQwNDdlNzA3M2QyNDE3IiwidHlwZSI6IndpdG5lc3NfdjFfdGFwcm9vdCJ9fSx7InZhbHVlIjowLjAwMDAwNjk3LCJuIjo2OSwic2NyaXB0UHViS2V5Ijp7ImFzbSI6IjEgZjExYmYzOTI2YjcwMjBhOWMzOGI4NmU2Mzg5NmZkZjZmMzk5OTM5NmVjODhlNDI2NDU0ZTM3YzU4ODFhODA3NyIsImhleCI6IjUxMjBmMTFiZjM5MjZiNzAyMGE5YzM4Yjg2ZTYzODk2ZmRmNmYzOTk5Mzk2ZWM4OGU0MjY0NTRlMzdjNTg4MWE4MDc3IiwidHlwZSI6IndpdG5lc3NfdjFfdGFwcm9vdCJ9fSx7InZhbHVlIjowLjAwMDAwNjk3LCJuIjo3MCwic2NyaXB0UHViS2V5Ijp7ImFzbSI6IjEgMGE5MTQ4MjZlMWZiN2FjNzFmMjExNWFlNDhhOGM3YTg0YTRmYjZjNWEyMDczNDM3N2Q3YjgyZmVkMzEyNjRjYyIsImhleCI6IjUxMjAwYTkxNDgyNmUxZmI3YWM3MWYyMTE1YWU0OGE4YzdhODRhNGZiNmM1YTIwNzM0Mzc3ZDdiODJmZWQzMTI2NGNjIiwidHlwZSI6IndpdG5lc3NfdjFfdGFwcm9vdCJ9fSx7InZhbHVlIjowLjAwMDAwNjk3LCJuIjo3MSwic2NyaXB0UHViS2V5Ijp7ImFzbSI6IjEgMzc1ZGI4N2Q3OGEzZmRjZDdmNzljOTY2OWQ5MDY4NjVmMDlmZDdkNTA4MmVmMzFmNTRiMWY2NTVjYTUxNjAxNyIsImhleCI6IjUxMjAzNzVkYjg3ZDc4YTNmZGNkN2Y3OWM5NjY5ZDkwNjg2NWYwOWZkN2Q1MDgyZWYzMWY1NGIxZjY1NWNhNTE2MDE3IiwidHlwZSI6IndpdG5lc3NfdjFfdGFwcm9vdCJ9fSx7InZhbHVlIjowLjAwMDAwNjk3LCJuIjo3Miwic2NyaXB0UHViS2V5Ijp7ImFzbSI6IjEgNWNlNDc5MzI2OWFiMTJlZmQxNGMyZTY2OTYyNmRmZDJlOTIyYWE3ZWEzOWJkZDM0NmY0MWFmOWQxZGYzNmQxZSIsImhleCI6IjUxMjA1Y2U0NzkzMjY5YWIxMmVmZDE0YzJlNjY5NjI2ZGZkMmU5MjJhYTdlYTM5YmRkMzQ2ZjQxYWY5ZDFkZjM2ZDFlIiwidHlwZSI6IndpdG5lc3NfdjFfdGFwcm9vdCJ9fSx7InZhbHVlIjowLjAwMDAwNjk3LCJuIjo3Mywic2NyaXB0UHViS2V5Ijp7ImFzbSI6IjEgNzVkZDU3ZGQzMjhhNzY3MTU2ZDc3M2NhMDllNGNiMTlhNGUxMDE2M2JmMzlhMTlkNjY3NzliNzY1MWI1ZjNkZSIsImhleCI6IjUxMjA3NWRkNTdkZDMyOGE3NjcxNTZkNzczY2EwOWU0Y2IxOWE0ZTEwMTYzYmYzOWExOWQ2Njc3OWI3NjUxYjVmM2RlIiwidHlwZSI6IndpdG5lc3NfdjFfdGFwcm9vdCJ9fSx7InZhbHVlIjowLjAwMDAwNjk3LCJuIjo3NCwic2NyaXB0UHViS2V5Ijp7ImFzbSI6IjEgNDBmNjY4YWZiMTE0NjgzOGRlYjU1MjJlY2Q1MTA3YmNiN2Y3NWEzMDZhMzc0NThhNTk5M2RkYTA4MTk4MDkxZiIsImhleCI6IjUxMjA0MGY2NjhhZmIxMTQ2ODM4ZGViNTUyMmVjZDUxMDdiY2I3Zjc1YTMwNmEzNzQ1OGE1OTkzZGRhMDgxOTgwOTFmIiwidHlwZSI6IndpdG5lc3NfdjFfdGFwcm9vdCJ9fSx7InZhbHVlIjowLjAwMDAwNjk3LCJuIjo3NSwic2NyaXB0UHViS2V5Ijp7ImFzbSI6IjEgNGZkYjI3MjQ3ZjM3YWUwNTA0ZWNmYTI5ZGJkMGQxNDhjYTE3ZWY4M2JmYzBmY2UwMDVjZThlM2I5YjViMWVjYiIsImhleCI6IjUxMjA0ZmRiMjcyNDdmMzdhZTA1MDRlY2ZhMjlkYmQwZDE0OGNhMTdlZjgzYmZjMGZjZTAwNWNlOGUzYjliNWIxZWNiIiwidHlwZSI6IndpdG5lc3NfdjFfdGFwcm9vdCJ9fSx7InZhbHVlIjowLjAwMDAwNjk3LCJuIjo3Niwic2NyaXB0UHViS2V5Ijp7ImFzbSI6IjEgODliNDFhMDQ3ZjVlYjVkZmZmMGZjYjZjY2Q5M2NhNmQ3NGMyMjY5ZGVjMWVhOGYyNDY4NTNjZDZhZmEwMTAyYiIsImhleCI6IjUxMjA4OWI0MWEwNDdmNWViNWRmZmYwZmNiNmNjZDkzY2E2ZDc0YzIyNjlkZWMxZWE4ZjI0Njg1M2NkNmFmYTAxMDJiIiwidHlwZSI6IndpdG5lc3NfdjFfdGFwcm9vdCJ9fSx7InZhbHVlIjowLjAwMDAwNjk3LCJuIjo3Nywic2NyaXB0UHViS2V5Ijp7ImFzbSI6IjEgM2U5YWFhNjNmM2Y0YzczNjNlYzQ3ZWU0YTBmZmQ0NTI2MzBhMmI5OTYyNmJlNWRhYTM0ZjhjMzVhZWVhMzVkYyIsImhleCI6IjUxMjAzZTlhYWE2M2YzZjRjNzM2M2VjNDdlZTRhMGZmZDQ1MjYzMGEyYjk5NjI2YmU1ZGFhMzRmOGMzNWFlZWEzNWRjIiwidHlwZSI6IndpdG5lc3NfdjFfdGFwcm9vdCJ9fSx7InZhbHVlIjowLjAwMDAwNjk3LCJuIjo3OCwic2NyaXB0UHViS2V5Ijp7ImFzbSI6IjEgODJjMjEyYWJlNjc1YWFlMjllMmRmZTAyNjllNDc1MzQzZjJlNzA5NDdkOWJlYTM1ZGNiZjA4NDc1ZThkNmFhOSIsImhleCI6IjUxMjA4MmMyMTJhYmU2NzVhYWUyOWUyZGZlMDI2OWU0NzUzNDNmMmU3MDk0N2Q5YmVhMzVkY2JmMDg0NzVlOGQ2YWE5IiwidHlwZSI6IndpdG5lc3NfdjFfdGFwcm9vdCJ9fSx7InZhbHVlIjowLjAwMDAwNjk3LCJuIjo3OSwic2NyaXB0UHViS2V5Ijp7ImFzbSI6IjEgZTdkOWQ0NmZjMWE0OTUyMWQwZjY2OGVkNjU0ZDI3NGY0ZDYyYmJkOWQxYWIxNzQ1N2Q2MTNkNTBhNjA1ZmViMCIsImhleCI6IjUxMjBlN2Q5ZDQ2ZmMxYTQ5NTIxZDBmNjY4ZWQ2NTRkMjc0ZjRkNjJiYmQ5ZDFhYjE3NDU3ZDYxM2Q1MGE2MDVmZWIwIiwidHlwZSI6IndpdG5lc3NfdjFfdGFwcm9vdCJ9fSx7InZhbHVlIjowLjAwMDAwNjk3LCJuIjo4MCwic2NyaXB0UHViS2V5Ijp7ImFzbSI6IjEgM2UxM2NiNWFlNzk4MDk0NmUwMmU0MjRjY2U1MmJmMDMwODVjM2YyZjljODliNTUwNjRmZTQ5MDg0ZjczODAyNiIsImhleCI6IjUxMjAzZTEzY2I1YWU3OTgwOTQ2ZTAyZTQyNGNjZTUyYmYwMzA4NWMzZjJmOWM4OWI1NTA2NGZlNDkwODRmNzM4MDI2IiwidHlwZSI6IndpdG5lc3NfdjFfdGFwcm9vdCJ9fSx7InZhbHVlIjowLjAwMDAwNjk3LCJuIjo4MSwic2NyaXB0UHViS2V5Ijp7ImFzbSI6IjEgZTFiOGRjMzVkMDg1MTU3NjE3OGJmZDRhMTYxZmY1NDBmNjNlYzAxYTVkOTI1NDBiMTEzYjVmNTE3NGM3YjA5MCIsImhleCI6IjUxMjBlMWI4ZGMzNWQwODUxNTc2MTc4YmZkNGExNjFmZjU0MGY2M2VjMDFhNWQ5MjU0MGIxMTNiNWY1MTc0YzdiMDkwIiwidHlwZSI6IndpdG5lc3NfdjFfdGFwcm9vdCJ9fSx7InZhbHVlIjowLjAwMDAwNjk3LCJuIjo4Miwic2NyaXB0UHViS2V5Ijp7ImFzbSI6IjEgZjMyNDk4MDk4YzYxNGQ5M2JiZmM0YmNkNjUwM2EwZjU1YTk3NDljNGYwODY5ZWYxMGVjMzgyMTI0ODQ1NDFmNCIsImhleCI6IjUxMjBmMzI0OTgwOThjNjE0ZDkzYmJmYzRiY2Q2NTAzYTBmNTVhOTc0OWM0ZjA4NjllZjEwZWMzODIxMjQ4NDU0MWY0IiwidHlwZSI6IndpdG5lc3NfdjFfdGFwcm9vdCJ9fSx7InZhbHVlIjowLjAwMDAwNjk3LCJuIjo4Mywic2NyaXB0UHViS2V5Ijp7ImFzbSI6IjEgZjNmZjg3ZTk1ZWQzOTg5MTI0N2I0NGRlMzg3ZWI3MWE2ODFjM2UyOGMyOGM4ZTgwYTQzMTE1ZWMwNjJmZDQ1YiIsImhleCI6IjUxMjBmM2ZmODdlOTVlZDM5ODkxMjQ3YjQ0ZGUzODdlYjcxYTY4MWMzZTI4YzI4YzhlODBhNDMxMTVlYzA2MmZkNDViIiwidHlwZSI6IndpdG5lc3NfdjFfdGFwcm9vdCJ9fSx7InZhbHVlIjowLjAwMDAwNjk3LCJuIjo4NCwic2NyaXB0UHViS2V5Ijp7ImFzbSI6IjEgYTRmMmM5OGY0YTFhYjY1M2M0NzhmZWUwZDIxM2NiOGZhMjg0ZjVhYjEwNDc2MTRmZGVlMDBiMDdmMDAxNWQyMSIsImhleCI6IjUxMjBhNGYyYzk4ZjRhMWFiNjUzYzQ3OGZlZTBkMjEzY2I4ZmEyODRmNWFiMTA0NzYxNGZkZWUwMGIwN2YwMDE1ZDIxIiwidHlwZSI6IndpdG5lc3NfdjFfdGFwcm9vdCJ9fSx7InZhbHVlIjowLjAwMDAwNjk3LCJuIjo4NSwic2NyaXB0UHViS2V5Ijp7ImFzbSI6IjEgNWIyOTVmYjdlM2IyOTBjNWZhZDMzNzAyYjBjMzg2OTVkZDY1MTA1Yjc2YmFlNGI3MjFkODc2YzVlNDUxY2Q4OSIsImhleCI6IjUxMjA1YjI5NWZiN2UzYjI5MGM1ZmFkMzM3MDJiMGMzODY5NWRkNjUxMDViNzZiYWU0YjcyMWQ4NzZjNWU0NTFjZDg5IiwidHlwZSI6IndpdG5lc3NfdjFfdGFwcm9vdCJ9fSx7InZhbHVlIjowLjAwMDAwNjk3LCJuIjo4Niwic2NyaXB0UHViS2V5Ijp7ImFzbSI6IjEgOTZmODEzZjUwZTAzMWU1N2RmYzJjMWYyOWNmYmUyYTBiZDlkMGNhZjE0ZjUzZjc0ZjAzZWQ3NzEyOTE3MjVhMiIsImhleCI6IjUxMjA5NmY4MTNmNTBlMDMxZTU3ZGZjMmMxZjI5Y2ZiZTJhMGJkOWQwY2FmMTRmNTNmNzRmMDNlZDc3MTI5MTcyNWEyIiwidHlwZSI6IndpdG5lc3NfdjFfdGFwcm9vdCJ9fSx7InZhbHVlIjowLjAwMDAwNjk3LCJuIjo4Nywic2NyaXB0UHViS2V5Ijp7ImFzbSI6IjEgOThjODdlM2U1MzMxNDQ4NzlkZGNlY2Y2YWEwMDA2YzdjZWYxNTI5NGUyNjk1MThkZTlmMDVlZTZhNDk1NGM2OSIsImhleCI6IjUxMjA5OGM4N2UzZTUzMzE0NDg3OWRkY2VjZjZhYTAwMDZjN2NlZjE1Mjk0ZTI2OTUxOGRlOWYwNWVlNmE0OTU0YzY5IiwidHlwZSI6IndpdG5lc3NfdjFfdGFwcm9vdCJ9fSx7InZhbHVlIjowLjAwMDAwNjk3LCJuIjo4OCwic2NyaXB0UHViS2V5Ijp7ImFzbSI6IjEgYjg2Njk1YTExYzhiYzI0MTA0NWFjMjRmM2FjZjU2ZDRkZjQ2ZGUxODZjNmIwZTgyZDM5NzUxOWNhYjExOGMwYiIsImhleCI6IjUxMjBiODY2OTVhMTFjOGJjMjQxMDQ1YWMyNGYzYWNmNTZkNGRmNDZkZTE4NmM2YjBlODJkMzk3NTE5Y2FiMTE4YzBiIiwidHlwZSI6IndpdG5lc3NfdjFfdGFwcm9vdCJ9fSx7InZhbHVlIjowLjAwMDAwNjk3LCJuIjo4OSwic2NyaXB0UHViS2V5Ijp7ImFzbSI6IjEgZmEzZTc2Y2MxY2FmOTdmYzI3MWYxNWU1YzFiNDYzMDc5NjJiMzA3YzEzZWFhNmMwODkxYjNmZTRkNWJlYmVlNiIsImhleCI6IjUxMjBmYTNlNzZjYzFjYWY5N2ZjMjcxZjE1ZTVjMWI0NjMwNzk2MmIzMDdjMTNlYWE2YzA4OTFiM2ZlNGQ1YmViZWU2IiwidHlwZSI6IndpdG5lc3NfdjFfdGFwcm9vdCJ9fSx7InZhbHVlIjowLjAwMDAwNjk3LCJuIjo5MCwic2NyaXB0UHViS2V5Ijp7ImFzbSI6IjEgZjNkM2Y3ZmJkMDEzMTg2NTM1MDkwNGZkNGU2YTU0NGJiNWM1ZmQ3Y2Y3YzIxMGUyNmFkZmJkYWRiYzBjMmQxMiIsImhleCI6IjUxMjBmM2QzZjdmYmQwMTMxODY1MzUwOTA0ZmQ0ZTZhNTQ0YmI1YzVmZDdjZjdjMjEwZTI2YWRmYmRhZGJjMGMyZDEyIiwidHlwZSI6IndpdG5lc3NfdjFfdGFwcm9vdCJ9fSx7InZhbHVlIjowLjAwMDAwNjk3LCJuIjo5MSwic2NyaXB0UHViS2V5Ijp7ImFzbSI6IjEgYTg2MzQ2ZjhkY2U5ZDc1NDQ2MWQ1OTczZTY4ZjhkMjQ4YmMyODllZjhjODgwNTYzMzM3MGFlNjVjMmE5Y2VmZSIsImhleCI6IjUxMjBhODYzNDZmOGRjZTlkNzU0NDYxZDU5NzNlNjhmOGQyNDhiYzI4OWVmOGM4ODA1NjMzMzcwYWU2NWMyYTljZWZlIiwidHlwZSI6IndpdG5lc3NfdjFfdGFwcm9vdCJ9fSx7InZhbHVlIjowLjAwMDAwNjk3LCJuIjo5Miwic2NyaXB0UHViS2V5Ijp7ImFzbSI6IjEgOGI5MzIyZDZmNmViOTIwZmZjN2FmY2YzZGJjZmI0YTdiOTMxMzQxY2I2NGUzY2M3MTFiNDAzMmUwMmExMjA2NSIsImhleCI6IjUxMjA4YjkzMjJkNmY2ZWI5MjBmZmM3YWZjZjNkYmNmYjRhN2I5MzEzNDFjYjY0ZTNjYzcxMWI0MDMyZTAyYTEyMDY1IiwidHlwZSI6IndpdG5lc3NfdjFfdGFwcm9vdCJ9fSx7InZhbHVlIjowLjAwMDAwNjk3LCJuIjo5Mywic2NyaXB0UHViS2V5Ijp7ImFzbSI6IjEgNDk0YmUzNjA2NmIzYTZjMTgxNmNkZGM2ODRmNmE5ZTNhY2FhZDg3MTU2YTZlOTQwYjQ5ODMwMjFkYTZlODNjYyIsImhleCI6IjUxMjA0OTRiZTM2MDY2YjNhNmMxODE2Y2RkYzY4NGY2YTllM2FjYWFkODcxNTZhNmU5NDBiNDk4MzAyMWRhNmU4M2NjIiwidHlwZSI6IndpdG5lc3NfdjFfdGFwcm9vdCJ9fSx7InZhbHVlIjowLjAwMDAwNjk3LCJuIjo5NCwic2NyaXB0UHViS2V5Ijp7ImFzbSI6IjEgYmE2MmJjYTdmODFiYzQ2NTdlNjMyYzY4M2MzNjhmNTIzOTkyMjNjMzZmNTEwMWZjZmJkMTdkYjVkMzhmZDBhOSIsImhleCI6IjUxMjBiYTYyYmNhN2Y4MWJjNDY1N2U2MzJjNjgzYzM2OGY1MjM5OTIyM2MzNmY1MTAxZmNmYmQxN2RiNWQzOGZkMGE5IiwidHlwZSI6IndpdG5lc3NfdjFfdGFwcm9vdCJ9fSx7InZhbHVlIjowLjAwMDAwNjk3LCJuIjo5NSwic2NyaXB0UHViS2V5Ijp7ImFzbSI6IjEgMWFiODA0Y2NjZGNkMTE0MmQ0NTcwZWI4NjQxZTJhNTYxMGRmYjhkMTQ1NzRmOTBjMDYyNWYxM2MwOTc4ODQwOCIsImhleCI6IjUxMjAxYWI4MDRjY2NkY2QxMTQyZDQ1NzBlYjg2NDFlMmE1NjEwZGZiOGQxNDU3NGY5MGMwNjI1ZjEzYzA5Nzg4NDA4IiwidHlwZSI6IndpdG5lc3NfdjFfdGFwcm9vdCJ9fSx7InZhbHVlIjowLjAwMDAwNjk3LCJuIjo5Niwic2NyaXB0UHViS2V5Ijp7ImFzbSI6IjEgZGYzMGI3MmY0OTg2MDZlNmU1N2IyNDFjMDlkNDViOGYxYzJhZjEzYmI1YWM3ZDNiZjk2ZmNmNWQyZmU2YjVkYiIsImhleCI6IjUxMjBkZjMwYjcyZjQ5ODYwNmU2ZTU3YjI0MWMwOWQ0NWI4ZjFjMmFmMTNiYjVhYzdkM2JmOTZmY2Y1ZDJmZTZiNWRiIiwidHlwZSI6IndpdG5lc3NfdjFfdGFwcm9vdCJ9fSx7InZhbHVlIjowLjAwMDAwNjk3LCJuIjo5Nywic2NyaXB0UHViS2V5Ijp7ImFzbSI6IjEgODk2MmU5MWY3YjhkYzE4MzIzNWVmZjBmMGMzMDk3OTkzNzM0NTM3NjJjY2MwMDljMmZhMDEyNDRhZGIzZjA5OCIsImhleCI6IjUxMjA4OTYyZTkxZjdiOGRjMTgzMjM1ZWZmMGYwYzMwOTc5OTM3MzQ1Mzc2MmNjYzAwOWMyZmEwMTI0NGFkYjNmMDk4IiwidHlwZSI6IndpdG5lc3NfdjFfdGFwcm9vdCJ9fSx7InZhbHVlIjowLjAwMDAwNjk3LCJuIjo5OCwic2NyaXB0UHViS2V5Ijp7ImFzbSI6IjEgZGRjNmIzNmE5NTE0NDZjNDQ2MmQzM2E4MmI1NDNlZTFkNTgxMjIxOGFkNDUwMTkzZWIxYThhZjQ0YWVkNzE0NyIsImhleCI6IjUxMjBkZGM2YjM2YTk1MTQ0NmM0NDYyZDMzYTgyYjU0M2VlMWQ1ODEyMjE4YWQ0NTAxOTNlYjFhOGFmNDRhZWQ3MTQ3IiwidHlwZSI6IndpdG5lc3NfdjFfdGFwcm9vdCJ9fSx7InZhbHVlIjowLjAwMDAwNjk3LCJuIjo5OSwic2NyaXB0UHViS2V5Ijp7ImFzbSI6IjEgYzJkNTk2OTcyMWEwZWI2NTQ3ZmZhMjc4NDJjMmM2MGVkZjZlYmNmODJjOTEyN2FlNTNlMzllN2ExZjQ4MWM1ZCIsImhleCI6IjUxMjBjMmQ1OTY5NzIxYTBlYjY1NDdmZmEyNzg0MmMyYzYwZWRmNmViY2Y4MmM5MTI3YWU1M2UzOWU3YTFmNDgxYzVkIiwidHlwZSI6IndpdG5lc3NfdjFfdGFwcm9vdCJ9fSx7InZhbHVlIjowLjAwMDUwMDEyLCJuIjoxMDAsInNjcmlwdFB1YktleSI6eyJhc20iOiIwIGJkZmQ2ZTBlODg5Y2U1N2M5YWRiZmU4MTdiMjY5Nzg2Y2EwODIxZDMiLCJoZXgiOiIwMDE0YmRmZDZlMGU4ODljZTU3YzlhZGJmZTgxN2IyNjk3ODZjYTA4MjFkMyIsInR5cGUiOiJ3aXRuZXNzX3YwX2tleWhhc2gifX1dfSx7ImhleCI6IjAyMDAwMDAwMDAwMTAxOWQxMThlY2I5MGQxMmEzZWJkNDhhZTMyMDhkMjJhM2VkMmYyMDhlY2JkM2E2ZDY0ODk5ZDE4MmJkMDFlYjBmMzE1MDAwMDAwMDBmZmZmZmZmZjAxMjIwMjAwMDAwMDAwMDAwMDIyNTEyMDJkZTg1MjE0OGVkMzE2ODg1NTY0YzQ0NjJiZDBmZDAwNjY2ZDNlMDc5ZDg1MjAxOWU0MWY5MDIxMjA4NzhkZDUwMzQwZjBkMDc0ODRmOTg4NzdjMzdjOWRjMjExMDg0OWYzYmI0ZDZlMzA2ZWNmMzA5ZjFmYWIzNmZmZDdiOTk4YjZlZDhkNTQ4NzEyMzYwOTBkMTIzN2JkNWVjMDlmODU2MDdmM2Y0NzNmYmM2N2U3MGEyNjNmOWY2NDgyOWE0MTFmNGY3YjIwMDhkOGMzNDFhNTVlNDQxNTQ0MmM4ZTE2YTNmNTZiNzY2MDUzYTlkZGE2M2IyN2FhMmQ5ZDRjNmUxMzlmNjg5ZWFjMDA2MzAzNmY3MjY0MDEwMTE4NzQ2NTc4NzQyZjcwNmM2MTY5NmUzYjYzNjg2MTcyNzM2NTc0M2Q3NTc0NjYyZDM4MDAzNTdiMjI3MDIyM2EyMjYyNzI2MzJkMzIzMDIyMmMyMjZmNzAyMjNhMjI2ZDY5NmU3NDIyMmMyMjc0Njk2MzZiMjIzYTIyNmQ2NTZkNjUyMjJjMjI2MTZkNzQyMjNhMjIzMTMwMzAzMDIyN2Q2ODIxYzA5ODM3MWMxMDhmNjVhYzkzYzJkMDg5MDBhMGViNmVhY2U5MGE1NDcxODY4MDFmYTI1MmI0M2U1N2U3ZTI3NTUxMDAwMDAwMDAiLCJ0eGlkIjoiYjg2MWFmZWIwNDY5MWZkNTRmNGVlNzVlZGQyZmZlMWYyNzJlNGM3MDQ2ODU1MTUwMDhkNmRmYjQ3NGQwYTIwZSIsImhhc2giOiIyZTk2NDc0NWZjOWRkNjkxYjI3ZjNlMDZhOTBkZjI0NDcwZGI4MTAzODNmYTFiODVkNDlkMTczZTA4OGU3NjM1Iiwic2l6ZSI6MzIwLCJ2c2l6ZSI6MTUxLCJ3ZWlnaHQiOjYwMiwidmVyc2lvbiI6MiwibG9ja3RpbWUiOjAsInZpbiI6W3sidHhpZCI6ImYzYjAxZWQwMmIxODlkODk2NDZkM2FiZGVjMDhmMmQyM2UyYWQyMDgzMmFlNDhiZDNlMmFkMTkwY2I4ZTExOWQiLCJ2b3V0IjoyMSwic2NyaXB0U2lnIjp7ImFzbSI6IiIsImhleCI6IiJ9LCJ0eGlud2l0bmVzcyI6WyJmMGQwNzQ4NGY5ODg3N2MzN2M5ZGMyMTEwODQ5ZjNiYjRkNmUzMDZlY2YzMDlmMWZhYjM2ZmZkN2I5OThiNmVkOGQ1NDg3MTIzNjA5MGQxMjM3YmQ1ZWMwOWY4NTYwN2YzZjQ3M2ZiYzY3ZTcwYTI2M2Y5ZjY0ODI5YTQxMWY0ZiIsIjIwMDhkOGMzNDFhNTVlNDQxNTQ0MmM4ZTE2YTNmNTZiNzY2MDUzYTlkZGE2M2IyN2FhMmQ5ZDRjNmUxMzlmNjg5ZWFjMDA2MzAzNmY3MjY0MDEwMTE4NzQ2NTc4NzQyZjcwNmM2MTY5NmUzYjYzNjg2MTcyNzM2NTc0M2Q3NTc0NjYyZDM4MDAzNTdiMjI3MDIyM2EyMjYyNzI2MzJkMzIzMDIyMmMyMjZmNzAyMjNhMjI2ZDY5NmU3NDIyMmMyMjc0Njk2MzZiMjIzYTIyNmQ2NTZkNjUyMjJjMjI2MTZkNzQyMjNhMjIzMTMwMzAzMDIyN2Q2OCIsImMwOTgzNzFjMTA4ZjY1YWM5M2MyZDA4OTAwYTBlYjZlYWNlOTBhNTQ3MTg2ODAxZmEyNTJiNDNlNTdlN2UyNzU1MSJdLCJzZXF1ZW5jZSI6NDI5NDk2NzI5NX1dLCJ2b3V0IjpbeyJ2YWx1ZSI6MC4wMDAwMDU0NiwibiI6MCwic2NyaXB0UHViS2V5Ijp7ImFzbSI6IjEgMmRlODUyMTQ4ZWQzMTY4ODU1NjRjNDQ2MmJkMGZkMDA2NjZkM2UwNzlkODUyMDE5ZTQxZjkwMjEyMDg3OGRkNSIsImhleCI6IjUxMjAyZGU4NTIxNDhlZDMxNjg4NTU2NGM0NDYyYmQwZmQwMDY2NmQzZTA3OWQ4NTIwMTllNDFmOTAyMTIwODc4ZGQ1IiwidHlwZSI6IndpdG5lc3NfdjFfdGFwcm9vdCJ9fV19LHsiaGV4IjoiMDIwMDAwMDAwMDAxMDE5ZDExOGVjYjkwZDEyYTNlYmQ0OGFlMzIwOGQyMmEzZWQyZjIwOGVjYmQzYTZkNjQ4OTlkMTgyYmQwMWViMGYzMDEwMDAwMDAwMGZmZmZmZmZmMDEyMjAyMDAwMDAwMDAwMDAwMjI1MTIwMmRlODUyMTQ4ZWQzMTY4ODU1NjRjNDQ2MmJkMGZkMDA2NjZkM2UwNzlkODUyMDE5ZTQxZjkwMjEyMDg3OGRkNTAzNDA2YzNjMGM2MjAxMWZiNjEyYjJjYWU0ZDAzNzAxN2QyNjU4MTQwOWNlZDk4MzIyMGM1MGI3YTU2OTNhYWE4Y2U1M2M1MzljNzYxYzQ2NDBhYWRiMDY5ZGU0MzE5OTY5YjQxODg1Yzc1ZDg2OWYyNmFlYmE2ZTI1YjZiOTFjOTVmMjdiMjAyMjUxOTVkNGE4NTViNzgzN2MzNzgxMjVhZjA0MzkzZjNkNTcxNDdjYzIwZGQzZDkyYjBkM2U0NzM5YTI3NDFjYWMwMDYzMDM2ZjcyNjQwMTAxMTg3NDY1Nzg3NDJmNzA2YzYxNjk2ZTNiNjM2ODYxNzI3MzY1NzQzZDc1NzQ2NjJkMzgwMDM1N2IyMjcwMjIzYTIyNjI3MjYzMmQzMjMwMjIyYzIyNmY3MDIyM2EyMjZkNjk2ZTc0MjIyYzIyNzQ2OTYzNmIyMjNhMjI2ZDY1NmQ2NTIyMmMyMjYxNmQ3NDIyM2EyMjMxMzAzMDMwMjI3ZDY4MjFjMDk4MzcxYzEwOGY2NWFjOTNjMmQwODkwMGEwZWI2ZWFjZTkwYTU0NzE4NjgwMWZhMjUyYjQzZTU3ZTdlMjc1NTEwMDAwMDAwMCIsInR4aWQiOiJhZjJiOGU3MmU3NTA5ZTY1MGRiZTIwOWM1MDA4MTQ3YTM3NzA1ODhmZGI0NzM4NWViZWZmMDcxNjA3MjJiYzBlIiwiaGFzaCI6IjcxNTNmZjBlYWM3OWZhZWZiNjUzMGIzNzgwMTQ2NGI1YjRkZTIwNGViZGJiMGNlYmNiMDU5MTYwOTZlZDRkNDUiLCJzaXplIjozMjAsInZzaXplIjoxNTEsIndlaWdodCI6NjAyLCJ2ZXJzaW9uIjoyLCJsb2NrdGltZSI6MCwidmluIjpbeyJ0eGlkIjoiZjNiMDFlZDAyYjE4OWQ4OTY0NmQzYWJkZWMwOGYyZDIzZTJhZDIwODMyYWU0OGJkM2UyYWQxOTBjYjhlMTE5ZCIsInZvdXQiOjEsInNjcmlwdFNpZyI6eyJhc20iOiIiLCJoZXgiOiIifSwidHhpbndpdG5lc3MiOlsiNmMzYzBjNjIwMTFmYjYxMmIyY2FlNGQwMzcwMTdkMjY1ODE0MDljZWQ5ODMyMjBjNTBiN2E1NjkzYWFhOGNlNTNjNTM5Yzc2MWM0NjQwYWFkYjA2OWRlNDMxOTk2OWI0MTg4NWM3NWQ4NjlmMjZhZWJhNmUyNWI2YjkxYzk1ZjIiLCIyMDIyNTE5NWQ0YTg1NWI3ODM3YzM3ODEyNWFmMDQzOTNmM2Q1NzE0N2NjMjBkZDNkOTJiMGQzZTQ3MzlhMjc0MWNhYzAwNjMwMzZmNzI2NDAxMDExODc0NjU3ODc0MmY3MDZjNjE2OTZlM2I2MzY4NjE3MjczNjU3NDNkNzU3NDY2MmQzODAwMzU3YjIyNzAyMjNhMjI2MjcyNjMyZDMyMzAyMjJjMjI2ZjcwMjIzYTIyNmQ2OTZlNzQyMjJjMjI3NDY5NjM2YjIyM2EyMjZkNjU2ZDY1MjIyYzIyNjE2ZDc0MjIzYTIyMzEzMDMwMzAyMjdkNjgiLCJjMDk4MzcxYzEwOGY2NWFjOTNjMmQwODkwMGEwZWI2ZWFjZTkwYTU0NzE4NjgwMWZhMjUyYjQzZTU3ZTdlMjc1NTEiXSwic2VxdWVuY2UiOjQyOTQ5NjcyOTV9XSwidm91dCI6W3sidmFsdWUiOjAuMDAwMDA1NDYsIm4iOjAsInNjcmlwdFB1YktleSI6eyJhc20iOiIxIDJkZTg1MjE0OGVkMzE2ODg1NTY0YzQ0NjJiZDBmZDAwNjY2ZDNlMDc5ZDg1MjAxOWU0MWY5MDIxMjA4NzhkZDUiLCJoZXgiOiI1MTIwMmRlODUyMTQ4ZWQzMTY4ODU1NjRjNDQ2MmJkMGZkMDA2NjZkM2UwNzlkODUyMDE5ZTQxZjkwMjEyMDg3OGRkNSIsInR5cGUiOiJ3aXRuZXNzX3YxX3RhcHJvb3QifX1dfSx7ImhleCI6IjAxMDAwMDAwMDAwMTAxMWM2NmM1YzkzZTMxMWM3ZmVlNDNmMTA0NWY0MDBhZDZhZjE0NmVhMjQwMzhmNDVjYjAxNDFlNDZhOGNhYzcxNTAwMDAwMDAwMTcxNjAwMTRlMjY0NGM4OWNlODI5MjVjMjcyYTNmODgyMDBjN2M4MDQ1YmM0MTM2ZmZmZmZmZmYwMjg0ZjkxMjAwMDAwMDAwMDAxN2E5MTQ5NWMxYzJjMTUzYjc5ZTNhYWU5MGE3NGZmMmEyYmE2MzFmY2I1YmU1ODdlODAzMDAwMDAwMDAwMDAwMTdhOTE0NzI1ZGU0ZDc2MTdiNmY5YTZkMzBmODViZTdlMzk5NzlhNWRkMzg3NDg3MDI0ODMwNDUwMjIxMDBjNmE0ODMzOWRhMzdkZmJjY2ViNDkxOTc5ZDAyZTNiZWVjYTExOTA2YTYyYmExMTJhNDFmNzNkODgyYWE2NjcwMDIyMDZjMjllYzY1OTE2ZjljYTMyZGZhYWIwZDA5MTI0OTJjZjAyZTJmNjJlYmVlODk0NDJkNzZkMDJkNGMxZGFkN2IwMTIxMDJhZTA2NDE0NWY2NzE5MTY4MjY1Y2U2YWY4YjgyYTI3YzFkZTY4YjBjMGZlZGFiZmY2YmRjNGZmYjc4MDg0MDliMDAwMDAwMDAiLCJ0eGlkIjoiMTExYmI0OGNkNmJhNDAyNmIyNDRmN2EzODMzYjhiZThkZjFkMmZjZjRlNDM3NGYxMWQyYmE0ZTg3NTMxOGZkMCIsImhhc2giOiIzOTg2NGRmMWE3YmJlODcwMGI1MmIwZjgzZTk3N2UwODZkMjFjMWQ3ZjY1OWJlYWM3YWUzMmEyZDM2YjM5MzBiIiwic2l6ZSI6MjQ4LCJ2c2l6ZSI6MTY2LCJ3ZWlnaHQiOjY2MiwidmVyc2lvbiI6MSwibG9ja3RpbWUiOjAsInZpbiI6W3sidHhpZCI6IjE1YzdjYWE4NDYxZTE0YjA1Y2Y0Mzg0MGEyNmUxNGFmZDYwYTQwNWYwNGYxNDNlZTdmMWMzMTNlYzljNTY2MWMiLCJ2b3V0IjowLCJzY3JpcHRTaWciOnsiYXNtIjoiMDAxNGUyNjQ0Yzg5Y2U4MjkyNWMyNzJhM2Y4ODIwMGM3YzgwNDViYzQxMzYiLCJoZXgiOiIxNjAwMTRlMjY0NGM4OWNlODI5MjVjMjcyYTNmODgyMDBjN2M4MDQ1YmM0MTM2In0sInR4aW53aXRuZXNzIjpbIjMwNDUwMjIxMDBjNmE0ODMzOWRhMzdkZmJjY2ViNDkxOTc5ZDAyZTNiZWVjYTExOTA2YTYyYmExMTJhNDFmNzNkODgyYWE2NjcwMDIyMDZjMjllYzY1OTE2ZjljYTMyZGZhYWIwZDA5MTI0OTJjZjAyZTJmNjJlYmVlODk0NDJkNzZkMDJkNGMxZGFkN2IwMSIsIjAyYWUwNjQxNDVmNjcxOTE2ODI2NWNlNmFmOGI4MmEyN2MxZGU2OGIwYzBmZWRhYmZmNmJkYzRmZmI3ODA4NDA5YiJdLCJzZXF1ZW5jZSI6NDI5NDk2NzI5NX1dLCJ2b3V0IjpbeyJ2YWx1ZSI6MC4wMTI0MzUyNCwibiI6MCwic2NyaXB0UHViS2V5Ijp7ImFzbSI6Ik9QX0hBU0gxNjAgOTVjMWMyYzE1M2I3OWUzYWFlOTBhNzRmZjJhMmJhNjMxZmNiNWJlNSBPUF9FUVVBTCIsImhleCI6ImE5MTQ5NWMxYzJjMTUzYjc5ZTNhYWU5MGE3NGZmMmEyYmE2MzFmY2I1YmU1ODciLCJ0eXBlIjoic2NyaXB0aGFzaCJ9fSx7InZhbHVlIjowLjAwMDAxLCJuIjoxLCJzY3JpcHRQdWJLZXkiOnsiYXNtIjoiT1BfSEFTSDE2MCA3MjVkZTRkNzYxN2I2ZjlhNmQzMGY4NWJlN2UzOTk3OWE1ZGQzODc0IE9QX0VRVUFMIiwiaGV4IjoiYTkxNDcyNWRlNGQ3NjE3YjZmOWE2ZDMwZjg1YmU3ZTM5OTc5YTVkZDM4NzQ4NyIsInR5cGUiOiJzY3JpcHRoYXNoIn19XX0seyJoZXgiOiIwMTAwMDAwMDAwMDEwMWQwOGYzMTc1ZThhNDJiMWRmMTc0NDM0ZWNmMmYxZGRmZTg4YjNiODNhM2Y3NDRiMjI2NDBiYWQ2OGNiNDFiMTEwMDAwMDAwMDE3MTYwMDE0NTBjNjI2YWQ4N2JkZDczMmM2NjY4Njc3YTE5MjgyNGJmNmYwNWRkOWZmZmZmZmZmMDI3YWY4MTIwMDAwMDAwMDAwMTdhOTE0ZmZiYmUxYmM1ZjM0OTcyMDgyNGZjNDU1MWM2MDg3MWFkNDFmNjZkNDg3NjQwMDAwMDAwMDAwMDAwMDE3YTkxNDMwMjQ2MmNhNDRlNWJjZjY4ZDcwNzcyMzliYTQ2MmM3NWQ1Y2NlMzc4NzAyNDgzMDQ1MDIyMTAwYjI0Y2Q3ZmRhNTQ4MDZhZTgxMDU3NDM2MWFlZDNjOTE4YjA0OWRkNTQzMWYxMzQ0ZDhjMWE4MDU2ODk4ZmNkZDAyMjA2NWFjZWY5Yzg1YThkMjg1NjcwNTU1MjFiMTdkZDgzZjYzNjk5N2I0NDFlZDllM2ZlZjhkODAzOGM2Mjc3Y2Q4MDEyMTAzMmIxYmQwMjI1NTdmYTRjODJjMjJlYzcxOGIzZjQ2Y2I4YTU0Mzc5YTU0NzJiYzVkZDhjZTY1YjFlOTI5YmMyMzAwMDAwMDAwIiwidHhpZCI6IjhjZWI0NDAzNTUyM2E2NWJmYjBlMDg2MTU2M2E4MmZiNjdiNDIzOTRlYmY2MGRiY2JjZjNiY2U2YTk1ZjQ2MTIiLCJoYXNoIjoiYzg3ODIwMDE4NWNhNmMzODU3MmQyNDQyNjg3YjE3OTA4ZGQ1NTMwNGUyZTE2ZWM2OGQ2ZDFhODgxYzE2ZGNjNiIsInNpemUiOjI0OCwidnNpemUiOjE2Niwid2VpZ2h0Ijo2NjIsInZlcnNpb24iOjEsImxvY2t0aW1lIjowLCJ2aW4iOlt7InR4aWQiOiIxMTFiYjQ4Y2Q2YmE0MDI2YjI0NGY3YTM4MzNiOGJlOGRmMWQyZmNmNGU0Mzc0ZjExZDJiYTRlODc1MzE4ZmQwIiwidm91dCI6MCwic2NyaXB0U2lnIjp7ImFzbSI6IjAwMTQ1MGM2MjZhZDg3YmRkNzMyYzY2Njg2NzdhMTkyODI0YmY2ZjA1ZGQ5IiwiaGV4IjoiMTYwMDE0NTBjNjI2YWQ4N2JkZDczMmM2NjY4Njc3YTE5MjgyNGJmNmYwNWRkOSJ9LCJ0eGlud2l0bmVzcyI6WyIzMDQ1MDIyMTAwYjI0Y2Q3ZmRhNTQ4MDZhZTgxMDU3NDM2MWFlZDNjOTE4YjA0OWRkNTQzMWYxMzQ0ZDhjMWE4MDU2ODk4ZmNkZDAyMjA2NWFjZWY5Yzg1YThkMjg1NjcwNTU1MjFiMTdkZDgzZjYzNjk5N2I0NDFlZDllM2ZlZjhkODAzOGM2Mjc3Y2Q4MDEiLCIwMzJiMWJkMDIyNTU3ZmE0YzgyYzIyZWM3MThiM2Y0NmNiOGE1NDM3OWE1NDcyYmM1ZGQ4Y2U2NWIxZTkyOWJjMjMiXSwic2VxdWVuY2UiOjQyOTQ5NjcyOTV9XSwidm91dCI6W3sidmFsdWUiOjAuMDEyNDMyNTgsIm4iOjAsInNjcmlwdFB1YktleSI6eyJhc20iOiJPUF9IQVNIMTYwIGZmYmJlMWJjNWYzNDk3MjA4MjRmYzQ1NTFjNjA4NzFhZDQxZjY2ZDQgT1BfRVFVQUwiLCJoZXgiOiJhOTE0ZmZiYmUxYmM1ZjM0OTcyMDgyNGZjNDU1MWM2MDg3MWFkNDFmNjZkNDg3IiwidHlwZSI6InNjcmlwdGhhc2gifX0seyJ2YWx1ZSI6MC4wMDAwMDEsIm4iOjEsInNjcmlwdFB1YktleSI6eyJhc20iOiJPUF9IQVNIMTYwIDMwMjQ2MmNhNDRlNWJjZjY4ZDcwNzcyMzliYTQ2MmM3NWQ1Y2NlMzcgT1BfRVFVQUwiLCJoZXgiOiJhOTE0MzAyNDYyY2E0NGU1YmNmNjhkNzA3NzIzOWJhNDYyYzc1ZDVjY2UzNzg3IiwidHlwZSI6InNjcmlwdGhhc2gifX1dfSx7ImhleCI6IjAyMDAwMDAwMDAwMTAxNjEyZmY0NmQ0MDBkZDIxMjBmYjhjNWVmZDBkNTk0MWMwNTAzM2E5MGI1ZDIxNmE2YWNjNTkyMTE4MDQ0OWMzYTAwMDAwMDAwMDBmZGZmZmZmZjAyMjIwMjAwMDAwMDAwMDAwMDE2MDAxNDI2NmI1Y2JhN2VmYzJlZjJkYzk3YWUxZGVmNmMzOTNiZTRlMzRlMWYwNDA1MDAwMDAwMDAwMDAwMTYwMDE0YmRmZDZlMGU4ODljZTU3YzlhZGJmZTgxN2IyNjk3ODZjYTA4MjFkMzAzNDBjNDdkMzNkN2FhYTQxOTdiODE3NDIwYjU1YjZkNjBlMTE2YzllMGYxOWY1NmVlNGRmN2U2ZDg2YjViNzUyNGZlMGNkM2IzNjQxN2Q1Zjc4MGY1MzI0YzMyNTg2ODljN2Q2YTllYWQ3MDQxODRhN2M2ODA5YzU2MmM0YTEwZmY3MzdiMjBhYzJmMmVmMTlhNWQyYTA1MzFkOTMzOTRmYTk5ZTNmNWVkYTM2ZGM4MmM5NzI1MmMyYWEwOTE1OTI3MWRiZDBlYWMwMDYzMDM2ZjcyNjQwMTAxMTg3NDY1Nzg3NDJmNzA2YzYxNjk2ZTNiNjM2ODYxNzI3MzY1NzQzZDc1NzQ2NjJkMzgwMDM1N2IyMjcwMjIzYTIyNjI3MjYzMmQzMjMwMjIyYzIyNmY3MDIyM2EyMjZkNjk2ZTc0MjIyYzIyNzQ2OTYzNmIyMjNhMjI2NDZmNmQ2ZjIyMmMyMjYxNmQ3NDIyM2EyMjMxMzAzMDMwMjI3ZDY4MjFjMTBjZmFkM2ZlMmNlYmEyMWRiOGQxNDliN2ZiOTBhMTg5MmYzNDE0ZGYwNWI2ZGQ5ZjI1MDA0OTVlOGU3ZjllYTcwMDAwMDAwMCIsInR4aWQiOiI4YTI1YjhlMTZkZDk2NzE0NWNlOGU3MjIxNjYyNDJjZjI0ZTRhNjdjYTUwZDBhNmUxMzcxMzMwZDA4OTg3NTE5IiwiaGFzaCI6IjJjZmQ1MDU2ZGVkMGE2NzdhMmY5YzNhMzZhZGNiYjhlODg3MDRjYWFkZmIxMDViOWE5N2Q1NTBlMGUxMWNmYjQiLCJzaXplIjozMzksInZzaXplIjoxNzAsIndlaWdodCI6Njc4LCJ2ZXJzaW9uIjoyLCJsb2NrdGltZSI6MCwidmluIjpbeyJ0eGlkIjoiM2E5YzQ0ODAxMTkyYzVhY2E2MTZkMmI1OTAzYTAzMDUxYzk0ZDVkMGVmYzViODBmMTJkMjBkNDA2ZGY0MmY2MSIsInZvdXQiOjAsInNjcmlwdFNpZyI6eyJhc20iOiIiLCJoZXgiOiIifSwidHhpbndpdG5lc3MiOlsiYzQ3ZDMzZDdhYWE0MTk3YjgxNzQyMGI1NWI2ZDYwZTExNmM5ZTBmMTlmNTZlZTRkZjdlNmQ4NmI1Yjc1MjRmZTBjZDNiMzY0MTdkNWY3ODBmNTMyNGMzMjU4Njg5YzdkNmE5ZWFkNzA0MTg0YTdjNjgwOWM1NjJjNGExMGZmNzMiLCIyMGFjMmYyZWYxOWE1ZDJhMDUzMWQ5MzM5NGZhOTllM2Y1ZWRhMzZkYzgyYzk3MjUyYzJhYTA5MTU5MjcxZGJkMGVhYzAwNjMwMzZmNzI2NDAxMDExODc0NjU3ODc0MmY3MDZjNjE2OTZlM2I2MzY4NjE3MjczNjU3NDNkNzU3NDY2MmQzODAwMzU3YjIyNzAyMjNhMjI2MjcyNjMyZDMyMzAyMjJjMjI2ZjcwMjIzYTIyNmQ2OTZlNzQyMjJjMjI3NDY5NjM2YjIyM2EyMjY0NmY2ZDZmMjIyYzIyNjE2ZDc0MjIzYTIyMzEzMDMwMzAyMjdkNjgiLCJjMTBjZmFkM2ZlMmNlYmEyMWRiOGQxNDliN2ZiOTBhMTg5MmYzNDE0ZGYwNWI2ZGQ5ZjI1MDA0OTVlOGU3ZjllYTciXSwic2VxdWVuY2UiOjQyOTQ5NjcyOTN9XSwidm91dCI6W3sidmFsdWUiOjAuMDAwMDA1NDYsIm4iOjAsInNjcmlwdFB1YktleSI6eyJhc20iOiIwIDI2NmI1Y2JhN2VmYzJlZjJkYzk3YWUxZGVmNmMzOTNiZTRlMzRlMWYiLCJoZXgiOiIwMDE0MjY2YjVjYmE3ZWZjMmVmMmRjOTdhZTFkZWY2YzM5M2JlNGUzNGUxZiIsInR5cGUiOiJ3aXRuZXNzX3YwX2tleWhhc2gifX0seyJ2YWx1ZSI6MC4wMDAwMTI4NCwibiI6MSwic2NyaXB0UHViS2V5Ijp7ImFzbSI6IjAgYmRmZDZlMGU4ODljZTU3YzlhZGJmZTgxN2IyNjk3ODZjYTA4MjFkMyIsImhleCI6IjAwMTRiZGZkNmUwZTg4OWNlNTdjOWFkYmZlODE3YjI2OTc4NmNhMDgyMWQzIiwidHlwZSI6IndpdG5lc3NfdjBfa2V5aGFzaCJ9fV19LHsiaGV4IjoiMDIwMDAwMDAwMDAxMDFkZTk3MjdiZDRkNjk4ZjBmMDM3ODExMTZmMWJiZGNjNGJjZGY3ZTlhYTc4NGZhZTZjNzFhMDA3NjlmMGNmZTc4MDEwMDAwMDAwMGZkZmZmZmZmMDI4MTA0MGYwMDAwMDAwMDAwMTYwMDE0MGNjNjI1YTQ1MzQ2M2RmNGJkYTRhN2Y2N2Y4NGExMTk0MjBkYzkxMmU4MDMwMDAwMDAwMDAwMDAxNjAwMTQ5M2U5ZWI0YTcwNzIwYzhkNDdlM2U5NGI1Yzk1ZDJlN2YxM2UyYmQ4MDI0NzMwNDQwMjIwM2M1ODIxOTE0MWFmM2M3NDY2ZWRmODA1NjE5YTlhYmNlNGNjYmVmYjk2MDBlODEwYTk0ZGNhYThjOGE5MjYxZjAyMjA3ODEyZDczN2FmODVlYjFmOWQ0ZGJmNDllODNmNTJmZjE4YTEwZmMxZTUxM2FlYjMyOWNmMmVmZWQxODUxMjczMDEyMTAyZjQxYmI3YjZiYWY2NjVhMjEzMjM0ZDkyMWY3NDJlNzcwZTdlYjcyNDY5MTVmNjJjYzU0OGI4MmZmZTQxZjY3ODExM2IyNjAwIiwidHhpZCI6ImEzNGM1NDMwZTZlYzhkNDNmOWVjOWRjZGU1NWEwOTNlNmQxNTkyMWJlZGZkMjM3YzE5YzJmMGJmOGU3NjI3MWMiLCJoYXNoIjoiZjMxNGU1ZjUyMjE0OWJiMDk3NTc0NWM4YWUzOTVjMjdhYzQxYjlkM2NlZWJjMDNjZGEwNWJkMDVjZDQxYjNhMCIsInNpemUiOjIyMiwidnNpemUiOjE0MSwid2VpZ2h0Ijo1NjEsInZlcnNpb24iOjIsImxvY2t0aW1lIjoyNTA1NDg5LCJ2aW4iOlt7InR4aWQiOiI3OGZlMGM5Zjc2MDAxYWM3ZTZmYTg0YTc5YTdlZGZiY2M0ZGNiYmYxMTYxMTc4MDMwZjhmNjk0ZGJkMjc5N2RlIiwidm91dCI6MSwic2NyaXB0U2lnIjp7ImFzbSI6IiIsImhleCI6IiJ9LCJ0eGlud2l0bmVzcyI6WyIzMDQ0MDIyMDNjNTgyMTkxNDFhZjNjNzQ2NmVkZjgwNTYxOWE5YWJjZTRjY2JlZmI5NjAwZTgxMGE5NGRjYWE4YzhhOTI2MWYwMjIwNzgxMmQ3MzdhZjg1ZWIxZjlkNGRiZjQ5ZTgzZjUyZmYxOGExMGZjMWU1MTNhZWIzMjljZjJlZmVkMTg1MTI3MzAxIiwiMDJmNDFiYjdiNmJhZjY2NWEyMTMyMzRkOTIxZjc0MmU3NzBlN2ViNzI0NjkxNWY2MmNjNTQ4YjgyZmZlNDFmNjc4Il0sInNlcXVlbmNlIjo0Mjk0OTY3MjkzfV0sInZvdXQiOlt7InZhbHVlIjowLjAwOTg0MTkzLCJuIjowLCJzY3JpcHRQdWJLZXkiOnsiYXNtIjoiMCAwY2M2MjVhNDUzNDYzZGY0YmRhNGE3ZjY3Zjg0YTExOTQyMGRjOTEyIiwiaGV4IjoiMDAxNDBjYzYyNWE0NTM0NjNkZjRiZGE0YTdmNjdmODRhMTE5NDIwZGM5MTIiLCJ0eXBlIjoid2l0bmVzc192MF9rZXloYXNoIn19LHsidmFsdWUiOjAuMDAwMDEsIm4iOjEsInNjcmlwdFB1YktleSI6eyJhc20iOiIwIDkzZTllYjRhNzA3MjBjOGQ0N2UzZTk0YjVjOTVkMmU3ZjEzZTJiZDgiLCJoZXgiOiIwMDE0OTNlOWViNGE3MDcyMGM4ZDQ3ZTNlOTRiNWM5NWQyZTdmMTNlMmJkOCIsInR5cGUiOiJ3aXRuZXNzX3YwX2tleWhhc2gifX1dfSx7ImhleCI6IjAyMDAwMDAwMDAwMTAxOTFkOWU0ZDZjZGU5OWQyYzAwYWQwM2YxZmYwZTBiNTI0OWQ0YWIyYWNhOTg0ODc3YTI1MzNiYWZiMmMzMmFhZTAwMDAwMDAwMDBmZGZmZmZmZjFhMjIwMjAwMDAwMDAwMDAwMDIyNTEyMDQ3ZWI2OWU1ZTg0MDZjZDI4NzVhMzliMmJkOGJjNWJiM2Q4YTM3YTk4ODg1ZjI4MmU3ODhjMTYxODdhZmIxZWViOTAyMDAwMDAwMDAwMDAwMjI1MTIwODVjZTcxODRkYTU2NDgxZDY1ZGUyZjNlODhjMzAxOTJlNzM5MDdkYzJjZTc1ZDZkOTJiNTMzMjEzNzc0NDFjN2I5MDIwMDAwMDAwMDAwMDAyMjUxMjA5ZThiYjEyY2Y2ZmM4MmY4MzU2M2M3NDY4MDdhOGNlMDVkZWEwY2VkOWQ5MTMwZTAzNDVlZDg5ZjBjMWE3MDJiYjkwMjAwMDAwMDAwMDAwMDIyNTEyMDExNTgwNjNjYTg5ZDBlNTdmYzJjZDQ5YjFmZWZhZmQ2NDNiZWZkZmVmNmM2NDcyNWEzNWYzMGFkODE4N2I1MjNiOTAyMDAwMDAwMDAwMDAwMjI1MTIwYWY5NTI1ZDNhMDlhZTYzYjc0N2I5OTYzMDQzZjMxYjk3NDlmZjY3M2I5ZTVmODFhMjY2NWU1YWIyMDljYjkzMWI5MDIwMDAwMDAwMDAwMDAyMjUxMjAxMGM1MmY1ZWZlYzkzZThkMzI2ZTM4OTZhMzUyOGI1NWJlNGRkYTQwMmRhYzIyN2YzYTFhNjMwZGQ0ZThjODMzYjkwMjAwMDAwMDAwMDAwMDIyNTEyMDY2YzlhNjQ2YjJmZmNmYjY0MjkyZmQzMmM3NGE3ODhiNWY4ZTVjYmVhNzdhMjgyMmZjZGM4MmM4NTM0NDlmNTZiOTAyMDAwMDAwMDAwMDAwMjI1MTIwMjE5ZWY5NTE2NGI5MWVlZDk3MWQxNmUwYjFlZjc4ZTUwYzQ5Mjk0ZTNkMThlYjE3ZmQ3MDk2MDVlYzQ5ZTA5MWI5MDIwMDAwMDAwMDAwMDAyMjUxMjBkYjU5NmZjNTc4OGJmYjYzYTc2YjkzMDYyNDU4MWJhNTc5ZDA3ZmFmMzVlNzY0Zjc4ZGIzYTVhN2RhYzk1MzhhYjkwMjAwMDAwMDAwMDAwMDIyNTEyMDI0NmVhNzBlZmU4ZGM3OTlhNmUzNzRkNzcxMGIxZTM2NTZkNzU3MWRkZjQ1ODgwNjJmOGNmZWE1N2M3NzlmYmNiOTAyMDAwMDAwMDAwMDAwMjI1MTIwNDViMzBhMjNkNGQzYWU0NGFmODM5NWJjNGNiMmViZDFjOGNlNWZiNDk1OTQ0NmQ5MGVmN2M1MDczM2FiYWRiOGI5MDIwMDAwMDAwMDAwMDAyMjUxMjBiYzgxMGJiYjY2NmY5MThjNjQ4YzZlZWY2ODE5Mjg4ZjNkNDMzMzBlYWRjYzYxZmFhZGU0ZjE2OTY1OGUwNTQyYjkwMjAwMDAwMDAwMDAwMDIyNTEyMDNlYmMxMWQ0YzBlMWE2NTMyOWYxMTFhOTA5M2UxNDlkMThjYWQyN2MyYzM0MjFmN2E1MTI3OTdjNGIwYmRjMGViOTAyMDAwMDAwMDAwMDAwMjI1MTIwNzI3ZGU3NDNkOGE1MzQ5MDZjNTkzMmZkYTY5ZWM1MmEwNzZhNDNmMjJlYjRmOTE5N2E4MWFmMWI2OWFjYTcxNmI5MDIwMDAwMDAwMDAwMDAyMjUxMjAyOTJlNzBjNTAwMDIwYWI0MmI3ZTJkNDljMTI0NjYyOWNkOWExODQ3ODE4NjQ3MDg2MzMwOTAzMTYyZTU3MzljYjkwMjAwMDAwMDAwMDAwMDIyNTEyMGVhM2RmNDMzYjkzMjY4NTBmYWRiYTViNWVlMzc4NzIwNjM3YTJlOGJlNmFjODIxZjJlMGE3YjY4YjI0M2JlZTNiOTAyMDAwMDAwMDAwMDAwMjI1MTIwZDk5OTE3NTRjZGUzMjVmMjIxNzAzZDg3N2ExMTJmN2E1ZDZkMGU3YzQwODE3MWIwNTlmZTdiYThjNGYzNjA0OGI5MDIwMDAwMDAwMDAwMDAyMjUxMjAxN2NiZDhiYTRiNDY4ZDkwNDgzMWQ1NDM0ZDA1M2ZmNjAyMWZkOTdlZGU5NjlkMmUzNzVlNWE3NDA1MmM1ZTg2YjkwMjAwMDAwMDAwMDAwMDIyNTEyMDY2ZTExNDcxODliNjI4MmUyMmYxZjJhMWZlMmNjNjc4YzUzM2Q4NGYyMGExMjRlYTliNTU0NWQzMmNlODBmNTliOTAyMDAwMDAwMDAwMDAwMjI1MTIwMDdkZDc1OTZiNjVjNDNlNjc5MDY3NDM2Y2YxYzVhNDBlNTlkMzUwYjZhNmYzODM4MzRmYWZhNzJiODgzZmU4ZmI5MDIwMDAwMDAwMDAwMDAyMjUxMjA5ZTFiNTYwMjBiNGE4MTQxNzU3ZjU1NGRiMzUyZDgwYzc2NmY0OGU5MGFhODhmNzAwZmRhMDZlNzhiMWIxYzQ0YjkwMjAwMDAwMDAwMDAwMDIyNTEyMDNhZjlkYmE0NGZlMWE0NWQxMzA3MTlkZTU3ZmVlNzkwODRiMTcyYmZjMDM0YmI1ZmE5MDQxOGNkMzA1ODlhMTViOTAyMDAwMDAwMDAwMDAwMjI1MTIwN2M1MmEzNTczMzQwMWViN2YwZTY2ZjkyNTc1Yjc1MTFiMjQ0ZjE2MWFiNjY5OTVjMTBhMDNhMmQyNTQ1OThhYWI5MDIwMDAwMDAwMDAwMDAyMjUxMjAyZDBhZmY5YTcyYTQ1MjVkOGZiYTMxYmJjOThmNzE5YzkxZTdkYjI2MWNkM2NiMWVkYjFmYWYzMzM4MzlmODAxYjkwMjAwMDAwMDAwMDAwMDIyNTEyMGU3ZTJjM2M2YzJhNTMzN2FhYzZiNTU2MGY0ODc4MmQxYzRhY2Y5MDI0YmVhYzQ3ZjlkYTg3N2QyMmEzNGRjYTg4MGJkMDAwMDAwMDAwMDAwMTYwMDE0YmRmZDZlMGU4ODljZTU3YzlhZGJmZTgxN2IyNjk3ODZjYTA4MjFkMzAzNDAyY2I5YWU5M2NlOGZjZTA0YmM4MjliYWRjOGE0YjEzMTllMzE1MTQwZjhkOTUzZWQyMDY3NGU4Yzg3NWMzNzA0Mjg1MGI0Y2VmNWUzYjI2MTdmM2NiMGQ2Zjg5ODllNzg4NDc3OTE1ZDc4NWI4Zjc4ZDIwMTRjOTIyNmRlNDk3MTdiMjBiODIxY2ZjMDc5OWZhZmYxYjE2M2FlMmIxNTcwNTlkODEzZGUwNTNjMzY0ZGU0MjQ0ZTM1NDVlODFhZWE5MWI2YWMwMDYzMDM2ZjcyNjQwMTAxMTg3NDY1Nzg3NDJmNzA2YzYxNjk2ZTNiNjM2ODYxNzI3MzY1NzQzZDc1NzQ2NjJkMzgwMDM1N2IyMjcwMjIzYTIyNjI3MjYzMmQzMjMwMjIyYzIyNmY3MDIyM2EyMjZkNjk2ZTc0MjIyYzIyNzQ2OTYzNmIyMjNhMjI1NTUzNDQ1NDIyMmMyMjYxNmQ3NDIyM2EyMjMxMzAzMDMwMjI3ZDY4MjFjMDMwYzA1ZGJlOWZjZmNiM2M2ZDYzYjhjNTRhNThiN2MzNDM4MDQ2ZjVkMjc1MzBlMzM2MTViOGMwZTM0NWRhYmEwMDAwMDAwMCIsInR4aWQiOiJjZGRlNTdjNTk2YjljY2Y0MmY2MzczYTFmYzhmZjVhZDU5OTI1ZGQwMDVmMDQ3NzQ4NjFkYTFmOGQ1MmQ0Mjk1IiwiaGFzaCI6IjYxNWI1MWMzNGRiNGY3N2M3MDRhOTc2YmQ2NjkzMmI0ZWM0ZGVmNWNhMGY5Yjk5ZDI5Yjk5YmNkNjI4MDBhMzEiLCJzaXplIjoxMzgzLCJ2c2l6ZSI6MTIxNCwid2VpZ2h0Ijo0ODU0LCJ2ZXJzaW9uIjoyLCJsb2NrdGltZSI6MCwidmluIjpbeyJ0eGlkIjoiYWUyYWMzYjJhZjNiNTNhMjc3NDg5OGNhMmFhYmQ0NDk1MjBiMGVmZmYxMDNhZDAwMmM5ZGU5Y2RkNmU0ZDk5MSIsInZvdXQiOjAsInNjcmlwdFNpZyI6eyJhc20iOiIiLCJoZXgiOiIifSwidHhpbndpdG5lc3MiOlsiMmNiOWFlOTNjZThmY2UwNGJjODI5YmFkYzhhNGIxMzE5ZTMxNTE0MGY4ZDk1M2VkMjA2NzRlOGM4NzVjMzcwNDI4NTBiNGNlZjVlM2IyNjE3ZjNjYjBkNmY4OTg5ZTc4ODQ3NzkxNWQ3ODViOGY3OGQyMDE0YzkyMjZkZTQ5NzEiLCIyMGI4MjFjZmMwNzk5ZmFmZjFiMTYzYWUyYjE1NzA1OWQ4MTNkZTA1M2MzNjRkZTQyNDRlMzU0NWU4MWFlYTkxYjZhYzAwNjMwMzZmNzI2NDAxMDExODc0NjU3ODc0MmY3MDZjNjE2OTZlM2I2MzY4NjE3MjczNjU3NDNkNzU3NDY2MmQzODAwMzU3YjIyNzAyMjNhMjI2MjcyNjMyZDMyMzAyMjJjMjI2ZjcwMjIzYTIyNmQ2OTZlNzQyMjJjMjI3NDY5NjM2YjIyM2EyMjU1NTM0NDU0MjIyYzIyNjE2ZDc0MjIzYTIyMzEzMDMwMzAyMjdkNjgiLCJjMDMwYzA1ZGJlOWZjZmNiM2M2ZDYzYjhjNTRhNThiN2MzNDM4MDQ2ZjVkMjc1MzBlMzM2MTViOGMwZTM0NWRhYmEiXSwic2VxdWVuY2UiOjQyOTQ5NjcyOTN9XSwidm91dCI6W3sidmFsdWUiOjAuMDAwMDA1NDYsIm4iOjAsInNjcmlwdFB1YktleSI6eyJhc20iOiIxIDQ3ZWI2OWU1ZTg0MDZjZDI4NzVhMzliMmJkOGJjNWJiM2Q4YTM3YTk4ODg1ZjI4MmU3ODhjMTYxODdhZmIxZWUiLCJoZXgiOiI1MTIwNDdlYjY5ZTVlODQwNmNkMjg3NWEzOWIyYmQ4YmM1YmIzZDhhMzdhOTg4ODVmMjgyZTc4OGMxNjE4N2FmYjFlZSIsInR5cGUiOiJ3aXRuZXNzX3YxX3RhcHJvb3QifX0seyJ2YWx1ZSI6MC4wMDAwMDY5NywibiI6MSwic2NyaXB0UHViS2V5Ijp7ImFzbSI6IjEgODVjZTcxODRkYTU2NDgxZDY1ZGUyZjNlODhjMzAxOTJlNzM5MDdkYzJjZTc1ZDZkOTJiNTMzMjEzNzc0NDFjNyIsImhleCI6IjUxMjA4NWNlNzE4NGRhNTY0ODFkNjVkZTJmM2U4OGMzMDE5MmU3MzkwN2RjMmNlNzVkNmQ5MmI1MzMyMTM3NzQ0MWM3IiwidHlwZSI6IndpdG5lc3NfdjFfdGFwcm9vdCJ9fSx7InZhbHVlIjowLjAwMDAwNjk3LCJuIjoyLCJzY3JpcHRQdWJLZXkiOnsiYXNtIjoiMSA5ZThiYjEyY2Y2ZmM4MmY4MzU2M2M3NDY4MDdhOGNlMDVkZWEwY2VkOWQ5MTMwZTAzNDVlZDg5ZjBjMWE3MDJiIiwiaGV4IjoiNTEyMDllOGJiMTJjZjZmYzgyZjgzNTYzYzc0NjgwN2E4Y2UwNWRlYTBjZWQ5ZDkxMzBlMDM0NWVkODlmMGMxYTcwMmIiLCJ0eXBlIjoid2l0bmVzc192MV90YXByb290In19LHsidmFsdWUiOjAuMDAwMDA2OTcsIm4iOjMsInNjcmlwdFB1YktleSI6eyJhc20iOiIxIDExNTgwNjNjYTg5ZDBlNTdmYzJjZDQ5YjFmZWZhZmQ2NDNiZWZkZmVmNmM2NDcyNWEzNWYzMGFkODE4N2I1MjMiLCJoZXgiOiI1MTIwMTE1ODA2M2NhODlkMGU1N2ZjMmNkNDliMWZlZmFmZDY0M2JlZmRmZWY2YzY0NzI1YTM1ZjMwYWQ4MTg3YjUyMyIsInR5cGUiOiJ3aXRuZXNzX3YxX3RhcHJvb3QifX0seyJ2YWx1ZSI6MC4wMDAwMDY5NywibiI6NCwic2NyaXB0UHViS2V5Ijp7ImFzbSI6IjEgYWY5NTI1ZDNhMDlhZTYzYjc0N2I5OTYzMDQzZjMxYjk3NDlmZjY3M2I5ZTVmODFhMjY2NWU1YWIyMDljYjkzMSIsImhleCI6IjUxMjBhZjk1MjVkM2EwOWFlNjNiNzQ3Yjk5NjMwNDNmMzFiOTc0OWZmNjczYjllNWY4MWEyNjY1ZTVhYjIwOWNiOTMxIiwidHlwZSI6IndpdG5lc3NfdjFfdGFwcm9vdCJ9fSx7InZhbHVlIjowLjAwMDAwNjk3LCJuIjo1LCJzY3JpcHRQdWJLZXkiOnsiYXNtIjoiMSAxMGM1MmY1ZWZlYzkzZThkMzI2ZTM4OTZhMzUyOGI1NWJlNGRkYTQwMmRhYzIyN2YzYTFhNjMwZGQ0ZThjODMzIiwiaGV4IjoiNTEyMDEwYzUyZjVlZmVjOTNlOGQzMjZlMzg5NmEzNTI4YjU1YmU0ZGRhNDAyZGFjMjI3ZjNhMWE2MzBkZDRlOGM4MzMiLCJ0eXBlIjoid2l0bmVzc192MV90YXByb290In19LHsidmFsdWUiOjAuMDAwMDA2OTcsIm4iOjYsInNjcmlwdFB1YktleSI6eyJhc20iOiIxIDY2YzlhNjQ2YjJmZmNmYjY0MjkyZmQzMmM3NGE3ODhiNWY4ZTVjYmVhNzdhMjgyMmZjZGM4MmM4NTM0NDlmNTYiLCJoZXgiOiI1MTIwNjZjOWE2NDZiMmZmY2ZiNjQyOTJmZDMyYzc0YTc4OGI1ZjhlNWNiZWE3N2EyODIyZmNkYzgyYzg1MzQ0OWY1NiIsInR5cGUiOiJ3aXRuZXNzX3YxX3RhcHJvb3QifX0seyJ2YWx1ZSI6MC4wMDAwMDY5NywibiI6Nywic2NyaXB0UHViS2V5Ijp7ImFzbSI6IjEgMjE5ZWY5NTE2NGI5MWVlZDk3MWQxNmUwYjFlZjc4ZTUwYzQ5Mjk0ZTNkMThlYjE3ZmQ3MDk2MDVlYzQ5ZTA5MSIsImhleCI6IjUxMjAyMTllZjk1MTY0YjkxZWVkOTcxZDE2ZTBiMWVmNzhlNTBjNDkyOTRlM2QxOGViMTdmZDcwOTYwNWVjNDllMDkxIiwidHlwZSI6IndpdG5lc3NfdjFfdGFwcm9vdCJ9fSx7InZhbHVlIjowLjAwMDAwNjk3LCJuIjo4LCJzY3JpcHRQdWJLZXkiOnsiYXNtIjoiMSBkYjU5NmZjNTc4OGJmYjYzYTc2YjkzMDYyNDU4MWJhNTc5ZDA3ZmFmMzVlNzY0Zjc4ZGIzYTVhN2RhYzk1MzhhIiwiaGV4IjoiNTEyMGRiNTk2ZmM1Nzg4YmZiNjNhNzZiOTMwNjI0NTgxYmE1NzlkMDdmYWYzNWU3NjRmNzhkYjNhNWE3ZGFjOTUzOGEiLCJ0eXBlIjoid2l0bmVzc192MV90YXByb290In19LHsidmFsdWUiOjAuMDAwMDA2OTcsIm4iOjksInNjcmlwdFB1YktleSI6eyJhc20iOiIxIDI0NmVhNzBlZmU4ZGM3OTlhNmUzNzRkNzcxMGIxZTM2NTZkNzU3MWRkZjQ1ODgwNjJmOGNmZWE1N2M3NzlmYmMiLCJoZXgiOiI1MTIwMjQ2ZWE3MGVmZThkYzc5OWE2ZTM3NGQ3NzEwYjFlMzY1NmQ3NTcxZGRmNDU4ODA2MmY4Y2ZlYTU3Yzc3OWZiYyIsInR5cGUiOiJ3aXRuZXNzX3YxX3RhcHJvb3QifX0seyJ2YWx1ZSI6MC4wMDAwMDY5NywibiI6MTAsInNjcmlwdFB1YktleSI6eyJhc20iOiIxIDQ1YjMwYTIzZDRkM2FlNDRhZjgzOTViYzRjYjJlYmQxYzhjZTVmYjQ5NTk0NDZkOTBlZjdjNTA3MzNhYmFkYjgiLCJoZXgiOiI1MTIwNDViMzBhMjNkNGQzYWU0NGFmODM5NWJjNGNiMmViZDFjOGNlNWZiNDk1OTQ0NmQ5MGVmN2M1MDczM2FiYWRiOCIsInR5cGUiOiJ3aXRuZXNzX3YxX3RhcHJvb3QifX0seyJ2YWx1ZSI6MC4wMDAwMDY5NywibiI6MTEsInNjcmlwdFB1YktleSI6eyJhc20iOiIxIGJjODEwYmJiNjY2ZjkxOGM2NDhjNmVlZjY4MTkyODhmM2Q0MzMzMGVhZGNjNjFmYWFkZTRmMTY5NjU4ZTA1NDIiLCJoZXgiOiI1MTIwYmM4MTBiYmI2NjZmOTE4YzY0OGM2ZWVmNjgxOTI4OGYzZDQzMzMwZWFkY2M2MWZhYWRlNGYxNjk2NThlMDU0MiIsInR5cGUiOiJ3aXRuZXNzX3YxX3RhcHJvb3QifX0seyJ2YWx1ZSI6MC4wMDAwMDY5NywibiI6MTIsInNjcmlwdFB1YktleSI6eyJhc20iOiIxIDNlYmMxMWQ0YzBlMWE2NTMyOWYxMTFhOTA5M2UxNDlkMThjYWQyN2MyYzM0MjFmN2E1MTI3OTdjNGIwYmRjMGUiLCJoZXgiOiI1MTIwM2ViYzExZDRjMGUxYTY1MzI5ZjExMWE5MDkzZTE0OWQxOGNhZDI3YzJjMzQyMWY3YTUxMjc5N2M0YjBiZGMwZSIsInR5cGUiOiJ3aXRuZXNzX3YxX3RhcHJvb3QifX0seyJ2YWx1ZSI6MC4wMDAwMDY5NywibiI6MTMsInNjcmlwdFB1YktleSI6eyJhc20iOiIxIDcyN2RlNzQzZDhhNTM0OTA2YzU5MzJmZGE2OWVjNTJhMDc2YTQzZjIyZWI0ZjkxOTdhODFhZjFiNjlhY2E3MTYiLCJoZXgiOiI1MTIwNzI3ZGU3NDNkOGE1MzQ5MDZjNTkzMmZkYTY5ZWM1MmEwNzZhNDNmMjJlYjRmOTE5N2E4MWFmMWI2OWFjYTcxNiIsInR5cGUiOiJ3aXRuZXNzX3YxX3RhcHJvb3QifX0seyJ2YWx1ZSI6MC4wMDAwMDY5NywibiI6MTQsInNjcmlwdFB1YktleSI6eyJhc20iOiIxIDI5MmU3MGM1MDAwMjBhYjQyYjdlMmQ0OWMxMjQ2NjI5Y2Q5YTE4NDc4MTg2NDcwODYzMzA5MDMxNjJlNTczOWMiLCJoZXgiOiI1MTIwMjkyZTcwYzUwMDAyMGFiNDJiN2UyZDQ5YzEyNDY2MjljZDlhMTg0NzgxODY0NzA4NjMzMDkwMzE2MmU1NzM5YyIsInR5cGUiOiJ3aXRuZXNzX3YxX3RhcHJvb3QifX0seyJ2YWx1ZSI6MC4wMDAwMDY5NywibiI6MTUsInNjcmlwdFB1YktleSI6eyJhc20iOiIxIGVhM2RmNDMzYjkzMjY4NTBmYWRiYTViNWVlMzc4NzIwNjM3YTJlOGJlNmFjODIxZjJlMGE3YjY4YjI0M2JlZTMiLCJoZXgiOiI1MTIwZWEzZGY0MzNiOTMyNjg1MGZhZGJhNWI1ZWUzNzg3MjA2MzdhMmU4YmU2YWM4MjFmMmUwYTdiNjhiMjQzYmVlMyIsInR5cGUiOiJ3aXRuZXNzX3YxX3RhcHJvb3QifX0seyJ2YWx1ZSI6MC4wMDAwMDY5NywibiI6MTYsInNjcmlwdFB1YktleSI6eyJhc20iOiIxIGQ5OTkxNzU0Y2RlMzI1ZjIyMTcwM2Q4NzdhMTEyZjdhNWQ2ZDBlN2M0MDgxNzFiMDU5ZmU3YmE4YzRmMzYwNDgiLCJoZXgiOiI1MTIwZDk5OTE3NTRjZGUzMjVmMjIxNzAzZDg3N2ExMTJmN2E1ZDZkMGU3YzQwODE3MWIwNTlmZTdiYThjNGYzNjA0OCIsInR5cGUiOiJ3aXRuZXNzX3YxX3RhcHJvb3QifX0seyJ2YWx1ZSI6MC4wMDAwMDY5NywibiI6MTcsInNjcmlwdFB1YktleSI6eyJhc20iOiIxIDE3Y2JkOGJhNGI0NjhkOTA0ODMxZDU0MzRkMDUzZmY2MDIxZmQ5N2VkZTk2OWQyZTM3NWU1YTc0MDUyYzVlODYiLCJoZXgiOiI1MTIwMTdjYmQ4YmE0YjQ2OGQ5MDQ4MzFkNTQzNGQwNTNmZjYwMjFmZDk3ZWRlOTY5ZDJlMzc1ZTVhNzQwNTJjNWU4NiIsInR5cGUiOiJ3aXRuZXNzX3YxX3RhcHJvb3QifX0seyJ2YWx1ZSI6MC4wMDAwMDY5NywibiI6MTgsInNjcmlwdFB1YktleSI6eyJhc20iOiIxIDY2ZTExNDcxODliNjI4MmUyMmYxZjJhMWZlMmNjNjc4YzUzM2Q4NGYyMGExMjRlYTliNTU0NWQzMmNlODBmNTkiLCJoZXgiOiI1MTIwNjZlMTE0NzE4OWI2MjgyZTIyZjFmMmExZmUyY2M2NzhjNTMzZDg0ZjIwYTEyNGVhOWI1NTQ1ZDMyY2U4MGY1OSIsInR5cGUiOiJ3aXRuZXNzX3YxX3RhcHJvb3QifX0seyJ2YWx1ZSI6MC4wMDAwMDY5NywibiI6MTksInNjcmlwdFB1YktleSI6eyJhc20iOiIxIDA3ZGQ3NTk2YjY1YzQzZTY3OTA2NzQzNmNmMWM1YTQwZTU5ZDM1MGI2YTZmMzgzODM0ZmFmYTcyYjg4M2ZlOGYiLCJoZXgiOiI1MTIwMDdkZDc1OTZiNjVjNDNlNjc5MDY3NDM2Y2YxYzVhNDBlNTlkMzUwYjZhNmYzODM4MzRmYWZhNzJiODgzZmU4ZiIsInR5cGUiOiJ3aXRuZXNzX3YxX3RhcHJvb3QifX0seyJ2YWx1ZSI6MC4wMDAwMDY5NywibiI6MjAsInNjcmlwdFB1YktleSI6eyJhc20iOiIxIDllMWI1NjAyMGI0YTgxNDE3NTdmNTU0ZGIzNTJkODBjNzY2ZjQ4ZTkwYWE4OGY3MDBmZGEwNmU3OGIxYjFjNDQiLCJoZXgiOiI1MTIwOWUxYjU2MDIwYjRhODE0MTc1N2Y1NTRkYjM1MmQ4MGM3NjZmNDhlOTBhYTg4ZjcwMGZkYTA2ZTc4YjFiMWM0NCIsInR5cGUiOiJ3aXRuZXNzX3YxX3RhcHJvb3QifX0seyJ2YWx1ZSI6MC4wMDAwMDY5NywibiI6MjEsInNjcmlwdFB1YktleSI6eyJhc20iOiIxIDNhZjlkYmE0NGZlMWE0NWQxMzA3MTlkZTU3ZmVlNzkwODRiMTcyYmZjMDM0YmI1ZmE5MDQxOGNkMzA1ODlhMTUiLCJoZXgiOiI1MTIwM2FmOWRiYTQ0ZmUxYTQ1ZDEzMDcxOWRlNTdmZWU3OTA4NGIxNzJiZmMwMzRiYjVmYTkwNDE4Y2QzMDU4OWExNSIsInR5cGUiOiJ3aXRuZXNzX3YxX3RhcHJvb3QifX0seyJ2YWx1ZSI6MC4wMDAwMDY5NywibiI6MjIsInNjcmlwdFB1YktleSI6eyJhc20iOiIxIDdjNTJhMzU3MzM0MDFlYjdmMGU2NmY5MjU3NWI3NTExYjI0NGYxNjFhYjY2OTk1YzEwYTAzYTJkMjU0NTk4YWEiLCJoZXgiOiI1MTIwN2M1MmEzNTczMzQwMWViN2YwZTY2ZjkyNTc1Yjc1MTFiMjQ0ZjE2MWFiNjY5OTVjMTBhMDNhMmQyNTQ1OThhYSIsInR5cGUiOiJ3aXRuZXNzX3YxX3RhcHJvb3QifX0seyJ2YWx1ZSI6MC4wMDAwMDY5NywibiI6MjMsInNjcmlwdFB1YktleSI6eyJhc20iOiIxIDJkMGFmZjlhNzJhNDUyNWQ4ZmJhMzFiYmM5OGY3MTljOTFlN2RiMjYxY2QzY2IxZWRiMWZhZjMzMzgzOWY4MDEiLCJoZXgiOiI1MTIwMmQwYWZmOWE3MmE0NTI1ZDhmYmEzMWJiYzk4ZjcxOWM5MWU3ZGIyNjFjZDNjYjFlZGIxZmFmMzMzODM5ZjgwMSIsInR5cGUiOiJ3aXRuZXNzX3YxX3RhcHJvb3QifX0seyJ2YWx1ZSI6MC4wMDAwMDY5NywibiI6MjQsInNjcmlwdFB1YktleSI6eyJhc20iOiIxIGU3ZTJjM2M2YzJhNTMzN2FhYzZiNTU2MGY0ODc4MmQxYzRhY2Y5MDI0YmVhYzQ3ZjlkYTg3N2QyMmEzNGRjYTgiLCJoZXgiOiI1MTIwZTdlMmMzYzZjMmE1MzM3YWFjNmI1NTYwZjQ4NzgyZDFjNGFjZjkwMjRiZWFjNDdmOWRhODc3ZDIyYTM0ZGNhOCIsInR5cGUiOiJ3aXRuZXNzX3YxX3RhcHJvb3QifX0seyJ2YWx1ZSI6MC4wMDA0ODUxMiwibiI6MjUsInNjcmlwdFB1YktleSI6eyJhc20iOiIwIGJkZmQ2ZTBlODg5Y2U1N2M5YWRiZmU4MTdiMjY5Nzg2Y2EwODIxZDMiLCJoZXgiOiIwMDE0YmRmZDZlMGU4ODljZTU3YzlhZGJmZTgxN2IyNjk3ODZjYTA4MjFkMyIsInR5cGUiOiJ3aXRuZXNzX3YwX2tleWhhc2gifX1dfSx7ImhleCI6IjAyMDAwMDAwMDAwMTAxOTU0MjJkZDVmOGExMWQ4Njc0NDdmMDA1ZDA1ZDkyNTlhZGY1OGZmY2ExNzM2MzJmZjRjY2I5OTZjNTU3ZGVjZDExMDAwMDAwMDBmZmZmZmZmZjAxMjIwMjAwMDAwMDAwMDAwMDIyNTEyMDQ3ZWI2OWU1ZTg0MDZjZDI4NzVhMzliMmJkOGJjNWJiM2Q4YTM3YTk4ODg1ZjI4MmU3ODhjMTYxODdhZmIxZWUwMzQwMDkxOTUwMTIwOGUzMTc5N2JhODAxYzgyZmEyNjBkYzU2YmZhZmJmNjg5YjU1MzBiNWE0ZTllMzI2ZTI1MTRiYjdlNmU0NDJmYjU0ZTM0NTk5ZTIwZDRiZThhNTllNjBkZjVkYTk1ZWRiOWZjN2RmZDlmY2UyMjM4ZWMzZjA0MzM3YjIwNzI1NzM0ZGRlZjJkYzhkM2Y4NDIwYzA3NzQ5Y2QyMzkzODFmMDFiNTM4MDNiYTk3ZDRiNGEwOTZhNjJlOWFiZWFjMDA2MzAzNmY3MjY0MDEwMTE4NzQ2NTc4NzQyZjcwNmM2MTY5NmUzYjYzNjg2MTcyNzM2NTc0M2Q3NTc0NjYyZDM4MDAzNTdiMjI3MDIyM2EyMjYyNzI2MzJkMzIzMDIyMmMyMjZmNzAyMjNhMjI2ZDY5NmU3NDIyMmMyMjc0Njk2MzZiMjIzYTIyNTU1MzQ0NTQyMjJjMjI2MTZkNzQyMjNhMjIzMTMwMzAzMDIyN2Q2ODIxYzAzMGMwNWRiZTlmY2ZjYjNjNmQ2M2I4YzU0YTU4YjdjMzQzODA0NmY1ZDI3NTMwZTMzNjE1YjhjMGUzNDVkYWJhMDAwMDAwMDAiLCJ0eGlkIjoiMTE2YjJmZjgxYzA1ZTk0MTU1Nzg1ZjUzMTViOGJmMmNiN2YwNjRlMTRkMTczZGY5YmRkZjViYjM5MGUwZGEyMiIsImhhc2giOiIxNGY2NTAyNGU2MWQyMDc2MWE1NmE0ZTk2YzQzNDQyNmM3OThmODg0MmU2N2UxZDY2YjMwYWZiM2Y1MWZiOTUyIiwic2l6ZSI6MzIwLCJ2c2l6ZSI6MTUxLCJ3ZWlnaHQiOjYwMiwidmVyc2lvbiI6MiwibG9ja3RpbWUiOjAsInZpbiI6W3sidHhpZCI6ImNkZGU1N2M1OTZiOWNjZjQyZjYzNzNhMWZjOGZmNWFkNTk5MjVkZDAwNWYwNDc3NDg2MWRhMWY4ZDUyZDQyOTUiLCJ2b3V0IjoxNywic2NyaXB0U2lnIjp7ImFzbSI6IiIsImhleCI6IiJ9LCJ0eGlud2l0bmVzcyI6WyIwOTE5NTAxMjA4ZTMxNzk3YmE4MDFjODJmYTI2MGRjNTZiZmFmYmY2ODliNTUzMGI1YTRlOWUzMjZlMjUxNGJiN2U2ZTQ0MmZiNTRlMzQ1OTllMjBkNGJlOGE1OWU2MGRmNWRhOTVlZGI5ZmM3ZGZkOWZjZTIyMzhlYzNmMDQzMyIsIjIwNzI1NzM0ZGRlZjJkYzhkM2Y4NDIwYzA3NzQ5Y2QyMzkzODFmMDFiNTM4MDNiYTk3ZDRiNGEwOTZhNjJlOWFiZWFjMDA2MzAzNmY3MjY0MDEwMTE4NzQ2NTc4NzQyZjcwNmM2MTY5NmUzYjYzNjg2MTcyNzM2NTc0M2Q3NTc0NjYyZDM4MDAzNTdiMjI3MDIyM2EyMjYyNzI2MzJkMzIzMDIyMmMyMjZmNzAyMjNhMjI2ZDY5NmU3NDIyMmMyMjc0Njk2MzZiMjIzYTIyNTU1MzQ0NTQyMjJjMjI2MTZkNzQyMjNhMjIzMTMwMzAzMDIyN2Q2OCIsImMwMzBjMDVkYmU5ZmNmY2IzYzZkNjNiOGM1NGE1OGI3YzM0MzgwNDZmNWQyNzUzMGUzMzYxNWI4YzBlMzQ1ZGFiYSJdLCJzZXF1ZW5jZSI6NDI5NDk2NzI5NX1dLCJ2b3V0IjpbeyJ2YWx1ZSI6MC4wMDAwMDU0NiwibiI6MCwic2NyaXB0UHViS2V5Ijp7ImFzbSI6IjEgNDdlYjY5ZTVlODQwNmNkMjg3NWEzOWIyYmQ4YmM1YmIzZDhhMzdhOTg4ODVmMjgyZTc4OGMxNjE4N2FmYjFlZSIsImhleCI6IjUxMjA0N2ViNjllNWU4NDA2Y2QyODc1YTM5YjJiZDhiYzViYjNkOGEzN2E5ODg4NWYyODJlNzg4YzE2MTg3YWZiMWVlIiwidHlwZSI6IndpdG5lc3NfdjFfdGFwcm9vdCJ9fV19LHsiaGV4IjoiMDIwMDAwMDAwMDAxMDE5ZDExOGVjYjkwZDEyYTNlYmQ0OGFlMzIwOGQyMmEzZWQyZjIwOGVjYmQzYTZkNjQ4OTlkMTgyYmQwMWViMGYzMGYwMDAwMDAwMGZmZmZmZmZmMDEyMjAyMDAwMDAwMDAwMDAwMjI1MTIwMmRlODUyMTQ4ZWQzMTY4ODU1NjRjNDQ2MmJkMGZkMDA2NjZkM2UwNzlkODUyMDE5ZTQxZjkwMjEyMDg3OGRkNTAzNDBjOTEyN2NmNGFlYTYyMjNjZjViN2JhOGI1NTUyMzE5NjM1YjNiNTNlMjYwYWM3Mjg4ZDY2ODIxZWFjODc5YjQ0MjUxOTQ2MmIwOTE3MDg4ZDYwNTFmODRiZWZiMWNlZGFhNDBhOTI3ZjI4Y2MxODkyMDg1NTljZWU0YjE1MTg2OTdiMjBkMjhmMGMzMzQ5ZmJiMGVkMGFkMjA2YTlhNGQwZDE3MzRjMjg5NjFiNDc0OTE2ZTVmYjcwNTkxNDYyYmRmNmU2YWMwMDYzMDM2ZjcyNjQwMTAxMTg3NDY1Nzg3NDJmNzA2YzYxNjk2ZTNiNjM2ODYxNzI3MzY1NzQzZDc1NzQ2NjJkMzgwMDM1N2IyMjcwMjIzYTIyNjI3MjYzMmQzMjMwMjIyYzIyNmY3MDIyM2EyMjZkNjk2ZTc0MjIyYzIyNzQ2OTYzNmIyMjNhMjI2ZDY1NmQ2NTIyMmMyMjYxNmQ3NDIyM2EyMjMxMzAzMDMwMjI3ZDY4MjFjMDk4MzcxYzEwOGY2NWFjOTNjMmQwODkwMGEwZWI2ZWFjZTkwYTU0NzE4NjgwMWZhMjUyYjQzZTU3ZTdlMjc1NTEwMDAwMDAwMCIsInR4aWQiOiIxMDRjNjc4MDJkYjk0ODIzNDM1NDczNjdjZDcxMzEwOGMzODkyMjEyYmQ5M2FiYWRhNGY1NTcwYjQ0MTc5YjI0IiwiaGFzaCI6IjM3MDhhODNiNWE0Y2YzNGRjNmM3ZjZlOTJhMWRlNmZmZTRlMDBkOGNjZDJkNWM0NDgxNGNhMDA0Mzk0ZTcwMzIiLCJzaXplIjozMjAsInZzaXplIjoxNTEsIndlaWdodCI6NjAyLCJ2ZXJzaW9uIjoyLCJsb2NrdGltZSI6MCwidmluIjpbeyJ0eGlkIjoiZjNiMDFlZDAyYjE4OWQ4OTY0NmQzYWJkZWMwOGYyZDIzZTJhZDIwODMyYWU0OGJkM2UyYWQxOTBjYjhlMTE5ZCIsInZvdXQiOjE1LCJzY3JpcHRTaWciOnsiYXNtIjoiIiwiaGV4IjoiIn0sInR4aW53aXRuZXNzIjpbImM5MTI3Y2Y0YWVhNjIyM2NmNWI3YmE4YjU1NTIzMTk2MzViM2I1M2UyNjBhYzcyODhkNjY4MjFlYWM4NzliNDQyNTE5NDYyYjA5MTcwODhkNjA1MWY4NGJlZmIxY2VkYWE0MGE5MjdmMjhjYzE4OTIwODU1OWNlZTRiMTUxODY5IiwiMjBkMjhmMGMzMzQ5ZmJiMGVkMGFkMjA2YTlhNGQwZDE3MzRjMjg5NjFiNDc0OTE2ZTVmYjcwNTkxNDYyYmRmNmU2YWMwMDYzMDM2ZjcyNjQwMTAxMTg3NDY1Nzg3NDJmNzA2YzYxNjk2ZTNiNjM2ODYxNzI3MzY1NzQzZDc1NzQ2NjJkMzgwMDM1N2IyMjcwMjIzYTIyNjI3MjYzMmQzMjMwMjIyYzIyNmY3MDIyM2EyMjZkNjk2ZTc0MjIyYzIyNzQ2OTYzNmIyMjNhMjI2ZDY1NmQ2NTIyMmMyMjYxNmQ3NDIyM2EyMjMxMzAzMDMwMjI3ZDY4IiwiYzA5ODM3MWMxMDhmNjVhYzkzYzJkMDg5MDBhMGViNmVhY2U5MGE1NDcxODY4MDFmYTI1MmI0M2U1N2U3ZTI3NTUxIl0sInNlcXVlbmNlIjo0Mjk0OTY3Mjk1fV0sInZvdXQiOlt7InZhbHVlIjowLjAwMDAwNTQ2LCJuIjowLCJzY3JpcHRQdWJLZXkiOnsiYXNtIjoiMSAyZGU4NTIxNDhlZDMxNjg4NTU2NGM0NDYyYmQwZmQwMDY2NmQzZTA3OWQ4NTIwMTllNDFmOTAyMTIwODc4ZGQ1IiwiaGV4IjoiNTEyMDJkZTg1MjE0OGVkMzE2ODg1NTY0YzQ0NjJiZDBmZDAwNjY2ZDNlMDc5ZDg1MjAxOWU0MWY5MDIxMjA4NzhkZDUiLCJ0eXBlIjoid2l0bmVzc192MV90YXByb290In19XX0seyJoZXgiOiIwMjAwMDAwMDAwMDEwMWMwMWMyM2I1M2Y3MzAwNWE1ODYxYTEyZDc4NzFkNWY2MGZhZDdhNDRlYjdlYzcxNjM0YmUyMzVhNGMzN2M1N2IwMDAwMDAwMDAwZmRmZmZmZmYwMjIyMDIwMDAwMDAwMDAwMDAxNjAwMTQyNjZiNWNiYTdlZmMyZWYyZGM5N2FlMWRlZjZjMzkzYmU0ZTM0ZTFmMDUwNTAwMDAwMDAwMDAwMDE2MDAxNGJkZmQ2ZTBlODg5Y2U1N2M5YWRiZmU4MTdiMjY5Nzg2Y2EwODIxZDMwMzQwYTJiMmRiOTgwZGVmOWQ3ZGUxYjZhN2VmZmEyNWM2MDFlZDgxNDg0MGIwY2NmZDNlY2NkODEyODRkMzQ4NjBmMWUyMDAyYWQ5YjczOGU2MDY5M2IxOTExNWE3MmZhMGFhNWE2NjEyOTk4ZGM5OWM0ZGMxZmEzM2RjZmViZjgzZTM3OTIwODk3YjRhNGJjOTcxY2M3OGU0MDc1OTRkMmRkYmY4NGZiOWZmODBkMjE5ZTQ3ZDVmNDZlZTM2M2NjZjhiMzU1NGFjMDA2MzAzNmY3MjY0MDEwMTE4NzQ2NTc4NzQyZjcwNmM2MTY5NmUzYjYzNjg2MTcyNzM2NTc0M2Q3NTc0NjYyZDM4MDAzMzdiMjI3MDIyM2EyMjYyNzI2MzJkMzIzMDIyMmMyMjZmNzAyMjNhMjI2ZDY5NmU3NDIyMmMyMjc0Njk2MzZiMjIzYTIyNjQ2MTczNjMyMjJjMjI2MTZkNzQyMjNhMjIzMTMwMjI3ZDY4MjFjMGNkZTQ0YzkzZmNiZWVjNjk2MTJiZDhlNjRhYWEyMDBiOWU3MGZmYmY1YTc1NWNjOWQ4MmE3ZmEwMTNlMjIzMTUwMDAwMDAwMCIsInR4aWQiOiJmYjk2ZTIwOTBkZWZmZDYxZjEwMTUxZWQyNzY0NWYyOGY3MzA2MGFmOGM0MDdkZTA4Y2E0ODFiMjVmMTI0NTJhIiwiaGFzaCI6ImE0MTgxNjMwMTRlYjMwMWI5ZTc1ZGFhYjczM2E5YzVkYjA0ZGE1MjIwNDhjNDVmMmY5MzhjOGU4NTFjMWI2NDQiLCJzaXplIjozMzcsInZzaXplIjoxNjksIndlaWdodCI6Njc2LCJ2ZXJzaW9uIjoyLCJsb2NrdGltZSI6MCwidmluIjpbeyJ0eGlkIjoiN2JjNTM3NGM1YTIzYmUzNDE2Yzc3ZWViNDQ3YWFkMGZmNmQ1NzE3ODJkYTE2MTU4NWEwMDczM2ZiNTIzMWNjMCIsInZvdXQiOjAsInNjcmlwdFNpZyI6eyJhc20iOiIiLCJoZXgiOiIifSwidHhpbndpdG5lc3MiOlsiYTJiMmRiOTgwZGVmOWQ3ZGUxYjZhN2VmZmEyNWM2MDFlZDgxNDg0MGIwY2NmZDNlY2NkODEyODRkMzQ4NjBmMWUyMDAyYWQ5YjczOGU2MDY5M2IxOTExNWE3MmZhMGFhNWE2NjEyOTk4ZGM5OWM0ZGMxZmEzM2RjZmViZjgzZTMiLCIyMDg5N2I0YTRiYzk3MWNjNzhlNDA3NTk0ZDJkZGJmODRmYjlmZjgwZDIxOWU0N2Q1ZjQ2ZWUzNjNjY2Y4YjM1NTRhYzAwNjMwMzZmNzI2NDAxMDExODc0NjU3ODc0MmY3MDZjNjE2OTZlM2I2MzY4NjE3MjczNjU3NDNkNzU3NDY2MmQzODAwMzM3YjIyNzAyMjNhMjI2MjcyNjMyZDMyMzAyMjJjMjI2ZjcwMjIzYTIyNmQ2OTZlNzQyMjJjMjI3NDY5NjM2YjIyM2EyMjY0NjE3MzYzMjIyYzIyNjE2ZDc0MjIzYTIyMzEzMDIyN2Q2OCIsImMwY2RlNDRjOTNmY2JlZWM2OTYxMmJkOGU2NGFhYTIwMGI5ZTcwZmZiZjVhNzU1Y2M5ZDgyYTdmYTAxM2UyMjMxNSJdLCJzZXF1ZW5jZSI6NDI5NDk2NzI5M31dLCJ2b3V0IjpbeyJ2YWx1ZSI6MC4wMDAwMDU0NiwibiI6MCwic2NyaXB0UHViS2V5Ijp7ImFzbSI6IjAgMjY2YjVjYmE3ZWZjMmVmMmRjOTdhZTFkZWY2YzM5M2JlNGUzNGUxZiIsImhleCI6IjAwMTQyNjZiNWNiYTdlZmMyZWYyZGM5N2FlMWRlZjZjMzkzYmU0ZTM0ZTFmIiwidHlwZSI6IndpdG5lc3NfdjBfa2V5aGFzaCJ9fSx7InZhbHVlIjowLjAwMDAxMjg1LCJuIjoxLCJzY3JpcHRQdWJLZXkiOnsiYXNtIjoiMCBiZGZkNmUwZTg4OWNlNTdjOWFkYmZlODE3YjI2OTc4NmNhMDgyMWQzIiwiaGV4IjoiMDAxNGJkZmQ2ZTBlODg5Y2U1N2M5YWRiZmU4MTdiMjY5Nzg2Y2EwODIxZDMiLCJ0eXBlIjoid2l0bmVzc192MF9rZXloYXNoIn19XX0seyJoZXgiOiIwMjAwMDAwMDAwMDEwMTlkMTE4ZWNiOTBkMTJhM2ViZDQ4YWUzMjA4ZDIyYTNlZDJmMjA4ZWNiZDNhNmQ2NDg5OWQxODJiZDAxZWIwZjMwMzAwMDAwMDAwZmZmZmZmZmYwMTIyMDIwMDAwMDAwMDAwMDAyMjUxMjAyZGU4NTIxNDhlZDMxNjg4NTU2NGM0NDYyYmQwZmQwMDY2NmQzZTA3OWQ4NTIwMTllNDFmOTAyMTIwODc4ZGQ1MDM0MDFjM2JkYTgxYmRlODZmYzhjNWQwZWE3ODYxN2E1Yzc1ODNmMTFjYzE4ZGNjYTlkOTMyMjE5YmE0YjFhZjE5MzAwZTcxYTA2N2I2MjhlMDM5ZGU4NDMwODRhZDg3YThhOTFhZmM5MTNiZGQwNDc0Mzc4ZTUwMzUyYmQ0ZjMzMGYxN2IyMGQ0MDg0NGRhOGNhNWE1NDkzMmM0NDk4YzYzNDA5OGZlOTU0NDExOTliOWJkM2Y3MTQzNDY4ZDEwNTYzMDA2ZTVhYzAwNjMwMzZmNzI2NDAxMDExODc0NjU3ODc0MmY3MDZjNjE2OTZlM2I2MzY4NjE3MjczNjU3NDNkNzU3NDY2MmQzODAwMzU3YjIyNzAyMjNhMjI2MjcyNjMyZDMyMzAyMjJjMjI2ZjcwMjIzYTIyNmQ2OTZlNzQyMjJjMjI3NDY5NjM2YjIyM2EyMjZkNjU2ZDY1MjIyYzIyNjE2ZDc0MjIzYTIyMzEzMDMwMzAyMjdkNjgyMWMwOTgzNzFjMTA4ZjY1YWM5M2MyZDA4OTAwYTBlYjZlYWNlOTBhNTQ3MTg2ODAxZmEyNTJiNDNlNTdlN2UyNzU1MTAwMDAwMDAwIiwidHhpZCI6Ijg4OTE2OTkwMGI1YWY2ZmQxMTlkMTBkOWMxYmI0NzIyMWNlZGY2NjAyN2RjZTdkYzRlOGZlYjVlYTJhOTA5MmQiLCJoYXNoIjoiY2ViYTFhOTVkYjZjZmJlY2Q4YWVjYjY1YmU4NTA5NTE0MDBmZjQxZjAxMWQxZmI1MjFmZmMwMGVkNTAzZGFkNyIsInNpemUiOjMyMCwidnNpemUiOjE1MSwid2VpZ2h0Ijo2MDIsInZlcnNpb24iOjIsImxvY2t0aW1lIjowLCJ2aW4iOlt7InR4aWQiOiJmM2IwMWVkMDJiMTg5ZDg5NjQ2ZDNhYmRlYzA4ZjJkMjNlMmFkMjA4MzJhZTQ4YmQzZTJhZDE5MGNiOGUxMTlkIiwidm91dCI6Mywic2NyaXB0U2lnIjp7ImFzbSI6IiIsImhleCI6IiJ9LCJ0eGlud2l0bmVzcyI6WyIxYzNiZGE4MWJkZTg2ZmM4YzVkMGVhNzg2MTdhNWM3NTgzZjExY2MxOGRjY2E5ZDkzMjIxOWJhNGIxYWYxOTMwMGU3MWEwNjdiNjI4ZTAzOWRlODQzMDg0YWQ4N2E4YTkxYWZjOTEzYmRkMDQ3NDM3OGU1MDM1MmJkNGYzMzBmMSIsIjIwZDQwODQ0ZGE4Y2E1YTU0OTMyYzQ0OThjNjM0MDk4ZmU5NTQ0MTE5OWI5YmQzZjcxNDM0NjhkMTA1NjMwMDZlNWFjMDA2MzAzNmY3MjY0MDEwMTE4NzQ2NTc4NzQyZjcwNmM2MTY5NmUzYjYzNjg2MTcyNzM2NTc0M2Q3NTc0NjYyZDM4MDAzNTdiMjI3MDIyM2EyMjYyNzI2MzJkMzIzMDIyMmMyMjZmNzAyMjNhMjI2ZDY5NmU3NDIyMmMyMjc0Njk2MzZiMjIzYTIyNmQ2NTZkNjUyMjJjMjI2MTZkNzQyMjNhMjIzMTMwMzAzMDIyN2Q2OCIsImMwOTgzNzFjMTA4ZjY1YWM5M2MyZDA4OTAwYTBlYjZlYWNlOTBhNTQ3MTg2ODAxZmEyNTJiNDNlNTdlN2UyNzU1MSJdLCJzZXF1ZW5jZSI6NDI5NDk2NzI5NX1dLCJ2b3V0IjpbeyJ2YWx1ZSI6MC4wMDAwMDU0NiwibiI6MCwic2NyaXB0UHViS2V5Ijp7ImFzbSI6IjEgMmRlODUyMTQ4ZWQzMTY4ODU1NjRjNDQ2MmJkMGZkMDA2NjZkM2UwNzlkODUyMDE5ZTQxZjkwMjEyMDg3OGRkNSIsImhleCI6IjUxMjAyZGU4NTIxNDhlZDMxNjg4NTU2NGM0NDYyYmQwZmQwMDY2NmQzZTA3OWQ4NTIwMTllNDFmOTAyMTIwODc4ZGQ1IiwidHlwZSI6IndpdG5lc3NfdjFfdGFwcm9vdCJ9fV19LHsiaGV4IjoiMDIwMDAwMDAwMDAxMDE5ZDExOGVjYjkwZDEyYTNlYmQ0OGFlMzIwOGQyMmEzZWQyZjIwOGVjYmQzYTZkNjQ4OTlkMTgyYmQwMWViMGYzMDYwMDAwMDAwMGZmZmZmZmZmMDEyMjAyMDAwMDAwMDAwMDAwMjI1MTIwMmRlODUyMTQ4ZWQzMTY4ODU1NjRjNDQ2MmJkMGZkMDA2NjZkM2UwNzlkODUyMDE5ZTQxZjkwMjEyMDg3OGRkNTAzNDBiNTY2NTQ2ZWI1ZDlhNjdlNWI4YTI3OTBlNmMzZjI3ZTViY2ZlMTNmNTc2ZmFiOTc2MzU0NjFlYjllNmY4OTY1ZmY2NTU4NTU5MWRkZmJkMTlkNmQ0NTZmYzI1MjQ5ODRhYjBmNzU0YmE4NWNlNGJjNjI0MzAxMTlkNjA3ZDMzZTdiMjA0MTU1ZDc5OTUzNDcwMzBhYzZmZWRiMzY3OGIyNWMyZTNkYTUzZGMxMTYwNjk4YTQ5NmQwZjAwMTk5MzA2ZmQwYWMwMDYzMDM2ZjcyNjQwMTAxMTg3NDY1Nzg3NDJmNzA2YzYxNjk2ZTNiNjM2ODYxNzI3MzY1NzQzZDc1NzQ2NjJkMzgwMDM1N2IyMjcwMjIzYTIyNjI3MjYzMmQzMjMwMjIyYzIyNmY3MDIyM2EyMjZkNjk2ZTc0MjIyYzIyNzQ2OTYzNmIyMjNhMjI2ZDY1NmQ2NTIyMmMyMjYxNmQ3NDIyM2EyMjMxMzAzMDMwMjI3ZDY4MjFjMDk4MzcxYzEwOGY2NWFjOTNjMmQwODkwMGEwZWI2ZWFjZTkwYTU0NzE4NjgwMWZhMjUyYjQzZTU3ZTdlMjc1NTEwMDAwMDAwMCIsInR4aWQiOiIxMGMwN2E2YTFhMTdhZDA0ZDYzODY2ZjA3M2JmMzllNGVmYjUzOWY4ODBjZDQ5OWU2ZjA0NTc2YjNkYjY5ZjJmIiwiaGFzaCI6IjY4NzM5YzVjNmVjMDZkNTg5YTViYmY0YWU4ZTE3OGI5ZDI4MmZlNDhjYTNhYmU3ZTcxZTA5YzVmZmM0MWU4YjQiLCJzaXplIjozMjAsInZzaXplIjoxNTEsIndlaWdodCI6NjAyLCJ2ZXJzaW9uIjoyLCJsb2NrdGltZSI6MCwidmluIjpbeyJ0eGlkIjoiZjNiMDFlZDAyYjE4OWQ4OTY0NmQzYWJkZWMwOGYyZDIzZTJhZDIwODMyYWU0OGJkM2UyYWQxOTBjYjhlMTE5ZCIsInZvdXQiOjYsInNjcmlwdFNpZyI6eyJhc20iOiIiLCJoZXgiOiIifSwidHhpbndpdG5lc3MiOlsiYjU2NjU0NmViNWQ5YTY3ZTViOGEyNzkwZTZjM2YyN2U1YmNmZTEzZjU3NmZhYjk3NjM1NDYxZWI5ZTZmODk2NWZmNjU1ODU1OTFkZGZiZDE5ZDZkNDU2ZmMyNTI0OTg0YWIwZjc1NGJhODVjZTRiYzYyNDMwMTE5ZDYwN2QzM2UiLCIyMDQxNTVkNzk5NTM0NzAzMGFjNmZlZGIzNjc4YjI1YzJlM2RhNTNkYzExNjA2OThhNDk2ZDBmMDAxOTkzMDZmZDBhYzAwNjMwMzZmNzI2NDAxMDExODc0NjU3ODc0MmY3MDZjNjE2OTZlM2I2MzY4NjE3MjczNjU3NDNkNzU3NDY2MmQzODAwMzU3YjIyNzAyMjNhMjI2MjcyNjMyZDMyMzAyMjJjMjI2ZjcwMjIzYTIyNmQ2OTZlNzQyMjJjMjI3NDY5NjM2YjIyM2EyMjZkNjU2ZDY1MjIyYzIyNjE2ZDc0MjIzYTIyMzEzMDMwMzAyMjdkNjgiLCJjMDk4MzcxYzEwOGY2NWFjOTNjMmQwODkwMGEwZWI2ZWFjZTkwYTU0NzE4NjgwMWZhMjUyYjQzZTU3ZTdlMjc1NTEiXSwic2VxdWVuY2UiOjQyOTQ5NjcyOTV9XSwidm91dCI6W3sidmFsdWUiOjAuMDAwMDA1NDYsIm4iOjAsInNjcmlwdFB1YktleSI6eyJhc20iOiIxIDJkZTg1MjE0OGVkMzE2ODg1NTY0YzQ0NjJiZDBmZDAwNjY2ZDNlMDc5ZDg1MjAxOWU0MWY5MDIxMjA4NzhkZDUiLCJoZXgiOiI1MTIwMmRlODUyMTQ4ZWQzMTY4ODU1NjRjNDQ2MmJkMGZkMDA2NjZkM2UwNzlkODUyMDE5ZTQxZjkwMjEyMDg3OGRkNSIsInR5cGUiOiJ3aXRuZXNzX3YxX3RhcHJvb3QifX1dfSx7ImhleCI6IjAyMDAwMDAwMDAwMTAxOTU0MjJkZDVmOGExMWQ4Njc0NDdmMDA1ZDA1ZDkyNTlhZGY1OGZmY2ExNzM2MzJmZjRjY2I5OTZjNTU3ZGVjZDE3MDAwMDAwMDBmZmZmZmZmZjAxMjIwMjAwMDAwMDAwMDAwMDIyNTEyMDQ3ZWI2OWU1ZTg0MDZjZDI4NzVhMzliMmJkOGJjNWJiM2Q4YTM3YTk4ODg1ZjI4MmU3ODhjMTYxODdhZmIxZWUwMzQwZWNmZmJkMDY4MmM0NjJkYjdkMzI1NWFjNTJkMjYwMzAwOWVkNWI0NTVhMzBiYmMxODQyYjg4MzVmZGE4ZDQ1MmEyYjg3ZjAxMmY5MGQ2ZTE4ZGRhMzUwYjA0NWU2NGMzOTA0NmVhZTk3ZjkzNjc2MWExNzVhM2VkMWQxMGRiMTc3YjIwY2JkNWE5MDAwOTkzNTkxN2I5YTVhM2UxYTM5NzcwNTIzZWUwM2UwYjBkOTU1MmUwZTQ5ZTFiNmYyOWZhMGIwNmFjMDA2MzAzNmY3MjY0MDEwMTE4NzQ2NTc4NzQyZjcwNmM2MTY5NmUzYjYzNjg2MTcyNzM2NTc0M2Q3NTc0NjYyZDM4MDAzNTdiMjI3MDIyM2EyMjYyNzI2MzJkMzIzMDIyMmMyMjZmNzAyMjNhMjI2ZDY5NmU3NDIyMmMyMjc0Njk2MzZiMjIzYTIyNTU1MzQ0NTQyMjJjMjI2MTZkNzQyMjNhMjIzMTMwMzAzMDIyN2Q2ODIxYzEzMGMwNWRiZTlmY2ZjYjNjNmQ2M2I4YzU0YTU4YjdjMzQzODA0NmY1ZDI3NTMwZTMzNjE1YjhjMGUzNDVkYWJhMDAwMDAwMDAiLCJ0eGlkIjoiMDQyYmZhYWM5MzEyYjM2MThiYmI4Yjc3ZGZkYmI3MTMzOWEzMzc3ZTFhOTUzODBlZTFjMWVhNmRjNDcyZjYzOCIsImhhc2giOiJhZTZiY2NkN2ZlMmYxMzVkZjUwNWRhYTYzOWQ3YTFlNmFmMGU4YTUwM2VjM2ZmZjExNGViODczMDE1M2Q5NmI0Iiwic2l6ZSI6MzIwLCJ2c2l6ZSI6MTUxLCJ3ZWlnaHQiOjYwMiwidmVyc2lvbiI6MiwibG9ja3RpbWUiOjAsInZpbiI6W3sidHhpZCI6ImNkZGU1N2M1OTZiOWNjZjQyZjYzNzNhMWZjOGZmNWFkNTk5MjVkZDAwNWYwNDc3NDg2MWRhMWY4ZDUyZDQyOTUiLCJ2b3V0IjoyMywic2NyaXB0U2lnIjp7ImFzbSI6IiIsImhleCI6IiJ9LCJ0eGlud2l0bmVzcyI6WyJlY2ZmYmQwNjgyYzQ2MmRiN2QzMjU1YWM1MmQyNjAzMDA5ZWQ1YjQ1NWEzMGJiYzE4NDJiODgzNWZkYThkNDUyYTJiODdmMDEyZjkwZDZlMThkZGEzNTBiMDQ1ZTY0YzM5MDQ2ZWFlOTdmOTM2NzYxYTE3NWEzZWQxZDEwZGIxNyIsIjIwY2JkNWE5MDAwOTkzNTkxN2I5YTVhM2UxYTM5NzcwNTIzZWUwM2UwYjBkOTU1MmUwZTQ5ZTFiNmYyOWZhMGIwNmFjMDA2MzAzNmY3MjY0MDEwMTE4NzQ2NTc4NzQyZjcwNmM2MTY5NmUzYjYzNjg2MTcyNzM2NTc0M2Q3NTc0NjYyZDM4MDAzNTdiMjI3MDIyM2EyMjYyNzI2MzJkMzIzMDIyMmMyMjZmNzAyMjNhMjI2ZDY5NmU3NDIyMmMyMjc0Njk2MzZiMjIzYTIyNTU1MzQ0NTQyMjJjMjI2MTZkNzQyMjNhMjIzMTMwMzAzMDIyN2Q2OCIsImMxMzBjMDVkYmU5ZmNmY2IzYzZkNjNiOGM1NGE1OGI3YzM0MzgwNDZmNWQyNzUzMGUzMzYxNWI4YzBlMzQ1ZGFiYSJdLCJzZXF1ZW5jZSI6NDI5NDk2NzI5NX1dLCJ2b3V0IjpbeyJ2YWx1ZSI6MC4wMDAwMDU0NiwibiI6MCwic2NyaXB0UHViS2V5Ijp7ImFzbSI6IjEgNDdlYjY5ZTVlODQwNmNkMjg3NWEzOWIyYmQ4YmM1YmIzZDhhMzdhOTg4ODVmMjgyZTc4OGMxNjE4N2FmYjFlZSIsImhleCI6IjUxMjA0N2ViNjllNWU4NDA2Y2QyODc1YTM5YjJiZDhiYzViYjNkOGEzN2E5ODg4NWYyODJlNzg4YzE2MTg3YWZiMWVlIiwidHlwZSI6IndpdG5lc3NfdjFfdGFwcm9vdCJ9fV19LHsiaGV4IjoiMDIwMDAwMDAwMDAxMDE5NTQyMmRkNWY4YTExZDg2NzQ0N2YwMDVkMDVkOTI1OWFkZjU4ZmZjYTE3MzYzMmZmNGNjYjk5NmM1NTdkZWNkMDkwMDAwMDAwMGZmZmZmZmZmMDEyMjAyMDAwMDAwMDAwMDAwMjI1MTIwNDdlYjY5ZTVlODQwNmNkMjg3NWEzOWIyYmQ4YmM1YmIzZDhhMzdhOTg4ODVmMjgyZTc4OGMxNjE4N2FmYjFlZTAzNDBkOTBlNzRiNDNlZDk2ODI2NDc5YzFjZjRhMWI5MTdkNzQ2MmQyMGEzNTQ2OTJmY2VjYjI1ODIyMDUwNWY1YTVjNjMwMDlhZDhiMjE3MmY4YWZlNzA5NWRlNWI0NWI0YTMyZTFiMDE3OWY4Y2FhNzZiMDE0NTgwOWRmZGQ4ZTljNjdiMjA5ZTk2ZDEzZWZiYmRhMzZhMDgzMDcxNjE3YzU3ODMxM2E5NjYyNTE4OWE0MGQ3OTdjNWMzYTgyMTBhZTAwY2RiYWMwMDYzMDM2ZjcyNjQwMTAxMTg3NDY1Nzg3NDJmNzA2YzYxNjk2ZTNiNjM2ODYxNzI3MzY1NzQzZDc1NzQ2NjJkMzgwMDM1N2IyMjcwMjIzYTIyNjI3MjYzMmQzMjMwMjIyYzIyNmY3MDIyM2EyMjZkNjk2ZTc0MjIyYzIyNzQ2OTYzNmIyMjNhMjI1NTUzNDQ1NDIyMmMyMjYxNmQ3NDIyM2EyMjMxMzAzMDMwMjI3ZDY4MjFjMDMwYzA1ZGJlOWZjZmNiM2M2ZDYzYjhjNTRhNThiN2MzNDM4MDQ2ZjVkMjc1MzBlMzM2MTViOGMwZTM0NWRhYmEwMDAwMDAwMCIsInR4aWQiOiJlNGM5MGM4ZjkzYzA2Y2FiMTIxNDRhMDAxY2M5NDA1YjI2ZmVmOGJiYTUxZWExYzFmMzRhNGZhZDI0NDIyNTM5IiwiaGFzaCI6IjMxN2JjZDgzNTQxOWVjMjIxYTQzNjYzNmU3NDUwMzlkMTMwYjM1NDQ1NWRhYzY0NDMxMzUxOWIyMWQ5NjdhZWMiLCJzaXplIjozMjAsInZzaXplIjoxNTEsIndlaWdodCI6NjAyLCJ2ZXJzaW9uIjoyLCJsb2NrdGltZSI6MCwidmluIjpbeyJ0eGlkIjoiY2RkZTU3YzU5NmI5Y2NmNDJmNjM3M2ExZmM4ZmY1YWQ1OTkyNWRkMDA1ZjA0Nzc0ODYxZGExZjhkNTJkNDI5NSIsInZvdXQiOjksInNjcmlwdFNpZyI6eyJhc20iOiIiLCJoZXgiOiIifSwidHhpbndpdG5lc3MiOlsiZDkwZTc0YjQzZWQ5NjgyNjQ3OWMxY2Y0YTFiOTE3ZDc0NjJkMjBhMzU0NjkyZmNlY2IyNTgyMjA1MDVmNWE1YzYzMDA5YWQ4YjIxNzJmOGFmZTcwOTVkZTViNDViNGEzMmUxYjAxNzlmOGNhYTc2YjAxNDU4MDlkZmRkOGU5YzYiLCIyMDllOTZkMTNlZmJiZGEzNmEwODMwNzE2MTdjNTc4MzEzYTk2NjI1MTg5YTQwZDc5N2M1YzNhODIxMGFlMDBjZGJhYzAwNjMwMzZmNzI2NDAxMDExODc0NjU3ODc0MmY3MDZjNjE2OTZlM2I2MzY4NjE3MjczNjU3NDNkNzU3NDY2MmQzODAwMzU3YjIyNzAyMjNhMjI2MjcyNjMyZDMyMzAyMjJjMjI2ZjcwMjIzYTIyNmQ2OTZlNzQyMjJjMjI3NDY5NjM2YjIyM2EyMjU1NTM0NDU0MjIyYzIyNjE2ZDc0MjIzYTIyMzEzMDMwMzAyMjdkNjgiLCJjMDMwYzA1ZGJlOWZjZmNiM2M2ZDYzYjhjNTRhNThiN2MzNDM4MDQ2ZjVkMjc1MzBlMzM2MTViOGMwZTM0NWRhYmEiXSwic2VxdWVuY2UiOjQyOTQ5NjcyOTV9XSwidm91dCI6W3sidmFsdWUiOjAuMDAwMDA1NDYsIm4iOjAsInNjcmlwdFB1YktleSI6eyJhc20iOiIxIDQ3ZWI2OWU1ZTg0MDZjZDI4NzVhMzliMmJkOGJjNWJiM2Q4YTM3YTk4ODg1ZjI4MmU3ODhjMTYxODdhZmIxZWUiLCJoZXgiOiI1MTIwNDdlYjY5ZTVlODQwNmNkMjg3NWEzOWIyYmQ4YmM1YmIzZDhhMzdhOTg4ODVmMjgyZTc4OGMxNjE4N2FmYjFlZSIsInR5cGUiOiJ3aXRuZXNzX3YxX3RhcHJvb3QifX1dfSx7ImhleCI6IjAyMDAwMDAwMDAwMTAxOTU0MjJkZDVmOGExMWQ4Njc0NDdmMDA1ZDA1ZDkyNTlhZGY1OGZmY2ExNzM2MzJmZjRjY2I5OTZjNTU3ZGVjZDA4MDAwMDAwMDBmZmZmZmZmZjAxMjIwMjAwMDAwMDAwMDAwMDIyNTEyMDQ3ZWI2OWU1ZTg0MDZjZDI4NzVhMzliMmJkOGJjNWJiM2Q4YTM3YTk4ODg1ZjI4MmU3ODhjMTYxODdhZmIxZWUwMzQwYTVlM2VmYmY3Yzc4ZGFmYmI2MWU1ZTk4NzQ5Nzk5NjIxMzNhYjYyZjY1ZDQ3M2IyZDQ5YzFhNDdlMTU0N2ZjMjBiMjg2Mjg4YWVlZTcxNjRmYWY2YmNkYjlkMmQ3Y2EzOWEyYTJmNGMzNjBhY2VmMmEwMjkyNTA4NjkzNjI5YmU3YjIwMzlmM2QxNThmMTc1MjYzNTJkNmEyYmY1MTc3MzIzZWViYWViZWZiZTRlMTU3ZTBjMzdiNGFkYjI2YmEyZWU3Y2FjMDA2MzAzNmY3MjY0MDEwMTE4NzQ2NTc4NzQyZjcwNmM2MTY5NmUzYjYzNjg2MTcyNzM2NTc0M2Q3NTc0NjYyZDM4MDAzNTdiMjI3MDIyM2EyMjYyNzI2MzJkMzIzMDIyMmMyMjZmNzAyMjNhMjI2ZDY5NmU3NDIyMmMyMjc0Njk2MzZiMjIzYTIyNTU1MzQ0NTQyMjJjMjI2MTZkNzQyMjNhMjIzMTMwMzAzMDIyN2Q2ODIxYzAzMGMwNWRiZTlmY2ZjYjNjNmQ2M2I4YzU0YTU4YjdjMzQzODA0NmY1ZDI3NTMwZTMzNjE1YjhjMGUzNDVkYWJhMDAwMDAwMDAiLCJ0eGlkIjoiMDdjYTBmZmY0Y2E3M2Y2ZjY4ODU0ZmU3YTE5ZGMwMmU0ODdiYmNlZmFmMDhkYTMzNWU5MTAxNmM4NDMxZWMzZCIsImhhc2giOiI2NjdjZTI0NjRhNTBjMDNiN2Y4MDhhMjg0NmMwZjhiOWIxNDQ1MmY3OWM0M2JmYmJlNTA5YmIzZjNlZDMzMzA2Iiwic2l6ZSI6MzIwLCJ2c2l6ZSI6MTUxLCJ3ZWlnaHQiOjYwMiwidmVyc2lvbiI6MiwibG9ja3RpbWUiOjAsInZpbiI6W3sidHhpZCI6ImNkZGU1N2M1OTZiOWNjZjQyZjYzNzNhMWZjOGZmNWFkNTk5MjVkZDAwNWYwNDc3NDg2MWRhMWY4ZDUyZDQyOTUiLCJ2b3V0Ijo4LCJzY3JpcHRTaWciOnsiYXNtIjoiIiwiaGV4IjoiIn0sInR4aW53aXRuZXNzIjpbImE1ZTNlZmJmN2M3OGRhZmJiNjFlNWU5ODc0OTc5OTYyMTMzYWI2MmY2NWQ0NzNiMmQ0OWMxYTQ3ZTE1NDdmYzIwYjI4NjI4OGFlZWU3MTY0ZmFmNmJjZGI5ZDJkN2NhMzlhMmEyZjRjMzYwYWNlZjJhMDI5MjUwODY5MzYyOWJlIiwiMjAzOWYzZDE1OGYxNzUyNjM1MmQ2YTJiZjUxNzczMjNlZWJhZWJlZmJlNGUxNTdlMGMzN2I0YWRiMjZiYTJlZTdjYWMwMDYzMDM2ZjcyNjQwMTAxMTg3NDY1Nzg3NDJmNzA2YzYxNjk2ZTNiNjM2ODYxNzI3MzY1NzQzZDc1NzQ2NjJkMzgwMDM1N2IyMjcwMjIzYTIyNjI3MjYzMmQzMjMwMjIyYzIyNmY3MDIyM2EyMjZkNjk2ZTc0MjIyYzIyNzQ2OTYzNmIyMjNhMjI1NTUzNDQ1NDIyMmMyMjYxNmQ3NDIyM2EyMjMxMzAzMDMwMjI3ZDY4IiwiYzAzMGMwNWRiZTlmY2ZjYjNjNmQ2M2I4YzU0YTU4YjdjMzQzODA0NmY1ZDI3NTMwZTMzNjE1YjhjMGUzNDVkYWJhIl0sInNlcXVlbmNlIjo0Mjk0OTY3Mjk1fV0sInZvdXQiOlt7InZhbHVlIjowLjAwMDAwNTQ2LCJuIjowLCJzY3JpcHRQdWJLZXkiOnsiYXNtIjoiMSA0N2ViNjllNWU4NDA2Y2QyODc1YTM5YjJiZDhiYzViYjNkOGEzN2E5ODg4NWYyODJlNzg4YzE2MTg3YWZiMWVlIiwiaGV4IjoiNTEyMDQ3ZWI2OWU1ZTg0MDZjZDI4NzVhMzliMmJkOGJjNWJiM2Q4YTM3YTk4ODg1ZjI4MmU3ODhjMTYxODdhZmIxZWUiLCJ0eXBlIjoid2l0bmVzc192MV90YXByb290In19XX0seyJoZXgiOiIwMjAwMDAwMDAwMDEwMTk1NDIyZGQ1ZjhhMTFkODY3NDQ3ZjAwNWQwNWQ5MjU5YWRmNThmZmNhMTczNjMyZmY0Y2NiOTk2YzU1N2RlY2QxNDAwMDAwMDAwZmZmZmZmZmYwMTIyMDIwMDAwMDAwMDAwMDAyMjUxMjA0N2ViNjllNWU4NDA2Y2QyODc1YTM5YjJiZDhiYzViYjNkOGEzN2E5ODg4NWYyODJlNzg4YzE2MTg3YWZiMWVlMDM0MDA3NTU0OWZiOWE0ZGI2OWM0YmI1NzMyZGViMTg5ZmIyMjE1MzUyNzAxNjQ1NjVmOWZmYjg0NjM0YTE3OGI2NjhjYTQ1YzljZGVjNzYxMjg2ZDM1YmY1MTk5ZDg0OTdhMjRmYTFhYjRhMjk3NmIzNjJjNTI1YzU1Y2MzMWQwY2FlN2IyMDBhMjNkZGY5ZDY3MDA1ODQ2NTQxZmRhZDI2ZWJhMmYyNzJmMGMxOTBjOTdjZmM1Y2M3YTA3ZWFkNjYwMzk1MzZhYzAwNjMwMzZmNzI2NDAxMDExODc0NjU3ODc0MmY3MDZjNjE2OTZlM2I2MzY4NjE3MjczNjU3NDNkNzU3NDY2MmQzODAwMzU3YjIyNzAyMjNhMjI2MjcyNjMyZDMyMzAyMjJjMjI2ZjcwMjIzYTIyNmQ2OTZlNzQyMjJjMjI3NDY5NjM2YjIyM2EyMjU1NTM0NDU0MjIyYzIyNjE2ZDc0MjIzYTIyMzEzMDMwMzAyMjdkNjgyMWMxMzBjMDVkYmU5ZmNmY2IzYzZkNjNiOGM1NGE1OGI3YzM0MzgwNDZmNWQyNzUzMGUzMzYxNWI4YzBlMzQ1ZGFiYTAwMDAwMDAwIiwidHhpZCI6IjQxOTg5YWUwMTg3ZjYzY2RmZmNmY2E1NTVhZjdjMWNlYWY5YzA4MDljNjU3ZDJmNDZlODRiODkyNDQ2MTk2NDIiLCJoYXNoIjoiNWI5NDI2MGY1ODc0ZDEwY2IxZTg4YWZkNGM5NDFkMzE1Y2Q5NjM1MzMwZGVhYmU3MGM1ZGQ2YjQwNmFkNWUyNyIsInNpemUiOjMyMCwidnNpemUiOjE1MSwid2VpZ2h0Ijo2MDIsInZlcnNpb24iOjIsImxvY2t0aW1lIjowLCJ2aW4iOlt7InR4aWQiOiJjZGRlNTdjNTk2YjljY2Y0MmY2MzczYTFmYzhmZjVhZDU5OTI1ZGQwMDVmMDQ3NzQ4NjFkYTFmOGQ1MmQ0Mjk1Iiwidm91dCI6MjAsInNjcmlwdFNpZyI6eyJhc20iOiIiLCJoZXgiOiIifSwidHhpbndpdG5lc3MiOlsiMDc1NTQ5ZmI5YTRkYjY5YzRiYjU3MzJkZWIxODlmYjIyMTUzNTI3MDE2NDU2NWY5ZmZiODQ2MzRhMTc4YjY2OGNhNDVjOWNkZWM3NjEyODZkMzViZjUxOTlkODQ5N2EyNGZhMWFiNGEyOTc2YjM2MmM1MjVjNTVjYzMxZDBjYWUiLCIyMDBhMjNkZGY5ZDY3MDA1ODQ2NTQxZmRhZDI2ZWJhMmYyNzJmMGMxOTBjOTdjZmM1Y2M3YTA3ZWFkNjYwMzk1MzZhYzAwNjMwMzZmNzI2NDAxMDExODc0NjU3ODc0MmY3MDZjNjE2OTZlM2I2MzY4NjE3MjczNjU3NDNkNzU3NDY2MmQzODAwMzU3YjIyNzAyMjNhMjI2MjcyNjMyZDMyMzAyMjJjMjI2ZjcwMjIzYTIyNmQ2OTZlNzQyMjJjMjI3NDY5NjM2YjIyM2EyMjU1NTM0NDU0MjIyYzIyNjE2ZDc0MjIzYTIyMzEzMDMwMzAyMjdkNjgiLCJjMTMwYzA1ZGJlOWZjZmNiM2M2ZDYzYjhjNTRhNThiN2MzNDM4MDQ2ZjVkMjc1MzBlMzM2MTViOGMwZTM0NWRhYmEiXSwic2VxdWVuY2UiOjQyOTQ5NjcyOTV9XSwidm91dCI6W3sidmFsdWUiOjAuMDAwMDA1NDYsIm4iOjAsInNjcmlwdFB1YktleSI6eyJhc20iOiIxIDQ3ZWI2OWU1ZTg0MDZjZDI4NzVhMzliMmJkOGJjNWJiM2Q4YTM3YTk4ODg1ZjI4MmU3ODhjMTYxODdhZmIxZWUiLCJoZXgiOiI1MTIwNDdlYjY5ZTVlODQwNmNkMjg3NWEzOWIyYmQ4YmM1YmIzZDhhMzdhOTg4ODVmMjgyZTc4OGMxNjE4N2FmYjFlZSIsInR5cGUiOiJ3aXRuZXNzX3YxX3RhcHJvb3QifX1dfSx7ImhleCI6IjAyMDAwMDAwMDAwMTAxOTU0MjJkZDVmOGExMWQ4Njc0NDdmMDA1ZDA1ZDkyNTlhZGY1OGZmY2ExNzM2MzJmZjRjY2I5OTZjNTU3ZGVjZDAzMDAwMDAwMDBmZmZmZmZmZjAxMjIwMjAwMDAwMDAwMDAwMDIyNTEyMDQ3ZWI2OWU1ZTg0MDZjZDI4NzVhMzliMmJkOGJjNWJiM2Q4YTM3YTk4ODg1ZjI4MmU3ODhjMTYxODdhZmIxZWUwMzQwYmYyOTExY2FmZmI1NDExOGQ3OGNhYzBkNTM5MjUwMDM0N2M4MTZmNjMyYTg3OWFhNjdlMzEwOWUyMzQ2ZDUzZTA4ZGQ0ODMwYWE0ZTc1Y2IyNTI2MDk0MTU0NzRmYTBmNTFjODQ2MGM3MjQ0OGMyZThhZjA1NTQ4NmQwNmU3OTA3YjIwZjRkNTIzNTMzZWQ0NzcyOGY3YzI5MGYzZjE3N2RiYjM5MzA0N2FhY2IwYjJkY2NjMzM2ZDFjZWM0MTRlOTM3NmFjMDA2MzAzNmY3MjY0MDEwMTE4NzQ2NTc4NzQyZjcwNmM2MTY5NmUzYjYzNjg2MTcyNzM2NTc0M2Q3NTc0NjYyZDM4MDAzNTdiMjI3MDIyM2EyMjYyNzI2MzJkMzIzMDIyMmMyMjZmNzAyMjNhMjI2ZDY5NmU3NDIyMmMyMjc0Njk2MzZiMjIzYTIyNTU1MzQ0NTQyMjJjMjI2MTZkNzQyMjNhMjIzMTMwMzAzMDIyN2Q2ODIxYzEzMGMwNWRiZTlmY2ZjYjNjNmQ2M2I4YzU0YTU4YjdjMzQzODA0NmY1ZDI3NTMwZTMzNjE1YjhjMGUzNDVkYWJhMDAwMDAwMDAiLCJ0eGlkIjoiMTI5MzAxODI0MTFjNDVmNmQxZTFhYTVkY2FkYTI5Y2JlMDY1Y2Q0OWFkMGZjZWUxNzUwMDFhZjE4MGM1YWU0MiIsImhhc2giOiIxZDEyMjVlZjA4NWIzYmY0MWY5ODI1MGM5YzBlMDQ5NmU0MTU5YjgwNWQ4MjBiMjE0Y2ZlYjU2NjZhOTBmNjY1Iiwic2l6ZSI6MzIwLCJ2c2l6ZSI6MTUxLCJ3ZWlnaHQiOjYwMiwidmVyc2lvbiI6MiwibG9ja3RpbWUiOjAsInZpbiI6W3sidHhpZCI6ImNkZGU1N2M1OTZiOWNjZjQyZjYzNzNhMWZjOGZmNWFkNTk5MjVkZDAwNWYwNDc3NDg2MWRhMWY4ZDUyZDQyOTUiLCJ2b3V0IjozLCJzY3JpcHRTaWciOnsiYXNtIjoiIiwiaGV4IjoiIn0sInR4aW53aXRuZXNzIjpbImJmMjkxMWNhZmZiNTQxMThkNzhjYWMwZDUzOTI1MDAzNDdjODE2ZjYzMmE4NzlhYTY3ZTMxMDllMjM0NmQ1M2UwOGRkNDgzMGFhNGU3NWNiMjUyNjA5NDE1NDc0ZmEwZjUxYzg0NjBjNzI0NDhjMmU4YWYwNTU0ODZkMDZlNzkwIiwiMjBmNGQ1MjM1MzNlZDQ3NzI4ZjdjMjkwZjNmMTc3ZGJiMzkzMDQ3YWFjYjBiMmRjY2MzMzZkMWNlYzQxNGU5Mzc2YWMwMDYzMDM2ZjcyNjQwMTAxMTg3NDY1Nzg3NDJmNzA2YzYxNjk2ZTNiNjM2ODYxNzI3MzY1NzQzZDc1NzQ2NjJkMzgwMDM1N2IyMjcwMjIzYTIyNjI3MjYzMmQzMjMwMjIyYzIyNmY3MDIyM2EyMjZkNjk2ZTc0MjIyYzIyNzQ2OTYzNmIyMjNhMjI1NTUzNDQ1NDIyMmMyMjYxNmQ3NDIyM2EyMjMxMzAzMDMwMjI3ZDY4IiwiYzEzMGMwNWRiZTlmY2ZjYjNjNmQ2M2I4YzU0YTU4YjdjMzQzODA0NmY1ZDI3NTMwZTMzNjE1YjhjMGUzNDVkYWJhIl0sInNlcXVlbmNlIjo0Mjk0OTY3Mjk1fV0sInZvdXQiOlt7InZhbHVlIjowLjAwMDAwNTQ2LCJuIjowLCJzY3JpcHRQdWJLZXkiOnsiYXNtIjoiMSA0N2ViNjllNWU4NDA2Y2QyODc1YTM5YjJiZDhiYzViYjNkOGEzN2E5ODg4NWYyODJlNzg4YzE2MTg3YWZiMWVlIiwiaGV4IjoiNTEyMDQ3ZWI2OWU1ZTg0MDZjZDI4NzVhMzliMmJkOGJjNWJiM2Q4YTM3YTk4ODg1ZjI4MmU3ODhjMTYxODdhZmIxZWUiLCJ0eXBlIjoid2l0bmVzc192MV90YXByb290In19XX0seyJoZXgiOiIwMjAwMDAwMDAwMDEwMTk1NDIyZGQ1ZjhhMTFkODY3NDQ3ZjAwNWQwNWQ5MjU5YWRmNThmZmNhMTczNjMyZmY0Y2NiOTk2YzU1N2RlY2QxNjAwMDAwMDAwZmZmZmZmZmYwMTIyMDIwMDAwMDAwMDAwMDAyMjUxMjA0N2ViNjllNWU4NDA2Y2QyODc1YTM5YjJiZDhiYzViYjNkOGEzN2E5ODg4NWYyODJlNzg4YzE2MTg3YWZiMWVlMDM0MDhkOTVjZDUyOTgxOWY2N2Q1YjY1Y2FkNjZjOWE1NDVkNmIwNjA2MTkwYmI5MjZlNTM1ZTZkYTkyM2JiZjgyMDhkYjE0YjU1NzA2ODI4NzVlNmU2ODMwNmZhY2Q0Y2RkYWI0MWM1YmUwMzQ4YzlkNTRlOTcwZWQyMjJiNWE3YTgyN2IyMGQ2MzBlMjhhMjhlZjVlNmU3ODdjZmYxOWFhYmQzMzlkYWQ1YWM4ZDI4ZmIwNDI1MGQxNTMyMTdkY2M3ZjE4Y2RhYzAwNjMwMzZmNzI2NDAxMDExODc0NjU3ODc0MmY3MDZjNjE2OTZlM2I2MzY4NjE3MjczNjU3NDNkNzU3NDY2MmQzODAwMzU3YjIyNzAyMjNhMjI2MjcyNjMyZDMyMzAyMjJjMjI2ZjcwMjIzYTIyNmQ2OTZlNzQyMjJjMjI3NDY5NjM2YjIyM2EyMjU1NTM0NDU0MjIyYzIyNjE2ZDc0MjIzYTIyMzEzMDMwMzAyMjdkNjgyMWMwMzBjMDVkYmU5ZmNmY2IzYzZkNjNiOGM1NGE1OGI3YzM0MzgwNDZmNWQyNzUzMGUzMzYxNWI4YzBlMzQ1ZGFiYTAwMDAwMDAwIiwidHhpZCI6IjE2NTFlMjE0MDAwOTcxMjdhMDc5OGUzNGFjZGNlZDkyOWUwZDcxZjhjYWFiMTY5Yzk4NzExMjA5YmI5NDMwNDQiLCJoYXNoIjoiZTI2YTkwMzBjODNhMDdmOGUzMjQwMDQwN2Q4MThhMWI5MGY2NTViYmQ0MjZhZWJlZmIzM2QxMjVkOGU5YTg4NCIsInNpemUiOjMyMCwidnNpemUiOjE1MSwid2VpZ2h0Ijo2MDIsInZlcnNpb24iOjIsImxvY2t0aW1lIjowLCJ2aW4iOlt7InR4aWQiOiJjZGRlNTdjNTk2YjljY2Y0MmY2MzczYTFmYzhmZjVhZDU5OTI1ZGQwMDVmMDQ3NzQ4NjFkYTFmOGQ1MmQ0Mjk1Iiwidm91dCI6MjIsInNjcmlwdFNpZyI6eyJhc20iOiIiLCJoZXgiOiIifSwidHhpbndpdG5lc3MiOlsiOGQ5NWNkNTI5ODE5ZjY3ZDViNjVjYWQ2NmM5YTU0NWQ2YjA2MDYxOTBiYjkyNmU1MzVlNmRhOTIzYmJmODIwOGRiMTRiNTU3MDY4Mjg3NWU2ZTY4MzA2ZmFjZDRjZGRhYjQxYzViZTAzNDhjOWQ1NGU5NzBlZDIyMmI1YTdhODIiLCIyMGQ2MzBlMjhhMjhlZjVlNmU3ODdjZmYxOWFhYmQzMzlkYWQ1YWM4ZDI4ZmIwNDI1MGQxNTMyMTdkY2M3ZjE4Y2RhYzAwNjMwMzZmNzI2NDAxMDExODc0NjU3ODc0MmY3MDZjNjE2OTZlM2I2MzY4NjE3MjczNjU3NDNkNzU3NDY2MmQzODAwMzU3YjIyNzAyMjNhMjI2MjcyNjMyZDMyMzAyMjJjMjI2ZjcwMjIzYTIyNmQ2OTZlNzQyMjJjMjI3NDY5NjM2YjIyM2EyMjU1NTM0NDU0MjIyYzIyNjE2ZDc0MjIzYTIyMzEzMDMwMzAyMjdkNjgiLCJjMDMwYzA1ZGJlOWZjZmNiM2M2ZDYzYjhjNTRhNThiN2MzNDM4MDQ2ZjVkMjc1MzBlMzM2MTViOGMwZTM0NWRhYmEiXSwic2VxdWVuY2UiOjQyOTQ5NjcyOTV9XSwidm91dCI6W3sidmFsdWUiOjAuMDAwMDA1NDYsIm4iOjAsInNjcmlwdFB1YktleSI6eyJhc20iOiIxIDQ3ZWI2OWU1ZTg0MDZjZDI4NzVhMzliMmJkOGJjNWJiM2Q4YTM3YTk4ODg1ZjI4MmU3ODhjMTYxODdhZmIxZWUiLCJoZXgiOiI1MTIwNDdlYjY5ZTVlODQwNmNkMjg3NWEzOWIyYmQ4YmM1YmIzZDhhMzdhOTg4ODVmMjgyZTc4OGMxNjE4N2FmYjFlZSIsInR5cGUiOiJ3aXRuZXNzX3YxX3RhcHJvb3QifX1dfSx7ImhleCI6IjAyMDAwMDAwMDAwMTAxNmM5MzllMWIyM2U5MWZmN2U2NTUyYjUyMDQ3NDRhOGU0MzYyNWIyNjRjOTdmODAwZTM2ZDdjYzY4YzY0ZmMyZjAxMDAwMDAwMDBmZGZmZmZmZjAyZjhmZDE0MDAwMDAwMDAwMDE2MDAxNDI0OGZjMWRkNzFhMTU5ZGMzMzU2MDY2MTU5Nzg5OGJkZDM2NjQwZjU0MDFmMDAwMDAwMDAwMDAwMTYwMDE0NDJkZjdkMjNiMWE1ODFhYWVjMjljY2VjNjBhMTU0YjVjY2MyZGMxZDAyNDczMDQ0MDIyMDY2N2E2ZDg2Yjk4ZjRlMDY3ZGQyZGM2NDg0YjkwNmE2Yzc3MjVmYTZjMjY3YWQxMDRlNmYzODQ5YWUzNjY2MGEwMjIwNTkxOTc3OTcyNDZiZTlmNjRmOGViYzE1NWJjYWM5YTllOGRlNzZmZDZkN2FhYzNmZmVmZmExMmUzMjBhMGRlMDAxMjEwM2EwNjA3MzQ3ODk2MDU1NDVkZmNiOWNjZWY2N2I0OGVkMTQ0YjI0YTZlOGYxZGEwYWE4YjcxZWE5M2UwMDAxZjJjNDNhMjYwMCIsInR4aWQiOiJiNGQzMmFlMzY0ZDBmODUzOWI1NWNmNTliYzU1NWU2NTQ4MTRlMDgwZGJmMTM1NTRmZTk0MDI1MjM2ZGY0YzQ1IiwiaGFzaCI6ImE0MmY1NTgwZTMzNjA2OTFlOTdjZGYzODhiYzliNDc1MjFjOGQ3YTk2Mzc1NGE2OWEzNGJkOWFlYmFlNmQ5NWUiLCJzaXplIjoyMjIsInZzaXplIjoxNDEsIndlaWdodCI6NTYxLCJ2ZXJzaW9uIjoyLCJsb2NrdGltZSI6MjUwNTQxMiwidmluIjpbeyJ0eGlkIjoiMmZmYzY0OGNjNjdjNmRlMzAwZjg5NzRjMjY1YjYyNDM4ZTRhNzQwNDUyMmI1NWU2ZjcxZmU5MjMxYjllOTM2YyIsInZvdXQiOjEsInNjcmlwdFNpZyI6eyJhc20iOiIiLCJoZXgiOiIifSwidHhpbndpdG5lc3MiOlsiMzA0NDAyMjA2NjdhNmQ4NmI5OGY0ZTA2N2RkMmRjNjQ4NGI5MDZhNmM3NzI1ZmE2YzI2N2FkMTA0ZTZmMzg0OWFlMzY2NjBhMDIyMDU5MTk3Nzk3MjQ2YmU5ZjY0ZjhlYmMxNTViY2FjOWE5ZThkZTc2ZmQ2ZDdhYWMzZmZlZmZhMTJlMzIwYTBkZTAwMSIsIjAzYTA2MDczNDc4OTYwNTU0NWRmY2I5Y2NlZjY3YjQ4ZWQxNDRiMjRhNmU4ZjFkYTBhYThiNzFlYTkzZTAwMDFmMiJdLCJzZXF1ZW5jZSI6NDI5NDk2NzI5M31dLCJ2b3V0IjpbeyJ2YWx1ZSI6MC4wMTM3NTczNiwibiI6MCwic2NyaXB0UHViS2V5Ijp7ImFzbSI6IjAgMjQ4ZmMxZGQ3MWExNTlkYzMzNTYwNjYxNTk3ODk4YmRkMzY2NDBmNSIsImhleCI6IjAwMTQyNDhmYzFkZDcxYTE1OWRjMzM1NjA2NjE1OTc4OThiZGQzNjY0MGY1IiwidHlwZSI6IndpdG5lc3NfdjBfa2V5aGFzaCJ9fSx7InZhbHVlIjowLjAwMDA4LCJuIjoxLCJzY3JpcHRQdWJLZXkiOnsiYXNtIjoiMCA0MmRmN2QyM2IxYTU4MWFhZWMyOWNjZWM2MGExNTRiNWNjYzJkYzFkIiwiaGV4IjoiMDAxNDQyZGY3ZDIzYjFhNTgxYWFlYzI5Y2NlYzYwYTE1NGI1Y2NjMmRjMWQiLCJ0eXBlIjoid2l0bmVzc192MF9rZXloYXNoIn19XX0seyJoZXgiOiIwMjAwMDAwMDAwMDEwMTlkMTE4ZWNiOTBkMTJhM2ViZDQ4YWUzMjA4ZDIyYTNlZDJmMjA4ZWNiZDNhNmQ2NDg5OWQxODJiZDAxZWIwZjMxMDAwMDAwMDAwZmZmZmZmZmYwMTIyMDIwMDAwMDAwMDAwMDAyMjUxMjAyZGU4NTIxNDhlZDMxNjg4NTU2NGM0NDYyYmQwZmQwMDY2NmQzZTA3OWQ4NTIwMTllNDFmOTAyMTIwODc4ZGQ1MDM0MDhhZTIxNjdmZWMxZmQ2MzE3YzU5ZjEyMWJkNDQ4NDQ5OWMxZTM0Y2RmNGExNjQ4ODAyZTFkMDI4ZDFlNjI4ODU1MmQzZTUzYWZjMmQ5YWMxZDI4MTc0ZGNhMDJkZGQwZGQxZDk0MjM4YmE2NTZmNGUwODk4ZDk2MTEzMWUwYjMxN2IyMDMyMDU0NTFmZjkwN2Q5OWQyZGY5YWI0NzMzYmRlNGVmMDE2MjQyNjNlYTc2MmVhNGQ3MDNjNjdiNTM0ZTgyYzJhYzAwNjMwMzZmNzI2NDAxMDExODc0NjU3ODc0MmY3MDZjNjE2OTZlM2I2MzY4NjE3MjczNjU3NDNkNzU3NDY2MmQzODAwMzU3YjIyNzAyMjNhMjI2MjcyNjMyZDMyMzAyMjJjMjI2ZjcwMjIzYTIyNmQ2OTZlNzQyMjJjMjI3NDY5NjM2YjIyM2EyMjZkNjU2ZDY1MjIyYzIyNjE2ZDc0MjIzYTIyMzEzMDMwMzAyMjdkNjgyMWMxOTgzNzFjMTA4ZjY1YWM5M2MyZDA4OTAwYTBlYjZlYWNlOTBhNTQ3MTg2ODAxZmEyNTJiNDNlNTdlN2UyNzU1MTAwMDAwMDAwIiwidHhpZCI6ImY5NjJmMDE3ZDk5M2NjNjU0MDQ1MDgyZDAzNjdkNzI0MWRlNmU5ZmU2ZjUwNTY4NDAyZDQ0ZmRlMWNiZGJlNTQiLCJoYXNoIjoiYTliZDRjOTk2MWQ0ZDI3OTgwNzQzNzIwYjkyN2Y0ZTQxMzE4YmZlZGFmYjJjMjE2MzJkYWJkMmNiOGU1ZTk0NiIsInNpemUiOjMyMCwidnNpemUiOjE1MSwid2VpZ2h0Ijo2MDIsInZlcnNpb24iOjIsImxvY2t0aW1lIjowLCJ2aW4iOlt7InR4aWQiOiJmM2IwMWVkMDJiMTg5ZDg5NjQ2ZDNhYmRlYzA4ZjJkMjNlMmFkMjA4MzJhZTQ4YmQzZTJhZDE5MGNiOGUxMTlkIiwidm91dCI6MTYsInNjcmlwdFNpZyI6eyJhc20iOiIiLCJoZXgiOiIifSwidHhpbndpdG5lc3MiOlsiOGFlMjE2N2ZlYzFmZDYzMTdjNTlmMTIxYmQ0NDg0NDk5YzFlMzRjZGY0YTE2NDg4MDJlMWQwMjhkMWU2Mjg4NTUyZDNlNTNhZmMyZDlhYzFkMjgxNzRkY2EwMmRkZDBkZDFkOTQyMzhiYTY1NmY0ZTA4OThkOTYxMTMxZTBiMzEiLCIyMDMyMDU0NTFmZjkwN2Q5OWQyZGY5YWI0NzMzYmRlNGVmMDE2MjQyNjNlYTc2MmVhNGQ3MDNjNjdiNTM0ZTgyYzJhYzAwNjMwMzZmNzI2NDAxMDExODc0NjU3ODc0MmY3MDZjNjE2OTZlM2I2MzY4NjE3MjczNjU3NDNkNzU3NDY2MmQzODAwMzU3YjIyNzAyMjNhMjI2MjcyNjMyZDMyMzAyMjJjMjI2ZjcwMjIzYTIyNmQ2OTZlNzQyMjJjMjI3NDY5NjM2YjIyM2EyMjZkNjU2ZDY1MjIyYzIyNjE2ZDc0MjIzYTIyMzEzMDMwMzAyMjdkNjgiLCJjMTk4MzcxYzEwOGY2NWFjOTNjMmQwODkwMGEwZWI2ZWFjZTkwYTU0NzE4NjgwMWZhMjUyYjQzZTU3ZTdlMjc1NTEiXSwic2VxdWVuY2UiOjQyOTQ5NjcyOTV9XSwidm91dCI6W3sidmFsdWUiOjAuMDAwMDA1NDYsIm4iOjAsInNjcmlwdFB1YktleSI6eyJhc20iOiIxIDJkZTg1MjE0OGVkMzE2ODg1NTY0YzQ0NjJiZDBmZDAwNjY2ZDNlMDc5ZDg1MjAxOWU0MWY5MDIxMjA4NzhkZDUiLCJoZXgiOiI1MTIwMmRlODUyMTQ4ZWQzMTY4ODU1NjRjNDQ2MmJkMGZkMDA2NjZkM2UwNzlkODUyMDE5ZTQxZjkwMjEyMDg3OGRkNSIsInR5cGUiOiJ3aXRuZXNzX3YxX3RhcHJvb3QifX1dfSx7ImhleCI6IjAyMDAwMDAwMDAwMTAxOTU0MjJkZDVmOGExMWQ4Njc0NDdmMDA1ZDA1ZDkyNTlhZGY1OGZmY2ExNzM2MzJmZjRjY2I5OTZjNTU3ZGVjZDA1MDAwMDAwMDBmZmZmZmZmZjAxMjIwMjAwMDAwMDAwMDAwMDIyNTEyMDQ3ZWI2OWU1ZTg0MDZjZDI4NzVhMzliMmJkOGJjNWJiM2Q4YTM3YTk4ODg1ZjI4MmU3ODhjMTYxODdhZmIxZWUwMzQwY2Y1ZWI0NzRjMjhiOWI3ZjdmM2FlMzk2M2UyNjg1NmViYzlmM2Q3ODgxMDJiZjU3NTllOTE5ZGQ3M2YwYWRiNjkwZjRlNmMyNDc0YzdhOTgyOTcyY2UyMjc4NWQ2MGM5NWY4OWJjNzI4ZjViNTlmZGUzNTZhZTk1YmNkODY0YWI3YjIwOTczZGQ2NzYyOGVlMzU2MWFjNjEyOWUwMjg0ODA5ZDE5NDEzOWMwZmUwYzdlMjBhN2IyMTcwNDc4YWQ0NmMyZmFjMDA2MzAzNmY3MjY0MDEwMTE4NzQ2NTc4NzQyZjcwNmM2MTY5NmUzYjYzNjg2MTcyNzM2NTc0M2Q3NTc0NjYyZDM4MDAzNTdiMjI3MDIyM2EyMjYyNzI2MzJkMzIzMDIyMmMyMjZmNzAyMjNhMjI2ZDY5NmU3NDIyMmMyMjc0Njk2MzZiMjIzYTIyNTU1MzQ0NTQyMjJjMjI2MTZkNzQyMjNhMjIzMTMwMzAzMDIyN2Q2ODIxYzAzMGMwNWRiZTlmY2ZjYjNjNmQ2M2I4YzU0YTU4YjdjMzQzODA0NmY1ZDI3NTMwZTMzNjE1YjhjMGUzNDVkYWJhMDAwMDAwMDAiLCJ0eGlkIjoiYzkwNTBjODM0Nzk0YTJmZTI1NTRiNWU0NzdlYWYxZjhlYmMxM2JlNDYzNGQ2OTE4MzQzOWU4ZDVhMDg2ZWE1NCIsImhhc2giOiI4Y2Q4ZTRlMWRiMzFmNDFmZjMxNGIzNzViNzA0MjM1NGJiMzNmMDMzNDdkMjA5YTdiNjQ0NzkyZTEyMThlNzkxIiwic2l6ZSI6MzIwLCJ2c2l6ZSI6MTUxLCJ3ZWlnaHQiOjYwMiwidmVyc2lvbiI6MiwibG9ja3RpbWUiOjAsInZpbiI6W3sidHhpZCI6ImNkZGU1N2M1OTZiOWNjZjQyZjYzNzNhMWZjOGZmNWFkNTk5MjVkZDAwNWYwNDc3NDg2MWRhMWY4ZDUyZDQyOTUiLCJ2b3V0Ijo1LCJzY3JpcHRTaWciOnsiYXNtIjoiIiwiaGV4IjoiIn0sInR4aW53aXRuZXNzIjpbImNmNWViNDc0YzI4YjliN2Y3ZjNhZTM5NjNlMjY4NTZlYmM5ZjNkNzg4MTAyYmY1NzU5ZTkxOWRkNzNmMGFkYjY5MGY0ZTZjMjQ3NGM3YTk4Mjk3MmNlMjI3ODVkNjBjOTVmODliYzcyOGY1YjU5ZmRlMzU2YWU5NWJjZDg2NGFiIiwiMjA5NzNkZDY3NjI4ZWUzNTYxYWM2MTI5ZTAyODQ4MDlkMTk0MTM5YzBmZTBjN2UyMGE3YjIxNzA0NzhhZDQ2YzJmYWMwMDYzMDM2ZjcyNjQwMTAxMTg3NDY1Nzg3NDJmNzA2YzYxNjk2ZTNiNjM2ODYxNzI3MzY1NzQzZDc1NzQ2NjJkMzgwMDM1N2IyMjcwMjIzYTIyNjI3MjYzMmQzMjMwMjIyYzIyNmY3MDIyM2EyMjZkNjk2ZTc0MjIyYzIyNzQ2OTYzNmIyMjNhMjI1NTUzNDQ1NDIyMmMyMjYxNmQ3NDIyM2EyMjMxMzAzMDMwMjI3ZDY4IiwiYzAzMGMwNWRiZTlmY2ZjYjNjNmQ2M2I4YzU0YTU4YjdjMzQzODA0NmY1ZDI3NTMwZTMzNjE1YjhjMGUzNDVkYWJhIl0sInNlcXVlbmNlIjo0Mjk0OTY3Mjk1fV0sInZvdXQiOlt7InZhbHVlIjowLjAwMDAwNTQ2LCJuIjowLCJzY3JpcHRQdWJLZXkiOnsiYXNtIjoiMSA0N2ViNjllNWU4NDA2Y2QyODc1YTM5YjJiZDhiYzViYjNkOGEzN2E5ODg4NWYyODJlNzg4YzE2MTg3YWZiMWVlIiwiaGV4IjoiNTEyMDQ3ZWI2OWU1ZTg0MDZjZDI4NzVhMzliMmJkOGJjNWJiM2Q4YTM3YTk4ODg1ZjI4MmU3ODhjMTYxODdhZmIxZWUiLCJ0eXBlIjoid2l0bmVzc192MV90YXByb290In19XX0seyJoZXgiOiIwMjAwMDAwMDAwMDEwMTlkMTE4ZWNiOTBkMTJhM2ViZDQ4YWUzMjA4ZDIyYTNlZDJmMjA4ZWNiZDNhNmQ2NDg5OWQxODJiZDAxZWIwZjMwNTAwMDAwMDAwZmZmZmZmZmYwMTIyMDIwMDAwMDAwMDAwMDAyMjUxMjAyZGU4NTIxNDhlZDMxNjg4NTU2NGM0NDYyYmQwZmQwMDY2NmQzZTA3OWQ4NTIwMTllNDFmOTAyMTIwODc4ZGQ1MDM0MDIyN2IxODg2NmNmMzQxOTZlZTA4YzgzZjM1YmMxOWJhMmVjZjJkMmQxNTI3MjNjOWIzNGY5MWUyOTkzY2I1NmFlZmI5YmY2NWNiYzAzMTAzM2I3MmMzZTdlMGM1YmNlZjBmZTkyOTk2YTFjMTkyNTQ5YjFhNjY3NDhhMzk1ZGE5N2IyMGE1M2ZjMzMxYTRjODk1ZDYzNDBmMjI3NjdlMDBhMDRjYWUzNzZjNGQyMTA0ZWNmNWYwMmU2N2ZkYjgxN2RjNTRhYzAwNjMwMzZmNzI2NDAxMDExODc0NjU3ODc0MmY3MDZjNjE2OTZlM2I2MzY4NjE3MjczNjU3NDNkNzU3NDY2MmQzODAwMzU3YjIyNzAyMjNhMjI2MjcyNjMyZDMyMzAyMjJjMjI2ZjcwMjIzYTIyNmQ2OTZlNzQyMjJjMjI3NDY5NjM2YjIyM2EyMjZkNjU2ZDY1MjIyYzIyNjE2ZDc0MjIzYTIyMzEzMDMwMzAyMjdkNjgyMWMwOTgzNzFjMTA4ZjY1YWM5M2MyZDA4OTAwYTBlYjZlYWNlOTBhNTQ3MTg2ODAxZmEyNTJiNDNlNTdlN2UyNzU1MTAwMDAwMDAwIiwidHhpZCI6IjAzYjQ0ZGZhMTMxMGE0ZWQ1OTU4MGJkNDNmZWM3OGI4MGZmYTE1MjFkOGNhZmExMjRkNjMwMGY3ZjY1NWVkNTciLCJoYXNoIjoiODlmZDg2MTc4ZGMwZGVlMTliZmNhY2U0ZjEzY2RiODUyYTM1ZGYyZjI0OTE5NGFiNmY0MDA0MjlmNzBkMTRkMSIsInNpemUiOjMyMCwidnNpemUiOjE1MSwid2VpZ2h0Ijo2MDIsInZlcnNpb24iOjIsImxvY2t0aW1lIjowLCJ2aW4iOlt7InR4aWQiOiJmM2IwMWVkMDJiMTg5ZDg5NjQ2ZDNhYmRlYzA4ZjJkMjNlMmFkMjA4MzJhZTQ4YmQzZTJhZDE5MGNiOGUxMTlkIiwidm91dCI6NSwic2NyaXB0U2lnIjp7ImFzbSI6IiIsImhleCI6IiJ9LCJ0eGlud2l0bmVzcyI6WyIyMjdiMTg4NjZjZjM0MTk2ZWUwOGM4M2YzNWJjMTliYTJlY2YyZDJkMTUyNzIzYzliMzRmOTFlMjk5M2NiNTZhZWZiOWJmNjVjYmMwMzEwMzNiNzJjM2U3ZTBjNWJjZWYwZmU5Mjk5NmExYzE5MjU0OWIxYTY2NzQ4YTM5NWRhOSIsIjIwYTUzZmMzMzFhNGM4OTVkNjM0MGYyMjc2N2UwMGEwNGNhZTM3NmM0ZDIxMDRlY2Y1ZjAyZTY3ZmRiODE3ZGM1NGFjMDA2MzAzNmY3MjY0MDEwMTE4NzQ2NTc4NzQyZjcwNmM2MTY5NmUzYjYzNjg2MTcyNzM2NTc0M2Q3NTc0NjYyZDM4MDAzNTdiMjI3MDIyM2EyMjYyNzI2MzJkMzIzMDIyMmMyMjZmNzAyMjNhMjI2ZDY5NmU3NDIyMmMyMjc0Njk2MzZiMjIzYTIyNmQ2NTZkNjUyMjJjMjI2MTZkNzQyMjNhMjIzMTMwMzAzMDIyN2Q2OCIsImMwOTgzNzFjMTA4ZjY1YWM5M2MyZDA4OTAwYTBlYjZlYWNlOTBhNTQ3MTg2ODAxZmEyNTJiNDNlNTdlN2UyNzU1MSJdLCJzZXF1ZW5jZSI6NDI5NDk2NzI5NX1dLCJ2b3V0IjpbeyJ2YWx1ZSI6MC4wMDAwMDU0NiwibiI6MCwic2NyaXB0UHViS2V5Ijp7ImFzbSI6IjEgMmRlODUyMTQ4ZWQzMTY4ODU1NjRjNDQ2MmJkMGZkMDA2NjZkM2UwNzlkODUyMDE5ZTQxZjkwMjEyMDg3OGRkNSIsImhleCI6IjUxMjAyZGU4NTIxNDhlZDMxNjg4NTU2NGM0NDYyYmQwZmQwMDY2NmQzZTA3OWQ4NTIwMTllNDFmOTAyMTIwODc4ZGQ1IiwidHlwZSI6IndpdG5lc3NfdjFfdGFwcm9vdCJ9fV19LHsiaGV4IjoiMDIwMDAwMDAwMDAxMDE5ZDExOGVjYjkwZDEyYTNlYmQ0OGFlMzIwOGQyMmEzZWQyZjIwOGVjYmQzYTZkNjQ4OTlkMTgyYmQwMWViMGYzMDcwMDAwMDAwMGZmZmZmZmZmMDEyMjAyMDAwMDAwMDAwMDAwMjI1MTIwMmRlODUyMTQ4ZWQzMTY4ODU1NjRjNDQ2MmJkMGZkMDA2NjZkM2UwNzlkODUyMDE5ZTQxZjkwMjEyMDg3OGRkNTAzNDAwNDljODVkMzAzYjZjM2U2MmU5MzY5MTEyNWMzNmQ4YTdjMDcwODg3NTliMWE1MzFhNTY5MjEyMTc3YWI1MDEyNTQ3ZDFlMzA1OWVlMmI4ZGExYWM3YjBiN2Q1NzA5NzE5ZDA3NDZiZTEwMGJhYjYxZmJiZjBjNGUzMGI1N2ExYTdiMjA3OTQ2ZDVjNzQzOWZmNjljYmI0MWViZTI2YmNlM2NkNWFlMDJhNzgwM2M3MmI5YzYyYTY1MzU3Y2IzZGQ2MGI4YWMwMDYzMDM2ZjcyNjQwMTAxMTg3NDY1Nzg3NDJmNzA2YzYxNjk2ZTNiNjM2ODYxNzI3MzY1NzQzZDc1NzQ2NjJkMzgwMDM1N2IyMjcwMjIzYTIyNjI3MjYzMmQzMjMwMjIyYzIyNmY3MDIyM2EyMjZkNjk2ZTc0MjIyYzIyNzQ2OTYzNmIyMjNhMjI2ZDY1NmQ2NTIyMmMyMjYxNmQ3NDIyM2EyMjMxMzAzMDMwMjI3ZDY4MjFjMTk4MzcxYzEwOGY2NWFjOTNjMmQwODkwMGEwZWI2ZWFjZTkwYTU0NzE4NjgwMWZhMjUyYjQzZTU3ZTdlMjc1NTEwMDAwMDAwMCIsInR4aWQiOiIxM2E5YzA5OGIyNDEyODMxM2M4MzMzNmRjZWZiZWJmYmM3NTY0ZjA2ODI1NGIwN2ExNTNkYmU4YTI4MjhlODU4IiwiaGFzaCI6IjE1ZDc3MTRlNGNhNzQzNGJhMmUwNDk3MzE0MGYyM2YwM2FlMTE2ZjQxNGVjYzNmMjk5M2ExZDk5YzJkZTdkMzUiLCJzaXplIjozMjAsInZzaXplIjoxNTEsIndlaWdodCI6NjAyLCJ2ZXJzaW9uIjoyLCJsb2NrdGltZSI6MCwidmluIjpbeyJ0eGlkIjoiZjNiMDFlZDAyYjE4OWQ4OTY0NmQzYWJkZWMwOGYyZDIzZTJhZDIwODMyYWU0OGJkM2UyYWQxOTBjYjhlMTE5ZCIsInZvdXQiOjcsInNjcmlwdFNpZyI6eyJhc20iOiIiLCJoZXgiOiIifSwidHhpbndpdG5lc3MiOlsiMDQ5Yzg1ZDMwM2I2YzNlNjJlOTM2OTExMjVjMzZkOGE3YzA3MDg4NzU5YjFhNTMxYTU2OTIxMjE3N2FiNTAxMjU0N2QxZTMwNTllZTJiOGRhMWFjN2IwYjdkNTcwOTcxOWQwNzQ2YmUxMDBiYWI2MWZiYmYwYzRlMzBiNTdhMWEiLCIyMDc5NDZkNWM3NDM5ZmY2OWNiYjQxZWJlMjZiY2UzY2Q1YWUwMmE3ODAzYzcyYjljNjJhNjUzNTdjYjNkZDYwYjhhYzAwNjMwMzZmNzI2NDAxMDExODc0NjU3ODc0MmY3MDZjNjE2OTZlM2I2MzY4NjE3MjczNjU3NDNkNzU3NDY2MmQzODAwMzU3YjIyNzAyMjNhMjI2MjcyNjMyZDMyMzAyMjJjMjI2ZjcwMjIzYTIyNmQ2OTZlNzQyMjJjMjI3NDY5NjM2YjIyM2EyMjZkNjU2ZDY1MjIyYzIyNjE2ZDc0MjIzYTIyMzEzMDMwMzAyMjdkNjgiLCJjMTk4MzcxYzEwOGY2NWFjOTNjMmQwODkwMGEwZWI2ZWFjZTkwYTU0NzE4NjgwMWZhMjUyYjQzZTU3ZTdlMjc1NTEiXSwic2VxdWVuY2UiOjQyOTQ5NjcyOTV9XSwidm91dCI6W3sidmFsdWUiOjAuMDAwMDA1NDYsIm4iOjAsInNjcmlwdFB1YktleSI6eyJhc20iOiIxIDJkZTg1MjE0OGVkMzE2ODg1NTY0YzQ0NjJiZDBmZDAwNjY2ZDNlMDc5ZDg1MjAxOWU0MWY5MDIxMjA4NzhkZDUiLCJoZXgiOiI1MTIwMmRlODUyMTQ4ZWQzMTY4ODU1NjRjNDQ2MmJkMGZkMDA2NjZkM2UwNzlkODUyMDE5ZTQxZjkwMjEyMDg3OGRkNSIsInR5cGUiOiJ3aXRuZXNzX3YxX3RhcHJvb3QifX1dfSx7ImhleCI6IjAyMDAwMDAwMDAwMTAxOTU0MjJkZDVmOGExMWQ4Njc0NDdmMDA1ZDA1ZDkyNTlhZGY1OGZmY2ExNzM2MzJmZjRjY2I5OTZjNTU3ZGVjZDBhMDAwMDAwMDBmZmZmZmZmZjAxMjIwMjAwMDAwMDAwMDAwMDIyNTEyMDQ3ZWI2OWU1ZTg0MDZjZDI4NzVhMzliMmJkOGJjNWJiM2Q4YTM3YTk4ODg1ZjI4MmU3ODhjMTYxODdhZmIxZWUwMzQwZTdmNTMyYTdlNjk2ZjkxMzI3ZTYzMDIxOWFiOGNiOTUxZGRiMTFjYTY1NmI3MzNiZDE1M2NkZDE4YWZmYjVhODE2ZDAxMjAzZWQzMmFmNTIzODM1Yzk4MDhkM2MwMDFlZTAzZjE4ZGY2MTY2NGNiMTY1NTVjNjdmYzBlMTkyZjM3YjIwMDQ1M2E5MDUzNjRiM2JiNjBjNmYzZmYwNzEwYmM1MmVmN2I5ZThiMTY0ZTQwYWEwOWNhOGYxYmVhMTE2MTBhZWFjMDA2MzAzNmY3MjY0MDEwMTE4NzQ2NTc4NzQyZjcwNmM2MTY5NmUzYjYzNjg2MTcyNzM2NTc0M2Q3NTc0NjYyZDM4MDAzNTdiMjI3MDIyM2EyMjYyNzI2MzJkMzIzMDIyMmMyMjZmNzAyMjNhMjI2ZDY5NmU3NDIyMmMyMjc0Njk2MzZiMjIzYTIyNTU1MzQ0NTQyMjJjMjI2MTZkNzQyMjNhMjIzMTMwMzAzMDIyN2Q2ODIxYzEzMGMwNWRiZTlmY2ZjYjNjNmQ2M2I4YzU0YTU4YjdjMzQzODA0NmY1ZDI3NTMwZTMzNjE1YjhjMGUzNDVkYWJhMDAwMDAwMDAiLCJ0eGlkIjoiZTc4Y2I2NzQxZmMwNTUzMzc3NGQ5NWY5YWE2YTQ1MDMxMjQ4NWI3ZGQzYTI4N2FhY2EyNTY2Yzg5NTI3MmM1YiIsImhhc2giOiJmNzQ3YWQwMzIzOGJjNTFkNjYyNjMwZGFjMDY4N2VlNDA5OGU2NjM5MjZkYzcxNGEwOTIyMjAxZjgyMzQxZWU3Iiwic2l6ZSI6MzIwLCJ2c2l6ZSI6MTUxLCJ3ZWlnaHQiOjYwMiwidmVyc2lvbiI6MiwibG9ja3RpbWUiOjAsInZpbiI6W3sidHhpZCI6ImNkZGU1N2M1OTZiOWNjZjQyZjYzNzNhMWZjOGZmNWFkNTk5MjVkZDAwNWYwNDc3NDg2MWRhMWY4ZDUyZDQyOTUiLCJ2b3V0IjoxMCwic2NyaXB0U2lnIjp7ImFzbSI6IiIsImhleCI6IiJ9LCJ0eGlud2l0bmVzcyI6WyJlN2Y1MzJhN2U2OTZmOTEzMjdlNjMwMjE5YWI4Y2I5NTFkZGIxMWNhNjU2YjczM2JkMTUzY2RkMThhZmZiNWE4MTZkMDEyMDNlZDMyYWY1MjM4MzVjOTgwOGQzYzAwMWVlMDNmMThkZjYxNjY0Y2IxNjU1NWM2N2ZjMGUxOTJmMyIsIjIwMDQ1M2E5MDUzNjRiM2JiNjBjNmYzZmYwNzEwYmM1MmVmN2I5ZThiMTY0ZTQwYWEwOWNhOGYxYmVhMTE2MTBhZWFjMDA2MzAzNmY3MjY0MDEwMTE4NzQ2NTc4NzQyZjcwNmM2MTY5NmUzYjYzNjg2MTcyNzM2NTc0M2Q3NTc0NjYyZDM4MDAzNTdiMjI3MDIyM2EyMjYyNzI2MzJkMzIzMDIyMmMyMjZmNzAyMjNhMjI2ZDY5NmU3NDIyMmMyMjc0Njk2MzZiMjIzYTIyNTU1MzQ0NTQyMjJjMjI2MTZkNzQyMjNhMjIzMTMwMzAzMDIyN2Q2OCIsImMxMzBjMDVkYmU5ZmNmY2IzYzZkNjNiOGM1NGE1OGI3YzM0MzgwNDZmNWQyNzUzMGUzMzYxNWI4YzBlMzQ1ZGFiYSJdLCJzZXF1ZW5jZSI6NDI5NDk2NzI5NX1dLCJ2b3V0IjpbeyJ2YWx1ZSI6MC4wMDAwMDU0NiwibiI6MCwic2NyaXB0UHViS2V5Ijp7ImFzbSI6IjEgNDdlYjY5ZTVlODQwNmNkMjg3NWEzOWIyYmQ4YmM1YmIzZDhhMzdhOTg4ODVmMjgyZTc4OGMxNjE4N2FmYjFlZSIsImhleCI6IjUxMjA0N2ViNjllNWU4NDA2Y2QyODc1YTM5YjJiZDhiYzViYjNkOGEzN2E5ODg4NWYyODJlNzg4YzE2MTg3YWZiMWVlIiwidHlwZSI6IndpdG5lc3NfdjFfdGFwcm9vdCJ9fV19LHsiaGV4IjoiMDIwMDAwMDAwMDAxMDE5NTQyMmRkNWY4YTExZDg2NzQ0N2YwMDVkMDVkOTI1OWFkZjU4ZmZjYTE3MzYzMmZmNGNjYjk5NmM1NTdkZWNkMDIwMDAwMDAwMGZmZmZmZmZmMDEyMjAyMDAwMDAwMDAwMDAwMjI1MTIwNDdlYjY5ZTVlODQwNmNkMjg3NWEzOWIyYmQ4YmM1YmIzZDhhMzdhOTg4ODVmMjgyZTc4OGMxNjE4N2FmYjFlZTAzNDBjZDQyNmJmY2ZiNGQzMzFhM2U4OTk5OTZhMzc2MTlmYTA5N2U2Mzc2ZjU5ZWRjYTdhNmZlYzg1MmYyMGE2YzVlODM2ZDliMzRkNWQzYTczYTRkZGMxZmYwNmY4ZGI5YWUzOGZkYTcyNDIxNDUyNGFkMWJlMWVjZTM5NTBhOWVmZDdiMjA1NTg4NmNkMmI2YmU3ZmQzN2I2NmQzODJhNTQ2YmQ0NDgyMjI2MzY0ZDY4ODQ0ZDhlZTgxNmQ5MWMyZTE5NzNmYWMwMDYzMDM2ZjcyNjQwMTAxMTg3NDY1Nzg3NDJmNzA2YzYxNjk2ZTNiNjM2ODYxNzI3MzY1NzQzZDc1NzQ2NjJkMzgwMDM1N2IyMjcwMjIzYTIyNjI3MjYzMmQzMjMwMjIyYzIyNmY3MDIyM2EyMjZkNjk2ZTc0MjIyYzIyNzQ2OTYzNmIyMjNhMjI1NTUzNDQ1NDIyMmMyMjYxNmQ3NDIyM2EyMjMxMzAzMDMwMjI3ZDY4MjFjMDMwYzA1ZGJlOWZjZmNiM2M2ZDYzYjhjNTRhNThiN2MzNDM4MDQ2ZjVkMjc1MzBlMzM2MTViOGMwZTM0NWRhYmEwMDAwMDAwMCIsInR4aWQiOiJkOWUzOGNhOTI0NjdjZWI0OWIyMWJhNDRmZmE1NGZhNzhkY2E0MGIzMzM1OTgwMDdhMTQ2ZDc1YWFiNGU2ZjVmIiwiaGFzaCI6IjcyYWMyY2I2ODBiYWUxNWMzZGVlY2Q0NjQyNWU1ZWM3OWI1ZDU2MmFkY2E1ZTBjYmY2NWViYTljZjgxODU0NGIiLCJzaXplIjozMjAsInZzaXplIjoxNTEsIndlaWdodCI6NjAyLCJ2ZXJzaW9uIjoyLCJsb2NrdGltZSI6MCwidmluIjpbeyJ0eGlkIjoiY2RkZTU3YzU5NmI5Y2NmNDJmNjM3M2ExZmM4ZmY1YWQ1OTkyNWRkMDA1ZjA0Nzc0ODYxZGExZjhkNTJkNDI5NSIsInZvdXQiOjIsInNjcmlwdFNpZyI6eyJhc20iOiIiLCJoZXgiOiIifSwidHhpbndpdG5lc3MiOlsiY2Q0MjZiZmNmYjRkMzMxYTNlODk5OTk2YTM3NjE5ZmEwOTdlNjM3NmY1OWVkY2E3YTZmZWM4NTJmMjBhNmM1ZTgzNmQ5YjM0ZDVkM2E3M2E0ZGRjMWZmMDZmOGRiOWFlMzhmZGE3MjQyMTQ1MjRhZDFiZTFlY2UzOTUwYTllZmQiLCIyMDU1ODg2Y2QyYjZiZTdmZDM3YjY2ZDM4MmE1NDZiZDQ0ODIyMjYzNjRkNjg4NDRkOGVlODE2ZDkxYzJlMTk3M2ZhYzAwNjMwMzZmNzI2NDAxMDExODc0NjU3ODc0MmY3MDZjNjE2OTZlM2I2MzY4NjE3MjczNjU3NDNkNzU3NDY2MmQzODAwMzU3YjIyNzAyMjNhMjI2MjcyNjMyZDMyMzAyMjJjMjI2ZjcwMjIzYTIyNmQ2OTZlNzQyMjJjMjI3NDY5NjM2YjIyM2EyMjU1NTM0NDU0MjIyYzIyNjE2ZDc0MjIzYTIyMzEzMDMwMzAyMjdkNjgiLCJjMDMwYzA1ZGJlOWZjZmNiM2M2ZDYzYjhjNTRhNThiN2MzNDM4MDQ2ZjVkMjc1MzBlMzM2MTViOGMwZTM0NWRhYmEiXSwic2VxdWVuY2UiOjQyOTQ5NjcyOTV9XSwidm91dCI6W3sidmFsdWUiOjAuMDAwMDA1NDYsIm4iOjAsInNjcmlwdFB1YktleSI6eyJhc20iOiIxIDQ3ZWI2OWU1ZTg0MDZjZDI4NzVhMzliMmJkOGJjNWJiM2Q4YTM3YTk4ODg1ZjI4MmU3ODhjMTYxODdhZmIxZWUiLCJoZXgiOiI1MTIwNDdlYjY5ZTVlODQwNmNkMjg3NWEzOWIyYmQ4YmM1YmIzZDhhMzdhOTg4ODVmMjgyZTc4OGMxNjE4N2FmYjFlZSIsInR5cGUiOiJ3aXRuZXNzX3YxX3RhcHJvb3QifX1dfSx7ImhleCI6IjAyMDAwMDAwMDAwMTAxOWQxMThlY2I5MGQxMmEzZWJkNDhhZTMyMDhkMjJhM2VkMmYyMDhlY2JkM2E2ZDY0ODk5ZDE4MmJkMDFlYjBmMzAyMDAwMDAwMDBmZmZmZmZmZjAxMjIwMjAwMDAwMDAwMDAwMDIyNTEyMDJkZTg1MjE0OGVkMzE2ODg1NTY0YzQ0NjJiZDBmZDAwNjY2ZDNlMDc5ZDg1MjAxOWU0MWY5MDIxMjA4NzhkZDUwMzQwOWM2YWI4M2U4ZWEzZGFmM2M5NzE1NWQ2MzBiMDVmNzBlYThlYjc0ZDk5MDYwNDFmODQ2ZDMzY2IzZGI4Yjc5OTZiMjMzMWJjY2I1MDc5YzNmOGY0YTM3NGE1NmM5MmJlNjQzNmY3MTU2NWQxODY4NDBhZWMzYTFmNjIzYmE4N2Q3YjIwZGU4OGRlMmU1YWNjNTNiNzkwZTg1MTA4OTQ1YzcyYWQ0YjcyNjQ5ZDc3ZWU0ZmU3YTg0NjU4NjA5YTVhNWM3MWFjMDA2MzAzNmY3MjY0MDEwMTE4NzQ2NTc4NzQyZjcwNmM2MTY5NmUzYjYzNjg2MTcyNzM2NTc0M2Q3NTc0NjYyZDM4MDAzNTdiMjI3MDIyM2EyMjYyNzI2MzJkMzIzMDIyMmMyMjZmNzAyMjNhMjI2ZDY5NmU3NDIyMmMyMjc0Njk2MzZiMjIzYTIyNmQ2NTZkNjUyMjJjMjI2MTZkNzQyMjNhMjIzMTMwMzAzMDIyN2Q2ODIxYzE5ODM3MWMxMDhmNjVhYzkzYzJkMDg5MDBhMGViNmVhY2U5MGE1NDcxODY4MDFmYTI1MmI0M2U1N2U3ZTI3NTUxMDAwMDAwMDAiLCJ0eGlkIjoiNjIyM2M3NDg5MDU1MDQwYTllNjQxMDU3MDA0ZmRkNWRiNGIyMDUyNzYwMjEzZWQ2YjYwOWFlZmRhMzgzNjM3MSIsImhhc2giOiIxMDdmOTI2NmEzZDBiMDE0ZjVmMjdlNDdlOTYxMmQ4YjM3MTZmMmQ1ZDJiOGU2OGUzZDM5OTQzYTc1MjgzYzlmIiwic2l6ZSI6MzIwLCJ2c2l6ZSI6MTUxLCJ3ZWlnaHQiOjYwMiwidmVyc2lvbiI6MiwibG9ja3RpbWUiOjAsInZpbiI6W3sidHhpZCI6ImYzYjAxZWQwMmIxODlkODk2NDZkM2FiZGVjMDhmMmQyM2UyYWQyMDgzMmFlNDhiZDNlMmFkMTkwY2I4ZTExOWQiLCJ2b3V0IjoyLCJzY3JpcHRTaWciOnsiYXNtIjoiIiwiaGV4IjoiIn0sInR4aW53aXRuZXNzIjpbIjljNmFiODNlOGVhM2RhZjNjOTcxNTVkNjMwYjA1ZjcwZWE4ZWI3NGQ5OTA2MDQxZjg0NmQzM2NiM2RiOGI3OTk2YjIzMzFiY2NiNTA3OWMzZjhmNGEzNzRhNTZjOTJiZTY0MzZmNzE1NjVkMTg2ODQwYWVjM2ExZjYyM2JhODdkIiwiMjBkZTg4ZGUyZTVhY2M1M2I3OTBlODUxMDg5NDVjNzJhZDRiNzI2NDlkNzdlZTRmZTdhODQ2NTg2MDlhNWE1YzcxYWMwMDYzMDM2ZjcyNjQwMTAxMTg3NDY1Nzg3NDJmNzA2YzYxNjk2ZTNiNjM2ODYxNzI3MzY1NzQzZDc1NzQ2NjJkMzgwMDM1N2IyMjcwMjIzYTIyNjI3MjYzMmQzMjMwMjIyYzIyNmY3MDIyM2EyMjZkNjk2ZTc0MjIyYzIyNzQ2OTYzNmIyMjNhMjI2ZDY1NmQ2NTIyMmMyMjYxNmQ3NDIyM2EyMjMxMzAzMDMwMjI3ZDY4IiwiYzE5ODM3MWMxMDhmNjVhYzkzYzJkMDg5MDBhMGViNmVhY2U5MGE1NDcxODY4MDFmYTI1MmI0M2U1N2U3ZTI3NTUxIl0sInNlcXVlbmNlIjo0Mjk0OTY3Mjk1fV0sInZvdXQiOlt7InZhbHVlIjowLjAwMDAwNTQ2LCJuIjowLCJzY3JpcHRQdWJLZXkiOnsiYXNtIjoiMSAyZGU4NTIxNDhlZDMxNjg4NTU2NGM0NDYyYmQwZmQwMDY2NmQzZTA3OWQ4NTIwMTllNDFmOTAyMTIwODc4ZGQ1IiwiaGV4IjoiNTEyMDJkZTg1MjE0OGVkMzE2ODg1NTY0YzQ0NjJiZDBmZDAwNjY2ZDNlMDc5ZDg1MjAxOWU0MWY5MDIxMjA4NzhkZDUiLCJ0eXBlIjoid2l0bmVzc192MV90YXByb290In19XX0seyJoZXgiOiIwMjAwMDAwMDAwMDEwMTlkMTE4ZWNiOTBkMTJhM2ViZDQ4YWUzMjA4ZDIyYTNlZDJmMjA4ZWNiZDNhNmQ2NDg5OWQxODJiZDAxZWIwZjMxNDAwMDAwMDAwZmZmZmZmZmYwMTIyMDIwMDAwMDAwMDAwMDAyMjUxMjAyZGU4NTIxNDhlZDMxNjg4NTU2NGM0NDYyYmQwZmQwMDY2NmQzZTA3OWQ4NTIwMTllNDFmOTAyMTIwODc4ZGQ1MDM0MDIyYzVmMDJmODllZjhjN2U2ZjRlYzkxMjNmOWIyNTIwZWEwM2UwMzllYjhjOTNkODQ3YWUyOTMyNTQ3ZTRlYThkOGRlZTdkNThmMmY5NGMyZGE2NzQ2ODM5MmRhMzcwMjE1NjdjNTQyZmQxNWI2OTlhYTdmMjlhOWJiM2MwMzc3N2IyMDZmODdhYzUyYTcyNjU3N2M5ODNiYTU1Nzk4ZjI5MDEyMzY3NmE0NDYzMDhlMDU4MjQ3NjZjOTg0OGYzMDQwMDZhYzAwNjMwMzZmNzI2NDAxMDExODc0NjU3ODc0MmY3MDZjNjE2OTZlM2I2MzY4NjE3MjczNjU3NDNkNzU3NDY2MmQzODAwMzU3YjIyNzAyMjNhMjI2MjcyNjMyZDMyMzAyMjJjMjI2ZjcwMjIzYTIyNmQ2OTZlNzQyMjJjMjI3NDY5NjM2YjIyM2EyMjZkNjU2ZDY1MjIyYzIyNjE2ZDc0MjIzYTIyMzEzMDMwMzAyMjdkNjgyMWMwOTgzNzFjMTA4ZjY1YWM5M2MyZDA4OTAwYTBlYjZlYWNlOTBhNTQ3MTg2ODAxZmEyNTJiNDNlNTdlN2UyNzU1MTAwMDAwMDAwIiwidHhpZCI6ImY2NzkzM2QxZDdjMGRhNjkyMTkyYmQ5NGQyOGFmM2MzNTdkZjU5NTUxM2RkMzJmZDE0NmRiYzkxMWQxYmI4NzciLCJoYXNoIjoiNzdkNmZkNzc5MzRjYTBlYjBiMTRiNmVkZjQ5MTU1MjA0NzM5NmM0NGQwYWMxYzkxNzdiNWZlYzQyOWQyY2NjZiIsInNpemUiOjMyMCwidnNpemUiOjE1MSwid2VpZ2h0Ijo2MDIsInZlcnNpb24iOjIsImxvY2t0aW1lIjowLCJ2aW4iOlt7InR4aWQiOiJmM2IwMWVkMDJiMTg5ZDg5NjQ2ZDNhYmRlYzA4ZjJkMjNlMmFkMjA4MzJhZTQ4YmQzZTJhZDE5MGNiOGUxMTlkIiwidm91dCI6MjAsInNjcmlwdFNpZyI6eyJhc20iOiIiLCJoZXgiOiIifSwidHhpbndpdG5lc3MiOlsiMjJjNWYwMmY4OWVmOGM3ZTZmNGVjOTEyM2Y5YjI1MjBlYTAzZTAzOWViOGM5M2Q4NDdhZTI5MzI1NDdlNGVhOGQ4ZGVlN2Q1OGYyZjk0YzJkYTY3NDY4MzkyZGEzNzAyMTU2N2M1NDJmZDE1YjY5OWFhN2YyOWE5YmIzYzAzNzciLCIyMDZmODdhYzUyYTcyNjU3N2M5ODNiYTU1Nzk4ZjI5MDEyMzY3NmE0NDYzMDhlMDU4MjQ3NjZjOTg0OGYzMDQwMDZhYzAwNjMwMzZmNzI2NDAxMDExODc0NjU3ODc0MmY3MDZjNjE2OTZlM2I2MzY4NjE3MjczNjU3NDNkNzU3NDY2MmQzODAwMzU3YjIyNzAyMjNhMjI2MjcyNjMyZDMyMzAyMjJjMjI2ZjcwMjIzYTIyNmQ2OTZlNzQyMjJjMjI3NDY5NjM2YjIyM2EyMjZkNjU2ZDY1MjIyYzIyNjE2ZDc0MjIzYTIyMzEzMDMwMzAyMjdkNjgiLCJjMDk4MzcxYzEwOGY2NWFjOTNjMmQwODkwMGEwZWI2ZWFjZTkwYTU0NzE4NjgwMWZhMjUyYjQzZTU3ZTdlMjc1NTEiXSwic2VxdWVuY2UiOjQyOTQ5NjcyOTV9XSwidm91dCI6W3sidmFsdWUiOjAuMDAwMDA1NDYsIm4iOjAsInNjcmlwdFB1YktleSI6eyJhc20iOiIxIDJkZTg1MjE0OGVkMzE2ODg1NTY0YzQ0NjJiZDBmZDAwNjY2ZDNlMDc5ZDg1MjAxOWU0MWY5MDIxMjA4NzhkZDUiLCJoZXgiOiI1MTIwMmRlODUyMTQ4ZWQzMTY4ODU1NjRjNDQ2MmJkMGZkMDA2NjZkM2UwNzlkODUyMDE5ZTQxZjkwMjEyMDg3OGRkNSIsInR5cGUiOiJ3aXRuZXNzX3YxX3RhcHJvb3QifX1dfSx7ImhleCI6IjAyMDAwMDAwMDAwMTAxOWQxMThlY2I5MGQxMmEzZWJkNDhhZTMyMDhkMjJhM2VkMmYyMDhlY2JkM2E2ZDY0ODk5ZDE4MmJkMDFlYjBmMzA0MDAwMDAwMDBmZmZmZmZmZjAxMjIwMjAwMDAwMDAwMDAwMDIyNTEyMDJkZTg1MjE0OGVkMzE2ODg1NTY0YzQ0NjJiZDBmZDAwNjY2ZDNlMDc5ZDg1MjAxOWU0MWY5MDIxMjA4NzhkZDUwMzQwOTMzYWQwMTg1OWY5NzczNDQ2ODgzYzJjMDMxOTNjZjQ5YTI5MjFlN2RkYmI4MDdiNjY5NzVlNDE4YWVhOWY0MWY2MmU1NTNhNDEzOWI2N2Y2ZjQ5NjE3NDEwMTc5ZGU4NTVlOWJkOWUwMDkxYjIzNjlhZTE0MDA2NWM5MjIyNDU3YjIwYTA2MzIwY2MwOGM4MmQyYWNiZjlmZTMzNzcwOTU4Nzc3N2I0MWU1Njk2MzMyMTIxYmNkNThiMmQ2N2FhNTdjN2FjMDA2MzAzNmY3MjY0MDEwMTE4NzQ2NTc4NzQyZjcwNmM2MTY5NmUzYjYzNjg2MTcyNzM2NTc0M2Q3NTc0NjYyZDM4MDAzNTdiMjI3MDIyM2EyMjYyNzI2MzJkMzIzMDIyMmMyMjZmNzAyMjNhMjI2ZDY5NmU3NDIyMmMyMjc0Njk2MzZiMjIzYTIyNmQ2NTZkNjUyMjJjMjI2MTZkNzQyMjNhMjIzMTMwMzAzMDIyN2Q2ODIxYzA5ODM3MWMxMDhmNjVhYzkzYzJkMDg5MDBhMGViNmVhY2U5MGE1NDcxODY4MDFmYTI1MmI0M2U1N2U3ZTI3NTUxMDAwMDAwMDAiLCJ0eGlkIjoiOTVmNzYyOWM2ODcwYmNlMjIzY2NkZTYxYzE0NGJhNjY2YjM5MzM0MDRkYjYyMmI5NzQ0ZmM2MzNjNjBmMTU4MSIsImhhc2giOiI2ZDg5MmZjYzNiMmUzNTZhNTZhNDIyNWQ0YWJjOTdmNDE0ODc3YzVhZjc5NjhhODAxZGU2Yjc3MjE5YTIyYjI3Iiwic2l6ZSI6MzIwLCJ2c2l6ZSI6MTUxLCJ3ZWlnaHQiOjYwMiwidmVyc2lvbiI6MiwibG9ja3RpbWUiOjAsInZpbiI6W3sidHhpZCI6ImYzYjAxZWQwMmIxODlkODk2NDZkM2FiZGVjMDhmMmQyM2UyYWQyMDgzMmFlNDhiZDNlMmFkMTkwY2I4ZTExOWQiLCJ2b3V0Ijo0LCJzY3JpcHRTaWciOnsiYXNtIjoiIiwiaGV4IjoiIn0sInR4aW53aXRuZXNzIjpbIjkzM2FkMDE4NTlmOTc3MzQ0Njg4M2MyYzAzMTkzY2Y0OWEyOTIxZTdkZGJiODA3YjY2OTc1ZTQxOGFlYTlmNDFmNjJlNTUzYTQxMzliNjdmNmY0OTYxNzQxMDE3OWRlODU1ZTliZDllMDA5MWIyMzY5YWUxNDAwNjVjOTIyMjQ1IiwiMjBhMDYzMjBjYzA4YzgyZDJhY2JmOWZlMzM3NzA5NTg3Nzc3YjQxZTU2OTYzMzIxMjFiY2Q1OGIyZDY3YWE1N2M3YWMwMDYzMDM2ZjcyNjQwMTAxMTg3NDY1Nzg3NDJmNzA2YzYxNjk2ZTNiNjM2ODYxNzI3MzY1NzQzZDc1NzQ2NjJkMzgwMDM1N2IyMjcwMjIzYTIyNjI3MjYzMmQzMjMwMjIyYzIyNmY3MDIyM2EyMjZkNjk2ZTc0MjIyYzIyNzQ2OTYzNmIyMjNhMjI2ZDY1NmQ2NTIyMmMyMjYxNmQ3NDIyM2EyMjMxMzAzMDMwMjI3ZDY4IiwiYzA5ODM3MWMxMDhmNjVhYzkzYzJkMDg5MDBhMGViNmVhY2U5MGE1NDcxODY4MDFmYTI1MmI0M2U1N2U3ZTI3NTUxIl0sInNlcXVlbmNlIjo0Mjk0OTY3Mjk1fV0sInZvdXQiOlt7InZhbHVlIjowLjAwMDAwNTQ2LCJuIjowLCJzY3JpcHRQdWJLZXkiOnsiYXNtIjoiMSAyZGU4NTIxNDhlZDMxNjg4NTU2NGM0NDYyYmQwZmQwMDY2NmQzZTA3OWQ4NTIwMTllNDFmOTAyMTIwODc4ZGQ1IiwiaGV4IjoiNTEyMDJkZTg1MjE0OGVkMzE2ODg1NTY0YzQ0NjJiZDBmZDAwNjY2ZDNlMDc5ZDg1MjAxOWU0MWY5MDIxMjA4NzhkZDUiLCJ0eXBlIjoid2l0bmVzc192MV90YXByb290In19XX0seyJoZXgiOiIwMjAwMDAwMDAwMDEwMTljM2M5MTEwNzVhZmYzNDllZjg4YzJkZGM2MzcyODFiNTkwYmI5YzlhYzk5ZTJjZmRmODI5NWE4NWYyM2MwOGQwMTAwMDAwMDAwZmRmZmZmZmYwMmU4MDMwMDAwMDAwMDAwMDAxNjAwMTQ5M2U5ZWI0YTcwNzIwYzhkNDdlM2U5NGI1Yzk1ZDJlN2YxM2UyYmQ4ZDI5ZjBkMDAwMDAwMDAwMDE2MDAxNDA4YTI2OGU1OWI3Y2I3YzYzNzg0ZGE3NTQxODA3ZmIzNmU3NDY0YmEwMjQ3MzA0NDAyMjA2NmFkNmYxZjM2MmI4ZjE1YTJmNmI4MjVkMWJkNzRmNWU1YWU2YmUwYWYxNjYwY2ExMWM1ZTNiYjMwZTAwZDA1MDIyMDBiOTYyYTE0MjdhOWE1NzU5Nzg1ZmNmNjdjNjgyOWI3NzEwYzIxYTZlMzJkNzBmODJmYTMwNzc1ZjA4MDMxNWMwMTIxMDM1M2FhYjBiOWNmZTRiNmJhZDg1YWYwZWRiOWM0OGFhYmMzY2U4ZGEzYzI5MjRlZTRmNTc0NTZkN2FhOGMwMmI5MTEzYjI2MDAiLCJ0eGlkIjoiNzk0ZjNhNWIzYTkzYjNhZDk3ZjYwMzkwY2U0NWY1NDllZmQ4NTJjNThkZGRlNGY1YTViYTAwN2QzZmMzNGE4MSIsImhhc2giOiJkNDllNjI5MTg5NzFmNDEyYjgwNGRmMzhhOTIyMzI2ODRhYmJkYzgxNzljZTEwOTk3ZThlMTFlZDk5ZjJkNWNkIiwic2l6ZSI6MjIyLCJ2c2l6ZSI6MTQxLCJ3ZWlnaHQiOjU2MSwidmVyc2lvbiI6MiwibG9ja3RpbWUiOjI1MDU0ODksInZpbiI6W3sidHhpZCI6IjhkYzAyMzVmYTg5NTgyZGZjZmUyOTlhY2M5YjkwYjU5MWIyODM3YzZkZGMyODhlZjQ5ZjNhZjc1MTA5MTNjOWMiLCJ2b3V0IjoxLCJzY3JpcHRTaWciOnsiYXNtIjoiIiwiaGV4IjoiIn0sInR4aW53aXRuZXNzIjpbIjMwNDQwMjIwNjZhZDZmMWYzNjJiOGYxNWEyZjZiODI1ZDFiZDc0ZjVlNWFlNmJlMGFmMTY2MGNhMTFjNWUzYmIzMGUwMGQwNTAyMjAwYjk2MmExNDI3YTlhNTc1OTc4NWZjZjY3YzY4MjliNzcxMGMyMWE2ZTMyZDcwZjgyZmEzMDc3NWYwODAzMTVjMDEiLCIwMzUzYWFiMGI5Y2ZlNGI2YmFkODVhZjBlZGI5YzQ4YWFiYzNjZThkYTNjMjkyNGVlNGY1NzQ1NmQ3YWE4YzAyYjkiXSwic2VxdWVuY2UiOjQyOTQ5NjcyOTN9XSwidm91dCI6W3sidmFsdWUiOjAuMDAwMDEsIm4iOjAsInNjcmlwdFB1YktleSI6eyJhc20iOiIwIDkzZTllYjRhNzA3MjBjOGQ0N2UzZTk0YjVjOTVkMmU3ZjEzZTJiZDgiLCJoZXgiOiIwMDE0OTNlOWViNGE3MDcyMGM4ZDQ3ZTNlOTRiNWM5NWQyZTdmMTNlMmJkOCIsInR5cGUiOiJ3aXRuZXNzX3YwX2tleWhhc2gifX0seyJ2YWx1ZSI6MC4wMDg5Mjg4MiwibiI6MSwic2NyaXB0UHViS2V5Ijp7ImFzbSI6IjAgMDhhMjY4ZTU5YjdjYjdjNjM3ODRkYTc1NDE4MDdmYjM2ZTc0NjRiYSIsImhleCI6IjAwMTQwOGEyNjhlNTliN2NiN2M2Mzc4NGRhNzU0MTgwN2ZiMzZlNzQ2NGJhIiwidHlwZSI6IndpdG5lc3NfdjBfa2V5aGFzaCJ9fV19LHsiaGV4IjoiMDIwMDAwMDAwMDAxMDFkZjg4MDhjYzQ3Y2Y0MmYyODEyN2ZjZjU2OWEyNDcyYWQ2NmZkNzJjM2RjZjgwMjk1NjAzMzBlM2QwMGM4ZTkwMDAwMDAwMDAwMGZkZmZmZmZmMDI0MDFmMDAwMDAwMDAwMDAwMTYwMDE0N2FlODQ2YTA3MDdiNTY2YTU2ZjA2ZDE1OGE3ZGU5YjNiZGRhZjM1YzBlNDIxNTAwMDAwMDAwMDAxNjAwMTRhOTZhMDlmMTFjOTc5Y2Y1NTE4OTQwYmRhNjEyYTY5NmU0MTc1NmQ0MDI0NzMwNDQwMjIwMzkwMjkxMjA1ZjdkYjU1ODU1NDBhNjk2NjA4YjI5ZmY0YTg1OWI0MjJlZGViNThiMGUzMmM0YjllYWViZDJjYzAyMjAwY2E5Yzg4YjJhYWQzNGFjNzg2MzIwMWZiNmI5ZDFkN2NlZGMyOWU2ODk4N2FlN2IxNWQwYTVlNmI5NjVmMTJjMDEyMTAyMmIzOWNkYTdiN2Y4YjUxZjRhZjdmOWI3OTIyNjg3YmExODQ4ZTNjZGEyY2Q1ODA0Y2EwNDFjZmNkMzk3ZGZkOWVmM2EyNjAwIiwidHhpZCI6IjE5NzJkYzM3OWMwMzk4YzUxOWZmNTk0MzIwNjBjMDZiN2UyOGMyZDQ4ZTA5MjUyNmU0ZjJlN2ZlYzk2M2ZkOGIiLCJoYXNoIjoiNTg5NmI1ZTFmY2E5ODU4ZTY2NTQyZmEwMTViNGY1MWFkNGZhNzRmNjc0Y2MyZDI0ZmZhOTgxYzA1ZjJjZWU1YSIsInNpemUiOjIyMiwidnNpemUiOjE0MSwid2VpZ2h0Ijo1NjEsInZlcnNpb24iOjIsImxvY2t0aW1lIjoyNTA1NDU1LCJ2aW4iOlt7InR4aWQiOiI5MDhlMGNkMGUzMzAwMzU2Mjk4MGNmM2QyY2Q3NmZkNjJhNDdhMjY5ZjVmYzI3ODFmMjQyY2Y0N2NjMDg4OGRmIiwidm91dCI6MCwic2NyaXB0U2lnIjp7ImFzbSI6IiIsImhleCI6IiJ9LCJ0eGlud2l0bmVzcyI6WyIzMDQ0MDIyMDM5MDI5MTIwNWY3ZGI1NTg1NTQwYTY5NjYwOGIyOWZmNGE4NTliNDIyZWRlYjU4YjBlMzJjNGI5ZWFlYmQyY2MwMjIwMGNhOWM4OGIyYWFkMzRhYzc4NjMyMDFmYjZiOWQxZDdjZWRjMjllNjg5ODdhZTdiMTVkMGE1ZTZiOTY1ZjEyYzAxIiwiMDIyYjM5Y2RhN2I3ZjhiNTFmNGFmN2Y5Yjc5MjI2ODdiYTE4NDhlM2NkYTJjZDU4MDRjYTA0MWNmY2QzOTdkZmQ5Il0sInNlcXVlbmNlIjo0Mjk0OTY3MjkzfV0sInZvdXQiOlt7InZhbHVlIjowLjAwMDA4LCJuIjowLCJzY3JpcHRQdWJLZXkiOnsiYXNtIjoiMCA3YWU4NDZhMDcwN2I1NjZhNTZmMDZkMTU4YTdkZTliM2JkZGFmMzVjIiwiaGV4IjoiMDAxNDdhZTg0NmEwNzA3YjU2NmE1NmYwNmQxNThhN2RlOWIzYmRkYWYzNWMiLCJ0eXBlIjoid2l0bmVzc192MF9rZXloYXNoIn19LHsidmFsdWUiOjAuMDEzOTMxNjYsIm4iOjEsInNjcmlwdFB1YktleSI6eyJhc20iOiIwIGE5NmEwOWYxMWM5NzljZjU1MTg5NDBiZGE2MTJhNjk2ZTQxNzU2ZDQiLCJoZXgiOiIwMDE0YTk2YTA5ZjExYzk3OWNmNTUxODk0MGJkYTYxMmE2OTZlNDE3NTZkNCIsInR5cGUiOiJ3aXRuZXNzX3YwX2tleWhhc2gifX1dfSx7ImhleCI6IjAyMDAwMDAwMDAwMTAxOTU0MjJkZDVmOGExMWQ4Njc0NDdmMDA1ZDA1ZDkyNTlhZGY1OGZmY2ExNzM2MzJmZjRjY2I5OTZjNTU3ZGVjZDE1MDAwMDAwMDBmZmZmZmZmZjAxMjIwMjAwMDAwMDAwMDAwMDIyNTEyMDQ3ZWI2OWU1ZTg0MDZjZDI4NzVhMzliMmJkOGJjNWJiM2Q4YTM3YTk4ODg1ZjI4MmU3ODhjMTYxODdhZmIxZWUwMzQwYjcwOTJkNTdkNzRhZjg1ODFmYjMwM2I1ODI3MzY3OWM3ZWYxMDYxNmJlMTJjZWFkZDMwZmVmODc5MWMyNjMxMzFlZjRmMzc3NDY5YTkzZTA5MTQxNGZjMWQyZmZmZGJiM2NjZTY3OGYwZTQ5MjQ0YTdjYTgwYjQ5MjdjNjJmM2Y3YjIwYTEyZjdkMjJmYmQxNmVlMWNmNmRiMDcyNjNiZGZhNjkzNzZmZDMzZTE1MzA2MjhkNDExNGQ2MTZmOGE0ZjFkMWFjMDA2MzAzNmY3MjY0MDEwMTE4NzQ2NTc4NzQyZjcwNmM2MTY5NmUzYjYzNjg2MTcyNzM2NTc0M2Q3NTc0NjYyZDM4MDAzNTdiMjI3MDIyM2EyMjYyNzI2MzJkMzIzMDIyMmMyMjZmNzAyMjNhMjI2ZDY5NmU3NDIyMmMyMjc0Njk2MzZiMjIzYTIyNTU1MzQ0NTQyMjJjMjI2MTZkNzQyMjNhMjIzMTMwMzAzMDIyN2Q2ODIxYzEzMGMwNWRiZTlmY2ZjYjNjNmQ2M2I4YzU0YTU4YjdjMzQzODA0NmY1ZDI3NTMwZTMzNjE1YjhjMGUzNDVkYWJhMDAwMDAwMDAiLCJ0eGlkIjoiZWUyOTMyZmFjMTMyZGIwMjFiMzAzMzliNjJjZTM1Njk3MmU3N2RiMzc1OTI3MzkzMjkxOWNjMjg4YTQyYjk4YyIsImhhc2giOiI0OGI4MzI1MjI2Y2UyNGU3Y2ZjZWFjMDAyMjY0OGZhNjFlYTg3NDk3YTAyMjYxZGYyNTJmM2I5OTliZTY5ODRlIiwic2l6ZSI6MzIwLCJ2c2l6ZSI6MTUxLCJ3ZWlnaHQiOjYwMiwidmVyc2lvbiI6MiwibG9ja3RpbWUiOjAsInZpbiI6W3sidHhpZCI6ImNkZGU1N2M1OTZiOWNjZjQyZjYzNzNhMWZjOGZmNWFkNTk5MjVkZDAwNWYwNDc3NDg2MWRhMWY4ZDUyZDQyOTUiLCJ2b3V0IjoyMSwic2NyaXB0U2lnIjp7ImFzbSI6IiIsImhleCI6IiJ9LCJ0eGlud2l0bmVzcyI6WyJiNzA5MmQ1N2Q3NGFmODU4MWZiMzAzYjU4MjczNjc5YzdlZjEwNjE2YmUxMmNlYWRkMzBmZWY4NzkxYzI2MzEzMWVmNGYzNzc0NjlhOTNlMDkxNDE0ZmMxZDJmZmZkYmIzY2NlNjc4ZjBlNDkyNDRhN2NhODBiNDkyN2M2MmYzZiIsIjIwYTEyZjdkMjJmYmQxNmVlMWNmNmRiMDcyNjNiZGZhNjkzNzZmZDMzZTE1MzA2MjhkNDExNGQ2MTZmOGE0ZjFkMWFjMDA2MzAzNmY3MjY0MDEwMTE4NzQ2NTc4NzQyZjcwNmM2MTY5NmUzYjYzNjg2MTcyNzM2NTc0M2Q3NTc0NjYyZDM4MDAzNTdiMjI3MDIyM2EyMjYyNzI2MzJkMzIzMDIyMmMyMjZmNzAyMjNhMjI2ZDY5NmU3NDIyMmMyMjc0Njk2MzZiMjIzYTIyNTU1MzQ0NTQyMjJjMjI2MTZkNzQyMjNhMjIzMTMwMzAzMDIyN2Q2OCIsImMxMzBjMDVkYmU5ZmNmY2IzYzZkNjNiOGM1NGE1OGI3YzM0MzgwNDZmNWQyNzUzMGUzMzYxNWI4YzBlMzQ1ZGFiYSJdLCJzZXF1ZW5jZSI6NDI5NDk2NzI5NX1dLCJ2b3V0IjpbeyJ2YWx1ZSI6MC4wMDAwMDU0NiwibiI6MCwic2NyaXB0UHViS2V5Ijp7ImFzbSI6IjEgNDdlYjY5ZTVlODQwNmNkMjg3NWEzOWIyYmQ4YmM1YmIzZDhhMzdhOTg4ODVmMjgyZTc4OGMxNjE4N2FmYjFlZSIsImhleCI6IjUxMjA0N2ViNjllNWU4NDA2Y2QyODc1YTM5YjJiZDhiYzViYjNkOGEzN2E5ODg4NWYyODJlNzg4YzE2MTg3YWZiMWVlIiwidHlwZSI6IndpdG5lc3NfdjFfdGFwcm9vdCJ9fV19LHsiaGV4IjoiMDIwMDAwMDAwMDAxMDE5NTQyMmRkNWY4YTExZDg2NzQ0N2YwMDVkMDVkOTI1OWFkZjU4ZmZjYTE3MzYzMmZmNGNjYjk5NmM1NTdkZWNkMTAwMDAwMDAwMGZmZmZmZmZmMDEyMjAyMDAwMDAwMDAwMDAwMjI1MTIwNDdlYjY5ZTVlODQwNmNkMjg3NWEzOWIyYmQ4YmM1YmIzZDhhMzdhOTg4ODVmMjgyZTc4OGMxNjE4N2FmYjFlZTAzNDBhNGIyNGJjNDI4ZWNjYmE3NzU2N2EzYTJjYjc0MTQ2MjJhNTAzOWJkOTcxY2JmMTI3Njg1ZTA0NzIyY2JiNTAwY2YwNmUxODI3ZDYxNTY2OGZmN2Q4NWYwZjljOTM4MTZmODM1MjMzOWQ1MDMyYWNlN2Y4MGY3NTIzMmFhYTcxZjdiMjBkNTNlYTE1NDgzOTRiZjQ5Y2U2YjhhMWNiMzIzNDY2ZWZhMDc3ZWY5YmFkMWQ5ZjBhMDE2ZGViYTBlNDE2Y2YwYWMwMDYzMDM2ZjcyNjQwMTAxMTg3NDY1Nzg3NDJmNzA2YzYxNjk2ZTNiNjM2ODYxNzI3MzY1NzQzZDc1NzQ2NjJkMzgwMDM1N2IyMjcwMjIzYTIyNjI3MjYzMmQzMjMwMjIyYzIyNmY3MDIyM2EyMjZkNjk2ZTc0MjIyYzIyNzQ2OTYzNmIyMjNhMjI1NTUzNDQ1NDIyMmMyMjYxNmQ3NDIyM2EyMjMxMzAzMDMwMjI3ZDY4MjFjMTMwYzA1ZGJlOWZjZmNiM2M2ZDYzYjhjNTRhNThiN2MzNDM4MDQ2ZjVkMjc1MzBlMzM2MTViOGMwZTM0NWRhYmEwMDAwMDAwMCIsInR4aWQiOiI3ZjRkY2I4MzM2ZGYzYjJhM2FmZjNiZmIwMzkzM2ZlMGFmMTFmN2M4ZDgyMjJjYzZkMWU0NDJhNjQyM2MxODhkIiwiaGFzaCI6Ijc1ZTNjOTY3NDE5MjJjNWM1NmIxMjRlMGM1ZWEyZmEwYmExNzU0NTRiNGZiNjc0MGE4MGY3YzhlZjFmODZkM2YiLCJzaXplIjozMjAsInZzaXplIjoxNTEsIndlaWdodCI6NjAyLCJ2ZXJzaW9uIjoyLCJsb2NrdGltZSI6MCwidmluIjpbeyJ0eGlkIjoiY2RkZTU3YzU5NmI5Y2NmNDJmNjM3M2ExZmM4ZmY1YWQ1OTkyNWRkMDA1ZjA0Nzc0ODYxZGExZjhkNTJkNDI5NSIsInZvdXQiOjE2LCJzY3JpcHRTaWciOnsiYXNtIjoiIiwiaGV4IjoiIn0sInR4aW53aXRuZXNzIjpbImE0YjI0YmM0MjhlY2NiYTc3NTY3YTNhMmNiNzQxNDYyMmE1MDM5YmQ5NzFjYmYxMjc2ODVlMDQ3MjJjYmI1MDBjZjA2ZTE4MjdkNjE1NjY4ZmY3ZDg1ZjBmOWM5MzgxNmY4MzUyMzM5ZDUwMzJhY2U3ZjgwZjc1MjMyYWFhNzFmIiwiMjBkNTNlYTE1NDgzOTRiZjQ5Y2U2YjhhMWNiMzIzNDY2ZWZhMDc3ZWY5YmFkMWQ5ZjBhMDE2ZGViYTBlNDE2Y2YwYWMwMDYzMDM2ZjcyNjQwMTAxMTg3NDY1Nzg3NDJmNzA2YzYxNjk2ZTNiNjM2ODYxNzI3MzY1NzQzZDc1NzQ2NjJkMzgwMDM1N2IyMjcwMjIzYTIyNjI3MjYzMmQzMjMwMjIyYzIyNmY3MDIyM2EyMjZkNjk2ZTc0MjIyYzIyNzQ2OTYzNmIyMjNhMjI1NTUzNDQ1NDIyMmMyMjYxNmQ3NDIyM2EyMjMxMzAzMDMwMjI3ZDY4IiwiYzEzMGMwNWRiZTlmY2ZjYjNjNmQ2M2I4YzU0YTU4YjdjMzQzODA0NmY1ZDI3NTMwZTMzNjE1YjhjMGUzNDVkYWJhIl0sInNlcXVlbmNlIjo0Mjk0OTY3Mjk1fV0sInZvdXQiOlt7InZhbHVlIjowLjAwMDAwNTQ2LCJuIjowLCJzY3JpcHRQdWJLZXkiOnsiYXNtIjoiMSA0N2ViNjllNWU4NDA2Y2QyODc1YTM5YjJiZDhiYzViYjNkOGEzN2E5ODg4NWYyODJlNzg4YzE2MTg3YWZiMWVlIiwiaGV4IjoiNTEyMDQ3ZWI2OWU1ZTg0MDZjZDI4NzVhMzliMmJkOGJjNWJiM2Q4YTM3YTk4ODg1ZjI4MmU3ODhjMTYxODdhZmIxZWUiLCJ0eXBlIjoid2l0bmVzc192MV90YXByb290In19XX0seyJoZXgiOiIwMjAwMDAwMDAwMDEwMTlkMTE4ZWNiOTBkMTJhM2ViZDQ4YWUzMjA4ZDIyYTNlZDJmMjA4ZWNiZDNhNmQ2NDg5OWQxODJiZDAxZWIwZjMwYTAwMDAwMDAwZmZmZmZmZmYwMTIyMDIwMDAwMDAwMDAwMDAyMjUxMjAyZGU4NTIxNDhlZDMxNjg4NTU2NGM0NDYyYmQwZmQwMDY2NmQzZTA3OWQ4NTIwMTllNDFmOTAyMTIwODc4ZGQ1MDM0MGQ5OTYwNjA3NTY4ZDkzY2NmYzk1YmZhMDhiZGIwYWE2ZGVjNTk4N2YzNmY5ZjRhYmY1M2RjMjJjNGI4NTMxMTE3MmQxZDhhYjk5ZTVhYjYyNDJkMzMyYTg3YjJkMTljMjAyOTQwZjg4Zjc2M2RjMDZhY2FhODUxZjg5YTA2MTMyN2IyMGY4ZmNjZjBmNDQ3N2ZmYjI4NWMyYzc4ZjAyMTJiOTIxNTBkN2E4YmI3MzBlZGQ0ZjY5MjNmZTk2NTZmZjVhYTZhYzAwNjMwMzZmNzI2NDAxMDExODc0NjU3ODc0MmY3MDZjNjE2OTZlM2I2MzY4NjE3MjczNjU3NDNkNzU3NDY2MmQzODAwMzU3YjIyNzAyMjNhMjI2MjcyNjMyZDMyMzAyMjJjMjI2ZjcwMjIzYTIyNmQ2OTZlNzQyMjJjMjI3NDY5NjM2YjIyM2EyMjZkNjU2ZDY1MjIyYzIyNjE2ZDc0MjIzYTIyMzEzMDMwMzAyMjdkNjgyMWMxOTgzNzFjMTA4ZjY1YWM5M2MyZDA4OTAwYTBlYjZlYWNlOTBhNTQ3MTg2ODAxZmEyNTJiNDNlNTdlN2UyNzU1MTAwMDAwMDAwIiwidHhpZCI6IjdjNTA5ZDI5MjExN2JkM2FjNjdiMWQ1YjZhYzlmZDgzYmY3ZWFiYjBiMjY2YjM2Yzg4NTU4MjNhM2YyMjFmOTEiLCJoYXNoIjoiMDQ4MTQ1NjZmMzgwYmYwMTFiOGNhOGQ2ZTViZjgyMzQzM2JmZTExNjMzYTAzNDE5ZGRmYjIyMDljMDM3NDk3ZSIsInNpemUiOjMyMCwidnNpemUiOjE1MSwid2VpZ2h0Ijo2MDIsInZlcnNpb24iOjIsImxvY2t0aW1lIjowLCJ2aW4iOlt7InR4aWQiOiJmM2IwMWVkMDJiMTg5ZDg5NjQ2ZDNhYmRlYzA4ZjJkMjNlMmFkMjA4MzJhZTQ4YmQzZTJhZDE5MGNiOGUxMTlkIiwidm91dCI6MTAsInNjcmlwdFNpZyI6eyJhc20iOiIiLCJoZXgiOiIifSwidHhpbndpdG5lc3MiOlsiZDk5NjA2MDc1NjhkOTNjY2ZjOTViZmEwOGJkYjBhYTZkZWM1OTg3ZjM2ZjlmNGFiZjUzZGMyMmM0Yjg1MzExMTcyZDFkOGFiOTllNWFiNjI0MmQzMzJhODdiMmQxOWMyMDI5NDBmODhmNzYzZGMwNmFjYWE4NTFmODlhMDYxMzIiLCIyMGY4ZmNjZjBmNDQ3N2ZmYjI4NWMyYzc4ZjAyMTJiOTIxNTBkN2E4YmI3MzBlZGQ0ZjY5MjNmZTk2NTZmZjVhYTZhYzAwNjMwMzZmNzI2NDAxMDExODc0NjU3ODc0MmY3MDZjNjE2OTZlM2I2MzY4NjE3MjczNjU3NDNkNzU3NDY2MmQzODAwMzU3YjIyNzAyMjNhMjI2MjcyNjMyZDMyMzAyMjJjMjI2ZjcwMjIzYTIyNmQ2OTZlNzQyMjJjMjI3NDY5NjM2YjIyM2EyMjZkNjU2ZDY1MjIyYzIyNjE2ZDc0MjIzYTIyMzEzMDMwMzAyMjdkNjgiLCJjMTk4MzcxYzEwOGY2NWFjOTNjMmQwODkwMGEwZWI2ZWFjZTkwYTU0NzE4NjgwMWZhMjUyYjQzZTU3ZTdlMjc1NTEiXSwic2VxdWVuY2UiOjQyOTQ5NjcyOTV9XSwidm91dCI6W3sidmFsdWUiOjAuMDAwMDA1NDYsIm4iOjAsInNjcmlwdFB1YktleSI6eyJhc20iOiIxIDJkZTg1MjE0OGVkMzE2ODg1NTY0YzQ0NjJiZDBmZDAwNjY2ZDNlMDc5ZDg1MjAxOWU0MWY5MDIxMjA4NzhkZDUiLCJoZXgiOiI1MTIwMmRlODUyMTQ4ZWQzMTY4ODU1NjRjNDQ2MmJkMGZkMDA2NjZkM2UwNzlkODUyMDE5ZTQxZjkwMjEyMDg3OGRkNSIsInR5cGUiOiJ3aXRuZXNzX3YxX3RhcHJvb3QifX1dfSx7ImhleCI6IjAyMDAwMDAwMDAwMTAxOWQxMThlY2I5MGQxMmEzZWJkNDhhZTMyMDhkMjJhM2VkMmYyMDhlY2JkM2E2ZDY0ODk5ZDE4MmJkMDFlYjBmMzBlMDAwMDAwMDBmZmZmZmZmZjAxMjIwMjAwMDAwMDAwMDAwMDIyNTEyMDJkZTg1MjE0OGVkMzE2ODg1NTY0YzQ0NjJiZDBmZDAwNjY2ZDNlMDc5ZDg1MjAxOWU0MWY5MDIxMjA4NzhkZDUwMzQwNTAxNGU0ZjQ2Y2FkY2EwMTY4Y2U0NGMxMmVlZTllYTJhYzM1MDJlYzViMDJlMTAyMGE2ZTM5NmNkOGMzY2JjM2YzNDkxMDIyOGQzNTkwNTI1Nzk3NmYyNjJjMmMxM2EzYTYwZWQ2ZDExMjQ0MzQ0NTNhZTQ5NDc2ZDExZDhiMzk3YjIwMTg5MjMyNjAyZWZiNTE0ZGQ3ODhiMTYyYWJiZDhiMTI3MzY1YTBmNGZhZTljMjU3ZDc0MTdjMzJhMzYyMDJlNWFjMDA2MzAzNmY3MjY0MDEwMTE4NzQ2NTc4NzQyZjcwNmM2MTY5NmUzYjYzNjg2MTcyNzM2NTc0M2Q3NTc0NjYyZDM4MDAzNTdiMjI3MDIyM2EyMjYyNzI2MzJkMzIzMDIyMmMyMjZmNzAyMjNhMjI2ZDY5NmU3NDIyMmMyMjc0Njk2MzZiMjIzYTIyNmQ2NTZkNjUyMjJjMjI2MTZkNzQyMjNhMjIzMTMwMzAzMDIyN2Q2ODIxYzA5ODM3MWMxMDhmNjVhYzkzYzJkMDg5MDBhMGViNmVhY2U5MGE1NDcxODY4MDFmYTI1MmI0M2U1N2U3ZTI3NTUxMDAwMDAwMDAiLCJ0eGlkIjoiZmE1MjJlNDVlNDFmMDhjYzlmNDU3ZGE3ODg1MWU2ZDFiODkwNWFkMTFiMTdhODRjOTA0ZTRmOGQxZDUxNGE5MyIsImhhc2giOiIwNmVjY2NhMWZiNzM1ODAwNmM3MDYzMzc2YjU5MmUyNDE5MDE4MGFiNmFhZGY4MDNjZDc0MTNjMjg0ZmNjMmM5Iiwic2l6ZSI6MzIwLCJ2c2l6ZSI6MTUxLCJ3ZWlnaHQiOjYwMiwidmVyc2lvbiI6MiwibG9ja3RpbWUiOjAsInZpbiI6W3sidHhpZCI6ImYzYjAxZWQwMmIxODlkODk2NDZkM2FiZGVjMDhmMmQyM2UyYWQyMDgzMmFlNDhiZDNlMmFkMTkwY2I4ZTExOWQiLCJ2b3V0IjoxNCwic2NyaXB0U2lnIjp7ImFzbSI6IiIsImhleCI6IiJ9LCJ0eGlud2l0bmVzcyI6WyI1MDE0ZTRmNDZjYWRjYTAxNjhjZTQ0YzEyZWVlOWVhMmFjMzUwMmVjNWIwMmUxMDIwYTZlMzk2Y2Q4YzNjYmMzZjM0OTEwMjI4ZDM1OTA1MjU3OTc2ZjI2MmMyYzEzYTNhNjBlZDZkMTEyNDQzNDQ1M2FlNDk0NzZkMTFkOGIzOSIsIjIwMTg5MjMyNjAyZWZiNTE0ZGQ3ODhiMTYyYWJiZDhiMTI3MzY1YTBmNGZhZTljMjU3ZDc0MTdjMzJhMzYyMDJlNWFjMDA2MzAzNmY3MjY0MDEwMTE4NzQ2NTc4NzQyZjcwNmM2MTY5NmUzYjYzNjg2MTcyNzM2NTc0M2Q3NTc0NjYyZDM4MDAzNTdiMjI3MDIyM2EyMjYyNzI2MzJkMzIzMDIyMmMyMjZmNzAyMjNhMjI2ZDY5NmU3NDIyMmMyMjc0Njk2MzZiMjIzYTIyNmQ2NTZkNjUyMjJjMjI2MTZkNzQyMjNhMjIzMTMwMzAzMDIyN2Q2OCIsImMwOTgzNzFjMTA4ZjY1YWM5M2MyZDA4OTAwYTBlYjZlYWNlOTBhNTQ3MTg2ODAxZmEyNTJiNDNlNTdlN2UyNzU1MSJdLCJzZXF1ZW5jZSI6NDI5NDk2NzI5NX1dLCJ2b3V0IjpbeyJ2YWx1ZSI6MC4wMDAwMDU0NiwibiI6MCwic2NyaXB0UHViS2V5Ijp7ImFzbSI6IjEgMmRlODUyMTQ4ZWQzMTY4ODU1NjRjNDQ2MmJkMGZkMDA2NjZkM2UwNzlkODUyMDE5ZTQxZjkwMjEyMDg3OGRkNSIsImhleCI6IjUxMjAyZGU4NTIxNDhlZDMxNjg4NTU2NGM0NDYyYmQwZmQwMDY2NmQzZTA3OWQ4NTIwMTllNDFmOTAyMTIwODc4ZGQ1IiwidHlwZSI6IndpdG5lc3NfdjFfdGFwcm9vdCJ9fV19LHsiaGV4IjoiMDIwMDAwMDAwMWU0NGNhMjMxOGEwZTRiYzVjMGNlYzM1NzFkOWIyODg0NDg4YmQzMTZmM2RlMWIwMzYyZjQ3MmNiYTY4M2Y1MjgwMDAwMDAwMDZhNDczMDQ0MDIyMDRkMmQ4NzJlNjZiYTRjNTZiZDhmZWUxMDIxYjUzZmZlNjJiMGYyYmY2MmIxZmM3ZDdkMmE5M2U3MDE2YjBhNjIwMjIwM2Q1M2NjMWE1YmU3MGJkNjVmNWZmMzI1ZGUzY2Y4YWVlOTRhN2EzMzI3YTJlMDk0YzYwODA3ODRkYTFlYzcwZjAxMjEwM2E0Mjc2MDIxZDQ2ZDRkMzhlNDU1NjFlOTljMTFjMTg0ZDU4YTc3YWE0NmIwN2RiNWJhOWE4MzE4ZGE2ODEyYTFmZGZmZmZmZjAyN2UyNDAwMDAwMDAwMDAwMDE2MDAxNGEyNjc3MDc5NDVlZGI3OWVhNGRlNGQwZDk2N2UyMzRmNjhmYjU0ZGUwZjE3MDEwMDAwMDAwMDAwMTYwMDE0YzM1MTY1MjRkZjcxOWZhNDA3YjczMWNjNTI5YTg4ZWE2ZmNjMzM5ODExM2IyNjAwIiwidHhpZCI6IjVlZTIzMzIyYTAwZDQzMDVlMzc4MGZhMjBiMGFlZGRhYmZhNTA2ZmFjYzc2NjM4NTljOWJiNWFiNGJlMmY0OTgiLCJoYXNoIjoiNWVlMjMzMjJhMDBkNDMwNWUzNzgwZmEyMGIwYWVkZGFiZmE1MDZmYWNjNzY2Mzg1OWM5YmI1YWI0YmUyZjQ5OCIsInNpemUiOjIxOSwidnNpemUiOjIxOSwid2VpZ2h0Ijo4NzYsInZlcnNpb24iOjIsImxvY2t0aW1lIjoyNTA1NDg5LCJ2aW4iOlt7InR4aWQiOiIyOGY1ODNhNmNiNzJmNDYyMDMxYmRlZjMxNmQzOGI0ODg0Mjg5YjFkNTdjM2NlYzBjNTRiMGU4YTMxYTI0Y2U0Iiwidm91dCI6MCwic2NyaXB0U2lnIjp7ImFzbSI6IjMwNDQwMjIwNGQyZDg3MmU2NmJhNGM1NmJkOGZlZTEwMjFiNTNmZmU2MmIwZjJiZjYyYjFmYzdkN2QyYTkzZTcwMTZiMGE2MjAyMjAzZDUzY2MxYTViZTcwYmQ2NWY1ZmYzMjVkZTNjZjhhZWU5NGE3YTMzMjdhMmUwOTRjNjA4MDc4NGRhMWVjNzBmW0FMTF0gMDNhNDI3NjAyMWQ0NmQ0ZDM4ZTQ1NTYxZTk5YzExYzE4NGQ1OGE3N2FhNDZiMDdkYjViYTlhODMxOGRhNjgxMmExIiwiaGV4IjoiNDczMDQ0MDIyMDRkMmQ4NzJlNjZiYTRjNTZiZDhmZWUxMDIxYjUzZmZlNjJiMGYyYmY2MmIxZmM3ZDdkMmE5M2U3MDE2YjBhNjIwMjIwM2Q1M2NjMWE1YmU3MGJkNjVmNWZmMzI1ZGUzY2Y4YWVlOTRhN2EzMzI3YTJlMDk0YzYwODA3ODRkYTFlYzcwZjAxMjEwM2E0Mjc2MDIxZDQ2ZDRkMzhlNDU1NjFlOTljMTFjMTg0ZDU4YTc3YWE0NmIwN2RiNWJhOWE4MzE4ZGE2ODEyYTEifSwic2VxdWVuY2UiOjQyOTQ5NjcyOTN9XSwidm91dCI6W3sidmFsdWUiOjAuMDAwMDkzNDIsIm4iOjAsInNjcmlwdFB1YktleSI6eyJhc20iOiIwIGEyNjc3MDc5NDVlZGI3OWVhNGRlNGQwZDk2N2UyMzRmNjhmYjU0ZGUiLCJoZXgiOiIwMDE0YTI2NzcwNzk0NWVkYjc5ZWE0ZGU0ZDBkOTY3ZTIzNGY2OGZiNTRkZSIsInR5cGUiOiJ3aXRuZXNzX3YwX2tleWhhc2gifX0seyJ2YWx1ZSI6MC4wMDA3MTQzOSwibiI6MSwic2NyaXB0UHViS2V5Ijp7ImFzbSI6IjAgYzM1MTY1MjRkZjcxOWZhNDA3YjczMWNjNTI5YTg4ZWE2ZmNjMzM5OCIsImhleCI6IjAwMTRjMzUxNjUyNGRmNzE5ZmE0MDdiNzMxY2M1MjlhODhlYTZmY2MzMzk4IiwidHlwZSI6IndpdG5lc3NfdjBfa2V5aGFzaCJ9fV19LHsiaGV4IjoiMDIwMDAwMDAwMDAxMDFjM2RiMWI2MzM1MmJhOGVmNmY2NWNiMTE3YWE0YjEwN2RjZjBlYWZmYmViNzg5Njg5NWI2MzNmZjAzNmIwM2MwMDEwMDAwMDAwMGZkZmZmZmZmMDJlODAzMDAwMDAwMDAwMDAwMjI1MTIwMGEzYzgyOWExNmY2NDI0OGRlN2EwYmQxNzQ1ZTQyZmMwNjdkNzZhY2YzZGZmOGRhNjg2OTM0NzQ2YjYyOGEwNjAyNTYwNjAwMDAwMDAwMDAxNjAwMTQxN2U1NTg0NmEyYWNkNmE3Nzg0YzkxZjI2NjlmMTdmZWRmZDc0Mzk3MDI0NzMwNDQwMjIwNmY1MDU4YzM4ZGM3MDY0NDM0ZDM2MmI5MDMzZjQzMGIwMWYzM2Q2ZjZlMWQ4OWEyODdlMWE5ZGMxMWJkNmEyZDAyMjA3ZTdhNzQ2MDkzMzFjOGVkZDhhMDNjMjNhNWNmNmUwZjUwODAyOGQ1MTUxN2IyMjUxYTIyNDk1MDQ0NzQ1NmFiMDEyMTAyNjgwYTE5YWVhMmRlYmU5NzhlMjBhNzg2YzM3MTk4Njk1ZDJlNmU1ODA4Y2Q4MWI2MDExZWEyMWEwODdjMDFjMDExM2IyNjAwIiwidHhpZCI6IjQ0NWU0N2NhMmY2OWE3OGIwY2FlZDAzZDg2MTY5NWRhOTQzZGQ3ZGE4MjEzN2I1MDg3YTljNWI2M2UwOWY0OTkiLCJoYXNoIjoiMzNhN2VlMjEzM2FlNTk1NjRiMjI1Njk2Y2Y2MmFkYjg0Yzg3YjAxZDE1N2YxNWRjYTkwYWU0NWQ2ODJkMzgwZiIsInNpemUiOjIzNCwidnNpemUiOjE1Mywid2VpZ2h0Ijo2MDksInZlcnNpb24iOjIsImxvY2t0aW1lIjoyNTA1NDg5LCJ2aW4iOlt7InR4aWQiOiJjMDAzNmIwM2ZmMzNiNjk1Njg4OWI3YmVmZmVhZjBkYzA3YjFhNDdhMTFjYjY1NmZlZmE4MmIzNTYzMWJkYmMzIiwidm91dCI6MSwic2NyaXB0U2lnIjp7ImFzbSI6IiIsImhleCI6IiJ9LCJ0eGlud2l0bmVzcyI6WyIzMDQ0MDIyMDZmNTA1OGMzOGRjNzA2NDQzNGQzNjJiOTAzM2Y0MzBiMDFmMzNkNmY2ZTFkODlhMjg3ZTFhOWRjMTFiZDZhMmQwMjIwN2U3YTc0NjA5MzMxYzhlZGQ4YTAzYzIzYTVjZjZlMGY1MDgwMjhkNTE1MTdiMjI1MWEyMjQ5NTA0NDc0NTZhYjAxIiwiMDI2ODBhMTlhZWEyZGViZTk3OGUyMGE3ODZjMzcxOTg2OTVkMmU2ZTU4MDhjZDgxYjYwMTFlYTIxYTA4N2MwMWMwIl0sInNlcXVlbmNlIjo0Mjk0OTY3MjkzfV0sInZvdXQiOlt7InZhbHVlIjowLjAwMDAxLCJuIjowLCJzY3JpcHRQdWJLZXkiOnsiYXNtIjoiMSAwYTNjODI5YTE2ZjY0MjQ4ZGU3YTBiZDE3NDVlNDJmYzA2N2Q3NmFjZjNkZmY4ZGE2ODY5MzQ3NDZiNjI4YTA2IiwiaGV4IjoiNTEyMDBhM2M4MjlhMTZmNjQyNDhkZTdhMGJkMTc0NWU0MmZjMDY3ZDc2YWNmM2RmZjhkYTY4NjkzNDc0NmI2MjhhMDYiLCJ0eXBlIjoid2l0bmVzc192MV90YXByb290In19LHsidmFsdWUiOjAuMDA0MTUyMzQsIm4iOjEsInNjcmlwdFB1YktleSI6eyJhc20iOiIwIDE3ZTU1ODQ2YTJhY2Q2YTc3ODRjOTFmMjY2OWYxN2ZlZGZkNzQzOTciLCJoZXgiOiIwMDE0MTdlNTU4NDZhMmFjZDZhNzc4NGM5MWYyNjY5ZjE3ZmVkZmQ3NDM5NyIsInR5cGUiOiJ3aXRuZXNzX3YwX2tleWhhc2gifX1dfSx7ImhleCI6IjAyMDAwMDAwMDAwMTAxOWQxMThlY2I5MGQxMmEzZWJkNDhhZTMyMDhkMjJhM2VkMmYyMDhlY2JkM2E2ZDY0ODk5ZDE4MmJkMDFlYjBmMzA5MDAwMDAwMDBmZmZmZmZmZjAxMjIwMjAwMDAwMDAwMDAwMDIyNTEyMDJkZTg1MjE0OGVkMzE2ODg1NTY0YzQ0NjJiZDBmZDAwNjY2ZDNlMDc5ZDg1MjAxOWU0MWY5MDIxMjA4NzhkZDUwMzQwZjRiMGIwNDRiMjRhODg0YjU3MTFlMzU0MWYzOTM2M2ExMTk1ODU2MDgzMWIzMjAwNmU2Y2JjMjllOTFmNDRkOWQyZWEzNGI5MTU2Yjc0M2Q5NjhmZTdjYjBkOThjZGExZmQ0ZjFhMDIzOWJjZWYwODgzZmJjNTg4MjE5MmUzNDU3YjIwYjk4YTcyZWM1MDkxNWNlYTYwODQyNzE2ODBmMWNlOWFmZTY5ZjdhMDlmZjk4NDFiZmM1YzE0MWY5OGEzYWUyZWFjMDA2MzAzNmY3MjY0MDEwMTE4NzQ2NTc4NzQyZjcwNmM2MTY5NmUzYjYzNjg2MTcyNzM2NTc0M2Q3NTc0NjYyZDM4MDAzNTdiMjI3MDIyM2EyMjYyNzI2MzJkMzIzMDIyMmMyMjZmNzAyMjNhMjI2ZDY5NmU3NDIyMmMyMjc0Njk2MzZiMjIzYTIyNmQ2NTZkNjUyMjJjMjI2MTZkNzQyMjNhMjIzMTMwMzAzMDIyN2Q2ODIxYzE5ODM3MWMxMDhmNjVhYzkzYzJkMDg5MDBhMGViNmVhY2U5MGE1NDcxODY4MDFmYTI1MmI0M2U1N2U3ZTI3NTUxMDAwMDAwMDAiLCJ0eGlkIjoiMTFhNTQxYmE0MWVlNGQxZjVkZmQ0YThjMTcyZDU4YTFhZDc4N2Q2N2IyMGUwYzQ3MDY3NmNiNDAyYWZmYTQ5ZCIsImhhc2giOiI2NmMwOTI4YjE2MzQwODE0ZjEyZDExOTk1ODhmOTVmMDIyYTIxMDFkNmI2M2Y5MmFkYzM3M2FhOTY2MjE1YzNiIiwic2l6ZSI6MzIwLCJ2c2l6ZSI6MTUxLCJ3ZWlnaHQiOjYwMiwidmVyc2lvbiI6MiwibG9ja3RpbWUiOjAsInZpbiI6W3sidHhpZCI6ImYzYjAxZWQwMmIxODlkODk2NDZkM2FiZGVjMDhmMmQyM2UyYWQyMDgzMmFlNDhiZDNlMmFkMTkwY2I4ZTExOWQiLCJ2b3V0Ijo5LCJzY3JpcHRTaWciOnsiYXNtIjoiIiwiaGV4IjoiIn0sInR4aW53aXRuZXNzIjpbImY0YjBiMDQ0YjI0YTg4NGI1NzExZTM1NDFmMzkzNjNhMTE5NTg1NjA4MzFiMzIwMDZlNmNiYzI5ZTkxZjQ0ZDlkMmVhMzRiOTE1NmI3NDNkOTY4ZmU3Y2IwZDk4Y2RhMWZkNGYxYTAyMzliY2VmMDg4M2ZiYzU4ODIxOTJlMzQ1IiwiMjBiOThhNzJlYzUwOTE1Y2VhNjA4NDI3MTY4MGYxY2U5YWZlNjlmN2EwOWZmOTg0MWJmYzVjMTQxZjk4YTNhZTJlYWMwMDYzMDM2ZjcyNjQwMTAxMTg3NDY1Nzg3NDJmNzA2YzYxNjk2ZTNiNjM2ODYxNzI3MzY1NzQzZDc1NzQ2NjJkMzgwMDM1N2IyMjcwMjIzYTIyNjI3MjYzMmQzMjMwMjIyYzIyNmY3MDIyM2EyMjZkNjk2ZTc0MjIyYzIyNzQ2OTYzNmIyMjNhMjI2ZDY1NmQ2NTIyMmMyMjYxNmQ3NDIyM2EyMjMxMzAzMDMwMjI3ZDY4IiwiYzE5ODM3MWMxMDhmNjVhYzkzYzJkMDg5MDBhMGViNmVhY2U5MGE1NDcxODY4MDFmYTI1MmI0M2U1N2U3ZTI3NTUxIl0sInNlcXVlbmNlIjo0Mjk0OTY3Mjk1fV0sInZvdXQiOlt7InZhbHVlIjowLjAwMDAwNTQ2LCJuIjowLCJzY3JpcHRQdWJLZXkiOnsiYXNtIjoiMSAyZGU4NTIxNDhlZDMxNjg4NTU2NGM0NDYyYmQwZmQwMDY2NmQzZTA3OWQ4NTIwMTllNDFmOTAyMTIwODc4ZGQ1IiwiaGV4IjoiNTEyMDJkZTg1MjE0OGVkMzE2ODg1NTY0YzQ0NjJiZDBmZDAwNjY2ZDNlMDc5ZDg1MjAxOWU0MWY5MDIxMjA4NzhkZDUiLCJ0eXBlIjoid2l0bmVzc192MV90YXByb290In19XX0seyJoZXgiOiIwMjAwMDAwMDAwMDEwMTNmN2ViYWVjMDA2NDYyMDE0YjUwOGUwNjYyMzM3ZmIxY2U1ODgxNTk5MDA2ZjA1NzI2Mjk5NjYxZTgzYTQ1OWIwMDAwMDAwMDAwZmRmZmZmZmYwMjIyMDIwMDAwMDAwMDAwMDAxNjAwMTQyNjZiNWNiYTdlZmMyZWYyZGM5N2FlMWRlZjZjMzkzYmU0ZTM0ZTFmMDUwNTAwMDAwMDAwMDAwMDE2MDAxNGJkZmQ2ZTBlODg5Y2U1N2M5YWRiZmU4MTdiMjY5Nzg2Y2EwODIxZDMwMzQwOTAyM2U2NDEzODJiZGRjZTRmMGEzMmNhYTYyOTA5ODY3M2M4Y2EwOGRhOGNlMDA2MmJhNzg4ZTQ0YzUzZGU1MzlmZjUwNjY4YzhhMmI4ZWViYTYxMWE2OTQ4NjIxYWZlZGVjODdjZDY1NDdlZGYzOWRhYTg4MWQ2OTU0NGE4ZWY3ODIwNThlN2Y1MDdiMzc3NGEwZWM5MmUxNzJjMzg5ZWU2N2Q2NTkyNTFiZjczYjAyODg3NmI2ZWY0MjJmYWRhYzg4ZWFjMDA2MzAzNmY3MjY0MDEwMTE4NzQ2NTc4NzQyZjcwNmM2MTY5NmUzYjYzNjg2MTcyNzM2NTc0M2Q3NTc0NjYyZDM4MDAzMjdiMjI3MDIyM2EyMjYyNzI2MzJkMzIzMDIyMmMyMjZmNzAyMjNhMjI2ZDY5NmU3NDIyMmMyMjc0Njk2MzZiMjIzYTIyNzA3NTZlNmIyMjJjMjI2MTZkNzQyMjNhMjIzMTIyN2Q2ODIxYzFmNzdhMjQ1MzZiZjBkYzliZDFjNGQxZTViOGJjOTkyMDgyM2ZlZDA3YmI4M2FhMTE2MzVjMDM5NDlmZTZmYjk3MDAwMDAwMDAiLCJ0eGlkIjoiNWVmYTJjNjc0YWMxMWZiOTM5YTI3ZjcwM2FiZjU3MGZjYTk4NWU5YjRkYzJlODZhN2RhYTA0YjMxZDBmNDk5ZiIsImhhc2giOiJlOWY2OWFmNjYxZGEzNjRkMmYwNGU5ZWE4YTNiYzJlZTc2N2I4MmNiMmUwMmJmZGYyMjU5ZDU1ZjNkMmE5MTU0Iiwic2l6ZSI6MzM2LCJ2c2l6ZSI6MTY5LCJ3ZWlnaHQiOjY3NSwidmVyc2lvbiI6MiwibG9ja3RpbWUiOjAsInZpbiI6W3sidHhpZCI6IjliNDUzYWU4NjE5NjI5MjY1N2YwMDY5MDU5ODE1OGNlYjE3ZjMzNjIwNjhlNTA0YjAxNjI2NDAwZWNiYTdlM2YiLCJ2b3V0IjowLCJzY3JpcHRTaWciOnsiYXNtIjoiIiwiaGV4IjoiIn0sInR4aW53aXRuZXNzIjpbIjkwMjNlNjQxMzgyYmRkY2U0ZjBhMzJjYWE2MjkwOTg2NzNjOGNhMDhkYThjZTAwNjJiYTc4OGU0NGM1M2RlNTM5ZmY1MDY2OGM4YTJiOGVlYmE2MTFhNjk0ODYyMWFmZWRlYzg3Y2Q2NTQ3ZWRmMzlkYWE4ODFkNjk1NDRhOGVmIiwiMjA1OGU3ZjUwN2IzNzc0YTBlYzkyZTE3MmMzODllZTY3ZDY1OTI1MWJmNzNiMDI4ODc2YjZlZjQyMmZhZGFjODhlYWMwMDYzMDM2ZjcyNjQwMTAxMTg3NDY1Nzg3NDJmNzA2YzYxNjk2ZTNiNjM2ODYxNzI3MzY1NzQzZDc1NzQ2NjJkMzgwMDMyN2IyMjcwMjIzYTIyNjI3MjYzMmQzMjMwMjIyYzIyNmY3MDIyM2EyMjZkNjk2ZTc0MjIyYzIyNzQ2OTYzNmIyMjNhMjI3MDc1NmU2YjIyMmMyMjYxNmQ3NDIyM2EyMjMxMjI3ZDY4IiwiYzFmNzdhMjQ1MzZiZjBkYzliZDFjNGQxZTViOGJjOTkyMDgyM2ZlZDA3YmI4M2FhMTE2MzVjMDM5NDlmZTZmYjk3Il0sInNlcXVlbmNlIjo0Mjk0OTY3MjkzfV0sInZvdXQiOlt7InZhbHVlIjowLjAwMDAwNTQ2LCJuIjowLCJzY3JpcHRQdWJLZXkiOnsiYXNtIjoiMCAyNjZiNWNiYTdlZmMyZWYyZGM5N2FlMWRlZjZjMzkzYmU0ZTM0ZTFmIiwiaGV4IjoiMDAxNDI2NmI1Y2JhN2VmYzJlZjJkYzk3YWUxZGVmNmMzOTNiZTRlMzRlMWYiLCJ0eXBlIjoid2l0bmVzc192MF9rZXloYXNoIn19LHsidmFsdWUiOjAuMDAwMDEyODUsIm4iOjEsInNjcmlwdFB1YktleSI6eyJhc20iOiIwIGJkZmQ2ZTBlODg5Y2U1N2M5YWRiZmU4MTdiMjY5Nzg2Y2EwODIxZDMiLCJoZXgiOiIwMDE0YmRmZDZlMGU4ODljZTU3YzlhZGJmZTgxN2IyNjk3ODZjYTA4MjFkMyIsInR5cGUiOiJ3aXRuZXNzX3YwX2tleWhhc2gifX1dfSx7ImhleCI6IjAyMDAwMDAwMDAwMTAxOWQxMThlY2I5MGQxMmEzZWJkNDhhZTMyMDhkMjJhM2VkMmYyMDhlY2JkM2E2ZDY0ODk5ZDE4MmJkMDFlYjBmMzExMDAwMDAwMDBmZmZmZmZmZjAxMjIwMjAwMDAwMDAwMDAwMDIyNTEyMDJkZTg1MjE0OGVkMzE2ODg1NTY0YzQ0NjJiZDBmZDAwNjY2ZDNlMDc5ZDg1MjAxOWU0MWY5MDIxMjA4NzhkZDUwMzQwOTc2YjcwMWJiNDI1ZmJjNGM2NjdjMzkyYWJlZDc0NDQyMzZhNmU4Yjg5NWE4MmExNmEyZTUyMDMxZmJjOGJlNjgyOTg5MDVjMzMyNTYxZjM1ZDIwNWE3OTQ0MGNlZWFjZjQ3YzgyNDdiNGMwYjlkMzgyNTA0MDg2ZGQ4YjBiMDM3YjIwMTcwYTFkMTE1NjBhODliYmI5ZjQ3OWYwNjAxNzg3NjcxM2QyYWJkNjlkOGUzMGY1MjYzODY4MzAzOTJlYjlhZmFjMDA2MzAzNmY3MjY0MDEwMTE4NzQ2NTc4NzQyZjcwNmM2MTY5NmUzYjYzNjg2MTcyNzM2NTc0M2Q3NTc0NjYyZDM4MDAzNTdiMjI3MDIyM2EyMjYyNzI2MzJkMzIzMDIyMmMyMjZmNzAyMjNhMjI2ZDY5NmU3NDIyMmMyMjc0Njk2MzZiMjIzYTIyNmQ2NTZkNjUyMjJjMjI2MTZkNzQyMjNhMjIzMTMwMzAzMDIyN2Q2ODIxYzA5ODM3MWMxMDhmNjVhYzkzYzJkMDg5MDBhMGViNmVhY2U5MGE1NDcxODY4MDFmYTI1MmI0M2U1N2U3ZTI3NTUxMDAwMDAwMDAiLCJ0eGlkIjoiMWE3MzZmZmUwOWY4NzgyYzY3NzU1NTk4MjY0OGRiOTM2MzEwZDg4YzFjZmY5MDA5YTdhYTQyYWExMDMyNmJhMSIsImhhc2giOiJmYzYwYmI3OTQ0ZGNlNzhkMDYwOWU1MDQxNjhkYjFlY2VhMmI0MDJlZWNjMzJlMzk5YTg5MDgyM2Y4MTE5ODc5Iiwic2l6ZSI6MzIwLCJ2c2l6ZSI6MTUxLCJ3ZWlnaHQiOjYwMiwidmVyc2lvbiI6MiwibG9ja3RpbWUiOjAsInZpbiI6W3sidHhpZCI6ImYzYjAxZWQwMmIxODlkODk2NDZkM2FiZGVjMDhmMmQyM2UyYWQyMDgzMmFlNDhiZDNlMmFkMTkwY2I4ZTExOWQiLCJ2b3V0IjoxNywic2NyaXB0U2lnIjp7ImFzbSI6IiIsImhleCI6IiJ9LCJ0eGlud2l0bmVzcyI6WyI5NzZiNzAxYmI0MjVmYmM0YzY2N2MzOTJhYmVkNzQ0NDIzNmE2ZThiODk1YTgyYTE2YTJlNTIwMzFmYmM4YmU2ODI5ODkwNWMzMzI1NjFmMzVkMjA1YTc5NDQwY2VlYWNmNDdjODI0N2I0YzBiOWQzODI1MDQwODZkZDhiMGIwMyIsIjIwMTcwYTFkMTE1NjBhODliYmI5ZjQ3OWYwNjAxNzg3NjcxM2QyYWJkNjlkOGUzMGY1MjYzODY4MzAzOTJlYjlhZmFjMDA2MzAzNmY3MjY0MDEwMTE4NzQ2NTc4NzQyZjcwNmM2MTY5NmUzYjYzNjg2MTcyNzM2NTc0M2Q3NTc0NjYyZDM4MDAzNTdiMjI3MDIyM2EyMjYyNzI2MzJkMzIzMDIyMmMyMjZmNzAyMjNhMjI2ZDY5NmU3NDIyMmMyMjc0Njk2MzZiMjIzYTIyNmQ2NTZkNjUyMjJjMjI2MTZkNzQyMjNhMjIzMTMwMzAzMDIyN2Q2OCIsImMwOTgzNzFjMTA4ZjY1YWM5M2MyZDA4OTAwYTBlYjZlYWNlOTBhNTQ3MTg2ODAxZmEyNTJiNDNlNTdlN2UyNzU1MSJdLCJzZXF1ZW5jZSI6NDI5NDk2NzI5NX1dLCJ2b3V0IjpbeyJ2YWx1ZSI6MC4wMDAwMDU0NiwibiI6MCwic2NyaXB0UHViS2V5Ijp7ImFzbSI6IjEgMmRlODUyMTQ4ZWQzMTY4ODU1NjRjNDQ2MmJkMGZkMDA2NjZkM2UwNzlkODUyMDE5ZTQxZjkwMjEyMDg3OGRkNSIsImhleCI6IjUxMjAyZGU4NTIxNDhlZDMxNjg4NTU2NGM0NDYyYmQwZmQwMDY2NmQzZTA3OWQ4NTIwMTllNDFmOTAyMTIwODc4ZGQ1IiwidHlwZSI6IndpdG5lc3NfdjFfdGFwcm9vdCJ9fV19LHsiaGV4IjoiMDIwMDAwMDAwMDAxMDE5NTQyMmRkNWY4YTExZDg2NzQ0N2YwMDVkMDVkOTI1OWFkZjU4ZmZjYTE3MzYzMmZmNGNjYjk5NmM1NTdkZWNkMGUwMDAwMDAwMGZmZmZmZmZmMDEyMjAyMDAwMDAwMDAwMDAwMjI1MTIwNDdlYjY5ZTVlODQwNmNkMjg3NWEzOWIyYmQ4YmM1YmIzZDhhMzdhOTg4ODVmMjgyZTc4OGMxNjE4N2FmYjFlZTAzNDA0ZTM1MGEwZDEwZjlmNTU4MjU1MmQ0NWZlNmE5MjE3ZWZmNzI0ZmVmMmVkNDY5NDdiNmY4NzY2ZmVhOWU0YzJjMDE5YTFkODMxNjFlNmE5MDAxYTY1MjdiNDAzZTVhM2U0MjlmODNhOWZhN2YyZjU4NTM3ZmVmZjhjZGYxODdkMjdiMjBmZjg0YmU1ZTkwMGY4MGI5MmY5MDk3YmVhMTBkNmNjMGM4ZDgyMWUyNmI1NWUzYzc5OTJjNGMwNDM5ODJmM2VmYWMwMDYzMDM2ZjcyNjQwMTAxMTg3NDY1Nzg3NDJmNzA2YzYxNjk2ZTNiNjM2ODYxNzI3MzY1NzQzZDc1NzQ2NjJkMzgwMDM1N2IyMjcwMjIzYTIyNjI3MjYzMmQzMjMwMjIyYzIyNmY3MDIyM2EyMjZkNjk2ZTc0MjIyYzIyNzQ2OTYzNmIyMjNhMjI1NTUzNDQ1NDIyMmMyMjYxNmQ3NDIyM2EyMjMxMzAzMDMwMjI3ZDY4MjFjMTMwYzA1ZGJlOWZjZmNiM2M2ZDYzYjhjNTRhNThiN2MzNDM4MDQ2ZjVkMjc1MzBlMzM2MTViOGMwZTM0NWRhYmEwMDAwMDAwMCIsInR4aWQiOiJlNWRlZThjMjRiZTY4MTNhZjA1ZTAyNjVhYmM2N2RhOWVmNTFiOWI0YjA3OGNkZjVkNjQ1MDEzOGQwZGI1Y2FkIiwiaGFzaCI6Ijg2N2JjZTllMmJhZDczNTRhYWFiNTk0M2QxMjA5MzI3MGQ5ZDAyYTFkODk3YjQ4MTdhY2RhYmU4ZGY1YTdjODgiLCJzaXplIjozMjAsInZzaXplIjoxNTEsIndlaWdodCI6NjAyLCJ2ZXJzaW9uIjoyLCJsb2NrdGltZSI6MCwidmluIjpbeyJ0eGlkIjoiY2RkZTU3YzU5NmI5Y2NmNDJmNjM3M2ExZmM4ZmY1YWQ1OTkyNWRkMDA1ZjA0Nzc0ODYxZGExZjhkNTJkNDI5NSIsInZvdXQiOjE0LCJzY3JpcHRTaWciOnsiYXNtIjoiIiwiaGV4IjoiIn0sInR4aW53aXRuZXNzIjpbIjRlMzUwYTBkMTBmOWY1NTgyNTUyZDQ1ZmU2YTkyMTdlZmY3MjRmZWYyZWQ0Njk0N2I2Zjg3NjZmZWE5ZTRjMmMwMTlhMWQ4MzE2MWU2YTkwMDFhNjUyN2I0MDNlNWEzZTQyOWY4M2E5ZmE3ZjJmNTg1MzdmZWZmOGNkZjE4N2QyIiwiMjBmZjg0YmU1ZTkwMGY4MGI5MmY5MDk3YmVhMTBkNmNjMGM4ZDgyMWUyNmI1NWUzYzc5OTJjNGMwNDM5ODJmM2VmYWMwMDYzMDM2ZjcyNjQwMTAxMTg3NDY1Nzg3NDJmNzA2YzYxNjk2ZTNiNjM2ODYxNzI3MzY1NzQzZDc1NzQ2NjJkMzgwMDM1N2IyMjcwMjIzYTIyNjI3MjYzMmQzMjMwMjIyYzIyNmY3MDIyM2EyMjZkNjk2ZTc0MjIyYzIyNzQ2OTYzNmIyMjNhMjI1NTUzNDQ1NDIyMmMyMjYxNmQ3NDIyM2EyMjMxMzAzMDMwMjI3ZDY4IiwiYzEzMGMwNWRiZTlmY2ZjYjNjNmQ2M2I4YzU0YTU4YjdjMzQzODA0NmY1ZDI3NTMwZTMzNjE1YjhjMGUzNDVkYWJhIl0sInNlcXVlbmNlIjo0Mjk0OTY3Mjk1fV0sInZvdXQiOlt7InZhbHVlIjowLjAwMDAwNTQ2LCJuIjowLCJzY3JpcHRQdWJLZXkiOnsiYXNtIjoiMSA0N2ViNjllNWU4NDA2Y2QyODc1YTM5YjJiZDhiYzViYjNkOGEzN2E5ODg4NWYyODJlNzg4YzE2MTg3YWZiMWVlIiwiaGV4IjoiNTEyMDQ3ZWI2OWU1ZTg0MDZjZDI4NzVhMzliMmJkOGJjNWJiM2Q4YTM3YTk4ODg1ZjI4MmU3ODhjMTYxODdhZmIxZWUiLCJ0eXBlIjoid2l0bmVzc192MV90YXByb290In19XX0seyJoZXgiOiIwMjAwMDAwMDAwMDEwMTk1NDIyZGQ1ZjhhMTFkODY3NDQ3ZjAwNWQwNWQ5MjU5YWRmNThmZmNhMTczNjMyZmY0Y2NiOTk2YzU1N2RlY2QwNzAwMDAwMDAwZmZmZmZmZmYwMTIyMDIwMDAwMDAwMDAwMDAyMjUxMjA0N2ViNjllNWU4NDA2Y2QyODc1YTM5YjJiZDhiYzViYjNkOGEzN2E5ODg4NWYyODJlNzg4YzE2MTg3YWZiMWVlMDM0MDQ3Y2Q4ZjdlMjYxODlhNGFkMDVkMjE3NWY0OTUyYWJjNDM0MzFkMjU5ODE1MWIzNDMyOTJjNWE3ZjdhYzdjY2NmMWRiYzBiNTU5YjAxNTZjNTljODUyYWU2NWVjMzc1NDA2Yjc4OTg5MmU0MTVkZDEyODkzODQ2YTM5OTYzNmNjN2IyMGFhNzdjMDc3ZDZiZDI2ZGI3YThjYWY0MjA1OTUyOGVkOWM0ZGM3N2UyODM0ZjA3NmZmMDI0YzUwODI3YmU2OWNhYzAwNjMwMzZmNzI2NDAxMDExODc0NjU3ODc0MmY3MDZjNjE2OTZlM2I2MzY4NjE3MjczNjU3NDNkNzU3NDY2MmQzODAwMzU3YjIyNzAyMjNhMjI2MjcyNjMyZDMyMzAyMjJjMjI2ZjcwMjIzYTIyNmQ2OTZlNzQyMjJjMjI3NDY5NjM2YjIyM2EyMjU1NTM0NDU0MjIyYzIyNjE2ZDc0MjIzYTIyMzEzMDMwMzAyMjdkNjgyMWMwMzBjMDVkYmU5ZmNmY2IzYzZkNjNiOGM1NGE1OGI3YzM0MzgwNDZmNWQyNzUzMGUzMzYxNWI4YzBlMzQ1ZGFiYTAwMDAwMDAwIiwidHhpZCI6ImJmOTI1NWRlYTE2ZGZjZGNiYzVmYzMwMmRhMGNhNTVlZDc4ZDI3ZGE0ODNhYzIyNGZiNDViZmUwMGI2ZDg3YjIiLCJoYXNoIjoiZTg1N2NiZWU3Y2ZmZDg2NTIzNzA3NzQ4NmNmMWY1MGYxMWY2NzYzODIyZGE4YWFlOGYwY2EyYmQ4YjM5NGY0NyIsInNpemUiOjMyMCwidnNpemUiOjE1MSwid2VpZ2h0Ijo2MDIsInZlcnNpb24iOjIsImxvY2t0aW1lIjowLCJ2aW4iOlt7InR4aWQiOiJjZGRlNTdjNTk2YjljY2Y0MmY2MzczYTFmYzhmZjVhZDU5OTI1ZGQwMDVmMDQ3NzQ4NjFkYTFmOGQ1MmQ0Mjk1Iiwidm91dCI6Nywic2NyaXB0U2lnIjp7ImFzbSI6IiIsImhleCI6IiJ9LCJ0eGlud2l0bmVzcyI6WyI0N2NkOGY3ZTI2MTg5YTRhZDA1ZDIxNzVmNDk1MmFiYzQzNDMxZDI1OTgxNTFiMzQzMjkyYzVhN2Y3YWM3Y2NjZjFkYmMwYjU1OWIwMTU2YzU5Yzg1MmFlNjVlYzM3NTQwNmI3ODk4OTJlNDE1ZGQxMjg5Mzg0NmEzOTk2MzZjYyIsIjIwYWE3N2MwNzdkNmJkMjZkYjdhOGNhZjQyMDU5NTI4ZWQ5YzRkYzc3ZTI4MzRmMDc2ZmYwMjRjNTA4MjdiZTY5Y2FjMDA2MzAzNmY3MjY0MDEwMTE4NzQ2NTc4NzQyZjcwNmM2MTY5NmUzYjYzNjg2MTcyNzM2NTc0M2Q3NTc0NjYyZDM4MDAzNTdiMjI3MDIyM2EyMjYyNzI2MzJkMzIzMDIyMmMyMjZmNzAyMjNhMjI2ZDY5NmU3NDIyMmMyMjc0Njk2MzZiMjIzYTIyNTU1MzQ0NTQyMjJjMjI2MTZkNzQyMjNhMjIzMTMwMzAzMDIyN2Q2OCIsImMwMzBjMDVkYmU5ZmNmY2IzYzZkNjNiOGM1NGE1OGI3YzM0MzgwNDZmNWQyNzUzMGUzMzYxNWI4YzBlMzQ1ZGFiYSJdLCJzZXF1ZW5jZSI6NDI5NDk2NzI5NX1dLCJ2b3V0IjpbeyJ2YWx1ZSI6MC4wMDAwMDU0NiwibiI6MCwic2NyaXB0UHViS2V5Ijp7ImFzbSI6IjEgNDdlYjY5ZTVlODQwNmNkMjg3NWEzOWIyYmQ4YmM1YmIzZDhhMzdhOTg4ODVmMjgyZTc4OGMxNjE4N2FmYjFlZSIsImhleCI6IjUxMjA0N2ViNjllNWU4NDA2Y2QyODc1YTM5YjJiZDhiYzViYjNkOGEzN2E5ODg4NWYyODJlNzg4YzE2MTg3YWZiMWVlIiwidHlwZSI6IndpdG5lc3NfdjFfdGFwcm9vdCJ9fV19LHsiaGV4IjoiMDIwMDAwMDAwMDAxMDFlYjAwMWNjNzg0ZmE0MDNiOWI5ODY5OGVhNzJkMTUxZDc2ZDkwNjQyNzk0OWJjZjQ0ZTdmOTZhYThmOGQ1ZjFlMDAwMDAwMDAwMGZkZmZmZmZmMDIyMjAyMDAwMDAwMDAwMDAwMTYwMDE0MjY2YjVjYmE3ZWZjMmVmMmRjOTdhZTFkZWY2YzM5M2JlNGUzNGUxZjA0MDUwMDAwMDAwMDAwMDAxNjAwMTRiZGZkNmUwZTg4OWNlNTdjOWFkYmZlODE3YjI2OTc4NmNhMDgyMWQzMDM0MGM0MzQ3OWFkOTM4OWMwYjJmMTZlMWExZGE2MjUzYTVmYTRhMDQ3NTExNjg1NDI4OGUzY2QyZjgzMWQ3NmNkOWFmZTc3MmJjNzkwNjg0N2MwZWIwZWFhMzAyMzM1NjE3Y2I2MTRlMzczNWNhMTZlNjAyZWUyNGVkNWY0MzE4ZDNkN2IyMDIyYzIyNTY5MDBiMWZhZTlhOWZjZDdmNzJjZGEyZjk2MTBkYjVlYjA1MGY1NzYxNGU0MzkyNTE5ZmUwYjgzNmNhYzAwNjMwMzZmNzI2NDAxMDExODc0NjU3ODc0MmY3MDZjNjE2OTZlM2I2MzY4NjE3MjczNjU3NDNkNzU3NDY2MmQzODAwMzU3YjIyNzAyMjNhMjI2MjcyNjMyZDMyMzAyMjJjMjI2ZjcwMjIzYTIyNmQ2OTZlNzQyMjJjMjI3NDY5NjM2YjIyM2EyMjZkNjU2ZDY1MjIyYzIyNjE2ZDc0MjIzYTIyMzEzMDMwMzAyMjdkNjgyMWMxMTdhZDcyNjEzMDgzNTM0YzNjM2ViZTgxOWQzZTlkOTdkNzBiNTZlYjVjOGUzODkwMjNiNmVmZWM1OThiYmI1ODAwMDAwMDAwIiwidHhpZCI6IjZlNGE3MWIwNjdiMGNkYjAwZjAzYTRkMzZmYzZkMTQzODdkNTVmMzZjM2EzMWRiZGJmYzI1ZjNmZDAzMTA0YjUiLCJoYXNoIjoiZGJmMDA1YzZkMTUxZjM5ZTcxZWQ1ZTFhYzNjODYzYTRmM2EzZGQ1ODg0OWEzM2Y0OGQxOWIzNmJkZGMxNThlYSIsInNpemUiOjMzOSwidnNpemUiOjE3MCwid2VpZ2h0Ijo2NzgsInZlcnNpb24iOjIsImxvY2t0aW1lIjowLCJ2aW4iOlt7InR4aWQiOiIxZTVmOGQ4ZmFhOTY3ZjRlZjRiYzQ5Nzk0MjA2ZDk3NjFkMTUyZGE3OGU2OTk4OWIzYjQwZmE4NGM3MWMwMGViIiwidm91dCI6MCwic2NyaXB0U2lnIjp7ImFzbSI6IiIsImhleCI6IiJ9LCJ0eGlud2l0bmVzcyI6WyJjNDM0NzlhZDkzODljMGIyZjE2ZTFhMWRhNjI1M2E1ZmE0YTA0NzUxMTY4NTQyODhlM2NkMmY4MzFkNzZjZDlhZmU3NzJiYzc5MDY4NDdjMGViMGVhYTMwMjMzNTYxN2NiNjE0ZTM3MzVjYTE2ZTYwMmVlMjRlZDVmNDMxOGQzZCIsIjIwMjJjMjI1NjkwMGIxZmFlOWE5ZmNkN2Y3MmNkYTJmOTYxMGRiNWViMDUwZjU3NjE0ZTQzOTI1MTlmZTBiODM2Y2FjMDA2MzAzNmY3MjY0MDEwMTE4NzQ2NTc4NzQyZjcwNmM2MTY5NmUzYjYzNjg2MTcyNzM2NTc0M2Q3NTc0NjYyZDM4MDAzNTdiMjI3MDIyM2EyMjYyNzI2MzJkMzIzMDIyMmMyMjZmNzAyMjNhMjI2ZDY5NmU3NDIyMmMyMjc0Njk2MzZiMjIzYTIyNmQ2NTZkNjUyMjJjMjI2MTZkNzQyMjNhMjIzMTMwMzAzMDIyN2Q2OCIsImMxMTdhZDcyNjEzMDgzNTM0YzNjM2ViZTgxOWQzZTlkOTdkNzBiNTZlYjVjOGUzODkwMjNiNmVmZWM1OThiYmI1OCJdLCJzZXF1ZW5jZSI6NDI5NDk2NzI5M31dLCJ2b3V0IjpbeyJ2YWx1ZSI6MC4wMDAwMDU0NiwibiI6MCwic2NyaXB0UHViS2V5Ijp7ImFzbSI6IjAgMjY2YjVjYmE3ZWZjMmVmMmRjOTdhZTFkZWY2YzM5M2JlNGUzNGUxZiIsImhleCI6IjAwMTQyNjZiNWNiYTdlZmMyZWYyZGM5N2FlMWRlZjZjMzkzYmU0ZTM0ZTFmIiwidHlwZSI6IndpdG5lc3NfdjBfa2V5aGFzaCJ9fSx7InZhbHVlIjowLjAwMDAxMjg0LCJuIjoxLCJzY3JpcHRQdWJLZXkiOnsiYXNtIjoiMCBiZGZkNmUwZTg4OWNlNTdjOWFkYmZlODE3YjI2OTc4NmNhMDgyMWQzIiwiaGV4IjoiMDAxNGJkZmQ2ZTBlODg5Y2U1N2M5YWRiZmU4MTdiMjY5Nzg2Y2EwODIxZDMiLCJ0eXBlIjoid2l0bmVzc192MF9rZXloYXNoIn19XX0seyJoZXgiOiIwMjAwMDAwMDAwMDEwMTlkMTE4ZWNiOTBkMTJhM2ViZDQ4YWUzMjA4ZDIyYTNlZDJmMjA4ZWNiZDNhNmQ2NDg5OWQxODJiZDAxZWIwZjMwODAwMDAwMDAwZmZmZmZmZmYwMTIyMDIwMDAwMDAwMDAwMDAyMjUxMjAyZGU4NTIxNDhlZDMxNjg4NTU2NGM0NDYyYmQwZmQwMDY2NmQzZTA3OWQ4NTIwMTllNDFmOTAyMTIwODc4ZGQ1MDM0MGFhOTNlY2M2NDJiM2NhY2FjYjIxOTNjZWYwNWYxODMyMTRiNjJkZjk0ZjFhYjYwMTA0ZTdhYzIwOGI4YzlmM2ZlYjJiMTdjYTliOWRiOTFlYTVlOTk4ODQ5MmNlNjUxNTIzZjBmM2FhNTZhYjRmODVlMThmMTM5YTYxZjU1OTZjN2IyMDkyNGNlYzNlZGEyNGFhNDYyNDI0MzQwYzcxZTZhZGY2NjA2NmExNjhmNmJhZTc5ZmQ0MWJkZTExOTNhYjBmZmZhYzAwNjMwMzZmNzI2NDAxMDExODc0NjU3ODc0MmY3MDZjNjE2OTZlM2I2MzY4NjE3MjczNjU3NDNkNzU3NDY2MmQzODAwMzU3YjIyNzAyMjNhMjI2MjcyNjMyZDMyMzAyMjJjMjI2ZjcwMjIzYTIyNmQ2OTZlNzQyMjJjMjI3NDY5NjM2YjIyM2EyMjZkNjU2ZDY1MjIyYzIyNjE2ZDc0MjIzYTIyMzEzMDMwMzAyMjdkNjgyMWMwOTgzNzFjMTA4ZjY1YWM5M2MyZDA4OTAwYTBlYjZlYWNlOTBhNTQ3MTg2ODAxZmEyNTJiNDNlNTdlN2UyNzU1MTAwMDAwMDAwIiwidHhpZCI6ImVlYjg5Zjg2ZmY1NzcyMmYxYzQyM2Y3ZmQ3MTk4ODg1Y2M2OTA1ZWI4Y2FjNGIzMWU0MDJlMWNhYWQ0YmE4YjUiLCJoYXNoIjoiYTlmMGUyYjk0ZDg5ZjVlMmZkNmIxYzFkZmNjYWQ3ZDIxNzU4OGE3YTU0MGJkODU5MTNjNTZjNmFkZjM2OWUxNSIsInNpemUiOjMyMCwidnNpemUiOjE1MSwid2VpZ2h0Ijo2MDIsInZlcnNpb24iOjIsImxvY2t0aW1lIjowLCJ2aW4iOlt7InR4aWQiOiJmM2IwMWVkMDJiMTg5ZDg5NjQ2ZDNhYmRlYzA4ZjJkMjNlMmFkMjA4MzJhZTQ4YmQzZTJhZDE5MGNiOGUxMTlkIiwidm91dCI6OCwic2NyaXB0U2lnIjp7ImFzbSI6IiIsImhleCI6IiJ9LCJ0eGlud2l0bmVzcyI6WyJhYTkzZWNjNjQyYjNjYWNhY2IyMTkzY2VmMDVmMTgzMjE0YjYyZGY5NGYxYWI2MDEwNGU3YWMyMDhiOGM5ZjNmZWIyYjE3Y2E5YjlkYjkxZWE1ZTk5ODg0OTJjZTY1MTUyM2YwZjNhYTU2YWI0Zjg1ZTE4ZjEzOWE2MWY1NTk2YyIsIjIwOTI0Y2VjM2VkYTI0YWE0NjI0MjQzNDBjNzFlNmFkZjY2MDY2YTE2OGY2YmFlNzlmZDQxYmRlMTE5M2FiMGZmZmFjMDA2MzAzNmY3MjY0MDEwMTE4NzQ2NTc4NzQyZjcwNmM2MTY5NmUzYjYzNjg2MTcyNzM2NTc0M2Q3NTc0NjYyZDM4MDAzNTdiMjI3MDIyM2EyMjYyNzI2MzJkMzIzMDIyMmMyMjZmNzAyMjNhMjI2ZDY5NmU3NDIyMmMyMjc0Njk2MzZiMjIzYTIyNmQ2NTZkNjUyMjJjMjI2MTZkNzQyMjNhMjIzMTMwMzAzMDIyN2Q2OCIsImMwOTgzNzFjMTA4ZjY1YWM5M2MyZDA4OTAwYTBlYjZlYWNlOTBhNTQ3MTg2ODAxZmEyNTJiNDNlNTdlN2UyNzU1MSJdLCJzZXF1ZW5jZSI6NDI5NDk2NzI5NX1dLCJ2b3V0IjpbeyJ2YWx1ZSI6MC4wMDAwMDU0NiwibiI6MCwic2NyaXB0UHViS2V5Ijp7ImFzbSI6IjEgMmRlODUyMTQ4ZWQzMTY4ODU1NjRjNDQ2MmJkMGZkMDA2NjZkM2UwNzlkODUyMDE5ZTQxZjkwMjEyMDg3OGRkNSIsImhleCI6IjUxMjAyZGU4NTIxNDhlZDMxNjg4NTU2NGM0NDYyYmQwZmQwMDY2NmQzZTA3OWQ4NTIwMTllNDFmOTAyMTIwODc4ZGQ1IiwidHlwZSI6IndpdG5lc3NfdjFfdGFwcm9vdCJ9fV19LHsiaGV4IjoiMDIwMDAwMDAwMDAxMDE5NTQyMmRkNWY4YTExZDg2NzQ0N2YwMDVkMDVkOTI1OWFkZjU4ZmZjYTE3MzYzMmZmNGNjYjk5NmM1NTdkZWNkMGQwMDAwMDAwMGZmZmZmZmZmMDEyMjAyMDAwMDAwMDAwMDAwMjI1MTIwNDdlYjY5ZTVlODQwNmNkMjg3NWEzOWIyYmQ4YmM1YmIzZDhhMzdhOTg4ODVmMjgyZTc4OGMxNjE4N2FmYjFlZTAzNDAxNzg0MzhmM2QyZmEwMzgyYmYyZjFiZDFkMGNhOGU3ZmIwNmE1YmFiNWEyZWRiMWU3M2EzYzE3NDc5NjRhZWEzOTRmNTk4OTYyZDJjYjc2MTJkOWI5OTU0MTRlZjc4NDdjYThlMmYxZDI0Y2NkNDBlY2Y2Y2Y2NmZiMGNlZTEyZDdiMjBkOTkwYmNiYWUyNjcwZjQ5YjM1NTRiNzQxNjFiYzE3NjQ3YmRlMWNiNWIyZTczNTgxOWYzMWZiMjY4NWJhM2VmYWMwMDYzMDM2ZjcyNjQwMTAxMTg3NDY1Nzg3NDJmNzA2YzYxNjk2ZTNiNjM2ODYxNzI3MzY1NzQzZDc1NzQ2NjJkMzgwMDM1N2IyMjcwMjIzYTIyNjI3MjYzMmQzMjMwMjIyYzIyNmY3MDIyM2EyMjZkNjk2ZTc0MjIyYzIyNzQ2OTYzNmIyMjNhMjI1NTUzNDQ1NDIyMmMyMjYxNmQ3NDIyM2EyMjMxMzAzMDMwMjI3ZDY4MjFjMTMwYzA1ZGJlOWZjZmNiM2M2ZDYzYjhjNTRhNThiN2MzNDM4MDQ2ZjVkMjc1MzBlMzM2MTViOGMwZTM0NWRhYmEwMDAwMDAwMCIsInR4aWQiOiIzZTgyMTAwMzBhYWQxZjg2YzQxYWI0ZDg3OWE1MzA3NzEzYzAxM2MzZmZkMGIzMGVkMjA3ZWYzMzRlZTRjNGI5IiwiaGFzaCI6Ijc2ZGQ5ZTBmZTU2YTIzMjllMTBiMTU4NThlMGZiMDk1YjUxZWY1MDUwNDY3YmZjNjQxOTdiZDJkZWJiZjAzMGIiLCJzaXplIjozMjAsInZzaXplIjoxNTEsIndlaWdodCI6NjAyLCJ2ZXJzaW9uIjoyLCJsb2NrdGltZSI6MCwidmluIjpbeyJ0eGlkIjoiY2RkZTU3YzU5NmI5Y2NmNDJmNjM3M2ExZmM4ZmY1YWQ1OTkyNWRkMDA1ZjA0Nzc0ODYxZGExZjhkNTJkNDI5NSIsInZvdXQiOjEzLCJzY3JpcHRTaWciOnsiYXNtIjoiIiwiaGV4IjoiIn0sInR4aW53aXRuZXNzIjpbIjE3ODQzOGYzZDJmYTAzODJiZjJmMWJkMWQwY2E4ZTdmYjA2YTViYWI1YTJlZGIxZTczYTNjMTc0Nzk2NGFlYTM5NGY1OTg5NjJkMmNiNzYxMmQ5Yjk5NTQxNGVmNzg0N2NhOGUyZjFkMjRjY2Q0MGVjZjZjZjY2ZmIwY2VlMTJkIiwiMjBkOTkwYmNiYWUyNjcwZjQ5YjM1NTRiNzQxNjFiYzE3NjQ3YmRlMWNiNWIyZTczNTgxOWYzMWZiMjY4NWJhM2VmYWMwMDYzMDM2ZjcyNjQwMTAxMTg3NDY1Nzg3NDJmNzA2YzYxNjk2ZTNiNjM2ODYxNzI3MzY1NzQzZDc1NzQ2NjJkMzgwMDM1N2IyMjcwMjIzYTIyNjI3MjYzMmQzMjMwMjIyYzIyNmY3MDIyM2EyMjZkNjk2ZTc0MjIyYzIyNzQ2OTYzNmIyMjNhMjI1NTUzNDQ1NDIyMmMyMjYxNmQ3NDIyM2EyMjMxMzAzMDMwMjI3ZDY4IiwiYzEzMGMwNWRiZTlmY2ZjYjNjNmQ2M2I4YzU0YTU4YjdjMzQzODA0NmY1ZDI3NTMwZTMzNjE1YjhjMGUzNDVkYWJhIl0sInNlcXVlbmNlIjo0Mjk0OTY3Mjk1fV0sInZvdXQiOlt7InZhbHVlIjowLjAwMDAwNTQ2LCJuIjowLCJzY3JpcHRQdWJLZXkiOnsiYXNtIjoiMSA0N2ViNjllNWU4NDA2Y2QyODc1YTM5YjJiZDhiYzViYjNkOGEzN2E5ODg4NWYyODJlNzg4YzE2MTg3YWZiMWVlIiwiaGV4IjoiNTEyMDQ3ZWI2OWU1ZTg0MDZjZDI4NzVhMzliMmJkOGJjNWJiM2Q4YTM3YTk4ODg1ZjI4MmU3ODhjMTYxODdhZmIxZWUiLCJ0eXBlIjoid2l0bmVzc192MV90YXByb290In19XX0seyJoZXgiOiIwMjAwMDAwMDAwMDEwMTlkMTE4ZWNiOTBkMTJhM2ViZDQ4YWUzMjA4ZDIyYTNlZDJmMjA4ZWNiZDNhNmQ2NDg5OWQxODJiZDAxZWIwZjMwYzAwMDAwMDAwZmZmZmZmZmYwMTIyMDIwMDAwMDAwMDAwMDAyMjUxMjAyZGU4NTIxNDhlZDMxNjg4NTU2NGM0NDYyYmQwZmQwMDY2NmQzZTA3OWQ4NTIwMTllNDFmOTAyMTIwODc4ZGQ1MDM0MDc1YjI1YzNmZmViMjBkZWMzM2U4ZTQzYjZiNmUyM2FlM2Y2OTRkNGQ0ZjVjNjllMWJjZDZhNjUxOWY5NTgyNWM4N2M0MmNkYjFlMTQ3MTJkOGUwZjRmYmU2NDI1NDY3YjliZmVjYTgwOTM4MjgwNzA3M2M0Mzc0NDMxOWNhNTBiN2IyMDFiYzY5NTdiZWI0M2ZkZTkyYjJkMGQ2NzFhYzYzNWY4NWIxNGIwNTQzMjYyZThjYWNjMWExNGRkMjlmNmM3OTlhYzAwNjMwMzZmNzI2NDAxMDExODc0NjU3ODc0MmY3MDZjNjE2OTZlM2I2MzY4NjE3MjczNjU3NDNkNzU3NDY2MmQzODAwMzU3YjIyNzAyMjNhMjI2MjcyNjMyZDMyMzAyMjJjMjI2ZjcwMjIzYTIyNmQ2OTZlNzQyMjJjMjI3NDY5NjM2YjIyM2EyMjZkNjU2ZDY1MjIyYzIyNjE2ZDc0MjIzYTIyMzEzMDMwMzAyMjdkNjgyMWMwOTgzNzFjMTA4ZjY1YWM5M2MyZDA4OTAwYTBlYjZlYWNlOTBhNTQ3MTg2ODAxZmEyNTJiNDNlNTdlN2UyNzU1MTAwMDAwMDAwIiwidHhpZCI6IjczM2UzMTBiNjhiOTlkMmU2ZTYzNTk2MDUyYzNiN2FlYzgwNThlM2M3M2JhYTQxZjdmMzgzZDc3OWY1NGViYzQiLCJoYXNoIjoiNjYwODlmNDFkYzNhNDYxOWQ5NmZiNDhkYzU1NGU2MDk1NmNjMGIzNDUzYjViYWQ5M2IwOGJlMzFlNTY0Mjc4MyIsInNpemUiOjMyMCwidnNpemUiOjE1MSwid2VpZ2h0Ijo2MDIsInZlcnNpb24iOjIsImxvY2t0aW1lIjowLCJ2aW4iOlt7InR4aWQiOiJmM2IwMWVkMDJiMTg5ZDg5NjQ2ZDNhYmRlYzA4ZjJkMjNlMmFkMjA4MzJhZTQ4YmQzZTJhZDE5MGNiOGUxMTlkIiwidm91dCI6MTIsInNjcmlwdFNpZyI6eyJhc20iOiIiLCJoZXgiOiIifSwidHhpbndpdG5lc3MiOlsiNzViMjVjM2ZmZWIyMGRlYzMzZThlNDNiNmI2ZTIzYWUzZjY5NGQ0ZDRmNWM2OWUxYmNkNmE2NTE5Zjk1ODI1Yzg3YzQyY2RiMWUxNDcxMmQ4ZTBmNGZiZTY0MjU0NjdiOWJmZWNhODA5MzgyODA3MDczYzQzNzQ0MzE5Y2E1MGIiLCIyMDFiYzY5NTdiZWI0M2ZkZTkyYjJkMGQ2NzFhYzYzNWY4NWIxNGIwNTQzMjYyZThjYWNjMWExNGRkMjlmNmM3OTlhYzAwNjMwMzZmNzI2NDAxMDExODc0NjU3ODc0MmY3MDZjNjE2OTZlM2I2MzY4NjE3MjczNjU3NDNkNzU3NDY2MmQzODAwMzU3YjIyNzAyMjNhMjI2MjcyNjMyZDMyMzAyMjJjMjI2ZjcwMjIzYTIyNmQ2OTZlNzQyMjJjMjI3NDY5NjM2YjIyM2EyMjZkNjU2ZDY1MjIyYzIyNjE2ZDc0MjIzYTIyMzEzMDMwMzAyMjdkNjgiLCJjMDk4MzcxYzEwOGY2NWFjOTNjMmQwODkwMGEwZWI2ZWFjZTkwYTU0NzE4NjgwMWZhMjUyYjQzZTU3ZTdlMjc1NTEiXSwic2VxdWVuY2UiOjQyOTQ5NjcyOTV9XSwidm91dCI6W3sidmFsdWUiOjAuMDAwMDA1NDYsIm4iOjAsInNjcmlwdFB1YktleSI6eyJhc20iOiIxIDJkZTg1MjE0OGVkMzE2ODg1NTY0YzQ0NjJiZDBmZDAwNjY2ZDNlMDc5ZDg1MjAxOWU0MWY5MDIxMjA4NzhkZDUiLCJoZXgiOiI1MTIwMmRlODUyMTQ4ZWQzMTY4ODU1NjRjNDQ2MmJkMGZkMDA2NjZkM2UwNzlkODUyMDE5ZTQxZjkwMjEyMDg3OGRkNSIsInR5cGUiOiJ3aXRuZXNzX3YxX3RhcHJvb3QifX1dfSx7ImhleCI6IjAyMDAwMDAwMDAwMTAxOTU0MjJkZDVmOGExMWQ4Njc0NDdmMDA1ZDA1ZDkyNTlhZGY1OGZmY2ExNzM2MzJmZjRjY2I5OTZjNTU3ZGVjZDA0MDAwMDAwMDBmZmZmZmZmZjAxMjIwMjAwMDAwMDAwMDAwMDIyNTEyMDQ3ZWI2OWU1ZTg0MDZjZDI4NzVhMzliMmJkOGJjNWJiM2Q4YTM3YTk4ODg1ZjI4MmU3ODhjMTYxODdhZmIxZWUwMzQwNDhiMjIyMGJlZGI1Yjg1ZWVlMjNhOWFjYTBkNjQ1NDZkMzZiMjBhMDBiYzA0MzZiZjI4ODM4NDhlNTlmZjEzOTJiNzlkNWJlNzUzMDYzYzFjNmJmZTEyZWNlZmRhYWI4ZDQzOTJlYWYwYTI0YWE1YjYzNWU2YTQ0OGMwNzZmY2Y3YjIwMzMyMmU1MTJkMjAxYTEzOGU4YjI3MWQ3NzdiYzQ4NWM2M2RiMzFhYjhiNjBiMjgyMDEwMDMyNjhmYTMzZDMyMGFjMDA2MzAzNmY3MjY0MDEwMTE4NzQ2NTc4NzQyZjcwNmM2MTY5NmUzYjYzNjg2MTcyNzM2NTc0M2Q3NTc0NjYyZDM4MDAzNTdiMjI3MDIyM2EyMjYyNzI2MzJkMzIzMDIyMmMyMjZmNzAyMjNhMjI2ZDY5NmU3NDIyMmMyMjc0Njk2MzZiMjIzYTIyNTU1MzQ0NTQyMjJjMjI2MTZkNzQyMjNhMjIzMTMwMzAzMDIyN2Q2ODIxYzEzMGMwNWRiZTlmY2ZjYjNjNmQ2M2I4YzU0YTU4YjdjMzQzODA0NmY1ZDI3NTMwZTMzNjE1YjhjMGUzNDVkYWJhMDAwMDAwMDAiLCJ0eGlkIjoiMGZiNjY2NGQ3MjAyNGQ5NTRhYzk4YTdiMGI1NzFkZTg2ZTJiZmVkZmEwNWE4ODg3NmIyOTZhYTkyOTZhZmFjNyIsImhhc2giOiI1NTJmNTZkZjU3OGJkMzIxNDBhNjIzMzhmYmYzM2ZmYjZlOWE1ZTUyYmUyZTJmM2M2NDdlOGNmOGE2NDNjZDEyIiwic2l6ZSI6MzIwLCJ2c2l6ZSI6MTUxLCJ3ZWlnaHQiOjYwMiwidmVyc2lvbiI6MiwibG9ja3RpbWUiOjAsInZpbiI6W3sidHhpZCI6ImNkZGU1N2M1OTZiOWNjZjQyZjYzNzNhMWZjOGZmNWFkNTk5MjVkZDAwNWYwNDc3NDg2MWRhMWY4ZDUyZDQyOTUiLCJ2b3V0Ijo0LCJzY3JpcHRTaWciOnsiYXNtIjoiIiwiaGV4IjoiIn0sInR4aW53aXRuZXNzIjpbIjQ4YjIyMjBiZWRiNWI4NWVlZTIzYTlhY2EwZDY0NTQ2ZDM2YjIwYTAwYmMwNDM2YmYyODgzODQ4ZTU5ZmYxMzkyYjc5ZDViZTc1MzA2M2MxYzZiZmUxMmVjZWZkYWFiOGQ0MzkyZWFmMGEyNGFhNWI2MzVlNmE0NDhjMDc2ZmNmIiwiMjAzMzIyZTUxMmQyMDFhMTM4ZThiMjcxZDc3N2JjNDg1YzYzZGIzMWFiOGI2MGIyODIwMTAwMzI2OGZhMzNkMzIwYWMwMDYzMDM2ZjcyNjQwMTAxMTg3NDY1Nzg3NDJmNzA2YzYxNjk2ZTNiNjM2ODYxNzI3MzY1NzQzZDc1NzQ2NjJkMzgwMDM1N2IyMjcwMjIzYTIyNjI3MjYzMmQzMjMwMjIyYzIyNmY3MDIyM2EyMjZkNjk2ZTc0MjIyYzIyNzQ2OTYzNmIyMjNhMjI1NTUzNDQ1NDIyMmMyMjYxNmQ3NDIyM2EyMjMxMzAzMDMwMjI3ZDY4IiwiYzEzMGMwNWRiZTlmY2ZjYjNjNmQ2M2I4YzU0YTU4YjdjMzQzODA0NmY1ZDI3NTMwZTMzNjE1YjhjMGUzNDVkYWJhIl0sInNlcXVlbmNlIjo0Mjk0OTY3Mjk1fV0sInZvdXQiOlt7InZhbHVlIjowLjAwMDAwNTQ2LCJuIjowLCJzY3JpcHRQdWJLZXkiOnsiYXNtIjoiMSA0N2ViNjllNWU4NDA2Y2QyODc1YTM5YjJiZDhiYzViYjNkOGEzN2E5ODg4NWYyODJlNzg4YzE2MTg3YWZiMWVlIiwiaGV4IjoiNTEyMDQ3ZWI2OWU1ZTg0MDZjZDI4NzVhMzliMmJkOGJjNWJiM2Q4YTM3YTk4ODg1ZjI4MmU3ODhjMTYxODdhZmIxZWUiLCJ0eXBlIjoid2l0bmVzc192MV90YXByb290In19XX0seyJoZXgiOiIwMjAwMDAwMDAwMDEwMTlkMTE4ZWNiOTBkMTJhM2ViZDQ4YWUzMjA4ZDIyYTNlZDJmMjA4ZWNiZDNhNmQ2NDg5OWQxODJiZDAxZWIwZjMwYjAwMDAwMDAwZmZmZmZmZmYwMTIyMDIwMDAwMDAwMDAwMDAyMjUxMjAyZGU4NTIxNDhlZDMxNjg4NTU2NGM0NDYyYmQwZmQwMDY2NmQzZTA3OWQ4NTIwMTllNDFmOTAyMTIwODc4ZGQ1MDM0MDRhNWNkMTk0YWM4ZGUyOTM0ZTQzMmZhYzMwMmQyYzA0NmFhYjk2ZDUxOTFiNzU0YjBkMTNiYWJhZWJjY2I0NmNmOTUwN2JhMTBiYzVkMjcyZTk1YmJjNjU2MGQ1ZGI3YTM3ZWQ4YWE5YjFhMzE0YmI0YzkxYTg4NWRjNzRiYTc5N2IyMDM3ODhjY2U5NmI2NDEzYmRlYWFjNGM3NzU2YTgwMGVlMTYxMDRmMTkyODUxNDk2NzM2ZmIyZmMwNTJiZGMxYjRhYzAwNjMwMzZmNzI2NDAxMDExODc0NjU3ODc0MmY3MDZjNjE2OTZlM2I2MzY4NjE3MjczNjU3NDNkNzU3NDY2MmQzODAwMzU3YjIyNzAyMjNhMjI2MjcyNjMyZDMyMzAyMjJjMjI2ZjcwMjIzYTIyNmQ2OTZlNzQyMjJjMjI3NDY5NjM2YjIyM2EyMjZkNjU2ZDY1MjIyYzIyNjE2ZDc0MjIzYTIyMzEzMDMwMzAyMjdkNjgyMWMxOTgzNzFjMTA4ZjY1YWM5M2MyZDA4OTAwYTBlYjZlYWNlOTBhNTQ3MTg2ODAxZmEyNTJiNDNlNTdlN2UyNzU1MTAwMDAwMDAwIiwidHhpZCI6ImNiZDM1MzFiZjA5OTM5Zjc2NTUyOTU3MGM5YjNiZDdjZTcyZDg1NTQyMGMxOGQ2Njc1M2FkZjk5MGU2OGZiZDAiLCJoYXNoIjoiM2M3ZWRiMGUyN2FkZjA2OWMwNmI1YmFhMDIyYjk5OTllM2VkOTNjY2I1MzE2Y2U2NWI0MGZmMTBjNmYzZTdkZiIsInNpemUiOjMyMCwidnNpemUiOjE1MSwid2VpZ2h0Ijo2MDIsInZlcnNpb24iOjIsImxvY2t0aW1lIjowLCJ2aW4iOlt7InR4aWQiOiJmM2IwMWVkMDJiMTg5ZDg5NjQ2ZDNhYmRlYzA4ZjJkMjNlMmFkMjA4MzJhZTQ4YmQzZTJhZDE5MGNiOGUxMTlkIiwidm91dCI6MTEsInNjcmlwdFNpZyI6eyJhc20iOiIiLCJoZXgiOiIifSwidHhpbndpdG5lc3MiOlsiNGE1Y2QxOTRhYzhkZTI5MzRlNDMyZmFjMzAyZDJjMDQ2YWFiOTZkNTE5MWI3NTRiMGQxM2JhYmFlYmNjYjQ2Y2Y5NTA3YmExMGJjNWQyNzJlOTViYmM2NTYwZDVkYjdhMzdlZDhhYTliMWEzMTRiYjRjOTFhODg1ZGM3NGJhNzkiLCIyMDM3ODhjY2U5NmI2NDEzYmRlYWFjNGM3NzU2YTgwMGVlMTYxMDRmMTkyODUxNDk2NzM2ZmIyZmMwNTJiZGMxYjRhYzAwNjMwMzZmNzI2NDAxMDExODc0NjU3ODc0MmY3MDZjNjE2OTZlM2I2MzY4NjE3MjczNjU3NDNkNzU3NDY2MmQzODAwMzU3YjIyNzAyMjNhMjI2MjcyNjMyZDMyMzAyMjJjMjI2ZjcwMjIzYTIyNmQ2OTZlNzQyMjJjMjI3NDY5NjM2YjIyM2EyMjZkNjU2ZDY1MjIyYzIyNjE2ZDc0MjIzYTIyMzEzMDMwMzAyMjdkNjgiLCJjMTk4MzcxYzEwOGY2NWFjOTNjMmQwODkwMGEwZWI2ZWFjZTkwYTU0NzE4NjgwMWZhMjUyYjQzZTU3ZTdlMjc1NTEiXSwic2VxdWVuY2UiOjQyOTQ5NjcyOTV9XSwidm91dCI6W3sidmFsdWUiOjAuMDAwMDA1NDYsIm4iOjAsInNjcmlwdFB1YktleSI6eyJhc20iOiIxIDJkZTg1MjE0OGVkMzE2ODg1NTY0YzQ0NjJiZDBmZDAwNjY2ZDNlMDc5ZDg1MjAxOWU0MWY5MDIxMjA4NzhkZDUiLCJoZXgiOiI1MTIwMmRlODUyMTQ4ZWQzMTY4ODU1NjRjNDQ2MmJkMGZkMDA2NjZkM2UwNzlkODUyMDE5ZTQxZjkwMjEyMDg3OGRkNSIsInR5cGUiOiJ3aXRuZXNzX3YxX3RhcHJvb3QifX1dfSx7ImhleCI6IjAyMDAwMDAwMDAwMTAxOTU0MjJkZDVmOGExMWQ4Njc0NDdmMDA1ZDA1ZDkyNTlhZGY1OGZmY2ExNzM2MzJmZjRjY2I5OTZjNTU3ZGVjZDAxMDAwMDAwMDBmZmZmZmZmZjAxMjIwMjAwMDAwMDAwMDAwMDIyNTEyMDQ3ZWI2OWU1ZTg0MDZjZDI4NzVhMzliMmJkOGJjNWJiM2Q4YTM3YTk4ODg1ZjI4MmU3ODhjMTYxODdhZmIxZWUwMzQwZmU3NTk0OWI3MGRjZGRlZDkxNGFlOTFkNzdhM2UwZjY3NGVlMjFjMDNhYjdkZDBjNTUxMDNlYmE2NTBhZDdjZWE1ZjhiZGQ3MDkxZmZhYjQyODIzOTI1ODRhYjBhMWRjNGI1MzQ1NDBjZTg1NTgwYjZiOWU1YzBkMDNjN2EwMWU3YjIwMzg5NDVmYWUwYjkyZjcwZDQ0OTRhMzYzNjViOWVjMjBkNDg1MzM3Yzk4MmNiMzdmMGY2NGQ4MDIxODFkMGUyM2FjMDA2MzAzNmY3MjY0MDEwMTE4NzQ2NTc4NzQyZjcwNmM2MTY5NmUzYjYzNjg2MTcyNzM2NTc0M2Q3NTc0NjYyZDM4MDAzNTdiMjI3MDIyM2EyMjYyNzI2MzJkMzIzMDIyMmMyMjZmNzAyMjNhMjI2ZDY5NmU3NDIyMmMyMjc0Njk2MzZiMjIzYTIyNTU1MzQ0NTQyMjJjMjI2MTZkNzQyMjNhMjIzMTMwMzAzMDIyN2Q2ODIxYzEzMGMwNWRiZTlmY2ZjYjNjNmQ2M2I4YzU0YTU4YjdjMzQzODA0NmY1ZDI3NTMwZTMzNjE1YjhjMGUzNDVkYWJhMDAwMDAwMDAiLCJ0eGlkIjoiNjM3NzlkOWQ1MTk5MDMzYzViNDAwY2RjYzBmZGQwZTZjY2E3Y2JjMDY0ZmY0MjBjOTMzNDQ0Y2FhNjc5N2NkMiIsImhhc2giOiJiNTExMjBiZDY4MTI1OTE2ZDAyMDZiZGVkZjIwMmVhOTU4ZDBkMGZlMmNjYjQwN2IzYWE3ZmRiNWYzOWU1NWViIiwic2l6ZSI6MzIwLCJ2c2l6ZSI6MTUxLCJ3ZWlnaHQiOjYwMiwidmVyc2lvbiI6MiwibG9ja3RpbWUiOjAsInZpbiI6W3sidHhpZCI6ImNkZGU1N2M1OTZiOWNjZjQyZjYzNzNhMWZjOGZmNWFkNTk5MjVkZDAwNWYwNDc3NDg2MWRhMWY4ZDUyZDQyOTUiLCJ2b3V0IjoxLCJzY3JpcHRTaWciOnsiYXNtIjoiIiwiaGV4IjoiIn0sInR4aW53aXRuZXNzIjpbImZlNzU5NDliNzBkY2RkZWQ5MTRhZTkxZDc3YTNlMGY2NzRlZTIxYzAzYWI3ZGQwYzU1MTAzZWJhNjUwYWQ3Y2VhNWY4YmRkNzA5MWZmYWI0MjgyMzkyNTg0YWIwYTFkYzRiNTM0NTQwY2U4NTU4MGI2YjllNWMwZDAzYzdhMDFlIiwiMjAzODk0NWZhZTBiOTJmNzBkNDQ5NGEzNjM2NWI5ZWMyMGQ0ODUzMzdjOTgyY2IzN2YwZjY0ZDgwMjE4MWQwZTIzYWMwMDYzMDM2ZjcyNjQwMTAxMTg3NDY1Nzg3NDJmNzA2YzYxNjk2ZTNiNjM2ODYxNzI3MzY1NzQzZDc1NzQ2NjJkMzgwMDM1N2IyMjcwMjIzYTIyNjI3MjYzMmQzMjMwMjIyYzIyNmY3MDIyM2EyMjZkNjk2ZTc0MjIyYzIyNzQ2OTYzNmIyMjNhMjI1NTUzNDQ1NDIyMmMyMjYxNmQ3NDIyM2EyMjMxMzAzMDMwMjI3ZDY4IiwiYzEzMGMwNWRiZTlmY2ZjYjNjNmQ2M2I4YzU0YTU4YjdjMzQzODA0NmY1ZDI3NTMwZTMzNjE1YjhjMGUzNDVkYWJhIl0sInNlcXVlbmNlIjo0Mjk0OTY3Mjk1fV0sInZvdXQiOlt7InZhbHVlIjowLjAwMDAwNTQ2LCJuIjowLCJzY3JpcHRQdWJLZXkiOnsiYXNtIjoiMSA0N2ViNjllNWU4NDA2Y2QyODc1YTM5YjJiZDhiYzViYjNkOGEzN2E5ODg4NWYyODJlNzg4YzE2MTg3YWZiMWVlIiwiaGV4IjoiNTEyMDQ3ZWI2OWU1ZTg0MDZjZDI4NzVhMzliMmJkOGJjNWJiM2Q4YTM3YTk4ODg1ZjI4MmU3ODhjMTYxODdhZmIxZWUiLCJ0eXBlIjoid2l0bmVzc192MV90YXByb290In19XX0seyJoZXgiOiIwMjAwMDAwMDAwMDEwMTlkMTE4ZWNiOTBkMTJhM2ViZDQ4YWUzMjA4ZDIyYTNlZDJmMjA4ZWNiZDNhNmQ2NDg5OWQxODJiZDAxZWIwZjMwZDAwMDAwMDAwZmZmZmZmZmYwMTIyMDIwMDAwMDAwMDAwMDAyMjUxMjAyZGU4NTIxNDhlZDMxNjg4NTU2NGM0NDYyYmQwZmQwMDY2NmQzZTA3OWQ4NTIwMTllNDFmOTAyMTIwODc4ZGQ1MDM0MDRmNWE1ZmUzYjM0MTQ4YTZkYmJmZTJjNWYyZTY0NzdhM2FhNTYzOTM5YzFjOTA5NTI3MDUyZDJlMWNlNjdhNjdlMzE5ODdjMTVhMjExNjYwNzdlMzI3Y2FlOGNkN2MzMjkyOGJkMzhmYmZjZTM4NmFkYjQyNzg0NzJhMGEyZTY4N2IyMGM4OTM1MzJkNzg2ZDg4Yzk5NGUwNDZiNThlYTNhNWZjNDZlM2U0MDFkZTFjZDFmNTUxMjQ2YzE1NWQ1OGM4NGZhYzAwNjMwMzZmNzI2NDAxMDExODc0NjU3ODc0MmY3MDZjNjE2OTZlM2I2MzY4NjE3MjczNjU3NDNkNzU3NDY2MmQzODAwMzU3YjIyNzAyMjNhMjI2MjcyNjMyZDMyMzAyMjJjMjI2ZjcwMjIzYTIyNmQ2OTZlNzQyMjJjMjI3NDY5NjM2YjIyM2EyMjZkNjU2ZDY1MjIyYzIyNjE2ZDc0MjIzYTIyMzEzMDMwMzAyMjdkNjgyMWMxOTgzNzFjMTA4ZjY1YWM5M2MyZDA4OTAwYTBlYjZlYWNlOTBhNTQ3MTg2ODAxZmEyNTJiNDNlNTdlN2UyNzU1MTAwMDAwMDAwIiwidHhpZCI6IjQ0ZDFjODM1NTdkZWRmMWNhNDJiYjBlYzk3ODJkOGE3YTNlNWVlNzZmMGU2ZDMwYTFhYmEwNWNmMDMwYWNhZDQiLCJoYXNoIjoiY2Y5ODdmZmZmZjEzZDVjZjg1Y2JmOTAwMjczYTExOGJjNTU5ZjZlZmU3NzZiNzVkNzU4YzI0NWMzNmU1ZDQ5NSIsInNpemUiOjMyMCwidnNpemUiOjE1MSwid2VpZ2h0Ijo2MDIsInZlcnNpb24iOjIsImxvY2t0aW1lIjowLCJ2aW4iOlt7InR4aWQiOiJmM2IwMWVkMDJiMTg5ZDg5NjQ2ZDNhYmRlYzA4ZjJkMjNlMmFkMjA4MzJhZTQ4YmQzZTJhZDE5MGNiOGUxMTlkIiwidm91dCI6MTMsInNjcmlwdFNpZyI6eyJhc20iOiIiLCJoZXgiOiIifSwidHhpbndpdG5lc3MiOlsiNGY1YTVmZTNiMzQxNDhhNmRiYmZlMmM1ZjJlNjQ3N2EzYWE1NjM5MzljMWM5MDk1MjcwNTJkMmUxY2U2N2E2N2UzMTk4N2MxNWEyMTE2NjA3N2UzMjdjYWU4Y2Q3YzMyOTI4YmQzOGZiZmNlMzg2YWRiNDI3ODQ3MmEwYTJlNjgiLCIyMGM4OTM1MzJkNzg2ZDg4Yzk5NGUwNDZiNThlYTNhNWZjNDZlM2U0MDFkZTFjZDFmNTUxMjQ2YzE1NWQ1OGM4NGZhYzAwNjMwMzZmNzI2NDAxMDExODc0NjU3ODc0MmY3MDZjNjE2OTZlM2I2MzY4NjE3MjczNjU3NDNkNzU3NDY2MmQzODAwMzU3YjIyNzAyMjNhMjI2MjcyNjMyZDMyMzAyMjJjMjI2ZjcwMjIzYTIyNmQ2OTZlNzQyMjJjMjI3NDY5NjM2YjIyM2EyMjZkNjU2ZDY1MjIyYzIyNjE2ZDc0MjIzYTIyMzEzMDMwMzAyMjdkNjgiLCJjMTk4MzcxYzEwOGY2NWFjOTNjMmQwODkwMGEwZWI2ZWFjZTkwYTU0NzE4NjgwMWZhMjUyYjQzZTU3ZTdlMjc1NTEiXSwic2VxdWVuY2UiOjQyOTQ5NjcyOTV9XSwidm91dCI6W3sidmFsdWUiOjAuMDAwMDA1NDYsIm4iOjAsInNjcmlwdFB1YktleSI6eyJhc20iOiIxIDJkZTg1MjE0OGVkMzE2ODg1NTY0YzQ0NjJiZDBmZDAwNjY2ZDNlMDc5ZDg1MjAxOWU0MWY5MDIxMjA4NzhkZDUiLCJoZXgiOiI1MTIwMmRlODUyMTQ4ZWQzMTY4ODU1NjRjNDQ2MmJkMGZkMDA2NjZkM2UwNzlkODUyMDE5ZTQxZjkwMjEyMDg3OGRkNSIsInR5cGUiOiJ3aXRuZXNzX3YxX3RhcHJvb3QifX1dfSx7ImhleCI6IjAyMDAwMDAwMDAwMTAxOWQxMThlY2I5MGQxMmEzZWJkNDhhZTMyMDhkMjJhM2VkMmYyMDhlY2JkM2E2ZDY0ODk5ZDE4MmJkMDFlYjBmMzEyMDAwMDAwMDBmZmZmZmZmZjAxMjIwMjAwMDAwMDAwMDAwMDIyNTEyMDJkZTg1MjE0OGVkMzE2ODg1NTY0YzQ0NjJiZDBmZDAwNjY2ZDNlMDc5ZDg1MjAxOWU0MWY5MDIxMjA4NzhkZDUwMzQwYzk5MzExYTAyMmRmNmJiMzMyOTk2OTYwM2I3MDA4MTMyMzcwY2RhNDJhYmI0OGM2ODVkYzlhZWI0ZTc2YjE1ZWI4MGRhZDI0NmU3YmYxZjBhY2E2NDIyMDk5NDQyNjQwMGU0OTUwNTY1YTI1NzEyMDJjOGZkMjc3MTA1ZDYzM2Y3YjIwNzgyOTU0MWU3ZWNhZjg3OTFlNDE4MTY4ODNmNjBkOWUxZGVmZjBlZTVlYTJkYzRmZWM4YmY5ZGM0NTUxYzQ1ZGFjMDA2MzAzNmY3MjY0MDEwMTE4NzQ2NTc4NzQyZjcwNmM2MTY5NmUzYjYzNjg2MTcyNzM2NTc0M2Q3NTc0NjYyZDM4MDAzNTdiMjI3MDIyM2EyMjYyNzI2MzJkMzIzMDIyMmMyMjZmNzAyMjNhMjI2ZDY5NmU3NDIyMmMyMjc0Njk2MzZiMjIzYTIyNmQ2NTZkNjUyMjJjMjI2MTZkNzQyMjNhMjIzMTMwMzAzMDIyN2Q2ODIxYzE5ODM3MWMxMDhmNjVhYzkzYzJkMDg5MDBhMGViNmVhY2U5MGE1NDcxODY4MDFmYTI1MmI0M2U1N2U3ZTI3NTUxMDAwMDAwMDAiLCJ0eGlkIjoiZjZmYWQ1ZmY5ZGIxNzQ5NDM1YzIzMDlhNGViZjg4NGVjODI2YTJlYWVkNjZjM2I1ZjIxMjBkMjM1MjRiMGRkNiIsImhhc2giOiI4ZTYzYjg5MTJiMTNkZTUzZjVlMzUzN2I0NjdmMmQ3MDNmZDcxN2E4MTMzN2I0YjdkYmMzMDEyMTliMDZmNmQ0Iiwic2l6ZSI6MzIwLCJ2c2l6ZSI6MTUxLCJ3ZWlnaHQiOjYwMiwidmVyc2lvbiI6MiwibG9ja3RpbWUiOjAsInZpbiI6W3sidHhpZCI6ImYzYjAxZWQwMmIxODlkODk2NDZkM2FiZGVjMDhmMmQyM2UyYWQyMDgzMmFlNDhiZDNlMmFkMTkwY2I4ZTExOWQiLCJ2b3V0IjoxOCwic2NyaXB0U2lnIjp7ImFzbSI6IiIsImhleCI6IiJ9LCJ0eGlud2l0bmVzcyI6WyJjOTkzMTFhMDIyZGY2YmIzMzI5OTY5NjAzYjcwMDgxMzIzNzBjZGE0MmFiYjQ4YzY4NWRjOWFlYjRlNzZiMTVlYjgwZGFkMjQ2ZTdiZjFmMGFjYTY0MjIwOTk0NDI2NDAwZTQ5NTA1NjVhMjU3MTIwMmM4ZmQyNzcxMDVkNjMzZiIsIjIwNzgyOTU0MWU3ZWNhZjg3OTFlNDE4MTY4ODNmNjBkOWUxZGVmZjBlZTVlYTJkYzRmZWM4YmY5ZGM0NTUxYzQ1ZGFjMDA2MzAzNmY3MjY0MDEwMTE4NzQ2NTc4NzQyZjcwNmM2MTY5NmUzYjYzNjg2MTcyNzM2NTc0M2Q3NTc0NjYyZDM4MDAzNTdiMjI3MDIyM2EyMjYyNzI2MzJkMzIzMDIyMmMyMjZmNzAyMjNhMjI2ZDY5NmU3NDIyMmMyMjc0Njk2MzZiMjIzYTIyNmQ2NTZkNjUyMjJjMjI2MTZkNzQyMjNhMjIzMTMwMzAzMDIyN2Q2OCIsImMxOTgzNzFjMTA4ZjY1YWM5M2MyZDA4OTAwYTBlYjZlYWNlOTBhNTQ3MTg2ODAxZmEyNTJiNDNlNTdlN2UyNzU1MSJdLCJzZXF1ZW5jZSI6NDI5NDk2NzI5NX1dLCJ2b3V0IjpbeyJ2YWx1ZSI6MC4wMDAwMDU0NiwibiI6MCwic2NyaXB0UHViS2V5Ijp7ImFzbSI6IjEgMmRlODUyMTQ4ZWQzMTY4ODU1NjRjNDQ2MmJkMGZkMDA2NjZkM2UwNzlkODUyMDE5ZTQxZjkwMjEyMDg3OGRkNSIsImhleCI6IjUxMjAyZGU4NTIxNDhlZDMxNjg4NTU2NGM0NDYyYmQwZmQwMDY2NmQzZTA3OWQ4NTIwMTllNDFmOTAyMTIwODc4ZGQ1IiwidHlwZSI6IndpdG5lc3NfdjFfdGFwcm9vdCJ9fV19LHsiaGV4IjoiMDIwMDAwMDAwMDAxMDE5NTQyMmRkNWY4YTExZDg2NzQ0N2YwMDVkMDVkOTI1OWFkZjU4ZmZjYTE3MzYzMmZmNGNjYjk5NmM1NTdkZWNkMTIwMDAwMDAwMGZmZmZmZmZmMDEyMjAyMDAwMDAwMDAwMDAwMjI1MTIwNDdlYjY5ZTVlODQwNmNkMjg3NWEzOWIyYmQ4YmM1YmIzZDhhMzdhOTg4ODVmMjgyZTc4OGMxNjE4N2FmYjFlZTAzNDBmNjlmNWMzM2ZkMmU1MzBkZDUyZjFkMmRkMWE0YmFiMzU3ZjQ3NWVjNjEzOTcxZDQ2MjdlYzMwNzZiNTNjMDcxMTM4ODMwZGE1NWQ4ZWRmMjM3YTBjMzgxNmI0ZWMyMTIzZTEzYTI4Y2I0ZjMzY2NiZTgzMzk4YmU1YzM2MTk5MzdiMjA2ZGVlZjcxNTkxZjMzNGQ2ZmM2MjIzZDNiNmVlNTM5MGRjN2YwMjAwMmUxNzcyZjcyMThhZTNlNGIxZjBhMzk1YWMwMDYzMDM2ZjcyNjQwMTAxMTg3NDY1Nzg3NDJmNzA2YzYxNjk2ZTNiNjM2ODYxNzI3MzY1NzQzZDc1NzQ2NjJkMzgwMDM1N2IyMjcwMjIzYTIyNjI3MjYzMmQzMjMwMjIyYzIyNmY3MDIyM2EyMjZkNjk2ZTc0MjIyYzIyNzQ2OTYzNmIyMjNhMjI1NTUzNDQ1NDIyMmMyMjYxNmQ3NDIyM2EyMjMxMzAzMDMwMjI3ZDY4MjFjMTMwYzA1ZGJlOWZjZmNiM2M2ZDYzYjhjNTRhNThiN2MzNDM4MDQ2ZjVkMjc1MzBlMzM2MTViOGMwZTM0NWRhYmEwMDAwMDAwMCIsInR4aWQiOiJkNzI4MjIyNjE4ZDExZGNiNmM3NTE5OWVhMTdiZjI5NmQ1MDYwZTljNTM1Nzc4ZDBlYzg5NWJmMjk3OWQ1ZWRlIiwiaGFzaCI6Ijc2YzQxZmFiZmM0MWI3MmI3Nzk3NTk1M2ZiMTY2MmYwOWQxNmY1Y2ZhYzY1ZDFhNzAyYTAyMzY4OTFiODcxNjciLCJzaXplIjozMjAsInZzaXplIjoxNTEsIndlaWdodCI6NjAyLCJ2ZXJzaW9uIjoyLCJsb2NrdGltZSI6MCwidmluIjpbeyJ0eGlkIjoiY2RkZTU3YzU5NmI5Y2NmNDJmNjM3M2ExZmM4ZmY1YWQ1OTkyNWRkMDA1ZjA0Nzc0ODYxZGExZjhkNTJkNDI5NSIsInZvdXQiOjE4LCJzY3JpcHRTaWciOnsiYXNtIjoiIiwiaGV4IjoiIn0sInR4aW53aXRuZXNzIjpbImY2OWY1YzMzZmQyZTUzMGRkNTJmMWQyZGQxYTRiYWIzNTdmNDc1ZWM2MTM5NzFkNDYyN2VjMzA3NmI1M2MwNzExMzg4MzBkYTU1ZDhlZGYyMzdhMGMzODE2YjRlYzIxMjNlMTNhMjhjYjRmMzNjY2JlODMzOThiZTVjMzYxOTkzIiwiMjA2ZGVlZjcxNTkxZjMzNGQ2ZmM2MjIzZDNiNmVlNTM5MGRjN2YwMjAwMmUxNzcyZjcyMThhZTNlNGIxZjBhMzk1YWMwMDYzMDM2ZjcyNjQwMTAxMTg3NDY1Nzg3NDJmNzA2YzYxNjk2ZTNiNjM2ODYxNzI3MzY1NzQzZDc1NzQ2NjJkMzgwMDM1N2IyMjcwMjIzYTIyNjI3MjYzMmQzMjMwMjIyYzIyNmY3MDIyM2EyMjZkNjk2ZTc0MjIyYzIyNzQ2OTYzNmIyMjNhMjI1NTUzNDQ1NDIyMmMyMjYxNmQ3NDIyM2EyMjMxMzAzMDMwMjI3ZDY4IiwiYzEzMGMwNWRiZTlmY2ZjYjNjNmQ2M2I4YzU0YTU4YjdjMzQzODA0NmY1ZDI3NTMwZTMzNjE1YjhjMGUzNDVkYWJhIl0sInNlcXVlbmNlIjo0Mjk0OTY3Mjk1fV0sInZvdXQiOlt7InZhbHVlIjowLjAwMDAwNTQ2LCJuIjowLCJzY3JpcHRQdWJLZXkiOnsiYXNtIjoiMSA0N2ViNjllNWU4NDA2Y2QyODc1YTM5YjJiZDhiYzViYjNkOGEzN2E5ODg4NWYyODJlNzg4YzE2MTg3YWZiMWVlIiwiaGV4IjoiNTEyMDQ3ZWI2OWU1ZTg0MDZjZDI4NzVhMzliMmJkOGJjNWJiM2Q4YTM3YTk4ODg1ZjI4MmU3ODhjMTYxODdhZmIxZWUiLCJ0eXBlIjoid2l0bmVzc192MV90YXByb290In19XX0seyJoZXgiOiIwMjAwMDAwMDAwMDEwMTk1NDIyZGQ1ZjhhMTFkODY3NDQ3ZjAwNWQwNWQ5MjU5YWRmNThmZmNhMTczNjMyZmY0Y2NiOTk2YzU1N2RlY2QwYzAwMDAwMDAwZmZmZmZmZmYwMTIyMDIwMDAwMDAwMDAwMDAyMjUxMjA0N2ViNjllNWU4NDA2Y2QyODc1YTM5YjJiZDhiYzViYjNkOGEzN2E5ODg4NWYyODJlNzg4YzE2MTg3YWZiMWVlMDM0MDkyOTE5N2MzYjFkODcxY2MwNmI3YTBkMmI3Zjg1NjlkYzkyYWRmZjJlZWVmZWZjYmVkODZiODc5ZjhiYTA2NDk2NWQ1MGM0OTAyMjIwYzRiZTAwY2MxNDRiZjg4ODkyYTIzMWI4M2Y4ZDRjNmZmNWIxZTIxODgxYzA4ZGJjZjk4N2IyMDg0ODZmMTU1OTI1YzNlMmQxMTljNjM3NmM2OTYwZjlmYmVmODEwYjc4ZjIzMjFmYmM0N2RkMGVjZjNiMzMzMmNhYzAwNjMwMzZmNzI2NDAxMDExODc0NjU3ODc0MmY3MDZjNjE2OTZlM2I2MzY4NjE3MjczNjU3NDNkNzU3NDY2MmQzODAwMzU3YjIyNzAyMjNhMjI2MjcyNjMyZDMyMzAyMjJjMjI2ZjcwMjIzYTIyNmQ2OTZlNzQyMjJjMjI3NDY5NjM2YjIyM2EyMjU1NTM0NDU0MjIyYzIyNjE2ZDc0MjIzYTIyMzEzMDMwMzAyMjdkNjgyMWMwMzBjMDVkYmU5ZmNmY2IzYzZkNjNiOGM1NGE1OGI3YzM0MzgwNDZmNWQyNzUzMGUzMzYxNWI4YzBlMzQ1ZGFiYTAwMDAwMDAwIiwidHhpZCI6ImNlMjI4YmQwOWU3OTk0MDUzOTI3OTE0ZmE4NGQ5NjQxNWUwMzEyYThlNDFiNjg2NzlmYjA1MDk5MGRmMTA3ZTIiLCJoYXNoIjoiZDY4YWU2NjkzNDVkOGJhNGI1M2Q0NzY0ZTE2OTgyODExZTQwZDdkMWM0ZGY1YzhmOTM0ZDhlNzdlNDIxNzNjOCIsInNpemUiOjMyMCwidnNpemUiOjE1MSwid2VpZ2h0Ijo2MDIsInZlcnNpb24iOjIsImxvY2t0aW1lIjowLCJ2aW4iOlt7InR4aWQiOiJjZGRlNTdjNTk2YjljY2Y0MmY2MzczYTFmYzhmZjVhZDU5OTI1ZGQwMDVmMDQ3NzQ4NjFkYTFmOGQ1MmQ0Mjk1Iiwidm91dCI6MTIsInNjcmlwdFNpZyI6eyJhc20iOiIiLCJoZXgiOiIifSwidHhpbndpdG5lc3MiOlsiOTI5MTk3YzNiMWQ4NzFjYzA2YjdhMGQyYjdmODU2OWRjOTJhZGZmMmVlZWZlZmNiZWQ4NmI4NzlmOGJhMDY0OTY1ZDUwYzQ5MDIyMjBjNGJlMDBjYzE0NGJmODg4OTJhMjMxYjgzZjhkNGM2ZmY1YjFlMjE4ODFjMDhkYmNmOTgiLCIyMDg0ODZmMTU1OTI1YzNlMmQxMTljNjM3NmM2OTYwZjlmYmVmODEwYjc4ZjIzMjFmYmM0N2RkMGVjZjNiMzMzMmNhYzAwNjMwMzZmNzI2NDAxMDExODc0NjU3ODc0MmY3MDZjNjE2OTZlM2I2MzY4NjE3MjczNjU3NDNkNzU3NDY2MmQzODAwMzU3YjIyNzAyMjNhMjI2MjcyNjMyZDMyMzAyMjJjMjI2ZjcwMjIzYTIyNmQ2OTZlNzQyMjJjMjI3NDY5NjM2YjIyM2EyMjU1NTM0NDU0MjIyYzIyNjE2ZDc0MjIzYTIyMzEzMDMwMzAyMjdkNjgiLCJjMDMwYzA1ZGJlOWZjZmNiM2M2ZDYzYjhjNTRhNThiN2MzNDM4MDQ2ZjVkMjc1MzBlMzM2MTViOGMwZTM0NWRhYmEiXSwic2VxdWVuY2UiOjQyOTQ5NjcyOTV9XSwidm91dCI6W3sidmFsdWUiOjAuMDAwMDA1NDYsIm4iOjAsInNjcmlwdFB1YktleSI6eyJhc20iOiIxIDQ3ZWI2OWU1ZTg0MDZjZDI4NzVhMzliMmJkOGJjNWJiM2Q4YTM3YTk4ODg1ZjI4MmU3ODhjMTYxODdhZmIxZWUiLCJoZXgiOiI1MTIwNDdlYjY5ZTVlODQwNmNkMjg3NWEzOWIyYmQ4YmM1YmIzZDhhMzdhOTg4ODVmMjgyZTc4OGMxNjE4N2FmYjFlZSIsInR5cGUiOiJ3aXRuZXNzX3YxX3RhcHJvb3QifX1dfSx7ImhleCI6IjAyMDAwMDAwMDAwMTAxOTU0MjJkZDVmOGExMWQ4Njc0NDdmMDA1ZDA1ZDkyNTlhZGY1OGZmY2ExNzM2MzJmZjRjY2I5OTZjNTU3ZGVjZDA2MDAwMDAwMDBmZmZmZmZmZjAxMjIwMjAwMDAwMDAwMDAwMDIyNTEyMDQ3ZWI2OWU1ZTg0MDZjZDI4NzVhMzliMmJkOGJjNWJiM2Q4YTM3YTk4ODg1ZjI4MmU3ODhjMTYxODdhZmIxZWUwMzQwMjAyYWM0ODMzOWQ2YjU2YTI0M2I1OGVmNmNlZjI0MGIxZjU1YWNkYjkzMzQyNzVmODI0MDdkZjgwZTM0ZjZjOTkyYjQ2NTJhYzI2NTMyZGQzMDZkNTFlZjlkNzhhM2Q3MDJiN2FiZjJmODI0MzczMTVjMmFmNGFmYzQyNGYzMjk3YjIwNThmYjY2M2MxMWMwZjIzYTQ5MzNlZWYxMTllOTVlMmIzZWQ2ZmFkZjI4YjJlZWI0Y2VjMTBjMzIyZDhkZTU1ZGFjMDA2MzAzNmY3MjY0MDEwMTE4NzQ2NTc4NzQyZjcwNmM2MTY5NmUzYjYzNjg2MTcyNzM2NTc0M2Q3NTc0NjYyZDM4MDAzNTdiMjI3MDIyM2EyMjYyNzI2MzJkMzIzMDIyMmMyMjZmNzAyMjNhMjI2ZDY5NmU3NDIyMmMyMjc0Njk2MzZiMjIzYTIyNTU1MzQ0NTQyMjJjMjI2MTZkNzQyMjNhMjIzMTMwMzAzMDIyN2Q2ODIxYzEzMGMwNWRiZTlmY2ZjYjNjNmQ2M2I4YzU0YTU4YjdjMzQzODA0NmY1ZDI3NTMwZTMzNjE1YjhjMGUzNDVkYWJhMDAwMDAwMDAiLCJ0eGlkIjoiZTk2ZjFmYTA3ZDY3MWVkMTQ1OGU0MmM0MTdiZGNlZDIyMGM0ZTU1NWQ5OThkNDY2YmFmZTI5NjVkYmI0MDRlNyIsImhhc2giOiI4NjMxZTUwZDkyM2IyYTUzYjEyMzA1MTIzNjVlMzJhZjAzYTAxYzY4NjY2MzVlN2Y2ZGY5YWU0YTIyYTBmMzU5Iiwic2l6ZSI6MzIwLCJ2c2l6ZSI6MTUxLCJ3ZWlnaHQiOjYwMiwidmVyc2lvbiI6MiwibG9ja3RpbWUiOjAsInZpbiI6W3sidHhpZCI6ImNkZGU1N2M1OTZiOWNjZjQyZjYzNzNhMWZjOGZmNWFkNTk5MjVkZDAwNWYwNDc3NDg2MWRhMWY4ZDUyZDQyOTUiLCJ2b3V0Ijo2LCJzY3JpcHRTaWciOnsiYXNtIjoiIiwiaGV4IjoiIn0sInR4aW53aXRuZXNzIjpbIjIwMmFjNDgzMzlkNmI1NmEyNDNiNThlZjZjZWYyNDBiMWY1NWFjZGI5MzM0Mjc1ZjgyNDA3ZGY4MGUzNGY2Yzk5MmI0NjUyYWMyNjUzMmRkMzA2ZDUxZWY5ZDc4YTNkNzAyYjdhYmYyZjgyNDM3MzE1YzJhZjRhZmM0MjRmMzI5IiwiMjA1OGZiNjYzYzExYzBmMjNhNDkzM2VlZjExOWU5NWUyYjNlZDZmYWRmMjhiMmVlYjRjZWMxMGMzMjJkOGRlNTVkYWMwMDYzMDM2ZjcyNjQwMTAxMTg3NDY1Nzg3NDJmNzA2YzYxNjk2ZTNiNjM2ODYxNzI3MzY1NzQzZDc1NzQ2NjJkMzgwMDM1N2IyMjcwMjIzYTIyNjI3MjYzMmQzMjMwMjIyYzIyNmY3MDIyM2EyMjZkNjk2ZTc0MjIyYzIyNzQ2OTYzNmIyMjNhMjI1NTUzNDQ1NDIyMmMyMjYxNmQ3NDIyM2EyMjMxMzAzMDMwMjI3ZDY4IiwiYzEzMGMwNWRiZTlmY2ZjYjNjNmQ2M2I4YzU0YTU4YjdjMzQzODA0NmY1ZDI3NTMwZTMzNjE1YjhjMGUzNDVkYWJhIl0sInNlcXVlbmNlIjo0Mjk0OTY3Mjk1fV0sInZvdXQiOlt7InZhbHVlIjowLjAwMDAwNTQ2LCJuIjowLCJzY3JpcHRQdWJLZXkiOnsiYXNtIjoiMSA0N2ViNjllNWU4NDA2Y2QyODc1YTM5YjJiZDhiYzViYjNkOGEzN2E5ODg4NWYyODJlNzg4YzE2MTg3YWZiMWVlIiwiaGV4IjoiNTEyMDQ3ZWI2OWU1ZTg0MDZjZDI4NzVhMzliMmJkOGJjNWJiM2Q4YTM3YTk4ODg1ZjI4MmU3ODhjMTYxODdhZmIxZWUiLCJ0eXBlIjoid2l0bmVzc192MV90YXByb290In19XX0seyJoZXgiOiIwMjAwMDAwMDAwMDEwMTk1NDIyZGQ1ZjhhMTFkODY3NDQ3ZjAwNWQwNWQ5MjU5YWRmNThmZmNhMTczNjMyZmY0Y2NiOTk2YzU1N2RlY2QwZjAwMDAwMDAwZmZmZmZmZmYwMTIyMDIwMDAwMDAwMDAwMDAyMjUxMjA0N2ViNjllNWU4NDA2Y2QyODc1YTM5YjJiZDhiYzViYjNkOGEzN2E5ODg4NWYyODJlNzg4YzE2MTg3YWZiMWVlMDM0MGE4OTczNWY1ZTI0YjFhYTViMzJkMzU4OWMxOTA3MTg5ZTJiMWQxY2E3ZWZmZTY2MjQ3ZGNkMGY2YmE4ZmNlYmU4OGIyNmM4OWViMDU3NDg0NTkxN2M2MGIxOTY1NjM4N2VkNDgyNmRhZTg5ODU4YmUzNWNiOWZkMDNkOWQ0OGY2N2IyMDIyM2U0YzVlYzUyNWQ0OTMzZWZhMmIxNjFiMmVjOGU1ZjBlZjJiYmRkYjFiMjIxY2E3MDVlOWY1OGUwNjk4MmZhYzAwNjMwMzZmNzI2NDAxMDExODc0NjU3ODc0MmY3MDZjNjE2OTZlM2I2MzY4NjE3MjczNjU3NDNkNzU3NDY2MmQzODAwMzU3YjIyNzAyMjNhMjI2MjcyNjMyZDMyMzAyMjJjMjI2ZjcwMjIzYTIyNmQ2OTZlNzQyMjJjMjI3NDY5NjM2YjIyM2EyMjU1NTM0NDU0MjIyYzIyNjE2ZDc0MjIzYTIyMzEzMDMwMzAyMjdkNjgyMWMxMzBjMDVkYmU5ZmNmY2IzYzZkNjNiOGM1NGE1OGI3YzM0MzgwNDZmNWQyNzUzMGUzMzYxNWI4YzBlMzQ1ZGFiYTAwMDAwMDAwIiwidHhpZCI6IjdjOTM3YjQ1NzZmYmRjMzhiMzJkMjFmOWY2MzZhMzg3MDhlN2I0YzFmYTA4YTA1ZjgxZTcyMTgxZDQwY2VkZWEiLCJoYXNoIjoiZmIwMTE5OWNmOTA3YWEwMmU5MDA3ZjMxMzY4NjBlYzA1ODkwNzYyZWFkMTY3ZWY2MzFmZjNkY2U1ODZjNzViOSIsInNpemUiOjMyMCwidnNpemUiOjE1MSwid2VpZ2h0Ijo2MDIsInZlcnNpb24iOjIsImxvY2t0aW1lIjowLCJ2aW4iOlt7InR4aWQiOiJjZGRlNTdjNTk2YjljY2Y0MmY2MzczYTFmYzhmZjVhZDU5OTI1ZGQwMDVmMDQ3NzQ4NjFkYTFmOGQ1MmQ0Mjk1Iiwidm91dCI6MTUsInNjcmlwdFNpZyI6eyJhc20iOiIiLCJoZXgiOiIifSwidHhpbndpdG5lc3MiOlsiYTg5NzM1ZjVlMjRiMWFhNWIzMmQzNTg5YzE5MDcxODllMmIxZDFjYTdlZmZlNjYyNDdkY2QwZjZiYThmY2ViZTg4YjI2Yzg5ZWIwNTc0ODQ1OTE3YzYwYjE5NjU2Mzg3ZWQ0ODI2ZGFlODk4NThiZTM1Y2I5ZmQwM2Q5ZDQ4ZjYiLCIyMDIyM2U0YzVlYzUyNWQ0OTMzZWZhMmIxNjFiMmVjOGU1ZjBlZjJiYmRkYjFiMjIxY2E3MDVlOWY1OGUwNjk4MmZhYzAwNjMwMzZmNzI2NDAxMDExODc0NjU3ODc0MmY3MDZjNjE2OTZlM2I2MzY4NjE3MjczNjU3NDNkNzU3NDY2MmQzODAwMzU3YjIyNzAyMjNhMjI2MjcyNjMyZDMyMzAyMjJjMjI2ZjcwMjIzYTIyNmQ2OTZlNzQyMjJjMjI3NDY5NjM2YjIyM2EyMjU1NTM0NDU0MjIyYzIyNjE2ZDc0MjIzYTIyMzEzMDMwMzAyMjdkNjgiLCJjMTMwYzA1ZGJlOWZjZmNiM2M2ZDYzYjhjNTRhNThiN2MzNDM4MDQ2ZjVkMjc1MzBlMzM2MTViOGMwZTM0NWRhYmEiXSwic2VxdWVuY2UiOjQyOTQ5NjcyOTV9XSwidm91dCI6W3sidmFsdWUiOjAuMDAwMDA1NDYsIm4iOjAsInNjcmlwdFB1YktleSI6eyJhc20iOiIxIDQ3ZWI2OWU1ZTg0MDZjZDI4NzVhMzliMmJkOGJjNWJiM2Q4YTM3YTk4ODg1ZjI4MmU3ODhjMTYxODdhZmIxZWUiLCJoZXgiOiI1MTIwNDdlYjY5ZTVlODQwNmNkMjg3NWEzOWIyYmQ4YmM1YmIzZDhhMzdhOTg4ODVmMjgyZTc4OGMxNjE4N2FmYjFlZSIsInR5cGUiOiJ3aXRuZXNzX3YxX3RhcHJvb3QifX1dfSx7ImhleCI6IjAyMDAwMDAwMDAwMTAxOWQxMThlY2I5MGQxMmEzZWJkNDhhZTMyMDhkMjJhM2VkMmYyMDhlY2JkM2E2ZDY0ODk5ZDE4MmJkMDFlYjBmMzEzMDAwMDAwMDBmZmZmZmZmZjAxMjIwMjAwMDAwMDAwMDAwMDIyNTEyMDJkZTg1MjE0OGVkMzE2ODg1NTY0YzQ0NjJiZDBmZDAwNjY2ZDNlMDc5ZDg1MjAxOWU0MWY5MDIxMjA4NzhkZDUwMzQwYmNkZWIwZmFmN2Y5ZmM0NTUwNWQ4OGM5M2M4OTE4ZjRmZDBiOTI1NmYzNWMyNjZlMmE2YjAwN2NjMjkyMzJjNDk4ODRjM2Y4MjhjODU0ODdiOWYwOTliYTRhNjcyMjQxNmQ0OGNmMjkyZmI3MTgyZjZiNjcxNzY0YzQ2NTUxODk3YjIwNWJjMzNhMDMyZDIxM2UwNjg4ZWU5NDkwM2M3NmE0ODE0YjViZWFmNWRiOTI5OThiNWZkOTAyMGFmMzE5YjM2ZGFjMDA2MzAzNmY3MjY0MDEwMTE4NzQ2NTc4NzQyZjcwNmM2MTY5NmUzYjYzNjg2MTcyNzM2NTc0M2Q3NTc0NjYyZDM4MDAzNTdiMjI3MDIyM2EyMjYyNzI2MzJkMzIzMDIyMmMyMjZmNzAyMjNhMjI2ZDY5NmU3NDIyMmMyMjc0Njk2MzZiMjIzYTIyNmQ2NTZkNjUyMjJjMjI2MTZkNzQyMjNhMjIzMTMwMzAzMDIyN2Q2ODIxYzA5ODM3MWMxMDhmNjVhYzkzYzJkMDg5MDBhMGViNmVhY2U5MGE1NDcxODY4MDFmYTI1MmI0M2U1N2U3ZTI3NTUxMDAwMDAwMDAiLCJ0eGlkIjoiMTI2ZGI2YjU0MDFlZTEyNjk1ODQ1M2RmZTQ3NGIxY2E2NDM2Y2NkMzA3OWQ4MDAzMGNjN2E1ZmIzNzM5Y2NlYyIsImhhc2giOiIzZGJiNDNlZGQzMGY4NTI0NWIxNzkzNDdlZGQ4OTY5YjYwZTc5ZTFlYTYwZmQyY2M2YWZlZjQxOGExYjkxMDRiIiwic2l6ZSI6MzIwLCJ2c2l6ZSI6MTUxLCJ3ZWlnaHQiOjYwMiwidmVyc2lvbiI6MiwibG9ja3RpbWUiOjAsInZpbiI6W3sidHhpZCI6ImYzYjAxZWQwMmIxODlkODk2NDZkM2FiZGVjMDhmMmQyM2UyYWQyMDgzMmFlNDhiZDNlMmFkMTkwY2I4ZTExOWQiLCJ2b3V0IjoxOSwic2NyaXB0U2lnIjp7ImFzbSI6IiIsImhleCI6IiJ9LCJ0eGlud2l0bmVzcyI6WyJiY2RlYjBmYWY3ZjlmYzQ1NTA1ZDg4YzkzYzg5MThmNGZkMGI5MjU2ZjM1YzI2NmUyYTZiMDA3Y2MyOTIzMmM0OTg4NGMzZjgyOGM4NTQ4N2I5ZjA5OWJhNGE2NzIyNDE2ZDQ4Y2YyOTJmYjcxODJmNmI2NzE3NjRjNDY1NTE4OSIsIjIwNWJjMzNhMDMyZDIxM2UwNjg4ZWU5NDkwM2M3NmE0ODE0YjViZWFmNWRiOTI5OThiNWZkOTAyMGFmMzE5YjM2ZGFjMDA2MzAzNmY3MjY0MDEwMTE4NzQ2NTc4NzQyZjcwNmM2MTY5NmUzYjYzNjg2MTcyNzM2NTc0M2Q3NTc0NjYyZDM4MDAzNTdiMjI3MDIyM2EyMjYyNzI2MzJkMzIzMDIyMmMyMjZmNzAyMjNhMjI2ZDY5NmU3NDIyMmMyMjc0Njk2MzZiMjIzYTIyNmQ2NTZkNjUyMjJjMjI2MTZkNzQyMjNhMjIzMTMwMzAzMDIyN2Q2OCIsImMwOTgzNzFjMTA4ZjY1YWM5M2MyZDA4OTAwYTBlYjZlYWNlOTBhNTQ3MTg2ODAxZmEyNTJiNDNlNTdlN2UyNzU1MSJdLCJzZXF1ZW5jZSI6NDI5NDk2NzI5NX1dLCJ2b3V0IjpbeyJ2YWx1ZSI6MC4wMDAwMDU0NiwibiI6MCwic2NyaXB0UHViS2V5Ijp7ImFzbSI6IjEgMmRlODUyMTQ4ZWQzMTY4ODU1NjRjNDQ2MmJkMGZkMDA2NjZkM2UwNzlkODUyMDE5ZTQxZjkwMjEyMDg3OGRkNSIsImhleCI6IjUxMjAyZGU4NTIxNDhlZDMxNjg4NTU2NGM0NDYyYmQwZmQwMDY2NmQzZTA3OWQ4NTIwMTllNDFmOTAyMTIwODc4ZGQ1IiwidHlwZSI6IndpdG5lc3NfdjFfdGFwcm9vdCJ9fV19LHsiaGV4IjoiMDIwMDAwMDAwMDAxMDE5NTQyMmRkNWY4YTExZDg2NzQ0N2YwMDVkMDVkOTI1OWFkZjU4ZmZjYTE3MzYzMmZmNGNjYjk5NmM1NTdkZWNkMGIwMDAwMDAwMGZmZmZmZmZmMDEyMjAyMDAwMDAwMDAwMDAwMjI1MTIwNDdlYjY5ZTVlODQwNmNkMjg3NWEzOWIyYmQ4YmM1YmIzZDhhMzdhOTg4ODVmMjgyZTc4OGMxNjE4N2FmYjFlZTAzNDA2YWY1OTkwMGU5N2NiODZhMTNkYzdjNzJjMGU1ODJmODJhYmQ2MDY1MTQ5Y2U1Njg3NzVlMTdlMGUzZTJkYWJiYWU0MDhlNWVjY2U1YTU0Y2FjOWRjYTEzZDY4MWEyMjJjZDcxZjlkODM2MjM5MTE3MWU0NmQ1NTZlM2JlOWRjNjdiMjBlOGI0MzUzZjFhMDQzYWVkZmVhZWMzNDZiY2UwNzBiNWQxNjZjZjllMmIwOGY3NzI4MTFhMDlkMjRkMDdjNzIxYWMwMDYzMDM2ZjcyNjQwMTAxMTg3NDY1Nzg3NDJmNzA2YzYxNjk2ZTNiNjM2ODYxNzI3MzY1NzQzZDc1NzQ2NjJkMzgwMDM1N2IyMjcwMjIzYTIyNjI3MjYzMmQzMjMwMjIyYzIyNmY3MDIyM2EyMjZkNjk2ZTc0MjIyYzIyNzQ2OTYzNmIyMjNhMjI1NTUzNDQ1NDIyMmMyMjYxNmQ3NDIyM2EyMjMxMzAzMDMwMjI3ZDY4MjFjMTMwYzA1ZGJlOWZjZmNiM2M2ZDYzYjhjNTRhNThiN2MzNDM4MDQ2ZjVkMjc1MzBlMzM2MTViOGMwZTM0NWRhYmEwMDAwMDAwMCIsInR4aWQiOiIxNTkyMDc4NGFmZTU5MjU4MjFjOWE3ZDdkZTA1ZDEyNzQyMmE2ZTgzN2ZlODkzODljMWMwOWVhZjMzMzdkMGY1IiwiaGFzaCI6IjI4OTA2NDY3ZGU0ZjU3YjdhMWVmMzgwYmMxNjdiZjNkNjRhMWU5OWEwNWZkMjFhZmFhZjBmMmIzMDNhYjUzYWYiLCJzaXplIjozMjAsInZzaXplIjoxNTEsIndlaWdodCI6NjAyLCJ2ZXJzaW9uIjoyLCJsb2NrdGltZSI6MCwidmluIjpbeyJ0eGlkIjoiY2RkZTU3YzU5NmI5Y2NmNDJmNjM3M2ExZmM4ZmY1YWQ1OTkyNWRkMDA1ZjA0Nzc0ODYxZGExZjhkNTJkNDI5NSIsInZvdXQiOjExLCJzY3JpcHRTaWciOnsiYXNtIjoiIiwiaGV4IjoiIn0sInR4aW53aXRuZXNzIjpbIjZhZjU5OTAwZTk3Y2I4NmExM2RjN2M3MmMwZTU4MmY4MmFiZDYwNjUxNDljZTU2ODc3NWUxN2UwZTNlMmRhYmJhZTQwOGU1ZWNjZTVhNTRjYWM5ZGNhMTNkNjgxYTIyMmNkNzFmOWQ4MzYyMzkxMTcxZTQ2ZDU1NmUzYmU5ZGM2IiwiMjBlOGI0MzUzZjFhMDQzYWVkZmVhZWMzNDZiY2UwNzBiNWQxNjZjZjllMmIwOGY3NzI4MTFhMDlkMjRkMDdjNzIxYWMwMDYzMDM2ZjcyNjQwMTAxMTg3NDY1Nzg3NDJmNzA2YzYxNjk2ZTNiNjM2ODYxNzI3MzY1NzQzZDc1NzQ2NjJkMzgwMDM1N2IyMjcwMjIzYTIyNjI3MjYzMmQzMjMwMjIyYzIyNmY3MDIyM2EyMjZkNjk2ZTc0MjIyYzIyNzQ2OTYzNmIyMjNhMjI1NTUzNDQ1NDIyMmMyMjYxNmQ3NDIyM2EyMjMxMzAzMDMwMjI3ZDY4IiwiYzEzMGMwNWRiZTlmY2ZjYjNjNmQ2M2I4YzU0YTU4YjdjMzQzODA0NmY1ZDI3NTMwZTMzNjE1YjhjMGUzNDVkYWJhIl0sInNlcXVlbmNlIjo0Mjk0OTY3Mjk1fV0sInZvdXQiOlt7InZhbHVlIjowLjAwMDAwNTQ2LCJuIjowLCJzY3JpcHRQdWJLZXkiOnsiYXNtIjoiMSA0N2ViNjllNWU4NDA2Y2QyODc1YTM5YjJiZDhiYzViYjNkOGEzN2E5ODg4NWYyODJlNzg4YzE2MTg3YWZiMWVlIiwiaGV4IjoiNTEyMDQ3ZWI2OWU1ZTg0MDZjZDI4NzVhMzliMmJkOGJjNWJiM2Q4YTM3YTk4ODg1ZjI4MmU3ODhjMTYxODdhZmIxZWUiLCJ0eXBlIjoid2l0bmVzc192MV90YXByb290In19XX0seyJoZXgiOiIwMjAwMDAwMDAwMDEwMTk1NDIyZGQ1ZjhhMTFkODY3NDQ3ZjAwNWQwNWQ5MjU5YWRmNThmZmNhMTczNjMyZmY0Y2NiOTk2YzU1N2RlY2QxMzAwMDAwMDAwZmZmZmZmZmYwMTIyMDIwMDAwMDAwMDAwMDAyMjUxMjA0N2ViNjllNWU4NDA2Y2QyODc1YTM5YjJiZDhiYzViYjNkOGEzN2E5ODg4NWYyODJlNzg4YzE2MTg3YWZiMWVlMDM0MGEzNDk0YjgyZWJjMTg1NTQxNjVjM2EyZjNjMzg2OTYyMjM1ZGY2ZTI2YTE4NDljNTY2NTllZjkwYjMxMTQ5YTEyMzNjMmIxYWNjMzZjY2M2MzI2NWI2NGNkNmM3N2I5Y2I4M2Q3ODVlMWMyM2E1MzQwY2Y2ZDlkZjQxYjE4MDZlN2IyMDVkNzNiZjQ0OTlkNWM1ODM3MDc1YWU1ODQ0ZjZjMjg4MTNjMjk2NGMwYmE2NGM4MTJkMGI2OGI3M2JkZDUyZDZhYzAwNjMwMzZmNzI2NDAxMDExODc0NjU3ODc0MmY3MDZjNjE2OTZlM2I2MzY4NjE3MjczNjU3NDNkNzU3NDY2MmQzODAwMzU3YjIyNzAyMjNhMjI2MjcyNjMyZDMyMzAyMjJjMjI2ZjcwMjIzYTIyNmQ2OTZlNzQyMjJjMjI3NDY5NjM2YjIyM2EyMjU1NTM0NDU0MjIyYzIyNjE2ZDc0MjIzYTIyMzEzMDMwMzAyMjdkNjgyMWMxMzBjMDVkYmU5ZmNmY2IzYzZkNjNiOGM1NGE1OGI3YzM0MzgwNDZmNWQyNzUzMGUzMzYxNWI4YzBlMzQ1ZGFiYTAwMDAwMDAwIiwidHhpZCI6IjZhOGQ1YmExNDQzMDAzODljN2NhOGFmMjRmMzNkMjcxNGZjMmY3ZGI4YWEzYjc4MWJjNmVmMDk0YjE3MDIwZjkiLCJoYXNoIjoiOWU2ZmRkNzIxYWQ2MTdlYmQzOWE4MDcyZGRlNmY5OWJjMWQ2NjA2NzQ4NjFkN2RiNWFiY2M1ZDlkMDVjMjFmYSIsInNpemUiOjMyMCwidnNpemUiOjE1MSwid2VpZ2h0Ijo2MDIsInZlcnNpb24iOjIsImxvY2t0aW1lIjowLCJ2aW4iOlt7InR4aWQiOiJjZGRlNTdjNTk2YjljY2Y0MmY2MzczYTFmYzhmZjVhZDU5OTI1ZGQwMDVmMDQ3NzQ4NjFkYTFmOGQ1MmQ0Mjk1Iiwidm91dCI6MTksInNjcmlwdFNpZyI6eyJhc20iOiIiLCJoZXgiOiIifSwidHhpbndpdG5lc3MiOlsiYTM0OTRiODJlYmMxODU1NDE2NWMzYTJmM2MzODY5NjIyMzVkZjZlMjZhMTg0OWM1NjY1OWVmOTBiMzExNDlhMTIzM2MyYjFhY2MzNmNjYzYzMjY1YjY0Y2Q2Yzc3YjljYjgzZDc4NWUxYzIzYTUzNDBjZjZkOWRmNDFiMTgwNmUiLCIyMDVkNzNiZjQ0OTlkNWM1ODM3MDc1YWU1ODQ0ZjZjMjg4MTNjMjk2NGMwYmE2NGM4MTJkMGI2OGI3M2JkZDUyZDZhYzAwNjMwMzZmNzI2NDAxMDExODc0NjU3ODc0MmY3MDZjNjE2OTZlM2I2MzY4NjE3MjczNjU3NDNkNzU3NDY2MmQzODAwMzU3YjIyNzAyMjNhMjI2MjcyNjMyZDMyMzAyMjJjMjI2ZjcwMjIzYTIyNmQ2OTZlNzQyMjJjMjI3NDY5NjM2YjIyM2EyMjU1NTM0NDU0MjIyYzIyNjE2ZDc0MjIzYTIyMzEzMDMwMzAyMjdkNjgiLCJjMTMwYzA1ZGJlOWZjZmNiM2M2ZDYzYjhjNTRhNThiN2MzNDM4MDQ2ZjVkMjc1MzBlMzM2MTViOGMwZTM0NWRhYmEiXSwic2VxdWVuY2UiOjQyOTQ5NjcyOTV9XSwidm91dCI6W3sidmFsdWUiOjAuMDAwMDA1NDYsIm4iOjAsInNjcmlwdFB1YktleSI6eyJhc20iOiIxIDQ3ZWI2OWU1ZTg0MDZjZDI4NzVhMzliMmJkOGJjNWJiM2Q4YTM3YTk4ODg1ZjI4MmU3ODhjMTYxODdhZmIxZWUiLCJoZXgiOiI1MTIwNDdlYjY5ZTVlODQwNmNkMjg3NWEzOWIyYmQ4YmM1YmIzZDhhMzdhOTg4ODVmMjgyZTc4OGMxNjE4N2FmYjFlZSIsInR5cGUiOiJ3aXRuZXNzX3YxX3RhcHJvb3QifX1dfV0sInRpbWUiOjE2OTU4NjAyMTgsIm5vbmNlIjo5NjYxMTk0NTQsImJpdHMiOiIxZDAwZmZmZiIsImRpZmZpY3VsdHkiOjEsInByZXZpb3VzYmxvY2toYXNoIjoiMDAwMDAwMDAwMDAwMDAyZDZiM2EwMTcwMTM4NzYzOWUzZjExYzJkY2I0OGQzMmFlMjRkMmYwZTEwMmY0MTkwNiIsIm5leHRibG9ja2hhc2giOiIwMDAwMDAwMDAwMDAwMDFhOWE2MjcwMTY0ZmNhYTg3MTBhY2ExYzU0NmQ1OTA1MjQyZGNmZWUyZjk4ODRjYmJhIn0=" + } + ] +} \ No newline at end of file diff --git a/common/utils.go b/common/utils.go new file mode 100644 index 0000000000..80f6701736 --- /dev/null +++ b/common/utils.go @@ -0,0 +1,47 @@ +package common + +import ( + "encoding/hex" + "fmt" + + "github.com/btcsuite/btcd/chaincfg/chainhash" + ethcommon "github.com/ethereum/go-ethereum/common" +) + +const ( + DustUTXOOffset = 2000 +) + +// A very special value to mark current nonce in UTXO +func NonceMarkAmount(nonce uint64) int64 { + // #nosec G701 always in range + return int64(nonce) + DustUTXOOffset // +2000 to avoid being a dust rejection +} + +// HashToString convert hash bytes to string +func HashToString(chainID int64, blockHash []byte) (string, error) { + if IsEVMChain(chainID) { + return hex.EncodeToString(blockHash), nil + } else if IsBitcoinChain(chainID) { + hash, err := chainhash.NewHash(blockHash) + if err != nil { + return "", err + } + return hash.String(), nil + } + return "", fmt.Errorf("cannot convert hash to string for chain %d", chainID) +} + +// StringToHash convert string to hash bytes +func StringToHash(chainID int64, hash string) ([]byte, error) { + if IsEVMChain(chainID) { + return ethcommon.HexToHash(hash).Bytes(), nil + } else if IsBitcoinChain(chainID) { + hash, err := chainhash.NewHashFromStr(hash) + if err != nil { + return nil, err + } + return hash.CloneBytes(), nil + } + return nil, fmt.Errorf("cannot convert hash to bytes for chain %d", chainID) +} diff --git a/contrib/localnet/orchestrator/smoketest/test_bitcoin.go b/contrib/localnet/orchestrator/smoketest/test_bitcoin.go index 736a2a1bfc..e6812f86fe 100644 --- a/contrib/localnet/orchestrator/smoketest/test_bitcoin.go +++ b/contrib/localnet/orchestrator/smoketest/test_bitcoin.go @@ -5,6 +5,7 @@ package main import ( "bytes" + "context" "encoding/hex" "fmt" "math/big" @@ -23,6 +24,8 @@ import ( "github.com/rs/zerolog/log" zrc20 "github.com/zeta-chain/protocol-contracts/pkg/contracts/zevm/zrc20.sol" "github.com/zeta-chain/zetacore/common" + "github.com/zeta-chain/zetacore/common/bitcoin" + observertypes "github.com/zeta-chain/zetacore/x/observer/types" "github.com/zeta-chain/zetacore/zetaclient" ) @@ -118,11 +121,11 @@ func (sm *SmokeTest) DepositBTC() { fmt.Printf(" spendableAmount: %f\n", spendableAmount) fmt.Printf(" spendableUTXOs: %d\n", spendableUTXOs) fmt.Printf("Now sending two txs to TSS address...\n") - _, err = SendToTSSFromDeployerToDeposit(BTCTSSAddress, 1.1, utxos[:2], btc) + txHash_1, err := SendToTSSFromDeployerToDeposit(BTCTSSAddress, 1.1, utxos[:2], btc) if err != nil { panic(err) } - _, err = SendToTSSFromDeployerToDeposit(BTCTSSAddress, 0.05, utxos[2:4], btc) + txHash_2, err := SendToTSSFromDeployerToDeposit(BTCTSSAddress, 0.05, utxos[2:4], btc) if err != nil { panic(err) } @@ -165,6 +168,87 @@ func (sm *SmokeTest) DepositBTC() { break } } + + // prove the two transactions of the deposit + LoudPrintf("Bitcoin Merkle Proof\n") + + sm.ProveBTCTransaction(txHash_1) + sm.ProveBTCTransaction(txHash_2) +} + +func (sm *SmokeTest) ProveBTCTransaction(txHash *chainhash.Hash) { + // get tx result + btc := sm.btcRPCClient + txResult, err := btc.GetTransaction(txHash) + if err != nil { + panic("should get outTx result") + } + if txResult.Confirmations <= 0 { + panic("outTx should have already confirmed") + } + txBytes, err := hex.DecodeString(txResult.Hex) + if err != nil { + panic(err) + } + + // get the block with verbose transactions + blockHash, err := chainhash.NewHashFromStr(txResult.BlockHash) + if err != nil { + panic(err) + } + blockVerbose, err := btc.GetBlockVerboseTx(blockHash) + if err != nil { + panic("should get block verbose tx") + } + + // get the block header + header, err := btc.GetBlockHeader(blockHash) + if err != nil { + panic("should get block header") + } + + // collect all the txs in the block + txns := []*btcutil.Tx{} + for _, res := range blockVerbose.Tx { + txBytes, err := hex.DecodeString(res.Hex) + if err != nil { + panic(err) + } + tx, err := btcutil.NewTxFromBytes(txBytes) + if err != nil { + panic(err) + } + txns = append(txns, tx) + } + + // build merkle proof + mk := bitcoin.NewMerkle(txns) + path, index, err := mk.BuildMerkleProof(int(txResult.BlockIndex)) + if err != nil { + panic("should build merkle proof") + } + + // verify merkle proof statically + pass := bitcoin.Prove(*txHash, header.MerkleRoot, path, index) + if !pass { + panic("should verify merkle proof") + } + + // verify merkle proof through RPC + res, err := sm.observerClient.Prove(context.Background(), &observertypes.QueryProveRequest{ + ChainId: common.BtcRegtestChain().ChainId, + TxHash: txHash.String(), + BlockHash: blockHash.String(), + Proof: common.NewBitcoinProof(txBytes, path, index), + TxIndex: 0, // bitcoin doesn't use txIndex + }) + if err != nil { + panic(err) + } + if !res.Valid { + panic("txProof should be valid") + } + fmt.Printf("OK: txProof verified for inTx: %s\n", txHash.String()) } func (sm *SmokeTest) DepositBTCRefund() { diff --git a/contrib/localnet/orchestrator/smoketest/test_deposit_eth.go b/contrib/localnet/orchestrator/smoketest/test_deposit_eth.go index 904d1858e4..b9da61416c 100644 --- a/contrib/localnet/orchestrator/smoketest/test_deposit_eth.go +++ b/contrib/localnet/orchestrator/smoketest/test_deposit_eth.go @@ -126,7 +126,7 @@ func (sm *SmokeTest) TestDepositEtherIntoZRC20() { TxIndex: int64(txIndex), TxHash: txHash.Hex(), Proof: common.NewEthereumProof(txProof), - ChainId: 0, + ChainId: common.GoerliChain().ChainId, }) if err != nil { panic(err) diff --git a/docs/openapi/openapi.swagger.yaml b/docs/openapi/openapi.swagger.yaml index 493ed11c53..2bd9ef4e4b 100644 --- a/docs/openapi/openapi.swagger.yaml +++ b/docs/openapi/openapi.swagger.yaml @@ -27631,7 +27631,7 @@ paths: in: query required: false type: string - format: uint64 + format: int64 - name: tx_hash in: query required: false @@ -27652,6 +27652,21 @@ paths: type: string format: byte collectionFormat: multi + - name: proof.bitcoin_proof.tx_bytes + in: query + required: false + type: string + format: byte + - name: proof.bitcoin_proof.path + in: query + required: false + type: string + format: byte + - name: proof.bitcoin_proof.index + in: query + required: false + type: integer + format: int64 - name: block_hash in: query required: false @@ -50228,6 +50243,18 @@ definitions: - VOTE_OPTION_ABSTAIN: VOTE_OPTION_ABSTAIN defines an abstain vote option. - VOTE_OPTION_NO: VOTE_OPTION_NO defines a no vote option. - VOTE_OPTION_NO_WITH_VETO: VOTE_OPTION_NO_WITH_VETO defines a no with veto vote option. + bitcoinProof: + type: object + properties: + tx_bytes: + type: string + format: byte + path: + type: string + format: byte + index: + type: integer + format: int64 commonBlockHeader: type: object properties: @@ -50298,11 +50325,17 @@ definitions: type: string format: byte title: binary encoded headers; RLP for ethereum + bitcoin_header: + type: string + format: byte + title: 80-byte little-endian encoded binary data commonProof: type: object properties: ethereum_proof: $ref: '#/definitions/ethereumProof' + bitcoin_proof: + $ref: '#/definitions/bitcoinProof' commonPubKeySet: type: object properties: diff --git a/proto/common/bitcoin/bitcoin.proto b/proto/common/bitcoin/bitcoin.proto new file mode 100644 index 0000000000..dc1df2fa42 --- /dev/null +++ b/proto/common/bitcoin/bitcoin.proto @@ -0,0 +1,10 @@ +syntax = "proto3"; +package bitcoin; + +option go_package = "github.com/zeta-chain/zetacore/common/bitcoin"; + +message Proof { + bytes tx_bytes = 1; + bytes path = 2; + uint32 index = 3; +} diff --git a/proto/common/common.proto b/proto/common/common.proto index 161f533034..d6b1dcf99b 100644 --- a/proto/common/common.proto +++ b/proto/common/common.proto @@ -1,6 +1,7 @@ syntax = "proto3"; package common; +import "common/bitcoin/bitcoin.proto"; import "common/ethereum/ethereum.proto"; //option (gogoproto.goproto_stringer_all) = false; //option (gogoproto.stringer_all) = false; @@ -75,11 +76,13 @@ message BlockHeader { message HeaderData { oneof data { bytes ethereum_header = 1; // binary encoded headers; RLP for ethereum + bytes bitcoin_header = 2; // 80-byte little-endian encoded binary data } } message Proof { oneof proof { ethereum.Proof ethereum_proof = 1; + bitcoin.Proof bitcoin_proof = 2; } } diff --git a/proto/observer/query.proto b/proto/observer/query.proto index 1de4b9df30..2f4b26a8f7 100644 --- a/proto/observer/query.proto +++ b/proto/observer/query.proto @@ -100,7 +100,7 @@ service Query { } message QueryProveRequest { - uint64 chain_id = 1; + int64 chain_id = 1; string tx_hash = 2; common.Proof proof = 3; string block_hash = 4; diff --git a/x/crosschain/keeper/keeper_out_tx_tracker.go b/x/crosschain/keeper/keeper_out_tx_tracker.go index a11329aea2..0eb2a7191a 100644 --- a/x/crosschain/keeper/keeper_out_tx_tracker.go +++ b/x/crosschain/keeper/keeper_out_tx_tracker.go @@ -3,10 +3,13 @@ package keeper import ( "context" "fmt" + "math/big" "strings" cosmoserrors "cosmossdk.io/errors" + "github.com/btcsuite/btcd/btcec" + "github.com/btcsuite/btcutil" "github.com/cosmos/cosmos-sdk/store/prefix" sdk "github.com/cosmos/cosmos-sdk/types" "github.com/cosmos/cosmos-sdk/types/query" @@ -15,6 +18,7 @@ import ( "github.com/zeta-chain/zetacore/common" "github.com/zeta-chain/zetacore/x/crosschain/types" observertypes "github.com/zeta-chain/zetacore/x/observer/types" + "github.com/zeta-chain/zetacore/zetaclient/config" "google.golang.org/grpc/codes" "google.golang.org/grpc/status" ) @@ -183,43 +187,36 @@ func (k msgServer) AddToOutTxTracker(goCtx context.Context, msg *types.MsgAddToO proven := false if msg.Proof != nil { - blockHash := eth.HexToHash(msg.BlockHash) - res, found := k.zetaObserverKeeper.GetBlockHeader(ctx, blockHash.Bytes()) + blockHash, err := common.StringToHash(msg.ChainId, msg.BlockHash) + if err != nil { + return nil, cosmoserrors.Wrap(err, "block hash conversion failed") + } + res, found := k.zetaObserverKeeper.GetBlockHeader(ctx, blockHash) if !found { return nil, cosmoserrors.Wrap(observertypes.ErrBlockHeaderNotFound, fmt.Sprintf("block header not found %s", msg.BlockHash)) } - // verify and process the proof - val, err := msg.Proof.Verify(res.Header, int(msg.TxIndex)) + // verify outTx merkle proof + txBytes, err := msg.Proof.Verify(res.Header, int(msg.TxIndex)) if err != nil && !common.IsErrorInvalidProof(err) { return nil, err } if err == nil { - var txx ethtypes.Transaction - err = txx.UnmarshalBinary(val) + tss, err := k.GetTssAddress(ctx, &types.QueryGetTssAddressRequest{}) if err != nil { return nil, err } - signer := ethtypes.NewLondonSigner(txx.ChainId()) - sender, err := ethtypes.Sender(signer, &txx) - if err != nil { - return nil, err + // verify outTx transaction body + if common.IsEVMChain(msg.ChainId) { + err = ValidateEVMOutTxBody(msg, txBytes, tss.Eth) + } else if common.IsBitcoinChain(msg.ChainId) { + err = ValidateBTCOutTxBody(msg, txBytes, tss.Btc) + } else { + return nil, fmt.Errorf("unsupported chain id %d", msg.ChainId) } - res, err := k.GetTssAddress(ctx, &types.QueryGetTssAddressRequest{}) if err != nil { return nil, err } - tssAddr := eth.HexToAddress(res.Eth) - if tssAddr == (eth.Address{}) { - return nil, fmt.Errorf("tss address not found") - } - if sender != tssAddr { - return nil, fmt.Errorf("sender is not tss address") - } - if txx.Nonce() != msg.Nonce { - return nil, fmt.Errorf("nonce mismatch") - } - proven = true } if !proven { @@ -268,6 +265,76 @@ func (k msgServer) AddToOutTxTracker(goCtx context.Context, msg *types.MsgAddToO return &types.MsgAddToOutTxTrackerResponse{}, nil } +// ValidateEVMOutTxBody validates the sender address, nonce and chain ID. +// Note: 'msg' may contain fabricated information +func ValidateEVMOutTxBody(msg *types.MsgAddToOutTxTracker, txBytes []byte, tssEth string) error { + var txx ethtypes.Transaction + err := txx.UnmarshalBinary(txBytes) + if err != nil { + return err + } + signer := ethtypes.NewLondonSigner(txx.ChainId()) + sender, err := ethtypes.Sender(signer, &txx) + if err != nil { + return err + } + tssAddr := eth.HexToAddress(tssEth) + if tssAddr == (eth.Address{}) { + return fmt.Errorf("tss address not found") + } + if sender != tssAddr { + return fmt.Errorf("sender %s is not tss address", sender) + } + if txx.ChainId().Cmp(big.NewInt(msg.ChainId)) != 0 { + return fmt.Errorf("want evm chain id %d, got %d", txx.ChainId(), msg.ChainId) + } + if txx.Nonce() != msg.Nonce { + return fmt.Errorf("want nonce %d, got %d", txx.Nonce(), msg.Nonce) + } + if txx.Hash().Hex() != msg.TxHash { + return fmt.Errorf("want tx hash %s, got %s", txx.Hash().Hex(), msg.TxHash) + } + return nil +} + +// ValidateBTCOutTxBody validates the SegWit sender address, nonce and chain ID. +// Note: 'msg' may contain fabricated information +func ValidateBTCOutTxBody(msg *types.MsgAddToOutTxTracker, txBytes []byte, tssBtc string) error { + tx, err := btcutil.NewTxFromBytes(txBytes) + if err != nil { + return err + } + for _, vin := range tx.MsgTx().TxIn { + if len(vin.Witness) != 2 { // outTx is SegWit transaction for now + return fmt.Errorf("not a SegWit transaction") + } + pubKey, err := btcec.ParsePubKey(vin.Witness[1], btcec.S256()) + if err != nil { + return fmt.Errorf("failed to parse public key") + } + addrP2WPKH, err := btcutil.NewAddressWitnessPubKeyHash(btcutil.Hash160(pubKey.SerializeCompressed()), config.BitconNetParams) + if err != nil { + return fmt.Errorf("failed to create P2WPKH address") + } + if addrP2WPKH.EncodeAddress() != tssBtc { + return fmt.Errorf("sender %s is not tss address", addrP2WPKH.EncodeAddress()) + } + } + if common.BtcChainID() != msg.ChainId { + return fmt.Errorf("want btc chain id %d, got %d", common.BtcChainID(), msg.ChainId) + } + if len(tx.MsgTx().TxOut) < 1 { + return fmt.Errorf("outTx should have at least one output") + } + if tx.MsgTx().TxOut[0].Value != common.NonceMarkAmount(msg.Nonce) { + return fmt.Errorf("want nonce mark %d, got %d", tx.MsgTx().TxOut[0].Value, common.NonceMarkAmount(msg.Nonce)) + } + if tx.MsgTx().TxHash().String() != msg.TxHash { + return fmt.Errorf("want tx hash %s, got %s", tx.MsgTx().TxHash(), msg.TxHash) + } + return nil +} + // RemoveFromOutTxTracker removes a record from the outbound transaction tracker by chain ID and nonce. // only the admin policy account is authorized to broadcast this message. func (k msgServer) RemoveFromOutTxTracker(goCtx context.Context, msg *types.MsgRemoveFromOutTxTracker) (*types.MsgRemoveFromOutTxTrackerResponse, error) { diff --git a/x/observer/keeper/grpc_query_prove.go b/x/observer/keeper/grpc_query_prove.go index e4880f4c2e..6f184cebed 100644 --- a/x/observer/keeper/grpc_query_prove.go +++ b/x/observer/keeper/grpc_query_prove.go @@ -4,41 +4,63 @@ import ( "context" "fmt" + "github.com/btcsuite/btcutil" "github.com/zeta-chain/zetacore/common" sdk "github.com/cosmos/cosmos-sdk/types" - eth "github.com/ethereum/go-ethereum/common" ethtypes "github.com/ethereum/go-ethereum/core/types" "github.com/zeta-chain/zetacore/x/observer/types" "google.golang.org/grpc/codes" "google.golang.org/grpc/status" ) +// Prove simply checks two things: +// 1. the block header is available +// 2. the proof is valid func (k Keeper) Prove(c context.Context, req *types.QueryProveRequest) (*types.QueryProveResponse, error) { if req == nil { return nil, status.Error(codes.InvalidArgument, "invalid request") } ctx := sdk.UnwrapSDKContext(c) - blockHash := eth.HexToHash(req.BlockHash) - res, found := k.GetBlockHeader(ctx, blockHash.Bytes()) + blockHash, err := common.StringToHash(req.ChainId, req.BlockHash) + if err != nil { + return nil, status.Error(codes.InvalidArgument, err.Error()) + } + res, found := k.GetBlockHeader(ctx, blockHash) if !found { return nil, status.Error(codes.NotFound, "block header not found") } proven := false - val, err := req.Proof.Verify(res.Header, int(req.TxIndex)) + txBytes, err := req.Proof.Verify(res.Header, int(req.TxIndex)) if err != nil && !common.IsErrorInvalidProof(err) { return nil, status.Error(codes.Internal, err.Error()) } if err == nil { - var txx ethtypes.Transaction - err = txx.UnmarshalBinary(val) - if err != nil { - return nil, status.Error(codes.Internal, fmt.Sprintf("failed to unmarshal transaction: %s", err)) + if common.IsEVMChain(req.ChainId) { + var txx ethtypes.Transaction + err = txx.UnmarshalBinary(txBytes) + if err != nil { + return nil, status.Error(codes.Internal, fmt.Sprintf("failed to unmarshal evm transaction: %s", err)) + } + if txx.Hash().Hex() != req.TxHash { + return nil, status.Error(codes.InvalidArgument, fmt.Sprintf("tx hash mismatch: %s != %s", txx.Hash().Hex(), req.TxHash)) + } + proven = true + } else if common.IsBitcoinChain(req.ChainId) { + tx, err := btcutil.NewTxFromBytes(txBytes) + if err != nil { + return nil, status.Error(codes.Internal, fmt.Sprintf("failed to unmarshal btc transaction: %s", err)) + } + if tx.MsgTx().TxHash().String() != req.TxHash { + return nil, status.Error(codes.InvalidArgument, fmt.Sprintf("tx hash mismatch: %s != %s", tx.MsgTx().TxHash().String(), req.TxHash)) + } + proven = true + } else { + return nil, status.Error(codes.InvalidArgument, fmt.Sprintf("invalid chain id (%d)", req.ChainId)) } - proven = true } return &types.QueryProveResponse{ diff --git a/x/observer/keeper/msg_server_add_block_header.go b/x/observer/keeper/msg_server_add_block_header.go index 185fd9d061..cfc3e32bcd 100644 --- a/x/observer/keeper/msg_server_add_block_header.go +++ b/x/observer/keeper/msg_server_add_block_header.go @@ -2,7 +2,6 @@ package keeper import ( "context" - "encoding/hex" cosmoserrors "cosmossdk.io/errors" @@ -40,7 +39,17 @@ func (k msgServer) AddBlockHeader(goCtx context.Context, msg *types.MsgAddBlockH */ _, found := k.GetBlockHeader(ctx, msg.BlockHash) if found { - return nil, cosmoserrors.Wrap(types.ErrBlockAlreadyExist, hex.EncodeToString(msg.BlockHash)) + hashString, err := common.HashToString(msg.ChainId, msg.BlockHash) + if err != nil { + return nil, cosmoserrors.Wrap(err, "block hash conversion failed") + } + return nil, cosmoserrors.Wrap(types.ErrBlockAlreadyExist, hashString) + } + + // Check timestamp + err = msg.Header.ValidateTimestamp(ctx.BlockTime()) + if err != nil { + return nil, cosmoserrors.Wrap(types.ErrInvalidTimestamp, err.Error()) } // NOTE: error is checked in BasicValidation in msg; check again for extra caution diff --git a/x/observer/types/errors.go b/x/observer/types/errors.go index afe8422699..3767712e34 100644 --- a/x/observer/types/errors.go +++ b/x/observer/types/errors.go @@ -29,4 +29,5 @@ var ( ErrUnrecognizedBlockHeader = errorsmod.Register(ModuleName, 1118, "unrecognized block header") ErrBlockAlreadyExist = errorsmod.Register(ModuleName, 1119, "block already exists") ErrNoParentHash = errorsmod.Register(ModuleName, 1120, "no parent hash") + ErrInvalidTimestamp = errorsmod.Register(ModuleName, 1121, "invalid timestamp") ) diff --git a/x/observer/types/messages_add_block_header.go b/x/observer/types/messages_add_block_header.go index 8db4410195..453a2f1b10 100644 --- a/x/observer/types/messages_add_block_header.go +++ b/x/observer/types/messages_add_block_header.go @@ -52,15 +52,15 @@ func (msg *MsgAddBlockHeader) ValidateBasic() error { return cosmoserrors.Wrapf(sdkerrors.ErrInvalidAddress, err.Error()) } - if common.IsEthereum(msg.ChainId) { - if len(msg.BlockHash) > 32 { - return cosmoserrors.Wrapf(sdkerrors.ErrInvalidRequest, "invalid msg.txhash; too long (%d)", len(msg.BlockHash)) + if common.IsEthereum(msg.ChainId) || common.IsBitcoinChain(msg.ChainId) { + if len(msg.BlockHash) != 32 { + return cosmoserrors.Wrapf(sdkerrors.ErrInvalidRequest, "invalid block hash length (%d)", len(msg.BlockHash)) } } else { return cosmoserrors.Wrapf(sdkerrors.ErrInvalidRequest, "invalid chain id (%d)", msg.ChainId) } - if err := msg.Header.Validate(msg.BlockHash, msg.Height); err != nil { + if err := msg.Header.Validate(msg.BlockHash, msg.ChainId, msg.Height); err != nil { return cosmoserrors.Wrapf(sdkerrors.ErrInvalidRequest, "invalid block header (%s)", err) } diff --git a/x/observer/types/query.pb.go b/x/observer/types/query.pb.go index 16985b39b0..cb9c9a1953 100644 --- a/x/observer/types/query.pb.go +++ b/x/observer/types/query.pb.go @@ -33,7 +33,7 @@ var _ = math.Inf const _ = proto.GoGoProtoPackageIsVersion3 // please upgrade the proto package type QueryProveRequest struct { - ChainId uint64 `protobuf:"varint,1,opt,name=chain_id,json=chainId,proto3" json:"chain_id,omitempty"` + ChainId int64 `protobuf:"varint,1,opt,name=chain_id,json=chainId,proto3" json:"chain_id,omitempty"` TxHash string `protobuf:"bytes,2,opt,name=tx_hash,json=txHash,proto3" json:"tx_hash,omitempty"` Proof *common.Proof `protobuf:"bytes,3,opt,name=proof,proto3" json:"proof,omitempty"` BlockHash string `protobuf:"bytes,4,opt,name=block_hash,json=blockHash,proto3" json:"block_hash,omitempty"` @@ -73,7 +73,7 @@ func (m *QueryProveRequest) XXX_DiscardUnknown() { var xxx_messageInfo_QueryProveRequest proto.InternalMessageInfo -func (m *QueryProveRequest) GetChainId() uint64 { +func (m *QueryProveRequest) GetChainId() int64 { if m != nil { return m.ChainId } @@ -1729,126 +1729,125 @@ func init() { func init() { proto.RegisterFile("observer/query.proto", fileDescriptor_dcb801e455adaee4) } var fileDescriptor_dcb801e455adaee4 = []byte{ - // 1889 bytes of a gzipped FileDescriptorProto + // 1881 bytes of a gzipped FileDescriptorProto 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xac, 0x59, 0xcf, 0x6f, 0x1b, 0xc7, - 0x15, 0xf6, 0x8a, 0x16, 0x6d, 0x3d, 0x4a, 0x96, 0x34, 0x92, 0x62, 0x79, 0x25, 0x51, 0xec, 0xa8, - 0x76, 0x68, 0xc9, 0xe1, 0x46, 0x34, 0x90, 0xd8, 0x51, 0xa4, 0x94, 0x14, 0x62, 0x59, 0xb1, 0xe3, - 0xb8, 0x54, 0x9b, 0x16, 0x2d, 0x5a, 0x62, 0x49, 0x8e, 0x28, 0x26, 0xab, 0x1d, 0x66, 0x77, 0xa5, - 0x88, 0x15, 0x04, 0x14, 0x3d, 0xf7, 0x10, 0xa0, 0x40, 0xcf, 0x3d, 0xf5, 0xd6, 0x1e, 0x72, 0xe9, - 0xa1, 0xe8, 0xa5, 0x97, 0xe6, 0x54, 0xa4, 0x28, 0x50, 0xb4, 0x87, 0x16, 0x81, 0xdd, 0x3f, 0xa0, + 0x15, 0xd6, 0x4a, 0x11, 0x23, 0x3d, 0x4a, 0x96, 0x34, 0xa2, 0x62, 0x79, 0x25, 0x51, 0xea, 0xa8, + 0x76, 0x64, 0xc9, 0xe1, 0x46, 0x34, 0x90, 0xd8, 0x51, 0xa4, 0x94, 0x14, 0x62, 0x59, 0xb1, 0xe3, + 0xb8, 0x54, 0x9b, 0x16, 0x2d, 0x5a, 0x62, 0x49, 0x8e, 0x28, 0x26, 0xab, 0x1d, 0x66, 0x77, 0x25, + 0x8b, 0x15, 0x04, 0x14, 0x3d, 0xf7, 0x60, 0xa0, 0x40, 0xcf, 0x3d, 0xf5, 0xd6, 0x1e, 0x7c, 0xe9, + 0xa1, 0xe8, 0xa5, 0x97, 0xfa, 0x54, 0xb8, 0x28, 0x50, 0xb4, 0x87, 0x16, 0x86, 0xdd, 0x3f, 0xa0, 0x7f, 0x42, 0x31, 0x3f, 0x76, 0x39, 0x5c, 0xee, 0x92, 0x4b, 0xc1, 0x27, 0x71, 0x67, 0xe6, 0xbd, - 0xf9, 0xbe, 0x37, 0x33, 0xef, 0xbd, 0x0f, 0x82, 0x79, 0x5a, 0x73, 0x89, 0x73, 0x4a, 0x1c, 0xe3, - 0xb3, 0x13, 0xe2, 0x74, 0x0a, 0x6d, 0x87, 0x7a, 0x14, 0x2d, 0xfd, 0x8c, 0x78, 0x66, 0xfd, 0xc8, - 0x6c, 0xd9, 0x05, 0xfe, 0x8b, 0x3a, 0xa4, 0xe0, 0x2f, 0xd4, 0xe7, 0xea, 0xf4, 0xf8, 0x98, 0xda, - 0x86, 0xf8, 0x23, 0x2c, 0xf4, 0xf5, 0x3a, 0x75, 0x8f, 0xa9, 0x6b, 0xd4, 0x4c, 0x97, 0x08, 0x57, - 0xc6, 0xe9, 0x66, 0x8d, 0x78, 0xe6, 0xa6, 0xd1, 0x36, 0x9b, 0x2d, 0xdb, 0xf4, 0x5a, 0xc1, 0xda, - 0xf9, 0x26, 0x6d, 0x52, 0xfe, 0xd3, 0x60, 0xbf, 0xe4, 0xe8, 0x72, 0x93, 0xd2, 0xa6, 0x45, 0x0c, - 0xb3, 0xdd, 0x32, 0x4c, 0xdb, 0xa6, 0x1e, 0x37, 0x71, 0xe5, 0xec, 0x42, 0x80, 0xb3, 0x66, 0x5a, - 0x16, 0xf5, 0x7c, 0x57, 0xdd, 0x61, 0xcb, 0x3c, 0x26, 0x72, 0x74, 0x35, 0x18, 0xad, 0x3b, 0xd4, - 0x75, 0x39, 0x91, 0xea, 0xa1, 0x65, 0x36, 0xfb, 0xbd, 0x7d, 0x4a, 0x3a, 0x4d, 0xe2, 0x03, 0x5b, - 0x0a, 0x86, 0x6d, 0xda, 0x20, 0x55, 0xb3, 0x5e, 0xa7, 0x27, 0xb6, 0xbf, 0xd5, 0xcd, 0x60, 0xd2, - 0xff, 0xd1, 0xe7, 0xac, 0x6d, 0x3a, 0xe6, 0xb1, 0xdc, 0x03, 0xff, 0x56, 0x83, 0xd9, 0xef, 0xb2, - 0x40, 0x3c, 0x77, 0xe8, 0x29, 0xa9, 0x90, 0xcf, 0x4e, 0x88, 0xeb, 0xa1, 0x5b, 0x70, 0x5d, 0xc0, - 0x69, 0x35, 0x16, 0xb5, 0x9c, 0x96, 0xbf, 0x5a, 0xb9, 0xc6, 0xbf, 0xf7, 0x1b, 0xe8, 0x26, 0x5c, - 0xf3, 0xce, 0xaa, 0x47, 0xa6, 0x7b, 0xb4, 0x38, 0x96, 0xd3, 0xf2, 0x13, 0x95, 0xb4, 0x77, 0xf6, - 0xd8, 0x74, 0x8f, 0xd0, 0x1a, 0x8c, 0xb7, 0x1d, 0x4a, 0x0f, 0x17, 0x53, 0x39, 0x2d, 0x9f, 0x29, - 0x4e, 0x15, 0x64, 0xe4, 0x9f, 0xb3, 0xc1, 0x8a, 0x98, 0x43, 0x2b, 0x00, 0x35, 0x8b, 0xd6, 0x3f, - 0x15, 0x0e, 0xae, 0x72, 0x07, 0x13, 0x7c, 0x84, 0xfb, 0xb8, 0x05, 0xd7, 0xbd, 0xb3, 0x6a, 0xcb, - 0x6e, 0x90, 0xb3, 0xc5, 0xf1, 0x9c, 0x96, 0x4f, 0x55, 0xae, 0x79, 0x67, 0xfb, 0xec, 0x13, 0xaf, - 0x03, 0x52, 0x71, 0xba, 0x6d, 0x6a, 0xbb, 0x04, 0xcd, 0xc3, 0xf8, 0xa9, 0x69, 0x49, 0x94, 0xd7, - 0x2b, 0xe2, 0x03, 0xcf, 0xfb, 0x6b, 0x39, 0x53, 0x49, 0x0a, 0xff, 0x10, 0xe6, 0x7a, 0x46, 0xa5, - 0x8b, 0x12, 0xa4, 0x45, 0x44, 0xb8, 0x8f, 0x4c, 0x71, 0xad, 0x30, 0xe0, 0x5a, 0x15, 0x84, 0x71, - 0xf9, 0xea, 0x57, 0xff, 0x59, 0xbd, 0x52, 0x91, 0x86, 0xf8, 0x43, 0xc8, 0x72, 0xcf, 0x65, 0x7e, - 0xe8, 0xe5, 0xce, 0x7e, 0x83, 0xd8, 0x5e, 0xeb, 0xb0, 0x45, 0x1c, 0x3f, 0xa0, 0x1b, 0x30, 0x2b, - 0x6e, 0x44, 0xb5, 0x15, 0xcc, 0xf1, 0xfd, 0x26, 0x2a, 0x33, 0x62, 0xa2, 0x6b, 0x83, 0x3d, 0x98, - 0xf8, 0x98, 0x7a, 0xc4, 0x79, 0xda, 0x72, 0x3d, 0xb4, 0x06, 0x53, 0xa7, 0xec, 0xa3, 0x6a, 0x36, - 0x1a, 0x0e, 0x71, 0x5d, 0x69, 0x35, 0xc9, 0x07, 0x4b, 0x62, 0x0c, 0x95, 0x61, 0x82, 0x7d, 0x57, - 0xbd, 0x4e, 0x9b, 0xf0, 0x63, 0xb9, 0x51, 0xbc, 0x3d, 0x90, 0x06, 0xf3, 0xff, 0xbd, 0x4e, 0x9b, - 0x54, 0xae, 0x9f, 0xca, 0x5f, 0xf8, 0x0f, 0x63, 0xb0, 0x1a, 0xcb, 0x42, 0xc6, 0x6a, 0x14, 0x1a, - 0x68, 0x07, 0xd2, 0x1c, 0xa4, 0xbb, 0x38, 0x96, 0x4b, 0xe5, 0x33, 0xc5, 0x3b, 0x43, 0x11, 0x71, - 0xc6, 0x15, 0x69, 0x85, 0x7e, 0x00, 0x33, 0x62, 0x96, 0x3f, 0x31, 0xc1, 0x2d, 0xc5, 0xb9, 0xdd, - 0x1b, 0xe8, 0xe9, 0xa3, 0xae, 0x11, 0xa7, 0x38, 0x4d, 0x7b, 0x07, 0xd0, 0x33, 0x98, 0x92, 0x2c, - 0x5c, 0xcf, 0xf4, 0x4e, 0x5c, 0x7e, 0x0f, 0x6f, 0x14, 0xef, 0x0e, 0xf4, 0x2a, 0xa2, 0x72, 0xc0, - 0x0d, 0x2a, 0x93, 0x35, 0xe5, 0x0b, 0x3f, 0x81, 0x65, 0x1e, 0xb8, 0x8f, 0xe4, 0x5a, 0xb7, 0xdc, - 0xd9, 0x65, 0x5e, 0x94, 0xc3, 0x57, 0x89, 0xf0, 0x1d, 0xfc, 0xa8, 0x29, 0x13, 0xdc, 0x06, 0x6f, - 0xc3, 0x4a, 0x8c, 0x33, 0x79, 0x06, 0xcb, 0x30, 0xe1, 0x83, 0x62, 0x97, 0x21, 0xc5, 0x5e, 0x50, - 0x30, 0x80, 0x73, 0xf2, 0x2a, 0x96, 0x2c, 0xcb, 0xf7, 0xf0, 0xa1, 0xd9, 0x6e, 0x13, 0x27, 0x78, - 0x06, 0x1d, 0x79, 0xcc, 0x51, 0x2b, 0xe4, 0x16, 0x1f, 0xfb, 0x91, 0x27, 0x4e, 0xf5, 0x58, 0xcc, - 0xf1, 0x9d, 0x32, 0xc5, 0x8d, 0x04, 0x91, 0xf7, 0xfd, 0xf9, 0x81, 0x0f, 0xfc, 0xe3, 0xd7, 0x60, - 0x9e, 0x6f, 0x7d, 0x70, 0xd2, 0x6e, 0x53, 0xc7, 0x23, 0x0d, 0xce, 0xcc, 0xc5, 0xef, 0xcb, 0x00, - 0x86, 0xc6, 0x03, 0x3c, 0xb7, 0x21, 0xcd, 0xb7, 0xf4, 0x51, 0x04, 0xb9, 0x45, 0x44, 0x46, 0x4e, - 0xe2, 0x1d, 0xf8, 0x16, 0x77, 0xb3, 0x47, 0xbc, 0x5d, 0xea, 0x10, 0xf1, 0x54, 0x1f, 0x51, 0xa7, - 0xe7, 0x30, 0xc2, 0xa9, 0x2d, 0x15, 0xa4, 0x36, 0x6c, 0x03, 0x1e, 0x64, 0x2f, 0xc1, 0x3c, 0x86, - 0x0c, 0x63, 0x5d, 0xed, 0x49, 0x1a, 0xaf, 0x0f, 0x8c, 0x4b, 0xd7, 0x5b, 0x05, 0xea, 0xc1, 0x6f, - 0xbc, 0x04, 0xb7, 0xfa, 0xf7, 0xf3, 0x8f, 0xe9, 0x13, 0xd0, 0xa3, 0x26, 0x25, 0x88, 0xa7, 0x51, - 0x20, 0x36, 0x12, 0x82, 0xe0, 0xaf, 0x4c, 0x05, 0x52, 0xec, 0xee, 0xf5, 0x8c, 0x36, 0x48, 0x49, - 0x54, 0x14, 0x3f, 0x62, 0xf3, 0x30, 0x2e, 0x32, 0xb2, 0xb8, 0xb2, 0xe2, 0x03, 0x7f, 0x02, 0x4b, - 0x91, 0x36, 0x12, 0xe0, 0x13, 0x98, 0x54, 0xab, 0x93, 0x44, 0x98, 0x1f, 0x88, 0x50, 0xf5, 0x93, - 0xb1, 0xbb, 0x1f, 0xb8, 0x21, 0xf1, 0x95, 0x2c, 0x2b, 0x02, 0xdf, 0x23, 0x80, 0x6e, 0xf1, 0x96, - 0x1b, 0xdd, 0x29, 0x88, 0x4a, 0x5f, 0x60, 0x95, 0xbe, 0x20, 0x9a, 0x06, 0x59, 0xe9, 0x0b, 0xcf, - 0xcd, 0xa6, 0x5f, 0xe8, 0x2a, 0x8a, 0x25, 0xfe, 0x52, 0x93, 0x94, 0xc2, 0xdb, 0x48, 0x4a, 0x1f, - 0x40, 0x46, 0x19, 0x96, 0x57, 0x71, 0x04, 0x46, 0xca, 0x07, 0xda, 0xeb, 0xc1, 0x3c, 0x26, 0xef, - 0xd0, 0x30, 0xcc, 0x02, 0x48, 0x0f, 0x68, 0xff, 0xbd, 0xb3, 0x6b, 0x12, 0x74, 0x11, 0x8f, 0x58, - 0x13, 0xe1, 0x5f, 0xa4, 0x9f, 0x6b, 0xf2, 0xc1, 0x47, 0x2d, 0x91, 0xd4, 0x7e, 0x02, 0x33, 0xe1, - 0x1e, 0x44, 0x06, 0x72, 0x70, 0xaa, 0x0d, 0xf9, 0x93, 0x65, 0x71, 0xba, 0xde, 0x3b, 0x8c, 0x6f, - 0xc2, 0x82, 0x8f, 0xe0, 0x09, 0xef, 0x64, 0x7c, 0x6c, 0xdf, 0x87, 0xd7, 0xc2, 0x13, 0x12, 0xd1, - 0x16, 0xa4, 0x45, 0xd3, 0x93, 0xa8, 0x2a, 0x4b, 0x63, 0x69, 0x82, 0x57, 0x65, 0x0e, 0x3d, 0x38, - 0xa2, 0x9f, 0xfb, 0x39, 0x69, 0x57, 0xb9, 0x32, 0x2c, 0x26, 0xd9, 0xb8, 0x15, 0x12, 0xc0, 0x4f, - 0x61, 0xce, 0x32, 0x5d, 0xaf, 0x1a, 0x24, 0x42, 0xf5, 0x1e, 0x17, 0x06, 0xa2, 0x79, 0x6a, 0xba, - 0x5e, 0xaf, 0xd3, 0x59, 0x2b, 0x3c, 0x84, 0x3f, 0x90, 0x18, 0xcb, 0xac, 0x23, 0x8c, 0x6a, 0x19, - 0xee, 0xc2, 0x0c, 0xef, 0x16, 0xfb, 0x4b, 0xed, 0x34, 0x1f, 0x57, 0x1a, 0x86, 0xba, 0xdf, 0x7f, - 0xf4, 0xfb, 0x0a, 0x9a, 0x1c, 0x90, 0xce, 0xec, 0x43, 0x2a, 0x49, 0xe0, 0xc1, 0xf5, 0x8e, 0x2d, - 0x67, 0xbd, 0x19, 0xdb, 0xca, 0x3e, 0xa4, 0x78, 0xa5, 0xfb, 0x3a, 0xc4, 0x1c, 0xa9, 0x53, 0xa7, - 0x11, 0x5c, 0x33, 0x53, 0xe6, 0xf0, 0xbe, 0xe9, 0x18, 0x04, 0xa9, 0xd1, 0x11, 0x1c, 0x40, 0x4e, - 0xa5, 0xc9, 0xd3, 0x72, 0xc9, 0x6e, 0x3c, 0xa3, 0x76, 0x9d, 0x0c, 0x4f, 0xef, 0x2c, 0x8f, 0xd9, - 0x6c, 0x29, 0x7f, 0x6e, 0xa9, 0x8a, 0xf8, 0xc0, 0x87, 0xb2, 0x68, 0x44, 0x3b, 0x7d, 0x75, 0xe0, - 0x95, 0x1c, 0x56, 0xe6, 0xfd, 0x2e, 0x31, 0x1b, 0xdd, 0xc3, 0x7e, 0x55, 0x39, 0xec, 0x37, 0x9a, - 0x7a, 0x4a, 0xca, 0x36, 0x92, 0xc8, 0x03, 0x98, 0x92, 0xfd, 0x37, 0x1f, 0xf7, 0x0b, 0xea, 0x9c, - 0x5f, 0x50, 0x55, 0x9b, 0xc9, 0x5a, 0xf7, 0xc3, 0x7d, 0x75, 0x19, 0xab, 0x24, 0x4f, 0x71, 0x8f, - 0x78, 0xca, 0x6e, 0xe5, 0x0e, 0x13, 0x00, 0x7e, 0x38, 0x7a, 0x65, 0x02, 0x0b, 0xc7, 0xa4, 0x22, - 0x13, 0xf0, 0x8f, 0xbb, 0x85, 0x3e, 0xc2, 0x85, 0xa4, 0xfa, 0x16, 0x4c, 0xaa, 0x54, 0x65, 0x50, - 0x23, 0x99, 0x66, 0x14, 0xa6, 0xc5, 0xff, 0xe9, 0x30, 0xce, 0xbd, 0xa3, 0x2f, 0x34, 0x48, 0x8b, - 0x0a, 0x89, 0x8c, 0x81, 0x87, 0xdd, 0x2f, 0x36, 0xf4, 0x37, 0x93, 0x1b, 0x08, 0xbc, 0x78, 0xed, - 0x17, 0x7f, 0xff, 0xef, 0xaf, 0xc6, 0x56, 0xd0, 0x92, 0xc1, 0xd6, 0xbf, 0xc1, 0x4d, 0x8d, 0x90, - 0x68, 0x43, 0xff, 0xd0, 0x00, 0xf5, 0xf7, 0xe7, 0x68, 0x6b, 0xf8, 0x6e, 0xb1, 0xda, 0x44, 0x7f, - 0xf7, 0x72, 0xc6, 0x12, 0xf6, 0xfb, 0x1c, 0xf6, 0x7b, 0x68, 0x3b, 0x12, 0xb6, 0xec, 0xb3, 0x6b, - 0x1d, 0x25, 0x8b, 0x19, 0xe7, 0x7d, 0x1a, 0xe2, 0x02, 0xfd, 0x55, 0x83, 0x99, 0x70, 0xcb, 0x8b, - 0x1e, 0x0e, 0x47, 0x16, 0xd3, 0x73, 0xeb, 0xef, 0x5c, 0xc6, 0x54, 0x52, 0xda, 0xe5, 0x94, 0xb6, - 0xd1, 0x56, 0x24, 0xa5, 0xa0, 0xd7, 0x66, 0xac, 0xc4, 0xdc, 0x79, 0x5f, 0x7b, 0x7f, 0x81, 0xfe, - 0xac, 0x01, 0xea, 0x6f, 0xb1, 0x93, 0x9c, 0x54, 0x6c, 0xeb, 0x9e, 0xe4, 0xa4, 0xe2, 0xbb, 0x7a, - 0xbc, 0xc9, 0x69, 0x6d, 0xa0, 0xbb, 0x91, 0xb4, 0x4c, 0xcb, 0xaa, 0x86, 0x9b, 0x7e, 0xf4, 0x3b, - 0x0d, 0xa6, 0x43, 0x4d, 0x39, 0xda, 0x1c, 0x0e, 0x22, 0x64, 0xa2, 0x3f, 0x1c, 0xd9, 0x24, 0x00, - 0x7d, 0x8f, 0x83, 0xbe, 0x83, 0xbe, 0x1d, 0x09, 0xda, 0x0d, 0x61, 0xfb, 0xb7, 0x06, 0x0b, 0x91, - 0xdd, 0x3b, 0xda, 0x19, 0x0e, 0x61, 0x90, 0x6c, 0xd0, 0xdf, 0xbb, 0xb4, 0x7d, 0xa2, 0x4b, 0xd5, - 0x24, 0x5e, 0xb5, 0x6e, 0xb5, 0x88, 0xed, 0xc9, 0x96, 0xbe, 0x7a, 0x48, 0x1d, 0xff, 0x76, 0xf9, - 0x05, 0xed, 0x02, 0xfd, 0x5e, 0x83, 0xa9, 0x9e, 0x6d, 0xd0, 0x5b, 0x23, 0xe2, 0xf2, 0xf9, 0xbc, - 0x3d, 0xb2, 0x5d, 0xa2, 0x03, 0xe1, 0x3c, 0xba, 0xc2, 0x04, 0x7d, 0xa9, 0xf5, 0x34, 0xcd, 0x28, - 0xd9, 0xb6, 0xfd, 0x4d, 0xbe, 0xfe, 0x60, 0x74, 0x43, 0x09, 0xf8, 0x4d, 0x0e, 0x78, 0x1d, 0xe5, - 0x23, 0x01, 0x2b, 0x32, 0xc3, 0x38, 0xe7, 0xca, 0xe6, 0x82, 0xdd, 0xfa, 0x1b, 0x8a, 0xa7, 0x92, - 0x65, 0x25, 0xc1, 0x1d, 0x29, 0x4e, 0x92, 0xe0, 0x8e, 0x96, 0x1b, 0x38, 0xcf, 0x71, 0x63, 0x94, - 0x1b, 0x86, 0x1b, 0xfd, 0x51, 0x83, 0xe9, 0x50, 0x27, 0x9e, 0x24, 0xcf, 0xc4, 0x4a, 0x86, 0x24, - 0x79, 0x26, 0x5e, 0x4c, 0xe0, 0x37, 0x38, 0xf0, 0xd7, 0xd1, 0xed, 0x48, 0xe0, 0x61, 0x9d, 0x81, - 0x7e, 0xad, 0x41, 0x5a, 0xf4, 0xef, 0xa8, 0x98, 0x68, 0xdf, 0x1e, 0x09, 0xa1, 0xdf, 0x1f, 0xc9, - 0x26, 0x51, 0xad, 0x15, 0x2a, 0x02, 0xfd, 0x45, 0x83, 0xd9, 0x3e, 0x7d, 0x80, 0x12, 0x14, 0x96, - 0x38, 0xd9, 0xa1, 0x6f, 0x5d, 0xca, 0x56, 0x62, 0x7e, 0xc8, 0x31, 0xdf, 0x47, 0x9b, 0x2a, 0x66, - 0xdf, 0x8b, 0x92, 0x12, 0x8f, 0xe8, 0xe7, 0x21, 0xd1, 0x82, 0xfe, 0xa6, 0xc1, 0x6c, 0x9f, 0x36, - 0x48, 0xc2, 0x24, 0x4e, 0x9c, 0x24, 0x61, 0x12, 0x2b, 0x46, 0x86, 0xa4, 0x42, 0xd1, 0x68, 0x87, - 0x3b, 0x86, 0x90, 0x12, 0xba, 0x40, 0x7f, 0xd2, 0x00, 0xed, 0x11, 0x2f, 0x24, 0x37, 0x50, 0xb2, - 0xf7, 0x16, 0x21, 0x60, 0x92, 0x14, 0xa9, 0x18, 0x6d, 0x83, 0x8b, 0x9c, 0xd0, 0x3d, 0xb4, 0x1e, - 0x9b, 0x13, 0x59, 0x75, 0x15, 0x1c, 0x1c, 0x09, 0xf4, 0x1b, 0x0d, 0x16, 0xb8, 0x33, 0x37, 0x24, - 0x3a, 0xd0, 0x76, 0xe2, 0xd8, 0x46, 0x29, 0x20, 0x7d, 0xe7, 0xb2, 0xe6, 0x92, 0xcc, 0x63, 0x4e, - 0xa6, 0x8c, 0xbe, 0x33, 0xf8, 0x74, 0xc4, 0x13, 0x36, 0xed, 0x46, 0x95, 0xeb, 0x28, 0xa5, 0x4a, - 0x19, 0xe7, 0x7c, 0xe4, 0x82, 0xe5, 0xa5, 0xe0, 0x88, 0x14, 0x25, 0xf1, 0x76, 0xc2, 0x40, 0x87, - 0x45, 0x92, 0xfe, 0x60, 0x74, 0xc3, 0x11, 0x0f, 0x48, 0x51, 0x46, 0xe8, 0x5f, 0x1a, 0xcc, 0x47, - 0x09, 0x8c, 0x24, 0xe7, 0x33, 0x40, 0xdb, 0xe8, 0x3b, 0x97, 0x35, 0x97, 0x5c, 0xca, 0x9c, 0xcb, - 0xbb, 0xe8, 0x9d, 0x58, 0x2e, 0x2a, 0x0f, 0x76, 0x54, 0x4c, 0x44, 0xb1, 0x27, 0xe4, 0x0b, 0xaa, - 0x0b, 0xf4, 0x4b, 0x0d, 0xc6, 0xf9, 0x3f, 0x52, 0x50, 0x21, 0x81, 0x4e, 0x51, 0xfe, 0x33, 0xa4, - 0x1b, 0x89, 0xd7, 0x4b, 0xb8, 0x98, 0xc3, 0x5d, 0x46, 0x7a, 0xb4, 0xac, 0x61, 0x6b, 0xcb, 0xfb, - 0x5f, 0xbd, 0xc8, 0x6a, 0x5f, 0xbf, 0xc8, 0x6a, 0xdf, 0xbc, 0xc8, 0x6a, 0x5f, 0xbc, 0xcc, 0x5e, - 0xf9, 0xfa, 0x65, 0xf6, 0xca, 0x3f, 0x5f, 0x66, 0xaf, 0xfc, 0xc8, 0x68, 0xb6, 0xbc, 0xa3, 0x93, - 0x1a, 0x13, 0x6d, 0x91, 0x69, 0xef, 0xac, 0xeb, 0xca, 0xeb, 0xb4, 0x89, 0x5b, 0x4b, 0xf3, 0x7f, - 0x6b, 0xdd, 0xff, 0x7f, 0x00, 0x00, 0x00, 0xff, 0xff, 0x80, 0xd9, 0x94, 0x6c, 0x32, 0x1c, 0x00, - 0x00, + 0xf9, 0xbe, 0x37, 0x33, 0xef, 0xbd, 0x0f, 0x82, 0x0c, 0xad, 0xb8, 0xc4, 0x39, 0x25, 0x8e, 0xf1, + 0xcd, 0x09, 0x71, 0x5a, 0xb9, 0xa6, 0x43, 0x3d, 0x8a, 0x16, 0x7e, 0x46, 0x3c, 0xb3, 0x7a, 0x64, + 0x36, 0xec, 0x1c, 0xff, 0x45, 0x1d, 0x92, 0xf3, 0x17, 0xea, 0xb3, 0x55, 0x7a, 0x7c, 0x4c, 0x6d, + 0x43, 0xfc, 0x11, 0x16, 0xfa, 0x7a, 0x95, 0xba, 0xc7, 0xd4, 0x35, 0x2a, 0xa6, 0x4b, 0x84, 0x2b, + 0xe3, 0x74, 0xb3, 0x42, 0x3c, 0x73, 0xd3, 0x68, 0x9a, 0xf5, 0x86, 0x6d, 0x7a, 0x8d, 0x60, 0x6d, + 0xa6, 0x4e, 0xeb, 0x94, 0xff, 0x34, 0xd8, 0x2f, 0x39, 0xba, 0x58, 0xa7, 0xb4, 0x6e, 0x11, 0xc3, + 0x6c, 0x36, 0x0c, 0xd3, 0xb6, 0xa9, 0xc7, 0x4d, 0x5c, 0x39, 0x3b, 0x17, 0xe0, 0xac, 0x98, 0x96, + 0x45, 0x3d, 0xdf, 0x55, 0x7b, 0xd8, 0x32, 0x8f, 0x89, 0x1c, 0x5d, 0x0e, 0x46, 0xab, 0x0e, 0x75, + 0x5d, 0x4e, 0xa4, 0x7c, 0x68, 0x99, 0xf5, 0x6e, 0x6f, 0x5f, 0x93, 0x56, 0x9d, 0xf8, 0xc0, 0x16, + 0x82, 0x61, 0x9b, 0xd6, 0x48, 0xd9, 0xac, 0x56, 0xe9, 0x89, 0xed, 0x6f, 0x75, 0x35, 0x98, 0xf4, + 0x7f, 0x74, 0x39, 0x6b, 0x9a, 0x8e, 0x79, 0x2c, 0xf7, 0xc0, 0xbf, 0xd5, 0x60, 0xe6, 0xbb, 0x2c, + 0x10, 0x8f, 0x1d, 0x7a, 0x4a, 0x4a, 0xe4, 0x9b, 0x13, 0xe2, 0x7a, 0xe8, 0x1a, 0x8c, 0x09, 0x38, + 0x8d, 0xda, 0xbc, 0xb6, 0xa2, 0xad, 0x8d, 0x94, 0xde, 0xe6, 0xdf, 0xfb, 0x35, 0x74, 0x15, 0xde, + 0xf6, 0xce, 0xca, 0x47, 0xa6, 0x7b, 0x34, 0x3f, 0xbc, 0xa2, 0xad, 0x8d, 0x97, 0x52, 0xde, 0xd9, + 0x7d, 0xd3, 0x3d, 0x42, 0xab, 0x30, 0xda, 0x74, 0x28, 0x3d, 0x9c, 0x1f, 0x59, 0xd1, 0xd6, 0xd2, + 0xf9, 0xc9, 0x9c, 0x8c, 0xfc, 0x63, 0x36, 0x58, 0x12, 0x73, 0x68, 0x09, 0xa0, 0x62, 0xd1, 0xea, + 0xd7, 0xc2, 0xc1, 0x5b, 0xdc, 0xc1, 0x38, 0x1f, 0xe1, 0x3e, 0xae, 0xc1, 0x98, 0x77, 0x56, 0x6e, + 0xd8, 0x35, 0x72, 0x36, 0x3f, 0x2a, 0xf6, 0xf5, 0xce, 0xf6, 0xd9, 0x27, 0x5e, 0x07, 0xa4, 0xe2, + 0x74, 0x9b, 0xd4, 0x76, 0x09, 0xca, 0xc0, 0xe8, 0xa9, 0x69, 0x49, 0x94, 0x63, 0x25, 0xf1, 0x81, + 0x33, 0xfe, 0x5a, 0xce, 0x54, 0x92, 0xc2, 0x3f, 0x84, 0xd9, 0x8e, 0x51, 0xe9, 0xa2, 0x00, 0x29, + 0x11, 0x11, 0xee, 0x23, 0x9d, 0x5f, 0xcd, 0xf5, 0xb8, 0x56, 0x39, 0x61, 0x5c, 0x7c, 0xeb, 0xf9, + 0x7f, 0x96, 0x87, 0x4a, 0xd2, 0x10, 0x7f, 0x0e, 0x59, 0xee, 0xb9, 0xc8, 0x0f, 0xbd, 0xd8, 0xda, + 0xaf, 0x11, 0xdb, 0x6b, 0x1c, 0x36, 0x88, 0xe3, 0x07, 0x74, 0x03, 0x66, 0xc4, 0x8d, 0x28, 0x37, + 0x82, 0x39, 0xbe, 0xdf, 0x78, 0x69, 0x5a, 0x4c, 0xb4, 0x6d, 0xb0, 0x07, 0xe3, 0x5f, 0x52, 0x8f, + 0x38, 0x0f, 0x1b, 0xae, 0x87, 0x56, 0x61, 0xf2, 0x94, 0x7d, 0x94, 0xcd, 0x5a, 0xcd, 0x21, 0xae, + 0x2b, 0xad, 0x26, 0xf8, 0x60, 0x41, 0x8c, 0xa1, 0x22, 0x8c, 0xb3, 0xef, 0xb2, 0xd7, 0x6a, 0x12, + 0x7e, 0x2c, 0x57, 0xf2, 0xd7, 0x7b, 0xd2, 0x60, 0xfe, 0xbf, 0xd7, 0x6a, 0x92, 0xd2, 0xd8, 0xa9, + 0xfc, 0x85, 0xff, 0x30, 0x0c, 0xcb, 0xb1, 0x2c, 0x64, 0xac, 0x06, 0xa1, 0x81, 0x76, 0x20, 0xc5, + 0x41, 0xba, 0xf3, 0xc3, 0x2b, 0x23, 0x6b, 0xe9, 0xfc, 0x8d, 0xbe, 0x88, 0x38, 0xe3, 0x92, 0xb4, + 0x42, 0x3f, 0x80, 0x69, 0x31, 0xcb, 0x9f, 0x98, 0xe0, 0x36, 0xc2, 0xb9, 0xdd, 0xea, 0xe9, 0xe9, + 0x8b, 0xb6, 0x11, 0xa7, 0x38, 0x45, 0x3b, 0x07, 0xd0, 0x23, 0x98, 0x94, 0x2c, 0x5c, 0xcf, 0xf4, + 0x4e, 0x5c, 0x7e, 0x0f, 0xaf, 0xe4, 0x6f, 0xf6, 0xf4, 0x2a, 0xa2, 0x72, 0xc0, 0x0d, 0x4a, 0x13, + 0x15, 0xe5, 0x0b, 0x3f, 0x80, 0x45, 0x1e, 0xb8, 0x2f, 0xe4, 0x5a, 0xb7, 0xd8, 0xda, 0x65, 0x5e, + 0x94, 0xc3, 0x57, 0x89, 0xf0, 0x1d, 0xfc, 0xa8, 0x29, 0x13, 0xdc, 0x06, 0x6f, 0xc3, 0x52, 0x8c, + 0x33, 0x79, 0x06, 0x8b, 0x30, 0xee, 0x83, 0x62, 0x97, 0x61, 0x84, 0xbd, 0xa0, 0x60, 0x00, 0xaf, + 0xc8, 0xab, 0x58, 0xb0, 0x2c, 0xdf, 0xc3, 0xe7, 0x66, 0xb3, 0x49, 0x9c, 0xe0, 0x19, 0xb4, 0xe4, + 0x31, 0x47, 0xad, 0x90, 0x5b, 0x7c, 0xe9, 0x47, 0x9e, 0x38, 0xe5, 0x63, 0x31, 0xc7, 0x77, 0x4a, + 0xe7, 0x37, 0x12, 0x44, 0xde, 0xf7, 0xe7, 0x07, 0x3e, 0xf0, 0x8f, 0xdf, 0x81, 0x0c, 0xdf, 0xfa, + 0xe0, 0xa4, 0xd9, 0xa4, 0x8e, 0x47, 0x6a, 0x9c, 0x99, 0x8b, 0x3f, 0x95, 0x01, 0x0c, 0x8d, 0x07, + 0x78, 0xae, 0x43, 0x8a, 0x6f, 0xe9, 0xa3, 0x08, 0x72, 0x8b, 0x88, 0x8c, 0x9c, 0xc4, 0x3b, 0xf0, + 0x2d, 0xee, 0x66, 0x8f, 0x78, 0xbb, 0xd4, 0x21, 0xe2, 0xa9, 0xde, 0xa3, 0x4e, 0xc7, 0x61, 0xc4, + 0xa7, 0x36, 0x6c, 0x03, 0xee, 0x65, 0x2f, 0xc1, 0xdc, 0x87, 0x34, 0x63, 0x5d, 0xee, 0x48, 0x1a, + 0xef, 0xf6, 0x8c, 0x4b, 0xdb, 0x5b, 0x09, 0xaa, 0xc1, 0x6f, 0xbc, 0x00, 0xd7, 0xba, 0xf7, 0xf3, + 0x8f, 0xe9, 0x2b, 0xd0, 0xa3, 0x26, 0x25, 0x88, 0x87, 0x51, 0x20, 0x36, 0x12, 0x82, 0xe0, 0xaf, + 0x4c, 0x05, 0x92, 0x6f, 0xef, 0xf5, 0x88, 0xd6, 0x48, 0x41, 0x54, 0x14, 0x3f, 0x62, 0x19, 0x18, + 0x15, 0x19, 0x59, 0x5c, 0x59, 0xf1, 0x81, 0xbf, 0x82, 0x85, 0x48, 0x1b, 0x09, 0xf0, 0x01, 0x4c, + 0xa8, 0xd5, 0x49, 0x22, 0x5c, 0xeb, 0x89, 0x50, 0xf5, 0x93, 0xb6, 0xdb, 0x1f, 0xb8, 0x26, 0xf1, + 0x15, 0x2c, 0x2b, 0x02, 0xdf, 0x3d, 0x80, 0x76, 0xf1, 0x96, 0x1b, 0xdd, 0xc8, 0x89, 0x4a, 0x9f, + 0x63, 0x95, 0x3e, 0x27, 0x9a, 0x06, 0x59, 0xe9, 0x73, 0x8f, 0xcd, 0xba, 0x5f, 0xe8, 0x4a, 0x8a, + 0x25, 0x7e, 0xa6, 0x49, 0x4a, 0xe1, 0x6d, 0x24, 0xa5, 0xcf, 0x20, 0xad, 0x0c, 0xcb, 0xab, 0x38, + 0x00, 0x23, 0xe5, 0x03, 0xed, 0x75, 0x60, 0x1e, 0x96, 0x77, 0xa8, 0x1f, 0x66, 0x01, 0xa4, 0x03, + 0xb4, 0xff, 0xde, 0xd9, 0x35, 0x09, 0xba, 0x88, 0x7b, 0xac, 0x89, 0xf0, 0x2f, 0xd2, 0xcf, 0x35, + 0xf9, 0xe0, 0xa3, 0x96, 0x48, 0x6a, 0x3f, 0x81, 0xe9, 0x70, 0x0f, 0x22, 0x03, 0xd9, 0x3b, 0xd5, + 0x86, 0xfc, 0xc9, 0xb2, 0x38, 0x55, 0xed, 0x1c, 0xc6, 0x57, 0x61, 0xce, 0x47, 0xf0, 0x80, 0x77, + 0x32, 0x3e, 0xb6, 0xef, 0xc3, 0x3b, 0xe1, 0x09, 0x89, 0x68, 0x0b, 0x52, 0xa2, 0xe9, 0x49, 0x54, + 0x95, 0xa5, 0xb1, 0x34, 0xc1, 0xcb, 0x32, 0x87, 0x1e, 0x1c, 0xd1, 0x27, 0x7e, 0x4e, 0xda, 0x55, + 0xae, 0x0c, 0x8b, 0x49, 0x36, 0x6e, 0x85, 0x04, 0xf0, 0x53, 0x98, 0xb5, 0x4c, 0xd7, 0x2b, 0x07, + 0x89, 0x50, 0xbd, 0xc7, 0xb9, 0x9e, 0x68, 0x1e, 0x9a, 0xae, 0xd7, 0xe9, 0x74, 0xc6, 0x0a, 0x0f, + 0xe1, 0xcf, 0x24, 0xc6, 0x22, 0xeb, 0x08, 0xa3, 0x5a, 0x86, 0x9b, 0x30, 0xcd, 0xbb, 0xc5, 0xee, + 0x52, 0x3b, 0xc5, 0xc7, 0x95, 0x86, 0xa1, 0xea, 0xf7, 0x1f, 0xdd, 0xbe, 0x82, 0x26, 0x07, 0xa4, + 0x33, 0xfb, 0x90, 0x4a, 0x12, 0xb8, 0x77, 0xbd, 0x63, 0xcb, 0x59, 0x6f, 0xc6, 0xb6, 0xb2, 0x0f, + 0x29, 0x5e, 0x6a, 0xbf, 0x0e, 0x31, 0x47, 0xaa, 0xd4, 0xa9, 0x05, 0xd7, 0xcc, 0x94, 0x39, 0xbc, + 0x6b, 0x3a, 0x06, 0xc1, 0xc8, 0xe0, 0x08, 0x0e, 0x60, 0x45, 0xa5, 0xc9, 0xd3, 0x72, 0xc1, 0xae, + 0x3d, 0xa2, 0x76, 0x35, 0x49, 0xe7, 0x9a, 0x81, 0x51, 0x9b, 0x2d, 0xe5, 0xcf, 0x6d, 0xa4, 0x24, + 0x3e, 0xf0, 0xa1, 0x2c, 0x1a, 0xd1, 0x4e, 0xdf, 0x1c, 0x78, 0x25, 0x87, 0x15, 0x79, 0xbf, 0x4b, + 0xcc, 0x5a, 0xfb, 0xb0, 0xdf, 0x54, 0x0e, 0xfb, 0x8d, 0xa6, 0x9e, 0x92, 0xb2, 0x8d, 0x24, 0x72, + 0x07, 0x26, 0x65, 0xff, 0xcd, 0xc7, 0xfd, 0x82, 0x3a, 0xeb, 0x17, 0x54, 0xd5, 0x66, 0xa2, 0xd2, + 0xfe, 0x70, 0xdf, 0x5c, 0xc6, 0x2a, 0xc8, 0x53, 0xdc, 0x23, 0x9e, 0xb2, 0x5b, 0xb1, 0xc5, 0x04, + 0x80, 0x1f, 0x8e, 0x4e, 0x99, 0xc0, 0xc2, 0x31, 0xa1, 0xc8, 0x04, 0xfc, 0xe3, 0x76, 0xa1, 0x8f, + 0x70, 0x21, 0xa9, 0x7e, 0x00, 0x13, 0x2a, 0x55, 0x19, 0xd4, 0x48, 0xa6, 0x69, 0x85, 0x69, 0xfe, + 0x7f, 0x3a, 0x8c, 0x72, 0xef, 0xe8, 0xa9, 0x06, 0x29, 0x51, 0x21, 0x91, 0xd1, 0xf3, 0xb0, 0xbb, + 0xc5, 0x86, 0xfe, 0x7e, 0x72, 0x03, 0x81, 0x17, 0xaf, 0xfe, 0xe2, 0xef, 0xff, 0xfd, 0xd5, 0xf0, + 0x12, 0x5a, 0x30, 0xd8, 0xfa, 0xf7, 0xb8, 0xa9, 0x11, 0x12, 0x6d, 0xe8, 0x1f, 0x1a, 0xa0, 0xee, + 0xfe, 0x1c, 0x6d, 0xf5, 0xdf, 0x2d, 0x56, 0x9b, 0xe8, 0x1f, 0x5f, 0xce, 0x58, 0xc2, 0xfe, 0x94, + 0xc3, 0xfe, 0x04, 0x6d, 0x47, 0xc2, 0x96, 0x7d, 0x76, 0xa5, 0xa5, 0x64, 0x31, 0xe3, 0xbc, 0x4b, + 0x43, 0x5c, 0xa0, 0xbf, 0x6a, 0x30, 0x1d, 0x6e, 0x79, 0xd1, 0xdd, 0xfe, 0xc8, 0x62, 0x7a, 0x6e, + 0xfd, 0xa3, 0xcb, 0x98, 0x4a, 0x4a, 0xbb, 0x9c, 0xd2, 0x36, 0xda, 0x8a, 0xa4, 0x14, 0xf4, 0xda, + 0x8c, 0x95, 0x98, 0x3b, 0xef, 0x6a, 0xef, 0x2f, 0xd0, 0x9f, 0x35, 0x40, 0xdd, 0x2d, 0x76, 0x92, + 0x93, 0x8a, 0x6d, 0xdd, 0x93, 0x9c, 0x54, 0x7c, 0x57, 0x8f, 0x37, 0x39, 0xad, 0x0d, 0x74, 0x33, + 0x92, 0x96, 0x69, 0x59, 0xe5, 0x70, 0xd3, 0x8f, 0x7e, 0xa7, 0xc1, 0x54, 0xa8, 0x29, 0x47, 0x9b, + 0xfd, 0x41, 0x84, 0x4c, 0xf4, 0xbb, 0x03, 0x9b, 0x04, 0xa0, 0x6f, 0x71, 0xd0, 0x37, 0xd0, 0xb7, + 0x23, 0x41, 0xbb, 0x21, 0x6c, 0xff, 0xd6, 0x60, 0x2e, 0xb2, 0x7b, 0x47, 0x3b, 0xfd, 0x21, 0xf4, + 0x92, 0x0d, 0xfa, 0x27, 0x97, 0xb6, 0x4f, 0x74, 0xa9, 0xea, 0xc4, 0x2b, 0x57, 0xad, 0x06, 0xb1, + 0x3d, 0xd9, 0xd2, 0x97, 0x0f, 0xa9, 0xe3, 0xdf, 0x2e, 0xbf, 0xa0, 0x5d, 0xa0, 0xdf, 0x6b, 0x30, + 0xd9, 0xb1, 0x0d, 0xfa, 0x60, 0x40, 0x5c, 0x3e, 0x9f, 0x0f, 0x07, 0xb6, 0x4b, 0x74, 0x20, 0x9c, + 0x47, 0x5b, 0x98, 0xa0, 0x67, 0x5a, 0x47, 0xd3, 0x8c, 0x92, 0x6d, 0xdb, 0xdd, 0xe4, 0xeb, 0x77, + 0x06, 0x37, 0x94, 0x80, 0xdf, 0xe7, 0x80, 0xd7, 0xd1, 0x5a, 0x24, 0x60, 0x45, 0x66, 0x18, 0xe7, + 0x5c, 0xd9, 0x5c, 0xb0, 0x5b, 0x7f, 0x45, 0xf1, 0x54, 0xb0, 0xac, 0x24, 0xb8, 0x23, 0xc5, 0x49, + 0x12, 0xdc, 0xd1, 0x72, 0x03, 0xaf, 0x71, 0xdc, 0x18, 0xad, 0xf4, 0xc3, 0x8d, 0xfe, 0xa8, 0xc1, + 0x54, 0xa8, 0x13, 0x4f, 0x92, 0x67, 0x62, 0x25, 0x43, 0x92, 0x3c, 0x13, 0x2f, 0x26, 0xf0, 0x7b, + 0x1c, 0xf8, 0xbb, 0xe8, 0x7a, 0x24, 0xf0, 0xb0, 0xce, 0x40, 0xbf, 0xd6, 0x20, 0x25, 0xfa, 0x77, + 0x94, 0x4f, 0xb4, 0x6f, 0x87, 0x84, 0xd0, 0x6f, 0x0f, 0x64, 0x93, 0xa8, 0xd6, 0x0a, 0x15, 0x81, + 0xfe, 0xa2, 0xc1, 0x4c, 0x97, 0x3e, 0x40, 0x09, 0x0a, 0x4b, 0x9c, 0xec, 0xd0, 0xb7, 0x2e, 0x65, + 0x2b, 0x31, 0xdf, 0xe5, 0x98, 0x6f, 0xa3, 0x4d, 0x15, 0xb3, 0xef, 0x45, 0x49, 0x89, 0x47, 0xf4, + 0x49, 0x48, 0xb4, 0xa0, 0xbf, 0x69, 0x30, 0xd3, 0xa5, 0x0d, 0x92, 0x30, 0x89, 0x13, 0x27, 0x49, + 0x98, 0xc4, 0x8a, 0x91, 0x3e, 0xa9, 0x50, 0x34, 0xda, 0xe1, 0x8e, 0x21, 0xa4, 0x84, 0x2e, 0xd0, + 0x9f, 0x34, 0x40, 0x7b, 0xc4, 0x0b, 0xc9, 0x0d, 0x94, 0xec, 0xbd, 0x45, 0x08, 0x98, 0x24, 0x45, + 0x2a, 0x46, 0xdb, 0xe0, 0x3c, 0x27, 0x74, 0x0b, 0xad, 0xc7, 0xe6, 0x44, 0x56, 0x5d, 0x05, 0x07, + 0x47, 0x02, 0x7d, 0xa9, 0xc1, 0x1c, 0x77, 0xe6, 0x86, 0x44, 0x07, 0xda, 0x4e, 0x1c, 0xdb, 0x28, + 0x05, 0xa4, 0xef, 0x5c, 0xd6, 0x5c, 0x92, 0xb9, 0xcf, 0xc9, 0x14, 0xd1, 0x77, 0x7a, 0x9f, 0x8e, + 0x78, 0xc2, 0xa6, 0x5d, 0x2b, 0x73, 0x1d, 0xa5, 0x54, 0x29, 0xe3, 0x9c, 0x8f, 0x5c, 0xb0, 0xbc, + 0x14, 0x1c, 0x91, 0xa2, 0x24, 0x3e, 0x4c, 0x18, 0xe8, 0xb0, 0x48, 0xd2, 0xef, 0x0c, 0x6e, 0x38, + 0xe0, 0x01, 0x29, 0xca, 0x08, 0xfd, 0x4b, 0x83, 0x4c, 0x94, 0xc0, 0x48, 0x72, 0x3e, 0x3d, 0xb4, + 0x8d, 0xbe, 0x73, 0x59, 0x73, 0xc9, 0xa5, 0xc8, 0xb9, 0x7c, 0x8c, 0x3e, 0x8a, 0xe5, 0xa2, 0xf2, + 0x60, 0x47, 0xc5, 0x44, 0x14, 0x7b, 0x42, 0xbe, 0xa0, 0xba, 0x40, 0xbf, 0xd4, 0x60, 0x94, 0xff, + 0x23, 0x05, 0xe5, 0x12, 0xe8, 0x14, 0xe5, 0x3f, 0x43, 0xba, 0x91, 0x78, 0xbd, 0x84, 0x8b, 0x39, + 0xdc, 0x45, 0xa4, 0x47, 0xcb, 0x1a, 0xb6, 0xb6, 0xb8, 0xff, 0xfc, 0x55, 0x56, 0x7b, 0xf1, 0x2a, + 0xab, 0xbd, 0x7c, 0x95, 0xd5, 0x9e, 0xbe, 0xce, 0x0e, 0xbd, 0x78, 0x9d, 0x1d, 0xfa, 0xe7, 0xeb, + 0xec, 0xd0, 0x8f, 0x8c, 0x7a, 0xc3, 0x3b, 0x3a, 0xa9, 0x30, 0xd1, 0x16, 0x99, 0xf6, 0xce, 0xda, + 0xae, 0xbc, 0x56, 0x93, 0xb8, 0x95, 0x14, 0xff, 0xb7, 0xd6, 0xed, 0xff, 0x07, 0x00, 0x00, 0xff, + 0xff, 0x1c, 0x38, 0x4c, 0x21, 0x32, 0x1c, 0x00, 0x00, } // Reference imports to suppress errors if they are not otherwise used. @@ -4360,7 +4359,7 @@ func (m *QueryProveRequest) Unmarshal(dAtA []byte) error { } b := dAtA[iNdEx] iNdEx++ - m.ChainId |= uint64(b&0x7F) << shift + m.ChainId |= int64(b&0x7F) << shift if b < 0x80 { break } diff --git a/zetaclient/bitcoin_client.go b/zetaclient/bitcoin_client.go index 217abaa0a7..6f68f28a7a 100644 --- a/zetaclient/bitcoin_client.go +++ b/zetaclient/bitcoin_client.go @@ -7,6 +7,7 @@ import ( "cosmossdk.io/math" "github.com/btcsuite/btcd/chaincfg/chainhash" + "github.com/btcsuite/btcd/wire" "github.com/pkg/errors" "gorm.io/driver/sqlite" "gorm.io/gorm" @@ -23,6 +24,7 @@ import ( "github.com/btcsuite/btcd/btcjson" "github.com/btcsuite/btcd/rpcclient" "github.com/btcsuite/btcutil" + lru "github.com/hashicorp/golang-lru" "github.com/rs/zerolog" "github.com/zeta-chain/zetacore/common" "github.com/zeta-chain/zetacore/x/crosschain/types" @@ -67,12 +69,14 @@ type BitcoinChainClient struct { stop chan struct{} logger BTCLog ts *TelemetryServer + + BlockCache *lru.Cache } const ( minConfirmations = 0 maxHeightDiff = 10000 - dustOffset = 2000 + btcBlocksPerDay = 144 bytesPerKB = 1000 ) @@ -133,6 +137,12 @@ func NewBitcoinClient(chain common.Chain, bridge *ZetaCoreBridge, tss TSSSigner, return nil, fmt.Errorf("error ping the bitcoin server: %s", err) } + ob.BlockCache, err = lru.New(btcBlocksPerDay) + if err != nil { + ob.logger.ChainLogger.Error().Err(err).Msg("failed to create bitcoin block cache") + return nil, err + } + err = ob.RegisterPromGauge(metricsPkg.PendingTxs, "Number of pending transactions") if err != nil { return nil, err @@ -266,30 +276,44 @@ func (ob *BitcoinChainClient) observeInTx() error { // query incoming gas asset if confirmedBlockNum > lastBN { bn := lastBN + 1 - ob.logger.WatchInTx.Info().Msgf("filtering block %d, current block %d, last block %d", bn, cnt, lastBN) - hash, err := ob.rpcClient.GetBlockHash(bn) + res, err := ob.GetBlockByNumberCached(bn) if err != nil { + ob.logger.WatchInTx.Error().Err(err).Msgf("error getting bitcoin block %d", bn) return err } + ob.logger.WatchInTx.Info().Msgf("block %d has %d txs, current block %d, last block %d", bn, len(res.Block.Tx), cnt, lastBN) - block, err := ob.rpcClient.GetBlockVerboseTx(hash) - if err != nil { - return err - } - ob.logger.WatchInTx.Info().Msgf("block %d has %d txs", bn, len(block.Tx)) - if len(block.Tx) > 1 { - for idx, tx := range block.Tx { - ob.logger.WatchInTx.Info().Msgf("BTC InTX | %d: %s\n", idx, tx.Txid) + // print some debug information + if len(res.Block.Tx) > 1 { + for idx, tx := range res.Block.Tx { + ob.logger.WatchInTx.Debug().Msgf("BTC InTX | %d: %s\n", idx, tx.Txid) for vidx, vout := range tx.Vout { ob.logger.WatchInTx.Debug().Msgf("vout %d \n value: %v\n scriptPubKey: %v\n", vidx, vout.Value, vout.ScriptPubKey.Hex) } - //ob.rpcClient.GetTransaction(tx.Txid) } } + // add block header to zetacore + var headerBuf bytes.Buffer + err = res.Header.Serialize(&headerBuf) + if err != nil { // should never happen + ob.logger.WatchInTx.Error().Err(err).Msgf("error serializing bitcoin block header: %d", bn) + return err + } + blockHash := res.Header.BlockHash() + _, err = ob.zetaClient.PostAddBlockHeader( + ob.chain.ChainId, + blockHash[:], + res.Block.Height, + common.NewBitcoinHeader(headerBuf.Bytes()), + ) + if err != nil { // error shouldn't block the process + ob.logger.WatchInTx.Error().Err(err).Msgf("error posting bitcoin block header: %d", bn) + } + tssAddress := ob.Tss.BTCAddress() // #nosec G701 always positive - inTxs := FilterAndParseIncomingTx(block.Tx, uint64(block.Height), tssAddress, &ob.logger.WatchInTx) + inTxs := FilterAndParseIncomingTx(res.Block.Tx, uint64(res.Block.Height), tssAddress, &ob.logger.WatchInTx) for _, inTx := range inTxs { ob.logger.WatchInTx.Debug().Msgf("Processing inTx: %s", inTx.TxHash) @@ -401,6 +425,7 @@ func (ob *BitcoinChainClient) IsSendOutTxProcessed(sendHash string, nonce uint64 zetaHash, err := ob.zetaClient.PostReceiveConfirmation( sendHash, res.TxID, + // #nosec G701 always positive uint64(res.BlockIndex), 0, // gas used not used with Bitcoin nil, // gas price not used with Bitcoin @@ -461,6 +486,10 @@ func (ob *BitcoinChainClient) PostGasPrice() error { if feeResult.Errors != nil || feeResult.FeeRate == nil { return fmt.Errorf("error getting gas price: %s", feeResult.Errors) } + if *feeResult.FeeRate > math2.MaxInt64 { + return fmt.Errorf("gas price is too large: %f", *feeResult.FeeRate) + } + // #nosec G701 always in range feeRate := new(big.Int).SetInt64(int64(*feeResult.FeeRate * 1e8)) feeRatePerByte := new(big.Int).Div(feeRate, big.NewInt(bytesPerKB)) bn, err := ob.rpcClient.GetBlockCount() @@ -717,7 +746,7 @@ func (ob *BitcoinChainClient) getOutTxidByNonce(nonce uint64, test bool) (string func (ob *BitcoinChainClient) findNonceMarkUTXO(nonce uint64, txid string) (int, error) { tssAddress := ob.Tss.BTCAddressWitnessPubkeyHash().EncodeAddress() - amount := NonceMarkAmount(nonce) + amount := common.NonceMarkAmount(nonce) for i, utxo := range ob.utxos { sats, err := getSatoshis(utxo.Amount) if err != nil { @@ -1042,8 +1071,8 @@ func (ob *BitcoinChainClient) checkTSSVout(vouts []btcjson.Vout, params types.Ou if recvAddress != tssAddress { return fmt.Errorf("checkTSSVout: nonce-mark address %s not match TSS address %s", recvAddress, tssAddress) } - if amount != NonceMarkAmount(nonce) { - return fmt.Errorf("checkTSSVout: nonce-mark amount %d not match nonce-mark amount %d", amount, NonceMarkAmount(nonce)) + if amount != common.NonceMarkAmount(nonce) { + return fmt.Errorf("checkTSSVout: nonce-mark amount %d not match nonce-mark amount %d", amount, common.NonceMarkAmount(nonce)) } } // 2nd vout: payment to recipient @@ -1145,8 +1174,35 @@ func (ob *BitcoinChainClient) GetTxID(nonce uint64) string { return fmt.Sprintf("%d-%s-%d", ob.chain.ChainId, tssAddr, nonce) } -// A very special value to mark current nonce in UTXO -func NonceMarkAmount(nonce uint64) int64 { - // #nosec G701 always in range - return int64(nonce) + dustOffset // +2000 to avoid being a dust rejection +type BTCBlockNHeader struct { + Header *wire.BlockHeader + Block *btcjson.GetBlockVerboseTxResult +} + +func (ob *BitcoinChainClient) GetBlockByNumberCached(blockNumber int64) (*BTCBlockNHeader, error) { + if result, ok := ob.BlockCache.Get(blockNumber); ok { + return result.(*BTCBlockNHeader), nil + } + // Get the block hash + hash, err := ob.rpcClient.GetBlockHash(blockNumber) + if err != nil { + return nil, err + } + // Get the block header + header, err := ob.rpcClient.GetBlockHeader(hash) + if err != nil { + return nil, err + } + // Get the block with verbose transactions + block, err := ob.rpcClient.GetBlockVerboseTx(hash) + if err != nil { + return nil, err + } + blockNheader := &BTCBlockNHeader{ + Header: header, + Block: block, + } + ob.BlockCache.Add(blockNumber, blockNheader) + ob.BlockCache.Add(hash, blockNheader) + return blockNheader, nil } diff --git a/zetaclient/btc_signer.go b/zetaclient/btc_signer.go index 07cf24df92..f8ba3d0e6f 100644 --- a/zetaclient/btc_signer.go +++ b/zetaclient/btc_signer.go @@ -69,7 +69,7 @@ func NewBTCSigner(cfg config.BTCConfig, tssSigner TSSSigner, logger zerolog.Logg func (signer *BTCSigner) SignWithdrawTx(to *btcutil.AddressWitnessPubKeyHash, amount float64, gasPrice *big.Int, sizeLimit uint64, btcClient *BitcoinChainClient, height uint64, nonce uint64, chain *common.Chain) (*wire.MsgTx, error) { estimateFee := float64(gasPrice.Uint64()) * outTxBytesMax / 1e8 - nonceMark := NonceMarkAmount(nonce) + nonceMark := common.NonceMarkAmount(nonce) // refresh unspent UTXOs and continue with keysign regardless of error err := btcClient.FetchUTXOS() @@ -101,6 +101,7 @@ func (signer *BTCSigner) SignWithdrawTx(to *btcutil.AddressWitnessPubKeyHash, am } // size checking + // #nosec G701 check as positive txSize := uint64(tx.SerializeSize()) if txSize > sizeLimit { // ZRC20 'withdraw' charged less fee from end user signer.logger.Info().Msgf("sizeLimit %d is less than txSize %d for nonce %d", sizeLimit, txSize, nonce) @@ -115,6 +116,7 @@ func (signer *BTCSigner) SignWithdrawTx(to *btcutil.AddressWitnessPubKeyHash, am } // fee calculation + // #nosec G701 always in range (checked above) fees := new(big.Int).Mul(big.NewInt(int64(txSize)), gasPrice) fees.Div(fees, big.NewInt(bytesPerKB)) signer.logger.Info().Msgf("bitcoin outTx nonce %d gasPrice %s size %d fees %s", nonce, gasPrice.String(), txSize, fees.String()) diff --git a/zetaclient/btc_signer_test.go b/zetaclient/btc_signer_test.go index 5dff18dfa4..631f110982 100644 --- a/zetaclient/btc_signer_test.go +++ b/zetaclient/btc_signer_test.go @@ -18,6 +18,7 @@ import ( "github.com/rs/zerolog" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" + "github.com/zeta-chain/zetacore/common" "github.com/zeta-chain/zetacore/zetaclient/config" . "gopkg.in/check.v1" ) @@ -233,7 +234,7 @@ func mineTxNSetNonceMark(ob *BitcoinChainClient, nonce uint64, txid string, preM // Set nonce mark if preMarkIndex >= 0 { tssAddress := ob.Tss.BTCAddressWitnessPubkeyHash().EncodeAddress() - nonceMark := btcjson.ListUnspentResult{TxID: txid, Address: tssAddress, Amount: float64(NonceMarkAmount(nonce)) * 1e-8} + nonceMark := btcjson.ListUnspentResult{TxID: txid, Address: tssAddress, Amount: float64(common.NonceMarkAmount(nonce)) * 1e-8} ob.utxos[preMarkIndex] = nonceMark sort.SliceStable(ob.utxos, func(i, j int) bool { return ob.utxos[i].Amount < ob.utxos[j].Amount @@ -274,7 +275,7 @@ func TestSelectUTXOs(t *testing.T) { require.Equal(t, "findNonceMarkUTXO: cannot find nonce-mark utxo with nonce 0", err.Error()) // add nonce-mark utxo for nonce 0 - nonceMark0 := btcjson.ListUnspentResult{TxID: dummyTxID, Address: tssAddress, Amount: float64(NonceMarkAmount(0)) * 1e-8} + nonceMark0 := btcjson.ListUnspentResult{TxID: dummyTxID, Address: tssAddress, Amount: float64(common.NonceMarkAmount(0)) * 1e-8} ob.utxos = append([]btcjson.ListUnspentResult{nonceMark0}, ob.utxos...) // Case4: nonce = 1, should pass now diff --git a/zetaclient/evm_client.go b/zetaclient/evm_client.go index 5bc89ae547..d828364f63 100644 --- a/zetaclient/evm_client.go +++ b/zetaclient/evm_client.go @@ -849,13 +849,11 @@ func (ob *EVMChainClient) observeInTX() error { // query incoming gas asset if !ob.chain.IsKlaytnChain() { for bn := startBlock; bn <= toBlock; bn++ { - //block, err := ob.EvmClient.BlockByNumber(context.Background(), big.NewInt(int64(bn))) block, err := ob.GetBlockByNumberCached(bn) if err != nil { ob.logger.ExternalChainWatcher.Error().Err(err).Msgf("error getting block: %d", bn) continue } - _ = ob.BlockCache.Add(block.Hash(), block) headerRLP, err := rlp.EncodeToBytes(block.Header()) if err != nil { ob.logger.ExternalChainWatcher.Error().Err(err).Msgf("error encoding block header: %d", bn) @@ -1219,5 +1217,6 @@ func (ob *EVMChainClient) GetBlockByNumberCached(blockNumber int64) (*ethtypes.B return nil, err } ob.BlockCache.Add(blockNumber, block) + ob.BlockCache.Add(block.Hash(), block) return block, nil } diff --git a/zetaclient/query.go b/zetaclient/query.go index 7b813600ce..909e2bdc56 100644 --- a/zetaclient/query.go +++ b/zetaclient/query.go @@ -324,7 +324,7 @@ func (b *ZetaCoreBridge) GetPendingNonces() (*types.QueryAllPendingNoncesRespons return resp, nil } -func (b *ZetaCoreBridge) Prove(blockHash string, txHash string, txIndex int64, proof *common.Proof, chainID uint64) (bool, error) { +func (b *ZetaCoreBridge) Prove(blockHash string, txHash string, txIndex int64, proof *common.Proof, chainID int64) (bool, error) { client := zetaObserverTypes.NewQueryClient(b.grpcConn) resp, err := client.Prove(context.Background(), &zetaObserverTypes.QueryProveRequest{ BlockHash: blockHash, diff --git a/zetaclient/tx.go b/zetaclient/tx.go index cfe306cf9d..85505d5623 100644 --- a/zetaclient/tx.go +++ b/zetaclient/tx.go @@ -194,9 +194,9 @@ func (b *ZetaCoreBridge) PostBlameData(blame *blame.Blame, chainID int64, index return "", fmt.Errorf("post blame data failed after %d retries", DefaultRetryCount) } -func (b *ZetaCoreBridge) PostAddBlockHeader(chainID int64, txhash []byte, height int64, header common.HeaderData) (string, error) { +func (b *ZetaCoreBridge) PostAddBlockHeader(chainID int64, blockHash []byte, height int64, header common.HeaderData) (string, error) { signerAddress := b.keys.GetOperatorAddress().String() - msg := observerTypes.NewMsgAddBlockHeader(signerAddress, chainID, txhash, height, header) + msg := observerTypes.NewMsgAddBlockHeader(signerAddress, chainID, blockHash, height, header) authzMsg, authzSigner := b.WrapMessageWithAuthz(msg) var gasLimit uint64 = DefaultGasLimit From 48f3a4496568c9725470b07d598a914d2e1de6e6 Mon Sep 17 00:00:00 2001 From: Lucas Bertrand Date: Thu, 12 Oct 2023 13:36:13 -0700 Subject: [PATCH 11/27] fix: read gas limit from smart contract (#1277) * read gas limit from smart contract * add more checks for gas limit --- x/crosschain/keeper/evm_hooks.go | 11 +++++++--- x/crosschain/keeper/gas_payment_test.go | 1 + .../keeper/msg_server_whitelist_erc20_test.go | 5 +++++ ...blocker_deploy_system_contracts_privnet.go | 4 ++-- ...blocker_deploy_system_contracts_testnet.go | 8 ++++---- x/fungible/keeper/gas_coin_and_pool.go | 20 +++++++++++++++---- x/fungible/keeper/gas_coin_and_pool_test.go | 1 + .../msg_server_deploy_fungible_coin_zrc20.go | 2 +- ..._server_deploy_fungible_coin_zrc20_test.go | 12 ++++++++++- 9 files changed, 49 insertions(+), 15 deletions(-) diff --git a/x/crosschain/keeper/evm_hooks.go b/x/crosschain/keeper/evm_hooks.go index a9779766d8..c575598cf1 100644 --- a/x/crosschain/keeper/evm_hooks.go +++ b/x/crosschain/keeper/evm_hooks.go @@ -129,8 +129,13 @@ func (k Keeper) ProcessZRC20WithdrawalEvent(ctx sdk.Context, event *zrc20.ZRC20W if err != nil { return fmt.Errorf("cannot encode address %s: %s", event.To, err.Error()) } - gasLimit := foreignCoin.GasLimit - // gasLimit+uint64(event.Raw.Index) to genereate different cctx for multiple events in the same tx. + + gasLimit, err := k.fungibleKeeper.QueryGasLimit(ctx, ethcommon.HexToAddress(foreignCoin.Zrc20ContractAddress)) + if err != nil { + return fmt.Errorf("cannot query gas limit: %s", err.Error()) + } + + // gasLimit+uint64(event.Raw.Index) to generate different cctx for multiple events in the same tx. msg := types.NewMsgVoteOnObservedInboundTx( "", emittingContract.Hex(), @@ -142,7 +147,7 @@ func (k Keeper) ProcessZRC20WithdrawalEvent(ctx sdk.Context, event *zrc20.ZRC20W "", event.Raw.TxHash.String(), event.Raw.BlockNumber, - gasLimit+uint64(event.Raw.Index), + gasLimit.Uint64()+uint64(event.Raw.Index), foreignCoin.CoinType, foreignCoin.Asset, ) diff --git a/x/crosschain/keeper/gas_payment_test.go b/x/crosschain/keeper/gas_payment_test.go index e110017694..d15bf96e94 100644 --- a/x/crosschain/keeper/gas_payment_test.go +++ b/x/crosschain/keeper/gas_payment_test.go @@ -99,6 +99,7 @@ func setupGasCoin( assetName, symbol, 8, + nil, ) require.NoError(t, err) assertContractDeployment(t, evmk, ctx, addr) diff --git a/x/crosschain/keeper/msg_server_whitelist_erc20_test.go b/x/crosschain/keeper/msg_server_whitelist_erc20_test.go index 0f7fa29916..8a2925ddcd 100644 --- a/x/crosschain/keeper/msg_server_whitelist_erc20_test.go +++ b/x/crosschain/keeper/msg_server_whitelist_erc20_test.go @@ -57,6 +57,11 @@ func TestKeeper_WhitelistERC20(t *testing.T) { require.True(t, found) require.EqualValues(t, fmt.Sprintf("%s:%s", common.CmdWhitelistERC20, erc20Address), cctx.RelayedMessage) + // check gas limit is set + gasLimit, err := zk.FungibleKeeper.QueryGasLimit(ctx, ethcommon.HexToAddress(zrc20)) + require.NoError(t, err) + require.Equal(t, uint64(100000), gasLimit.Uint64()) + // Ensure that whitelist a new erc20 create a cctx with a different index res, err = k.WhitelistERC20(ctx, &types.MsgWhitelistERC20{ Creator: admin, diff --git a/x/fungible/keeper/begin_blocker_deploy_system_contracts_privnet.go b/x/fungible/keeper/begin_blocker_deploy_system_contracts_privnet.go index 803510d38d..c806073894 100644 --- a/x/fungible/keeper/begin_blocker_deploy_system_contracts_privnet.go +++ b/x/fungible/keeper/begin_blocker_deploy_system_contracts_privnet.go @@ -83,13 +83,13 @@ func (k Keeper) BlockOneDeploySystemContracts(goCtx context.Context) error { return err } - ETHZRC20Addr, err := k.SetupChainGasCoinAndPool(ctx, common.GoerliChain().ChainId, "ETH", "gETH", 18) + ETHZRC20Addr, err := k.SetupChainGasCoinAndPool(ctx, common.GoerliChain().ChainId, "ETH", "gETH", 18, nil) if err != nil { return sdkerrors.Wrapf(err, "failed to setupChainGasCoinAndPool") } ctx.Logger().Info("Deployed ETH ZRC20 at " + ETHZRC20Addr.String()) - BTCZRC20Addr, err := k.SetupChainGasCoinAndPool(ctx, common.BtcRegtestChain().ChainId, "BTC", "tBTC", 8) + BTCZRC20Addr, err := k.SetupChainGasCoinAndPool(ctx, common.BtcRegtestChain().ChainId, "BTC", "tBTC", 8, nil) if err != nil { return sdkerrors.Wrapf(err, "failed to setupChainGasCoinAndPool") } diff --git a/x/fungible/keeper/begin_blocker_deploy_system_contracts_testnet.go b/x/fungible/keeper/begin_blocker_deploy_system_contracts_testnet.go index cb516422cc..5c19164ba0 100644 --- a/x/fungible/keeper/begin_blocker_deploy_system_contracts_testnet.go +++ b/x/fungible/keeper/begin_blocker_deploy_system_contracts_testnet.go @@ -76,20 +76,20 @@ func (k Keeper) BlockOneDeploySystemContracts(goCtx context.Context) error { if err != nil { return err } - _, err = k.SetupChainGasCoinAndPool(ctx, common.GoerliChain().ChainId, "ETH", "gETH", 18) + _, err = k.SetupChainGasCoinAndPool(ctx, common.GoerliChain().ChainId, "ETH", "gETH", 18, nil) if err != nil { return sdkerrors.Wrapf(err, "failed to setupChainGasCoinAndPool") } - _, err = k.SetupChainGasCoinAndPool(ctx, common.BscTestnetChain().ChainId, "BNB", "tBNB", 18) + _, err = k.SetupChainGasCoinAndPool(ctx, common.BscTestnetChain().ChainId, "BNB", "tBNB", 18, nil) if err != nil { return sdkerrors.Wrapf(err, "failed to setupChainGasCoinAndPool") } - _, err = k.SetupChainGasCoinAndPool(ctx, common.MumbaiChain().ChainId, "MATIC", "tMATIC", 18) + _, err = k.SetupChainGasCoinAndPool(ctx, common.MumbaiChain().ChainId, "MATIC", "tMATIC", 18, nil) if err != nil { return sdkerrors.Wrapf(err, "failed to setupChainGasCoinAndPool") } - _, err = k.SetupChainGasCoinAndPool(ctx, common.BtcTestNetChain().ChainId, "BTC", "tBTC", 8) + _, err = k.SetupChainGasCoinAndPool(ctx, common.BtcTestNetChain().ChainId, "BTC", "tBTC", 8, nil) if err != nil { return sdkerrors.Wrapf(err, "failed to setupChainGasCoinAndPool") } diff --git a/x/fungible/keeper/gas_coin_and_pool.go b/x/fungible/keeper/gas_coin_and_pool.go index 493977a879..ce725743cb 100644 --- a/x/fungible/keeper/gas_coin_and_pool.go +++ b/x/fungible/keeper/gas_coin_and_pool.go @@ -18,16 +18,28 @@ import ( // SetupChainGasCoinAndPool setup gas ZRC20, and ZETA/gas pool for a chain // add 0.1gas/0.1wzeta to the pool // FIXME: add cointype and use proper gas limit based on cointype/chain -func (k Keeper) SetupChainGasCoinAndPool(ctx sdk.Context, chainID int64, gasAssetName string, symbol string, decimals uint8) (ethcommon.Address, error) { +func (k Keeper) SetupChainGasCoinAndPool( + ctx sdk.Context, + chainID int64, + gasAssetName string, + symbol string, + decimals uint8, + gasLimit *big.Int, +) (ethcommon.Address, error) { chain := common.GetChainFromChainID(chainID) if chain == nil { return ethcommon.Address{}, zetaObserverTypes.ErrSupportedChains } name := fmt.Sprintf("%s-%s", gasAssetName, chain.ChainName) - transferGasLimit := big.NewInt(21_000) - if common.IsBitcoinChain(chain.ChainId) { - transferGasLimit = big.NewInt(100) // 100B for a typical tx + transferGasLimit := gasLimit + + // default values + if transferGasLimit == nil { + transferGasLimit = big.NewInt(21_000) + if common.IsBitcoinChain(chain.ChainId) { + transferGasLimit = big.NewInt(100) // 100B for a typical tx + } } zrc20Addr, err := k.DeployZRC20Contract(ctx, name, symbol, decimals, chain.ChainId, common.CoinType_Gas, "", transferGasLimit) diff --git a/x/fungible/keeper/gas_coin_and_pool_test.go b/x/fungible/keeper/gas_coin_and_pool_test.go index c2fb61e960..9bdd139fdc 100644 --- a/x/fungible/keeper/gas_coin_and_pool_test.go +++ b/x/fungible/keeper/gas_coin_and_pool_test.go @@ -30,6 +30,7 @@ func setupGasCoin( assetName, symbol, 8, + nil, ) require.NoError(t, err) assertContractDeployment(t, evmk, ctx, addr) diff --git a/x/fungible/keeper/msg_server_deploy_fungible_coin_zrc20.go b/x/fungible/keeper/msg_server_deploy_fungible_coin_zrc20.go index 4784f3f3f6..24ab3f5f87 100644 --- a/x/fungible/keeper/msg_server_deploy_fungible_coin_zrc20.go +++ b/x/fungible/keeper/msg_server_deploy_fungible_coin_zrc20.go @@ -45,7 +45,7 @@ func (k msgServer) DeployFungibleCoinZRC20(goCtx context.Context, msg *types.Msg } if msg.CoinType == zetacommon.CoinType_Gas { // #nosec G701 always in range - address, err = k.SetupChainGasCoinAndPool(ctx, msg.ForeignChainId, msg.Name, msg.Symbol, uint8(msg.Decimals)) + address, err = k.SetupChainGasCoinAndPool(ctx, msg.ForeignChainId, msg.Name, msg.Symbol, uint8(msg.Decimals), big.NewInt(msg.GasLimit)) if err != nil { return nil, sdkerrors.Wrapf(err, "failed to setupChainGasCoinAndPool") } diff --git a/x/fungible/keeper/msg_server_deploy_fungible_coin_zrc20_test.go b/x/fungible/keeper/msg_server_deploy_fungible_coin_zrc20_test.go index e40c1af9ae..788feba0fb 100644 --- a/x/fungible/keeper/msg_server_deploy_fungible_coin_zrc20_test.go +++ b/x/fungible/keeper/msg_server_deploy_fungible_coin_zrc20_test.go @@ -46,6 +46,11 @@ func TestMsgServer_DeployFungibleCoinZRC20(t *testing.T) { require.Equal(t, foreignCoin.CoinType, common.CoinType_Gas) require.Contains(t, foreignCoin.Name, "foo") + // check gas limit + gasLimit, err := k.QueryGasLimit(ctx, ethcommon.HexToAddress(foreignCoin.Zrc20ContractAddress)) + require.NoError(t, err) + require.Equal(t, uint64(1000000), gasLimit.Uint64()) + gas, err := k.QuerySystemContractGasCoinZRC20(ctx, big.NewInt(chainID)) require.NoError(t, err) require.Equal(t, gasAddress, gas.Hex()) @@ -59,7 +64,7 @@ func TestMsgServer_DeployFungibleCoinZRC20(t *testing.T) { "bar", "bar", common.CoinType_ERC20, - 1000000, + 2000000, )) require.NoError(t, err) assertContractDeployment(t, sdkk.EvmKeeper, ctx, ethcommon.HexToAddress(res.Address)) @@ -69,6 +74,11 @@ func TestMsgServer_DeployFungibleCoinZRC20(t *testing.T) { require.Equal(t, foreignCoin.CoinType, common.CoinType_ERC20) require.Contains(t, foreignCoin.Name, "bar") + // check gas limit + gasLimit, err = k.QueryGasLimit(ctx, ethcommon.HexToAddress(foreignCoin.Zrc20ContractAddress)) + require.NoError(t, err) + require.Equal(t, uint64(2000000), gasLimit.Uint64()) + // gas should remain the same gas, err = k.QuerySystemContractGasCoinZRC20(ctx, big.NewInt(chainID)) require.NoError(t, err) From db3e5072f6e94daba7f89974a838fb4a63422e3f Mon Sep 17 00:00:00 2001 From: Lucas Bertrand Date: Thu, 12 Oct 2023 14:00:59 -0700 Subject: [PATCH 12/27] fix(`fungible`): add CLI command to query system contract (#1252) * fix proto * fix filename * add cli query --- docs/openapi/openapi.swagger.yaml | 2 +- proto/fungible/query.proto | 2 +- x/fungible/client/cli/query.go | 1 + .../client/cli/query_system_contract.go | 32 +++++++++++++++++++ ...tract.go => grpc_query_system_contract.go} | 0 x/fungible/types/query.pb.go | 4 +-- 6 files changed, 37 insertions(+), 4 deletions(-) create mode 100644 x/fungible/client/cli/query_system_contract.go rename x/fungible/keeper/{grpc_query_zeta_deposit_and_call_contract.go => grpc_query_system_contract.go} (100%) diff --git a/docs/openapi/openapi.swagger.yaml b/docs/openapi/openapi.swagger.yaml index 2bd9ef4e4b..185c5305c3 100644 --- a/docs/openapi/openapi.swagger.yaml +++ b/docs/openapi/openapi.swagger.yaml @@ -27889,7 +27889,7 @@ paths: - Query /zeta-chain/zetacore/fungible/system_contract: get: - summary: Queries a ZetaDepositAndCallContract by index. + summary: Queries SystemContract operationId: Query_SystemContract responses: "200": diff --git a/proto/fungible/query.proto b/proto/fungible/query.proto index 6796836aab..9abb33095c 100644 --- a/proto/fungible/query.proto +++ b/proto/fungible/query.proto @@ -26,7 +26,7 @@ service Query { option (google.api.http).get = "/zeta-chain/zetacore/fungible/foreign_coins"; } - // Queries a ZetaDepositAndCallContract by index. + // Queries SystemContract rpc SystemContract(QueryGetSystemContractRequest) returns (QueryGetSystemContractResponse) { option (google.api.http).get = "/zeta-chain/zetacore/fungible/system_contract"; } diff --git a/x/fungible/client/cli/query.go b/x/fungible/client/cli/query.go index f4e4e7994e..74b4a55adb 100644 --- a/x/fungible/client/cli/query.go +++ b/x/fungible/client/cli/query.go @@ -30,6 +30,7 @@ func GetQueryCmd(_ string) *cobra.Command { CmdShowForeignCoins(), CmdGasStabilityPoolAddress(), CmdGasStabilityPoolBalance(), + CmdSystemContract(), ) return cmd diff --git a/x/fungible/client/cli/query_system_contract.go b/x/fungible/client/cli/query_system_contract.go new file mode 100644 index 0000000000..df79e833d9 --- /dev/null +++ b/x/fungible/client/cli/query_system_contract.go @@ -0,0 +1,32 @@ +package cli + +import ( + "context" + + "github.com/cosmos/cosmos-sdk/client" + "github.com/cosmos/cosmos-sdk/client/flags" + "github.com/spf13/cobra" + "github.com/zeta-chain/zetacore/x/fungible/types" +) + +func CmdSystemContract() *cobra.Command { + cmd := &cobra.Command{ + Use: "system-contract", + Short: "query system contract", + RunE: func(cmd *cobra.Command, args []string) error { + clientCtx := client.GetClientContextFromCmd(cmd) + queryClient := types.NewQueryClient(clientCtx) + + res, err := queryClient.SystemContract(context.Background(), &types.QueryGetSystemContractRequest{}) + if err != nil { + return err + } + + return clientCtx.PrintProto(res) + }, + } + + flags.AddQueryFlagsToCmd(cmd) + + return cmd +} diff --git a/x/fungible/keeper/grpc_query_zeta_deposit_and_call_contract.go b/x/fungible/keeper/grpc_query_system_contract.go similarity index 100% rename from x/fungible/keeper/grpc_query_zeta_deposit_and_call_contract.go rename to x/fungible/keeper/grpc_query_system_contract.go diff --git a/x/fungible/types/query.pb.go b/x/fungible/types/query.pb.go index 8c1744410b..f40c319e4e 100644 --- a/x/fungible/types/query.pb.go +++ b/x/fungible/types/query.pb.go @@ -655,7 +655,7 @@ type QueryClient interface { ForeignCoins(ctx context.Context, in *QueryGetForeignCoinsRequest, opts ...grpc.CallOption) (*QueryGetForeignCoinsResponse, error) // Queries a list of ForeignCoins items. ForeignCoinsAll(ctx context.Context, in *QueryAllForeignCoinsRequest, opts ...grpc.CallOption) (*QueryAllForeignCoinsResponse, error) - // Queries a ZetaDepositAndCallContract by index. + // Queries SystemContract SystemContract(ctx context.Context, in *QueryGetSystemContractRequest, opts ...grpc.CallOption) (*QueryGetSystemContractResponse, error) // Queries the address of a gas stability pool on a given chain. GasStabilityPoolAddress(ctx context.Context, in *QueryGetGasStabilityPoolAddress, opts ...grpc.CallOption) (*QueryGetGasStabilityPoolAddressResponse, error) @@ -733,7 +733,7 @@ type QueryServer interface { ForeignCoins(context.Context, *QueryGetForeignCoinsRequest) (*QueryGetForeignCoinsResponse, error) // Queries a list of ForeignCoins items. ForeignCoinsAll(context.Context, *QueryAllForeignCoinsRequest) (*QueryAllForeignCoinsResponse, error) - // Queries a ZetaDepositAndCallContract by index. + // Queries SystemContract SystemContract(context.Context, *QueryGetSystemContractRequest) (*QueryGetSystemContractResponse, error) // Queries the address of a gas stability pool on a given chain. GasStabilityPoolAddress(context.Context, *QueryGetGasStabilityPoolAddress) (*QueryGetGasStabilityPoolAddressResponse, error) From 8a308fc89bec7cca126c20ff6ea9d097f2bf2639 Mon Sep 17 00:00:00 2001 From: Lucas Bertrand Date: Fri, 13 Oct 2023 09:37:11 -0700 Subject: [PATCH 13/27] fix(`cmd`): add notice when using `--ledger` with Ethereum HD path (#1285) * change comment * add notice for ledger --- cmd/zetacored/main.go | 30 ++++++++++++++++++++++++++++-- cmd/zetacored/root.go | 3 +-- 2 files changed, 29 insertions(+), 4 deletions(-) diff --git a/cmd/zetacored/main.go b/cmd/zetacored/main.go index 4abdc3366b..5da5d57913 100644 --- a/cmd/zetacored/main.go +++ b/cmd/zetacored/main.go @@ -1,13 +1,14 @@ package main import ( + "fmt" "os" + "strings" "github.com/cosmos/cosmos-sdk/server" - cmdcfg "github.com/zeta-chain/zetacore/cmd/zetacored/config" - svrcmd "github.com/cosmos/cosmos-sdk/server/cmd" "github.com/zeta-chain/zetacore/app" + cmdcfg "github.com/zeta-chain/zetacore/cmd/zetacored/config" ) func main() { @@ -16,12 +17,37 @@ func main() { rootCmd, _ := NewRootCmd() if err := svrcmd.Execute(rootCmd, "", app.DefaultNodeHome); err != nil { + switch e := err.(type) { case server.ErrorCode: os.Exit(e.Code) default: + processError(e) os.Exit(1) } } } + +func processError(err error) { + // --ledger flag can't be used with Ethereum HD path + if strings.Contains(err.Error(), "cannot set custom bip32 path with ledger") { + printNotice([]string{ + "note: --ledger flag can't be used with Ethereum HD path (used by default)", + "use --hd-path=\"\" in the command to use Cosmos HD path", + }) + os.Exit(1) + } +} + +func printNotice(messages []string) { + if len(messages) == 0 { + return + } + border := strings.Repeat("*", len(messages[0])+4) // 4 to account for padding + fmt.Println(border) + for _, message := range messages { + fmt.Printf("* %s \n", message) + } + fmt.Println(border) +} diff --git a/cmd/zetacored/root.go b/cmd/zetacored/root.go index 82a146c582..68c60efcce 100644 --- a/cmd/zetacored/root.go +++ b/cmd/zetacored/root.go @@ -155,13 +155,12 @@ func initRootCmd(rootCmd *cobra.Command, encodingConfig appparams.EncodingConfig ethermintclient.KeyCommands(app.DefaultNodeHome), ) - // replace the default hd-path for the key add command + // replace the default hd-path for the key add command with Ethereum HD Path if err := SetEthereumHDPath(rootCmd); err != nil { fmt.Printf("warning: unable to set default HD path: %v\n", err) } rootCmd.AddCommand(server.RosettaCommand(encodingConfig.InterfaceRegistry, encodingConfig.Codec)) - } func addModuleInitFlags(startCmd *cobra.Command) { From db6a2f4d58f4b501daee845484d093f3b6a915a3 Mon Sep 17 00:00:00 2001 From: Lucas Bertrand Date: Fri, 13 Oct 2023 18:52:23 -0700 Subject: [PATCH 14/27] fix: gosec issues (#1290) * nosec * timeouts * comment position --- rpc/websockets.go | 22 +++++++++++++++++++--- x/emissions/client/tests/suite.go | 13 +++++++------ x/observer/module_simulation.go | 1 + 3 files changed, 27 insertions(+), 9 deletions(-) diff --git a/rpc/websockets.go b/rpc/websockets.go index 1346aad955..84d334e952 100644 --- a/rpc/websockets.go +++ b/rpc/websockets.go @@ -25,6 +25,7 @@ import ( "net" "net/http" "sync" + "time" "github.com/cosmos/cosmos-sdk/client" "github.com/ethereum/go-ethereum/common" @@ -47,6 +48,13 @@ import ( const ( messageSizeLimit = 32 * 1024 * 1024 // 32MB + +) + +var ( + readTimeout = 15 * time.Second // Time to read the request + writeTimeout = 15 * time.Second // Time to write the response + idleTimeout = 60 * time.Second // Max time for connections using TCP Keep-Alive ) type WebsocketsServer interface { @@ -111,13 +119,21 @@ func (s *websocketsServer) Start() { ws := mux.NewRouter() ws.Handle("/", s) + // configuring the HTTP server + server := &http.Server{ + Addr: s.wsAddr, + Handler: ws, + ReadTimeout: readTimeout, + WriteTimeout: writeTimeout, + IdleTimeout: idleTimeout, + } + go func() { var err error - /* #nosec G114 -- http functions have no support for timeouts */ if s.certFile == "" || s.keyFile == "" { - err = http.ListenAndServe(s.wsAddr, ws) + err = server.ListenAndServe() } else { - err = http.ListenAndServeTLS(s.wsAddr, s.certFile, s.keyFile, ws) + err = server.ListenAndServeTLS(s.certFile, s.keyFile) } if err != nil { diff --git a/x/emissions/client/tests/suite.go b/x/emissions/client/tests/suite.go index b9e950289d..b59adf9483 100644 --- a/x/emissions/client/tests/suite.go +++ b/x/emissions/client/tests/suite.go @@ -81,12 +81,13 @@ func RandomBallotGenerator(numberOfBallots int, voterList []string) []*observerT // #nosec G404 randomness is not a security issue here for i := 0; i < numberOfBallots; i++ { ballots[i] = &observerTypes.Ballot{ - Index: "", - BallotIdentifier: "TestBallot" + strconv.Itoa(i), - VoterList: voterList, - Votes: CreateRandomVoteList(len(voterList)), - ObservationType: observerTypes.ObservationType_InBoundTx, - BallotThreshold: sdk.MustNewDecFromStr("0.66"), + Index: "", + BallotIdentifier: "TestBallot" + strconv.Itoa(i), + VoterList: voterList, + Votes: CreateRandomVoteList(len(voterList)), + ObservationType: observerTypes.ObservationType_InBoundTx, + BallotThreshold: sdk.MustNewDecFromStr("0.66"), + // #nosec G404 randomness used for testing BallotStatus: ballotStatus[rand.Intn(max-min)+min], BallotCreationHeight: 0, } diff --git a/x/observer/module_simulation.go b/x/observer/module_simulation.go index 806a28c1db..08b52bcc08 100644 --- a/x/observer/module_simulation.go +++ b/x/observer/module_simulation.go @@ -11,6 +11,7 @@ import ( /* #nosec */ const ( + // #nosec G101 not a hardcoded credential opWeightMsgUpdateClientParams = "op_weight_msg_update_client_params" defaultWeightMsgUpdateClientParams int = 100 ) From d31b61cedcc87152215ea9de9dd7bd4cd907f69a Mon Sep 17 00:00:00 2001 From: Luke Ma Date: Sat, 14 Oct 2023 10:59:20 +0800 Subject: [PATCH 15/27] refactor: remove duplicate funtion name IsEthereum (#1279) Co-authored-by: Lucas Bertrand --- common/chain.go | 6 ------ x/observer/types/messages_add_block_header.go | 2 +- 2 files changed, 1 insertion(+), 7 deletions(-) diff --git a/common/chain.go b/common/chain.go index 0952a64b49..c0286a1f8d 100644 --- a/common/chain.go +++ b/common/chain.go @@ -102,12 +102,6 @@ func IsEVMChain(chainID int64) bool { chainID == 137 // polygon mainnet } -func IsEthereum(chainID int64) bool { - return chainID == 5 || // Goerli - chainID == 1337 || // eth privnet - chainID == 1 // eth mainnet -} - func (chain Chain) IsKlaytnChain() bool { return chain.ChainId == 1001 } diff --git a/x/observer/types/messages_add_block_header.go b/x/observer/types/messages_add_block_header.go index 453a2f1b10..cfa2867128 100644 --- a/x/observer/types/messages_add_block_header.go +++ b/x/observer/types/messages_add_block_header.go @@ -52,7 +52,7 @@ func (msg *MsgAddBlockHeader) ValidateBasic() error { return cosmoserrors.Wrapf(sdkerrors.ErrInvalidAddress, err.Error()) } - if common.IsEthereum(msg.ChainId) || common.IsBitcoinChain(msg.ChainId) { + if common.IsEthereumChain(msg.ChainId) || common.IsBitcoinChain(msg.ChainId) { if len(msg.BlockHash) != 32 { return cosmoserrors.Wrapf(sdkerrors.ErrInvalidRequest, "invalid block hash length (%d)", len(msg.BlockHash)) } From fb82095fb4776620ca9e08c330adf88ec316d223 Mon Sep 17 00:00:00 2001 From: Charlie Chen <34498985+ws4charlie@users.noreply.github.com> Date: Sat, 14 Oct 2023 00:40:29 -0500 Subject: [PATCH 16/27] fix: query outtx tracker by chain using prefixed store (#1283) * query outtx tracker by chain using prefixed store * query outtx tracker by chain using prefixed store --------- Co-authored-by: charliec Co-authored-by: Lucas Bertrand --- x/crosschain/keeper/keeper_out_tx_tracker.go | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/x/crosschain/keeper/keeper_out_tx_tracker.go b/x/crosschain/keeper/keeper_out_tx_tracker.go index 0eb2a7191a..308f4c13b0 100644 --- a/x/crosschain/keeper/keeper_out_tx_tracker.go +++ b/x/crosschain/keeper/keeper_out_tx_tracker.go @@ -124,17 +124,15 @@ func (k Keeper) OutTxTrackerAllByChain(c context.Context, req *types.QueryAllOut var outTxTrackers []types.OutTxTracker ctx := sdk.UnwrapSDKContext(c) - store := ctx.KVStore(k.storeKey) - outTxTrackerStore := prefix.NewStore(store, types.KeyPrefix(types.OutTxTrackerKeyPrefix)) + store := prefix.NewStore(ctx.KVStore(k.storeKey), types.KeyPrefix(types.OutTxTrackerKeyPrefix)) + chainStore := prefix.NewStore(store, types.KeyPrefix(fmt.Sprintf("%d-", req.Chain))) - pageRes, err := query.Paginate(outTxTrackerStore, req.Pagination, func(key []byte, value []byte) error { + pageRes, err := query.Paginate(chainStore, req.Pagination, func(key []byte, value []byte) error { var outTxTracker types.OutTxTracker if err := k.cdc.Unmarshal(value, &outTxTracker); err != nil { return err } - if outTxTracker.ChainId == req.Chain { - outTxTrackers = append(outTxTrackers, outTxTracker) - } + outTxTrackers = append(outTxTrackers, outTxTracker) return nil }) From e0c3ba16637e3b1961bbc23bc8a2ba6fda90fa59 Mon Sep 17 00:00:00 2001 From: Luke Ma Date: Tue, 17 Oct 2023 00:06:12 +0800 Subject: [PATCH 17/27] refactor: skip gas stability pool funding when gasLimit is equal gasUsed (#1289) * ignore funding the GasStabilityPool when remaining fees are 0 * optimize code format * follow coding standards --------- Co-authored-by: Lucas Bertrand --- .../keeper/keeper_cross_chain_tx_vote_outbound_tx.go | 6 +++++- .../keeper/keeper_cross_chain_tx_vote_outbound_tx_test.go | 7 +++++++ 2 files changed, 12 insertions(+), 1 deletion(-) diff --git a/x/crosschain/keeper/keeper_cross_chain_tx_vote_outbound_tx.go b/x/crosschain/keeper/keeper_cross_chain_tx_vote_outbound_tx.go index f7d781bfd2..3a07546157 100644 --- a/x/crosschain/keeper/keeper_cross_chain_tx_vote_outbound_tx.go +++ b/x/crosschain/keeper/keeper_cross_chain_tx_vote_outbound_tx.go @@ -226,9 +226,13 @@ func (k Keeper) FundGasStabilityPoolFromRemainingFees(ctx sdk.Context, outboundT gasLimit := outboundTxParams.OutboundTxEffectiveGasLimit gasPrice := math.NewUintFromBigInt(outboundTxParams.OutboundTxEffectiveGasPrice.BigInt()) + if gasLimit == gasUsed { + return nil + } + // We skip gas stability pool funding if one of the params is zero if gasLimit > 0 && gasUsed > 0 && !gasPrice.IsZero() { - if gasLimit >= gasUsed { + if gasLimit > gasUsed { remainingGas := gasLimit - gasUsed remainingFees := math.NewUint(remainingGas).Mul(gasPrice).BigInt() diff --git a/x/crosschain/keeper/keeper_cross_chain_tx_vote_outbound_tx_test.go b/x/crosschain/keeper/keeper_cross_chain_tx_vote_outbound_tx_test.go index 1cb362df6f..b5ad6ab78d 100644 --- a/x/crosschain/keeper/keeper_cross_chain_tx_vote_outbound_tx_test.go +++ b/x/crosschain/keeper/keeper_cross_chain_tx_vote_outbound_tx_test.go @@ -26,6 +26,13 @@ func TestKeeper_FundGasStabilityPoolFromRemainingFees(t *testing.T) { fundStabilityPoolExpectedRemainingFee *big.Int isError bool }{ + { + name: "no call if gasLimit is equal to gasUsed", + effectiveGasLimit: 42, + gasUsed: 42, + effectiveGasPrice: math.NewInt(42), + expectFundStabilityPoolCall: false, + }, { name: "no call if gasLimit is 0", effectiveGasLimit: 0, From 817cc4780e09065139de99cf3513a7968b10e80e Mon Sep 17 00:00:00 2001 From: kevinssgh <79858682+kevinssgh@users.noreply.github.com> Date: Mon, 16 Oct 2023 16:30:24 -0400 Subject: [PATCH 18/27] minor fixes to stateful upgrade (#1280) --- Dockerfile-versioned | 1 - Makefile | 2 +- contrib/localnet/orchestrator/start-upgrade.sh | 4 ++-- contrib/localnet/scripts/genesis-stateful.sh | 2 +- 4 files changed, 4 insertions(+), 5 deletions(-) diff --git a/Dockerfile-versioned b/Dockerfile-versioned index 0ec85f149e..c948817829 100644 --- a/Dockerfile-versioned +++ b/Dockerfile-versioned @@ -29,7 +29,6 @@ RUN cp $GOPATH/bin/smoketest $GOPATH/bin/new/ # Checkout and build old binary RUN cd node && git checkout ${old_version} -RUN cd node && git pull RUN cd node && make install RUN cd node && make install-smoketest RUN cp $GOPATH/bin/zetacored $GOPATH/bin/old/ diff --git a/Makefile b/Makefile index 575057ef70..c5662752b0 100644 --- a/Makefile +++ b/Makefile @@ -222,7 +222,7 @@ stop-stress-test: stateful-upgrade: @echo "--> Starting stateful smoketest" - $(DOCKER) build --build-arg old_version=v9.0.0-rc2 --build-arg new_version=v10.0.0 -t zetanode -f ./Dockerfile-versioned . + $(DOCKER) build --build-arg old_version=mock-mainnet-01-5-ga66d0b77 --build-arg new_version=v10.0.0-30 -t zetanode -f ./Dockerfile-versioned . $(DOCKER) build -t orchestrator -f contrib/localnet/orchestrator/Dockerfile-upgrade.fastbuild . cd contrib/localnet/ && $(DOCKER) compose -f docker-compose-stateful.yml up -d diff --git a/contrib/localnet/orchestrator/start-upgrade.sh b/contrib/localnet/orchestrator/start-upgrade.sh index b787a5b0da..a9e123ad72 100644 --- a/contrib/localnet/orchestrator/start-upgrade.sh +++ b/contrib/localnet/orchestrator/start-upgrade.sh @@ -29,9 +29,9 @@ if [ $SMOKETEST_EXIT_CODE -ne 0 ]; then fi # Restart zetaclients at upgrade height -/work/restart-zetaclientd.sh -u 330 -n 2 +/work/restart-zetaclientd.sh -u 400 -n 2 -smoketest-new "$SMOKETEST_CMD" --deployed --wait-for 335 +smoketest-new "$SMOKETEST_CMD" --deployed --wait-for 405 if [ $SMOKETEST_EXIT_CODE -eq 0 ]; then echo "smoketest passed" diff --git a/contrib/localnet/scripts/genesis-stateful.sh b/contrib/localnet/scripts/genesis-stateful.sh index 5f9f293f1b..ff3a0b4646 100755 --- a/contrib/localnet/scripts/genesis-stateful.sh +++ b/contrib/localnet/scripts/genesis-stateful.sh @@ -174,7 +174,7 @@ echo if [ $HOSTNAME = "zetacore0" ] then -/root/.zetacored/zetavisor/current/bin/zetacored tx gov submit-legacy-proposal software-upgrade $UpgradeName --from hotkey --deposit 100000000azeta --upgrade-height 320 --title $UpgradeName --description $UpgradeName --keyring-backend test --chain-id $CHAINID --yes --no-validate --fees=200azeta --broadcast-mode block +/root/.zetacored/zetavisor/current/bin/zetacored tx gov submit-legacy-proposal software-upgrade $UpgradeName --from hotkey --deposit 100000000azeta --upgrade-height 400 --title $UpgradeName --description $UpgradeName --keyring-backend test --chain-id $CHAINID --yes --no-validate --fees=200azeta --broadcast-mode block fi sleep 8 From 820465e323035e2b3490b8b51cc4d4a597a16051 Mon Sep 17 00:00:00 2001 From: Charlie <31941002+CharlieMc0@users.noreply.github.com> Date: Mon, 16 Oct 2023 13:53:01 -0700 Subject: [PATCH 19/27] ci: add mainnet builds to goreleaser (#1302) * Added mainnet builds to goreleaser --- .dockerignore | 3 +- .github/workflows/publish-release.yml | 4 +-- .goreleaser.yaml | 42 ++++++++++++++++++++++++++- 3 files changed, 45 insertions(+), 4 deletions(-) diff --git a/.dockerignore b/.dockerignore index 48ff9d1a32..adc6255bfe 100644 --- a/.dockerignore +++ b/.dockerignore @@ -2,4 +2,5 @@ localnet package.json yarn.lock .github/ -.gitignore \ No newline at end of file +.gitignore +dist/** \ No newline at end of file diff --git a/.github/workflows/publish-release.yml b/.github/workflows/publish-release.yml index 7f88220c26..773ff28c4d 100644 --- a/.github/workflows/publish-release.yml +++ b/.github/workflows/publish-release.yml @@ -3,8 +3,8 @@ name: Publish Release on: push: tags: - - "v*.*.*" - + - "v*.*.*" + concurrency: group: publish-release cancel-in-progress: false diff --git a/.goreleaser.yaml b/.goreleaser.yaml index 1995d6b43d..090108f3fa 100644 --- a/.goreleaser.yaml +++ b/.goreleaser.yaml @@ -62,7 +62,7 @@ builds: - -X github.com/zeta-chain/zetacore/common.CommitHash={{ .Env.COMMIT }} - -X github.com/zeta-chain/zetacore/common.BuildTime=={{ .Env.BUILDTIME }} - -X github.com/cosmos/cosmos-sdk/types.DBBackend=pebbledb -W + - id: "zetaclientd_testnet" main: ./cmd/zetaclientd binary: "zetaclientd_testnet-{{ .Os }}-{{ .Arch }}" @@ -121,6 +121,46 @@ W flags: *default_mock_mainnet_flags ldflags: *default_ldflags + - id: "zetacored_mainnet" + main: ./cmd/zetacored + binary: "zetacored_mainnet-{{ .Os }}-{{ .Arch }}" + env: + - 'CC={{ index .Env (print "CC_" .Os "_" .Arch) }}' + - 'CXX={{ index .Env (print "CXX_" .Os "_" .Arch) }}' + goos: + - linux + - darwin + - windows + goarch: + - arm64 + - amd64 + ignore: + - goos: windows + goarch: arm64 + flags: &default_mainnet_flags + - -tags=pebbledb,ledger,cgo + ldflags: *default_ldflags + + - id: "zetaclientd_mainnet" + main: ./cmd/zetaclientd + binary: "zetaclientd_mainnet-{{ .Os }}-{{ .Arch }}" + env: + - 'CC={{ index .Env (print "CC_" .Os "_" .Arch) }}' + - 'CXX={{ index .Env (print "CXX_" .Os "_" .Arch) }}' + goos: + - linux + # - darwin + # - windows + goarch: + - arm64 + - amd64 + ignore: + - goos: windows + goarch: arm64 + flags: *default_mainnet_flags + ldflags: *default_ldflags + + archives: - format: binary name_template: "{{ .Binary }}" From e48b35544466d48d0ae68e9dc57ede705ece6992 Mon Sep 17 00:00:00 2001 From: Lucas Bertrand Date: Mon, 16 Oct 2023 14:21:49 -0700 Subject: [PATCH 20/27] feat(`fungible`): add query command to get all gas stability pool balances (#1247) * remove contract address * add all stability pool query * add CLI command * lint --- docs/openapi/openapi.swagger.yaml | 33 +- proto/fungible/query.proto | 16 +- x/fungible/client/cli/query.go | 8 +- .../client/cli/query_gas_stability_pool.go | 25 + x/fungible/keeper/grpc_gas_stability_pool.go | 37 + x/fungible/types/query.pb.go | 631 ++++++++++++++++-- x/fungible/types/query.pb.gw.go | 65 ++ 7 files changed, 741 insertions(+), 74 deletions(-) diff --git a/docs/openapi/openapi.swagger.yaml b/docs/openapi/openapi.swagger.yaml index 185c5305c3..6e3026b4a7 100644 --- a/docs/openapi/openapi.swagger.yaml +++ b/docs/openapi/openapi.swagger.yaml @@ -27851,6 +27851,21 @@ paths: $ref: '#/definitions/googlerpcStatus' tags: - Query + /zeta-chain/zetacore/fungible/gas_stability_pool_balance: + get: + summary: Queries all gas stability pool balances. + operationId: Query_GasStabilityPoolBalanceAll + responses: + "200": + description: A successful response. + schema: + $ref: '#/definitions/fungibleQueryAllGasStabilityPoolBalanceResponse' + default: + description: An unexpected error response. + schema: + $ref: '#/definitions/googlerpcStatus' + tags: + - Query /zeta-chain/zetacore/fungible/gas_stability_pool_balance/{chain_id}: get: summary: Queries the balance of a gas stability pool on a given chain. @@ -50243,6 +50258,14 @@ definitions: - VOTE_OPTION_ABSTAIN: VOTE_OPTION_ABSTAIN defines an abstain vote option. - VOTE_OPTION_NO: VOTE_OPTION_NO defines a no vote option. - VOTE_OPTION_NO_WITH_VETO: VOTE_OPTION_NO_WITH_VETO defines a no with veto vote option. + QueryAllGasStabilityPoolBalanceResponseBalance: + type: object + properties: + chain_id: + type: string + format: int64 + balance: + type: string bitcoinProof: type: object properties: @@ -50880,6 +50903,14 @@ definitions: $ref: '#/definitions/fungibleForeignCoins' pagination: $ref: '#/definitions/v1beta1PageResponse' + fungibleQueryAllGasStabilityPoolBalanceResponse: + type: object + properties: + balances: + type: array + items: + type: object + $ref: '#/definitions/QueryAllGasStabilityPoolBalanceResponseBalance' fungibleQueryGetForeignCoinsResponse: type: object properties: @@ -50895,8 +50926,6 @@ definitions: fungibleQueryGetGasStabilityPoolBalanceResponse: type: object properties: - contract_address: - type: string balance: type: string fungibleQueryGetSystemContractResponse: diff --git a/proto/fungible/query.proto b/proto/fungible/query.proto index 9abb33095c..a54730ba76 100644 --- a/proto/fungible/query.proto +++ b/proto/fungible/query.proto @@ -40,6 +40,11 @@ service Query { rpc GasStabilityPoolBalance(QueryGetGasStabilityPoolBalance) returns (QueryGetGasStabilityPoolBalanceResponse) { option (google.api.http).get = "/zeta-chain/zetacore/fungible/gas_stability_pool_balance/{chain_id}"; } + + // Queries all gas stability pool balances. + rpc GasStabilityPoolBalanceAll(QueryAllGasStabilityPoolBalance) returns (QueryAllGasStabilityPoolBalanceResponse) { + option (google.api.http).get = "/zeta-chain/zetacore/fungible/gas_stability_pool_balance"; + } } // QueryParamsRequest is request type for the Query/Params RPC method. @@ -86,6 +91,15 @@ message QueryGetGasStabilityPoolBalance { } message QueryGetGasStabilityPoolBalanceResponse { - string contract_address = 1; string balance = 2; } + +message QueryAllGasStabilityPoolBalance {} + +message QueryAllGasStabilityPoolBalanceResponse { + message Balance { + int64 chain_id = 1; + string balance = 2; + } + repeated Balance balances = 1 [(gogoproto.nullable) = false]; +} diff --git a/x/fungible/client/cli/query.go b/x/fungible/client/cli/query.go index 74b4a55adb..f0498d44b8 100644 --- a/x/fungible/client/cli/query.go +++ b/x/fungible/client/cli/query.go @@ -2,14 +2,9 @@ package cli import ( "fmt" - // "strings" - - "github.com/spf13/cobra" "github.com/cosmos/cosmos-sdk/client" - // "github.com/cosmos/cosmos-sdk/client/flags" - // sdk "github.com/cosmos/cosmos-sdk/types" - + "github.com/spf13/cobra" "github.com/zeta-chain/zetacore/x/fungible/types" ) @@ -30,6 +25,7 @@ func GetQueryCmd(_ string) *cobra.Command { CmdShowForeignCoins(), CmdGasStabilityPoolAddress(), CmdGasStabilityPoolBalance(), + CmdGasStabilityPoolBalances(), CmdSystemContract(), ) diff --git a/x/fungible/client/cli/query_gas_stability_pool.go b/x/fungible/client/cli/query_gas_stability_pool.go index 4aa9e24a18..46e2fa3ae8 100644 --- a/x/fungible/client/cli/query_gas_stability_pool.go +++ b/x/fungible/client/cli/query_gas_stability_pool.go @@ -68,3 +68,28 @@ func CmdGasStabilityPoolBalance() *cobra.Command { return cmd } + +func CmdGasStabilityPoolBalances() *cobra.Command { + cmd := &cobra.Command{ + Use: "gas-stability-pool-balances", + Short: "query all gas stability pool balances", + Args: cobra.NoArgs, + RunE: func(cmd *cobra.Command, args []string) error { + clientCtx := client.GetClientContextFromCmd(cmd) + + queryClient := types.NewQueryClient(clientCtx) + + res, err := queryClient.GasStabilityPoolBalanceAll(context.Background(), &types.QueryAllGasStabilityPoolBalance{}) + if err != nil { + return err + } + + return clientCtx.PrintProto(res) + }, + } + + flags.AddPaginationFlagsToCmd(cmd, cmd.Use) + flags.AddQueryFlagsToCmd(cmd) + + return cmd +} diff --git a/x/fungible/keeper/grpc_gas_stability_pool.go b/x/fungible/keeper/grpc_gas_stability_pool.go index 449a336594..023ef82836 100644 --- a/x/fungible/keeper/grpc_gas_stability_pool.go +++ b/x/fungible/keeper/grpc_gas_stability_pool.go @@ -42,3 +42,40 @@ func (k Keeper) GasStabilityPoolBalance( return &types.QueryGetGasStabilityPoolBalanceResponse{Balance: balance.String()}, nil } + +func (k Keeper) GasStabilityPoolBalanceAll( + c context.Context, + req *types.QueryAllGasStabilityPoolBalance, +) (*types.QueryAllGasStabilityPoolBalanceResponse, error) { + if req == nil { + return nil, status.Error(codes.InvalidArgument, "invalid request") + } + ctx := sdk.UnwrapSDKContext(c) + + // iterate supported chains + chains := k.observerKeeper.GetParams(ctx).GetSupportedChains() + balances := make([]types.QueryAllGasStabilityPoolBalanceResponse_Balance, 0, len(chains)) + for _, chain := range chains { + if chain == nil { + return nil, status.Error(codes.Internal, "invalid chain") + } + chainID := chain.ChainId + + balance, err := k.GetGasStabilityPoolBalance(ctx, chainID) + if err != nil { + return nil, status.Error(codes.Internal, err.Error()) + } + if balance == nil { + return nil, status.Error(codes.NotFound, "no balance for the gas stability pool") + } + + balances = append(balances, types.QueryAllGasStabilityPoolBalanceResponse_Balance{ + ChainId: chainID, + Balance: balance.String(), + }) + } + + return &types.QueryAllGasStabilityPoolBalanceResponse{ + Balances: balances, + }, nil +} diff --git a/x/fungible/types/query.pb.go b/x/fungible/types/query.pb.go index f40c319e4e..0b2b3c1bc5 100644 --- a/x/fungible/types/query.pb.go +++ b/x/fungible/types/query.pb.go @@ -513,8 +513,7 @@ func (m *QueryGetGasStabilityPoolBalance) GetChainId() int64 { } type QueryGetGasStabilityPoolBalanceResponse struct { - ContractAddress string `protobuf:"bytes,1,opt,name=contract_address,json=contractAddress,proto3" json:"contract_address,omitempty"` - Balance string `protobuf:"bytes,2,opt,name=balance,proto3" json:"balance,omitempty"` + Balance string `protobuf:"bytes,2,opt,name=balance,proto3" json:"balance,omitempty"` } func (m *QueryGetGasStabilityPoolBalanceResponse) Reset() { @@ -552,14 +551,145 @@ func (m *QueryGetGasStabilityPoolBalanceResponse) XXX_DiscardUnknown() { var xxx_messageInfo_QueryGetGasStabilityPoolBalanceResponse proto.InternalMessageInfo -func (m *QueryGetGasStabilityPoolBalanceResponse) GetContractAddress() string { +func (m *QueryGetGasStabilityPoolBalanceResponse) GetBalance() string { if m != nil { - return m.ContractAddress + return m.Balance } return "" } -func (m *QueryGetGasStabilityPoolBalanceResponse) GetBalance() string { +type QueryAllGasStabilityPoolBalance struct { +} + +func (m *QueryAllGasStabilityPoolBalance) Reset() { *m = QueryAllGasStabilityPoolBalance{} } +func (m *QueryAllGasStabilityPoolBalance) String() string { return proto.CompactTextString(m) } +func (*QueryAllGasStabilityPoolBalance) ProtoMessage() {} +func (*QueryAllGasStabilityPoolBalance) Descriptor() ([]byte, []int) { + return fileDescriptor_d671b6e9298b37cd, []int{12} +} +func (m *QueryAllGasStabilityPoolBalance) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *QueryAllGasStabilityPoolBalance) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_QueryAllGasStabilityPoolBalance.Marshal(b, m, deterministic) + } else { + b = b[:cap(b)] + n, err := m.MarshalToSizedBuffer(b) + if err != nil { + return nil, err + } + return b[:n], nil + } +} +func (m *QueryAllGasStabilityPoolBalance) XXX_Merge(src proto.Message) { + xxx_messageInfo_QueryAllGasStabilityPoolBalance.Merge(m, src) +} +func (m *QueryAllGasStabilityPoolBalance) XXX_Size() int { + return m.Size() +} +func (m *QueryAllGasStabilityPoolBalance) XXX_DiscardUnknown() { + xxx_messageInfo_QueryAllGasStabilityPoolBalance.DiscardUnknown(m) +} + +var xxx_messageInfo_QueryAllGasStabilityPoolBalance proto.InternalMessageInfo + +type QueryAllGasStabilityPoolBalanceResponse struct { + Balances []QueryAllGasStabilityPoolBalanceResponse_Balance `protobuf:"bytes,1,rep,name=balances,proto3" json:"balances"` +} + +func (m *QueryAllGasStabilityPoolBalanceResponse) Reset() { + *m = QueryAllGasStabilityPoolBalanceResponse{} +} +func (m *QueryAllGasStabilityPoolBalanceResponse) String() string { return proto.CompactTextString(m) } +func (*QueryAllGasStabilityPoolBalanceResponse) ProtoMessage() {} +func (*QueryAllGasStabilityPoolBalanceResponse) Descriptor() ([]byte, []int) { + return fileDescriptor_d671b6e9298b37cd, []int{13} +} +func (m *QueryAllGasStabilityPoolBalanceResponse) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *QueryAllGasStabilityPoolBalanceResponse) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_QueryAllGasStabilityPoolBalanceResponse.Marshal(b, m, deterministic) + } else { + b = b[:cap(b)] + n, err := m.MarshalToSizedBuffer(b) + if err != nil { + return nil, err + } + return b[:n], nil + } +} +func (m *QueryAllGasStabilityPoolBalanceResponse) XXX_Merge(src proto.Message) { + xxx_messageInfo_QueryAllGasStabilityPoolBalanceResponse.Merge(m, src) +} +func (m *QueryAllGasStabilityPoolBalanceResponse) XXX_Size() int { + return m.Size() +} +func (m *QueryAllGasStabilityPoolBalanceResponse) XXX_DiscardUnknown() { + xxx_messageInfo_QueryAllGasStabilityPoolBalanceResponse.DiscardUnknown(m) +} + +var xxx_messageInfo_QueryAllGasStabilityPoolBalanceResponse proto.InternalMessageInfo + +func (m *QueryAllGasStabilityPoolBalanceResponse) GetBalances() []QueryAllGasStabilityPoolBalanceResponse_Balance { + if m != nil { + return m.Balances + } + return nil +} + +type QueryAllGasStabilityPoolBalanceResponse_Balance struct { + ChainId int64 `protobuf:"varint,1,opt,name=chain_id,json=chainId,proto3" json:"chain_id,omitempty"` + Balance string `protobuf:"bytes,2,opt,name=balance,proto3" json:"balance,omitempty"` +} + +func (m *QueryAllGasStabilityPoolBalanceResponse_Balance) Reset() { + *m = QueryAllGasStabilityPoolBalanceResponse_Balance{} +} +func (m *QueryAllGasStabilityPoolBalanceResponse_Balance) String() string { + return proto.CompactTextString(m) +} +func (*QueryAllGasStabilityPoolBalanceResponse_Balance) ProtoMessage() {} +func (*QueryAllGasStabilityPoolBalanceResponse_Balance) Descriptor() ([]byte, []int) { + return fileDescriptor_d671b6e9298b37cd, []int{13, 0} +} +func (m *QueryAllGasStabilityPoolBalanceResponse_Balance) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *QueryAllGasStabilityPoolBalanceResponse_Balance) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_QueryAllGasStabilityPoolBalanceResponse_Balance.Marshal(b, m, deterministic) + } else { + b = b[:cap(b)] + n, err := m.MarshalToSizedBuffer(b) + if err != nil { + return nil, err + } + return b[:n], nil + } +} +func (m *QueryAllGasStabilityPoolBalanceResponse_Balance) XXX_Merge(src proto.Message) { + xxx_messageInfo_QueryAllGasStabilityPoolBalanceResponse_Balance.Merge(m, src) +} +func (m *QueryAllGasStabilityPoolBalanceResponse_Balance) XXX_Size() int { + return m.Size() +} +func (m *QueryAllGasStabilityPoolBalanceResponse_Balance) XXX_DiscardUnknown() { + xxx_messageInfo_QueryAllGasStabilityPoolBalanceResponse_Balance.DiscardUnknown(m) +} + +var xxx_messageInfo_QueryAllGasStabilityPoolBalanceResponse_Balance proto.InternalMessageInfo + +func (m *QueryAllGasStabilityPoolBalanceResponse_Balance) GetChainId() int64 { + if m != nil { + return m.ChainId + } + return 0 +} + +func (m *QueryAllGasStabilityPoolBalanceResponse_Balance) GetBalance() string { if m != nil { return m.Balance } @@ -579,62 +709,68 @@ func init() { proto.RegisterType((*QueryGetGasStabilityPoolAddressResponse)(nil), "zetachain.zetacore.fungible.QueryGetGasStabilityPoolAddressResponse") proto.RegisterType((*QueryGetGasStabilityPoolBalance)(nil), "zetachain.zetacore.fungible.QueryGetGasStabilityPoolBalance") proto.RegisterType((*QueryGetGasStabilityPoolBalanceResponse)(nil), "zetachain.zetacore.fungible.QueryGetGasStabilityPoolBalanceResponse") + proto.RegisterType((*QueryAllGasStabilityPoolBalance)(nil), "zetachain.zetacore.fungible.QueryAllGasStabilityPoolBalance") + proto.RegisterType((*QueryAllGasStabilityPoolBalanceResponse)(nil), "zetachain.zetacore.fungible.QueryAllGasStabilityPoolBalanceResponse") + proto.RegisterType((*QueryAllGasStabilityPoolBalanceResponse_Balance)(nil), "zetachain.zetacore.fungible.QueryAllGasStabilityPoolBalanceResponse.Balance") } func init() { proto.RegisterFile("fungible/query.proto", fileDescriptor_d671b6e9298b37cd) } var fileDescriptor_d671b6e9298b37cd = []byte{ - // 785 bytes of a gzipped FileDescriptorProto - 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xa4, 0x56, 0x4f, 0x4f, 0x13, 0x41, - 0x1c, 0xed, 0x82, 0x80, 0x0c, 0x08, 0x66, 0xac, 0x11, 0x0b, 0x6e, 0x75, 0x55, 0x10, 0x91, 0x1d, - 0xa1, 0x21, 0x41, 0xe0, 0x60, 0x41, 0x21, 0xc4, 0x0b, 0x96, 0x8b, 0x7a, 0x69, 0xa6, 0xed, 0xb0, - 0x6c, 0xb2, 0xdd, 0x29, 0x9d, 0x29, 0xa1, 0x12, 0x2e, 0x7e, 0x02, 0x13, 0x4f, 0x7e, 0x11, 0x2f, - 0x7a, 0xf0, 0xc8, 0x91, 0xc4, 0x8b, 0x27, 0x35, 0xe0, 0xc9, 0x4f, 0x61, 0x3a, 0x7f, 0x4a, 0x5b, - 0x76, 0x97, 0x52, 0x6e, 0xbb, 0x33, 0xbf, 0xf7, 0x7b, 0xef, 0xcd, 0xfc, 0xf6, 0xb5, 0x20, 0xbe, - 0x55, 0xf1, 0x1d, 0x37, 0xe7, 0x11, 0xb4, 0x53, 0x21, 0xe5, 0xaa, 0x5d, 0x2a, 0x53, 0x4e, 0xe1, - 0xe8, 0x7b, 0xc2, 0x71, 0x7e, 0x1b, 0xbb, 0xbe, 0x2d, 0x9e, 0x68, 0x99, 0xd8, 0xba, 0x30, 0xf1, - 0x38, 0x4f, 0x59, 0x91, 0x32, 0x94, 0xc3, 0x4c, 0xa1, 0xd0, 0xee, 0x4c, 0x8e, 0x70, 0x3c, 0x83, - 0x4a, 0xd8, 0x71, 0x7d, 0xcc, 0x5d, 0xea, 0xcb, 0x46, 0x89, 0xb1, 0x7a, 0xfb, 0x2d, 0x5a, 0x26, - 0xae, 0xe3, 0x67, 0xf3, 0xd4, 0xf5, 0x99, 0xda, 0xbd, 0x59, 0xdf, 0x2d, 0xe1, 0x32, 0x2e, 0xea, - 0x65, 0xb3, 0xbe, 0xcc, 0xaa, 0x8c, 0x93, 0x62, 0x36, 0x4f, 0x7d, 0x5e, 0xc6, 0x79, 0xae, 0xf6, - 0xe3, 0x0e, 0x75, 0xa8, 0x78, 0x44, 0xb5, 0x27, 0x4d, 0xe5, 0x50, 0xea, 0x78, 0x04, 0xe1, 0x92, - 0x8b, 0xb0, 0xef, 0x53, 0x2e, 0x74, 0xa8, 0x9e, 0x56, 0x1c, 0xc0, 0xd7, 0x35, 0xa9, 0x1b, 0x82, - 0x28, 0x43, 0x76, 0x2a, 0x84, 0x71, 0xeb, 0x0d, 0xb8, 0xd1, 0xb4, 0xca, 0x4a, 0xd4, 0x67, 0x04, - 0xa6, 0x41, 0xaf, 0x14, 0x34, 0x62, 0xdc, 0x35, 0x1e, 0x0d, 0xcc, 0xde, 0xb7, 0x23, 0xce, 0xc3, - 0x96, 0xe0, 0xe5, 0x2b, 0x87, 0xbf, 0x92, 0xb1, 0x8c, 0x02, 0x5a, 0x29, 0x30, 0x2a, 0x3a, 0xaf, - 0x11, 0xbe, 0x2a, 0x9d, 0xaf, 0xd4, 0x8c, 0x2b, 0x62, 0x18, 0x07, 0x3d, 0xae, 0x5f, 0x20, 0x7b, - 0x82, 0xa0, 0x3f, 0x23, 0x5f, 0x2c, 0x06, 0xc6, 0x82, 0x41, 0x4a, 0xd7, 0x26, 0x18, 0xdc, 0x6a, - 0x58, 0x57, 0xea, 0x26, 0x23, 0xd5, 0x35, 0x36, 0x52, 0x1a, 0x9b, 0x9a, 0x58, 0x44, 0x29, 0x4d, - 0x7b, 0x5e, 0x90, 0xd2, 0x55, 0x00, 0x4e, 0x6f, 0x55, 0x31, 0x8e, 0xdb, 0x72, 0x04, 0xec, 0xda, - 0x08, 0xd8, 0x72, 0x70, 0xd4, 0x08, 0xd8, 0x1b, 0xd8, 0x21, 0x0a, 0x9b, 0x69, 0x40, 0x5a, 0xdf, - 0x0c, 0x65, 0xee, 0x0c, 0x4f, 0xa8, 0xb9, 0xee, 0x4b, 0x9b, 0x83, 0x6b, 0x4d, 0xea, 0xbb, 0x84, - 0xfa, 0x89, 0x73, 0xd5, 0x4b, 0x45, 0x4d, 0xf2, 0x93, 0xe0, 0x8e, 0xbe, 0x9a, 0x4d, 0x31, 0x94, - 0x2b, 0x6a, 0x26, 0xf5, 0x28, 0xed, 0x03, 0x33, 0xac, 0x40, 0x19, 0x7c, 0x0b, 0x86, 0x9a, 0x77, - 0xd4, 0x69, 0x4e, 0x45, 0x5a, 0x6c, 0x86, 0x28, 0x93, 0x2d, 0x8d, 0xac, 0x7b, 0x20, 0xa9, 0xc9, - 0xd7, 0x30, 0xdb, 0xe4, 0x38, 0xe7, 0x7a, 0x2e, 0xaf, 0x6e, 0x50, 0xea, 0xa5, 0x0b, 0x85, 0x32, - 0x61, 0xcc, 0xda, 0x01, 0x13, 0xe7, 0x94, 0xd4, 0x85, 0x3e, 0x04, 0x43, 0xf2, 0x84, 0xb2, 0x58, - 0xee, 0xa8, 0x29, 0xbd, 0x26, 0x57, 0x55, 0x39, 0x4c, 0x82, 0x01, 0xb2, 0x5b, 0xac, 0xd7, 0x74, - 0x89, 0x1a, 0x40, 0x76, 0x8b, 0x9a, 0x72, 0x29, 0x5c, 0xd5, 0x32, 0xf6, 0xb0, 0x9f, 0x27, 0xf0, - 0x36, 0xb8, 0x2a, 0x8c, 0x67, 0xdd, 0x82, 0x20, 0xe9, 0xce, 0xf4, 0x89, 0xf7, 0xf5, 0x82, 0xe5, - 0x87, 0x0b, 0x56, 0xe8, 0xba, 0xe0, 0x49, 0x70, 0x5d, 0x47, 0x44, 0x8b, 0xe4, 0x61, 0xbd, 0xae, - 0x45, 0x8f, 0x80, 0xbe, 0x9c, 0x44, 0x2b, 0xc1, 0xfa, 0x75, 0xf6, 0x4b, 0x3f, 0xe8, 0x11, 0x84, - 0xf0, 0xb3, 0x01, 0x7a, 0xe5, 0x47, 0x0d, 0x51, 0xe4, 0xdd, 0x9c, 0x4d, 0x94, 0xc4, 0xd3, 0xf6, - 0x01, 0x52, 0xbc, 0xf5, 0xe4, 0xc3, 0x8f, 0xbf, 0x9f, 0xba, 0xc6, 0xe1, 0x03, 0x54, 0xab, 0x9f, - 0x16, 0x50, 0xa4, 0xa1, 0xa8, 0x25, 0x21, 0xe1, 0x77, 0x03, 0x0c, 0x36, 0x4e, 0x3d, 0x9c, 0x3f, - 0x9f, 0x30, 0x38, 0x83, 0x12, 0xcf, 0x3a, 0x40, 0x2a, 0xcd, 0x8b, 0x42, 0xf3, 0x1c, 0x4c, 0x45, - 0x6b, 0x6e, 0xca, 0x7c, 0xb4, 0x2f, 0x42, 0xee, 0x00, 0x7e, 0x35, 0xc0, 0x70, 0x63, 0xd7, 0xb4, - 0xe7, 0xb5, 0xe3, 0x22, 0x38, 0x9f, 0xda, 0x71, 0x11, 0x92, 0x38, 0x56, 0x4a, 0xb8, 0x98, 0x86, - 0x53, 0x17, 0x70, 0x51, 0xbb, 0x80, 0x96, 0xaf, 0x0f, 0x2e, 0xb4, 0x75, 0x90, 0x81, 0xb1, 0x91, - 0x58, 0xec, 0x08, 0xab, 0x0c, 0xcc, 0x09, 0x03, 0x08, 0x4e, 0x47, 0x1b, 0x68, 0xf9, 0x15, 0x85, - 0xbf, 0x0d, 0x70, 0x2b, 0x24, 0x03, 0xe0, 0x52, 0x5b, 0x7a, 0x42, 0xd0, 0x89, 0x17, 0x97, 0x41, - 0xd7, 0x6d, 0x3d, 0x17, 0xb6, 0x16, 0xe0, 0x7c, 0xb4, 0x2d, 0x07, 0xb3, 0x2c, 0xd3, 0x7d, 0xb2, - 0x25, 0x4a, 0x3d, 0xfd, 0xf1, 0xc3, 0x7f, 0x01, 0x0e, 0x75, 0xe4, 0x74, 0xe6, 0x50, 0xa1, 0x3b, - 0x74, 0xd8, 0x12, 0x58, 0xd6, 0x2b, 0xe1, 0xf0, 0x25, 0x5c, 0xb9, 0xb0, 0x43, 0x95, 0x56, 0x68, - 0x5f, 0xc7, 0xe6, 0xc1, 0xf2, 0xfa, 0xe1, 0xb1, 0x69, 0x1c, 0x1d, 0x9b, 0xc6, 0x9f, 0x63, 0xd3, - 0xf8, 0x78, 0x62, 0xc6, 0x8e, 0x4e, 0xcc, 0xd8, 0xcf, 0x13, 0x33, 0xf6, 0x0e, 0x39, 0x2e, 0xdf, - 0xae, 0xe4, 0xec, 0x3c, 0x2d, 0x06, 0x12, 0xed, 0x9d, 0x52, 0xf1, 0x6a, 0x89, 0xb0, 0x5c, 0xaf, - 0xf8, 0xb3, 0x94, 0xfa, 0x1f, 0x00, 0x00, 0xff, 0xff, 0xd3, 0x77, 0x16, 0x8c, 0x16, 0x0a, 0x00, - 0x00, + // 843 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xa4, 0x56, 0xcf, 0x4f, 0x13, 0x4d, + 0x18, 0xee, 0xc2, 0xc7, 0x8f, 0x6f, 0xe0, 0xe3, 0x4b, 0xe6, 0xeb, 0x17, 0x71, 0xc1, 0xad, 0xae, + 0x0a, 0x2a, 0xb2, 0x23, 0x34, 0x24, 0x08, 0xc4, 0x58, 0xaa, 0x10, 0xa2, 0x07, 0x2c, 0x17, 0xf5, + 0xd2, 0x4c, 0xdb, 0x61, 0xd9, 0x64, 0xbb, 0x53, 0x3a, 0x5b, 0x42, 0x25, 0x5c, 0xfc, 0x0b, 0x4c, + 0x3c, 0x19, 0xff, 0x14, 0x3d, 0x78, 0xe4, 0x48, 0xe2, 0x45, 0x2f, 0x6a, 0x8a, 0x27, 0xff, 0x0a, + 0xd3, 0xd9, 0x77, 0x97, 0x6e, 0xed, 0xb6, 0xa5, 0xbd, 0xed, 0xce, 0xbc, 0xcf, 0xfb, 0x3c, 0xcf, + 0xcc, 0xdb, 0xa7, 0x8b, 0xe2, 0xbb, 0x15, 0xc7, 0xb4, 0x72, 0x36, 0x23, 0xfb, 0x15, 0x56, 0xae, + 0x1a, 0xa5, 0x32, 0x77, 0x39, 0x9e, 0x7a, 0xc5, 0x5c, 0x9a, 0xdf, 0xa3, 0x96, 0x63, 0xc8, 0x27, + 0x5e, 0x66, 0x86, 0x5f, 0xa8, 0xde, 0xc9, 0x73, 0x51, 0xe4, 0x82, 0xe4, 0xa8, 0x00, 0x14, 0x39, + 0x58, 0xc8, 0x31, 0x97, 0x2e, 0x90, 0x12, 0x35, 0x2d, 0x87, 0xba, 0x16, 0x77, 0xbc, 0x46, 0xea, + 0x74, 0xd0, 0x7e, 0x97, 0x97, 0x99, 0x65, 0x3a, 0xd9, 0x3c, 0xb7, 0x1c, 0x01, 0xbb, 0xff, 0x07, + 0xbb, 0x25, 0x5a, 0xa6, 0x45, 0x7f, 0x59, 0x0b, 0x96, 0x45, 0x55, 0xb8, 0xac, 0x98, 0xcd, 0x73, + 0xc7, 0x2d, 0xd3, 0xbc, 0x0b, 0xfb, 0x71, 0x93, 0x9b, 0x5c, 0x3e, 0x92, 0xfa, 0x93, 0x4f, 0x65, + 0x72, 0x6e, 0xda, 0x8c, 0xd0, 0x92, 0x45, 0xa8, 0xe3, 0x70, 0x57, 0xea, 0x80, 0x9e, 0x7a, 0x1c, + 0xe1, 0x67, 0x75, 0xa9, 0xdb, 0x92, 0x28, 0xc3, 0xf6, 0x2b, 0x4c, 0xb8, 0xfa, 0x73, 0xf4, 0x5f, + 0x68, 0x55, 0x94, 0xb8, 0x23, 0x18, 0x4e, 0xa1, 0x61, 0x4f, 0xd0, 0xa4, 0x72, 0x55, 0xb9, 0x35, + 0xb6, 0x78, 0xdd, 0x68, 0x73, 0x1e, 0x86, 0x07, 0x5e, 0xff, 0xeb, 0xe4, 0x5b, 0x22, 0x96, 0x01, + 0xa0, 0x9e, 0x44, 0x53, 0xb2, 0xf3, 0x26, 0x73, 0x37, 0x3c, 0xe7, 0xe9, 0xba, 0x71, 0x20, 0xc6, + 0x71, 0x34, 0x64, 0x39, 0x05, 0x76, 0x28, 0x09, 0xfe, 0xce, 0x78, 0x2f, 0xba, 0x40, 0xd3, 0xad, + 0x41, 0xa0, 0x6b, 0x07, 0x8d, 0xef, 0x36, 0xac, 0x83, 0xba, 0xdb, 0x6d, 0xd5, 0x35, 0x36, 0x02, + 0x8d, 0xa1, 0x26, 0x3a, 0x03, 0xa5, 0x29, 0xdb, 0x6e, 0xa5, 0x74, 0x03, 0xa1, 0xf3, 0x5b, 0x05, + 0xc6, 0x19, 0xc3, 0x1b, 0x01, 0xa3, 0x3e, 0x02, 0x86, 0x37, 0x38, 0x30, 0x02, 0xc6, 0x36, 0x35, + 0x19, 0x60, 0x33, 0x0d, 0x48, 0xfd, 0xa3, 0x02, 0xe6, 0xfe, 0xe0, 0x89, 0x34, 0x37, 0xd8, 0xb7, + 0x39, 0xbc, 0x19, 0x52, 0x3f, 0x20, 0xd5, 0xcf, 0x76, 0x54, 0xef, 0x29, 0x0a, 0xc9, 0x4f, 0xa0, + 0x2b, 0xfe, 0xd5, 0xec, 0xc8, 0xa1, 0x4c, 0xc3, 0x4c, 0xfa, 0xa3, 0x74, 0x84, 0xb4, 0xa8, 0x02, + 0x30, 0xf8, 0x02, 0x4d, 0x84, 0x77, 0xe0, 0x34, 0xe7, 0xda, 0x5a, 0x0c, 0x43, 0xc0, 0x64, 0x53, + 0x23, 0xfd, 0x1a, 0x4a, 0xf8, 0xe4, 0x9b, 0x54, 0xec, 0xb8, 0x34, 0x67, 0xd9, 0x96, 0x5b, 0xdd, + 0xe6, 0xdc, 0x4e, 0x15, 0x0a, 0x65, 0x26, 0x84, 0xbe, 0x8f, 0x66, 0x3b, 0x94, 0x04, 0x42, 0x6f, + 0xa2, 0x09, 0xef, 0x84, 0xb2, 0xd4, 0xdb, 0x81, 0x29, 0xfd, 0xc7, 0x5b, 0x85, 0x72, 0x9c, 0x40, + 0x63, 0xec, 0xa0, 0x18, 0xd4, 0x0c, 0xc8, 0x1a, 0xc4, 0x0e, 0x8a, 0x3e, 0xe5, 0x5a, 0xb4, 0xaa, + 0x75, 0x6a, 0x53, 0x27, 0xcf, 0xf0, 0x65, 0x34, 0x2a, 0x8d, 0x67, 0xad, 0x82, 0x24, 0x19, 0xcc, + 0x8c, 0xc8, 0xf7, 0xad, 0x82, 0x9e, 0x8e, 0x16, 0x0c, 0xe8, 0x40, 0xf0, 0x24, 0x1a, 0xc9, 0x79, + 0x4b, 0xa0, 0xc2, 0x7f, 0x0d, 0x0e, 0x26, 0x65, 0xdb, 0x11, 0x4d, 0xf4, 0xaf, 0x0a, 0x10, 0x45, + 0xd7, 0x04, 0x44, 0x0e, 0x1a, 0x85, 0xce, 0xfe, 0x7c, 0x3e, 0x6d, 0x7b, 0x79, 0x5d, 0xf6, 0x35, + 0xe0, 0x1d, 0x6e, 0x37, 0xe0, 0x50, 0x1f, 0xa0, 0x91, 0xce, 0x27, 0x15, 0x6d, 0x7f, 0xf1, 0xfd, + 0x18, 0x1a, 0x92, 0x1a, 0xf0, 0x3b, 0x05, 0x0d, 0x7b, 0x41, 0x85, 0x49, 0x67, 0xc9, 0xa1, 0x94, + 0x54, 0xef, 0x75, 0x0f, 0xf0, 0xfc, 0xe8, 0x77, 0x5f, 0x7f, 0xfe, 0xf9, 0x76, 0x60, 0x06, 0xdf, + 0x20, 0xf5, 0xfa, 0x79, 0x09, 0x25, 0x3e, 0x94, 0x34, 0xa5, 0x3e, 0xfe, 0xa4, 0xa0, 0xf1, 0xc6, + 0x5f, 0x32, 0x5e, 0xee, 0x4c, 0xd8, 0x3a, 0x57, 0xd5, 0xfb, 0x3d, 0x20, 0x41, 0xf3, 0xaa, 0xd4, + 0xbc, 0x84, 0x93, 0xed, 0x35, 0x87, 0xfe, 0xc7, 0xc8, 0x91, 0x0c, 0xee, 0x63, 0xfc, 0x41, 0x41, + 0xff, 0x36, 0x76, 0x4d, 0xd9, 0x76, 0x37, 0x2e, 0x5a, 0x67, 0x6e, 0x37, 0x2e, 0x22, 0x52, 0x54, + 0x4f, 0x4a, 0x17, 0xf3, 0x78, 0xee, 0x02, 0x2e, 0xea, 0x17, 0xd0, 0x94, 0x28, 0x78, 0xa5, 0xab, + 0x83, 0x6c, 0x19, 0x85, 0xea, 0x6a, 0x4f, 0x58, 0x30, 0xb0, 0x24, 0x0d, 0x10, 0x3c, 0xdf, 0xde, + 0x40, 0xd3, 0x97, 0x01, 0xfe, 0xae, 0xa0, 0x4b, 0x11, 0xb9, 0x86, 0xd7, 0xba, 0xd2, 0x13, 0x81, + 0x56, 0x1f, 0xf5, 0x83, 0x0e, 0x6c, 0x3d, 0x94, 0xb6, 0x56, 0xf0, 0x72, 0x7b, 0x5b, 0x26, 0x15, + 0x59, 0xe1, 0xf7, 0xc9, 0x96, 0x38, 0xb7, 0xfd, 0x7c, 0xc5, 0xbf, 0x5a, 0x38, 0xf4, 0xc3, 0xa1, + 0x37, 0x87, 0x80, 0xee, 0xd1, 0x61, 0x53, 0x86, 0xe9, 0x4f, 0xa4, 0xc3, 0xc7, 0x38, 0x7d, 0x61, + 0x87, 0x90, 0x56, 0xe4, 0xc8, 0x0f, 0xb8, 0x63, 0x5c, 0x53, 0x90, 0x1a, 0x41, 0x58, 0xff, 0x69, + 0xad, 0xf5, 0x93, 0xba, 0xdd, 0xf8, 0xed, 0x9c, 0xd9, 0x7d, 0xdc, 0x28, 0xf8, 0x5d, 0xdf, 0x3a, + 0xa9, 0x69, 0xca, 0x69, 0x4d, 0x53, 0x7e, 0xd4, 0x34, 0xe5, 0xcd, 0x99, 0x16, 0x3b, 0x3d, 0xd3, + 0x62, 0x5f, 0xce, 0xb4, 0xd8, 0x4b, 0x62, 0x5a, 0xee, 0x5e, 0x25, 0x67, 0xe4, 0x79, 0xb1, 0x65, + 0xf7, 0xc3, 0xf3, 0xfe, 0x6e, 0xb5, 0xc4, 0x44, 0x6e, 0x58, 0x7e, 0xe5, 0x26, 0x7f, 0x07, 0x00, + 0x00, 0xff, 0xff, 0x70, 0xd2, 0xfa, 0xa6, 0xcf, 0x0b, 0x00, 0x00, } // Reference imports to suppress errors if they are not otherwise used. @@ -661,6 +797,8 @@ type QueryClient interface { GasStabilityPoolAddress(ctx context.Context, in *QueryGetGasStabilityPoolAddress, opts ...grpc.CallOption) (*QueryGetGasStabilityPoolAddressResponse, error) // Queries the balance of a gas stability pool on a given chain. GasStabilityPoolBalance(ctx context.Context, in *QueryGetGasStabilityPoolBalance, opts ...grpc.CallOption) (*QueryGetGasStabilityPoolBalanceResponse, error) + // Queries all gas stability pool balances. + GasStabilityPoolBalanceAll(ctx context.Context, in *QueryAllGasStabilityPoolBalance, opts ...grpc.CallOption) (*QueryAllGasStabilityPoolBalanceResponse, error) } type queryClient struct { @@ -725,6 +863,15 @@ func (c *queryClient) GasStabilityPoolBalance(ctx context.Context, in *QueryGetG return out, nil } +func (c *queryClient) GasStabilityPoolBalanceAll(ctx context.Context, in *QueryAllGasStabilityPoolBalance, opts ...grpc.CallOption) (*QueryAllGasStabilityPoolBalanceResponse, error) { + out := new(QueryAllGasStabilityPoolBalanceResponse) + err := c.cc.Invoke(ctx, "/zetachain.zetacore.fungible.Query/GasStabilityPoolBalanceAll", in, out, opts...) + if err != nil { + return nil, err + } + return out, nil +} + // QueryServer is the server API for Query service. type QueryServer interface { // Parameters queries the parameters of the module. @@ -739,6 +886,8 @@ type QueryServer interface { GasStabilityPoolAddress(context.Context, *QueryGetGasStabilityPoolAddress) (*QueryGetGasStabilityPoolAddressResponse, error) // Queries the balance of a gas stability pool on a given chain. GasStabilityPoolBalance(context.Context, *QueryGetGasStabilityPoolBalance) (*QueryGetGasStabilityPoolBalanceResponse, error) + // Queries all gas stability pool balances. + GasStabilityPoolBalanceAll(context.Context, *QueryAllGasStabilityPoolBalance) (*QueryAllGasStabilityPoolBalanceResponse, error) } // UnimplementedQueryServer can be embedded to have forward compatible implementations. @@ -763,6 +912,9 @@ func (*UnimplementedQueryServer) GasStabilityPoolAddress(ctx context.Context, re func (*UnimplementedQueryServer) GasStabilityPoolBalance(ctx context.Context, req *QueryGetGasStabilityPoolBalance) (*QueryGetGasStabilityPoolBalanceResponse, error) { return nil, status.Errorf(codes.Unimplemented, "method GasStabilityPoolBalance not implemented") } +func (*UnimplementedQueryServer) GasStabilityPoolBalanceAll(ctx context.Context, req *QueryAllGasStabilityPoolBalance) (*QueryAllGasStabilityPoolBalanceResponse, error) { + return nil, status.Errorf(codes.Unimplemented, "method GasStabilityPoolBalanceAll not implemented") +} func RegisterQueryServer(s grpc1.Server, srv QueryServer) { s.RegisterService(&_Query_serviceDesc, srv) @@ -876,6 +1028,24 @@ func _Query_GasStabilityPoolBalance_Handler(srv interface{}, ctx context.Context return interceptor(ctx, in, info, handler) } +func _Query_GasStabilityPoolBalanceAll_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(QueryAllGasStabilityPoolBalance) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(QueryServer).GasStabilityPoolBalanceAll(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: "/zetachain.zetacore.fungible.Query/GasStabilityPoolBalanceAll", + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(QueryServer).GasStabilityPoolBalanceAll(ctx, req.(*QueryAllGasStabilityPoolBalance)) + } + return interceptor(ctx, in, info, handler) +} + var _Query_serviceDesc = grpc.ServiceDesc{ ServiceName: "zetachain.zetacore.fungible.Query", HandlerType: (*QueryServer)(nil), @@ -904,6 +1074,10 @@ var _Query_serviceDesc = grpc.ServiceDesc{ MethodName: "GasStabilityPoolBalance", Handler: _Query_GasStabilityPoolBalance_Handler, }, + { + MethodName: "GasStabilityPoolBalanceAll", + Handler: _Query_GasStabilityPoolBalanceAll_Handler, + }, }, Streams: []grpc.StreamDesc{}, Metadata: "fungible/query.proto", @@ -1283,12 +1457,100 @@ func (m *QueryGetGasStabilityPoolBalanceResponse) MarshalToSizedBuffer(dAtA []by i-- dAtA[i] = 0x12 } - if len(m.ContractAddress) > 0 { - i -= len(m.ContractAddress) - copy(dAtA[i:], m.ContractAddress) - i = encodeVarintQuery(dAtA, i, uint64(len(m.ContractAddress))) + return len(dAtA) - i, nil +} + +func (m *QueryAllGasStabilityPoolBalance) Marshal() (dAtA []byte, err error) { + size := m.Size() + dAtA = make([]byte, size) + n, err := m.MarshalToSizedBuffer(dAtA[:size]) + if err != nil { + return nil, err + } + return dAtA[:n], nil +} + +func (m *QueryAllGasStabilityPoolBalance) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *QueryAllGasStabilityPoolBalance) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + return len(dAtA) - i, nil +} + +func (m *QueryAllGasStabilityPoolBalanceResponse) Marshal() (dAtA []byte, err error) { + size := m.Size() + dAtA = make([]byte, size) + n, err := m.MarshalToSizedBuffer(dAtA[:size]) + if err != nil { + return nil, err + } + return dAtA[:n], nil +} + +func (m *QueryAllGasStabilityPoolBalanceResponse) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *QueryAllGasStabilityPoolBalanceResponse) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + if len(m.Balances) > 0 { + for iNdEx := len(m.Balances) - 1; iNdEx >= 0; iNdEx-- { + { + size, err := m.Balances[iNdEx].MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarintQuery(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0xa + } + } + return len(dAtA) - i, nil +} + +func (m *QueryAllGasStabilityPoolBalanceResponse_Balance) Marshal() (dAtA []byte, err error) { + size := m.Size() + dAtA = make([]byte, size) + n, err := m.MarshalToSizedBuffer(dAtA[:size]) + if err != nil { + return nil, err + } + return dAtA[:n], nil +} + +func (m *QueryAllGasStabilityPoolBalanceResponse_Balance) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *QueryAllGasStabilityPoolBalanceResponse_Balance) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + if len(m.Balance) > 0 { + i -= len(m.Balance) + copy(dAtA[i:], m.Balance) + i = encodeVarintQuery(dAtA, i, uint64(len(m.Balance))) + i-- + dAtA[i] = 0x12 + } + if m.ChainId != 0 { + i = encodeVarintQuery(dAtA, i, uint64(m.ChainId)) i-- - dAtA[i] = 0xa + dAtA[i] = 0x8 } return len(dAtA) - i, nil } @@ -1444,10 +1706,46 @@ func (m *QueryGetGasStabilityPoolBalanceResponse) Size() (n int) { } var l int _ = l - l = len(m.ContractAddress) + l = len(m.Balance) if l > 0 { n += 1 + l + sovQuery(uint64(l)) } + return n +} + +func (m *QueryAllGasStabilityPoolBalance) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + return n +} + +func (m *QueryAllGasStabilityPoolBalanceResponse) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + if len(m.Balances) > 0 { + for _, e := range m.Balances { + l = e.Size() + n += 1 + l + sovQuery(uint64(l)) + } + } + return n +} + +func (m *QueryAllGasStabilityPoolBalanceResponse_Balance) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + if m.ChainId != 0 { + n += 1 + sovQuery(uint64(m.ChainId)) + } l = len(m.Balance) if l > 0 { n += 1 + l + sovQuery(uint64(l)) @@ -2360,9 +2658,9 @@ func (m *QueryGetGasStabilityPoolBalanceResponse) Unmarshal(dAtA []byte) error { return fmt.Errorf("proto: QueryGetGasStabilityPoolBalanceResponse: illegal tag %d (wire type %d)", fieldNum, wire) } switch fieldNum { - case 1: + case 2: if wireType != 2 { - return fmt.Errorf("proto: wrong wireType = %d for field ContractAddress", wireType) + return fmt.Errorf("proto: wrong wireType = %d for field Balance", wireType) } var stringLen uint64 for shift := uint(0); ; shift += 7 { @@ -2390,8 +2688,211 @@ func (m *QueryGetGasStabilityPoolBalanceResponse) Unmarshal(dAtA []byte) error { if postIndex > l { return io.ErrUnexpectedEOF } - m.ContractAddress = string(dAtA[iNdEx:postIndex]) + m.Balance = string(dAtA[iNdEx:postIndex]) iNdEx = postIndex + default: + iNdEx = preIndex + skippy, err := skipQuery(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return ErrInvalidLengthQuery + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func (m *QueryAllGasStabilityPoolBalance) Unmarshal(dAtA []byte) error { + l := len(dAtA) + iNdEx := 0 + for iNdEx < l { + preIndex := iNdEx + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowQuery + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + fieldNum := int32(wire >> 3) + wireType := int(wire & 0x7) + if wireType == 4 { + return fmt.Errorf("proto: QueryAllGasStabilityPoolBalance: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: QueryAllGasStabilityPoolBalance: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + default: + iNdEx = preIndex + skippy, err := skipQuery(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return ErrInvalidLengthQuery + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func (m *QueryAllGasStabilityPoolBalanceResponse) Unmarshal(dAtA []byte) error { + l := len(dAtA) + iNdEx := 0 + for iNdEx < l { + preIndex := iNdEx + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowQuery + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + fieldNum := int32(wire >> 3) + wireType := int(wire & 0x7) + if wireType == 4 { + return fmt.Errorf("proto: QueryAllGasStabilityPoolBalanceResponse: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: QueryAllGasStabilityPoolBalanceResponse: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Balances", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowQuery + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return ErrInvalidLengthQuery + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return ErrInvalidLengthQuery + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.Balances = append(m.Balances, QueryAllGasStabilityPoolBalanceResponse_Balance{}) + if err := m.Balances[len(m.Balances)-1].Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + default: + iNdEx = preIndex + skippy, err := skipQuery(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return ErrInvalidLengthQuery + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func (m *QueryAllGasStabilityPoolBalanceResponse_Balance) Unmarshal(dAtA []byte) error { + l := len(dAtA) + iNdEx := 0 + for iNdEx < l { + preIndex := iNdEx + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowQuery + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + fieldNum := int32(wire >> 3) + wireType := int(wire & 0x7) + if wireType == 4 { + return fmt.Errorf("proto: Balance: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: Balance: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field ChainId", wireType) + } + m.ChainId = 0 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowQuery + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + m.ChainId |= int64(b&0x7F) << shift + if b < 0x80 { + break + } + } case 2: if wireType != 2 { return fmt.Errorf("proto: wrong wireType = %d for field Balance", wireType) diff --git a/x/fungible/types/query.pb.gw.go b/x/fungible/types/query.pb.gw.go index 5e3c9f3e9a..509f8a452a 100644 --- a/x/fungible/types/query.pb.gw.go +++ b/x/fungible/types/query.pb.gw.go @@ -231,6 +231,24 @@ func local_request_Query_GasStabilityPoolBalance_0(ctx context.Context, marshale } +func request_Query_GasStabilityPoolBalanceAll_0(ctx context.Context, marshaler runtime.Marshaler, client QueryClient, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) { + var protoReq QueryAllGasStabilityPoolBalance + var metadata runtime.ServerMetadata + + msg, err := client.GasStabilityPoolBalanceAll(ctx, &protoReq, grpc.Header(&metadata.HeaderMD), grpc.Trailer(&metadata.TrailerMD)) + return msg, metadata, err + +} + +func local_request_Query_GasStabilityPoolBalanceAll_0(ctx context.Context, marshaler runtime.Marshaler, server QueryServer, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) { + var protoReq QueryAllGasStabilityPoolBalance + var metadata runtime.ServerMetadata + + msg, err := server.GasStabilityPoolBalanceAll(ctx, &protoReq) + return msg, metadata, err + +} + // RegisterQueryHandlerServer registers the http handlers for service Query to "mux". // UnaryRPC :call QueryServer directly. // StreamingRPC :currently unsupported pending https://github.com/grpc/grpc-go/issues/906. @@ -375,6 +393,29 @@ func RegisterQueryHandlerServer(ctx context.Context, mux *runtime.ServeMux, serv }) + mux.Handle("GET", pattern_Query_GasStabilityPoolBalanceAll_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) { + ctx, cancel := context.WithCancel(req.Context()) + defer cancel() + var stream runtime.ServerTransportStream + ctx = grpc.NewContextWithServerTransportStream(ctx, &stream) + inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req) + rctx, err := runtime.AnnotateIncomingContext(ctx, mux, req) + if err != nil { + runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) + return + } + resp, md, err := local_request_Query_GasStabilityPoolBalanceAll_0(rctx, inboundMarshaler, server, req, pathParams) + md.HeaderMD, md.TrailerMD = metadata.Join(md.HeaderMD, stream.Header()), metadata.Join(md.TrailerMD, stream.Trailer()) + ctx = runtime.NewServerMetadataContext(ctx, md) + if err != nil { + runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) + return + } + + forward_Query_GasStabilityPoolBalanceAll_0(ctx, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...) + + }) + return nil } @@ -536,6 +577,26 @@ func RegisterQueryHandlerClient(ctx context.Context, mux *runtime.ServeMux, clie }) + mux.Handle("GET", pattern_Query_GasStabilityPoolBalanceAll_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) { + ctx, cancel := context.WithCancel(req.Context()) + defer cancel() + inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req) + rctx, err := runtime.AnnotateContext(ctx, mux, req) + if err != nil { + runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) + return + } + resp, md, err := request_Query_GasStabilityPoolBalanceAll_0(rctx, inboundMarshaler, client, req, pathParams) + ctx = runtime.NewServerMetadataContext(ctx, md) + if err != nil { + runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) + return + } + + forward_Query_GasStabilityPoolBalanceAll_0(ctx, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...) + + }) + return nil } @@ -551,6 +612,8 @@ var ( pattern_Query_GasStabilityPoolAddress_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2, 2, 3}, []string{"zeta-chain", "zetacore", "fungible", "gas_stability_pool_address"}, "", runtime.AssumeColonVerbOpt(false))) pattern_Query_GasStabilityPoolBalance_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2, 2, 3, 1, 0, 4, 1, 5, 4}, []string{"zeta-chain", "zetacore", "fungible", "gas_stability_pool_balance", "chain_id"}, "", runtime.AssumeColonVerbOpt(false))) + + pattern_Query_GasStabilityPoolBalanceAll_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2, 2, 3}, []string{"zeta-chain", "zetacore", "fungible", "gas_stability_pool_balance"}, "", runtime.AssumeColonVerbOpt(false))) ) var ( @@ -565,4 +628,6 @@ var ( forward_Query_GasStabilityPoolAddress_0 = runtime.ForwardResponseMessage forward_Query_GasStabilityPoolBalance_0 = runtime.ForwardResponseMessage + + forward_Query_GasStabilityPoolBalanceAll_0 = runtime.ForwardResponseMessage ) From 0a9d506b890252456435a3e5f728e60ee542b4b6 Mon Sep 17 00:00:00 2001 From: Tanmay Date: Mon, 16 Oct 2023 17:49:17 -0400 Subject: [PATCH 21/27] feat: tss funds migration (#1143) --- app/app.go | 7 +- common/commands.go | 3 +- docs/openapi/openapi.swagger.yaml | 7 + docs/spec/crosschain/messages.md | 10 + proto/crosschain/query.proto | 4 +- proto/crosschain/tx.proto | 11 + testutil/keeper/keeper.go | 24 +- testutil/simapp/simapp.go | 8 +- x/crosschain/client/cli/cli_cctx.go | 31 + x/crosschain/client/cli/cli_chain_nonce.go | 26 + x/crosschain/client/cli/cli_tss.go | 30 + x/crosschain/client/cli/query.go | 2 + .../client/cli/query_get_tss_address.go | 12 +- x/crosschain/client/cli/tx.go | 1 + .../keeper/grpc_query_get_tss_address.go | 23 +- x/crosschain/keeper/msg_migrate_tss_funds.go | 140 ++++ x/crosschain/types/errors.go | 1 + .../types/messages_migrate_tss_funds.go | 54 ++ .../types/messages_migrate_tss_funds_test.go | 59 ++ x/crosschain/types/query.pb.go | 422 ++++++------ x/crosschain/types/query.pb.gw.go | 18 + x/crosschain/types/tx.pb.go | 626 +++++++++++++++--- x/emissions/client/cli/query.go | 3 +- x/emissions/client/cli/tx.go | 3 +- .../client/tests/observer_rewards_test.go | 34 +- .../grpc_query_show_available_emissions.go | 2 +- x/emissions/keeper/keeper.go | 2 +- x/emissions/module.go | 12 +- x/emissions/types/events.pb.go | 4 +- zetaclient/bitcoin_client.go | 11 +- zetaclient/btc_signer.go | 4 +- zetaclient/config/config_mainnet.go | 1 + zetaclient/config/config_mock_mainnet.go | 1 + zetaclient/config/config_privnet.go | 1 + zetaclient/config/config_testnet.go | 1 + zetaclient/evm_signer.go | 35 +- 36 files changed, 1269 insertions(+), 364 deletions(-) create mode 100644 x/crosschain/keeper/msg_migrate_tss_funds.go create mode 100644 x/crosschain/types/messages_migrate_tss_funds.go create mode 100644 x/crosschain/types/messages_migrate_tss_funds_test.go diff --git a/app/app.go b/app/app.go index 53bfee51cd..fdcd402ed8 100644 --- a/app/app.go +++ b/app/app.go @@ -9,6 +9,9 @@ import ( "github.com/gorilla/mux" "github.com/rakyll/statik/fs" "github.com/spf13/cast" + emissionsModule "github.com/zeta-chain/zetacore/x/emissions" + emissionsModuleKeeper "github.com/zeta-chain/zetacore/x/emissions/keeper" + emissionsModuleTypes "github.com/zeta-chain/zetacore/x/emissions/types" "github.com/cosmos/cosmos-sdk/baseapp" "github.com/cosmos/cosmos-sdk/client" @@ -97,10 +100,6 @@ import ( zetaCoreModuleKeeper "github.com/zeta-chain/zetacore/x/crosschain/keeper" zetaCoreModuleTypes "github.com/zeta-chain/zetacore/x/crosschain/types" - emissionsModule "github.com/zeta-chain/zetacore/x/emissions" - emissionsModuleKeeper "github.com/zeta-chain/zetacore/x/emissions/keeper" - emissionsModuleTypes "github.com/zeta-chain/zetacore/x/emissions/types" - fungibleModule "github.com/zeta-chain/zetacore/x/fungible" fungibleModuleKeeper "github.com/zeta-chain/zetacore/x/fungible/keeper" fungibleModuleTypes "github.com/zeta-chain/zetacore/x/fungible/types" diff --git a/common/commands.go b/common/commands.go index d177f499f5..eb51797c3d 100644 --- a/common/commands.go +++ b/common/commands.go @@ -3,5 +3,6 @@ package common // commands for the zetaclient; mostly administrative commands/txs const ( - CmdWhitelistERC20 = "cmd_whitelist_erc20" + CmdWhitelistERC20 = "cmd_whitelist_erc20" + CmdMigrateTssFunds = "cmd_migrate_tss_funds" ) diff --git a/docs/openapi/openapi.swagger.yaml b/docs/openapi/openapi.swagger.yaml index 6e3026b4a7..ae13471986 100644 --- a/docs/openapi/openapi.swagger.yaml +++ b/docs/openapi/openapi.swagger.yaml @@ -26841,6 +26841,11 @@ paths: description: An unexpected error response. schema: $ref: '#/definitions/googlerpcStatus' + parameters: + - name: tss_pub_key + in: query + required: false + type: string tags: - Query /zeta-chain/crosschain/in_tx_hash_to_cctx_data/{inTxHash}: @@ -50519,6 +50524,8 @@ definitions: type: object crosschainMsgGasPriceVoterResponse: type: object + crosschainMsgMigrateTssFundsResponse: + type: object crosschainMsgNonceVoterResponse: type: object crosschainMsgRemoveFromOutTxTrackerResponse: diff --git a/docs/spec/crosschain/messages.md b/docs/spec/crosschain/messages.md index 43a8678e41..a42024e82e 100644 --- a/docs/spec/crosschain/messages.md +++ b/docs/spec/crosschain/messages.md @@ -231,3 +231,13 @@ message MsgUpdateTssAddress { } ``` +## MsgMigrateTssFunds + +```proto +message MsgMigrateTssFunds { + string creator = 1; + int64 chain_id = 2; + string amount = 3; +} +``` + diff --git a/proto/crosschain/query.proto b/proto/crosschain/query.proto index d68192bc7b..9f2c035a4c 100644 --- a/proto/crosschain/query.proto +++ b/proto/crosschain/query.proto @@ -205,7 +205,9 @@ message QueryAllInTxHashToCctxResponse { cosmos.base.query.v1beta1.PageResponse pagination = 2; } -message QueryGetTssAddressRequest {} +message QueryGetTssAddressRequest { + string tss_pub_key = 1; +} message QueryGetTssAddressResponse { string eth = 1; diff --git a/proto/crosschain/tx.proto b/proto/crosschain/tx.proto index 51826c92bc..2e3b3a63a6 100644 --- a/proto/crosschain/tx.proto +++ b/proto/crosschain/tx.proto @@ -17,9 +17,20 @@ service Msg { rpc VoteOnObservedInboundTx(MsgVoteOnObservedInboundTx) returns (MsgVoteOnObservedInboundTxResponse); rpc WhitelistERC20(MsgWhitelistERC20) returns (MsgWhitelistERC20Response); rpc UpdateTssAddress(MsgUpdateTssAddress) returns (MsgUpdateTssAddressResponse); + rpc MigrateTssFunds(MsgMigrateTssFunds) returns (MsgMigrateTssFundsResponse); // rpc ProveOutboundTx(MsgProveOutboundTx) returns (MsgProveOutboundTxResponse); } +message MsgMigrateTssFunds { + string creator = 1; + int64 chain_id = 2; + string amount = 3 [ + (gogoproto.customtype) = "github.com/cosmos/cosmos-sdk/types.Uint", + (gogoproto.nullable) = false + ]; +} +message MsgMigrateTssFundsResponse {} + message MsgUpdateTssAddress { string creator = 1; string tss_pubkey = 2; diff --git a/testutil/keeper/keeper.go b/testutil/keeper/keeper.go index 316dc4c598..2868f86941 100644 --- a/testutil/keeper/keeper.go +++ b/testutil/keeper/keeper.go @@ -40,7 +40,7 @@ import ( crosschaintypes "github.com/zeta-chain/zetacore/x/crosschain/types" emissionsmodule "github.com/zeta-chain/zetacore/x/emissions" emissionskeeper "github.com/zeta-chain/zetacore/x/emissions/keeper" - emissionstypes "github.com/zeta-chain/zetacore/x/emissions/types" + types2 "github.com/zeta-chain/zetacore/x/emissions/types" fungiblemodule "github.com/zeta-chain/zetacore/x/fungible" fungiblekeeper "github.com/zeta-chain/zetacore/x/fungible/keeper" fungibletypes "github.com/zeta-chain/zetacore/x/fungible/types" @@ -94,16 +94,16 @@ type ZetaKeepers struct { } var moduleAccountPerms = map[string][]string{ - authtypes.FeeCollectorName: nil, - distrtypes.ModuleName: nil, - stakingtypes.BondedPoolName: {authtypes.Burner, authtypes.Staking}, - stakingtypes.NotBondedPoolName: {authtypes.Burner, authtypes.Staking}, - evmtypes.ModuleName: {authtypes.Minter, authtypes.Burner}, - crosschaintypes.ModuleName: {authtypes.Minter, authtypes.Burner}, - fungibletypes.ModuleName: {authtypes.Minter, authtypes.Burner}, - emissionstypes.ModuleName: nil, - emissionstypes.UndistributedObserverRewardsPool: nil, - emissionstypes.UndistributedTssRewardsPool: nil, + authtypes.FeeCollectorName: nil, + distrtypes.ModuleName: nil, + stakingtypes.BondedPoolName: {authtypes.Burner, authtypes.Staking}, + stakingtypes.NotBondedPoolName: {authtypes.Burner, authtypes.Staking}, + evmtypes.ModuleName: {authtypes.Minter, authtypes.Burner}, + crosschaintypes.ModuleName: {authtypes.Minter, authtypes.Burner}, + fungibletypes.ModuleName: {authtypes.Minter, authtypes.Burner}, + types2.ModuleName: nil, + types2.UndistributedObserverRewardsPool: nil, + types2.UndistributedTssRewardsPool: nil, } // ModuleAccountAddrs returns all the app's module account addresses. @@ -363,7 +363,7 @@ func (zk ZetaKeepers) InitGenesis(ctx sdk.Context) { crosschainmodule.InitGenesis(ctx, *zk.CrosschainKeeper, *crosschaintypes.DefaultGenesis()) } if zk.EmissionsKeeper != nil { - emissionsmodule.InitGenesis(ctx, *zk.EmissionsKeeper, *emissionstypes.DefaultGenesis()) + emissionsmodule.InitGenesis(ctx, *zk.EmissionsKeeper, *types2.DefaultGenesis()) } if zk.FungibleKeeper != nil { fungiblemodule.InitGenesis(ctx, *zk.FungibleKeeper, *fungibletypes.DefaultGenesis()) diff --git a/testutil/simapp/simapp.go b/testutil/simapp/simapp.go index 698af75a72..cde89abbab 100644 --- a/testutil/simapp/simapp.go +++ b/testutil/simapp/simapp.go @@ -16,7 +16,7 @@ import ( tmproto "github.com/tendermint/tendermint/proto/tendermint/types" tmtypes "github.com/tendermint/tendermint/types" "github.com/zeta-chain/zetacore/cmd/zetacored/config" - emissionsModuleTypes "github.com/zeta-chain/zetacore/x/emissions/types" + types2 "github.com/zeta-chain/zetacore/x/emissions/types" //"github.com/ignite-hq/cli/ignite/pkg/cosmoscmd" abci "github.com/tendermint/tendermint/abci/types" @@ -58,7 +58,7 @@ func setup(withGenesis bool, invCheckPeriod uint) (*app.App, app.GenesisState) { return a, app.GenesisState{} } -func SetupWithGenesisValSet(t *testing.T, valSet *tmtypes.ValidatorSet, genDelAccs []authtypes.GenesisAccount, bondAmt sdk.Int, emissionParams emissionsModuleTypes.Params, genDelBalances []banktypes.Balance, genBalances []banktypes.Balance) *app.App { +func SetupWithGenesisValSet(t *testing.T, valSet *tmtypes.ValidatorSet, genDelAccs []authtypes.GenesisAccount, bondAmt sdk.Int, emissionParams types2.Params, genDelBalances []banktypes.Balance, genBalances []banktypes.Balance) *app.App { app, genesisState := setup(true, 5) // set genesis accounts authGenesis := authtypes.NewGenesisState(authtypes.DefaultParams(), genDelAccs) @@ -90,9 +90,9 @@ func SetupWithGenesisValSet(t *testing.T, valSet *tmtypes.ValidatorSet, genDelAc delegations = append(delegations, stakingtypes.NewDelegation(genDelAccs[0].GetAddress(), val.Address.Bytes(), sdk.OneDec())) } - emissionsGenesis := emissionsModuleTypes.DefaultGenesis() + emissionsGenesis := types2.DefaultGenesis() emissionsGenesis.Params = emissionParams - genesisState[emissionsModuleTypes.ModuleName] = app.AppCodec().MustMarshalJSON(emissionsGenesis) + genesisState[types2.ModuleName] = app.AppCodec().MustMarshalJSON(emissionsGenesis) // set validators and delegations params := stakingtypes.DefaultParams() params.BondDenom = config.BaseDenom diff --git a/x/crosschain/client/cli/cli_cctx.go b/x/crosschain/client/cli/cli_cctx.go index 058233bb77..070764ca44 100644 --- a/x/crosschain/client/cli/cli_cctx.go +++ b/x/crosschain/client/cli/cli_cctx.go @@ -49,6 +49,37 @@ func CmdListSend() *cobra.Command { return cmd } +func CmdPendingCctx() *cobra.Command { + cmd := &cobra.Command{ + Use: "list-pending-cctx [chain-id]", + Short: "shows pending CCTX", + Args: cobra.ExactArgs(1), + RunE: func(cmd *cobra.Command, args []string) error { + clientCtx := client.GetClientContextFromCmd(cmd) + + queryClient := types.NewQueryClient(clientCtx) + chainID, err := strconv.ParseInt(args[0], 10, 64) + if err != nil { + return err + } + params := &types.QueryAllCctxPendingRequest{ + ChainId: chainID, + } + + res, err := queryClient.CctxAllPending(context.Background(), params) + if err != nil { + return err + } + + return clientCtx.PrintProto(res) + }, + } + + flags.AddQueryFlagsToCmd(cmd) + + return cmd +} + func CmdShowSend() *cobra.Command { cmd := &cobra.Command{ Use: "show-cctx [index]", diff --git a/x/crosschain/client/cli/cli_chain_nonce.go b/x/crosschain/client/cli/cli_chain_nonce.go index dd1ddb2b0d..b5d1dec101 100644 --- a/x/crosschain/client/cli/cli_chain_nonce.go +++ b/x/crosschain/client/cli/cli_chain_nonce.go @@ -72,6 +72,32 @@ func CmdShowChainNonces() *cobra.Command { return cmd } +func CmdListPendingNonces() *cobra.Command { + cmd := &cobra.Command{ + Use: "list-pending-nonces", + Short: "shows a chainNonces", + Args: cobra.NoArgs, + RunE: func(cmd *cobra.Command, args []string) error { + clientCtx := client.GetClientContextFromCmd(cmd) + + queryClient := types.NewQueryClient(clientCtx) + + params := &types.QueryAllPendingNoncesRequest{} + + res, err := queryClient.PendingNoncesAll(context.Background(), params) + if err != nil { + return err + } + + return clientCtx.PrintProto(res) + }, + } + + flags.AddQueryFlagsToCmd(cmd) + + return cmd +} + // Transaction CLI ///////////////////////// func CmdNonceVoter() *cobra.Command { diff --git a/x/crosschain/client/cli/cli_tss.go b/x/crosschain/client/cli/cli_tss.go index f3bc6f18f7..0dd93a244c 100644 --- a/x/crosschain/client/cli/cli_tss.go +++ b/x/crosschain/client/cli/cli_tss.go @@ -5,6 +5,7 @@ import ( "fmt" "strconv" + "cosmossdk.io/math" "github.com/cosmos/cosmos-sdk/client/tx" "github.com/spf13/cast" "github.com/zeta-chain/zetacore/common" @@ -137,3 +138,32 @@ func CmdUpdateTss() *cobra.Command { flags.AddTxFlagsToCmd(cmd) return cmd } + +func CmdMigrateTssFunds() *cobra.Command { + cmd := &cobra.Command{ + Use: "migrate-tss-funds [chainID] [amount]", + Short: "Migrate TSS funds to the latest TSS address", + Args: cobra.ExactArgs(2), + RunE: func(cmd *cobra.Command, args []string) error { + + argsChainID, err := strconv.ParseInt(args[0], 10, 64) + if err != nil { + return err + } + argsAmount := math.NewUintFromString(args[1]) + clientCtx, err := client.GetClientTxContext(cmd) + if err != nil { + return err + } + + msg := types.NewMsgMigrateTssFunds(clientCtx.GetFromAddress().String(), argsChainID, argsAmount) + if err := msg.ValidateBasic(); err != nil { + return err + } + return tx.GenerateOrBroadcastTxCLI(clientCtx, cmd.Flags(), msg) + }, + } + + flags.AddTxFlagsToCmd(cmd) + return cmd +} diff --git a/x/crosschain/client/cli/query.go b/x/crosschain/client/cli/query.go index c87c38771c..fe4ac3dc4c 100644 --- a/x/crosschain/client/cli/query.go +++ b/x/crosschain/client/cli/query.go @@ -42,6 +42,8 @@ func GetQueryCmd(_ string) *cobra.Command { CmdQueryParams(), CmdGetTssAddress(), CmdListTssHistory(), + CmdListPendingNonces(), + CmdPendingCctx(), ) return cmd diff --git a/x/crosschain/client/cli/query_get_tss_address.go b/x/crosschain/client/cli/query_get_tss_address.go index 3c95d715cc..785dd05a03 100644 --- a/x/crosschain/client/cli/query_get_tss_address.go +++ b/x/crosschain/client/cli/query_get_tss_address.go @@ -9,19 +9,25 @@ import ( func CmdGetTssAddress() *cobra.Command { cmd := &cobra.Command{ - Use: "get-tss-address", + Use: "get-tss-address [tss-pubkey]", Short: "Query current tss address", - Args: cobra.NoArgs, + Args: cobra.MaximumNArgs(1), RunE: func(cmd *cobra.Command, args []string) (err error) { clientCtx, err := client.GetClientTxContext(cmd) if err != nil { return err } + tssPubKey := "" + if len(args) == 1 { + tssPubKey = args[0] + } queryClient := types.NewQueryClient(clientCtx) - params := &types.QueryGetTssAddressRequest{} + params := &types.QueryGetTssAddressRequest{ + TssPubKey: tssPubKey, + } res, err := queryClient.GetTssAddress(cmd.Context(), params) if err != nil { diff --git a/x/crosschain/client/cli/tx.go b/x/crosschain/client/cli/tx.go index 67e68c59f7..27a0c03af8 100644 --- a/x/crosschain/client/cli/tx.go +++ b/x/crosschain/client/cli/tx.go @@ -29,6 +29,7 @@ func GetTxCmd() *cobra.Command { CmdCCTXInboundVoter(), CmdRemoveFromWatchList(), CmdUpdateTss(), + CmdMigrateTssFunds(), ) return cmd diff --git a/x/crosschain/keeper/grpc_query_get_tss_address.go b/x/crosschain/keeper/grpc_query_get_tss_address.go index e7f5001361..6d21719388 100644 --- a/x/crosschain/keeper/grpc_query_get_tss_address.go +++ b/x/crosschain/keeper/grpc_query_get_tss_address.go @@ -21,16 +21,27 @@ func (k Keeper) GetTssAddress(goCtx context.Context, req *types.QueryGetTssAddre } ctx := sdk.UnwrapSDKContext(goCtx) - - tss, found := k.GetTSS(ctx) - if !found { - return nil, status.Error(codes.NotFound, "not found") + var tssPubKey string + if req.TssPubKey == "" { + tss, found := k.GetTSS(ctx) + if !found { + return nil, status.Error(codes.NotFound, "current tss not set") + } + tssPubKey = tss.TssPubkey + } else { + tssList := k.GetAllTSS(ctx) + for _, t := range tssList { + if t.TssPubkey == req.TssPubKey { + tssPubKey = t.TssPubkey + break + } + } } - ethAddress, err := getTssAddrEVM(tss.TssPubkey) + ethAddress, err := getTssAddrEVM(tssPubKey) if err != nil { return nil, status.Error(codes.Internal, err.Error()) } - btcAddress, err := getTssAddrBTC(tss.TssPubkey) + btcAddress, err := getTssAddrBTC(tssPubKey) if err != nil { return nil, status.Error(codes.Internal, err.Error()) } diff --git a/x/crosschain/keeper/msg_migrate_tss_funds.go b/x/crosschain/keeper/msg_migrate_tss_funds.go new file mode 100644 index 0000000000..85107860dc --- /dev/null +++ b/x/crosschain/keeper/msg_migrate_tss_funds.go @@ -0,0 +1,140 @@ +package keeper + +import ( + "context" + "fmt" + "sort" + + errorsmod "cosmossdk.io/errors" + sdkmath "cosmossdk.io/math" + sdk "github.com/cosmos/cosmos-sdk/types" + sdkerrors "github.com/cosmos/cosmos-sdk/types/errors" + "github.com/ethereum/go-ethereum/crypto" + tmbytes "github.com/tendermint/tendermint/libs/bytes" + tmtypes "github.com/tendermint/tendermint/types" + "github.com/zeta-chain/zetacore/common" + "github.com/zeta-chain/zetacore/x/crosschain/types" + observerTypes "github.com/zeta-chain/zetacore/x/observer/types" +) + +func (k msgServer) MigrateTssFunds(goCtx context.Context, msg *types.MsgMigrateTssFunds) (*types.MsgMigrateTssFundsResponse, error) { + ctx := sdk.UnwrapSDKContext(goCtx) + if msg.Creator != k.zetaObserverKeeper.GetParams(ctx).GetAdminPolicyAccount(observerTypes.Policy_Type_group2) { + return nil, errorsmod.Wrap(sdkerrors.ErrUnauthorized, "Update can only be executed by the correct policy account") + } + if k.zetaObserverKeeper.IsInboundEnabled(ctx) { + return nil, errorsmod.Wrap(types.ErrUnableToUpdateTss, "cannot migrate funds while inbound is enabled") + } + tss, found := k.GetTSS(ctx) + if !found { + return nil, errorsmod.Wrap(types.ErrUnableToUpdateTss, "cannot find current TSS") + } + pendingNonces, found := k.GetPendingNonces(ctx, tss.TssPubkey, msg.ChainId) + if !found { + return nil, errorsmod.Wrap(types.ErrUnableToUpdateTss, "cannot find pending nonces for chain") + } + if pendingNonces.NonceLow != pendingNonces.NonceHigh { + return nil, errorsmod.Wrap(types.ErrUnableToUpdateTss, "cannot migrate funds when there are pending nonces") + } + err := k.MigrateTSSFundsForChain(ctx, msg.ChainId, msg.Amount, tss) + if err != nil { + return nil, errorsmod.Wrap(types.ErrUnableToUpdateTss, err.Error()) + } + return &types.MsgMigrateTssFundsResponse{}, nil +} + +func (k Keeper) MigrateTSSFundsForChain(ctx sdk.Context, chainID int64, amount sdkmath.Uint, currentTss types.TSS) error { + tssList := k.GetAllTSS(ctx) + if len(tssList) < 2 { + return errorsmod.Wrap(types.ErrCannotMigrateTss, "only one TSS found") + } + // Sort tssList by FinalizedZetaHeight + sort.SliceStable(tssList, func(i, j int) bool { + return tssList[i].FinalizedZetaHeight < tssList[j].FinalizedZetaHeight + }) + // Always migrate to the latest TSS if multiple TSS addresses have been generated + newTss := tssList[len(tssList)-1] + ethAddressOld, err := getTssAddrEVM(currentTss.TssPubkey) + if err != nil { + return err + } + btcAddressOld, err := getTssAddrBTC(currentTss.TssPubkey) + if err != nil { + return err + } + ethAddressNew, err := getTssAddrEVM(newTss.TssPubkey) + if err != nil { + return err + } + btcAddressNew, err := getTssAddrBTC(newTss.TssPubkey) + if err != nil { + return err + } + + medianGasPrice, isFound := k.GetMedianGasPriceInUint(ctx, chainID) + if !isFound { + return types.ErrUnableToGetGasPrice + } + indexString := fmt.Sprintf("%s-%s-%d-%s-%d", currentTss.TssPubkey, newTss.TssPubkey, chainID, amount.String(), ctx.BlockHeight()) + + hash := crypto.Keccak256Hash([]byte(indexString)) + index := hash.Hex() + + cctx := types.CrossChainTx{ + Creator: "", + Index: index, + ZetaFees: sdkmath.Uint{}, + RelayedMessage: fmt.Sprintf("%s:%s", common.CmdMigrateTssFunds, "Funds Migrator Admin Cmd"), + CctxStatus: &types.Status{ + Status: types.CctxStatus_PendingOutbound, + StatusMessage: "", + LastUpdateTimestamp: 0, + }, + InboundTxParams: &types.InboundTxParams{ + Sender: "", + SenderChainId: chainID, + TxOrigin: "", + CoinType: common.CoinType_Cmd, + Asset: "", + Amount: amount, + InboundTxObservedHash: tmbytes.HexBytes(tmtypes.Tx(ctx.TxBytes()).Hash()).String(), + InboundTxObservedExternalHeight: 0, + InboundTxBallotIndex: "", + InboundTxFinalizedZetaHeight: 0, + }, + OutboundTxParams: []*types.OutboundTxParams{{ + Receiver: "", + ReceiverChainId: chainID, + CoinType: common.CoinType_Cmd, + Amount: amount, + OutboundTxTssNonce: 0, + OutboundTxGasLimit: 1_000_000, + OutboundTxGasPrice: medianGasPrice.MulUint64(2).String(), + OutboundTxHash: "", + OutboundTxBallotIndex: "", + OutboundTxObservedExternalHeight: 0, + OutboundTxGasUsed: 0, + OutboundTxEffectiveGasPrice: sdkmath.Int{}, + OutboundTxEffectiveGasLimit: 0, + TssPubkey: currentTss.TssPubkey, + }}} + + if common.IsEVMChain(chainID) { + cctx.InboundTxParams.Sender = ethAddressOld.String() + cctx.GetCurrentOutTxParam().Receiver = ethAddressNew.String() + } + if common.IsBitcoinChain(chainID) { + cctx.InboundTxParams.Sender = btcAddressOld + cctx.GetCurrentOutTxParam().Receiver = btcAddressNew + } + if cctx.GetCurrentOutTxParam().Receiver == "" { + return errorsmod.Wrap(types.ErrCannotMigrateTss, fmt.Sprintf("chain %d is not supported", chainID)) + } + err = k.UpdateNonce(ctx, chainID, &cctx) + if err != nil { + return err + } + k.SetCctxAndNonceToCctxAndInTxHashToCctx(ctx, cctx) + EmitEventInboundFinalized(ctx, &cctx) + return nil +} diff --git a/x/crosschain/types/errors.go b/x/crosschain/types/errors.go index da0674b5c3..32d07bc636 100644 --- a/x/crosschain/types/errors.go +++ b/x/crosschain/types/errors.go @@ -38,4 +38,5 @@ var ( ErrInvalidGasAmount = errorsmod.Register(ModuleName, 1137, "invalid gas amount") ErrNoLiquidityPool = errorsmod.Register(ModuleName, 1138, "no liquidity pool") ErrInvalidCoinType = errorsmod.Register(ModuleName, 1139, "invalid coin type") + ErrCannotMigrateTss = errorsmod.Register(ModuleName, 1140, "Cannot migrate TSS funds") ) diff --git a/x/crosschain/types/messages_migrate_tss_funds.go b/x/crosschain/types/messages_migrate_tss_funds.go new file mode 100644 index 0000000000..b667f4192c --- /dev/null +++ b/x/crosschain/types/messages_migrate_tss_funds.go @@ -0,0 +1,54 @@ +package types + +import ( + errorsmod "cosmossdk.io/errors" + sdkmath "cosmossdk.io/math" + sdk "github.com/cosmos/cosmos-sdk/types" + sdkerrors "github.com/cosmos/cosmos-sdk/types/errors" + "github.com/zeta-chain/zetacore/common" +) + +var _ sdk.Msg = &MsgMigrateTssFunds{} + +func NewMsgMigrateTssFunds(creator string, chainID int64, amount sdkmath.Uint) *MsgMigrateTssFunds { + return &MsgMigrateTssFunds{ + Creator: creator, + ChainId: chainID, + Amount: amount, + } +} + +func (msg *MsgMigrateTssFunds) Route() string { + return RouterKey +} + +func (msg *MsgMigrateTssFunds) Type() string { + return "MigrateTssFunds" +} + +func (msg *MsgMigrateTssFunds) GetSigners() []sdk.AccAddress { + creator, err := sdk.AccAddressFromBech32(msg.Creator) + if err != nil { + panic(err) + } + return []sdk.AccAddress{creator} +} + +func (msg *MsgMigrateTssFunds) GetSignBytes() []byte { + bz := ModuleCdc.MustMarshalJSON(msg) + return sdk.MustSortJSON(bz) +} + +func (msg *MsgMigrateTssFunds) ValidateBasic() error { + _, err := sdk.AccAddressFromBech32(msg.Creator) + if err != nil { + return errorsmod.Wrapf(sdkerrors.ErrInvalidAddress, "invalid creator address (%s)", err) + } + if common.GetChainFromChainID(msg.ChainId) == nil { + return errorsmod.Wrapf(sdkerrors.ErrInvalidRequest, "invalid chain id (%d)", msg.ChainId) + } + if msg.Amount.IsZero() { + return errorsmod.Wrapf(sdkerrors.ErrInvalidRequest, "amount cannot be zero") + } + return nil +} diff --git a/x/crosschain/types/messages_migrate_tss_funds_test.go b/x/crosschain/types/messages_migrate_tss_funds_test.go new file mode 100644 index 0000000000..bde8ebf02d --- /dev/null +++ b/x/crosschain/types/messages_migrate_tss_funds_test.go @@ -0,0 +1,59 @@ +package types_test + +import ( + "testing" + + sdkmath "cosmossdk.io/math" + "github.com/stretchr/testify/require" + "github.com/zeta-chain/zetacore/common" + "github.com/zeta-chain/zetacore/x/crosschain/types" + observerTypes "github.com/zeta-chain/zetacore/x/observer/types" +) + +func TestNewMsgMigrateTssFunds(t *testing.T) { + tests := []struct { + name string + msg types.MsgMigrateTssFunds + error bool + }{ + { + name: "invalid creator", + msg: types.MsgMigrateTssFunds{ + Creator: "invalid_address", + ChainId: common.GoerliChain().ChainId, + Amount: sdkmath.NewUintFromString("100000"), + }, + error: true, + }, + { + name: "invalid chain id", + msg: types.MsgMigrateTssFunds{ + Creator: "zeta15ruj2tc76pnj9xtw64utktee7cc7w6vzaes73z", + ChainId: 999, + Amount: sdkmath.NewUintFromString("100000"), + }, + error: true, + }, + { + name: "valid msg", + msg: types.MsgMigrateTssFunds{ + Creator: "zeta15ruj2tc76pnj9xtw64utktee7cc7w6vzaes73z", + ChainId: common.GoerliChain().ChainId, + Amount: sdkmath.NewUintFromString("100000"), + }, + error: false, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + observerTypes.SetConfig(false) + err := tt.msg.ValidateBasic() + if tt.error { + require.Error(t, err) + return + } else { + require.NoError(t, err) + } + }) + } +} diff --git a/x/crosschain/types/query.pb.go b/x/crosschain/types/query.pb.go index 793173dd20..dfeacc4365 100644 --- a/x/crosschain/types/query.pb.go +++ b/x/crosschain/types/query.pb.go @@ -763,6 +763,7 @@ func (m *QueryAllInTxHashToCctxResponse) GetPagination() *query.PageResponse { } type QueryGetTssAddressRequest struct { + TssPubKey string `protobuf:"bytes,1,opt,name=tss_pub_key,json=tssPubKey,proto3" json:"tss_pub_key,omitempty"` } func (m *QueryGetTssAddressRequest) Reset() { *m = QueryGetTssAddressRequest{} } @@ -798,6 +799,13 @@ func (m *QueryGetTssAddressRequest) XXX_DiscardUnknown() { var xxx_messageInfo_QueryGetTssAddressRequest proto.InternalMessageInfo +func (m *QueryGetTssAddressRequest) GetTssPubKey() string { + if m != nil { + return m.TssPubKey + } + return "" +} + type QueryGetTssAddressResponse struct { Eth string `protobuf:"bytes,1,opt,name=eth,proto3" json:"eth,omitempty"` Btc string `protobuf:"bytes,2,opt,name=btc,proto3" json:"btc,omitempty"` @@ -3077,196 +3085,197 @@ func init() { func init() { proto.RegisterFile("crosschain/query.proto", fileDescriptor_65a992045e92a606) } var fileDescriptor_65a992045e92a606 = []byte{ - // 3016 bytes of a gzipped FileDescriptorProto + // 3038 bytes of a gzipped FileDescriptorProto 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xd4, 0x5a, 0xdd, 0x6f, 0x1b, 0xc7, 0x11, 0xf7, 0x89, 0xfa, 0x5c, 0x7d, 0x7a, 0xad, 0x38, 0x0c, 0x63, 0x8b, 0xce, 0x39, 0xfe, 0x88, - 0x3f, 0xc8, 0x58, 0xb1, 0x95, 0xc4, 0x76, 0xd2, 0x48, 0x76, 0xac, 0x18, 0x51, 0x12, 0xf5, 0xa4, - 0xf4, 0xc3, 0x45, 0x4b, 0x9c, 0x8e, 0x6b, 0xea, 0x90, 0x23, 0x8f, 0xb9, 0x5d, 0x0a, 0x52, 0x0c, + 0x3f, 0xc8, 0x58, 0xb1, 0x9d, 0xc4, 0x76, 0xd2, 0x48, 0x76, 0xac, 0x18, 0x51, 0x12, 0xf5, 0xa4, + 0xf4, 0xc3, 0x45, 0x4b, 0x9c, 0x8e, 0x6b, 0xea, 0xe0, 0x23, 0x8f, 0xb9, 0x5d, 0x0a, 0x52, 0x0c, 0xb5, 0x40, 0xfe, 0x82, 0x00, 0x05, 0xda, 0x97, 0xbe, 0xf6, 0xe3, 0xa1, 0x0f, 0x01, 0x1a, 0x34, - 0x05, 0x0a, 0xa4, 0x0f, 0x6d, 0xd3, 0x3c, 0x06, 0x2d, 0x50, 0xb4, 0x28, 0x40, 0x14, 0x49, 0x9f, + 0x05, 0x0a, 0xa4, 0x0f, 0x6d, 0xd3, 0x3c, 0x06, 0x2d, 0x50, 0xb4, 0x28, 0x40, 0x14, 0x71, 0x9f, 0xf8, 0x1f, 0x14, 0xe8, 0x43, 0xb1, 0x73, 0x73, 0xbc, 0x3d, 0xf2, 0x4e, 0x3c, 0x51, 0x6c, 0xd1, - 0xbe, 0x88, 0xbb, 0xb3, 0x3b, 0xb3, 0xbf, 0x99, 0x9d, 0xd9, 0x9d, 0xbd, 0x11, 0x39, 0x69, 0x79, - 0x2e, 0xe7, 0xd6, 0xb6, 0x69, 0xd7, 0x8a, 0xef, 0x36, 0x98, 0xb7, 0x57, 0xa8, 0x7b, 0xae, 0x70, - 0xe9, 0xe9, 0xf7, 0x98, 0x30, 0x81, 0x5c, 0x80, 0x96, 0xeb, 0xb1, 0x42, 0x38, 0x35, 0x77, 0xc9, - 0x72, 0x79, 0xd5, 0xe5, 0xc5, 0x2d, 0x93, 0x33, 0x9f, 0xaf, 0xb8, 0x73, 0x6d, 0x8b, 0x09, 0xf3, - 0x5a, 0xb1, 0x6e, 0x56, 0xec, 0x9a, 0x29, 0x6c, 0xb7, 0xe6, 0x8b, 0xca, 0x9d, 0x56, 0x96, 0x80, + 0xbe, 0x88, 0xbb, 0xb3, 0x3b, 0xb3, 0xbf, 0x99, 0x9d, 0xd9, 0x9d, 0xbd, 0x11, 0x39, 0x6e, 0x79, + 0x2e, 0xe7, 0xd6, 0x96, 0x69, 0xd7, 0x8a, 0xef, 0x35, 0x98, 0xb7, 0x5b, 0xa8, 0x7b, 0xae, 0x70, + 0xe9, 0xc9, 0xf7, 0x99, 0x30, 0x81, 0x5c, 0x80, 0x96, 0xeb, 0xb1, 0x42, 0x38, 0x35, 0x77, 0xc1, + 0x72, 0x79, 0xd5, 0xe5, 0xc5, 0x4d, 0x93, 0x33, 0x9f, 0xaf, 0xb8, 0x7d, 0x65, 0x93, 0x09, 0xf3, + 0x4a, 0xb1, 0x6e, 0x56, 0xec, 0x9a, 0x29, 0x6c, 0xb7, 0xe6, 0x8b, 0xca, 0x9d, 0x54, 0x96, 0x80, 0xbf, 0xa5, 0x9a, 0x5b, 0xb3, 0x18, 0xc7, 0xe1, 0xbc, 0x3a, 0x2c, 0x9b, 0x25, 0x7f, 0x92, 0xd8, - 0xc5, 0x09, 0x39, 0x65, 0x42, 0xc5, 0xe4, 0xa5, 0xba, 0x67, 0x5b, 0x0c, 0xc7, 0xce, 0x2a, 0x63, - 0xc0, 0x53, 0xda, 0x36, 0xf9, 0x76, 0x49, 0xb8, 0x25, 0xcb, 0x6a, 0x0b, 0xd0, 0x95, 0x49, 0x8e, - 0xc9, 0x45, 0x69, 0xcb, 0x71, 0xad, 0x77, 0x4a, 0xdb, 0xcc, 0xae, 0x6c, 0x0b, 0x9c, 0xb3, 0xa0, - 0xcc, 0x01, 0x78, 0x1d, 0x32, 0x54, 0x94, 0x6e, 0x43, 0xc8, 0x95, 0x84, 0x67, 0x5a, 0xef, 0x30, - 0x0f, 0x27, 0x3c, 0xae, 0x4c, 0xa8, 0x9b, 0x9e, 0x59, 0x0d, 0xf4, 0x9b, 0x57, 0x06, 0x04, 0x6f, - 0x53, 0x2b, 0x6e, 0xc5, 0x85, 0x66, 0x51, 0xb6, 0x90, 0x7a, 0xaa, 0xe2, 0xba, 0x15, 0x87, 0x15, - 0xcd, 0xba, 0x5d, 0x34, 0x6b, 0x35, 0x57, 0x80, 0x1d, 0x91, 0x47, 0xcf, 0x92, 0x93, 0x5f, 0x95, - 0xa6, 0xde, 0xe4, 0xfc, 0x35, 0x9b, 0x0b, 0xd7, 0xdb, 0x33, 0xd8, 0xbb, 0x0d, 0xc6, 0x85, 0xfe, - 0x1d, 0xf2, 0x78, 0xd7, 0x08, 0xaf, 0xbb, 0x35, 0xce, 0xe8, 0x1d, 0x32, 0x2e, 0x38, 0x2f, 0x39, - 0x36, 0x17, 0x59, 0xed, 0x4c, 0xe6, 0xe2, 0xe4, 0xa2, 0x5e, 0x38, 0x70, 0x6f, 0x0b, 0x9b, 0x1b, - 0x1b, 0x2b, 0xc3, 0x9f, 0x35, 0xf3, 0xc7, 0x8c, 0x31, 0xc1, 0xf9, 0x9a, 0xcd, 0x85, 0x3e, 0x4f, - 0x28, 0xc8, 0x5f, 0x07, 0xc5, 0x82, 0x55, 0x1f, 0x90, 0x13, 0x11, 0x6a, 0x7b, 0xc5, 0x51, 0xdf, - 0x00, 0x59, 0xed, 0x8c, 0x76, 0x71, 0x72, 0xf1, 0x5c, 0x8f, 0xf5, 0x7c, 0x76, 0x5c, 0x12, 0x59, - 0xf5, 0x37, 0xc8, 0x93, 0x20, 0x7b, 0x95, 0x89, 0xb7, 0x1a, 0x62, 0x73, 0x77, 0xd3, 0x37, 0x36, - 0x2e, 0x4d, 0xb3, 0x64, 0x0c, 0x98, 0xef, 0xdf, 0x85, 0x45, 0x32, 0x46, 0xd0, 0xa5, 0xf3, 0x64, - 0x04, 0xf6, 0x2f, 0x3b, 0x74, 0x46, 0xbb, 0x38, 0x6c, 0xf8, 0x1d, 0xbd, 0x41, 0x4e, 0xc5, 0x8b, - 0x43, 0xcc, 0x6f, 0x93, 0x29, 0x57, 0xa1, 0x23, 0xf2, 0xcb, 0x3d, 0x90, 0xab, 0xa2, 0x10, 0x7f, - 0x44, 0x8c, 0xce, 0x50, 0x8b, 0x65, 0xc7, 0x89, 0xd3, 0xe2, 0x1e, 0x21, 0x61, 0xb4, 0xe0, 0x9a, - 0xe7, 0x0b, 0x7e, 0x68, 0x15, 0x64, 0x68, 0x15, 0xfc, 0x90, 0xc4, 0xd0, 0x2a, 0xac, 0x9b, 0x15, - 0x86, 0xbc, 0x86, 0xc2, 0xa9, 0x7f, 0xa2, 0xa1, 0x7a, 0x5d, 0xeb, 0x24, 0xaa, 0x97, 0x19, 0x80, - 0x7a, 0x74, 0x35, 0x82, 0x7f, 0x08, 0xf0, 0x5f, 0xe8, 0x89, 0xdf, 0xc7, 0x14, 0x51, 0xe0, 0x7d, - 0x8d, 0xe8, 0x71, 0x0a, 0xac, 0xec, 0xdd, 0x91, 0x48, 0x02, 0x7b, 0xcd, 0x93, 0x11, 0x40, 0x86, - 0x7b, 0xee, 0x77, 0x3a, 0xac, 0x38, 0xd4, 0xb7, 0x15, 0x7f, 0xaf, 0x91, 0xb3, 0x07, 0x82, 0xf8, - 0x3f, 0x31, 0xe6, 0x2d, 0x72, 0x3a, 0xf0, 0xf5, 0xfb, 0xb5, 0xcd, 0xdd, 0xd7, 0x4c, 0xbe, 0xbd, - 0xe9, 0xde, 0xb1, 0xc4, 0x6e, 0x60, 0xc6, 0x1c, 0x19, 0xb7, 0x71, 0x00, 0x2c, 0x39, 0x61, 0xb4, - 0xfb, 0xfa, 0x3e, 0x59, 0x48, 0x62, 0x46, 0xf5, 0xbf, 0x45, 0x66, 0xec, 0xc8, 0x08, 0x3a, 0xee, - 0xd5, 0x1e, 0x06, 0x88, 0x8a, 0x43, 0x13, 0x74, 0x88, 0xd2, 0x6f, 0xe3, 0xf2, 0xd1, 0xc9, 0x77, - 0x4d, 0x61, 0xa6, 0x01, 0xff, 0x1e, 0xc9, 0x27, 0x72, 0x23, 0xfa, 0xaf, 0x93, 0xe9, 0x3b, 0x12, - 0x13, 0x6c, 0xe9, 0xe6, 0x2e, 0x4f, 0xb9, 0x7b, 0x2a, 0x0f, 0x42, 0x8f, 0xca, 0xd1, 0x2b, 0x68, - 0xf5, 0x65, 0xc7, 0x89, 0xb7, 0xfa, 0xa0, 0x82, 0xfd, 0x53, 0x0d, 0x6d, 0x14, 0xb3, 0xd2, 0x01, - 0x5b, 0x94, 0x19, 0xd0, 0x16, 0x0d, 0xce, 0x4f, 0x9f, 0x24, 0x4f, 0x04, 0xae, 0xb6, 0xc9, 0xf9, - 0x72, 0xb9, 0xec, 0x31, 0xde, 0xbe, 0x5b, 0x5e, 0x21, 0xb9, 0xb8, 0x41, 0x54, 0x70, 0x8e, 0x64, - 0x98, 0x08, 0xf6, 0x5f, 0x36, 0x25, 0x65, 0x4b, 0x58, 0x00, 0x67, 0xc2, 0x90, 0xcd, 0xf6, 0x9d, - 0x25, 0x25, 0x6c, 0x6c, 0x04, 0x72, 0x5f, 0xc7, 0x3b, 0x2b, 0xa0, 0xa2, 0xc0, 0xeb, 0x24, 0xb3, - 0xb9, 0xb1, 0x81, 0xbb, 0x92, 0xe2, 0x82, 0x34, 0xe4, 0x74, 0xbd, 0x88, 0xd7, 0xee, 0x2a, 0x13, - 0xab, 0x26, 0x5f, 0x97, 0x79, 0x89, 0x72, 0x54, 0xd9, 0xb5, 0x32, 0xdb, 0x45, 0x8c, 0x7e, 0x47, - 0x2f, 0x91, 0x6c, 0x37, 0x43, 0x78, 0x51, 0x07, 0x34, 0xc4, 0x71, 0xa1, 0x07, 0x8e, 0xb6, 0x88, - 0x36, 0xa3, 0x6e, 0x22, 0xa2, 0x65, 0xc7, 0xe9, 0x44, 0x34, 0x28, 0xff, 0xfb, 0x99, 0x86, 0x4a, - 0x44, 0xd6, 0x88, 0x55, 0x22, 0xd3, 0x97, 0x12, 0x83, 0xf3, 0xb0, 0xc5, 0xd0, 0x89, 0x20, 0x4e, - 0xdf, 0x84, 0xbc, 0xf3, 0xe0, 0x2d, 0x7a, 0x27, 0x4c, 0x3c, 0x22, 0x3c, 0xa8, 0xe0, 0x1a, 0x99, - 0x54, 0xc8, 0x68, 0xc6, 0x4b, 0xbd, 0x4e, 0x0f, 0x45, 0x90, 0xca, 0xae, 0x97, 0x11, 0xe0, 0xb2, - 0xe3, 0xc4, 0x00, 0x1c, 0xd4, 0x8e, 0x7d, 0xa4, 0x85, 0x69, 0x48, 0x2a, 0x9d, 0x32, 0x47, 0xd0, - 0x69, 0x70, 0xbb, 0xb7, 0x10, 0x26, 0x35, 0xeb, 0xac, 0x56, 0xb6, 0x6b, 0x95, 0x88, 0x79, 0x74, - 0x11, 0x9e, 0xb8, 0x1d, 0xe3, 0xa8, 0xd7, 0x06, 0x99, 0xa9, 0xfb, 0x03, 0xf8, 0xe2, 0x40, 0xd5, - 0xae, 0xf4, 0x4a, 0x48, 0x23, 0xd2, 0xa6, 0xeb, 0x6a, 0x57, 0x7f, 0x89, 0x9c, 0xf1, 0x93, 0x5e, - 0x95, 0xda, 0x91, 0xa7, 0x3c, 0x41, 0xc6, 0xfd, 0x37, 0x8c, 0x5d, 0x8e, 0xa6, 0xa7, 0x65, 0xfd, - 0xbb, 0xe4, 0xa9, 0x03, 0xd8, 0x11, 0xf8, 0x37, 0x63, 0x80, 0x6b, 0x87, 0x05, 0x1e, 0x5c, 0x53, - 0x51, 0xf8, 0x4b, 0xe1, 0xfd, 0xbe, 0x66, 0x72, 0xb1, 0x22, 0x5f, 0x42, 0xaf, 0xc1, 0x43, 0xe8, - 0xe0, 0xb0, 0x78, 0x84, 0x57, 0x6b, 0x1c, 0x1f, 0xa2, 0xfe, 0x06, 0x99, 0xed, 0x18, 0x42, 0xd8, - 0x85, 0x1e, 0xb0, 0x3b, 0x05, 0x76, 0x8a, 0xd1, 0xb7, 0xc3, 0x1b, 0x2f, 0x01, 0xf4, 0xa0, 0x42, - 0xe5, 0x77, 0x1a, 0xea, 0x19, 0xb7, 0xd4, 0x41, 0x7a, 0x66, 0x06, 0xa0, 0xe7, 0xe0, 0x42, 0xe7, - 0x72, 0x78, 0xcb, 0xa9, 0x29, 0x48, 0xfc, 0xd6, 0xae, 0x29, 0xa7, 0xa4, 0xbc, 0xf6, 0xf7, 0xc0, - 0x55, 0xfa, 0x7d, 0x69, 0x55, 0xc8, 0x7c, 0x74, 0x69, 0xb4, 0xda, 0x5b, 0x64, 0x4a, 0x4d, 0x98, - 0x52, 0xbe, 0xb0, 0x54, 0x16, 0x23, 0x22, 0x40, 0xff, 0x36, 0xea, 0x28, 0x0f, 0xb5, 0xff, 0x40, - 0x9a, 0xf5, 0xa1, 0x86, 0x8a, 0xb4, 0xe5, 0x27, 0x2a, 0x92, 0x39, 0x92, 0x22, 0x83, 0xdb, 0xf5, - 0xef, 0x29, 0xb7, 0x89, 0x25, 0x76, 0xf1, 0x34, 0xe8, 0x7d, 0x28, 0x0d, 0xec, 0x05, 0xf5, 0xb1, - 0x7a, 0xd1, 0xa8, 0x08, 0xfe, 0xe7, 0x4d, 0x77, 0x0a, 0x4d, 0x27, 0x23, 0xf2, 0x01, 0x13, 0x66, - 0xe4, 0x74, 0xd1, 0x6f, 0xa0, 0x5a, 0x9d, 0xa3, 0xa8, 0xd6, 0x49, 0x32, 0xaa, 0x9c, 0x77, 0x19, - 0x03, 0x7b, 0xfa, 0x26, 0x5e, 0x60, 0x77, 0xdc, 0xda, 0x0e, 0xf3, 0x64, 0xc6, 0xb7, 0xe9, 0x4a, - 0xf6, 0xae, 0xd0, 0xea, 0xda, 0x90, 0x1c, 0x19, 0xaf, 0x98, 0x7c, 0xcd, 0xae, 0xda, 0x02, 0x53, - 0xda, 0x76, 0x5f, 0xff, 0xb1, 0x86, 0xf7, 0x5e, 0xb7, 0x58, 0xc4, 0x73, 0x85, 0x1c, 0x77, 0x1b, - 0x62, 0xcb, 0x6d, 0xd4, 0xca, 0xab, 0x26, 0xbf, 0x5f, 0x93, 0x83, 0x18, 0xf2, 0xdd, 0x03, 0x72, - 0x36, 0x7c, 0x5e, 0xb2, 0x5c, 0xe7, 0x1e, 0x63, 0x38, 0xdb, 0x5f, 0xb4, 0x7b, 0x80, 0x5e, 0x24, - 0xb3, 0xf2, 0x57, 0x3d, 0xfc, 0x32, 0x10, 0xfe, 0x9d, 0x64, 0xfd, 0x02, 0x39, 0x07, 0x30, 0xdf, - 0x60, 0x9c, 0x9b, 0x15, 0xb6, 0x6e, 0x72, 0x6e, 0xd7, 0x2a, 0xeb, 0xa1, 0xc4, 0xc0, 0xba, 0xf7, - 0xc8, 0xf9, 0x5e, 0x13, 0x51, 0xb1, 0x53, 0x64, 0xe2, 0x61, 0x1b, 0xa2, 0xaf, 0x50, 0x48, 0xd0, - 0x6f, 0xe1, 0x82, 0x0f, 0x5e, 0xfd, 0xda, 0x1b, 0x32, 0xbd, 0xf7, 0xcc, 0x1a, 0x37, 0x2d, 0xb9, - 0xbd, 0x06, 0xb3, 0x98, 0x5d, 0x6f, 0x5f, 0x16, 0x94, 0x0c, 0x6f, 0x87, 0xcf, 0x47, 0x68, 0xeb, - 0xff, 0x1a, 0x46, 0x14, 0x07, 0x70, 0xb7, 0xcd, 0x4b, 0xf0, 0x03, 0x62, 0x5b, 0xc8, 0xca, 0x74, - 0xab, 0x99, 0x9f, 0x00, 0xaa, 0x7c, 0x29, 0x19, 0x61, 0x93, 0x2e, 0x92, 0x29, 0x7f, 0x76, 0xad, - 0x51, 0xdd, 0x62, 0x9e, 0x6f, 0xd9, 0x95, 0xd9, 0x56, 0x33, 0x3f, 0x09, 0xf4, 0x37, 0x81, 0x6c, - 0xa8, 0x1d, 0xfa, 0x32, 0x99, 0xb3, 0xdc, 0x9a, 0xf0, 0x4c, 0x4b, 0x94, 0x4c, 0xff, 0xe9, 0x03, - 0x56, 0x9e, 0x58, 0x39, 0xd1, 0x6a, 0xe6, 0x67, 0x83, 0xb1, 0xe0, 0x55, 0xd4, 0x49, 0xa0, 0xaf, - 0x92, 0x13, 0x56, 0xa3, 0xda, 0x70, 0x4c, 0x61, 0xef, 0xb0, 0x52, 0xc5, 0xe4, 0xa5, 0x06, 0x67, - 0xe5, 0xec, 0x30, 0x88, 0x78, 0xac, 0xd5, 0xcc, 0x1f, 0x0f, 0x87, 0x57, 0x4d, 0xfe, 0x36, 0x67, - 0x65, 0xa3, 0x9b, 0x44, 0x4f, 0x91, 0xe1, 0x87, 0x9e, 0x5b, 0xcd, 0x8e, 0x00, 0xdf, 0x78, 0xab, - 0x99, 0x87, 0xbe, 0x01, 0x7f, 0xe9, 0x79, 0xf0, 0x51, 0x5f, 0xf2, 0x28, 0xcc, 0x98, 0x6c, 0x35, - 0xf3, 0x63, 0x15, 0x94, 0x17, 0x34, 0xa4, 0xb9, 0x1c, 0xb7, 0xc2, 0x4b, 0x5b, 0x8e, 0xeb, 0x56, - 0xb3, 0x63, 0xa1, 0xb9, 0x24, 0x75, 0x45, 0x12, 0x8d, 0xb0, 0x49, 0x75, 0x32, 0xca, 0x85, 0x29, - 0x1a, 0x3c, 0x3b, 0x0e, 0x33, 0x49, 0xab, 0x99, 0x47, 0x8a, 0x81, 0xbf, 0xf4, 0x24, 0x19, 0x12, - 0x6e, 0x76, 0x02, 0xc6, 0x47, 0x5b, 0xcd, 0xfc, 0x90, 0x70, 0x8d, 0x21, 0xe1, 0x4a, 0xb3, 0x89, - 0x70, 0xdb, 0xfc, 0xed, 0x21, 0xa1, 0xd9, 0x94, 0x31, 0xd8, 0xa4, 0x4e, 0x02, 0x5d, 0x26, 0xc7, - 0x55, 0x7e, 0xff, 0xaa, 0x9c, 0x04, 0x01, 0xf3, 0xad, 0x66, 0x5e, 0x15, 0x7e, 0x5f, 0x8e, 0x19, - 0x5d, 0x14, 0xba, 0x44, 0x86, 0xa5, 0x2e, 0xd9, 0xa9, 0x54, 0x5f, 0x5a, 0xd7, 0xdc, 0x8a, 0x01, - 0xf3, 0xf5, 0xf7, 0x33, 0x24, 0xb3, 0xe6, 0x56, 0xe4, 0x91, 0x10, 0x6c, 0xb8, 0xef, 0x9d, 0x41, - 0x57, 0x1e, 0x32, 0xc2, 0xad, 0xdb, 0x16, 0xcf, 0x0e, 0x9d, 0xc9, 0x5c, 0x9c, 0x30, 0xb0, 0x27, - 0x9d, 0xb9, 0x6c, 0x0a, 0xd3, 0xf7, 0x0f, 0x03, 0xda, 0x5d, 0x3e, 0x27, 0x37, 0x7e, 0xb8, 0xb7, - 0xcf, 0x75, 0x19, 0x6f, 0xe4, 0xa8, 0xc6, 0x1b, 0x85, 0x85, 0xd3, 0x1a, 0x2f, 0x1a, 0x58, 0x63, - 0x3d, 0x02, 0xeb, 0x19, 0x22, 0xdd, 0x06, 0x17, 0x1a, 0x87, 0x85, 0xa6, 0x5a, 0xcd, 0xfc, 0xb8, - 0xe3, 0x56, 0xfc, 0x05, 0xda, 0x2d, 0x7a, 0x8e, 0x8c, 0x79, 0xac, 0xea, 0xee, 0xb0, 0x32, 0x78, - 0xcd, 0xb8, 0xef, 0xa9, 0x48, 0x32, 0x82, 0x86, 0x7e, 0x1d, 0xd3, 0xcc, 0xb8, 0x23, 0x20, 0xf9, - 0xe4, 0xf8, 0xe7, 0x30, 0xa6, 0x8c, 0x71, 0x6c, 0xff, 0xb5, 0x23, 0x23, 0x88, 0xd5, 0x4c, 0x6c, - 0xac, 0x3e, 0x41, 0x32, 0x15, 0x93, 0xe3, 0x01, 0x30, 0xd6, 0x6a, 0xe6, 0x65, 0xd7, 0x90, 0x7f, - 0xa4, 0x19, 0xdb, 0x45, 0x15, 0xdc, 0x70, 0x30, 0x63, 0xa5, 0xfd, 0x2e, 0x0f, 0x5a, 0x72, 0x0d, - 0xc0, 0x3f, 0x1a, 0xae, 0x21, 0xfb, 0xbe, 0x1d, 0x68, 0x5e, 0x26, 0x97, 0xf5, 0x86, 0xc0, 0x8d, - 0x9b, 0x68, 0x35, 0xf3, 0x3e, 0xc1, 0xf0, 0x7f, 0xe4, 0x04, 0x3f, 0x5f, 0x1c, 0x0f, 0x27, 0x00, - 0x01, 0x53, 0xc7, 0xc4, 0xb8, 0x8e, 0x75, 0x2d, 0x72, 0xa8, 0xb8, 0xcc, 0x93, 0x91, 0x1d, 0xd3, - 0x69, 0x30, 0x0c, 0x67, 0x58, 0x1b, 0x08, 0x86, 0xff, 0x23, 0x75, 0x13, 0x7b, 0x75, 0x96, 0x9d, - 0x0a, 0x75, 0x93, 0x7d, 0x03, 0xfe, 0xd2, 0x22, 0x99, 0x34, 0x2d, 0x8b, 0x05, 0x75, 0x94, 0x69, - 0x19, 0x81, 0x2b, 0x33, 0xad, 0x66, 0x9e, 0xf8, 0xe4, 0x35, 0x5b, 0x66, 0x42, 0x61, 0x5b, 0x1e, - 0x8e, 0xed, 0x64, 0x6b, 0x26, 0x3c, 0x1c, 0xf1, 0x7e, 0x0f, 0x2f, 0xfa, 0x13, 0x44, 0xdb, 0xc9, - 0xce, 0xc2, 0x84, 0x91, 0x56, 0x33, 0xaf, 0xed, 0x18, 0xda, 0x8e, 0x24, 0x7a, 0xd9, 0xb9, 0x90, - 0xe8, 0x19, 0x9a, 0x27, 0x89, 0x3c, 0x7b, 0x3c, 0x24, 0x72, 0x43, 0xe3, 0xfa, 0x4d, 0x7c, 0x8c, - 0xa2, 0xeb, 0xc1, 0xf5, 0xbb, 0xb2, 0x87, 0xfe, 0x81, 0x3e, 0x7b, 0x92, 0x8c, 0x6e, 0x87, 0xd9, - 0xc9, 0xb0, 0x81, 0x3d, 0xfd, 0xaf, 0x63, 0xf8, 0x14, 0x8d, 0x67, 0x46, 0xcf, 0xd5, 0xc9, 0x28, - 0x7a, 0xa1, 0x16, 0x9e, 0xc7, 0x3e, 0xc5, 0xc0, 0xdf, 0xb6, 0x5f, 0x0c, 0xc5, 0xfa, 0x45, 0x91, - 0x4c, 0xd6, 0x4d, 0x8f, 0xd5, 0x84, 0xef, 0xfc, 0xbe, 0x83, 0x82, 0xed, 0x7c, 0x32, 0x78, 0xbf, - 0xd2, 0x0e, 0xfd, 0x64, 0x38, 0xc1, 0x4f, 0x8a, 0x64, 0x92, 0x6f, 0x9b, 0xcf, 0x95, 0x1a, 0x35, - 0xcb, 0x61, 0x1c, 0x9d, 0x16, 0x24, 0x4a, 0xf2, 0xdb, 0x40, 0x35, 0x94, 0x76, 0xc7, 0x15, 0x34, - 0xda, 0xe3, 0x0a, 0x8a, 0xba, 0x1b, 0x2f, 0x79, 0xae, 0x1b, 0x38, 0x75, 0xa7, 0xbb, 0x71, 0xc3, - 0x75, 0x85, 0xd1, 0x45, 0x91, 0x0b, 0xca, 0xbb, 0x8a, 0xf9, 0xbc, 0xe3, 0xe1, 0x82, 0x40, 0x05, - 0xa6, 0xb0, 0x49, 0x6f, 0x90, 0x69, 0xcf, 0xcf, 0x31, 0x70, 0x31, 0x3f, 0x04, 0xe6, 0x5a, 0xcd, - 0xfc, 0x54, 0x30, 0x00, 0x3c, 0x91, 0x9e, 0xb4, 0x53, 0xd5, 0xae, 0x31, 0x0f, 0x43, 0x01, 0xec, - 0x04, 0x04, 0xc3, 0xff, 0xa1, 0x05, 0x42, 0xca, 0xf6, 0xc3, 0x87, 0xb6, 0xd5, 0x70, 0xc4, 0x1e, - 0x7a, 0x3e, 0x98, 0x29, 0xa4, 0x1a, 0x4a, 0x1b, 0xae, 0x00, 0x57, 0x98, 0x4e, 0x49, 0xe1, 0x9a, - 0x52, 0xae, 0x00, 0x39, 0x76, 0x37, 0x64, 0xed, 0x24, 0x48, 0xad, 0xd9, 0xae, 0xf0, 0xcc, 0x12, - 0x5c, 0x48, 0xd3, 0xa1, 0xd6, 0x40, 0x85, 0xcf, 0xf0, 0x61, 0x53, 0x7a, 0x0d, 0xb7, 0xdf, 0x63, - 0x18, 0x1e, 0xe0, 0x35, 0xb2, 0x6f, 0xc0, 0xdf, 0xe0, 0x58, 0x72, 0x20, 0x05, 0x9e, 0x8d, 0x1c, - 0x4b, 0x90, 0x06, 0x87, 0x09, 0x71, 0x24, 0x11, 0x99, 0x3b, 0x20, 0x11, 0xb9, 0x4c, 0x26, 0x84, - 0x5d, 0x65, 0x5c, 0x98, 0xd5, 0x3a, 0x46, 0x12, 0xa0, 0x6b, 0x13, 0x8d, 0xb0, 0x49, 0xaf, 0x93, - 0x29, 0x75, 0x57, 0xb3, 0x14, 0x42, 0x1e, 0xb6, 0x24, 0xb2, 0xdb, 0x91, 0x9e, 0x8c, 0x16, 0x74, - 0xca, 0x13, 0x30, 0x1f, 0xa2, 0xc5, 0xa7, 0x18, 0xf8, 0x4b, 0x6f, 0x92, 0x39, 0xf9, 0x32, 0x29, - 0x3d, 0x64, 0xac, 0x54, 0x67, 0x9e, 0x4c, 0xcf, 0xb2, 0xf3, 0x80, 0xe6, 0x78, 0xab, 0x99, 0x9f, - 0x96, 0x63, 0xf7, 0x18, 0x5b, 0x67, 0xde, 0xaa, 0xc9, 0x8d, 0x68, 0x57, 0xaa, 0x5a, 0xb5, 0xfd, - 0x1a, 0x77, 0xf6, 0xb1, 0x50, 0xd5, 0xaa, 0x0d, 0x1f, 0xe8, 0x8d, 0xa0, 0xb1, 0xf8, 0xe1, 0xd3, - 0x64, 0x04, 0x62, 0x9b, 0xfe, 0x40, 0x23, 0xa3, 0x7e, 0x81, 0x95, 0x5e, 0xeb, 0x91, 0x8d, 0x74, - 0x57, 0x78, 0x73, 0x8b, 0x87, 0x61, 0xf1, 0x4f, 0x0c, 0xfd, 0xdc, 0xfb, 0x7f, 0xfa, 0xc7, 0xf7, - 0x87, 0xf2, 0xf4, 0x74, 0x51, 0x72, 0x5c, 0x55, 0x0a, 0xfb, 0x6a, 0x71, 0x9c, 0x7e, 0xaa, 0x91, - 0x29, 0xb5, 0x26, 0x46, 0x6f, 0xa6, 0x59, 0x2b, 0xbe, 0x1c, 0x9c, 0xbb, 0xd5, 0x17, 0x2f, 0x02, - 0x7e, 0x09, 0x00, 0x3f, 0x4f, 0x6f, 0x24, 0x00, 0x56, 0xab, 0x74, 0xc5, 0x47, 0xf8, 0xf5, 0x63, - 0xbf, 0xf8, 0x08, 0x0e, 0xa3, 0x7d, 0xfa, 0xb1, 0x46, 0x66, 0x55, 0xb9, 0xcb, 0x8e, 0x93, 0x4e, - 0x97, 0xf8, 0xa2, 0x70, 0x3a, 0x5d, 0x12, 0x0a, 0xbd, 0xfa, 0x65, 0xd0, 0xe5, 0x1c, 0x3d, 0x9b, - 0x42, 0x17, 0xfa, 0x37, 0x8d, 0x9c, 0xec, 0x40, 0x8e, 0x5f, 0x22, 0xe9, 0x72, 0x1f, 0x20, 0xa2, - 0x1f, 0x41, 0x73, 0x2b, 0x47, 0x11, 0x81, 0xea, 0xdc, 0x04, 0x75, 0xae, 0xd3, 0xc5, 0x14, 0xea, - 0x20, 0x2f, 0xee, 0xd0, 0x3e, 0xfd, 0x83, 0x46, 0x66, 0xa2, 0x05, 0x2d, 0x7a, 0x3b, 0xa5, 0x9b, - 0xc4, 0x16, 0xf0, 0x72, 0x2f, 0xf5, 0xc9, 0x8d, 0xba, 0xbc, 0x00, 0xba, 0x2c, 0xd2, 0x67, 0x13, - 0x74, 0x89, 0x96, 0xd9, 0x8a, 0x8f, 0x82, 0xfe, 0x3e, 0xfd, 0xb3, 0x46, 0x68, 0x77, 0x49, 0x93, - 0xa6, 0xc2, 0x93, 0x58, 0x48, 0xcd, 0xbd, 0xdc, 0x2f, 0x3b, 0xea, 0xb3, 0x0c, 0xfa, 0xdc, 0xa2, - 0x2f, 0x26, 0xea, 0xd3, 0xf9, 0xef, 0x38, 0x70, 0x2f, 0xa8, 0x8a, 0xfd, 0x46, 0x23, 0xc7, 0xa3, - 0x2b, 0xc8, 0xe0, 0xb9, 0x9d, 0xd2, 0x71, 0x8e, 0xb0, 0x4b, 0x89, 0xa5, 0x53, 0xfd, 0x2a, 0x68, - 0x75, 0x81, 0x9e, 0x4b, 0xb5, 0x4b, 0xf4, 0x23, 0x8d, 0x4c, 0x47, 0x4a, 0x94, 0xf4, 0x85, 0x94, - 0x5e, 0xd2, 0x55, 0xf2, 0xcc, 0xbd, 0xd8, 0x07, 0x27, 0xa2, 0x2e, 0x00, 0xea, 0x8b, 0xf4, 0x7c, - 0x02, 0xea, 0x0a, 0x13, 0x25, 0xc1, 0x79, 0xf0, 0x31, 0x81, 0x7e, 0xa0, 0x41, 0xbd, 0x33, 0xdd, - 0x95, 0x10, 0x29, 0xa0, 0xa6, 0xbb, 0x12, 0xa2, 0xd5, 0x55, 0x5d, 0x07, 0x78, 0xa7, 0x68, 0x2e, - 0x01, 0x9e, 0x84, 0xf2, 0x73, 0x2d, 0x2c, 0x1d, 0xd2, 0xa5, 0x94, 0x8b, 0x74, 0xd4, 0x38, 0x73, - 0xcf, 0x1f, 0x9a, 0x0f, 0x11, 0x16, 0x01, 0xe1, 0x33, 0xf4, 0x42, 0x92, 0x01, 0x91, 0x41, 0x7a, - 0x6f, 0x99, 0xed, 0xee, 0xd3, 0x9f, 0x6a, 0x64, 0x32, 0x90, 0x22, 0x9d, 0x76, 0x29, 0xa5, 0xdb, - 0xf5, 0x85, 0x38, 0xa6, 0xd2, 0xaa, 0x5f, 0x00, 0xc4, 0x4f, 0xd1, 0x7c, 0x0f, 0xc4, 0xf4, 0x13, - 0x8d, 0xcc, 0x75, 0x7e, 0x2a, 0xa4, 0xa9, 0x2e, 0x99, 0x84, 0xef, 0x96, 0xb9, 0xdb, 0xfd, 0x31, - 0xa7, 0x34, 0xb5, 0xd5, 0x89, 0xf5, 0x53, 0x8d, 0x4c, 0x2a, 0x5f, 0x03, 0xe9, 0xdd, 0x34, 0xcb, - 0xf7, 0xfa, 0xea, 0x98, 0x7b, 0xf5, 0x88, 0x52, 0x50, 0x9b, 0x4b, 0xa0, 0xcd, 0xd3, 0x54, 0x4f, - 0xca, 0x76, 0x14, 0xe0, 0xbf, 0xd2, 0x22, 0x85, 0x56, 0x9a, 0x36, 0xe0, 0xbb, 0x4b, 0xc3, 0xb9, - 0x9b, 0xfd, 0xb0, 0x22, 0xe4, 0x45, 0x80, 0x7c, 0x85, 0x5e, 0x4a, 0xda, 0x80, 0x90, 0xa7, 0xed, - 0xee, 0xbf, 0xd0, 0xc8, 0x8c, 0x22, 0x4b, 0x7a, 0xfc, 0x8b, 0x29, 0x3d, 0xb7, 0x5f, 0xf4, 0xf1, - 0xc5, 0xea, 0x9e, 0x06, 0x57, 0xd0, 0xd3, 0x5f, 0x6b, 0x64, 0x2e, 0x52, 0x13, 0x95, 0xb8, 0xd3, - 0xe6, 0x57, 0x71, 0x35, 0xe7, 0xdc, 0xed, 0xfe, 0x98, 0x11, 0xfb, 0x15, 0xc0, 0x7e, 0x9e, 0x3e, - 0x9d, 0xe4, 0x2c, 0x2a, 0x17, 0xfd, 0xa3, 0x46, 0xe6, 0xe3, 0xca, 0xc4, 0xf4, 0x2b, 0xa9, 0xb2, - 0xf2, 0xe4, 0xfa, 0x74, 0xee, 0x95, 0xfe, 0x05, 0xa0, 0x26, 0xcf, 0x83, 0x26, 0xd7, 0x68, 0x31, - 0x8d, 0x26, 0x98, 0x92, 0x95, 0xec, 0xf2, 0x3e, 0xfd, 0x4c, 0xeb, 0xaa, 0x9e, 0xd2, 0xb4, 0x89, - 0x55, 0x7c, 0xed, 0x37, 0x5d, 0x22, 0x93, 0x5c, 0xb7, 0xd6, 0x97, 0x40, 0x97, 0x67, 0x69, 0x21, - 0x41, 0x17, 0x27, 0xca, 0xd7, 0x8e, 0x89, 0xdf, 0x6a, 0x84, 0x76, 0xc8, 0x94, 0xfe, 0x95, 0x36, - 0x01, 0x39, 0x8a, 0x36, 0xc9, 0xd5, 0xe9, 0x9e, 0xa9, 0x40, 0x87, 0x36, 0xf4, 0x47, 0x1a, 0x19, - 0x86, 0x54, 0x26, 0xed, 0xc5, 0xae, 0x26, 0x5b, 0xcf, 0x1d, 0x8a, 0x27, 0xe5, 0x1b, 0xc5, 0xc2, - 0xf4, 0x17, 0x8c, 0xfc, 0x91, 0x3c, 0x33, 0xc3, 0xaa, 0x74, 0xfa, 0x33, 0xb3, 0xab, 0x92, 0xdd, - 0x1f, 0xd8, 0x1b, 0x00, 0xb6, 0x48, 0xaf, 0x1e, 0x08, 0xb6, 0xeb, 0x51, 0xf8, 0x43, 0x8d, 0x8c, - 0x05, 0xf9, 0xec, 0x62, 0xda, 0xd3, 0xee, 0xb0, 0x86, 0xed, 0xa8, 0x4c, 0xeb, 0x67, 0x01, 0xeb, - 0x69, 0xfa, 0xe4, 0x01, 0x58, 0xfd, 0x93, 0xdc, 0x47, 0x86, 0x11, 0x9e, 0xfe, 0x24, 0xef, 0x2a, - 0x2a, 0xa7, 0x3f, 0xc9, 0xbb, 0xab, 0xc1, 0xbd, 0x4f, 0xf2, 0x90, 0x87, 0xfe, 0x52, 0x23, 0x33, - 0xd1, 0xea, 0x6b, 0x3a, 0xd4, 0xb1, 0xf5, 0xdc, 0x74, 0xa8, 0xe3, 0x8b, 0xbd, 0x3d, 0x1f, 0x08, - 0x4e, 0x14, 0xe5, 0x4f, 0x34, 0x42, 0xc2, 0xff, 0xca, 0xa7, 0x37, 0xd2, 0xac, 0xdc, 0xf5, 0xff, - 0xfd, 0xb9, 0xa5, 0xc3, 0xb2, 0x21, 0xd8, 0x67, 0x00, 0xec, 0x59, 0xfa, 0x54, 0x02, 0x58, 0xd1, - 0x66, 0x59, 0x79, 0xfd, 0xb3, 0x2f, 0x16, 0xb4, 0xcf, 0xbf, 0x58, 0xd0, 0xfe, 0xfe, 0xc5, 0x82, - 0xf6, 0xc1, 0x97, 0x0b, 0xc7, 0x3e, 0xff, 0x72, 0xe1, 0xd8, 0x5f, 0xbe, 0x5c, 0x38, 0xf6, 0xe0, - 0x5a, 0xc5, 0x16, 0xdb, 0x8d, 0xad, 0x82, 0xe5, 0x56, 0x55, 0x31, 0x01, 0x8e, 0xe2, 0x6e, 0x44, - 0xe2, 0x5e, 0x9d, 0xf1, 0xad, 0x51, 0x48, 0x7b, 0x9e, 0xfb, 0x77, 0x00, 0x00, 0x00, 0xff, 0xff, - 0xe5, 0x77, 0xa5, 0xc6, 0x5e, 0x32, 0x00, 0x00, + 0xc1, 0x09, 0x39, 0x65, 0x42, 0xc5, 0xe4, 0xa5, 0xba, 0x67, 0x5b, 0x0c, 0xc7, 0x4e, 0x2b, 0x63, + 0xc0, 0x53, 0xda, 0x32, 0xf9, 0x56, 0x49, 0xb8, 0x25, 0xcb, 0x6a, 0x0b, 0xd0, 0x95, 0x49, 0x8e, + 0xc9, 0x45, 0x69, 0xd3, 0x71, 0xad, 0x87, 0xa5, 0x2d, 0x66, 0x57, 0xb6, 0x04, 0xce, 0x59, 0x50, + 0xe6, 0x00, 0xbc, 0x0e, 0x19, 0x2a, 0x4a, 0xb7, 0x21, 0xe4, 0x4a, 0xc2, 0x33, 0xad, 0x87, 0xcc, + 0xc3, 0x09, 0x4f, 0x2a, 0x13, 0xea, 0xa6, 0x67, 0x56, 0x03, 0xfd, 0xe6, 0x95, 0x01, 0xc1, 0xdb, + 0xd4, 0x8a, 0x5b, 0x71, 0xa1, 0x59, 0x94, 0x2d, 0xa4, 0x9e, 0xa8, 0xb8, 0x6e, 0xc5, 0x61, 0x45, + 0xb3, 0x6e, 0x17, 0xcd, 0x5a, 0xcd, 0x15, 0x60, 0x47, 0xe4, 0xd1, 0xb3, 0xe4, 0xf8, 0x57, 0xa5, + 0xa9, 0x37, 0x38, 0x7f, 0xc3, 0xe6, 0xc2, 0xf5, 0x76, 0x0d, 0xf6, 0x5e, 0x83, 0x71, 0xa1, 0x7f, + 0x87, 0x3c, 0xd9, 0x35, 0xc2, 0xeb, 0x6e, 0x8d, 0x33, 0x7a, 0x9b, 0x8c, 0x0b, 0xce, 0x4b, 0x8e, + 0xcd, 0x45, 0x56, 0x3b, 0x95, 0x39, 0x3f, 0xb9, 0xa8, 0x17, 0xf6, 0xdd, 0xdb, 0xc2, 0xc6, 0xfa, + 0xfa, 0xf2, 0xf0, 0xe7, 0xcd, 0xfc, 0x11, 0x63, 0x4c, 0x70, 0xbe, 0x6a, 0x73, 0xa1, 0xcf, 0x13, + 0x0a, 0xf2, 0xd7, 0x40, 0xb1, 0x60, 0xd5, 0xfb, 0xe4, 0x58, 0x84, 0xda, 0x5e, 0x71, 0xd4, 0x37, + 0x40, 0x56, 0x3b, 0xa5, 0x9d, 0x9f, 0x5c, 0x3c, 0xd3, 0x63, 0x3d, 0x9f, 0x1d, 0x97, 0x44, 0x56, + 0xfd, 0x2d, 0xf2, 0x34, 0xc8, 0x5e, 0x61, 0xe2, 0x9d, 0x86, 0xd8, 0xd8, 0xd9, 0xf0, 0x8d, 0x8d, + 0x4b, 0xd3, 0x2c, 0x19, 0x03, 0xe6, 0x7b, 0x77, 0x60, 0x91, 0x8c, 0x11, 0x74, 0xe9, 0x3c, 0x19, + 0x81, 0xfd, 0xcb, 0x0e, 0x9d, 0xd2, 0xce, 0x0f, 0x1b, 0x7e, 0x47, 0x6f, 0x90, 0x13, 0xf1, 0xe2, + 0x10, 0xf3, 0xbb, 0x64, 0xca, 0x55, 0xe8, 0x88, 0xfc, 0x62, 0x0f, 0xe4, 0xaa, 0x28, 0xc4, 0x1f, + 0x11, 0xa3, 0x33, 0xd4, 0x62, 0xc9, 0x71, 0xe2, 0xb4, 0xb8, 0x4b, 0x48, 0x18, 0x2d, 0xb8, 0xe6, + 0xd9, 0x82, 0x1f, 0x5a, 0x05, 0x19, 0x5a, 0x05, 0x3f, 0x24, 0x31, 0xb4, 0x0a, 0x6b, 0x66, 0x85, + 0x21, 0xaf, 0xa1, 0x70, 0xea, 0x9f, 0x6a, 0xa8, 0x5e, 0xd7, 0x3a, 0x89, 0xea, 0x65, 0x06, 0xa0, + 0x1e, 0x5d, 0x89, 0xe0, 0x1f, 0x02, 0xfc, 0xe7, 0x7a, 0xe2, 0xf7, 0x31, 0x45, 0x14, 0xf8, 0x40, + 0x23, 0x7a, 0x9c, 0x02, 0xcb, 0xbb, 0xb7, 0x25, 0x92, 0xc0, 0x5e, 0xf3, 0x64, 0x04, 0x90, 0xe1, + 0x9e, 0xfb, 0x9d, 0x0e, 0x2b, 0x0e, 0xf5, 0x6d, 0xc5, 0xdf, 0x6b, 0xe4, 0xf4, 0xbe, 0x20, 0xfe, + 0x4f, 0x8c, 0x79, 0x93, 0x9c, 0x0c, 0x7c, 0xfd, 0x5e, 0x6d, 0x63, 0xe7, 0x0d, 0x93, 0x6f, 0x6d, + 0xb8, 0xb7, 0x2d, 0xb1, 0x13, 0x98, 0x31, 0x47, 0xc6, 0x6d, 0x1c, 0x00, 0x4b, 0x4e, 0x18, 0xed, + 0xbe, 0xbe, 0x47, 0x16, 0x92, 0x98, 0x51, 0xfd, 0x6f, 0x91, 0x19, 0x3b, 0x32, 0x82, 0x8e, 0x7b, + 0xb9, 0x87, 0x01, 0xa2, 0xe2, 0xd0, 0x04, 0x1d, 0xa2, 0xf4, 0x5b, 0xb8, 0x7c, 0x74, 0xf2, 0x1d, + 0x53, 0x98, 0x69, 0xc0, 0xbf, 0x4f, 0xf2, 0x89, 0xdc, 0x88, 0xfe, 0xeb, 0x64, 0xfa, 0xb6, 0xc4, + 0x04, 0x5b, 0xba, 0xb1, 0xc3, 0x53, 0xee, 0x9e, 0xca, 0x83, 0xd0, 0xa3, 0x72, 0xf4, 0x0a, 0x5a, + 0x7d, 0xc9, 0x71, 0xe2, 0xad, 0x3e, 0xa8, 0x60, 0xff, 0x4c, 0x43, 0x1b, 0xc5, 0xac, 0xb4, 0xcf, + 0x16, 0x65, 0x06, 0xb4, 0x45, 0x83, 0xf4, 0xd3, 0xa7, 0x02, 0x57, 0xdb, 0xe0, 0x7c, 0xa9, 0x5c, + 0xf6, 0x18, 0x0f, 0xee, 0x16, 0xba, 0x40, 0x26, 0xe5, 0xb5, 0x55, 0x6f, 0x6c, 0x96, 0x1e, 0xb2, + 0x5d, 0xdc, 0xe9, 0x09, 0xc1, 0xf9, 0x5a, 0x63, 0xf3, 0x4d, 0xb6, 0xab, 0xbf, 0x46, 0x72, 0x71, + 0xcc, 0x68, 0x80, 0x39, 0x92, 0x61, 0x22, 0xf0, 0x0f, 0xd9, 0x94, 0x94, 0x4d, 0x61, 0x01, 0xdc, + 0x09, 0x43, 0x36, 0xdb, 0x77, 0x9a, 0x94, 0xb0, 0xbe, 0x1e, 0xdc, 0x69, 0x6f, 0xe2, 0x9d, 0x16, + 0x50, 0x51, 0xe0, 0x55, 0x92, 0xd9, 0x58, 0x5f, 0xc7, 0x5d, 0x4b, 0x71, 0x81, 0x1a, 0x72, 0xba, + 0x5e, 0xc4, 0x6b, 0x79, 0x85, 0x89, 0x15, 0x93, 0xaf, 0xc9, 0xbc, 0x45, 0x39, 0xca, 0xec, 0x5a, + 0x99, 0xed, 0x20, 0x46, 0xbf, 0xa3, 0x97, 0x48, 0xb6, 0x9b, 0x21, 0xbc, 0xc8, 0x03, 0x1a, 0xe2, + 0x38, 0xd7, 0x03, 0x47, 0x5b, 0x44, 0x9b, 0x51, 0x37, 0x11, 0xd1, 0x92, 0xe3, 0x74, 0x22, 0x1a, + 0x94, 0x7f, 0xfe, 0x4c, 0x43, 0x25, 0x22, 0x6b, 0xc4, 0x2a, 0x91, 0xe9, 0x4b, 0x89, 0xc1, 0x79, + 0xe0, 0x62, 0xe8, 0x44, 0x10, 0xc7, 0x6f, 0x43, 0x5e, 0xba, 0xff, 0x16, 0x3d, 0x0c, 0x13, 0x93, + 0x08, 0x0f, 0x2a, 0xb8, 0x4a, 0x26, 0x15, 0x32, 0x9a, 0xf1, 0x42, 0xaf, 0xd3, 0x45, 0x11, 0xa4, + 0xb2, 0xeb, 0x65, 0x04, 0xb8, 0xe4, 0x38, 0x31, 0x00, 0x07, 0xb5, 0x63, 0x1f, 0x6b, 0x61, 0x9a, + 0x92, 0x4a, 0xa7, 0xcc, 0x21, 0x74, 0x1a, 0xdc, 0xee, 0x2d, 0x84, 0x49, 0xcf, 0x1a, 0xab, 0x95, + 0xed, 0x5a, 0x25, 0x62, 0x1e, 0x5d, 0x84, 0x27, 0x72, 0xc7, 0x38, 0xea, 0xb5, 0x4e, 0x66, 0xea, + 0xfe, 0x00, 0xbe, 0x48, 0x50, 0xb5, 0x4b, 0xbd, 0x12, 0xd6, 0x88, 0xb4, 0xe9, 0xba, 0xda, 0xd5, + 0x5f, 0x21, 0xa7, 0xfc, 0xa4, 0x58, 0xa5, 0x76, 0xe4, 0x31, 0x4f, 0x91, 0x71, 0xff, 0x8d, 0x63, + 0x97, 0xa3, 0xe9, 0x6b, 0x59, 0xff, 0x2e, 0x79, 0x66, 0x1f, 0x76, 0x04, 0xfe, 0xcd, 0x18, 0xe0, + 0xda, 0x41, 0x81, 0x07, 0xd7, 0x58, 0x14, 0xfe, 0xf5, 0xf0, 0xfe, 0x5f, 0x35, 0xb9, 0x58, 0x96, + 0x2f, 0xa5, 0x37, 0xe0, 0xa1, 0xb4, 0x7f, 0x58, 0x3c, 0xc2, 0xab, 0x37, 0x8e, 0x0f, 0x51, 0x7f, + 0x83, 0xcc, 0x76, 0x0c, 0x21, 0xec, 0x42, 0x0f, 0xd8, 0x9d, 0x02, 0x3b, 0xc5, 0xe8, 0x5b, 0xe1, + 0x8d, 0x98, 0x00, 0x7a, 0x50, 0xa1, 0xf2, 0x3b, 0x0d, 0xf5, 0x8c, 0x5b, 0x6a, 0x3f, 0x3d, 0x33, + 0x03, 0xd0, 0x73, 0x70, 0xa1, 0x73, 0x31, 0xbc, 0xe5, 0xd4, 0x14, 0x25, 0x7e, 0x6b, 0x57, 0x95, + 0x53, 0x52, 0xa6, 0x05, 0xbb, 0xe0, 0x2a, 0xfd, 0xbe, 0xc4, 0x2a, 0x64, 0x3e, 0xba, 0x34, 0x5a, + 0xed, 0x1d, 0x32, 0xa5, 0x26, 0x54, 0x29, 0x5f, 0x60, 0x2a, 0x8b, 0x11, 0x11, 0xa0, 0x7f, 0x1b, + 0x75, 0x94, 0x87, 0xda, 0x7f, 0x20, 0x0d, 0xfb, 0x48, 0x43, 0x45, 0xda, 0xf2, 0x13, 0x15, 0xc9, + 0x1c, 0x4a, 0x91, 0xc1, 0xed, 0xfa, 0xf7, 0x94, 0xdb, 0xc4, 0x12, 0x3b, 0x78, 0x1a, 0xf4, 0x3e, + 0x94, 0x06, 0xf6, 0xc2, 0xfa, 0x44, 0xbd, 0x68, 0x54, 0x04, 0xff, 0xf3, 0xa6, 0x3b, 0x81, 0xa6, + 0x93, 0x11, 0x79, 0x9f, 0x09, 0x33, 0x72, 0xba, 0xe8, 0xd7, 0x50, 0xad, 0xce, 0x51, 0x54, 0xeb, + 0x38, 0x19, 0x55, 0xce, 0xbb, 0x8c, 0x81, 0x3d, 0x7d, 0x03, 0x2f, 0xb0, 0xdb, 0x6e, 0x6d, 0x9b, + 0x79, 0x32, 0xe3, 0xdb, 0x70, 0x25, 0x7b, 0x57, 0x68, 0x75, 0x6d, 0x48, 0x8e, 0x8c, 0x57, 0x4c, + 0xbe, 0x6a, 0x57, 0x6d, 0x81, 0x29, 0x6d, 0xbb, 0xaf, 0xff, 0x58, 0xc3, 0x7b, 0xaf, 0x5b, 0x2c, + 0xe2, 0xb9, 0x44, 0x8e, 0xba, 0x0d, 0xb1, 0xe9, 0x36, 0x6a, 0xe5, 0x15, 0x93, 0xdf, 0xab, 0xc9, + 0x41, 0x0c, 0xf9, 0xee, 0x01, 0x39, 0x1b, 0x3e, 0x3f, 0x59, 0xae, 0x73, 0x97, 0x31, 0x9c, 0xed, + 0x2f, 0xda, 0x3d, 0x40, 0xcf, 0x93, 0x59, 0xf9, 0xab, 0x1e, 0x7e, 0x19, 0x08, 0xff, 0x4e, 0xb2, + 0x7e, 0x8e, 0x9c, 0x01, 0x98, 0x6f, 0x31, 0xce, 0xcd, 0x0a, 0x5b, 0x33, 0x39, 0xb7, 0x6b, 0x95, + 0xb5, 0x50, 0x62, 0x60, 0xdd, 0xbb, 0xe4, 0x6c, 0xaf, 0x89, 0xa8, 0xd8, 0x09, 0x32, 0xf1, 0xa0, + 0x0d, 0x11, 0x9f, 0x0c, 0x6d, 0x82, 0x7e, 0x13, 0x17, 0xbc, 0xff, 0xfa, 0xd7, 0xde, 0x92, 0xe9, + 0xbd, 0x67, 0xd6, 0xb8, 0x69, 0xc9, 0xed, 0x35, 0x98, 0xc5, 0xec, 0x7a, 0xfb, 0xb2, 0xa0, 0x64, + 0x78, 0x2b, 0x7c, 0x5e, 0x42, 0x5b, 0xff, 0xd7, 0x30, 0xa2, 0xd8, 0x87, 0xbb, 0x6d, 0x5e, 0x82, + 0x1f, 0x18, 0xdb, 0x42, 0x96, 0xa7, 0x5b, 0xcd, 0xfc, 0x04, 0x50, 0xe5, 0x4b, 0xca, 0x08, 0x9b, + 0x74, 0x91, 0x4c, 0xf9, 0xb3, 0x6b, 0x8d, 0xea, 0x26, 0xf3, 0x7c, 0xcb, 0x2e, 0xcf, 0xb6, 0x9a, + 0xf9, 0x49, 0xa0, 0xbf, 0x0d, 0x64, 0x43, 0xed, 0xd0, 0x57, 0xc9, 0x9c, 0xe5, 0xd6, 0x84, 0x67, + 0x5a, 0xa2, 0x64, 0xfa, 0x4f, 0x1f, 0xb0, 0xf2, 0xc4, 0xf2, 0xb1, 0x56, 0x33, 0x3f, 0x1b, 0x8c, + 0x05, 0xaf, 0xa2, 0x4e, 0x02, 0x7d, 0x9d, 0x1c, 0xb3, 0x1a, 0xd5, 0x86, 0x63, 0x0a, 0x7b, 0x9b, + 0x95, 0x2a, 0x26, 0x2f, 0x35, 0x38, 0x2b, 0x67, 0x87, 0x41, 0xc4, 0x13, 0xad, 0x66, 0xfe, 0x68, + 0x38, 0xbc, 0x62, 0xf2, 0x77, 0x39, 0x2b, 0x1b, 0xdd, 0x24, 0x7a, 0x82, 0x0c, 0x3f, 0xf0, 0xdc, + 0x6a, 0x76, 0x04, 0xf8, 0xc6, 0x5b, 0xcd, 0x3c, 0xf4, 0x0d, 0xf8, 0x4b, 0xcf, 0x82, 0x8f, 0xfa, + 0x92, 0x47, 0x61, 0xc6, 0x64, 0xab, 0x99, 0x1f, 0xab, 0xa0, 0xbc, 0xa0, 0x21, 0xcd, 0xe5, 0xb8, + 0x15, 0x5e, 0xda, 0x74, 0x5c, 0xb7, 0x9a, 0x1d, 0x0b, 0xcd, 0x25, 0xa9, 0xcb, 0x92, 0x68, 0x84, + 0x4d, 0xaa, 0x93, 0x51, 0x2e, 0x4c, 0xd1, 0xe0, 0xd9, 0x71, 0x98, 0x49, 0x5a, 0xcd, 0x3c, 0x52, + 0x0c, 0xfc, 0xa5, 0xc7, 0xc9, 0x90, 0x70, 0xb3, 0x13, 0x30, 0x3e, 0xda, 0x6a, 0xe6, 0x87, 0x84, + 0x6b, 0x0c, 0x09, 0x57, 0x9a, 0x4d, 0x84, 0xdb, 0xe6, 0x6f, 0x0f, 0x09, 0xcd, 0xa6, 0x8c, 0xc1, + 0x26, 0x75, 0x12, 0xe8, 0x12, 0x39, 0xaa, 0xf2, 0xfb, 0x57, 0xe5, 0x24, 0x08, 0x98, 0x6f, 0x35, + 0xf3, 0xaa, 0xf0, 0x7b, 0x72, 0xcc, 0xe8, 0xa2, 0xd0, 0xeb, 0x64, 0x58, 0xea, 0x92, 0x9d, 0x4a, + 0xf5, 0x25, 0x76, 0xd5, 0xad, 0x18, 0x30, 0x5f, 0xff, 0x20, 0x43, 0x32, 0xab, 0x6e, 0x45, 0x1e, + 0x09, 0xc1, 0x86, 0xfb, 0xde, 0x19, 0x74, 0xe5, 0x21, 0x23, 0xdc, 0xba, 0x6d, 0xf1, 0xec, 0xd0, + 0xa9, 0xcc, 0xf9, 0x09, 0x03, 0x7b, 0xd2, 0x99, 0xcb, 0xa6, 0x30, 0x7d, 0xff, 0x30, 0xa0, 0xdd, + 0xe5, 0x73, 0x72, 0xe3, 0x87, 0x7b, 0xfb, 0x5c, 0x97, 0xf1, 0x46, 0x0e, 0x6b, 0xbc, 0x51, 0x58, + 0x38, 0xad, 0xf1, 0xa2, 0x81, 0x35, 0xd6, 0x23, 0xb0, 0x9e, 0x23, 0xd2, 0x6d, 0x70, 0xa1, 0x71, + 0x58, 0x68, 0xaa, 0xd5, 0xcc, 0x8f, 0x3b, 0x6e, 0xc5, 0x5f, 0xa0, 0xdd, 0xa2, 0x67, 0xc8, 0x98, + 0xc7, 0xaa, 0xee, 0x36, 0x2b, 0x83, 0xd7, 0x8c, 0xfb, 0x9e, 0x8a, 0x24, 0x23, 0x68, 0xe8, 0x57, + 0x31, 0xcd, 0x8c, 0x3b, 0x02, 0x92, 0x4f, 0x8e, 0x7f, 0x0e, 0x63, 0xca, 0x18, 0xc7, 0xf6, 0x5f, + 0x3b, 0x32, 0x82, 0x58, 0xcd, 0xc4, 0xc6, 0xea, 0x53, 0x24, 0x53, 0x31, 0x39, 0x1e, 0x00, 0x63, + 0xad, 0x66, 0x5e, 0x76, 0x0d, 0xf9, 0x47, 0x9a, 0xb1, 0x5d, 0x74, 0xc1, 0x0d, 0x07, 0x33, 0x56, + 0xda, 0xef, 0xf2, 0xa0, 0x25, 0xd7, 0x00, 0xfc, 0xa3, 0xe1, 0x1a, 0xb2, 0xef, 0xdb, 0x81, 0xe6, + 0x65, 0x72, 0x59, 0x6f, 0x08, 0xdc, 0xb8, 0x89, 0x56, 0x33, 0xef, 0x13, 0x0c, 0xff, 0x47, 0x4e, + 0xf0, 0xf3, 0xc5, 0xf1, 0x70, 0x02, 0x10, 0x30, 0x75, 0x4c, 0x8c, 0xeb, 0x58, 0xd7, 0x22, 0x07, + 0x8a, 0xcb, 0x3c, 0x19, 0xd9, 0x36, 0x9d, 0x06, 0xc3, 0x70, 0x86, 0xb5, 0x81, 0x60, 0xf8, 0x3f, + 0x52, 0x37, 0xb1, 0x5b, 0x67, 0xd9, 0xa9, 0x50, 0x37, 0xd9, 0x37, 0xe0, 0x2f, 0x2d, 0x92, 0x49, + 0xd3, 0xb2, 0x58, 0x50, 0x67, 0x99, 0x96, 0x11, 0xb8, 0x3c, 0xd3, 0x6a, 0xe6, 0x89, 0x4f, 0x5e, + 0xb5, 0x65, 0x26, 0x14, 0xb6, 0xe5, 0xe1, 0xd8, 0x4e, 0xb6, 0x66, 0xc2, 0xc3, 0x11, 0xef, 0xf7, + 0xf0, 0xa2, 0x3f, 0x46, 0xb4, 0xed, 0xec, 0x2c, 0x4c, 0x18, 0x69, 0x35, 0xf3, 0xda, 0xb6, 0xa1, + 0x6d, 0x4b, 0xa2, 0x97, 0x9d, 0x0b, 0x89, 0x9e, 0xa1, 0x79, 0x92, 0xc8, 0xb3, 0x47, 0x43, 0x22, + 0x37, 0x34, 0xae, 0xdf, 0xc0, 0xc7, 0x28, 0xba, 0x1e, 0x5c, 0xbf, 0xcb, 0xbb, 0xe8, 0x1f, 0xe8, + 0xb3, 0xc7, 0xc9, 0xe8, 0x56, 0x98, 0x9d, 0x0c, 0x1b, 0xd8, 0xd3, 0xff, 0x3a, 0x86, 0x4f, 0xd1, + 0x78, 0x66, 0xf4, 0x5c, 0x9d, 0x8c, 0xa2, 0x17, 0x6a, 0xe1, 0x79, 0xec, 0x53, 0x0c, 0xfc, 0x6d, + 0xfb, 0xc5, 0x50, 0xac, 0x5f, 0x14, 0xc9, 0x64, 0xdd, 0xf4, 0x58, 0x4d, 0xf8, 0xce, 0xef, 0x3b, + 0x28, 0xd8, 0xce, 0x27, 0x83, 0xf7, 0x2b, 0xed, 0xd0, 0x4f, 0x86, 0x13, 0xfc, 0xa4, 0x48, 0x26, + 0xf9, 0x96, 0xf9, 0x42, 0xa9, 0x51, 0xb3, 0x1c, 0xc6, 0xd1, 0x69, 0x41, 0xa2, 0x24, 0xbf, 0x0b, + 0x54, 0x43, 0x69, 0x77, 0x5c, 0x41, 0xa3, 0x3d, 0xae, 0xa0, 0xa8, 0xbb, 0xf1, 0x92, 0xe7, 0xba, + 0x81, 0x53, 0x77, 0xba, 0x1b, 0x37, 0x5c, 0x57, 0x18, 0x5d, 0x14, 0xb9, 0xa0, 0xbc, 0xab, 0x98, + 0xcf, 0x3b, 0x1e, 0x2e, 0x08, 0x54, 0x60, 0x0a, 0x9b, 0xf4, 0x1a, 0x99, 0xf6, 0xfc, 0x1c, 0x03, + 0x17, 0xf3, 0x43, 0x60, 0xae, 0xd5, 0xcc, 0x4f, 0x05, 0x03, 0xc0, 0x13, 0xe9, 0x49, 0x3b, 0x55, + 0xed, 0x1a, 0xf3, 0x30, 0x14, 0xc0, 0x4e, 0x40, 0x30, 0xfc, 0x1f, 0x5a, 0x20, 0xa4, 0x6c, 0x3f, + 0x78, 0x60, 0x5b, 0x0d, 0x47, 0xec, 0xa2, 0xe7, 0x83, 0x99, 0x42, 0xaa, 0xa1, 0xb4, 0xe1, 0x0a, + 0x70, 0x85, 0xe9, 0x94, 0x14, 0xae, 0x29, 0xe5, 0x0a, 0x90, 0x63, 0x77, 0x42, 0xd6, 0x4e, 0x82, + 0xd4, 0x9a, 0xed, 0x08, 0xcf, 0x2c, 0xc1, 0x85, 0x34, 0x1d, 0x6a, 0x0d, 0x54, 0xf8, 0x4c, 0x1f, + 0x36, 0xa5, 0xd7, 0x70, 0xfb, 0x7d, 0x86, 0xe1, 0x01, 0x5e, 0x23, 0xfb, 0x06, 0xfc, 0x0d, 0x8e, + 0x25, 0x07, 0x52, 0xe0, 0xd9, 0xc8, 0xb1, 0x04, 0x69, 0x70, 0x98, 0x10, 0x47, 0x12, 0x91, 0xb9, + 0x7d, 0x12, 0x91, 0x8b, 0x64, 0x42, 0xd8, 0x55, 0xc6, 0x85, 0x59, 0xad, 0x63, 0x24, 0x01, 0xba, + 0x36, 0xd1, 0x08, 0x9b, 0xf4, 0x2a, 0x99, 0x52, 0x77, 0x35, 0x4b, 0x21, 0xe4, 0x61, 0x4b, 0x22, + 0xbb, 0x1d, 0xe9, 0xc9, 0x68, 0x41, 0xa7, 0x3c, 0x06, 0xf3, 0x21, 0x5a, 0x7c, 0x8a, 0x81, 0xbf, + 0xf4, 0x06, 0x99, 0x93, 0x2f, 0x93, 0xd2, 0x03, 0xc6, 0x4a, 0x75, 0xe6, 0xc9, 0xf4, 0x2c, 0x3b, + 0x0f, 0x68, 0x8e, 0xb6, 0x9a, 0xf9, 0x69, 0x39, 0x76, 0x97, 0xb1, 0x35, 0xe6, 0xad, 0x98, 0xdc, + 0x88, 0x76, 0xa5, 0xaa, 0x55, 0xdb, 0xaf, 0x81, 0x67, 0x9f, 0x08, 0x55, 0xad, 0xda, 0xf0, 0x01, + 0xdf, 0x08, 0x1a, 0x8b, 0x1f, 0x3d, 0x4b, 0x46, 0x20, 0xb6, 0xe9, 0x0f, 0x34, 0x32, 0xea, 0x17, + 0x60, 0xe9, 0x95, 0x1e, 0xd9, 0x48, 0x77, 0x05, 0x38, 0xb7, 0x78, 0x10, 0x16, 0xff, 0xc4, 0xd0, + 0xcf, 0x7c, 0xf0, 0xa7, 0x7f, 0x7c, 0x7f, 0x28, 0x4f, 0x4f, 0x16, 0x25, 0xc7, 0x65, 0xa5, 0xf0, + 0xaf, 0x16, 0xcf, 0xe9, 0x67, 0x1a, 0x99, 0x52, 0x6b, 0x66, 0xf4, 0x46, 0x9a, 0xb5, 0xe2, 0xcb, + 0xc5, 0xb9, 0x9b, 0x7d, 0xf1, 0x22, 0xe0, 0x57, 0x00, 0xf0, 0x8b, 0xf4, 0x5a, 0x02, 0x60, 0xb5, + 0x8a, 0x57, 0x7c, 0x84, 0x5f, 0x3f, 0xf6, 0x8a, 0x8f, 0xe0, 0x30, 0xda, 0xa3, 0x9f, 0x68, 0x64, + 0x56, 0x95, 0xbb, 0xe4, 0x38, 0xe9, 0x74, 0x89, 0x2f, 0x1a, 0xa7, 0xd3, 0x25, 0xa1, 0x10, 0xac, + 0x5f, 0x04, 0x5d, 0xce, 0xd0, 0xd3, 0x29, 0x74, 0xa1, 0x7f, 0xd3, 0xc8, 0xf1, 0x0e, 0xe4, 0xf8, + 0x25, 0x92, 0x2e, 0xf5, 0x01, 0x22, 0xfa, 0x11, 0x34, 0xb7, 0x7c, 0x18, 0x11, 0xa8, 0xce, 0x0d, + 0x50, 0xe7, 0x2a, 0x5d, 0x4c, 0xa1, 0x0e, 0xf2, 0xe2, 0x0e, 0xed, 0xd1, 0x3f, 0x68, 0x64, 0x26, + 0x5a, 0xf0, 0xa2, 0xb7, 0x52, 0xba, 0x49, 0x6c, 0x81, 0x2f, 0xf7, 0x4a, 0x9f, 0xdc, 0xa8, 0xcb, + 0x4b, 0xa0, 0xcb, 0x22, 0x7d, 0x3e, 0x41, 0x97, 0x68, 0x19, 0xae, 0xf8, 0x28, 0xe8, 0xef, 0xd1, + 0x3f, 0x6b, 0x84, 0x76, 0x97, 0x3c, 0x69, 0x2a, 0x3c, 0x89, 0x85, 0xd6, 0xdc, 0xab, 0xfd, 0xb2, + 0xa3, 0x3e, 0x4b, 0xa0, 0xcf, 0x4d, 0xfa, 0x72, 0xa2, 0x3e, 0x9d, 0xff, 0xae, 0x03, 0xf7, 0x82, + 0xaa, 0xd8, 0x6f, 0x34, 0x72, 0x34, 0xba, 0x82, 0x0c, 0x9e, 0x5b, 0x29, 0x1d, 0xe7, 0x10, 0xbb, + 0x94, 0x58, 0x5a, 0xd5, 0x2f, 0x83, 0x56, 0xe7, 0xe8, 0x99, 0x54, 0xbb, 0x44, 0x3f, 0xd6, 0xc8, + 0x74, 0xa4, 0x44, 0x49, 0x5f, 0x4a, 0xe9, 0x25, 0x5d, 0x25, 0xd1, 0xdc, 0xcb, 0x7d, 0x70, 0x22, + 0xea, 0x02, 0xa0, 0x3e, 0x4f, 0xcf, 0x26, 0xa0, 0xae, 0x30, 0x51, 0x12, 0x9c, 0x07, 0x1f, 0x13, + 0xe8, 0x87, 0x1a, 0xd4, 0x3b, 0xd3, 0x5d, 0x09, 0x91, 0x02, 0x6a, 0xba, 0x2b, 0x21, 0x5a, 0x5d, + 0xd5, 0x75, 0x80, 0x77, 0x82, 0xe6, 0x12, 0xe0, 0x49, 0x28, 0x3f, 0xd7, 0xc2, 0xd2, 0x21, 0xbd, + 0x9e, 0x72, 0x91, 0x8e, 0x1a, 0x67, 0xee, 0xc5, 0x03, 0xf3, 0x21, 0xc2, 0x22, 0x20, 0x7c, 0x8e, + 0x9e, 0x4b, 0x32, 0x20, 0x32, 0x48, 0xef, 0x2d, 0xb3, 0x9d, 0x3d, 0xfa, 0x53, 0x8d, 0x4c, 0x06, + 0x52, 0xa4, 0xd3, 0x5e, 0x4f, 0xe9, 0x76, 0x7d, 0x21, 0x8e, 0xa9, 0xb4, 0xea, 0xe7, 0x00, 0xf1, + 0x33, 0x34, 0xdf, 0x03, 0x31, 0xfd, 0x54, 0x23, 0x73, 0x9d, 0x9f, 0x0a, 0x69, 0xaa, 0x4b, 0x26, + 0xe1, 0xbb, 0x65, 0xee, 0x56, 0x7f, 0xcc, 0x29, 0x4d, 0x6d, 0x75, 0x62, 0xfd, 0x4c, 0x23, 0x93, + 0xca, 0xd7, 0x40, 0x7a, 0x27, 0xcd, 0xf2, 0xbd, 0xbe, 0x3a, 0xe6, 0x5e, 0x3f, 0xa4, 0x14, 0xd4, + 0xe6, 0x02, 0x68, 0xf3, 0x2c, 0xd5, 0x93, 0xb2, 0x1d, 0x05, 0xf8, 0xaf, 0xb4, 0x48, 0xa1, 0x95, + 0xa6, 0x0d, 0xf8, 0xee, 0xd2, 0x70, 0xee, 0x46, 0x3f, 0xac, 0x08, 0x79, 0x11, 0x20, 0x5f, 0xa2, + 0x17, 0x92, 0x36, 0x20, 0xe4, 0x69, 0xbb, 0xfb, 0x2f, 0x34, 0x32, 0xa3, 0xc8, 0x92, 0x1e, 0xff, + 0x72, 0x4a, 0xcf, 0xed, 0x17, 0x7d, 0x7c, 0xb1, 0xba, 0xa7, 0xc1, 0x15, 0xf4, 0xf4, 0xd7, 0x1a, + 0x99, 0x8b, 0xd4, 0x44, 0x25, 0xee, 0xb4, 0xf9, 0x55, 0x5c, 0xcd, 0x39, 0x77, 0xab, 0x3f, 0x66, + 0xc4, 0x7e, 0x09, 0xb0, 0x9f, 0xa5, 0xcf, 0x26, 0x39, 0x8b, 0xca, 0x45, 0xff, 0xa8, 0x91, 0xf9, + 0xb8, 0x32, 0x31, 0xfd, 0x4a, 0xaa, 0xac, 0x3c, 0xb9, 0x3e, 0x9d, 0x7b, 0xad, 0x7f, 0x01, 0xa8, + 0xc9, 0x8b, 0xa0, 0xc9, 0x15, 0x5a, 0x4c, 0xa3, 0x09, 0xa6, 0x64, 0x25, 0xbb, 0xbc, 0x47, 0x3f, + 0xd7, 0xba, 0xaa, 0xa7, 0x34, 0x6d, 0x62, 0x15, 0x5f, 0xfb, 0x4d, 0x97, 0xc8, 0x24, 0xd7, 0xad, + 0xf5, 0xeb, 0xa0, 0xcb, 0xf3, 0xb4, 0x90, 0xa0, 0x8b, 0x13, 0xe5, 0x6b, 0xc7, 0xc4, 0x6f, 0x35, + 0x42, 0x3b, 0x64, 0x4a, 0xff, 0x4a, 0x9b, 0x80, 0x1c, 0x46, 0x9b, 0xe4, 0xea, 0x74, 0xcf, 0x54, + 0xa0, 0x43, 0x1b, 0xfa, 0x23, 0x8d, 0x0c, 0x43, 0x2a, 0x93, 0xf6, 0x62, 0x57, 0x93, 0xad, 0x17, + 0x0e, 0xc4, 0x93, 0xf2, 0x8d, 0x62, 0x61, 0xfa, 0x0b, 0x46, 0xfe, 0x58, 0x9e, 0x99, 0x61, 0x55, + 0x3a, 0xfd, 0x99, 0xd9, 0x55, 0xc9, 0xee, 0x0f, 0xec, 0x35, 0x00, 0x5b, 0xa4, 0x97, 0xf7, 0x05, + 0xdb, 0xf5, 0x28, 0xfc, 0xa1, 0x46, 0xc6, 0x82, 0x7c, 0x76, 0x31, 0xed, 0x69, 0x77, 0x50, 0xc3, + 0x76, 0x54, 0xa6, 0xf5, 0xd3, 0x80, 0xf5, 0x24, 0x7d, 0x7a, 0x1f, 0xac, 0xfe, 0x49, 0xee, 0x23, + 0xc3, 0x08, 0x4f, 0x7f, 0x92, 0x77, 0x15, 0x95, 0xd3, 0x9f, 0xe4, 0xdd, 0xd5, 0xe0, 0xde, 0x27, + 0x79, 0xc8, 0x43, 0x7f, 0xa9, 0x91, 0x99, 0x68, 0xf5, 0x35, 0x1d, 0xea, 0xd8, 0x7a, 0x6e, 0x3a, + 0xd4, 0xf1, 0xc5, 0xde, 0x9e, 0x0f, 0x04, 0x27, 0x8a, 0xf2, 0x27, 0x1a, 0x21, 0xe1, 0x7f, 0xed, + 0xd3, 0x6b, 0x69, 0x56, 0xee, 0xfa, 0xff, 0xff, 0xdc, 0xf5, 0x83, 0xb2, 0x21, 0xd8, 0xe7, 0x00, + 0xec, 0x69, 0xfa, 0x4c, 0x02, 0x58, 0xd1, 0x66, 0x59, 0x7e, 0xf3, 0xf3, 0x2f, 0x17, 0xb4, 0x2f, + 0xbe, 0x5c, 0xd0, 0xfe, 0xfe, 0xe5, 0x82, 0xf6, 0xe1, 0xe3, 0x85, 0x23, 0x5f, 0x3c, 0x5e, 0x38, + 0xf2, 0x97, 0xc7, 0x0b, 0x47, 0xee, 0x5f, 0xa9, 0xd8, 0x62, 0xab, 0xb1, 0x59, 0xb0, 0xdc, 0xaa, + 0x2a, 0x26, 0xc0, 0x51, 0xdc, 0x89, 0x48, 0xdc, 0xad, 0x33, 0xbe, 0x39, 0x0a, 0x69, 0xcf, 0x0b, + 0xff, 0x0e, 0x00, 0x00, 0xff, 0xff, 0xe5, 0x26, 0xeb, 0xed, 0x7e, 0x32, 0x00, 0x00, } // Reference imports to suppress errors if they are not otherwise used. @@ -4840,6 +4849,13 @@ func (m *QueryGetTssAddressRequest) MarshalToSizedBuffer(dAtA []byte) (int, erro _ = i var l int _ = l + if len(m.TssPubKey) > 0 { + i -= len(m.TssPubKey) + copy(dAtA[i:], m.TssPubKey) + i = encodeVarintQuery(dAtA, i, uint64(len(m.TssPubKey))) + i-- + dAtA[i] = 0xa + } return len(dAtA) - i, nil } @@ -6817,6 +6833,10 @@ func (m *QueryGetTssAddressRequest) Size() (n int) { } var l int _ = l + l = len(m.TssPubKey) + if l > 0 { + n += 1 + l + sovQuery(uint64(l)) + } return n } @@ -9024,6 +9044,38 @@ func (m *QueryGetTssAddressRequest) Unmarshal(dAtA []byte) error { return fmt.Errorf("proto: QueryGetTssAddressRequest: illegal tag %d (wire type %d)", fieldNum, wire) } switch fieldNum { + case 1: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field TssPubKey", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowQuery + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + stringLen |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + intStringLen := int(stringLen) + if intStringLen < 0 { + return ErrInvalidLengthQuery + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthQuery + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.TssPubKey = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex default: iNdEx = preIndex skippy, err := skipQuery(dAtA[iNdEx:]) diff --git a/x/crosschain/types/query.pb.gw.go b/x/crosschain/types/query.pb.gw.go index 2f1029d3f6..7832f5170c 100644 --- a/x/crosschain/types/query.pb.gw.go +++ b/x/crosschain/types/query.pb.gw.go @@ -379,10 +379,21 @@ func local_request_Query_InTxHashToCctxAll_0(ctx context.Context, marshaler runt } +var ( + filter_Query_GetTssAddress_0 = &utilities.DoubleArray{Encoding: map[string]int{}, Base: []int(nil), Check: []int(nil)} +) + func request_Query_GetTssAddress_0(ctx context.Context, marshaler runtime.Marshaler, client QueryClient, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) { var protoReq QueryGetTssAddressRequest var metadata runtime.ServerMetadata + if err := req.ParseForm(); err != nil { + return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err) + } + if err := runtime.PopulateQueryParameters(&protoReq, req.Form, filter_Query_GetTssAddress_0); err != nil { + return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err) + } + msg, err := client.GetTssAddress(ctx, &protoReq, grpc.Header(&metadata.HeaderMD), grpc.Trailer(&metadata.TrailerMD)) return msg, metadata, err @@ -392,6 +403,13 @@ func local_request_Query_GetTssAddress_0(ctx context.Context, marshaler runtime. var protoReq QueryGetTssAddressRequest var metadata runtime.ServerMetadata + if err := req.ParseForm(); err != nil { + return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err) + } + if err := runtime.PopulateQueryParameters(&protoReq, req.Form, filter_Query_GetTssAddress_0); err != nil { + return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err) + } + msg, err := server.GetTssAddress(ctx, &protoReq) return msg, metadata, err diff --git a/x/crosschain/types/tx.pb.go b/x/crosschain/types/tx.pb.go index 3261f28ea9..6b173e9478 100644 --- a/x/crosschain/types/tx.pb.go +++ b/x/crosschain/types/tx.pb.go @@ -31,6 +31,95 @@ var _ = math.Inf // proto package needs to be updated. const _ = proto.GoGoProtoPackageIsVersion3 // please upgrade the proto package +type MsgMigrateTssFunds struct { + Creator string `protobuf:"bytes,1,opt,name=creator,proto3" json:"creator,omitempty"` + ChainId int64 `protobuf:"varint,2,opt,name=chain_id,json=chainId,proto3" json:"chain_id,omitempty"` + Amount github_com_cosmos_cosmos_sdk_types.Uint `protobuf:"bytes,3,opt,name=amount,proto3,customtype=github.com/cosmos/cosmos-sdk/types.Uint" json:"amount"` +} + +func (m *MsgMigrateTssFunds) Reset() { *m = MsgMigrateTssFunds{} } +func (m *MsgMigrateTssFunds) String() string { return proto.CompactTextString(m) } +func (*MsgMigrateTssFunds) ProtoMessage() {} +func (*MsgMigrateTssFunds) Descriptor() ([]byte, []int) { + return fileDescriptor_81d6d611190b7635, []int{0} +} +func (m *MsgMigrateTssFunds) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *MsgMigrateTssFunds) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_MsgMigrateTssFunds.Marshal(b, m, deterministic) + } else { + b = b[:cap(b)] + n, err := m.MarshalToSizedBuffer(b) + if err != nil { + return nil, err + } + return b[:n], nil + } +} +func (m *MsgMigrateTssFunds) XXX_Merge(src proto.Message) { + xxx_messageInfo_MsgMigrateTssFunds.Merge(m, src) +} +func (m *MsgMigrateTssFunds) XXX_Size() int { + return m.Size() +} +func (m *MsgMigrateTssFunds) XXX_DiscardUnknown() { + xxx_messageInfo_MsgMigrateTssFunds.DiscardUnknown(m) +} + +var xxx_messageInfo_MsgMigrateTssFunds proto.InternalMessageInfo + +func (m *MsgMigrateTssFunds) GetCreator() string { + if m != nil { + return m.Creator + } + return "" +} + +func (m *MsgMigrateTssFunds) GetChainId() int64 { + if m != nil { + return m.ChainId + } + return 0 +} + +type MsgMigrateTssFundsResponse struct { +} + +func (m *MsgMigrateTssFundsResponse) Reset() { *m = MsgMigrateTssFundsResponse{} } +func (m *MsgMigrateTssFundsResponse) String() string { return proto.CompactTextString(m) } +func (*MsgMigrateTssFundsResponse) ProtoMessage() {} +func (*MsgMigrateTssFundsResponse) Descriptor() ([]byte, []int) { + return fileDescriptor_81d6d611190b7635, []int{1} +} +func (m *MsgMigrateTssFundsResponse) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *MsgMigrateTssFundsResponse) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_MsgMigrateTssFundsResponse.Marshal(b, m, deterministic) + } else { + b = b[:cap(b)] + n, err := m.MarshalToSizedBuffer(b) + if err != nil { + return nil, err + } + return b[:n], nil + } +} +func (m *MsgMigrateTssFundsResponse) XXX_Merge(src proto.Message) { + xxx_messageInfo_MsgMigrateTssFundsResponse.Merge(m, src) +} +func (m *MsgMigrateTssFundsResponse) XXX_Size() int { + return m.Size() +} +func (m *MsgMigrateTssFundsResponse) XXX_DiscardUnknown() { + xxx_messageInfo_MsgMigrateTssFundsResponse.DiscardUnknown(m) +} + +var xxx_messageInfo_MsgMigrateTssFundsResponse proto.InternalMessageInfo + type MsgUpdateTssAddress struct { Creator string `protobuf:"bytes,1,opt,name=creator,proto3" json:"creator,omitempty"` TssPubkey string `protobuf:"bytes,2,opt,name=tss_pubkey,json=tssPubkey,proto3" json:"tss_pubkey,omitempty"` @@ -40,7 +129,7 @@ func (m *MsgUpdateTssAddress) Reset() { *m = MsgUpdateTssAddress{} } func (m *MsgUpdateTssAddress) String() string { return proto.CompactTextString(m) } func (*MsgUpdateTssAddress) ProtoMessage() {} func (*MsgUpdateTssAddress) Descriptor() ([]byte, []int) { - return fileDescriptor_81d6d611190b7635, []int{0} + return fileDescriptor_81d6d611190b7635, []int{2} } func (m *MsgUpdateTssAddress) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -90,7 +179,7 @@ func (m *MsgUpdateTssAddressResponse) Reset() { *m = MsgUpdateTssAddress func (m *MsgUpdateTssAddressResponse) String() string { return proto.CompactTextString(m) } func (*MsgUpdateTssAddressResponse) ProtoMessage() {} func (*MsgUpdateTssAddressResponse) Descriptor() ([]byte, []int) { - return fileDescriptor_81d6d611190b7635, []int{1} + return fileDescriptor_81d6d611190b7635, []int{3} } func (m *MsgUpdateTssAddressResponse) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -133,7 +222,7 @@ func (m *MsgWhitelistERC20) Reset() { *m = MsgWhitelistERC20{} } func (m *MsgWhitelistERC20) String() string { return proto.CompactTextString(m) } func (*MsgWhitelistERC20) ProtoMessage() {} func (*MsgWhitelistERC20) Descriptor() ([]byte, []int) { - return fileDescriptor_81d6d611190b7635, []int{2} + return fileDescriptor_81d6d611190b7635, []int{4} } func (m *MsgWhitelistERC20) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -220,7 +309,7 @@ func (m *MsgWhitelistERC20Response) Reset() { *m = MsgWhitelistERC20Resp func (m *MsgWhitelistERC20Response) String() string { return proto.CompactTextString(m) } func (*MsgWhitelistERC20Response) ProtoMessage() {} func (*MsgWhitelistERC20Response) Descriptor() ([]byte, []int) { - return fileDescriptor_81d6d611190b7635, []int{3} + return fileDescriptor_81d6d611190b7635, []int{5} } func (m *MsgWhitelistERC20Response) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -277,7 +366,7 @@ func (m *MsgAddToOutTxTracker) Reset() { *m = MsgAddToOutTxTracker{} } func (m *MsgAddToOutTxTracker) String() string { return proto.CompactTextString(m) } func (*MsgAddToOutTxTracker) ProtoMessage() {} func (*MsgAddToOutTxTracker) Descriptor() ([]byte, []int) { - return fileDescriptor_81d6d611190b7635, []int{4} + return fileDescriptor_81d6d611190b7635, []int{6} } func (m *MsgAddToOutTxTracker) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -362,7 +451,7 @@ func (m *MsgAddToOutTxTrackerResponse) Reset() { *m = MsgAddToOutTxTrack func (m *MsgAddToOutTxTrackerResponse) String() string { return proto.CompactTextString(m) } func (*MsgAddToOutTxTrackerResponse) ProtoMessage() {} func (*MsgAddToOutTxTrackerResponse) Descriptor() ([]byte, []int) { - return fileDescriptor_81d6d611190b7635, []int{5} + return fileDescriptor_81d6d611190b7635, []int{7} } func (m *MsgAddToOutTxTrackerResponse) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -401,7 +490,7 @@ func (m *MsgRemoveFromOutTxTracker) Reset() { *m = MsgRemoveFromOutTxTra func (m *MsgRemoveFromOutTxTracker) String() string { return proto.CompactTextString(m) } func (*MsgRemoveFromOutTxTracker) ProtoMessage() {} func (*MsgRemoveFromOutTxTracker) Descriptor() ([]byte, []int) { - return fileDescriptor_81d6d611190b7635, []int{6} + return fileDescriptor_81d6d611190b7635, []int{8} } func (m *MsgRemoveFromOutTxTracker) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -458,7 +547,7 @@ func (m *MsgRemoveFromOutTxTrackerResponse) Reset() { *m = MsgRemoveFrom func (m *MsgRemoveFromOutTxTrackerResponse) String() string { return proto.CompactTextString(m) } func (*MsgRemoveFromOutTxTrackerResponse) ProtoMessage() {} func (*MsgRemoveFromOutTxTrackerResponse) Descriptor() ([]byte, []int) { - return fileDescriptor_81d6d611190b7635, []int{7} + return fileDescriptor_81d6d611190b7635, []int{9} } func (m *MsgRemoveFromOutTxTrackerResponse) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -498,7 +587,7 @@ func (m *MsgCreateTSSVoter) Reset() { *m = MsgCreateTSSVoter{} } func (m *MsgCreateTSSVoter) String() string { return proto.CompactTextString(m) } func (*MsgCreateTSSVoter) ProtoMessage() {} func (*MsgCreateTSSVoter) Descriptor() ([]byte, []int) { - return fileDescriptor_81d6d611190b7635, []int{8} + return fileDescriptor_81d6d611190b7635, []int{10} } func (m *MsgCreateTSSVoter) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -562,7 +651,7 @@ func (m *MsgCreateTSSVoterResponse) Reset() { *m = MsgCreateTSSVoterResp func (m *MsgCreateTSSVoterResponse) String() string { return proto.CompactTextString(m) } func (*MsgCreateTSSVoterResponse) ProtoMessage() {} func (*MsgCreateTSSVoterResponse) Descriptor() ([]byte, []int) { - return fileDescriptor_81d6d611190b7635, []int{9} + return fileDescriptor_81d6d611190b7635, []int{11} } func (m *MsgCreateTSSVoterResponse) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -603,7 +692,7 @@ func (m *MsgGasPriceVoter) Reset() { *m = MsgGasPriceVoter{} } func (m *MsgGasPriceVoter) String() string { return proto.CompactTextString(m) } func (*MsgGasPriceVoter) ProtoMessage() {} func (*MsgGasPriceVoter) Descriptor() ([]byte, []int) { - return fileDescriptor_81d6d611190b7635, []int{10} + return fileDescriptor_81d6d611190b7635, []int{12} } func (m *MsgGasPriceVoter) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -674,7 +763,7 @@ func (m *MsgGasPriceVoterResponse) Reset() { *m = MsgGasPriceVoterRespon func (m *MsgGasPriceVoterResponse) String() string { return proto.CompactTextString(m) } func (*MsgGasPriceVoterResponse) ProtoMessage() {} func (*MsgGasPriceVoterResponse) Descriptor() ([]byte, []int) { - return fileDescriptor_81d6d611190b7635, []int{11} + return fileDescriptor_81d6d611190b7635, []int{13} } func (m *MsgGasPriceVoterResponse) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -713,7 +802,7 @@ func (m *MsgNonceVoter) Reset() { *m = MsgNonceVoter{} } func (m *MsgNonceVoter) String() string { return proto.CompactTextString(m) } func (*MsgNonceVoter) ProtoMessage() {} func (*MsgNonceVoter) Descriptor() ([]byte, []int) { - return fileDescriptor_81d6d611190b7635, []int{12} + return fileDescriptor_81d6d611190b7635, []int{14} } func (m *MsgNonceVoter) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -770,7 +859,7 @@ func (m *MsgNonceVoterResponse) Reset() { *m = MsgNonceVoterResponse{} } func (m *MsgNonceVoterResponse) String() string { return proto.CompactTextString(m) } func (*MsgNonceVoterResponse) ProtoMessage() {} func (*MsgNonceVoterResponse) Descriptor() ([]byte, []int) { - return fileDescriptor_81d6d611190b7635, []int{13} + return fileDescriptor_81d6d611190b7635, []int{15} } func (m *MsgNonceVoterResponse) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -818,7 +907,7 @@ func (m *MsgVoteOnObservedOutboundTx) Reset() { *m = MsgVoteOnObservedOu func (m *MsgVoteOnObservedOutboundTx) String() string { return proto.CompactTextString(m) } func (*MsgVoteOnObservedOutboundTx) ProtoMessage() {} func (*MsgVoteOnObservedOutboundTx) Descriptor() ([]byte, []int) { - return fileDescriptor_81d6d611190b7635, []int{14} + return fileDescriptor_81d6d611190b7635, []int{16} } func (m *MsgVoteOnObservedOutboundTx) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -924,7 +1013,7 @@ func (m *MsgVoteOnObservedOutboundTxResponse) Reset() { *m = MsgVoteOnOb func (m *MsgVoteOnObservedOutboundTxResponse) String() string { return proto.CompactTextString(m) } func (*MsgVoteOnObservedOutboundTxResponse) ProtoMessage() {} func (*MsgVoteOnObservedOutboundTxResponse) Descriptor() ([]byte, []int) { - return fileDescriptor_81d6d611190b7635, []int{15} + return fileDescriptor_81d6d611190b7635, []int{17} } func (m *MsgVoteOnObservedOutboundTxResponse) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -975,7 +1064,7 @@ func (m *MsgVoteOnObservedInboundTx) Reset() { *m = MsgVoteOnObservedInb func (m *MsgVoteOnObservedInboundTx) String() string { return proto.CompactTextString(m) } func (*MsgVoteOnObservedInboundTx) ProtoMessage() {} func (*MsgVoteOnObservedInboundTx) Descriptor() ([]byte, []int) { - return fileDescriptor_81d6d611190b7635, []int{16} + return fileDescriptor_81d6d611190b7635, []int{18} } func (m *MsgVoteOnObservedInboundTx) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -1095,7 +1184,7 @@ func (m *MsgVoteOnObservedInboundTxResponse) Reset() { *m = MsgVoteOnObs func (m *MsgVoteOnObservedInboundTxResponse) String() string { return proto.CompactTextString(m) } func (*MsgVoteOnObservedInboundTxResponse) ProtoMessage() {} func (*MsgVoteOnObservedInboundTxResponse) Descriptor() ([]byte, []int) { - return fileDescriptor_81d6d611190b7635, []int{17} + return fileDescriptor_81d6d611190b7635, []int{19} } func (m *MsgVoteOnObservedInboundTxResponse) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -1134,7 +1223,7 @@ func (m *MsgSetNodeKeys) Reset() { *m = MsgSetNodeKeys{} } func (m *MsgSetNodeKeys) String() string { return proto.CompactTextString(m) } func (*MsgSetNodeKeys) ProtoMessage() {} func (*MsgSetNodeKeys) Descriptor() ([]byte, []int) { - return fileDescriptor_81d6d611190b7635, []int{18} + return fileDescriptor_81d6d611190b7635, []int{20} } func (m *MsgSetNodeKeys) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -1191,7 +1280,7 @@ func (m *MsgSetNodeKeysResponse) Reset() { *m = MsgSetNodeKeysResponse{} func (m *MsgSetNodeKeysResponse) String() string { return proto.CompactTextString(m) } func (*MsgSetNodeKeysResponse) ProtoMessage() {} func (*MsgSetNodeKeysResponse) Descriptor() ([]byte, []int) { - return fileDescriptor_81d6d611190b7635, []int{19} + return fileDescriptor_81d6d611190b7635, []int{21} } func (m *MsgSetNodeKeysResponse) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -1221,6 +1310,8 @@ func (m *MsgSetNodeKeysResponse) XXX_DiscardUnknown() { var xxx_messageInfo_MsgSetNodeKeysResponse proto.InternalMessageInfo func init() { + proto.RegisterType((*MsgMigrateTssFunds)(nil), "zetachain.zetacore.crosschain.MsgMigrateTssFunds") + proto.RegisterType((*MsgMigrateTssFundsResponse)(nil), "zetachain.zetacore.crosschain.MsgMigrateTssFundsResponse") proto.RegisterType((*MsgUpdateTssAddress)(nil), "zetachain.zetacore.crosschain.MsgUpdateTssAddress") proto.RegisterType((*MsgUpdateTssAddressResponse)(nil), "zetachain.zetacore.crosschain.MsgUpdateTssAddressResponse") proto.RegisterType((*MsgWhitelistERC20)(nil), "zetachain.zetacore.crosschain.MsgWhitelistERC20") @@ -1246,94 +1337,97 @@ func init() { func init() { proto.RegisterFile("crosschain/tx.proto", fileDescriptor_81d6d611190b7635) } var fileDescriptor_81d6d611190b7635 = []byte{ - // 1383 bytes of a gzipped FileDescriptorProto - 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xb4, 0x58, 0x4f, 0x6f, 0x1b, 0x45, - 0x14, 0xcf, 0x36, 0x89, 0x63, 0xbf, 0xc4, 0x69, 0xb2, 0x49, 0x9b, 0xed, 0xa6, 0x71, 0xda, 0x0d, - 0x2d, 0x15, 0x6a, 0xec, 0xe2, 0x82, 0x28, 0x85, 0x03, 0x4d, 0x54, 0xd2, 0x50, 0x9c, 0x54, 0x1b, - 0x17, 0xa4, 0x5e, 0x56, 0xeb, 0xdd, 0xc9, 0x7a, 0x15, 0xef, 0x8e, 0xb5, 0x33, 0x8e, 0xec, 0x88, - 0x13, 0x12, 0x07, 0x6e, 0x1c, 0x90, 0x40, 0x7c, 0x01, 0xbe, 0x4a, 0xb9, 0x55, 0x9c, 0x28, 0x87, - 0x0a, 0x9a, 0x6f, 0xc0, 0x27, 0x40, 0xf3, 0x67, 0x37, 0x5e, 0x27, 0xb6, 0xe3, 0x20, 0x4e, 0x9e, - 0xf7, 0xe6, 0xfd, 0xde, 0xbf, 0x79, 0x6f, 0xe6, 0xad, 0x61, 0xc1, 0x89, 0x30, 0x21, 0x4e, 0xdd, - 0xf6, 0xc3, 0x12, 0x6d, 0x17, 0x9b, 0x11, 0xa6, 0x58, 0x5d, 0x39, 0x42, 0xd4, 0xe6, 0xbc, 0x22, - 0x5f, 0xe1, 0x08, 0x15, 0x4f, 0xe4, 0xf4, 0x05, 0x07, 0x07, 0x01, 0x0e, 0x4b, 0xe2, 0x47, 0x60, - 0xf4, 0x45, 0x0f, 0x7b, 0x98, 0x2f, 0x4b, 0x6c, 0x25, 0xb8, 0xc6, 0x0e, 0x2c, 0x54, 0x88, 0xf7, - 0xbc, 0xe9, 0xda, 0x14, 0x55, 0x09, 0x79, 0xe4, 0xba, 0x11, 0x22, 0x44, 0xd5, 0x60, 0xca, 0x89, - 0x90, 0x4d, 0x71, 0xa4, 0x29, 0x37, 0x94, 0x3b, 0x39, 0x33, 0x26, 0xd5, 0x15, 0x00, 0x4a, 0x88, - 0xd5, 0x6c, 0xd5, 0x0e, 0x50, 0x47, 0xbb, 0xc4, 0x37, 0x73, 0x94, 0x90, 0x67, 0x9c, 0x61, 0xac, - 0xc0, 0xf2, 0x19, 0xfa, 0x4c, 0x44, 0x9a, 0x38, 0x24, 0xc8, 0xf8, 0x5d, 0x81, 0xf9, 0x0a, 0xf1, - 0xbe, 0xae, 0xfb, 0x14, 0x35, 0x7c, 0x42, 0x1f, 0x9b, 0x9b, 0xe5, 0x7b, 0x03, 0xac, 0xad, 0x41, - 0x1e, 0x45, 0x4e, 0xf9, 0x9e, 0x65, 0x0b, 0x45, 0xd2, 0xe0, 0x0c, 0x67, 0xc6, 0xce, 0x5e, 0x83, - 0x2c, 0x8f, 0xdb, 0xf2, 0x5d, 0x6d, 0xfc, 0x86, 0x72, 0x67, 0xdc, 0x9c, 0xe2, 0xf4, 0xb6, 0xab, - 0xaa, 0x30, 0x11, 0xda, 0x01, 0xd2, 0x26, 0x38, 0x8c, 0xaf, 0xd5, 0xab, 0x90, 0x21, 0x9d, 0xa0, - 0x86, 0x1b, 0xda, 0x24, 0xe7, 0x4a, 0x4a, 0xd5, 0x21, 0xeb, 0x22, 0xc7, 0x0f, 0xec, 0x06, 0xd1, - 0x32, 0x37, 0x94, 0x3b, 0x79, 0x33, 0xa1, 0xd5, 0x65, 0xc8, 0x79, 0x36, 0xb1, 0x1a, 0x7e, 0xe0, - 0x53, 0x6d, 0x8a, 0xdb, 0xc8, 0x7a, 0x36, 0xf9, 0x92, 0xd1, 0x86, 0x05, 0xd7, 0x4e, 0xc5, 0x14, - 0x47, 0xcc, 0x22, 0x38, 0x4a, 0x45, 0x20, 0x22, 0x9c, 0x39, 0xea, 0x8e, 0x60, 0x05, 0xc0, 0x71, - 0x68, 0xdb, 0xf2, 0x43, 0x17, 0xb5, 0xe3, 0xa4, 0x32, 0xce, 0x36, 0x63, 0x18, 0xaf, 0x15, 0x58, - 0xac, 0x10, 0xef, 0x91, 0xeb, 0x56, 0xf1, 0x6e, 0x8b, 0x56, 0xdb, 0xd5, 0xc8, 0x76, 0x0e, 0x50, - 0x34, 0x20, 0x71, 0xdd, 0x39, 0xb9, 0x94, 0xce, 0xc9, 0x22, 0x4c, 0x86, 0x38, 0x74, 0x10, 0xcf, - 0xd5, 0x84, 0x29, 0x08, 0x75, 0x09, 0xa6, 0x68, 0xdb, 0xaa, 0xdb, 0xa4, 0x2e, 0x93, 0x95, 0xa1, - 0xed, 0x27, 0x36, 0xa9, 0xab, 0x6b, 0x30, 0xd9, 0x8c, 0x30, 0xde, 0xe7, 0xd9, 0x9a, 0x2e, 0xe7, - 0x8b, 0xb2, 0xaa, 0x9e, 0x31, 0xa6, 0x29, 0xf6, 0x58, 0x00, 0xb5, 0x06, 0x76, 0x0e, 0x84, 0x82, - 0x8c, 0x08, 0x80, 0x73, 0xb8, 0x8e, 0x6b, 0x90, 0x4d, 0xa2, 0x13, 0xd9, 0x9b, 0x8a, 0x63, 0x2b, - 0xc0, 0xf5, 0xb3, 0x42, 0x4b, 0x2a, 0x66, 0x9f, 0x27, 0xd7, 0x44, 0x01, 0x3e, 0x44, 0x9f, 0x47, - 0x38, 0xf8, 0x9f, 0xe2, 0x37, 0xd6, 0xe0, 0x66, 0x5f, 0x3b, 0x89, 0x33, 0xbf, 0x8a, 0xf2, 0xdd, - 0x64, 0x46, 0x50, 0x75, 0x6f, 0xef, 0x2b, 0x4c, 0x07, 0x7a, 0x31, 0xb8, 0x59, 0xd4, 0xf7, 0x60, - 0xee, 0x00, 0x75, 0xb6, 0x50, 0xf8, 0x02, 0x51, 0xfb, 0x09, 0xf2, 0xbd, 0x3a, 0x95, 0x05, 0x7c, - 0x8a, 0xaf, 0xae, 0x43, 0x86, 0x50, 0x9b, 0xb6, 0x08, 0x3f, 0x9e, 0xd9, 0xf2, 0x95, 0xf8, 0x1c, - 0x4c, 0xe4, 0x20, 0xff, 0x10, 0xed, 0xf1, 0x4d, 0x53, 0x0a, 0x19, 0xcb, 0x3c, 0x6d, 0x69, 0x47, - 0x93, 0x30, 0x7e, 0x56, 0x60, 0xae, 0x42, 0xbc, 0x2d, 0x9b, 0x3c, 0x8b, 0x7c, 0x07, 0x0d, 0x8b, - 0x62, 0x70, 0x2e, 0x9b, 0x4c, 0x45, 0x9c, 0x4b, 0x4e, 0xa8, 0x37, 0x61, 0x46, 0x54, 0x43, 0xd8, - 0x0a, 0x6a, 0x28, 0xe2, 0x1e, 0x4f, 0x98, 0xd3, 0x9c, 0xb7, 0xc3, 0x59, 0xbc, 0x09, 0x5b, 0xcd, - 0x66, 0xa3, 0x93, 0x34, 0x21, 0xa7, 0x0c, 0x1d, 0xb4, 0x5e, 0xcf, 0x12, 0xb7, 0x5f, 0x40, 0xbe, - 0x42, 0xbc, 0x1d, 0x76, 0x5c, 0xff, 0xcd, 0xe5, 0x33, 0x8e, 0x7f, 0x09, 0xae, 0xa4, 0x74, 0x27, - 0x46, 0x5f, 0x4f, 0xf2, 0x1b, 0x8d, 0x31, 0x77, 0xc3, 0xdd, 0x1a, 0x41, 0xd1, 0x21, 0x72, 0x77, - 0x5b, 0xb4, 0x86, 0x5b, 0xa1, 0x5b, 0x6d, 0x0f, 0xf0, 0x61, 0x19, 0x78, 0x0b, 0x8b, 0x96, 0x10, - 0x67, 0x9f, 0x65, 0x0c, 0xde, 0x11, 0x45, 0x58, 0xc0, 0x52, 0x99, 0x85, 0x59, 0xa9, 0x09, 0xb1, - 0x71, 0x2e, 0x36, 0x8f, 0x4f, 0xec, 0x54, 0x85, 0xfc, 0xa7, 0xa0, 0xf7, 0xc8, 0x8b, 0xee, 0x12, - 0x45, 0x23, 0x12, 0xac, 0xa5, 0x60, 0x1b, 0x27, 0xfb, 0xea, 0x87, 0xb0, 0xd4, 0x83, 0x66, 0xb7, - 0x59, 0x8b, 0x20, 0x57, 0x03, 0x0e, 0x5d, 0x4c, 0x41, 0xb7, 0x6c, 0xf2, 0x9c, 0x20, 0x57, 0x3d, - 0x02, 0xa3, 0x07, 0x86, 0xf6, 0xf7, 0x91, 0x43, 0xfd, 0x43, 0xc4, 0x15, 0x88, 0xa3, 0x9f, 0x66, - 0x3e, 0x6f, 0x14, 0x5f, 0xbe, 0x59, 0x1d, 0xfb, 0xf3, 0xcd, 0xea, 0x6d, 0xcf, 0xa7, 0xf5, 0x56, - 0x8d, 0x55, 0x67, 0xc9, 0xc1, 0x24, 0xc0, 0x44, 0xfe, 0xac, 0x13, 0xf7, 0xa0, 0x44, 0x3b, 0x4d, - 0x44, 0x8a, 0xdb, 0x21, 0x35, 0x0b, 0x29, 0x8b, 0x8f, 0x63, 0xbd, 0xf1, 0xc9, 0xab, 0x5f, 0x0c, - 0xb1, 0x2d, 0xae, 0xe2, 0x19, 0xee, 0x7d, 0x7f, 0x5d, 0xfc, 0x82, 0x56, 0x31, 0xcc, 0x1e, 0xda, - 0x8d, 0x16, 0xb2, 0x22, 0xd1, 0x2b, 0xae, 0x28, 0xba, 0x8d, 0x27, 0xd2, 0xe7, 0x77, 0xcf, 0xe1, - 0xf3, 0x73, 0x3f, 0xa4, 0xff, 0xbc, 0x59, 0xbd, 0xd2, 0xb1, 0x83, 0xc6, 0x43, 0x23, 0xad, 0xce, - 0x30, 0xf3, 0x9c, 0x21, 0x5b, 0xd1, 0xed, 0x6a, 0xd6, 0xcc, 0x39, 0x9a, 0x55, 0x5d, 0x85, 0x69, - 0x11, 0x22, 0xaf, 0x51, 0x79, 0x43, 0x02, 0x67, 0x6d, 0x32, 0x8e, 0x7a, 0x1b, 0x2e, 0x0b, 0x01, - 0x76, 0x9b, 0x88, 0xea, 0xcd, 0xf2, 0xc8, 0xf3, 0x9c, 0x5d, 0x25, 0x84, 0x57, 0xae, 0xba, 0x0e, - 0x39, 0x07, 0xfb, 0xa1, 0xc5, 0x5c, 0xd6, 0x72, 0xdc, 0xf4, 0x5c, 0x6c, 0x7a, 0x13, 0xfb, 0x61, - 0xb5, 0xd3, 0x44, 0x66, 0xd6, 0x91, 0x2b, 0xe3, 0x16, 0xac, 0x0d, 0x28, 0xed, 0xa4, 0x05, 0xfe, - 0x1e, 0x07, 0xfd, 0x94, 0xdc, 0x76, 0x38, 0xbc, 0x03, 0x58, 0x93, 0xa3, 0xd0, 0x45, 0x91, 0x2c, - 0x7f, 0x49, 0xb1, 0x70, 0xc4, 0xca, 0xea, 0x79, 0xb7, 0xf3, 0x82, 0xbd, 0x29, 0x5b, 0x55, 0x87, - 0xac, 0x4c, 0x71, 0x24, 0x1f, 0xa5, 0x84, 0x56, 0x6f, 0xc1, 0x6c, 0xbc, 0x96, 0x69, 0x9b, 0x14, - 0x2a, 0x62, 0xae, 0xc8, 0xdc, 0x16, 0x64, 0xec, 0x00, 0xb7, 0x42, 0x2a, 0x1e, 0xa5, 0x8d, 0xd2, - 0x88, 0x47, 0x6e, 0x4a, 0x38, 0x8b, 0x32, 0x40, 0x84, 0xd8, 0x9e, 0x48, 0x7d, 0xce, 0x8c, 0x49, - 0xf5, 0x3a, 0x00, 0x4b, 0xb9, 0xec, 0xe0, 0x9c, 0xf0, 0xd3, 0x0f, 0x65, 0xe3, 0xde, 0x86, 0xcb, - 0x7e, 0x68, 0xc9, 0xc7, 0x51, 0x74, 0xab, 0x68, 0xb9, 0xbc, 0x1f, 0x76, 0xb7, 0x68, 0x6a, 0xc2, - 0x98, 0xe6, 0x12, 0xc9, 0x84, 0x91, 0x3e, 0xd7, 0x99, 0x61, 0xe7, 0xca, 0x74, 0xd1, 0xb6, 0x85, - 0x23, 0xdf, 0xf3, 0x43, 0x2d, 0x2f, 0x1c, 0xa2, 0xed, 0x5d, 0x4e, 0xb3, 0xfb, 0xcf, 0x26, 0x04, - 0x51, 0x6d, 0x96, 0x6f, 0x08, 0xc2, 0x78, 0x07, 0x8c, 0xfe, 0x47, 0x9c, 0x54, 0xc2, 0xf7, 0x0a, - 0xcc, 0x56, 0x88, 0xb7, 0x87, 0xe8, 0x0e, 0x76, 0xd1, 0x53, 0xd4, 0x19, 0x34, 0x29, 0x96, 0x20, - 0x27, 0x1e, 0xbe, 0x3d, 0x44, 0x79, 0x01, 0x4c, 0x97, 0xe7, 0x93, 0xe1, 0xa1, 0x55, 0x7b, 0xca, - 0x37, 0xcc, 0x13, 0x19, 0xf5, 0x2e, 0xa8, 0xac, 0xbe, 0x89, 0xef, 0x85, 0x28, 0xb2, 0xe4, 0x6c, - 0x24, 0xaf, 0xc4, 0x39, 0x4a, 0xc8, 0x1e, 0xdf, 0x90, 0x7c, 0x43, 0x83, 0xab, 0x69, 0x57, 0x62, - 0x2f, 0xcb, 0xbf, 0xe5, 0x60, 0xbc, 0x42, 0x3c, 0xf5, 0x3b, 0x05, 0xe6, 0x4f, 0xcf, 0x4c, 0xf7, - 0x8b, 0x03, 0x87, 0xe7, 0xe2, 0x59, 0xd3, 0x88, 0xfe, 0xc9, 0x05, 0x40, 0xc9, 0x08, 0xf8, 0xa3, - 0x02, 0x57, 0xfb, 0x0c, 0x30, 0x0f, 0x86, 0xeb, 0x3d, 0x1b, 0xa9, 0x7f, 0x76, 0x51, 0x64, 0xe2, - 0xd6, 0x37, 0x30, 0xdb, 0x33, 0xc8, 0xdc, 0x1b, 0xae, 0x33, 0x8d, 0xd0, 0x1f, 0x8c, 0x8a, 0x48, - 0xac, 0x77, 0x20, 0x9f, 0x9e, 0x3f, 0x4a, 0xc3, 0x55, 0xa5, 0x00, 0xfa, 0x47, 0x23, 0x02, 0x12, - 0xd3, 0x4d, 0x80, 0xae, 0x21, 0xe2, 0xee, 0x70, 0x35, 0x27, 0xd2, 0xfa, 0x07, 0xa3, 0x48, 0x27, - 0x16, 0x7f, 0x51, 0x40, 0xeb, 0x3b, 0x41, 0x3c, 0x1c, 0xae, 0xb2, 0x1f, 0x56, 0xdf, 0xb8, 0x38, - 0x36, 0x71, 0xee, 0x27, 0x05, 0x96, 0xfa, 0xdd, 0xed, 0x1f, 0x8f, 0xaa, 0x3f, 0x81, 0xea, 0x8f, - 0x2e, 0x0c, 0xed, 0xae, 0xd0, 0x9e, 0x2f, 0xc5, 0x73, 0x54, 0x68, 0x1a, 0x71, 0x9e, 0x0a, 0xed, - 0xf3, 0xe5, 0xf6, 0xad, 0x02, 0x73, 0xa7, 0x3e, 0x8c, 0xcb, 0xc3, 0xd5, 0xf5, 0x62, 0xf4, 0x87, - 0xa3, 0x63, 0x62, 0x27, 0x36, 0x9e, 0xbe, 0x7c, 0x5b, 0x50, 0x5e, 0xbd, 0x2d, 0x28, 0x7f, 0xbd, - 0x2d, 0x28, 0x3f, 0x1c, 0x17, 0xc6, 0x5e, 0x1d, 0x17, 0xc6, 0xfe, 0x38, 0x2e, 0x8c, 0xbd, 0x78, - 0xbf, 0xeb, 0x05, 0x63, 0x5a, 0xd7, 0xc5, 0x7f, 0x04, 0xb1, 0x81, 0x52, 0xbb, 0xd4, 0xfd, 0xcf, - 0x01, 0x7b, 0xd0, 0x6a, 0x19, 0xfe, 0xcd, 0x7f, 0xff, 0xdf, 0x00, 0x00, 0x00, 0xff, 0xff, 0x43, - 0xc6, 0x61, 0x3f, 0x54, 0x10, 0x00, 0x00, + // 1440 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xb4, 0x58, 0x4f, 0x6f, 0xdb, 0xc6, + 0x12, 0x37, 0x9f, 0x6d, 0x59, 0x1a, 0x5b, 0x8e, 0xbd, 0x76, 0x62, 0x86, 0x8e, 0xe5, 0x84, 0x7e, + 0xc9, 0x0b, 0x1e, 0x62, 0x29, 0x51, 0xde, 0x43, 0x93, 0xb4, 0x87, 0xc6, 0x46, 0xe2, 0xb8, 0xa9, + 0xec, 0x80, 0x56, 0x5a, 0x20, 0x17, 0x82, 0x22, 0xd7, 0x14, 0x61, 0x91, 0x2b, 0x70, 0x57, 0x86, + 0x64, 0x14, 0x28, 0x50, 0xa0, 0x87, 0xde, 0x8a, 0xa2, 0x40, 0x8b, 0x7e, 0x81, 0x7e, 0x95, 0xa0, + 0xa7, 0xa0, 0xa7, 0xa6, 0x87, 0xa0, 0x4d, 0xbe, 0x41, 0x3f, 0x41, 0xb1, 0xbb, 0x24, 0x2d, 0xca, + 0x96, 0x64, 0x39, 0xe8, 0x49, 0x3b, 0xb3, 0xf3, 0x9b, 0x7f, 0x3b, 0xb3, 0x3b, 0x22, 0x2c, 0xd8, + 0x21, 0xa1, 0xd4, 0xae, 0x5b, 0x5e, 0x50, 0x62, 0xed, 0x62, 0x33, 0x24, 0x8c, 0xa0, 0x95, 0x23, + 0xcc, 0x2c, 0xc1, 0x2b, 0x8a, 0x15, 0x09, 0x71, 0xf1, 0x58, 0x4e, 0x5b, 0xb0, 0x89, 0xef, 0x93, + 0xa0, 0x24, 0x7f, 0x24, 0x46, 0x5b, 0x74, 0x89, 0x4b, 0xc4, 0xb2, 0xc4, 0x57, 0x92, 0xab, 0x7f, + 0xa7, 0x00, 0xaa, 0x50, 0xb7, 0xe2, 0xb9, 0xa1, 0xc5, 0x70, 0x95, 0xd2, 0xc7, 0xad, 0xc0, 0xa1, + 0x48, 0x85, 0x29, 0x3b, 0xc4, 0x16, 0x23, 0xa1, 0xaa, 0x5c, 0x55, 0x6e, 0xe6, 0x8c, 0x98, 0x44, + 0x97, 0x21, 0x2b, 0x8c, 0x98, 0x9e, 0xa3, 0xfe, 0xeb, 0xaa, 0x72, 0x73, 0xdc, 0x98, 0x12, 0xf4, + 0xb6, 0x83, 0xb6, 0x20, 0x63, 0xf9, 0xa4, 0x15, 0x30, 0x75, 0x9c, 0x63, 0x36, 0x4a, 0x2f, 0xdf, + 0xac, 0x8e, 0xfd, 0xfe, 0x66, 0xf5, 0x3f, 0xae, 0xc7, 0xea, 0xad, 0x5a, 0xd1, 0x26, 0x7e, 0xc9, + 0x26, 0xd4, 0x27, 0x34, 0xfa, 0x59, 0xa7, 0xce, 0x41, 0x89, 0x75, 0x9a, 0x98, 0x16, 0x9f, 0x7b, + 0x01, 0x33, 0x22, 0xb8, 0x7e, 0x05, 0xb4, 0x93, 0x3e, 0x19, 0x98, 0x36, 0x49, 0x40, 0xb1, 0xbe, + 0x03, 0x0b, 0x15, 0xea, 0x3e, 0x6f, 0x3a, 0x72, 0xf3, 0xa1, 0xe3, 0x84, 0x98, 0x0e, 0x72, 0x79, + 0x05, 0x80, 0x51, 0x6a, 0x36, 0x5b, 0xb5, 0x03, 0xdc, 0x11, 0x4e, 0xe7, 0x8c, 0x1c, 0xa3, 0xf4, + 0x99, 0x60, 0xe8, 0x2b, 0xb0, 0x7c, 0x8a, 0xbe, 0xc4, 0xdc, 0xaf, 0x0a, 0xcc, 0x57, 0xa8, 0xfb, + 0x79, 0xdd, 0x63, 0xb8, 0xe1, 0x51, 0xf6, 0xc8, 0xd8, 0x2c, 0xdf, 0x1e, 0x60, 0x6d, 0x0d, 0xf2, + 0x38, 0xb4, 0xcb, 0xb7, 0x4d, 0x4b, 0x2a, 0x8a, 0x0c, 0xce, 0x08, 0x66, 0xec, 0x6c, 0x77, 0x16, + 0xc7, 0xd3, 0x59, 0x44, 0x30, 0x11, 0x58, 0x3e, 0x56, 0x27, 0x04, 0x4c, 0xac, 0xd1, 0x25, 0xc8, + 0xd0, 0x8e, 0x5f, 0x23, 0x0d, 0x75, 0x52, 0x70, 0x23, 0x0a, 0x69, 0x90, 0x75, 0xb0, 0xed, 0xf9, + 0x56, 0x83, 0xaa, 0x99, 0xab, 0xca, 0xcd, 0xbc, 0x91, 0xd0, 0x68, 0x19, 0x72, 0xae, 0x45, 0xcd, + 0x86, 0xe7, 0x7b, 0x4c, 0x9d, 0x12, 0x36, 0xb2, 0xae, 0x45, 0x3f, 0xe5, 0xb4, 0x6e, 0xc2, 0xe5, + 0x13, 0x31, 0xc5, 0x11, 0xf3, 0x08, 0x8e, 0x52, 0x11, 0xc8, 0x08, 0x67, 0x8e, 0xba, 0x23, 0x58, + 0x01, 0xb0, 0x6d, 0xd6, 0x36, 0xbd, 0xc0, 0xc1, 0xed, 0x38, 0xa9, 0x9c, 0xb3, 0xcd, 0x19, 0xfa, + 0x6b, 0x05, 0x16, 0x2b, 0xd4, 0x7d, 0xe8, 0x38, 0x55, 0xb2, 0xdb, 0x62, 0xd5, 0x76, 0x35, 0xb4, + 0xec, 0x03, 0x1c, 0x9e, 0xaf, 0xb2, 0x16, 0x61, 0x32, 0x20, 0x81, 0x8d, 0x45, 0xae, 0x26, 0x0c, + 0x49, 0xa0, 0x25, 0x98, 0x62, 0x6d, 0xb3, 0x6e, 0xd1, 0x7a, 0x94, 0xac, 0x0c, 0x6b, 0x3f, 0xb1, + 0x68, 0x1d, 0xad, 0xc1, 0x64, 0x33, 0x24, 0x64, 0x5f, 0x64, 0x6b, 0xba, 0x9c, 0x2f, 0x46, 0x8d, + 0xf0, 0x8c, 0x33, 0x0d, 0xb9, 0xc7, 0x03, 0xa8, 0x35, 0x88, 0x7d, 0x20, 0x15, 0x64, 0x64, 0x00, + 0x82, 0x23, 0x74, 0x5c, 0x86, 0x6c, 0x12, 0x9d, 0xcc, 0xde, 0x54, 0x1c, 0x5b, 0x01, 0xae, 0x9c, + 0x16, 0x5a, 0x52, 0x31, 0xfb, 0x22, 0xb9, 0x06, 0xf6, 0xc9, 0x21, 0x7e, 0x1c, 0x12, 0xff, 0x1f, + 0x8a, 0x5f, 0x5f, 0x83, 0x6b, 0x7d, 0xed, 0x24, 0xce, 0xfc, 0x2c, 0xcb, 0x77, 0x93, 0x1b, 0xc1, + 0xd5, 0xbd, 0xbd, 0xcf, 0x08, 0x1b, 0xe8, 0xc5, 0xe0, 0x66, 0x41, 0xff, 0x85, 0xb9, 0x03, 0xdc, + 0xd9, 0xc2, 0xc1, 0x0b, 0xcc, 0xac, 0x27, 0xd8, 0x73, 0xeb, 0x2c, 0x2a, 0xe0, 0x13, 0x7c, 0xb4, + 0x0e, 0x19, 0xca, 0x2c, 0xd6, 0xa2, 0xe2, 0x78, 0x66, 0xcb, 0x17, 0xe3, 0x73, 0x30, 0xb0, 0x8d, + 0xbd, 0x43, 0xbc, 0x27, 0x36, 0x8d, 0x48, 0x48, 0x5f, 0x16, 0x69, 0x4b, 0x3b, 0x9a, 0x84, 0xf1, + 0xa3, 0x02, 0x73, 0x15, 0xea, 0x6e, 0x59, 0xf4, 0x59, 0xe8, 0xd9, 0x78, 0x58, 0x14, 0x83, 0x73, + 0xd9, 0xe4, 0x2a, 0xe2, 0x5c, 0x0a, 0x02, 0x5d, 0x83, 0x19, 0x59, 0x0d, 0x41, 0xcb, 0xaf, 0xe1, + 0x50, 0x78, 0x3c, 0x61, 0x4c, 0x0b, 0xde, 0x8e, 0x60, 0x89, 0x26, 0x6c, 0x35, 0x9b, 0x8d, 0x4e, + 0xd2, 0x84, 0x82, 0xd2, 0x35, 0x50, 0x7b, 0x3d, 0x4b, 0xdc, 0x7e, 0x01, 0xf9, 0x0a, 0x75, 0x77, + 0xf8, 0x71, 0xbd, 0x9f, 0xcb, 0xa7, 0x1c, 0xff, 0x12, 0x5c, 0x4c, 0xe9, 0x4e, 0x8c, 0xbe, 0x9e, + 0x14, 0x37, 0x1a, 0x67, 0xee, 0x06, 0xbb, 0x35, 0x8a, 0xc3, 0x43, 0xec, 0xec, 0xb6, 0x58, 0x8d, + 0xb4, 0x02, 0xa7, 0xda, 0x1e, 0xe0, 0xc3, 0x32, 0x88, 0x16, 0x96, 0x2d, 0x21, 0xcf, 0x3e, 0xcb, + 0x19, 0xa2, 0x23, 0x8a, 0xb0, 0x40, 0x22, 0x65, 0x26, 0xe1, 0xa5, 0x26, 0xc5, 0xc4, 0x5d, 0x6f, + 0xcc, 0x93, 0x63, 0x3b, 0x55, 0x29, 0xff, 0x11, 0x68, 0x3d, 0xf2, 0xb2, 0xbb, 0x64, 0xd1, 0xc8, + 0x04, 0xab, 0x29, 0xd8, 0xc6, 0xf1, 0x3e, 0xfa, 0x3f, 0x2c, 0xf5, 0xa0, 0xf9, 0x6d, 0xd6, 0xa2, + 0xd8, 0x51, 0x41, 0x40, 0x17, 0x53, 0xd0, 0x2d, 0x8b, 0x3e, 0xa7, 0xd8, 0x41, 0x47, 0xa0, 0xf7, + 0xc0, 0xf0, 0xfe, 0x3e, 0xb6, 0x99, 0x77, 0x88, 0x85, 0x02, 0x79, 0xf4, 0xd3, 0xe2, 0x7d, 0x2a, + 0x46, 0xef, 0xd3, 0x8d, 0x33, 0xbc, 0x4f, 0xdb, 0x01, 0x33, 0x0a, 0x29, 0x8b, 0x8f, 0x62, 0xbd, + 0xf1, 0xc9, 0xa3, 0x4f, 0x86, 0xd8, 0x96, 0x57, 0xf1, 0x8c, 0xf0, 0xbe, 0xbf, 0x2e, 0x71, 0x41, + 0x23, 0x02, 0xb3, 0x87, 0x56, 0xa3, 0x85, 0xcd, 0x50, 0xf6, 0x8a, 0x23, 0x8b, 0x6e, 0xe3, 0xc9, + 0x88, 0x6f, 0xea, 0x5f, 0x6f, 0x56, 0x2f, 0x76, 0x2c, 0xbf, 0xf1, 0x40, 0x4f, 0xab, 0xd3, 0x8d, + 0xbc, 0x60, 0x44, 0xad, 0xe8, 0x74, 0x35, 0x6b, 0xe6, 0x0c, 0xcd, 0x8a, 0x56, 0x61, 0x5a, 0x86, + 0x28, 0x6a, 0x34, 0xba, 0x21, 0x41, 0xb0, 0x36, 0x39, 0x07, 0xdd, 0x80, 0x0b, 0x52, 0x80, 0xdf, + 0x26, 0xb2, 0x7a, 0xb3, 0x22, 0xf2, 0xbc, 0x60, 0x57, 0x29, 0x15, 0x95, 0x8b, 0xd6, 0x21, 0x67, + 0x13, 0x2f, 0x30, 0xb9, 0xcb, 0x6a, 0x4e, 0x98, 0x9e, 0x8b, 0x4d, 0x6f, 0x12, 0x2f, 0xa8, 0x76, + 0x9a, 0xd8, 0xc8, 0xda, 0xd1, 0x4a, 0xbf, 0x0e, 0x6b, 0x03, 0x4a, 0x3b, 0x69, 0x81, 0x3f, 0xc7, + 0xc5, 0x08, 0x91, 0x96, 0xdb, 0x0e, 0x86, 0x77, 0x00, 0x6f, 0x72, 0x1c, 0x38, 0x38, 0x8c, 0xca, + 0x3f, 0xa2, 0x78, 0x38, 0x72, 0x65, 0xf6, 0xbc, 0xdb, 0x79, 0xc9, 0xde, 0x8c, 0x5a, 0x55, 0x83, + 0x6c, 0x94, 0xe2, 0x30, 0x7a, 0x94, 0x12, 0x1a, 0x5d, 0x87, 0xd9, 0x78, 0x1d, 0xa5, 0x6d, 0x52, + 0xaa, 0x88, 0xb9, 0x32, 0x73, 0xc7, 0x63, 0x54, 0xe6, 0xbd, 0xc6, 0x28, 0x1e, 0xa5, 0x8f, 0x29, + 0xb5, 0x5c, 0x99, 0xfa, 0x9c, 0x11, 0x93, 0xe8, 0x0a, 0x00, 0x4f, 0x79, 0xd4, 0xc1, 0x39, 0xe9, + 0xa7, 0x17, 0x44, 0x8d, 0x7b, 0x03, 0x2e, 0x78, 0x81, 0x19, 0x3d, 0x8e, 0xb2, 0x5b, 0x65, 0xcb, + 0xe5, 0xbd, 0xa0, 0xbb, 0x45, 0x53, 0x13, 0xc6, 0xb4, 0x90, 0x48, 0x26, 0x8c, 0xf4, 0xb9, 0xce, + 0x0c, 0x3b, 0x57, 0xae, 0x8b, 0xb5, 0x4d, 0x12, 0x7a, 0xae, 0x17, 0xa8, 0x79, 0xe9, 0x10, 0x6b, + 0xef, 0x0a, 0x9a, 0xdf, 0x7f, 0x16, 0xa5, 0x98, 0xa9, 0xb3, 0x62, 0x43, 0x12, 0xfa, 0xbf, 0x41, + 0xef, 0x7f, 0xc4, 0x49, 0x25, 0x7c, 0xa3, 0xc0, 0x6c, 0x85, 0xba, 0x7b, 0x98, 0xed, 0x10, 0x07, + 0x3f, 0xc5, 0x9d, 0x41, 0x93, 0x62, 0x09, 0x72, 0xf2, 0xe1, 0xdb, 0xc3, 0x4c, 0x14, 0xc0, 0x74, + 0x79, 0x3e, 0x19, 0x1e, 0x5a, 0xb5, 0xa7, 0x62, 0xc3, 0x38, 0x96, 0x41, 0xb7, 0x00, 0xf1, 0xfa, + 0xa6, 0x9e, 0x1b, 0xe0, 0xd0, 0x8c, 0x66, 0xa3, 0xe8, 0x4a, 0x9c, 0x63, 0x94, 0xee, 0x89, 0x8d, + 0x88, 0xaf, 0xab, 0x70, 0x29, 0xed, 0x4a, 0xec, 0x65, 0xf9, 0x17, 0x80, 0xf1, 0x0a, 0x75, 0xd1, + 0xd7, 0x0a, 0xcc, 0x9f, 0x9c, 0x99, 0xee, 0x16, 0x07, 0xce, 0xfb, 0xc5, 0xd3, 0xa6, 0x11, 0xed, + 0xc3, 0x73, 0x80, 0x92, 0x11, 0xf0, 0x7b, 0x05, 0x2e, 0xf5, 0x19, 0x60, 0xee, 0x0d, 0xd7, 0x7b, + 0x3a, 0x52, 0xfb, 0xf8, 0xbc, 0xc8, 0xc4, 0xad, 0x2f, 0x60, 0xb6, 0x67, 0x90, 0xb9, 0x3d, 0x5c, + 0x67, 0x1a, 0xa1, 0xdd, 0x1b, 0x15, 0x91, 0x58, 0xef, 0x40, 0x3e, 0x3d, 0x7f, 0x94, 0x86, 0xab, + 0x4a, 0x01, 0xb4, 0x0f, 0x46, 0x04, 0x24, 0xa6, 0x9b, 0x00, 0x5d, 0x43, 0xc4, 0xad, 0xe1, 0x6a, + 0x8e, 0xa5, 0xb5, 0xff, 0x8d, 0x22, 0x9d, 0x58, 0xfc, 0x49, 0x01, 0xb5, 0xef, 0x04, 0xf1, 0x60, + 0xb8, 0xca, 0x7e, 0x58, 0x6d, 0xe3, 0xfc, 0xd8, 0xc4, 0xb9, 0x1f, 0x14, 0x58, 0xea, 0x77, 0xb7, + 0xdf, 0x1f, 0x55, 0x7f, 0x02, 0xd5, 0x1e, 0x9e, 0x1b, 0xda, 0x5d, 0xa1, 0x3d, 0xff, 0x14, 0xcf, + 0x50, 0xa1, 0x69, 0xc4, 0x59, 0x2a, 0xb4, 0xcf, 0x3f, 0xb7, 0xaf, 0x14, 0x98, 0x3b, 0xf1, 0xc7, + 0xb8, 0x3c, 0x5c, 0x5d, 0x2f, 0x46, 0x7b, 0x30, 0x3a, 0x26, 0x71, 0xe2, 0x4b, 0xb8, 0xd0, 0xfb, + 0x39, 0xe1, 0xce, 0x70, 0x75, 0x3d, 0x10, 0xed, 0xfe, 0xc8, 0x90, 0xd8, 0x81, 0x8d, 0xa7, 0x2f, + 0xdf, 0x16, 0x94, 0x57, 0x6f, 0x0b, 0xca, 0x1f, 0x6f, 0x0b, 0xca, 0xb7, 0xef, 0x0a, 0x63, 0xaf, + 0xde, 0x15, 0xc6, 0x7e, 0x7b, 0x57, 0x18, 0x7b, 0x71, 0xa7, 0xeb, 0x09, 0xe5, 0x4a, 0xd7, 0xe5, + 0x77, 0x95, 0x58, 0x7f, 0xa9, 0x5d, 0xea, 0xfe, 0xda, 0xc2, 0x5f, 0xd4, 0x5a, 0x46, 0x7c, 0x27, + 0xb9, 0xfb, 0x77, 0x00, 0x00, 0x00, 0xff, 0xff, 0x59, 0x22, 0xcb, 0x23, 0x88, 0x11, 0x00, 0x00, } // Reference imports to suppress errors if they are not otherwise used. @@ -1357,6 +1451,7 @@ type MsgClient interface { VoteOnObservedInboundTx(ctx context.Context, in *MsgVoteOnObservedInboundTx, opts ...grpc.CallOption) (*MsgVoteOnObservedInboundTxResponse, error) WhitelistERC20(ctx context.Context, in *MsgWhitelistERC20, opts ...grpc.CallOption) (*MsgWhitelistERC20Response, error) UpdateTssAddress(ctx context.Context, in *MsgUpdateTssAddress, opts ...grpc.CallOption) (*MsgUpdateTssAddressResponse, error) + MigrateTssFunds(ctx context.Context, in *MsgMigrateTssFunds, opts ...grpc.CallOption) (*MsgMigrateTssFundsResponse, error) } type msgClient struct { @@ -1448,6 +1543,15 @@ func (c *msgClient) UpdateTssAddress(ctx context.Context, in *MsgUpdateTssAddres return out, nil } +func (c *msgClient) MigrateTssFunds(ctx context.Context, in *MsgMigrateTssFunds, opts ...grpc.CallOption) (*MsgMigrateTssFundsResponse, error) { + out := new(MsgMigrateTssFundsResponse) + err := c.cc.Invoke(ctx, "/zetachain.zetacore.crosschain.Msg/MigrateTssFunds", in, out, opts...) + if err != nil { + return nil, err + } + return out, nil +} + // MsgServer is the server API for Msg service. type MsgServer interface { AddToOutTxTracker(context.Context, *MsgAddToOutTxTracker) (*MsgAddToOutTxTrackerResponse, error) @@ -1459,6 +1563,7 @@ type MsgServer interface { VoteOnObservedInboundTx(context.Context, *MsgVoteOnObservedInboundTx) (*MsgVoteOnObservedInboundTxResponse, error) WhitelistERC20(context.Context, *MsgWhitelistERC20) (*MsgWhitelistERC20Response, error) UpdateTssAddress(context.Context, *MsgUpdateTssAddress) (*MsgUpdateTssAddressResponse, error) + MigrateTssFunds(context.Context, *MsgMigrateTssFunds) (*MsgMigrateTssFundsResponse, error) } // UnimplementedMsgServer can be embedded to have forward compatible implementations. @@ -1492,6 +1597,9 @@ func (*UnimplementedMsgServer) WhitelistERC20(ctx context.Context, req *MsgWhite func (*UnimplementedMsgServer) UpdateTssAddress(ctx context.Context, req *MsgUpdateTssAddress) (*MsgUpdateTssAddressResponse, error) { return nil, status.Errorf(codes.Unimplemented, "method UpdateTssAddress not implemented") } +func (*UnimplementedMsgServer) MigrateTssFunds(ctx context.Context, req *MsgMigrateTssFunds) (*MsgMigrateTssFundsResponse, error) { + return nil, status.Errorf(codes.Unimplemented, "method MigrateTssFunds not implemented") +} func RegisterMsgServer(s grpc1.Server, srv MsgServer) { s.RegisterService(&_Msg_serviceDesc, srv) @@ -1659,6 +1767,24 @@ func _Msg_UpdateTssAddress_Handler(srv interface{}, ctx context.Context, dec fun return interceptor(ctx, in, info, handler) } +func _Msg_MigrateTssFunds_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(MsgMigrateTssFunds) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(MsgServer).MigrateTssFunds(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: "/zetachain.zetacore.crosschain.Msg/MigrateTssFunds", + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(MsgServer).MigrateTssFunds(ctx, req.(*MsgMigrateTssFunds)) + } + return interceptor(ctx, in, info, handler) +} + var _Msg_serviceDesc = grpc.ServiceDesc{ ServiceName: "zetachain.zetacore.crosschain.Msg", HandlerType: (*MsgServer)(nil), @@ -1699,11 +1825,83 @@ var _Msg_serviceDesc = grpc.ServiceDesc{ MethodName: "UpdateTssAddress", Handler: _Msg_UpdateTssAddress_Handler, }, + { + MethodName: "MigrateTssFunds", + Handler: _Msg_MigrateTssFunds_Handler, + }, }, Streams: []grpc.StreamDesc{}, Metadata: "crosschain/tx.proto", } +func (m *MsgMigrateTssFunds) Marshal() (dAtA []byte, err error) { + size := m.Size() + dAtA = make([]byte, size) + n, err := m.MarshalToSizedBuffer(dAtA[:size]) + if err != nil { + return nil, err + } + return dAtA[:n], nil +} + +func (m *MsgMigrateTssFunds) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *MsgMigrateTssFunds) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + { + size := m.Amount.Size() + i -= size + if _, err := m.Amount.MarshalTo(dAtA[i:]); err != nil { + return 0, err + } + i = encodeVarintTx(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0x1a + if m.ChainId != 0 { + i = encodeVarintTx(dAtA, i, uint64(m.ChainId)) + i-- + dAtA[i] = 0x10 + } + if len(m.Creator) > 0 { + i -= len(m.Creator) + copy(dAtA[i:], m.Creator) + i = encodeVarintTx(dAtA, i, uint64(len(m.Creator))) + i-- + dAtA[i] = 0xa + } + return len(dAtA) - i, nil +} + +func (m *MsgMigrateTssFundsResponse) Marshal() (dAtA []byte, err error) { + size := m.Size() + dAtA = make([]byte, size) + n, err := m.MarshalToSizedBuffer(dAtA[:size]) + if err != nil { + return nil, err + } + return dAtA[:n], nil +} + +func (m *MsgMigrateTssFundsResponse) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *MsgMigrateTssFundsResponse) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + return len(dAtA) - i, nil +} + func (m *MsgUpdateTssAddress) Marshal() (dAtA []byte, err error) { size := m.Size() dAtA = make([]byte, size) @@ -2567,6 +2765,33 @@ func encodeVarintTx(dAtA []byte, offset int, v uint64) int { dAtA[offset] = uint8(v) return base } +func (m *MsgMigrateTssFunds) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + l = len(m.Creator) + if l > 0 { + n += 1 + l + sovTx(uint64(l)) + } + if m.ChainId != 0 { + n += 1 + sovTx(uint64(m.ChainId)) + } + l = m.Amount.Size() + n += 1 + l + sovTx(uint64(l)) + return n +} + +func (m *MsgMigrateTssFundsResponse) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + return n +} + func (m *MsgUpdateTssAddress) Size() (n int) { if m == nil { return 0 @@ -2964,6 +3189,191 @@ func sovTx(x uint64) (n int) { func sozTx(x uint64) (n int) { return sovTx(uint64((x << 1) ^ uint64((int64(x) >> 63)))) } +func (m *MsgMigrateTssFunds) Unmarshal(dAtA []byte) error { + l := len(dAtA) + iNdEx := 0 + for iNdEx < l { + preIndex := iNdEx + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowTx + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + fieldNum := int32(wire >> 3) + wireType := int(wire & 0x7) + if wireType == 4 { + return fmt.Errorf("proto: MsgMigrateTssFunds: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: MsgMigrateTssFunds: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Creator", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowTx + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + stringLen |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + intStringLen := int(stringLen) + if intStringLen < 0 { + return ErrInvalidLengthTx + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthTx + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.Creator = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + case 2: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field ChainId", wireType) + } + m.ChainId = 0 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowTx + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + m.ChainId |= int64(b&0x7F) << shift + if b < 0x80 { + break + } + } + case 3: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Amount", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowTx + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + stringLen |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + intStringLen := int(stringLen) + if intStringLen < 0 { + return ErrInvalidLengthTx + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthTx + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + if err := m.Amount.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + default: + iNdEx = preIndex + skippy, err := skipTx(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return ErrInvalidLengthTx + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func (m *MsgMigrateTssFundsResponse) Unmarshal(dAtA []byte) error { + l := len(dAtA) + iNdEx := 0 + for iNdEx < l { + preIndex := iNdEx + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowTx + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + fieldNum := int32(wire >> 3) + wireType := int(wire & 0x7) + if wireType == 4 { + return fmt.Errorf("proto: MsgMigrateTssFundsResponse: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: MsgMigrateTssFundsResponse: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + default: + iNdEx = preIndex + skippy, err := skipTx(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return ErrInvalidLengthTx + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} func (m *MsgUpdateTssAddress) Unmarshal(dAtA []byte) error { l := len(dAtA) iNdEx := 0 diff --git a/x/emissions/client/cli/query.go b/x/emissions/client/cli/query.go index b4ae1a4e03..bd2ed2b0bb 100644 --- a/x/emissions/client/cli/query.go +++ b/x/emissions/client/cli/query.go @@ -5,12 +5,11 @@ import ( // "strings" "github.com/spf13/cobra" + "github.com/zeta-chain/zetacore/x/emissions/types" "github.com/cosmos/cosmos-sdk/client" // "github.com/cosmos/cosmos-sdk/client/flags" // sdk "github.com/cosmos/cosmos-sdk/types" - - "github.com/zeta-chain/zetacore/x/emissions/types" ) // GetQueryCmd returns the cli query commands for this module diff --git a/x/emissions/client/cli/tx.go b/x/emissions/client/cli/tx.go index 53f12c7cc0..8e1fe8632e 100644 --- a/x/emissions/client/cli/tx.go +++ b/x/emissions/client/cli/tx.go @@ -4,10 +4,9 @@ import ( "fmt" "github.com/spf13/cobra" + "github.com/zeta-chain/zetacore/x/emissions/types" "github.com/cosmos/cosmos-sdk/client" - // "github.com/cosmos/cosmos-sdk/client/flags" - "github.com/zeta-chain/zetacore/x/emissions/types" ) // GetTxCmd returns the transaction commands for this module diff --git a/x/emissions/client/tests/observer_rewards_test.go b/x/emissions/client/tests/observer_rewards_test.go index c3113deb87..853e3a3ad8 100644 --- a/x/emissions/client/tests/observer_rewards_test.go +++ b/x/emissions/client/tests/observer_rewards_test.go @@ -9,19 +9,19 @@ import ( sdk "github.com/cosmos/cosmos-sdk/types" "github.com/cosmos/cosmos-sdk/x/bank/client/cli" "github.com/zeta-chain/zetacore/cmd/zetacored/config" - emmisonscli "github.com/zeta-chain/zetacore/x/emissions/client/cli" - emmisonstypes "github.com/zeta-chain/zetacore/x/emissions/types" - observerCli "github.com/zeta-chain/zetacore/x/observer/client/cli" - observerTypes "github.com/zeta-chain/zetacore/x/observer/types" + emissionscli "github.com/zeta-chain/zetacore/x/emissions/client/cli" + emissionstypes "github.com/zeta-chain/zetacore/x/emissions/types" + observercli "github.com/zeta-chain/zetacore/x/observer/client/cli" + observertypes "github.com/zeta-chain/zetacore/x/observer/types" ) func (s *CliTestSuite) TestObserverRewards() { emissionPool := "800000000000000000000azeta" val := s.network.Validators[0] - out, err := clitestutil.ExecTestCLICmd(val.ClientCtx, emmisonscli.CmdListPoolAddresses(), []string{"--output", "json"}) + out, err := clitestutil.ExecTestCLICmd(val.ClientCtx, emissionscli.CmdListPoolAddresses(), []string{"--output", "json"}) s.Require().NoError(err) - resPools := emmisonstypes.QueryListPoolAddressesResponse{} + resPools := emissionstypes.QueryListPoolAddressesResponse{} s.Require().NoError(err) s.Require().NoError(val.ClientCtx.Codec.UnmarshalJSON(out.Bytes(), &resPools)) txArgs := []string{ @@ -38,22 +38,22 @@ func (s *CliTestSuite) TestObserverRewards() { s.Require().NoError(s.network.WaitForNextBlock()) // Collect parameter values and build assertion map for the randomised ballot set created - emissionFactors := emmisonstypes.QueryGetEmissionsFactorsResponse{} - out, err = clitestutil.ExecTestCLICmd(val.ClientCtx, emmisonscli.CmdGetEmmisonsFactors(), []string{"--output", "json"}) + emissionFactors := emissionstypes.QueryGetEmissionsFactorsResponse{} + out, err = clitestutil.ExecTestCLICmd(val.ClientCtx, emissionscli.CmdGetEmmisonsFactors(), []string{"--output", "json"}) s.Require().NoError(err) s.Require().NoError(val.ClientCtx.Codec.UnmarshalJSON(out.Bytes(), &emissionFactors)) - emissionParams := emmisonstypes.QueryParamsResponse{} - out, err = clitestutil.ExecTestCLICmd(val.ClientCtx, emmisonscli.CmdQueryParams(), []string{"--output", "json"}) + emissionParams := emissionstypes.QueryParamsResponse{} + out, err = clitestutil.ExecTestCLICmd(val.ClientCtx, emissionscli.CmdQueryParams(), []string{"--output", "json"}) s.Require().NoError(err) s.Require().NoError(val.ClientCtx.Codec.UnmarshalJSON(out.Bytes(), &emissionParams)) - observerParams := observerTypes.QueryParamsResponse{} - out, err = clitestutil.ExecTestCLICmd(val.ClientCtx, observerCli.CmdQueryParams(), []string{"--output", "json"}) + observerParams := observertypes.QueryParamsResponse{} + out, err = clitestutil.ExecTestCLICmd(val.ClientCtx, observercli.CmdQueryParams(), []string{"--output", "json"}) s.Require().NoError(err) s.Require().NoError(val.ClientCtx.Codec.UnmarshalJSON(out.Bytes(), &observerParams)) _, err = s.network.WaitForHeight(s.ballots[0].BallotCreationHeight + observerParams.Params.BallotMaturityBlocks) s.Require().NoError(err) - out, err = clitestutil.ExecTestCLICmd(val.ClientCtx, emmisonscli.CmdGetEmmisonsFactors(), []string{"--output", "json"}) - resFactorsNewBlocks := emmisonstypes.QueryGetEmissionsFactorsResponse{} + out, err = clitestutil.ExecTestCLICmd(val.ClientCtx, emissionscli.CmdGetEmmisonsFactors(), []string{"--output", "json"}) + resFactorsNewBlocks := emissionstypes.QueryGetEmissionsFactorsResponse{} s.Require().NoError(err) s.Require().NoError(val.ClientCtx.Codec.UnmarshalJSON(out.Bytes(), &resFactorsNewBlocks)) // Duration factor is calculated in the same block,so we need to query based from the committed state at which the distribution is done @@ -62,9 +62,9 @@ func (s *CliTestSuite) TestObserverRewards() { asertValues := CalculateObserverRewards(s.ballots, emissionParams.Params.ObserverEmissionPercentage, emissionFactors.ReservesFactor, emissionFactors.BondFactor, emissionFactors.DurationFactor) // Assert withdrawable rewards for each validator - resAvailable := emmisonstypes.QueryShowAvailableEmissionsResponse{} + resAvailable := emissionstypes.QueryShowAvailableEmissionsResponse{} for i := 0; i < len(s.network.Validators); i++ { - out, err = clitestutil.ExecTestCLICmd(val.ClientCtx, emmisonscli.CmdShowAvailableEmissions(), []string{s.network.Validators[i].Address.String(), "--output", "json"}) + out, err = clitestutil.ExecTestCLICmd(val.ClientCtx, emissionscli.CmdShowAvailableEmissions(), []string{s.network.Validators[i].Address.String(), "--output", "json"}) s.Require().NoError(err) s.Require().NoError(val.ClientCtx.Codec.UnmarshalJSON(out.Bytes(), &resAvailable)) s.Require().Equal(sdk.NewCoin(config.BaseDenom, asertValues[s.network.Validators[i].Address.String()]).String(), resAvailable.Amount, "Validator %s has incorrect withdrawable rewards", s.network.Validators[i].Address.String()) @@ -72,7 +72,7 @@ func (s *CliTestSuite) TestObserverRewards() { } -func CalculateObserverRewards(ballots []*observerTypes.Ballot, observerEmissionPercentage, reservesFactor, bondFactor, durationFactor string) map[string]sdkmath.Int { +func CalculateObserverRewards(ballots []*observertypes.Ballot, observerEmissionPercentage, reservesFactor, bondFactor, durationFactor string) map[string]sdkmath.Int { calculatedDistributer := map[string]sdkmath.Int{} blockRewards := sdk.MustNewDecFromStr(reservesFactor).Mul(sdk.MustNewDecFromStr(bondFactor)).Mul(sdk.MustNewDecFromStr(durationFactor)) observerRewards := sdk.MustNewDecFromStr(observerEmissionPercentage).Mul(blockRewards).TruncateInt() diff --git a/x/emissions/keeper/grpc_query_show_available_emissions.go b/x/emissions/keeper/grpc_query_show_available_emissions.go index c56a6f4d45..4f33bf5f07 100644 --- a/x/emissions/keeper/grpc_query_show_available_emissions.go +++ b/x/emissions/keeper/grpc_query_show_available_emissions.go @@ -4,9 +4,9 @@ import ( "context" "github.com/zeta-chain/zetacore/cmd/zetacored/config" + "github.com/zeta-chain/zetacore/x/emissions/types" sdk "github.com/cosmos/cosmos-sdk/types" - "github.com/zeta-chain/zetacore/x/emissions/types" ) func (k Keeper) ShowAvailableEmissions(goCtx context.Context, req *types.QueryShowAvailableEmissionsRequest) (*types.QueryShowAvailableEmissionsResponse, error) { diff --git a/x/emissions/keeper/keeper.go b/x/emissions/keeper/keeper.go index 96d825de3b..3655c42016 100644 --- a/x/emissions/keeper/keeper.go +++ b/x/emissions/keeper/keeper.go @@ -5,11 +5,11 @@ import ( storetypes "github.com/cosmos/cosmos-sdk/store/types" "github.com/tendermint/tendermint/libs/log" + "github.com/zeta-chain/zetacore/x/emissions/types" "github.com/cosmos/cosmos-sdk/codec" sdk "github.com/cosmos/cosmos-sdk/types" paramtypes "github.com/cosmos/cosmos-sdk/x/params/types" - "github.com/zeta-chain/zetacore/x/emissions/types" ) type ( diff --git a/x/emissions/module.go b/x/emissions/module.go index 02c7e9437d..a40c9743e9 100644 --- a/x/emissions/module.go +++ b/x/emissions/module.go @@ -8,6 +8,9 @@ import ( "github.com/gorilla/mux" "github.com/grpc-ecosystem/grpc-gateway/runtime" "github.com/spf13/cobra" + "github.com/zeta-chain/zetacore/x/emissions/client/cli" + emissionskeeper "github.com/zeta-chain/zetacore/x/emissions/keeper" + "github.com/zeta-chain/zetacore/x/emissions/types" abci "github.com/tendermint/tendermint/abci/types" @@ -16,9 +19,6 @@ import ( cdctypes "github.com/cosmos/cosmos-sdk/codec/types" sdk "github.com/cosmos/cosmos-sdk/types" "github.com/cosmos/cosmos-sdk/types/module" - "github.com/zeta-chain/zetacore/x/emissions/client/cli" - "github.com/zeta-chain/zetacore/x/emissions/keeper" - "github.com/zeta-chain/zetacore/x/emissions/types" ) var ( @@ -101,13 +101,13 @@ func (AppModuleBasic) GetQueryCmd() *cobra.Command { type AppModule struct { AppModuleBasic - keeper keeper.Keeper + keeper emissionskeeper.Keeper accountKeeper types.AccountKeeper } func NewAppModule( cdc codec.Codec, - keeper keeper.Keeper, + keeper emissionskeeper.Keeper, accountKeeper types.AccountKeeper, ) AppModule { return AppModule{ @@ -138,7 +138,7 @@ func (am AppModule) LegacyQuerierHandler(_ *codec.LegacyAmino) sdk.Querier { // RegisterServices registers a GRPC query service to respond to the // module-specific GRPC queries. func (am AppModule) RegisterServices(cfg module.Configurator) { - types.RegisterMsgServer(cfg.MsgServer(), keeper.NewMsgServerImpl(am.keeper)) + types.RegisterMsgServer(cfg.MsgServer(), emissionskeeper.NewMsgServerImpl(am.keeper)) types.RegisterQueryServer(cfg.QueryServer(), am.keeper) } diff --git a/x/emissions/types/events.pb.go b/x/emissions/types/events.pb.go index 201211e96f..a1a96178cc 100644 --- a/x/emissions/types/events.pb.go +++ b/x/emissions/types/events.pb.go @@ -51,8 +51,8 @@ func (EmissionType) EnumDescriptor() ([]byte, []int) { } type ObserverEmission struct { - EmissionType EmissionType `protobuf:"varint,1,opt,name=emission_type,json=emissionType,proto3,enum=zetachain.zetacore.emissions.EmissionType" json:"emission_type,omitempty"` - ObserverAddress string `protobuf:"bytes,2,opt,name=observer_address,json=observerAddress,proto3" json:"observer_address,omitempty"` + EmissionType EmissionType `protobuf:"varint,1,opt,name=emission_type,json=emissionType,proto3,enum=zetachain.zetacore.emissions.EmissionType" json:"emission_type,omitempty"` + ObserverAddress string `protobuf:"bytes,2,opt,name=observer_address,json=observerAddress,proto3" json:"observer_address,omitempty"` Amount github_com_cosmos_cosmos_sdk_types.Int `protobuf:"bytes,3,opt,name=amount,proto3,customtype=github.com/cosmos/cosmos-sdk/types.Int" json:"amount"` } diff --git a/zetaclient/bitcoin_client.go b/zetaclient/bitcoin_client.go index 6f68f28a7a..83e75d5a53 100644 --- a/zetaclient/bitcoin_client.go +++ b/zetaclient/bitcoin_client.go @@ -76,8 +76,9 @@ type BitcoinChainClient struct { const ( minConfirmations = 0 maxHeightDiff = 10000 - btcBlocksPerDay = 144 + dustOffset = 2000 bytesPerKB = 1000 + btcBlocksPerDay = 144 ) func (ob *BitcoinChainClient) SetCoreParams(params observertypes.CoreParams) { @@ -1004,7 +1005,7 @@ func (ob *BitcoinChainClient) getRawTxResult(hash *chainhash.Hash, res *btcjson. // - All inputs are from TSS address func (ob *BitcoinChainClient) checkTSSVin(vins []btcjson.Vin, nonce uint64) error { // vins: [nonce-mark, UTXO1, UTXO2, ...] - if len(vins) <= 1 { + if nonce > 0 && len(vins) <= 1 { return fmt.Errorf("checkTSSVin: len(vins) <= 1") } pubKeyTss := hex.EncodeToString(ob.Tss.PubKeyCompressedBytes()) @@ -1206,3 +1207,9 @@ func (ob *BitcoinChainClient) GetBlockByNumberCached(blockNumber int64) (*BTCBlo ob.BlockCache.Add(hash, blockNheader) return blockNheader, nil } + +// A very special value to mark current nonce in UTXO +func NonceMarkAmount(nonce uint64) int64 { + // #nosec G701 always in range + return int64(nonce) + config.DustOffset // +2000 to avoid being a dust rejection +} diff --git a/zetaclient/btc_signer.go b/zetaclient/btc_signer.go index f8ba3d0e6f..ffc0d56a67 100644 --- a/zetaclient/btc_signer.go +++ b/zetaclient/btc_signer.go @@ -68,7 +68,9 @@ func NewBTCSigner(cfg config.BTCConfig, tssSigner TSSSigner, logger zerolog.Logg // SignWithdrawTx receives utxos sorted by value, amount in BTC, feeRate in BTC per Kb func (signer *BTCSigner) SignWithdrawTx(to *btcutil.AddressWitnessPubKeyHash, amount float64, gasPrice *big.Int, sizeLimit uint64, btcClient *BitcoinChainClient, height uint64, nonce uint64, chain *common.Chain) (*wire.MsgTx, error) { + estimateFee := float64(gasPrice.Uint64()) * outTxBytesMax / 1e8 + nonceMark := common.NonceMarkAmount(nonce) // refresh unspent UTXOs and continue with keysign regardless of error @@ -237,7 +239,7 @@ func (signer *BTCSigner) TryProcessOutTx(send *types.CrossChainTx, outTxMan *Out Logger() params := send.GetCurrentOutTxParam() - if params.CoinType != common.CoinType_Gas { + if params.CoinType == common.CoinType_Zeta || params.CoinType == common.CoinType_ERC20 { logger.Error().Msgf("BTC TryProcessOutTx: can only send BTC to a BTC network") return } diff --git a/zetaclient/config/config_mainnet.go b/zetaclient/config/config_mainnet.go index 646b8b3460..2a52abfc24 100644 --- a/zetaclient/config/config_mainnet.go +++ b/zetaclient/config/config_mainnet.go @@ -9,6 +9,7 @@ import ( ) const ( + DustOffset = 0 BtcConfirmationCount = 1 DevEthConfirmationCount = 2 ) diff --git a/zetaclient/config/config_mock_mainnet.go b/zetaclient/config/config_mock_mainnet.go index fe7195d1cd..1f3f82970b 100644 --- a/zetaclient/config/config_mock_mainnet.go +++ b/zetaclient/config/config_mock_mainnet.go @@ -9,6 +9,7 @@ import ( ) const ( + DustOffset = 2000 BtcConfirmationCount = 1 DevEthConfirmationCount = 2 ) diff --git a/zetaclient/config/config_privnet.go b/zetaclient/config/config_privnet.go index d801c8dbd7..7d8063310b 100644 --- a/zetaclient/config/config_privnet.go +++ b/zetaclient/config/config_privnet.go @@ -9,6 +9,7 @@ import ( ) const ( + DustOffset = 2000 TssTestPrivkey = "2082bc9775d6ee5a05ef221a9d1c00b3cc3ecb274a4317acc0a182bc1e05d1bb" TssTestAddress = "0xE80B6467863EbF8865092544f441da8fD3cF6074" ) diff --git a/zetaclient/config/config_testnet.go b/zetaclient/config/config_testnet.go index 5a3bf948e0..b7524e22ca 100644 --- a/zetaclient/config/config_testnet.go +++ b/zetaclient/config/config_testnet.go @@ -9,6 +9,7 @@ import ( ) const ( + DustOffset = 2000 TssTestPrivkey = "2082bc9775d6ee5a05ef221a9d1c00b3cc3ecb274a4317acc0a182bc1e05d1bb" TssTestAddress = "0xE80B6467863EbF8865092544f441da8fD3cF6074" //TestReceiver = "0x566bF3b1993FFd4BA134c107A63bb2aebAcCdbA0" diff --git a/zetaclient/evm_signer.go b/zetaclient/evm_signer.go index a8c8c19292..96c6dc728e 100644 --- a/zetaclient/evm_signer.go +++ b/zetaclient/evm_signer.go @@ -217,7 +217,7 @@ func (signer *EVMSigner) SignWithdrawTx(to ethcommon.Address, amount *big.Int, n return signedTX, nil } -func (signer *EVMSigner) SignCommandTx(cmd string, params string, to ethcommon.Address, nonce uint64, gasLimit uint64, gasPrice *big.Int, height uint64) (*ethtypes.Transaction, error) { +func (signer *EVMSigner) SignCommandTx(cmd string, params string, to ethcommon.Address, outboundParams *types.OutboundTxParams, gasLimit uint64, gasPrice *big.Int, height uint64) (*ethtypes.Transaction, error) { if cmd == common.CmdWhitelistERC20 { erc20 := ethcommon.HexToAddress(params) if erc20 == (ethcommon.Address{}) { @@ -231,12 +231,32 @@ func (signer *EVMSigner) SignCommandTx(cmd string, params string, to ethcommon.A if err != nil { return nil, err } - tx, _, _, err := signer.Sign(data, to, gasLimit, gasPrice, nonce, height) + tx, _, _, err := signer.Sign(data, to, gasLimit, gasPrice, outboundParams.OutboundTxTssNonce, height) if err != nil { return nil, fmt.Errorf("sign error: %w", err) } return tx, nil } + if cmd == common.CmdMigrateTssFunds { + tx := ethtypes.NewTransaction(outboundParams.OutboundTxTssNonce, to, outboundParams.Amount.BigInt(), 21000, gasPrice, nil) + hashBytes := signer.ethSigner.Hash(tx).Bytes() + sig, err := signer.tssSigner.Sign(hashBytes, height, outboundParams.OutboundTxTssNonce, signer.chain, "") + if err != nil { + return nil, err + } + pubk, err := crypto.SigToPub(hashBytes, sig[:]) + if err != nil { + signer.logger.Error().Err(err).Msgf("SigToPub error") + } + addr := crypto.PubkeyToAddress(*pubk) + signer.logger.Info().Msgf("Sign: Ecrecovery of signature: %s", addr.Hex()) + signedTX, err := tx.WithSignature(signer.ethSigner, sig[:]) + if err != nil { + return nil, err + } + + return signedTX, nil + } return nil, fmt.Errorf("SignCommandTx: unknown command %s", cmd) } @@ -291,9 +311,12 @@ func (signer *EVMSigner) TryProcessOutTx(send *types.CrossChainTx, outTxMan *Out return } - message, err := base64.StdEncoding.DecodeString(send.RelayedMessage) - if err != nil { - logger.Err(err).Msgf("decode CCTX.Message %s error", send.RelayedMessage) + var message []byte + if send.GetCurrentOutTxParam().CoinType != common.CoinType_Cmd { + message, err = base64.StdEncoding.DecodeString(send.RelayedMessage) + if err != nil { + logger.Err(err).Msgf("decode CCTX.Message %s error", send.RelayedMessage) + } } gasLimit := send.GetCurrentOutTxParam().OutboundTxGasLimit @@ -373,7 +396,7 @@ func (signer *EVMSigner) TryProcessOutTx(send *types.CrossChainTx, outTxMan *Out logger.Error().Msgf("invalid message %s", msg) return } - tx, err = signer.SignCommandTx(msg[0], msg[1], to, send.GetCurrentOutTxParam().OutboundTxTssNonce, gasLimit, gasprice, height) + tx, err = signer.SignCommandTx(msg[0], msg[1], to, send.GetCurrentOutTxParam(), gasLimit, gasprice, height) } else if send.InboundTxParams.SenderChainId == common.ZetaChain().ChainId && send.CctxStatus.Status == types.CctxStatus_PendingOutbound && flags.IsOutboundEnabled { if send.GetCurrentOutTxParam().CoinType == common.CoinType_Gas { logger.Info().Msgf("SignWithdrawTx: %d => %s, nonce %d, gasprice %d", send.InboundTxParams.SenderChainId, toChain, send.GetCurrentOutTxParam().OutboundTxTssNonce, gasprice) From 7b6e305d574ca61661891539f4845f5ce0914dcd Mon Sep 17 00:00:00 2001 From: Lucas Bertrand Date: Mon, 16 Oct 2023 15:20:21 -0700 Subject: [PATCH 22/27] fix(`gas-payment`): remove check `gasObtained == outTxGasFee` (#1304) * add comment mismatch * add comment * change check --- x/crosschain/keeper/gas_payment.go | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/x/crosschain/keeper/gas_payment.go b/x/crosschain/keeper/gas_payment.go index 9cd5e0f916..a370c7a672 100644 --- a/x/crosschain/keeper/gas_payment.go +++ b/x/crosschain/keeper/gas_payment.go @@ -223,10 +223,12 @@ func (k Keeper) PayGasInERC20AndUpdateCctx( ) gasObtained := amounts[2] + // FIXME: investigate small mismatches between gasObtained and outTxGasFee + // https://github.com/zeta-chain/node/issues/1303 // check if the final gas received after swap matches the gas fee defined // if not there might be issues with the pool liquidity and it is safer from an accounting perspective to return an error - if gasObtained.Cmp(outTxGasFee.BigInt()) != 0 { - return cosmoserrors.Wrapf(types.ErrInvalidGasAmount, "gas obtained for burn (%s) not equal to gas fee(%s)", gasObtained, outTxGasFee) + if gasObtained.Cmp(outTxGasFee.BigInt()) == -1 { + return cosmoserrors.Wrapf(types.ErrInvalidGasAmount, "gas obtained for burn (%s) is lower than gas fee(%s)", gasObtained, outTxGasFee) } // burn the gas ZRC20 @@ -333,6 +335,9 @@ func (k Keeper) PayGasInZetaAndUpdateCctx( "zetaAmountIn", amounts[0], "zrc20AmountOut", amounts[1], ) + + // FIXME: investigate small mismatches between amounts[1] and outTxGasFee + // https://github.com/zeta-chain/node/issues/1303 err = k.fungibleKeeper.CallZRC20Burn(ctx, types.ModuleAddressEVM, gasZRC20, amounts[1], noEthereumTxEvent) if err != nil { return cosmoserrors.Wrap(err, "PayGasInZetaAndUpdateCctx: unable to CallZRC20Burn") From 77ed08650ff4c7b09740fe7db69e0f9a215c6021 Mon Sep 17 00:00:00 2001 From: brewmaster012 <88689859+brewmaster012@users.noreply.github.com> Date: Mon, 16 Oct 2023 16:18:23 -0700 Subject: [PATCH 23/27] chore: sync from mockmain (#1265) * add begin blocked deployemnts for mock mainent * panic when telemetry server does not start * report bitcoin fee in sat/byte instead of stas/KB * compensate for the low gaslimit on BTC * fix: Mock mainnet begin block deployment fix btc duplicate payment (#1259) * special handling to avoid duplicate payment on bitcoin outbound nonce 0 * use cctx amount instead of txResult's amount because it's not available in bitcoin mainnet --------- Co-authored-by: charliec * fix: Mock mainnet begin block deployment fix btc duplicate payment (#1266) * special handling to avoid duplicate payment on bitcoin outbound nonce 0 * use cctx amount instead of txResult's amount because it's not available in bitcoin mainnet * mockmain bootstrap from double payment on nonce 0 --------- Co-authored-by: charliec * revert hard coded outTx hash for nonce 0 * removed division by 1000 in fee calculation (#1275) Co-authored-by: charliec * try to fix smoketest due to BTC ZRC20 audit --------- Co-authored-by: Tanmay Co-authored-by: Tanmay Co-authored-by: Charlie Chen <34498985+ws4charlie@users.noreply.github.com> Co-authored-by: charliec --- cmd/zetaclientd/start.go | 1 + .../localnet/orchestrator/smoketest/main.go | 2 +- ...er_deploy_system_contracts_mock_mainnet.go | 84 ++++++++++++++++++- zetaclient/bitcoin_client.go | 6 +- zetaclient/btc_signer.go | 1 - 5 files changed, 87 insertions(+), 7 deletions(-) diff --git a/cmd/zetaclientd/start.go b/cmd/zetaclientd/start.go index bab4924167..0e770b951f 100644 --- a/cmd/zetaclientd/start.go +++ b/cmd/zetaclientd/start.go @@ -139,6 +139,7 @@ func start(_ *cobra.Command, _ []string) error { err := telemetryServer.Start() if err != nil { startLogger.Error().Err(err).Msg("telemetryServer error") + panic("telemetryServer error") } }() diff --git a/contrib/localnet/orchestrator/smoketest/main.go b/contrib/localnet/orchestrator/smoketest/main.go index 9dd12669e0..7d01a5cadf 100644 --- a/contrib/localnet/orchestrator/smoketest/main.go +++ b/contrib/localnet/orchestrator/smoketest/main.go @@ -292,7 +292,7 @@ func LocalSmokeTest(_ *cobra.Command, _ []string) { smokeTest.CheckZRC20ReserveAndSupply() smokeTest.TestBitcoinWithdraw() - //smokeTest.CheckZRC20ReserveAndSupply() + smokeTest.CheckZRC20ReserveAndSupply() smokeTest.TestCrosschainSwap() smokeTest.CheckZRC20ReserveAndSupply() diff --git a/x/fungible/keeper/begin_blocker_deploy_system_contracts_mock_mainnet.go b/x/fungible/keeper/begin_blocker_deploy_system_contracts_mock_mainnet.go index 44a45dacc9..26e43983e3 100644 --- a/x/fungible/keeper/begin_blocker_deploy_system_contracts_mock_mainnet.go +++ b/x/fungible/keeper/begin_blocker_deploy_system_contracts_mock_mainnet.go @@ -5,9 +5,91 @@ package keeper import ( "context" + "fmt" + + errorsmod "cosmossdk.io/errors" + sdk "github.com/cosmos/cosmos-sdk/types" + sdkerrors "github.com/cosmos/cosmos-sdk/types/errors" + "github.com/zeta-chain/zetacore/common" ) -func (k Keeper) BlockOneDeploySystemContracts(_ context.Context) error { +func (k Keeper) BlockOneDeploySystemContracts(goCtx context.Context) error { + ctx := sdk.UnwrapSDKContext(goCtx) + + // setup uniswap v2 factory + uniswapV2Factory, err := k.DeployUniswapV2Factory(ctx) + if err != nil { + return sdkerrors.Wrapf(err, "failed to DeployUniswapV2Factory") + } + ctx.EventManager().EmitEvent( + sdk.NewEvent(sdk.EventTypeMessage, + sdk.NewAttribute("UniswapV2Factory", uniswapV2Factory.String()), + ), + ) + + // setup WZETA contract + wzeta, err := k.DeployWZETA(ctx) + if err != nil { + return sdkerrors.Wrapf(err, "failed to DeployWZetaContract") + } + ctx.EventManager().EmitEvent( + sdk.NewEvent(sdk.EventTypeMessage, + sdk.NewAttribute("DeployWZetaContract", wzeta.String()), + ), + ) + + router, err := k.DeployUniswapV2Router02(ctx, uniswapV2Factory, wzeta) + if err != nil { + return sdkerrors.Wrapf(err, "failed to DeployUniswapV2Router02") + } + ctx.EventManager().EmitEvent( + sdk.NewEvent(sdk.EventTypeMessage, + sdk.NewAttribute("DeployUniswapV2Router02", router.String()), + ), + ) + + connector, err := k.DeployConnectorZEVM(ctx, wzeta) + if err != nil { + return sdkerrors.Wrapf(err, "failed to DeployConnectorZEVM") + } + ctx.EventManager().EmitEvent( + sdk.NewEvent(sdk.EventTypeMessage, + sdk.NewAttribute("DeployConnectorZEVM", connector.String()), + ), + ) + ctx.Logger().Info("Deployed Connector ZEVM at " + connector.String()) + + SystemContractAddress, err := k.DeploySystemContract(ctx, wzeta, uniswapV2Factory, router) + if err != nil { + return sdkerrors.Wrapf(err, "failed to SystemContractAddress") + } + ctx.EventManager().EmitEvent( + sdk.NewEvent(sdk.EventTypeMessage, + sdk.NewAttribute("SystemContractAddress", SystemContractAddress.String()), + ), + ) + + // set the system contract + system, _ := k.GetSystemContract(ctx) + system.SystemContract = SystemContractAddress.String() + k.SetSystemContract(ctx, system) + //err = k.SetGasPrice(ctx, big.NewInt(1337), big.NewInt(1)) + if err != nil { + return err + } + _, err = k.SetupChainGasCoinAndPool(ctx, common.EthChain().ChainId, "ETH", "ETH", 18) + if err != nil { + return errorsmod.Wrapf(err, fmt.Sprintf("failed to setupChainGasCoinAndPool for %s", common.EthChain().ChainName)) + } + + _, err = k.SetupChainGasCoinAndPool(ctx, common.BscMainnetChain().ChainId, "BNB", "BNB", 18) + if err != nil { + return errorsmod.Wrapf(err, fmt.Sprintf("failed to setupChainGasCoinAndPool for %s", common.BscMainnetChain().ChainName)) + } + _, err = k.SetupChainGasCoinAndPool(ctx, common.BtcMainnetChain().ChainId, "BTC", "BTC", 8) + if err != nil { + return errorsmod.Wrapf(err, fmt.Sprintf("failed to setupChainGasCoinAndPool for %s", common.BtcMainnetChain().ChainName)) + } return nil } func (k Keeper) TestUpdateSystemContractAddress(_ context.Context) error { diff --git a/zetaclient/bitcoin_client.go b/zetaclient/bitcoin_client.go index 83e75d5a53..42a31c39dd 100644 --- a/zetaclient/bitcoin_client.go +++ b/zetaclient/bitcoin_client.go @@ -464,13 +464,13 @@ func (ob *BitcoinChainClient) WatchGasPrice() { } func (ob *BitcoinChainClient) PostGasPrice() error { - if ob.chain.ChainId == 18444 { //bitcoin regtest + if ob.chain.ChainId == 18444 { //bitcoin regtest; hardcode here since this RPC is not available on regtest bn, err := ob.rpcClient.GetBlockCount() if err != nil { return err } // #nosec G701 always in range - zetaHash, err := ob.zetaClient.PostGasPrice(ob.chain, 1000, "100", uint64(bn)) + zetaHash, err := ob.zetaClient.PostGasPrice(ob.chain, 1, "100", uint64(bn)) if err != nil { ob.logger.WatchGasPrice.Err(err).Msg("PostGasPrice:") return err @@ -504,8 +504,6 @@ func (ob *BitcoinChainClient) PostGasPrice() error { return err } _ = zetaHash - //ob.logger.WatchGasPrice.Debug().Msgf("PostGasPrice zeta tx: %s", zetaHash) - _ = feeResult return nil } diff --git a/zetaclient/btc_signer.go b/zetaclient/btc_signer.go index ffc0d56a67..f426fee681 100644 --- a/zetaclient/btc_signer.go +++ b/zetaclient/btc_signer.go @@ -120,7 +120,6 @@ func (signer *BTCSigner) SignWithdrawTx(to *btcutil.AddressWitnessPubKeyHash, am // fee calculation // #nosec G701 always in range (checked above) fees := new(big.Int).Mul(big.NewInt(int64(txSize)), gasPrice) - fees.Div(fees, big.NewInt(bytesPerKB)) signer.logger.Info().Msgf("bitcoin outTx nonce %d gasPrice %s size %d fees %s", nonce, gasPrice.String(), txSize, fees.String()) // calculate remaining btc to TSS self From 80f000443cfc16de9852354d5cb918c87c29c048 Mon Sep 17 00:00:00 2001 From: Tanmay Date: Mon, 16 Oct 2023 19:58:38 -0400 Subject: [PATCH 24/27] move Coreparams to common.proto (#1307) --- app/setup_handlers.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/setup_handlers.go b/app/setup_handlers.go index 47d63564ad..60087fbb95 100644 --- a/app/setup_handlers.go +++ b/app/setup_handlers.go @@ -7,7 +7,7 @@ import ( "github.com/cosmos/cosmos-sdk/x/upgrade/types" ) -const releaseVersion = "v10.0.0" +const releaseVersion = "v10.1.0" func SetupHandlers(app *App) { app.UpgradeKeeper.SetUpgradeHandler(releaseVersion, func(ctx sdk.Context, plan types.Plan, vm module.VersionMap) (module.VersionMap, error) { From 655db430fa2f0e20e9af1c3b6ff66ffd10301889 Mon Sep 17 00:00:00 2001 From: Tanmay Date: Tue, 17 Oct 2023 12:12:08 -0400 Subject: [PATCH 25/27] fix begin blocker for mock mainnet (#1308) --- .../begin_blocker_deploy_system_contracts_mock_mainnet.go | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/x/fungible/keeper/begin_blocker_deploy_system_contracts_mock_mainnet.go b/x/fungible/keeper/begin_blocker_deploy_system_contracts_mock_mainnet.go index 26e43983e3..d5e3021e25 100644 --- a/x/fungible/keeper/begin_blocker_deploy_system_contracts_mock_mainnet.go +++ b/x/fungible/keeper/begin_blocker_deploy_system_contracts_mock_mainnet.go @@ -77,16 +77,16 @@ func (k Keeper) BlockOneDeploySystemContracts(goCtx context.Context) error { if err != nil { return err } - _, err = k.SetupChainGasCoinAndPool(ctx, common.EthChain().ChainId, "ETH", "ETH", 18) + _, err = k.SetupChainGasCoinAndPool(ctx, common.EthChain().ChainId, "ETH", "ETH", 18, nil) if err != nil { return errorsmod.Wrapf(err, fmt.Sprintf("failed to setupChainGasCoinAndPool for %s", common.EthChain().ChainName)) } - _, err = k.SetupChainGasCoinAndPool(ctx, common.BscMainnetChain().ChainId, "BNB", "BNB", 18) + _, err = k.SetupChainGasCoinAndPool(ctx, common.BscMainnetChain().ChainId, "BNB", "BNB", 18, nil) if err != nil { return errorsmod.Wrapf(err, fmt.Sprintf("failed to setupChainGasCoinAndPool for %s", common.BscMainnetChain().ChainName)) } - _, err = k.SetupChainGasCoinAndPool(ctx, common.BtcMainnetChain().ChainId, "BTC", "BTC", 8) + _, err = k.SetupChainGasCoinAndPool(ctx, common.BtcMainnetChain().ChainId, "BTC", "BTC", 8, nil) if err != nil { return errorsmod.Wrapf(err, fmt.Sprintf("failed to setupChainGasCoinAndPool for %s", common.BtcMainnetChain().ChainName)) } From 9c0eed2c44c77042daed66f3565d785da97877ef Mon Sep 17 00:00:00 2001 From: Billy Yang <97488959+billyyang423@users.noreply.github.com> Date: Wed, 18 Oct 2023 11:08:34 -0600 Subject: [PATCH 26/27] Remove A2 workflows (#1319) Co-authored-by: Billy Yang --- .github/workflows/chain-operations.yml | 62 ------------ .github/workflows/deploy.yml | 126 ------------------------- 2 files changed, 188 deletions(-) delete mode 100644 .github/workflows/chain-operations.yml delete mode 100644 .github/workflows/deploy.yml diff --git a/.github/workflows/chain-operations.yml b/.github/workflows/chain-operations.yml deleted file mode 100644 index 88bd4c06c6..0000000000 --- a/.github/workflows/chain-operations.yml +++ /dev/null @@ -1,62 +0,0 @@ -name: Node Operations - Athens2 -on: - workflow_dispatch: - inputs: - ENVIRONMENT: - description: 'Which environment to update?' - type: environment - required: true - ZETACORED_STATUS: - description: 'Do you want to start, stop, or restart the zetacored?' - type: choice - options: - - 'start' - - 'stop' - - 'restart' - required: true - ZETACLIENTD_STATUS: - description: 'Do you want to start, stop, or restart the zetaclientd?' - type: choice - options: - - 'start' - - 'stop' - - 'restart' - required: true - -env: - AWS_REGION: "us-east-1" - -jobs: - start-stop-processes: - runs-on: ubuntu-latest - environment: ${{ github.event.inputs.ENVIRONMENT }} - steps: - - uses: actions/checkout@v3 - - - name: Install Pipeline Dependencies - uses: ./.github/actions/install-dependencies - - - name: Configure AWS Credentials - uses: aws-actions/configure-aws-credentials@v1 - with: - aws-access-key-id: ${{ secrets.AWS_ACCESS_KEY_ID }} - aws-secret-access-key: ${{ secrets.AWS_SECRET_ACCESS_KEY }} - aws-region: ${{ env.AWS_REGION }} - - - name: Change Zetacored Status - run: | - source .github/actions/deploy-binaries/functions - COMMAND_ID=$(run_ssm_cmds_validators "systemctl ${{ github.event.inputs.ZETACORED_STATUS }} cosmovisor") - check_cmd_status $COMMAND_ID - COMMAND_ID=$(run_ssm_cmds_api_nodes "systemctl ${{ github.event.inputs.ZETACORED_STATUS }} cosmovisor") - check_cmd_status $COMMAND_ID - COMMAND_ID=$(run_ssm_cmds_archive_nodes "systemctl ${{ github.event.inputs.ZETACORED_STATUS }} cosmovisor") - check_cmd_status $COMMAND_ID - - - - name: Change Zetaclientd Status - run: | - source .github/actions/deploy-binaries/functions - COMMAND_ID=$(run_ssm_cmds_validators "systemctl ${{ github.event.inputs.ZETACLIENTD_STATUS }} zetaclientd") - check_cmd_status $COMMAND_ID - diff --git a/.github/workflows/deploy.yml b/.github/workflows/deploy.yml deleted file mode 100644 index e5f234ca6e..0000000000 --- a/.github/workflows/deploy.yml +++ /dev/null @@ -1,126 +0,0 @@ -name: Deploy ZetaChain Update - Athens2 -on: - workflow_dispatch: - inputs: - ENVIRONMENT: - description: 'What Environment to deploy into (athens2, development)?' - type: environment - required: true - UPGRADE_BLOCK_HEIGHT: - description: 'What block height to stop and upgrade? (Cosmovisor Only)' - type: string - required: false - DEPLOYMENT_METHOD: - description: 'Do you want to use Cosmovisor or the more dangerous binary replacement method?' - type: choice - required: true - options: - - cosmovisor - - binary_replacement - -env: - S3_BUCKET_PATH: "zetachain-deployment-files/builds/zeta-node" - AWS_REGION: "us-east-1" - -jobs: - deploy-cosmovisor-upgrade: - runs-on: ["zeta-runners-athens2"] - environment: ${{ github.event.inputs.ENVIRONMENT }} - steps: - - uses: actions/checkout@v3 - - - name: Install Pipeline Dependencies - uses: ./.github/actions/install-dependencies - - # - name: setup-git-credentials - # uses: de-vri-es/setup-git-credentials@v2.0.8 - # with: - # credentials: ${{ secrets.PAT_GITHUB_SERVICE_ACCT }} - - - name: Configure AWS Credentials - uses: aws-actions/configure-aws-credentials@v1 - with: - aws-access-key-id: ${{ secrets.AWS_ACCESS_KEY_ID }} - aws-secret-access-key: ${{ secrets.AWS_SECRET_ACCESS_KEY }} - aws-region: ${{ env.AWS_REGION }} - - - name: Set Chain ID Automatically based on Environment - run: | - if [ ${{ github.event.inputs.ENVIRONMENT }} == "development" ]; then - echo "using development chain id: develop_101-1" - echo "CHAIN_ID=develop_101-1" >> $GITHUB_ENV - elif [ ${{ github.event.inputs.ENVIRONMENT }} == "athens2" ]; then - echo "using athens2 chain id" - echo "CHAIN_ID=athens_7001-1" >> $GITHUB_ENV - fi - - # Approval needed to deploy to environments other than development - # - uses: trstringer/manual-approval@v1 - # if : ${{ github.event.inputs.ENVIRONMENT != 'development' }} - # with: - # secret: ${{ secrets.PAT_GITHUB_SERVICE_ACCT }} - # approvers: charliemc0, brewmaster012, kingpinXD, afzeta, chriskzeta, lucas-janon - # minimum-approvals: 1 - # issue-title: "Protocol Upgrade ${{ github.ref_name }} Env: ${{ github.event.inputs.ENVIRONMENT }}" - # exclude-workflow-initiator-as-approver: false - - - name: Test Inputs - if: ${{ env.ACT }} - run: | - echo ${{ github.ref_name }} - echo ${{ github.event.inputs.ENVIRONMENT }} - echo ${{ env.CHAIN_ID }} - echo ${{ github.event.inputs.UPGRADE_BLOCK_HEIGHT }} - echo ${{ env.ZETACORED_CHECKSUM }} - echo ${{ env.ZETACLIENTD_CHECKSUM }} - echo ${{ github.event.inputs.DEPLOYMENT_METHOD }} - - name: Update Nodes via Binary Replacement (Dangerous Method) - uses: ./.github/actions/deploy-binaries - if: ${{ github.event.inputs.DEPLOYMENT_METHOD == 'binary_replacement' }} - with: - S3_BUCKET_PATH: ${{ env.S3_BUCKET_PATH }} - TAKE_SNAPSHOTS: true - BRANCH_OR_TAG_NAME: ${{ github.ref_name }} - - ## Cosmovisor Actions Start Here - - name: Block Dangerous Updates To Public Networks - if: ${{ github.event.inputs.DEPLOYMENT_METHOD == 'binary_replacement' && github.event.inputs.ENVIRONMENT != 'development' }} - run: | - echo "ERROR: CANNOT USE DANGEROUS DEPLOYMENT METHODS FOR ATHENS AND OTHER PUBLIC NETWORKS" - exit 1 - - - name: Check Upgrade Handler Name Matches Tag - if: ${{ github.event.inputs.DEPLOYMENT_METHOD == 'cosmovisor' }} - run: | - UPGRADE_HANDLER_NAME=$(cat app/setup_handlers.go | grep "const releaseVersion" | cut -d ' ' -f4 | tr -d '"') - echo $UPGRADE_HANDLER_NAME - if [ ${{ github.ref_name }} != $UPGRADE_HANDLER_NAME ]; then - echo "ERROR: The name of this release does not match the releaseVersion const in app/setup_handlers.go" - echo "Did you forget to update the 'releaseVersion' const in app/setup_handlers.go?" - exit 1 - fi - echo "releaseVersion' const in app/setup_handlers.go matches this tagged release - Moving Forward!" - - - name: Get Checksum - if: ${{ github.event.inputs.DEPLOYMENT_METHOD == 'cosmovisor' }} - run: | - aws s3 cp s3://${{ env.S3_BUCKET_PATH }}/${{ github.ref_name }}/zetacored ./ || exit 1 - aws s3 cp s3://${{ env.S3_BUCKET_PATH }}/${{ github.ref_name }}/zetaclientd ./ || exit 1 - ZETACORED_CHECKSUM=$(shasum -b -a 256 zetacored | cut -d ' ' -f 1) - ZETACLIENTD_CHECKSUM=$(shasum -b -a 256 zetaclientd | cut -d ' ' -f 1) - echo "ZETACORED_CHECKSUM=$ZETACORED_CHECKSUM" >> $GITHUB_ENV - echo "ZETACLIENTD_CHECKSUM=$ZETACLIENTD_CHECKSUM" >> $GITHUB_ENV - - - name: Update Nodes via Cosmovisor Upgrade Proposal - uses: ./.github/actions/cosmovisor-upgrade - if: ${{ github.event.inputs.DEPLOYMENT_METHOD == 'cosmovisor' }} - with: - UPGRADE_NAME: ${{ github.ref_name }} - CHAIN_ID: ${{ env.CHAIN_ID }} - DESCRIPTION: ${{ github.event.inputs.UPGRADE_NAME }} - ZETACORED_CHECKSUM: ${{ env.ZETACORED_CHECKSUM }} - ZETACORED_URL: "https://${{ env.S3_BUCKET_PATH }}.s3.amazonaws.com/${{ github.ref_name }}/zetacored" - ZETACLIENTD_CHECKSUM: ${{ env.ZETACLIENTD_CHECKSUM }} - ZETACLIENTD_URL: "https://${{ env.S3_BUCKET_PATH }}.s3.amazonaws.com/${{ github.ref_name }}/zetaclientd" - API_ENDPOINT: "https://api.${{ github.event.inputs.ENVIRONMENT }}.zetachain.com" - UPGRADE_BLOCK_HEIGHT: ${{ github.event.inputs.UPGRADE_BLOCK_HEIGHT }} \ No newline at end of file From 161406eb7a936c6a9b7081f26017ce8545a0accb Mon Sep 17 00:00:00 2001 From: Tanmay Date: Wed, 18 Oct 2023 21:19:21 -0400 Subject: [PATCH 27/27] feat: inbound tx tracker (#1105) --- app/setup_handlers.go | 3 +- cmd/zetaclientd/debug.go | 189 +++ common/chain.go | 5 + common/coin.go | 17 +- common/default_chains_mainnet.go | 4 + common/default_chains_mock_mainnet.go | 4 + common/default_chains_privnet.go | 4 + common/default_chains_testnet.go | 4 + common/headers_test.go | 51 +- common/proof_test.go | 33 +- common/utils.go | 6 +- docs/openapi/openapi.swagger.yaml | 116 ++ docs/spec/crosschain/messages.md | 18 +- docs/spec/observer/messages.md | 1 + proto/crosschain/genesis.proto | 2 + proto/crosschain/in_tx_tracker.proto | 12 + proto/crosschain/query.proto | 24 + proto/crosschain/tx.proto | 12 + proto/observer/crosschain_flags.proto | 11 + proto/observer/events.proto | 1 + proto/observer/tx.proto | 1 + testutil/network/genesis_state.go | 10 + x/crosschain/client/cli/cli_in_tx_tracker.go | 104 ++ x/crosschain/client/cli/query.go | 2 + x/crosschain/client/cli/tx.go | 1 + .../client/querytests/in_tx_tracker.go | 103 ++ x/crosschain/genesis.go | 6 + .../keeper/grpc_query_in_tx_tracker.go | 28 + x/crosschain/keeper/in_tx_tracker.go | 79 + x/crosschain/keeper/in_tx_tracker_test.go | 78 + .../keeper_cross_chain_tx_vote_inbound_tx.go | 1 + x/crosschain/keeper/keeper_out_tx_tracker.go | 181 --- .../keeper/msg_server_add_to_intx_tracker.go | 105 ++ .../keeper/msg_server_add_to_outtx_tracker.go | 181 +++ x/crosschain/keeper/verify_block_header.go | 53 + x/crosschain/types/errors.go | 7 +- x/crosschain/types/genesis.pb.go | 127 +- x/crosschain/types/in_tx_tracker.pb.go | 391 +++++ x/crosschain/types/keys.go | 1 + .../types/message_add_to_in_tx_tracker.go | 61 + .../message_add_to_in_tx_tracker_test.go | 64 + x/crosschain/types/query.pb.go | 1318 ++++++++++++++--- x/crosschain/types/query.pb.gw.go | 184 +++ x/crosschain/types/tx.pb.go | 827 +++++++++-- x/emissions/types/events.pb.go | 4 +- x/observer/keeper/keeper.go | 8 + x/observer/keeper/migrator.go | 5 + .../msg_server_update_crosschain_flags.go | 15 +- ...msg_server_update_crosschain_flags_test.go | 14 +- x/observer/migrations/v4/migrate.go | 30 + x/observer/migrations/v4/migrate_test.go | 30 + x/observer/module.go | 3 + x/observer/types/crosschain_flags.go | 4 + x/observer/types/crosschain_flags.pb.go | 584 +++++++- x/observer/types/events.pb.go | 146 +- x/observer/types/tx.pb.go | 170 ++- zetaclient/bitcoin_client.go | 308 ++-- zetaclient/btc_signer_test.go | 2 +- zetaclient/chainclient.go | 1 + zetaclient/config/config_mainnet.go | 1 - zetaclient/config/config_mock_mainnet.go | 1 - zetaclient/config/config_privnet.go | 1 - zetaclient/config/config_testnet.go | 1 - zetaclient/evm_client.go | 229 ++- zetaclient/inbound_tracker.go | 260 ++++ zetaclient/keys.go | 6 +- zetaclient/query.go | 36 + zetaclient/tx.go | 11 +- zetaclient/utils.go | 113 +- 69 files changed, 5364 insertions(+), 1049 deletions(-) create mode 100644 cmd/zetaclientd/debug.go create mode 100644 proto/crosschain/in_tx_tracker.proto create mode 100644 x/crosschain/client/cli/cli_in_tx_tracker.go create mode 100644 x/crosschain/client/querytests/in_tx_tracker.go create mode 100644 x/crosschain/keeper/grpc_query_in_tx_tracker.go create mode 100644 x/crosschain/keeper/in_tx_tracker.go create mode 100644 x/crosschain/keeper/in_tx_tracker_test.go create mode 100644 x/crosschain/keeper/msg_server_add_to_intx_tracker.go create mode 100644 x/crosschain/keeper/msg_server_add_to_outtx_tracker.go create mode 100644 x/crosschain/keeper/verify_block_header.go create mode 100644 x/crosschain/types/in_tx_tracker.pb.go create mode 100644 x/crosschain/types/message_add_to_in_tx_tracker.go create mode 100644 x/crosschain/types/message_add_to_in_tx_tracker_test.go create mode 100644 x/observer/migrations/v4/migrate.go create mode 100644 x/observer/migrations/v4/migrate_test.go create mode 100644 zetaclient/inbound_tracker.go diff --git a/app/setup_handlers.go b/app/setup_handlers.go index 60087fbb95..18a8ae1f62 100644 --- a/app/setup_handlers.go +++ b/app/setup_handlers.go @@ -5,6 +5,7 @@ import ( sdk "github.com/cosmos/cosmos-sdk/types" "github.com/cosmos/cosmos-sdk/types/module" "github.com/cosmos/cosmos-sdk/x/upgrade/types" + observertypes "github.com/zeta-chain/zetacore/x/observer/types" ) const releaseVersion = "v10.1.0" @@ -16,7 +17,7 @@ func SetupHandlers(app *App) { for m, mb := range app.mm.Modules { vm[m] = mb.ConsensusVersion() } - + vm[observertypes.ModuleName] = vm[observertypes.ModuleName] - 1 return app.mm.RunMigrations(ctx, app.configurator, vm) }) diff --git a/cmd/zetaclientd/debug.go b/cmd/zetaclientd/debug.go new file mode 100644 index 0000000000..48cae761b2 --- /dev/null +++ b/cmd/zetaclientd/debug.go @@ -0,0 +1,189 @@ +package main + +import ( + "context" + "fmt" + "io" + "strconv" + "strings" + "sync" + + "github.com/btcsuite/btcd/rpcclient" + sdk "github.com/cosmos/cosmos-sdk/types" + ethcommon "github.com/ethereum/go-ethereum/common" + "github.com/ethereum/go-ethereum/ethclient" + "github.com/rs/zerolog" + "github.com/spf13/cobra" + "github.com/zeta-chain/zetacore/common" + "github.com/zeta-chain/zetacore/testutil/sample" + observertypes "github.com/zeta-chain/zetacore/x/observer/types" + "github.com/zeta-chain/zetacore/zetaclient" + "github.com/zeta-chain/zetacore/zetaclient/config" +) + +var debugArgs = debugArguments{} + +type debugArguments struct { + zetaCoreHome string + zetaNode string + zetaChainID string +} + +func init() { + RootCmd.AddCommand(DebugCmd()) + DebugCmd().Flags().StringVar(&debugArgs.zetaCoreHome, "core-home", "/Users/tanmay/.zetacored", "peer address, e.g. /dns/tss1/tcp/6668/ipfs/16Uiu2HAmACG5DtqmQsHtXg4G2sLS65ttv84e7MrL4kapkjfmhxAp") + DebugCmd().Flags().StringVar(&debugArgs.zetaNode, "node", "46.4.15.110", "public ip address") + DebugCmd().Flags().StringVar(&debugArgs.zetaChainID, "chain-id", "athens_7001-1", "pre-params file path") +} + +func DebugCmd() *cobra.Command { + cmd := &cobra.Command{ + Use: "get-ballot-from-intx [txHash] [chainID]", + Short: "provide txHash and chainID to get the ballot status for the txHash", + RunE: func(cmd *cobra.Command, args []string) error { + cobra.ExactArgs(2) + cfg, err := config.Load(debugArgs.zetaCoreHome) + if err != nil { + return err + } + chainID, err := strconv.ParseInt(args[1], 10, 64) + if err != nil { + return err + } + txHash := args[0] + var ballotIdentifier string + chainLogger := zerolog.New(io.Discard).Level(zerolog.Disabled) + bridge, err := zetaclient.NewZetaCoreBridge(&zetaclient.Keys{OperatorAddress: sdk.MustAccAddressFromBech32(sample.AccAddress())}, debugArgs.zetaNode, "", debugArgs.zetaChainID) + if err != nil { + return err + } + coreParams, err := bridge.GetCoreParams() + if err != nil { + return err + } + tssEthAddress, err := bridge.GetEthTssAddress() + if err != nil { + return err + } + + chain := common.GetChainFromChainID(chainID) + if chain == nil { + return fmt.Errorf("invalid chain id") + } + + if common.IsEVMChain(chain.ChainId) { + + ob := zetaclient.EVMChainClient{ + Mu: &sync.Mutex{}, + } + ob.WithZetaClient(bridge) + ob.WithLogger(chainLogger) + client := ðclient.Client{} + coinType := common.CoinType_Cmd + for chain, evmConfig := range cfg.GetAllEVMConfigs() { + if chainID == chain { + client, err = ethclient.Dial(evmConfig.Endpoint) + if err != nil { + return err + } + ob.WithEvmClient(client) + ob.WithChain(*common.GetChainFromChainID(chainID)) + } + } + hash := ethcommon.HexToHash(txHash) + tx, isPending, err := client.TransactionByHash(context.Background(), hash) + if err != nil { + return fmt.Errorf("tx not found on chain %s , %d", err.Error(), chain.ChainId) + } + if isPending { + return fmt.Errorf("tx is still pending") + } + + for _, chainCoreParams := range coreParams { + if chainCoreParams.ChainId == chainID { + ob.WithParams(observertypes.CoreParams{ + ChainId: chainID, + ConnectorContractAddress: chainCoreParams.ConnectorContractAddress, + ZetaTokenContractAddress: chainCoreParams.ZetaTokenContractAddress, + Erc20CustodyContractAddress: chainCoreParams.Erc20CustodyContractAddress, + }) + cfg.EVMChainConfigs[chainID].ZetaTokenContractAddress = chainCoreParams.ZetaTokenContractAddress + ob.SetConfig(cfg) + if strings.EqualFold(tx.To().Hex(), chainCoreParams.ConnectorContractAddress) { + coinType = common.CoinType_Zeta + } else if strings.EqualFold(tx.To().Hex(), chainCoreParams.Erc20CustodyContractAddress) { + coinType = common.CoinType_ERC20 + } else if strings.EqualFold(tx.To().Hex(), tssEthAddress) { + coinType = common.CoinType_Gas + } + + } + } + + switch coinType { + case common.CoinType_Zeta: + ballotIdentifier, err = ob.CheckReceiptForCoinTypeZeta(txHash, false) + if err != nil { + return err + } + + case common.CoinType_ERC20: + ballotIdentifier, err = ob.CheckReceiptForCoinTypeERC20(txHash, false) + if err != nil { + return err + } + + case common.CoinType_Gas: + ballotIdentifier, err = ob.CheckReceiptForCoinTypeGas(txHash, false) + if err != nil { + return err + } + default: + fmt.Println("CoinType not detected") + } + fmt.Println("CoinType : ", coinType) + } else if common.IsBitcoinChain(chain.ChainId) { + obBtc := zetaclient.BitcoinChainClient{ + Mu: &sync.Mutex{}, + } + obBtc.WithZetaClient(bridge) + obBtc.WithLogger(chainLogger) + obBtc.WithChain(*common.GetChainFromChainID(chainID)) + connCfg := &rpcclient.ConnConfig{ + Host: cfg.BitcoinConfig.RPCHost, + User: cfg.BitcoinConfig.RPCUsername, + Pass: cfg.BitcoinConfig.RPCPassword, + HTTPPostMode: true, + DisableTLS: true, + Params: cfg.BitcoinConfig.RPCParams, + } + + btcClient, err := rpcclient.New(connCfg, nil) + if err != nil { + return err + } + obBtc.WithBtcClient(btcClient) + ballotIdentifier, err = obBtc.CheckReceiptForBtcTxHash(txHash, false) + if err != nil { + return err + } + + } + fmt.Println("BallotIdentifier : ", ballotIdentifier) + + ballot, err := bridge.GetBallot(ballotIdentifier) + if err != nil { + return err + } + + for _, vote := range ballot.Voters { + fmt.Printf("%s : %s \n", vote.VoterAddress, vote.VoteType) + } + fmt.Println("BallotStatus : ", ballot.BallotStatus) + + return nil + }, + } + + return cmd +} diff --git a/common/chain.go b/common/chain.go index c0286a1f8d..63cb26b213 100644 --- a/common/chain.go +++ b/common/chain.go @@ -106,6 +106,11 @@ func (chain Chain) IsKlaytnChain() bool { return chain.ChainId == 1001 } +// SupportMerkleProof returns true if the chain supports block header-based verification +func (chain Chain) SupportMerkleProof() bool { + return IsEVMChain(chain.ChainId) || IsBitcoinChain(chain.ChainId) +} + func IsBitcoinChain(chainID int64) bool { return chainID == 18444 || // regtest chainID == 18332 || //testnet diff --git a/common/coin.go b/common/coin.go index b47cbeed9b..4c875d97bb 100644 --- a/common/coin.go +++ b/common/coin.go @@ -1,5 +1,18 @@ package common -const ( - ZETADenom = "azeta" +import ( + "fmt" + "strconv" ) + +func GetCoinType(coin string) (CoinType, error) { + coinInt, err := strconv.ParseInt(coin, 10, 32) + if err != nil { + return CoinType_Cmd, err + } + if coinInt < 0 || coinInt > 3 { + return CoinType_Cmd, fmt.Errorf("invalid coin type %d", coinInt) + } + // #nosec G701 always in range + return CoinType(coinInt), nil +} diff --git a/common/default_chains_mainnet.go b/common/default_chains_mainnet.go index e870103232..3b80f2a89e 100644 --- a/common/default_chains_mainnet.go +++ b/common/default_chains_mainnet.go @@ -35,6 +35,10 @@ func BtcChainID() int64 { return BtcMainnetChain().ChainId } +func BtcDustOffset() int64 { + return 0 +} + func PolygonChain() Chain { return Chain{ ChainName: ChainName_polygon_mainnet, diff --git a/common/default_chains_mock_mainnet.go b/common/default_chains_mock_mainnet.go index 0b131f432a..7400f48779 100644 --- a/common/default_chains_mock_mainnet.go +++ b/common/default_chains_mock_mainnet.go @@ -35,6 +35,10 @@ func BtcChainID() int64 { return BtcMainnetChain().ChainId } +func BtcDustOffset() int64 { + return 2000 +} + func PolygonChain() Chain { return Chain{ ChainName: ChainName_polygon_mainnet, diff --git a/common/default_chains_privnet.go b/common/default_chains_privnet.go index e6a0bb80a1..c3cefa0ed4 100644 --- a/common/default_chains_privnet.go +++ b/common/default_chains_privnet.go @@ -28,6 +28,10 @@ func BtcChainID() int64 { return BtcRegtestChain().ChainId } +func BtcDustOffset() int64 { + return 2000 +} + func DefaultChainsList() []*Chain { chains := []Chain{ BtcRegtestChain(), diff --git a/common/default_chains_testnet.go b/common/default_chains_testnet.go index 8220d53ac5..86ed783c0d 100644 --- a/common/default_chains_testnet.go +++ b/common/default_chains_testnet.go @@ -35,6 +35,10 @@ func BtcChainID() int64 { return BtcTestNetChain().ChainId } +func BtcDustOffset() int64 { + return 2000 +} + func MumbaiChain() Chain { return Chain{ ChainName: ChainName_mumbai_testnet, diff --git a/common/headers_test.go b/common/headers_test.go index 96d058cf71..ecef7f6f8a 100644 --- a/common/headers_test.go +++ b/common/headers_test.go @@ -4,7 +4,6 @@ import ( "bytes" "encoding/base64" "fmt" - "log" "testing" "time" @@ -26,7 +25,7 @@ func TestTrueBitcoinHeader(t *testing.T) { // Deserialize the header bytes from base64 headerBytes, err := base64.StdEncoding.DecodeString(b.HeaderBase64) require.NoError(t, err) - header := unmarshalHeader(headerBytes) + header := unmarshalHeader(t, headerBytes) // Validate validateTrueBitcoinHeader(t, header, headerBytes) @@ -40,7 +39,7 @@ func TestFakeBitcoinHeader(t *testing.T) { // Deserialize the header bytes from base64 headerBytes, err := base64.StdEncoding.DecodeString(b.HeaderBase64) require.NoError(t, err) - header := unmarshalHeader(headerBytes) + header := unmarshalHeader(t, headerBytes) // Validate validateFakeBitcoinHeader(t, header, headerBytes) @@ -60,7 +59,7 @@ func BitcoinHeaderValidationLiveTest(t *testing.T) { // Get the block header header, err := client.GetBlockHeader(blockHash) require.NoError(t, err) - headerBytes := marshalHeader(header) + headerBytes := marshalHeader(t, header) // Validate true header validateTrueBitcoinHeader(t, header, headerBytes) @@ -101,21 +100,17 @@ func copyHeader(header *wire.BlockHeader) *wire.BlockHeader { return copyHeader } -func marshalHeader(header *wire.BlockHeader) []byte { +func marshalHeader(t *testing.T, header *wire.BlockHeader) []byte { var headerBuf bytes.Buffer err := header.Serialize(&headerBuf) - if err != nil { - log.Fatal(err) - } + require.NoError(t, err) return headerBuf.Bytes() } -func unmarshalHeader(headerBytes []byte) *wire.BlockHeader { +func unmarshalHeader(t *testing.T, headerBytes []byte) *wire.BlockHeader { var header wire.BlockHeader err := header.Deserialize(bytes.NewReader(headerBytes)) - if err != nil { - log.Fatal(err) - } + require.NoError(t, err) return &header } @@ -136,52 +131,40 @@ func validateFakeBitcoinHeader(t *testing.T, header *wire.BlockHeader, headerByt // Incorrect header length should fail validation err := common.ValidateBitcoinHeader(headerBytes[:79], blockHash[:], 18332) - if err == nil { - t.Error("Incorrect header length should fail validation") - } + require.Error(t, err) // Incorrect version should fail validation fakeHeader := copyHeader(header) fakeHeader.Version = 0 - fakeBytes := marshalHeader(fakeHeader) + fakeBytes := marshalHeader(t, fakeHeader) fakeHash := fakeHeader.BlockHash() err = common.ValidateBitcoinHeader(fakeBytes, fakeHash[:], 18332) - if err == nil { - t.Error("Incorrect version should fail validation") - } + require.Error(t, err) // Incorrect timestamp should fail validation // Case1: timestamp is before genesis block fakeHeader = copyHeader(header) fakeHeader.Timestamp = chaincfg.TestNet3Params.GenesisBlock.Header.Timestamp.Add(-time.Second) - fakeBytes = marshalHeader(fakeHeader) + fakeBytes = marshalHeader(t, fakeHeader) fakeHash = fakeHeader.BlockHash() err = common.ValidateBitcoinHeader(fakeBytes, fakeHash[:], 18332) - if err == nil { - t.Error("Timestamp before genesis should fail validation") - } + require.Error(t, err) // Case2: timestamp is after 2 hours in the future fakeHeader = copyHeader(header) fakeHeader.Timestamp = header.Timestamp.Add(time.Second * (blockchain.MaxTimeOffsetSeconds + 1)) - fakeBytes = marshalHeader(fakeHeader) + fakeBytes = marshalHeader(t, fakeHeader) err = common.NewBitcoinHeader(fakeBytes).ValidateTimestamp(header.Timestamp) - if err == nil { - t.Error("Timestamp in future should fail validation") - } + require.Error(t, err) // Incorrect block hash should fail validation fakeHeader = copyHeader(header) header.Nonce = 0 - fakeBytes = marshalHeader(header) + fakeBytes = marshalHeader(t, header) err = common.ValidateBitcoinHeader(fakeBytes, blockHash[:], 18332) - if err == nil { - t.Error("Incorrect block hash should fail validation") - } + require.Error(t, err) // PoW not satisfied should fail validation fakeHash = fakeHeader.BlockHash() err = common.ValidateBitcoinHeader(fakeBytes, fakeHash[:], 18332) - if err == nil { - t.Error("PoW not satisfied should fail validation") - } + require.Error(t, err) } diff --git a/common/proof_test.go b/common/proof_test.go index 6e6fd0a588..9f3f958504 100644 --- a/common/proof_test.go +++ b/common/proof_test.go @@ -5,12 +5,10 @@ import ( "os" "testing" - "bytes" "encoding/base64" "encoding/hex" "encoding/json" "fmt" - "log" "github.com/stretchr/testify/require" "github.com/zeta-chain/zetacore/common" @@ -65,7 +63,7 @@ func TestBitcoinMerkleProof(t *testing.T) { // Deserialize the header bytes from base64 headerBytes, err := base64.StdEncoding.DecodeString(b.HeaderBase64) require.NoError(t, err) - header := unmarshalHeader(headerBytes) + header := unmarshalHeader(t, headerBytes) // Deserialize the block bytes from base64 blockBytes, err := base64.StdEncoding.DecodeString(b.BlockBase64) @@ -93,7 +91,7 @@ func BitcoinMerkleProofLiveTest(t *testing.T) { // Get the block header header, err := client.GetBlockHeader(blockHash) require.NoError(t, err) - headerBytes := marshalHeader(header) + headerBytes := marshalHeader(t, header) target := blockchain.CompactToBig(header.Bits) // Get the block with verbose transactions @@ -113,13 +111,9 @@ func validateBitcoinBlock(t *testing.T, header *wire.BlockHeader, headerBytes [] txBodies := [][]byte{} for _, res := range blockVerbose.Tx { txBytes, err := hex.DecodeString(res.Hex) - if err != nil { - log.Fatalf("error decoding transaction hex: %v", err) - } + require.NoError(t, err) tx, err := btcutil.NewTxFromBytes(txBytes) - if err != nil { - log.Fatalf("error deserializing transaction: %v", err) - } + require.NoError(t, err) // Validate Tss SegWit transaction if it's an outTx if res.Txid == outTxid { @@ -128,7 +122,7 @@ func validateBitcoinBlock(t *testing.T, header *wire.BlockHeader, headerBytes [] Nonce: nonce, TxHash: outTxid, } - err = keeper.ValidateBTCOutTxBody(msg, txBytes, tssAddress) + err = keeper.VerifyBTCOutTxBody(msg, txBytes, tssAddress) require.NoError(t, err) } txns = append(txns, tx) @@ -139,26 +133,19 @@ func validateBitcoinBlock(t *testing.T, header *wire.BlockHeader, headerBytes [] mk := bitcoin.NewMerkle(txns) for i := range txns { path, index, err := mk.BuildMerkleProof(i) - if err != nil { - log.Fatalf("Error building merkle proof: %v", err) - } + require.NoError(t, err) // True proof should verify proof := common.NewBitcoinProof(txBodies[i], path, index) txBytes, err := proof.Verify(common.NewBitcoinHeader(headerBytes), 0) - if err != nil { - log.Fatal("Merkle proof verification failed") - } - if !bytes.Equal(txBytes, txBodies[i]) { - log.Fatalf("Transaction body mismatch") - } + require.NoError(t, err) + require.Equal(t, txBytes, txBodies[i]) // Fake proof should not verify fakeIndex := index ^ 0xffffffff // flip all bits fakeProof := common.NewBitcoinProof(txBodies[i], path, fakeIndex) txBytes, err = fakeProof.Verify(common.NewBitcoinHeader(headerBytes), 0) - if err == nil || txBytes != nil { - log.Fatalf("Merkle proof should not verify") - } + require.Error(t, err) + require.Nil(t, txBytes) } } diff --git a/common/utils.go b/common/utils.go index 80f6701736..773c709210 100644 --- a/common/utils.go +++ b/common/utils.go @@ -8,14 +8,10 @@ import ( ethcommon "github.com/ethereum/go-ethereum/common" ) -const ( - DustUTXOOffset = 2000 -) - // A very special value to mark current nonce in UTXO func NonceMarkAmount(nonce uint64) int64 { // #nosec G701 always in range - return int64(nonce) + DustUTXOOffset // +2000 to avoid being a dust rejection + return int64(nonce) + BtcDustOffset() // +2000 to avoid being a dust rejection } // HashToString convert hash bytes to string diff --git a/docs/openapi/openapi.swagger.yaml b/docs/openapi/openapi.swagger.yaml index ae13471986..c53284398a 100644 --- a/docs/openapi/openapi.swagger.yaml +++ b/docs/openapi/openapi.swagger.yaml @@ -26947,6 +26947,83 @@ paths: type: string tags: - Query + /zeta-chain/crosschain/inTxTrackerByChain/{chain_id}: + get: + operationId: Query_InTxTrackerAllByChain + responses: + "200": + description: A successful response. + schema: + $ref: '#/definitions/crosschainQueryAllInTxTrackerByChainResponse' + default: + description: An unexpected error response. + schema: + $ref: '#/definitions/googlerpcStatus' + parameters: + - name: chain_id + in: path + required: true + type: string + format: int64 + - name: pagination.key + description: |- + key is a value returned in PageResponse.next_key to begin + querying the next page most efficiently. Only one of offset or key + should be set. + in: query + required: false + type: string + format: byte + - name: pagination.offset + description: |- + offset is a numeric offset that can be used when key is unavailable. + It is less efficient than using key. Only one of offset or key should + be set. + in: query + required: false + type: string + format: uint64 + - name: pagination.limit + description: |- + limit is the total number of results to be returned in the result page. + If left empty it will default to a value to be set by each app. + in: query + required: false + type: string + format: uint64 + - name: pagination.count_total + description: |- + count_total is set to true to indicate that the result set should include + a count of the total number of items available for pagination in UIs. + count_total is only respected when offset is used. It is ignored when key + is set. + in: query + required: false + type: boolean + - name: pagination.reverse + description: |- + reverse is set to true if results are to be returned in the descending order. + + Since: cosmos-sdk 0.43 + in: query + required: false + type: boolean + tags: + - Query + /zeta-chain/crosschain/inTxTrackers: + get: + operationId: Query_InTxTrackerAll + responses: + "200": + description: A successful response. + schema: + $ref: '#/definitions/crosschainQueryAllInTxTrackersResponse' + default: + description: An unexpected error response. + schema: + $ref: '#/definitions/googlerpcStatus' + tags: + - Query /zeta-chain/crosschain/lastBlockHeight: get: summary: Queries a list of lastBlockHeight items. @@ -50474,6 +50551,16 @@ definitions: type: array items: type: string + crosschainInTxTracker: + type: object + properties: + chain_id: + type: string + format: int64 + tx_hash: + type: string + coin_type: + $ref: '#/definitions/commonCoinType' crosschainInboundTxParams: type: object properties: @@ -50518,6 +50605,8 @@ definitions: lastReceiveHeight: type: string format: uint64 + crosschainMsgAddToInTxTrackerResponse: + type: object crosschainMsgAddToOutTxTrackerResponse: type: object crosschainMsgCreateTSSVoterResponse: @@ -50665,6 +50754,24 @@ definitions: $ref: '#/definitions/crosschainInTxHashToCctx' pagination: $ref: '#/definitions/v1beta1PageResponse' + crosschainQueryAllInTxTrackerByChainResponse: + type: object + properties: + inTxTracker: + type: array + items: + type: object + $ref: '#/definitions/crosschainInTxTracker' + pagination: + $ref: '#/definitions/v1beta1PageResponse' + crosschainQueryAllInTxTrackersResponse: + type: object + properties: + inTxTracker: + type: array + items: + type: object + $ref: '#/definitions/crosschainInTxTracker' crosschainQueryAllLastBlockHeightResponse: type: object properties: @@ -50992,6 +51099,13 @@ definitions: items: type: object $ref: '#/definitions/observerNode' + observerBlockHeaderVerificationFlags: + type: object + properties: + isEthTypeChainEnabled: + type: boolean + isBtcTypeChainEnabled: + type: boolean observerCoreParams: type: object properties: @@ -51042,6 +51156,8 @@ definitions: type: boolean gasPriceIncreaseFlags: $ref: '#/definitions/observerGasPriceIncreaseFlags' + blockHeaderVerificationFlags: + $ref: '#/definitions/observerBlockHeaderVerificationFlags' observerGasPriceIncreaseFlags: type: object properties: diff --git a/docs/spec/crosschain/messages.md b/docs/spec/crosschain/messages.md index a42024e82e..7ad44e674e 100644 --- a/docs/spec/crosschain/messages.md +++ b/docs/spec/crosschain/messages.md @@ -3,7 +3,7 @@ ## MsgAddToOutTxTracker AddToOutTxTracker adds a new record to the outbound transaction tracker. -only the admin policy account and the observer validators are authorized to broadcast this message. +only the admin policy account and the observer validators are authorized to broadcast this message without proof. ```proto message MsgAddToOutTxTracker { @@ -17,6 +17,22 @@ message MsgAddToOutTxTracker { } ``` +## MsgAddToInTxTracker + +TODO https://github.com/zeta-chain/node/issues/1269 + +```proto +message MsgAddToInTxTracker { + string creator = 1; + int64 chain_id = 2; + string tx_hash = 3; + common.CoinType coin_type = 4; + common.Proof proof = 5; + string block_hash = 6; + int64 tx_index = 7; +} +``` + ## MsgRemoveFromOutTxTracker RemoveFromOutTxTracker removes a record from the outbound transaction tracker by chain ID and nonce. diff --git a/docs/spec/observer/messages.md b/docs/spec/observer/messages.md index 5373e16993..3f7f4cc5d9 100644 --- a/docs/spec/observer/messages.md +++ b/docs/spec/observer/messages.md @@ -52,6 +52,7 @@ message MsgUpdateCrosschainFlags { bool isInboundEnabled = 3; bool isOutboundEnabled = 4; GasPriceIncreaseFlags gasPriceIncreaseFlags = 5; + BlockHeaderVerificationFlags blockHeaderVerificationFlags = 6; } ``` diff --git a/proto/crosschain/genesis.proto b/proto/crosschain/genesis.proto index e86cf6d073..c62d228d0b 100644 --- a/proto/crosschain/genesis.proto +++ b/proto/crosschain/genesis.proto @@ -5,6 +5,7 @@ import "crosschain/chain_nonces.proto"; import "crosschain/cross_chain_tx.proto"; import "crosschain/gas_price.proto"; import "crosschain/in_tx_hash_to_cctx.proto"; +import "crosschain/in_tx_tracker.proto"; import "crosschain/last_block_height.proto"; import "crosschain/out_tx_tracker.proto"; import "crosschain/params.proto"; @@ -25,4 +26,5 @@ message GenesisState { repeated LastBlockHeight lastBlockHeightList = 8; repeated InTxHashToCctx inTxHashToCctxList = 9 [(gogoproto.nullable) = false]; repeated TSS tss_history = 10 [(gogoproto.nullable) = false]; + repeated InTxTracker in_tx_tracker_list = 11 [(gogoproto.nullable) = false]; } diff --git a/proto/crosschain/in_tx_tracker.proto b/proto/crosschain/in_tx_tracker.proto new file mode 100644 index 0000000000..e0775f7e0c --- /dev/null +++ b/proto/crosschain/in_tx_tracker.proto @@ -0,0 +1,12 @@ +syntax = "proto3"; +package zetachain.zetacore.crosschain; + +import "common/common.proto"; + +option go_package = "github.com/zeta-chain/zetacore/x/crosschain/types"; + +message InTxTracker { + int64 chain_id = 1; + string tx_hash = 2; + common.CoinType coin_type = 3; +} diff --git a/proto/crosschain/query.proto b/proto/crosschain/query.proto index 9f2c035a4c..e05265258d 100644 --- a/proto/crosschain/query.proto +++ b/proto/crosschain/query.proto @@ -6,6 +6,7 @@ import "crosschain/chain_nonces.proto"; import "crosschain/cross_chain_tx.proto"; import "crosschain/gas_price.proto"; import "crosschain/in_tx_hash_to_cctx.proto"; +import "crosschain/in_tx_tracker.proto"; import "crosschain/last_block_height.proto"; import "crosschain/nonce_to_cctx.proto"; import "crosschain/out_tx_tracker.proto"; @@ -37,6 +38,13 @@ service Query { option (google.api.http).get = "/zeta-chain/crosschain/outTxTrackerByChain/{chain}"; } + rpc InTxTrackerAllByChain(QueryAllInTxTrackerByChainRequest) returns (QueryAllInTxTrackerByChainResponse) { + option (google.api.http).get = "/zeta-chain/crosschain/inTxTrackerByChain/{chain_id}"; + } + rpc InTxTrackerAll(QueryAllInTxTrackersRequest) returns (QueryAllInTxTrackersResponse) { + option (google.api.http).get = "/zeta-chain/crosschain/inTxTrackers"; + } + // Queries a InTxHashToCctx by index. rpc InTxHashToCctx(QueryGetInTxHashToCctxRequest) returns (QueryGetInTxHashToCctxResponse) { option (google.api.http).get = "/zeta-chain/crosschain/inTxHashToCctx/{inTxHash}"; @@ -180,6 +188,22 @@ message QueryAllOutTxTrackerByChainResponse { cosmos.base.query.v1beta1.PageResponse pagination = 2; } +message QueryAllInTxTrackerByChainRequest { + int64 chain_id = 1; + cosmos.base.query.v1beta1.PageRequest pagination = 2; +} + +message QueryAllInTxTrackerByChainResponse { + repeated InTxTracker inTxTracker = 1 [(gogoproto.nullable) = false]; + cosmos.base.query.v1beta1.PageResponse pagination = 2; +} + +message QueryAllInTxTrackersRequest {} + +message QueryAllInTxTrackersResponse { + repeated InTxTracker inTxTracker = 1 [(gogoproto.nullable) = false]; +} + message QueryGetInTxHashToCctxRequest { string inTxHash = 1; } diff --git a/proto/crosschain/tx.proto b/proto/crosschain/tx.proto index 2e3b3a63a6..b34fa2f47d 100644 --- a/proto/crosschain/tx.proto +++ b/proto/crosschain/tx.proto @@ -9,6 +9,7 @@ option go_package = "github.com/zeta-chain/zetacore/x/crosschain/types"; // Msg defines the Msg service. service Msg { rpc AddToOutTxTracker(MsgAddToOutTxTracker) returns (MsgAddToOutTxTrackerResponse); + rpc AddToInTxTracker(MsgAddToInTxTracker) returns (MsgAddToInTxTrackerResponse); rpc RemoveFromOutTxTracker(MsgRemoveFromOutTxTracker) returns (MsgRemoveFromOutTxTrackerResponse); rpc CreateTSSVoter(MsgCreateTSSVoter) returns (MsgCreateTSSVoterResponse); rpc GasPriceVoter(MsgGasPriceVoter) returns (MsgGasPriceVoterResponse); @@ -31,6 +32,17 @@ message MsgMigrateTssFunds { } message MsgMigrateTssFundsResponse {} +message MsgAddToInTxTracker { + string creator = 1; + int64 chain_id = 2; + string tx_hash = 3; + common.CoinType coin_type = 4; + common.Proof proof = 5; + string block_hash = 6; + int64 tx_index = 7; +} +message MsgAddToInTxTrackerResponse {} + message MsgUpdateTssAddress { string creator = 1; string tss_pubkey = 2; diff --git a/proto/observer/crosschain_flags.proto b/proto/observer/crosschain_flags.proto index af52a75f46..32e7ae8669 100644 --- a/proto/observer/crosschain_flags.proto +++ b/proto/observer/crosschain_flags.proto @@ -14,9 +14,20 @@ message GasPriceIncreaseFlags { ]; uint32 gasPriceIncreasePercent = 3; } +message BlockHeaderVerificationFlags { + bool isEthTypeChainEnabled = 1; + bool isBtcTypeChainEnabled = 2; +} message CrosschainFlags { bool isInboundEnabled = 1; bool isOutboundEnabled = 2; GasPriceIncreaseFlags gasPriceIncreaseFlags = 3; + BlockHeaderVerificationFlags blockHeaderVerificationFlags = 4; +} + +message LegacyCrosschainFlags { + bool isInboundEnabled = 1; + bool isOutboundEnabled = 2; + GasPriceIncreaseFlags gasPriceIncreaseFlags = 3; } diff --git a/proto/observer/events.proto b/proto/observer/events.proto index 66fff998f4..88bd20fe39 100644 --- a/proto/observer/events.proto +++ b/proto/observer/events.proto @@ -35,4 +35,5 @@ message EventCrosschainFlagsUpdated { bool isOutboundEnabled = 3; GasPriceIncreaseFlags gasPriceIncreaseFlags = 4; string signer = 5; + BlockHeaderVerificationFlags blockHeaderVerificationFlags = 6; } diff --git a/proto/observer/tx.proto b/proto/observer/tx.proto index 441fa01b8b..7d1fd5e1e2 100644 --- a/proto/observer/tx.proto +++ b/proto/observer/tx.proto @@ -59,6 +59,7 @@ message MsgUpdateCrosschainFlags { bool isInboundEnabled = 3; bool isOutboundEnabled = 4; GasPriceIncreaseFlags gasPriceIncreaseFlags = 5; + BlockHeaderVerificationFlags blockHeaderVerificationFlags = 6; } message MsgUpdateCrosschainFlagsResponse {} diff --git a/testutil/network/genesis_state.go b/testutil/network/genesis_state.go index 047114afe9..334c258746 100644 --- a/testutil/network/genesis_state.go +++ b/testutil/network/genesis_state.go @@ -165,6 +165,16 @@ func AddCrosschainData(t *testing.T, n int, genesisState map[string]json.RawMess state.OutTxTrackerList = append(state.OutTxTrackerList, outTxTracker) } + for i := 0; i < n; i++ { + inTxTracker := types.InTxTracker{ + ChainId: 5, + TxHash: fmt.Sprintf("txHash-%d", i), + CoinType: common.CoinType_Gas, + } + nullify.Fill(&inTxTracker) + state.InTxTrackerList = append(state.InTxTrackerList, inTxTracker) + } + for i := 0; i < n; i++ { inTxHashToCctx := types.InTxHashToCctx{ InTxHash: strconv.Itoa(i), diff --git a/x/crosschain/client/cli/cli_in_tx_tracker.go b/x/crosschain/client/cli/cli_in_tx_tracker.go new file mode 100644 index 0000000000..764127a900 --- /dev/null +++ b/x/crosschain/client/cli/cli_in_tx_tracker.go @@ -0,0 +1,104 @@ +package cli + +import ( + "context" + "strconv" + + "github.com/cosmos/cosmos-sdk/client" + "github.com/cosmos/cosmos-sdk/client/flags" + "github.com/cosmos/cosmos-sdk/client/tx" + "github.com/spf13/cobra" + "github.com/zeta-chain/zetacore/common" + "github.com/zeta-chain/zetacore/x/crosschain/types" +) + +func CmdAddToInTxTracker() *cobra.Command { + cmd := &cobra.Command{ + Use: "add-to-in-tx-tracker [chain-id] [tx-hash] [coin-type]", + Short: `Add a in-tx-tracker + Use 0:Zeta,1:Gas,2:ERC20`, + Args: cobra.ExactArgs(3), + RunE: func(cmd *cobra.Command, args []string) (err error) { + argChain, err := strconv.ParseInt(args[0], 10, 64) + if err != nil { + return err + } + argTxHash := args[1] + argsCoinType, err := common.GetCoinType(args[2]) + if err != nil { + return err + } + clientCtx, err := client.GetClientTxContext(cmd) + if err != nil { + return err + } + msg := types.NewMsgAddToInTxTracker( + clientCtx.GetFromAddress().String(), + argChain, + argsCoinType, + argTxHash, + ) + if err := msg.ValidateBasic(); err != nil { + return err + } + return tx.GenerateOrBroadcastTxCLI(clientCtx, cmd.Flags(), msg) + }, + } + + flags.AddTxFlagsToCmd(cmd) + + return cmd +} + +func CmdListInTxTrackerByChain() *cobra.Command { + cmd := &cobra.Command{ + Use: "list-in-tx-tracker [chainId]", + Short: "shows a list of in tx tracker by chainId", + Args: cobra.ExactArgs(1), + RunE: func(cmd *cobra.Command, args []string) (err error) { + clientCtx := client.GetClientContextFromCmd(cmd) + queryClient := types.NewQueryClient(clientCtx) + argChain, err := strconv.ParseInt(args[0], 10, 64) + if err != nil { + return err + } + pageReq, err := client.ReadPageRequest(cmd.Flags()) + if err != nil { + return err + } + params := &types.QueryAllInTxTrackerByChainRequest{ + ChainId: argChain, + Pagination: pageReq, + } + res, err := queryClient.InTxTrackerAllByChain(context.Background(), params) + if err != nil { + return err + } + + return clientCtx.PrintProto(res) + }, + } + flags.AddQueryFlagsToCmd(cmd) + flags.AddPaginationFlagsToCmd(cmd, cmd.Use) + return cmd +} + +func CmdListInTxTrackers() *cobra.Command { + cmd := &cobra.Command{ + Use: "list-all-in-tx-trackers", + Short: "shows all inTxTrackers", + Args: cobra.NoArgs, + RunE: func(cmd *cobra.Command, args []string) (err error) { + clientCtx := client.GetClientContextFromCmd(cmd) + queryClient := types.NewQueryClient(clientCtx) + params := &types.QueryAllInTxTrackersRequest{} + res, err := queryClient.InTxTrackerAll(context.Background(), params) + if err != nil { + return err + } + return clientCtx.PrintProto(res) + }, + } + flags.AddQueryFlagsToCmd(cmd) + return cmd +} diff --git a/x/crosschain/client/cli/query.go b/x/crosschain/client/cli/query.go index fe4ac3dc4c..21b112a621 100644 --- a/x/crosschain/client/cli/query.go +++ b/x/crosschain/client/cli/query.go @@ -44,6 +44,8 @@ func GetQueryCmd(_ string) *cobra.Command { CmdListTssHistory(), CmdListPendingNonces(), CmdPendingCctx(), + CmdListInTxTrackerByChain(), + CmdListInTxTrackers(), ) return cmd diff --git a/x/crosschain/client/cli/tx.go b/x/crosschain/client/cli/tx.go index 27a0c03af8..868ff07549 100644 --- a/x/crosschain/client/cli/tx.go +++ b/x/crosschain/client/cli/tx.go @@ -30,6 +30,7 @@ func GetTxCmd() *cobra.Command { CmdRemoveFromWatchList(), CmdUpdateTss(), CmdMigrateTssFunds(), + CmdAddToInTxTracker(), ) return cmd diff --git a/x/crosschain/client/querytests/in_tx_tracker.go b/x/crosschain/client/querytests/in_tx_tracker.go new file mode 100644 index 0000000000..15c34b3bda --- /dev/null +++ b/x/crosschain/client/querytests/in_tx_tracker.go @@ -0,0 +1,103 @@ +package querytests + +import ( + "fmt" + + "github.com/cosmos/cosmos-sdk/client/flags" + clitestutil "github.com/cosmos/cosmos-sdk/testutil/cli" + tmcli "github.com/tendermint/tendermint/libs/cli" + "github.com/zeta-chain/zetacore/testutil/nullify" + "github.com/zeta-chain/zetacore/x/crosschain/client/cli" + "github.com/zeta-chain/zetacore/x/crosschain/types" +) + +func (s *CliTestSuite) TestListInTxTrackers() { + ctx := s.network.Validators[0].ClientCtx + objs := s.crosschainState.InTxTrackerList + s.Run("List all trackers", func() { + args := []string{ + fmt.Sprintf("--%s=json", tmcli.OutputFlag), + } + out, err := clitestutil.ExecTestCLICmd(ctx, cli.CmdListInTxTrackers(), args) + s.Require().NoError(err) + var resp types.QueryAllInTxTrackersResponse + s.Require().NoError(s.network.Config.Codec.UnmarshalJSON(out.Bytes(), &resp)) + s.Require().Equal(len(objs), len(resp.InTxTracker)) + s.Require().ElementsMatch(nullify.Fill(objs), nullify.Fill(resp.InTxTracker)) + }) +} + +func (s *CliTestSuite) TestListInTxTrackersByChain() { + ctx := s.network.Validators[0].ClientCtx + objs := s.crosschainState.InTxTrackerList + request := func(next []byte, offset, limit uint64, total bool, chainID int) []string { + args := []string{ + fmt.Sprintf("--%s=json", tmcli.OutputFlag), + } + if next == nil { + args = append(args, fmt.Sprintf("--%s=%d", flags.FlagOffset, offset)) + } else { + args = append(args, fmt.Sprintf("--%s=%s", flags.FlagPageKey, next)) + } + args = append(args, fmt.Sprintf("--%s=%d", flags.FlagLimit, limit)) + if total { + args = append(args, fmt.Sprintf("--%s", flags.FlagCountTotal)) + } + args = append(args, fmt.Sprintf("%d", chainID)) + return args + } + s.Run("ByOffset", func() { + step := 2 + for i := 0; i < len(objs); i += step { + // #nosec G701 always positive + args := request(nil, uint64(i), uint64(step), false, 5) + out, err := clitestutil.ExecTestCLICmd(ctx, cli.CmdListInTxTrackerByChain(), args) + s.Require().NoError(err) + var resp types.QueryAllInTxTrackerByChainResponse + s.Require().NoError(s.network.Config.Codec.UnmarshalJSON(out.Bytes(), &resp)) + s.Require().LessOrEqual(len(resp.InTxTracker), step) + s.Require().Subset(nullify.Fill(objs), + nullify.Fill(resp.InTxTracker), + ) + } + }) + s.Run("ByKey", func() { + step := 2 + var next []byte + for i := 0; i < len(objs); i += step { + // #nosec G701 always positive + args := request(next, 0, uint64(step), false, 5) + out, err := clitestutil.ExecTestCLICmd(ctx, cli.CmdListInTxTrackerByChain(), args) + s.Require().NoError(err) + var resp types.QueryAllInTxTrackerByChainResponse + s.Require().NoError(s.network.Config.Codec.UnmarshalJSON(out.Bytes(), &resp)) + s.Require().LessOrEqual(len(resp.InTxTracker), step) + s.Require().Subset( + nullify.Fill(objs), + nullify.Fill(resp.InTxTracker), + ) + next = resp.Pagination.NextKey + } + }) + s.Run("Total", func() { + args := request(nil, 0, uint64(len(objs)), true, 5) + out, err := clitestutil.ExecTestCLICmd(ctx, cli.CmdListInTxTrackerByChain(), args) + s.Require().NoError(err) + var resp types.QueryAllInTxTrackerByChainResponse + s.Require().NoError(s.network.Config.Codec.UnmarshalJSON(out.Bytes(), &resp)) + s.Require().NoError(err) + s.Require().Equal(uint64(len(objs)), resp.Pagination.Total) + s.Require().ElementsMatch(nullify.Fill(objs), + nullify.Fill(resp.InTxTracker), + ) + }) + s.Run("Incorrect Chain ID ", func() { + args := request(nil, 0, uint64(len(objs)), true, 15) + out, err := clitestutil.ExecTestCLICmd(ctx, cli.CmdListInTxTrackerByChain(), args) + s.Require().NoError(err) + var resp types.QueryAllInTxTrackerByChainResponse + s.Require().NoError(s.network.Config.Codec.UnmarshalJSON(out.Bytes(), &resp)) + s.Require().NoError(err) + s.Require().Equal(uint64(0), resp.Pagination.Total) + }) +} diff --git a/x/crosschain/genesis.go b/x/crosschain/genesis.go index f6b6a910dd..e1d77b1c02 100644 --- a/x/crosschain/genesis.go +++ b/x/crosschain/genesis.go @@ -18,6 +18,11 @@ func InitGenesis(ctx sdk.Context, k keeper.Keeper, genState types.GenesisState) k.SetOutTxTracker(ctx, elem) } + // Set all the inTxTracker + for _, elem := range genState.InTxTrackerList { + k.SetInTxTracker(ctx, elem) + } + // Set all the inTxHashToCctx for _, elem := range genState.InTxHashToCctxList { k.SetInTxHashToCctx(ctx, elem) @@ -76,6 +81,7 @@ func ExportGenesis(ctx sdk.Context, k keeper.Keeper) *types.GenesisState { genesis.Params = k.GetParams(ctx) genesis.OutTxTrackerList = k.GetAllOutTxTracker(ctx) genesis.InTxHashToCctxList = k.GetAllInTxHashToCctx(ctx) + genesis.InTxTrackerList = k.GetAllInTxTracker(ctx) // Get tss tss, found := k.GetTSS(ctx) diff --git a/x/crosschain/keeper/grpc_query_in_tx_tracker.go b/x/crosschain/keeper/grpc_query_in_tx_tracker.go new file mode 100644 index 0000000000..ccdaa92e3d --- /dev/null +++ b/x/crosschain/keeper/grpc_query_in_tx_tracker.go @@ -0,0 +1,28 @@ +package keeper + +import ( + "context" + + sdk "github.com/cosmos/cosmos-sdk/types" + + "github.com/zeta-chain/zetacore/x/crosschain/types" + "google.golang.org/grpc/codes" + "google.golang.org/grpc/status" +) + +func (k Keeper) InTxTrackerAllByChain(goCtx context.Context, request *types.QueryAllInTxTrackerByChainRequest) (*types.QueryAllInTxTrackerByChainResponse, error) { + ctx := sdk.UnwrapSDKContext(goCtx) + var inTxTrackers []types.InTxTracker + inTxTrackers, pageRes, err := k.GetAllInTxTrackerForChainPaginated(ctx, request.ChainId, request.Pagination) + if err != nil { + return nil, status.Error(codes.Internal, err.Error()) + } + return &types.QueryAllInTxTrackerByChainResponse{InTxTracker: inTxTrackers, Pagination: pageRes}, nil +} + +func (k Keeper) InTxTrackerAll(goCtx context.Context, _ *types.QueryAllInTxTrackersRequest) (*types.QueryAllInTxTrackersResponse, error) { + ctx := sdk.UnwrapSDKContext(goCtx) + var inTxTrackers []types.InTxTracker + inTxTrackers = k.GetAllInTxTracker(ctx) + return &types.QueryAllInTxTrackersResponse{InTxTracker: inTxTrackers}, nil +} diff --git a/x/crosschain/keeper/in_tx_tracker.go b/x/crosschain/keeper/in_tx_tracker.go new file mode 100644 index 0000000000..0957cb2162 --- /dev/null +++ b/x/crosschain/keeper/in_tx_tracker.go @@ -0,0 +1,79 @@ +package keeper + +import ( + "fmt" + + "github.com/cosmos/cosmos-sdk/store/prefix" + sdk "github.com/cosmos/cosmos-sdk/types" + "github.com/cosmos/cosmos-sdk/types/query" + "github.com/zeta-chain/zetacore/x/crosschain/types" +) + +func getInTrackerKey(chainID int64, txHash string) string { + return fmt.Sprintf("%d-%s", chainID, txHash) +} + +// SetInTxTracker set a specific InTxTracker in the store from its index +func (k Keeper) SetInTxTracker(ctx sdk.Context, InTxTracker types.InTxTracker) { + store := prefix.NewStore(ctx.KVStore(k.storeKey), types.KeyPrefix(types.InTxTrackerKeyPrefix)) + b := k.cdc.MustMarshal(&InTxTracker) + key := types.KeyPrefix(getInTrackerKey(InTxTracker.ChainId, InTxTracker.TxHash)) + store.Set(key, b) +} + +// GetInTxTracker returns a InTxTracker from its index +func (k Keeper) GetInTxTracker(ctx sdk.Context, chainID int64, txHash string) (val types.InTxTracker, found bool) { + key := getInTrackerKey(chainID, txHash) + store := prefix.NewStore(ctx.KVStore(k.storeKey), types.KeyPrefix(types.InTxTrackerKeyPrefix)) + b := store.Get(types.KeyPrefix(key)) + if b == nil { + return val, false + } + k.cdc.MustUnmarshal(b, &val) + return val, true +} + +func (k Keeper) RemoveInTxTrackerIfExists(ctx sdk.Context, chainID int64, txHash string) { + key := getInTrackerKey(chainID, txHash) + store := prefix.NewStore(ctx.KVStore(k.storeKey), types.KeyPrefix(types.InTxTrackerKeyPrefix)) + if store.Has(types.KeyPrefix(key)) { + store.Delete(types.KeyPrefix(key)) + } +} +func (k Keeper) GetAllInTxTracker(ctx sdk.Context) (list []types.InTxTracker) { + store := prefix.NewStore(ctx.KVStore(k.storeKey), types.KeyPrefix(types.InTxTrackerKeyPrefix)) + iterator := sdk.KVStorePrefixIterator(store, []byte{}) + defer iterator.Close() + for ; iterator.Valid(); iterator.Next() { + var val types.InTxTracker + k.cdc.MustUnmarshal(iterator.Value(), &val) + list = append(list, val) + } + return list +} + +func (k Keeper) GetAllInTxTrackerForChain(ctx sdk.Context, chainID int64) (list []types.InTxTracker) { + store := prefix.NewStore(ctx.KVStore(k.storeKey), types.KeyPrefix(types.InTxTrackerKeyPrefix)) + iterator := sdk.KVStorePrefixIterator(store, []byte(fmt.Sprintf("%d-", chainID))) + defer iterator.Close() + for ; iterator.Valid(); iterator.Next() { + var val types.InTxTracker + k.cdc.MustUnmarshal(iterator.Value(), &val) + list = append(list, val) + } + return list +} + +func (k Keeper) GetAllInTxTrackerForChainPaginated(ctx sdk.Context, chainID int64, pagination *query.PageRequest) (inTxTrackers []types.InTxTracker, pageRes *query.PageResponse, err error) { + store := prefix.NewStore(ctx.KVStore(k.storeKey), types.KeyPrefix(fmt.Sprintf("%s", types.InTxTrackerKeyPrefix))) + chainStore := prefix.NewStore(store, types.KeyPrefix(fmt.Sprintf("%d-", chainID))) + pageRes, err = query.Paginate(chainStore, pagination, func(key []byte, value []byte) error { + var inTxTracker types.InTxTracker + if err := k.cdc.Unmarshal(value, &inTxTracker); err != nil { + return err + } + inTxTrackers = append(inTxTrackers, inTxTracker) + return nil + }) + return +} diff --git a/x/crosschain/keeper/in_tx_tracker_test.go b/x/crosschain/keeper/in_tx_tracker_test.go new file mode 100644 index 0000000000..c16deeb819 --- /dev/null +++ b/x/crosschain/keeper/in_tx_tracker_test.go @@ -0,0 +1,78 @@ +package keeper + +import ( + "fmt" + "sort" + "testing" + + sdk "github.com/cosmos/cosmos-sdk/types" + "github.com/cosmos/cosmos-sdk/types/query" + "github.com/stretchr/testify/require" + "github.com/zeta-chain/zetacore/common" + "github.com/zeta-chain/zetacore/testutil/nullify" + "github.com/zeta-chain/zetacore/x/crosschain/types" +) + +func createNInTxTracker(keeper *Keeper, ctx sdk.Context, n int, chainID int64) []types.InTxTracker { + items := make([]types.InTxTracker, n) + for i := range items { + items[i].TxHash = fmt.Sprintf("TxHash-%d", i) + items[i].ChainId = chainID + items[i].CoinType = common.CoinType_Gas + keeper.SetInTxTracker(ctx, items[i]) + } + return items +} +func TestKeeper_GetAllInTxTrackerForChain(t *testing.T) { + keeper, ctx := setupKeeper(t) + intxTrackers := createNInTxTracker(keeper, ctx, 10, 5) + t.Run("Get InTx trackers one by one", func(t *testing.T) { + for _, item := range intxTrackers { + rst, found := keeper.GetInTxTracker(ctx, item.ChainId, item.TxHash) + require.True(t, found) + require.Equal(t, item, rst) + } + }) + t.Run("Get all InTx trackers", func(t *testing.T) { + rst := keeper.GetAllInTxTracker(ctx) + require.Equal(t, intxTrackers, rst) + }) + t.Run("Get all InTx trackers for chain", func(t *testing.T) { + intxTrackersNew := createNInTxTracker(keeper, ctx, 100, 6) + rst := keeper.GetAllInTxTrackerForChain(ctx, 6) + sort.SliceStable(rst, func(i, j int) bool { + return rst[i].TxHash < rst[j].TxHash + }) + sort.SliceStable(intxTrackersNew, func(i, j int) bool { + return intxTrackersNew[i].TxHash < intxTrackersNew[j].TxHash + }) + require.Equal(t, intxTrackersNew, rst) + }) + t.Run("Get all InTx trackers for chain paginated by limit", func(t *testing.T) { + intxTrackers = createNInTxTracker(keeper, ctx, 100, 6) + rst, pageRes, err := keeper.GetAllInTxTrackerForChainPaginated(ctx, 6, &query.PageRequest{Limit: 10, CountTotal: true}) + require.NoError(t, err) + require.Subset(t, nullify.Fill(intxTrackers), nullify.Fill(rst)) + require.Equal(t, len(intxTrackers), int(pageRes.Total)) + }) + t.Run("Get all InTx trackers for chain paginated by offset", func(t *testing.T) { + intxTrackers = createNInTxTracker(keeper, ctx, 100, 6) + rst, pageRes, err := keeper.GetAllInTxTrackerForChainPaginated(ctx, 6, &query.PageRequest{Offset: 10, CountTotal: true}) + require.NoError(t, err) + require.Subset(t, nullify.Fill(intxTrackers), nullify.Fill(rst)) + require.Equal(t, len(intxTrackers), int(pageRes.Total)) + }) + t.Run("Delete InTxTracker", func(t *testing.T) { + trackers := keeper.GetAllInTxTracker(ctx) + for _, item := range trackers { + keeper.RemoveInTxTrackerIfExists(ctx, item.ChainId, item.TxHash) + } + + intxTrackers = createNInTxTracker(keeper, ctx, 10, 6) + for _, item := range intxTrackers { + keeper.RemoveInTxTrackerIfExists(ctx, item.ChainId, item.TxHash) + } + rst := keeper.GetAllInTxTrackerForChain(ctx, 6) + require.Equal(t, 0, len(rst)) + }) +} diff --git a/x/crosschain/keeper/keeper_cross_chain_tx_vote_inbound_tx.go b/x/crosschain/keeper/keeper_cross_chain_tx_vote_inbound_tx.go index a384c320ba..ac82cd022f 100644 --- a/x/crosschain/keeper/keeper_cross_chain_tx_vote_inbound_tx.go +++ b/x/crosschain/keeper/keeper_cross_chain_tx_vote_inbound_tx.go @@ -124,6 +124,7 @@ func (k msgServer) VoteOnObservedInboundTx(goCtx context.Context, msg *types.Msg EmitEventInboundFinalized(ctx, &cctx) // #nosec G701 always positive cctx.InboundTxParams.InboundTxFinalizedZetaHeight = uint64(ctx.BlockHeight()) + k.RemoveInTxTrackerIfExists(ctx, cctx.InboundTxParams.SenderChainId, cctx.InboundTxParams.InboundTxObservedHash) k.SetCctxAndNonceToCctxAndInTxHashToCctx(ctx, cctx) }() // FinalizeInbound updates CCTX Prices and Nonce diff --git a/x/crosschain/keeper/keeper_out_tx_tracker.go b/x/crosschain/keeper/keeper_out_tx_tracker.go index 308f4c13b0..1be2b0e8a4 100644 --- a/x/crosschain/keeper/keeper_out_tx_tracker.go +++ b/x/crosschain/keeper/keeper_out_tx_tracker.go @@ -3,22 +3,12 @@ package keeper import ( "context" "fmt" - "math/big" - "strings" - cosmoserrors "cosmossdk.io/errors" - - "github.com/btcsuite/btcd/btcec" - "github.com/btcsuite/btcutil" "github.com/cosmos/cosmos-sdk/store/prefix" sdk "github.com/cosmos/cosmos-sdk/types" "github.com/cosmos/cosmos-sdk/types/query" - eth "github.com/ethereum/go-ethereum/common" - ethtypes "github.com/ethereum/go-ethereum/core/types" - "github.com/zeta-chain/zetacore/common" "github.com/zeta-chain/zetacore/x/crosschain/types" observertypes "github.com/zeta-chain/zetacore/x/observer/types" - "github.com/zeta-chain/zetacore/zetaclient/config" "google.golang.org/grpc/codes" "google.golang.org/grpc/status" ) @@ -162,177 +152,6 @@ func (k Keeper) OutTxTracker(c context.Context, req *types.QueryGetOutTxTrackerR // Messages -// AddToOutTxTracker adds a new record to the outbound transaction tracker. -// only the admin policy account and the observer validators are authorized to broadcast this message. -func (k msgServer) AddToOutTxTracker(goCtx context.Context, msg *types.MsgAddToOutTxTracker) (*types.MsgAddToOutTxTrackerResponse, error) { - ctx := sdk.UnwrapSDKContext(goCtx) - chain := k.zetaObserverKeeper.GetParams(ctx).GetChainFromChainID(msg.ChainId) - if chain == nil { - return nil, observertypes.ErrSupportedChains - } - - if msg.Proof == nil { // without proof, only certain accounts can send this message - adminPolicyAccount := k.zetaObserverKeeper.GetParams(ctx).GetAdminPolicyAccount(observertypes.Policy_Type_group1) - isAdmin := msg.Creator == adminPolicyAccount - - isObserver := k.zetaObserverKeeper.IsAuthorized(ctx, msg.Creator, chain) - - // Sender needs to be either the admin policy account or an observer - if !(isAdmin || isObserver) { - return nil, cosmoserrors.Wrap(observertypes.ErrNotAuthorized, fmt.Sprintf("Creator %s", msg.Creator)) - } - } - - proven := false - if msg.Proof != nil { - blockHash, err := common.StringToHash(msg.ChainId, msg.BlockHash) - if err != nil { - return nil, cosmoserrors.Wrap(err, "block hash conversion failed") - } - res, found := k.zetaObserverKeeper.GetBlockHeader(ctx, blockHash) - if !found { - return nil, cosmoserrors.Wrap(observertypes.ErrBlockHeaderNotFound, fmt.Sprintf("block header not found %s", msg.BlockHash)) - } - - // verify outTx merkle proof - txBytes, err := msg.Proof.Verify(res.Header, int(msg.TxIndex)) - if err != nil && !common.IsErrorInvalidProof(err) { - return nil, err - } - if err == nil { - tss, err := k.GetTssAddress(ctx, &types.QueryGetTssAddressRequest{}) - if err != nil { - return nil, err - } - // verify outTx transaction body - if common.IsEVMChain(msg.ChainId) { - err = ValidateEVMOutTxBody(msg, txBytes, tss.Eth) - } else if common.IsBitcoinChain(msg.ChainId) { - err = ValidateBTCOutTxBody(msg, txBytes, tss.Btc) - } else { - return nil, fmt.Errorf("unsupported chain id %d", msg.ChainId) - } - if err != nil { - return nil, err - } - } - - if !proven { - return nil, fmt.Errorf("proof failed") - } - } - - tracker, found := k.GetOutTxTracker(ctx, msg.ChainId, msg.Nonce) - hash := types.TxHashList{ - TxHash: msg.TxHash, - TxSigner: msg.Creator, - } - if !found { - k.SetOutTxTracker(ctx, types.OutTxTracker{ - Index: "", - ChainId: chain.ChainId, - Nonce: msg.Nonce, - HashList: []*types.TxHashList{&hash}, - }) - return &types.MsgAddToOutTxTrackerResponse{}, nil - } - - var isDup = false - for _, hash := range tracker.HashList { - if strings.EqualFold(hash.TxHash, msg.TxHash) { - isDup = true - if proven { - hash.Proved = true - k.SetOutTxTracker(ctx, tracker) - k.Logger(ctx).Info("Proof'd outbound transaction") - return &types.MsgAddToOutTxTrackerResponse{}, nil - } - break - } - } - if !isDup { - if proven { - hash.Proved = true - tracker.HashList = append([]*types.TxHashList{&hash}, tracker.HashList...) - k.Logger(ctx).Info("Proof'd outbound transaction") - } else { - tracker.HashList = append(tracker.HashList, &hash) - } - k.SetOutTxTracker(ctx, tracker) - } - return &types.MsgAddToOutTxTrackerResponse{}, nil -} - -// ValidateEVMOutTxBody validates the sender address, nonce and chain ID. -// Note: 'msg' may contain fabricated information -func ValidateEVMOutTxBody(msg *types.MsgAddToOutTxTracker, txBytes []byte, tssEth string) error { - var txx ethtypes.Transaction - err := txx.UnmarshalBinary(txBytes) - if err != nil { - return err - } - signer := ethtypes.NewLondonSigner(txx.ChainId()) - sender, err := ethtypes.Sender(signer, &txx) - if err != nil { - return err - } - tssAddr := eth.HexToAddress(tssEth) - if tssAddr == (eth.Address{}) { - return fmt.Errorf("tss address not found") - } - if sender != tssAddr { - return fmt.Errorf("sender %s is not tss address", sender) - } - if txx.ChainId().Cmp(big.NewInt(msg.ChainId)) != 0 { - return fmt.Errorf("want evm chain id %d, got %d", txx.ChainId(), msg.ChainId) - } - if txx.Nonce() != msg.Nonce { - return fmt.Errorf("want nonce %d, got %d", txx.Nonce(), msg.Nonce) - } - if txx.Hash().Hex() != msg.TxHash { - return fmt.Errorf("want tx hash %s, got %s", txx.Hash().Hex(), msg.TxHash) - } - return nil -} - -// ValidateBTCOutTxBody validates the SegWit sender address, nonce and chain ID. -// Note: 'msg' may contain fabricated information -func ValidateBTCOutTxBody(msg *types.MsgAddToOutTxTracker, txBytes []byte, tssBtc string) error { - tx, err := btcutil.NewTxFromBytes(txBytes) - if err != nil { - return err - } - for _, vin := range tx.MsgTx().TxIn { - if len(vin.Witness) != 2 { // outTx is SegWit transaction for now - return fmt.Errorf("not a SegWit transaction") - } - pubKey, err := btcec.ParsePubKey(vin.Witness[1], btcec.S256()) - if err != nil { - return fmt.Errorf("failed to parse public key") - } - addrP2WPKH, err := btcutil.NewAddressWitnessPubKeyHash(btcutil.Hash160(pubKey.SerializeCompressed()), config.BitconNetParams) - if err != nil { - return fmt.Errorf("failed to create P2WPKH address") - } - if addrP2WPKH.EncodeAddress() != tssBtc { - return fmt.Errorf("sender %s is not tss address", addrP2WPKH.EncodeAddress()) - } - } - if common.BtcChainID() != msg.ChainId { - return fmt.Errorf("want btc chain id %d, got %d", common.BtcChainID(), msg.ChainId) - } - if len(tx.MsgTx().TxOut) < 1 { - return fmt.Errorf("outTx should have at least one output") - } - if tx.MsgTx().TxOut[0].Value != common.NonceMarkAmount(msg.Nonce) { - return fmt.Errorf("want nonce mark %d, got %d", tx.MsgTx().TxOut[0].Value, common.NonceMarkAmount(msg.Nonce)) - } - if tx.MsgTx().TxHash().String() != msg.TxHash { - return fmt.Errorf("want tx hash %s, got %s", tx.MsgTx().TxHash(), msg.TxHash) - } - return nil -} - // RemoveFromOutTxTracker removes a record from the outbound transaction tracker by chain ID and nonce. // only the admin policy account is authorized to broadcast this message. func (k msgServer) RemoveFromOutTxTracker(goCtx context.Context, msg *types.MsgRemoveFromOutTxTracker) (*types.MsgRemoveFromOutTxTrackerResponse, error) { diff --git a/x/crosschain/keeper/msg_server_add_to_intx_tracker.go b/x/crosschain/keeper/msg_server_add_to_intx_tracker.go new file mode 100644 index 0000000000..cb9510e9fd --- /dev/null +++ b/x/crosschain/keeper/msg_server_add_to_intx_tracker.go @@ -0,0 +1,105 @@ +package keeper + +import ( + "context" + "fmt" + + errorsmod "cosmossdk.io/errors" + sdk "github.com/cosmos/cosmos-sdk/types" + eth "github.com/ethereum/go-ethereum/common" + ethtypes "github.com/ethereum/go-ethereum/core/types" + "github.com/zeta-chain/zetacore/common" + "github.com/zeta-chain/zetacore/x/crosschain/types" + observertypes "github.com/zeta-chain/zetacore/x/observer/types" +) + +// TODO https://github.com/zeta-chain/node/issues/1269 +func (k msgServer) AddToInTxTracker(goCtx context.Context, msg *types.MsgAddToInTxTracker) (*types.MsgAddToInTxTrackerResponse, error) { + ctx := sdk.UnwrapSDKContext(goCtx) + chain := k.zetaObserverKeeper.GetParams(ctx).GetChainFromChainID(msg.ChainId) + if chain == nil { + return nil, observertypes.ErrSupportedChains + } + + adminPolicyAccount := k.zetaObserverKeeper.GetParams(ctx).GetAdminPolicyAccount(observertypes.Policy_Type_group1) + isAdmin := msg.Creator == adminPolicyAccount + isObserver := k.zetaObserverKeeper.IsAuthorized(ctx, msg.Creator, chain) + + isProven := false + if !(isAdmin || isObserver) && msg.Proof != nil { + txBytes, err := k.VerifyProof(ctx, msg.Proof, msg.ChainId, msg.BlockHash, msg.TxIndex) + if err != nil { + return nil, types.ErrCannotVerifyProof.Wrapf(err.Error()) + } + err = k.VerifyInTxBody(ctx, msg, txBytes) + if err != nil { + return nil, types.ErrCannotVerifyProof.Wrapf(err.Error()) + } + isProven = true + } + + // Sender needs to be either the admin policy account or an observer + if !(isAdmin || isObserver || isProven) { + return nil, errorsmod.Wrap(observertypes.ErrNotAuthorized, fmt.Sprintf("Creator %s", msg.Creator)) + } + + k.Keeper.SetInTxTracker(ctx, types.InTxTracker{ + ChainId: msg.ChainId, + TxHash: msg.TxHash, + CoinType: msg.CoinType, + }) + return &types.MsgAddToInTxTrackerResponse{}, nil +} + +// https://github.com/zeta-chain/node/issues/1254 +func (k Keeper) VerifyInTxBody(ctx sdk.Context, msg *types.MsgAddToInTxTracker, txBytes []byte) error { + // get core params and tss address + coreParams, found := k.zetaObserverKeeper.GetCoreParamsByChainID(ctx, msg.ChainId) + if !found { + return types.ErrUnsupportedChain.Wrapf("core params not found for chain %d", msg.ChainId) + } + tss, err := k.GetTssAddress(ctx, &types.QueryGetTssAddressRequest{}) + if err != nil { + return err + } + + // verify message against transaction body + if common.IsEVMChain(msg.ChainId) { + err = VerifyEVMInTxBody(coreParams, msg, txBytes, tss.Eth) + } else { + return fmt.Errorf("cannot verify inTx body for chain %d", msg.ChainId) + } + return err +} + +func VerifyEVMInTxBody(coreParams *observertypes.CoreParams, msg *types.MsgAddToInTxTracker, txBytes []byte, tssEth string) error { + var txx ethtypes.Transaction + err := txx.UnmarshalBinary(txBytes) + if err != nil { + return err + } + tssAddr := eth.HexToAddress(tssEth) + if tssAddr == (eth.Address{}) { + return fmt.Errorf("tss address not found") + } + + switch msg.CoinType { + case common.CoinType_Zeta: + if txx.To().Hex() != coreParams.ConnectorContractAddress { + return fmt.Errorf("receiver is not connector contract for coin type %s", msg.CoinType) + } + return nil + case common.CoinType_ERC20: + if txx.To().Hex() != coreParams.Erc20CustodyContractAddress { + return fmt.Errorf("receiver is not erc20Custory contract for coin type %s", msg.CoinType) + } + return nil + case common.CoinType_Gas: + if txx.To().Hex() != tssAddr.Hex() { + return fmt.Errorf("receiver is not tssAddress contract for coin type %s", msg.CoinType) + } + return nil + default: + return fmt.Errorf("coin type %s not supported", msg.CoinType) + } +} diff --git a/x/crosschain/keeper/msg_server_add_to_outtx_tracker.go b/x/crosschain/keeper/msg_server_add_to_outtx_tracker.go new file mode 100644 index 0000000000..c562f2344b --- /dev/null +++ b/x/crosschain/keeper/msg_server_add_to_outtx_tracker.go @@ -0,0 +1,181 @@ +package keeper + +import ( + "context" + "fmt" + "math/big" + "strings" + + cosmoserrors "cosmossdk.io/errors" + "github.com/btcsuite/btcd/btcec" + "github.com/btcsuite/btcutil" + sdk "github.com/cosmos/cosmos-sdk/types" + eth "github.com/ethereum/go-ethereum/common" + ethtypes "github.com/ethereum/go-ethereum/core/types" + "github.com/zeta-chain/zetacore/common" + "github.com/zeta-chain/zetacore/x/crosschain/types" + observertypes "github.com/zeta-chain/zetacore/x/observer/types" + "github.com/zeta-chain/zetacore/zetaclient/config" +) + +// AddToOutTxTracker adds a new record to the outbound transaction tracker. +// only the admin policy account and the observer validators are authorized to broadcast this message without proof. +func (k msgServer) AddToOutTxTracker(goCtx context.Context, msg *types.MsgAddToOutTxTracker) (*types.MsgAddToOutTxTrackerResponse, error) { + ctx := sdk.UnwrapSDKContext(goCtx) + chain := k.zetaObserverKeeper.GetParams(ctx).GetChainFromChainID(msg.ChainId) + if chain == nil { + return nil, observertypes.ErrSupportedChains + } + + if msg.Proof == nil { // without proof, only certain accounts can send this message + adminPolicyAccount := k.zetaObserverKeeper.GetParams(ctx).GetAdminPolicyAccount(observertypes.Policy_Type_group1) + isAdmin := msg.Creator == adminPolicyAccount + isObserver := k.zetaObserverKeeper.IsAuthorized(ctx, msg.Creator, chain) + + // Sender needs to be either the admin policy account or an observer + if !(isAdmin || isObserver) { + return nil, cosmoserrors.Wrap(observertypes.ErrNotAuthorized, fmt.Sprintf("Creator %s", msg.Creator)) + } + } + + isProven := false + if msg.Proof != nil { // verify proof when it is provided + txBytes, err := k.VerifyProof(ctx, msg.Proof, msg.ChainId, msg.BlockHash, msg.TxIndex) + if err != nil { + return nil, types.ErrProofVerificationFail.Wrapf(err.Error()) + } + err = k.VerifyOutTxBody(ctx, msg, txBytes) + if err != nil { + return nil, types.ErrTxBodyVerificationFail.Wrapf(err.Error()) + } + isProven = true + } + + tracker, found := k.GetOutTxTracker(ctx, msg.ChainId, msg.Nonce) + hash := types.TxHashList{ + TxHash: msg.TxHash, + TxSigner: msg.Creator, + } + if !found { + k.SetOutTxTracker(ctx, types.OutTxTracker{ + Index: "", + ChainId: chain.ChainId, + Nonce: msg.Nonce, + HashList: []*types.TxHashList{&hash}, + }) + return &types.MsgAddToOutTxTrackerResponse{}, nil + } + + var isDup = false + for _, hash := range tracker.HashList { + if strings.EqualFold(hash.TxHash, msg.TxHash) { + isDup = true + if isProven { + hash.Proved = true + k.SetOutTxTracker(ctx, tracker) + k.Logger(ctx).Info("Proof'd outbound transaction") + return &types.MsgAddToOutTxTrackerResponse{}, nil + } + break + } + } + if !isDup { + if isProven { + hash.Proved = true + tracker.HashList = append([]*types.TxHashList{&hash}, tracker.HashList...) + k.Logger(ctx).Info("Proof'd outbound transaction") + } else { + tracker.HashList = append(tracker.HashList, &hash) + } + k.SetOutTxTracker(ctx, tracker) + } + return &types.MsgAddToOutTxTrackerResponse{}, nil +} + +func (k Keeper) VerifyOutTxBody(ctx sdk.Context, msg *types.MsgAddToOutTxTracker, txBytes []byte) error { + // get tss address + tss, err := k.GetTssAddress(ctx, &types.QueryGetTssAddressRequest{}) + if err != nil { + return err + } + + // verify message against transaction body + if common.IsEVMChain(msg.ChainId) { + err = VerifyEVMOutTxBody(msg, txBytes, tss.Eth) + } else if common.IsBitcoinChain(msg.ChainId) { + err = VerifyBTCOutTxBody(msg, txBytes, tss.Btc) + } else { + return fmt.Errorf("cannot verify outTx body for chain %d", msg.ChainId) + } + return err +} + +// VerifyEVMOutTxBody validates the sender address, nonce, chain id and tx hash. +// Note: 'msg' may contain fabricated information +func VerifyEVMOutTxBody(msg *types.MsgAddToOutTxTracker, txBytes []byte, tssEth string) error { + var txx ethtypes.Transaction + err := txx.UnmarshalBinary(txBytes) + if err != nil { + return err + } + signer := ethtypes.NewLondonSigner(txx.ChainId()) + sender, err := ethtypes.Sender(signer, &txx) + if err != nil { + return err + } + tssAddr := eth.HexToAddress(tssEth) + if tssAddr == (eth.Address{}) { + return fmt.Errorf("tss address not found") + } + if sender != tssAddr { + return fmt.Errorf("sender %s is not tss address", sender) + } + if txx.ChainId().Cmp(big.NewInt(msg.ChainId)) != 0 { + return fmt.Errorf("want evm chain id %d, got %d", txx.ChainId(), msg.ChainId) + } + if txx.Nonce() != msg.Nonce { + return fmt.Errorf("want nonce %d, got %d", txx.Nonce(), msg.Nonce) + } + if txx.Hash().Hex() != msg.TxHash { + return fmt.Errorf("want tx hash %s, got %s", txx.Hash().Hex(), msg.TxHash) + } + return nil +} + +// VerifyBTCOutTxBody validates the SegWit sender address, nonce and chain id and tx hash +// Note: 'msg' may contain fabricated information +func VerifyBTCOutTxBody(msg *types.MsgAddToOutTxTracker, txBytes []byte, tssBtc string) error { + tx, err := btcutil.NewTxFromBytes(txBytes) + if err != nil { + return err + } + for _, vin := range tx.MsgTx().TxIn { + if len(vin.Witness) != 2 { // outTx is SegWit transaction for now + return fmt.Errorf("not a SegWit transaction") + } + pubKey, err := btcec.ParsePubKey(vin.Witness[1], btcec.S256()) + if err != nil { + return fmt.Errorf("failed to parse public key") + } + addrP2WPKH, err := btcutil.NewAddressWitnessPubKeyHash(btcutil.Hash160(pubKey.SerializeCompressed()), config.BitconNetParams) + if err != nil { + return fmt.Errorf("failed to create P2WPKH address") + } + if addrP2WPKH.EncodeAddress() != tssBtc { + return fmt.Errorf("sender %s is not tss address", addrP2WPKH.EncodeAddress()) + } + } + if common.BtcChainID() != msg.ChainId { + return fmt.Errorf("want btc chain id %d, got %d", common.BtcChainID(), msg.ChainId) + } + if len(tx.MsgTx().TxOut) < 1 { + return fmt.Errorf("outTx should have at least one output") + } + if tx.MsgTx().TxOut[0].Value != common.NonceMarkAmount(msg.Nonce) { + return fmt.Errorf("want nonce mark %d, got %d", tx.MsgTx().TxOut[0].Value, common.NonceMarkAmount(msg.Nonce)) + } + if tx.MsgTx().TxHash().String() != msg.TxHash { + return fmt.Errorf("want tx hash %s, got %s", tx.MsgTx().TxHash(), msg.TxHash) + } + return nil +} diff --git a/x/crosschain/keeper/verify_block_header.go b/x/crosschain/keeper/verify_block_header.go new file mode 100644 index 0000000000..92f389987e --- /dev/null +++ b/x/crosschain/keeper/verify_block_header.go @@ -0,0 +1,53 @@ +package keeper + +import ( + "fmt" + + sdk "github.com/cosmos/cosmos-sdk/types" + "github.com/zeta-chain/zetacore/common" + "github.com/zeta-chain/zetacore/x/crosschain/types" +) + +func (k Keeper) VerifyProof(ctx sdk.Context, proof *common.Proof, chainID int64, blockHash string, txIndex int64) ([]byte, error) { + // header-based merkle proof verification must be enabled + crosschainFlags, found := k.zetaObserverKeeper.GetCrosschainFlags(ctx) + if !found { + return nil, fmt.Errorf("crosschain flags not found") + } + if crosschainFlags.BlockHeaderVerificationFlags == nil { + return nil, fmt.Errorf("block header verification flags not found") + } + if common.IsBitcoinChain(chainID) && !crosschainFlags.BlockHeaderVerificationFlags.IsBtcTypeChainEnabled { + return nil, fmt.Errorf("proof verification not enabled for bitcoin chain") + } + if common.IsEVMChain(chainID) && !crosschainFlags.BlockHeaderVerificationFlags.IsEthTypeChainEnabled { + return nil, fmt.Errorf("proof verification not enabled for evm chain") + } + + // chain must support header-based merkle proof verification + senderChain := common.GetChainFromChainID(chainID) + if senderChain == nil { + return nil, types.ErrUnsupportedChain + } + if !senderChain.SupportMerkleProof() { + return nil, fmt.Errorf("chain %d does not support block header-based verification", chainID) + } + + // get block header from the store + hashBytes, err := common.StringToHash(chainID, blockHash) + if err != nil { + return nil, fmt.Errorf("block hash %s conversion failed %s", blockHash, err) + } + res, found := k.zetaObserverKeeper.GetBlockHeader(ctx, hashBytes) + if !found { + return nil, fmt.Errorf("block header not found %s", blockHash) + } + + // verify merkle proof + txBytes, err := proof.Verify(res.Header, int(txIndex)) + if err != nil { + return nil, err + } + + return txBytes, err +} diff --git a/x/crosschain/types/errors.go b/x/crosschain/types/errors.go index 32d07bc636..c9186f9795 100644 --- a/x/crosschain/types/errors.go +++ b/x/crosschain/types/errors.go @@ -30,8 +30,8 @@ var ( ErrNotEnoughGas = errorsmod.Register(ModuleName, 1131, "not enough gas") ErrNotEnoughFunds = errorsmod.Register(ModuleName, 1132, "not enough funds") - ErrProofVerificationFail = errorsmod.Register(ModuleName, 1133, "Proof verification fail") - ErrCannotFindCctx = errorsmod.Register(ModuleName, 1134, "Cannot find cctx") + ErrProofVerificationFail = errorsmod.Register(ModuleName, 1133, "proof verification fail") + ErrCannotFindCctx = errorsmod.Register(ModuleName, 1134, "cannot find cctx") ErrStatusNotPending = errorsmod.Register(ModuleName, 1135, "Status not pending") ErrCannotFindGasParams = errorsmod.Register(ModuleName, 1136, "cannot find gas params") @@ -39,4 +39,7 @@ var ( ErrNoLiquidityPool = errorsmod.Register(ModuleName, 1138, "no liquidity pool") ErrInvalidCoinType = errorsmod.Register(ModuleName, 1139, "invalid coin type") ErrCannotMigrateTss = errorsmod.Register(ModuleName, 1140, "Cannot migrate TSS funds") + + ErrCannotVerifyProof = errorsmod.Register(ModuleName, 1141, "cannot verify proof") + ErrTxBodyVerificationFail = errorsmod.Register(ModuleName, 1142, "transaction body verification fail") ) diff --git a/x/crosschain/types/genesis.pb.go b/x/crosschain/types/genesis.pb.go index b5e24bfca0..c1b357ebad 100644 --- a/x/crosschain/types/genesis.pb.go +++ b/x/crosschain/types/genesis.pb.go @@ -35,6 +35,7 @@ type GenesisState struct { LastBlockHeightList []*LastBlockHeight `protobuf:"bytes,8,rep,name=lastBlockHeightList,proto3" json:"lastBlockHeightList,omitempty"` InTxHashToCctxList []InTxHashToCctx `protobuf:"bytes,9,rep,name=inTxHashToCctxList,proto3" json:"inTxHashToCctxList"` TssHistory []TSS `protobuf:"bytes,10,rep,name=tss_history,json=tssHistory,proto3" json:"tss_history"` + InTxTrackerList []InTxTracker `protobuf:"bytes,11,rep,name=in_tx_tracker_list,json=inTxTrackerList,proto3" json:"in_tx_tracker_list"` } func (m *GenesisState) Reset() { *m = GenesisState{} } @@ -133,6 +134,13 @@ func (m *GenesisState) GetTssHistory() []TSS { return nil } +func (m *GenesisState) GetInTxTrackerList() []InTxTracker { + if m != nil { + return m.InTxTrackerList + } + return nil +} + func init() { proto.RegisterType((*GenesisState)(nil), "zetachain.zetacore.crosschain.GenesisState") } @@ -140,38 +148,39 @@ func init() { func init() { proto.RegisterFile("crosschain/genesis.proto", fileDescriptor_dd51403692d571f4) } var fileDescriptor_dd51403692d571f4 = []byte{ - // 488 bytes of a gzipped FileDescriptorProto - 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x8c, 0x93, 0xd1, 0x6a, 0x13, 0x41, - 0x14, 0x86, 0xb3, 0xb6, 0x8d, 0x3a, 0xa9, 0x28, 0xa3, 0xe0, 0x12, 0xe8, 0xb6, 0x44, 0xc4, 0xa2, - 0x74, 0x17, 0xab, 0x4f, 0x90, 0x5c, 0x34, 0xa5, 0x45, 0xeb, 0x66, 0xaf, 0x04, 0x59, 0x27, 0xc3, - 0xb0, 0xbb, 0xb4, 0xcd, 0x84, 0x3d, 0x27, 0xb0, 0xf5, 0x29, 0x7c, 0xac, 0x5e, 0xf6, 0xd2, 0x2b, - 0x91, 0xe4, 0x05, 0x7c, 0x04, 0x99, 0xb3, 0xd3, 0x76, 0xa2, 0xc1, 0xed, 0xcd, 0x72, 0xd8, 0xf3, - 0xff, 0xdf, 0xf9, 0x99, 0x39, 0xc3, 0x7c, 0x59, 0x6a, 0x00, 0x99, 0x8b, 0x62, 0x12, 0x65, 0x6a, - 0xa2, 0xa0, 0x80, 0x70, 0x5a, 0x6a, 0xd4, 0x7c, 0xeb, 0x9b, 0x42, 0x41, 0x8d, 0x90, 0x2a, 0x5d, - 0xaa, 0xf0, 0x56, 0xdc, 0xdd, 0x72, 0x8c, 0xf4, 0x4d, 0x27, 0x7a, 0x22, 0x95, 0x75, 0x77, 0xb7, - 0xdd, 0xb6, 0x29, 0xd3, 0x5a, 0x84, 0x95, 0x15, 0x74, 0xdd, 0xc1, 0x02, 0xd2, 0x69, 0x59, 0x48, - 0x65, 0x7b, 0x2f, 0x9c, 0x1e, 0x79, 0xd2, 0x5c, 0x40, 0x9e, 0xa2, 0x4e, 0xa5, 0xbc, 0x01, 0xf4, - 0x1c, 0xd1, 0x99, 0x00, 0x4c, 0xc7, 0x67, 0x5a, 0x9e, 0xa6, 0xb9, 0x2a, 0xb2, 0x1c, 0x57, 0xa4, - 0xd0, 0x33, 0x34, 0x24, 0x2c, 0x85, 0x3c, 0x55, 0xa5, 0x15, 0x3c, 0x77, 0x04, 0x53, 0x51, 0x8a, - 0xf3, 0xeb, 0xfc, 0xcf, 0x9c, 0x06, 0xc2, 0xcd, 0xdf, 0x4c, 0x67, 0x9a, 0xca, 0xc8, 0x54, 0xf5, - 0xdf, 0xde, 0xef, 0x0d, 0xb6, 0x79, 0x50, 0x9f, 0xdd, 0x08, 0x05, 0x2a, 0x3e, 0x60, 0xed, 0x1a, - 0xe6, 0x7b, 0x3b, 0xde, 0x6e, 0x67, 0xff, 0x65, 0xf8, 0xdf, 0xb3, 0x0c, 0x4f, 0x48, 0xdc, 0x5f, - 0xbf, 0xfc, 0xb9, 0xdd, 0x8a, 0xad, 0x95, 0x7f, 0x61, 0x4f, 0xf4, 0x0c, 0x93, 0x2a, 0xa9, 0x03, - 0x1f, 0x17, 0x80, 0xfe, 0xbd, 0x9d, 0xb5, 0xdd, 0xce, 0xfe, 0x9b, 0x06, 0xdc, 0x47, 0xc7, 0x66, - 0xa1, 0xff, 0xa0, 0xf8, 0x7b, 0xb6, 0x86, 0x00, 0xfe, 0x3a, 0x05, 0xec, 0x35, 0x10, 0x93, 0xd1, - 0x28, 0x36, 0x72, 0x7e, 0xc4, 0x36, 0x33, 0x01, 0x27, 0xe6, 0xae, 0x28, 0xd0, 0x06, 0x05, 0x7a, - 0xd5, 0x60, 0x3f, 0xb0, 0x96, 0x78, 0xc9, 0xcc, 0x13, 0xf6, 0x98, 0xfa, 0x1f, 0x68, 0x71, 0x88, - 0xd7, 0x26, 0xde, 0xeb, 0x06, 0xde, 0xe0, 0xd6, 0x15, 0xff, 0x8d, 0xe0, 0x9f, 0xd8, 0xa3, 0x81, - 0x91, 0x92, 0x28, 0xa9, 0xc0, 0xbf, 0x7f, 0xa7, 0x43, 0x73, 0x3d, 0xf1, 0x32, 0x81, 0x7f, 0x65, - 0x4f, 0xcd, 0x86, 0xf5, 0xcd, 0x82, 0x0d, 0x69, 0xbf, 0x28, 0xec, 0x03, 0x02, 0x87, 0x0d, 0xe0, - 0xe3, 0x65, 0x67, 0xbc, 0x0a, 0xc5, 0x25, 0xe3, 0x66, 0xd4, 0x50, 0x40, 0x9e, 0xe8, 0x81, 0xc4, - 0x8a, 0x06, 0x3c, 0xa4, 0x01, 0x7b, 0x0d, 0x03, 0x0e, 0x97, 0x8c, 0xf6, 0xc2, 0x57, 0xe0, 0xf8, - 0x21, 0xeb, 0x20, 0x40, 0x9a, 0x17, 0x80, 0xba, 0xbc, 0xf0, 0x19, 0xd1, 0xef, 0x70, 0xf5, 0x16, - 0xc9, 0x10, 0x60, 0x58, 0x7b, 0xfb, 0x47, 0x97, 0xf3, 0xc0, 0xbb, 0x9a, 0x07, 0xde, 0xaf, 0x79, - 0xe0, 0x7d, 0x5f, 0x04, 0xad, 0xab, 0x45, 0xd0, 0xfa, 0xb1, 0x08, 0x5a, 0x9f, 0xdf, 0x66, 0x05, - 0xe6, 0xb3, 0x71, 0x28, 0xf5, 0x79, 0x64, 0x78, 0x7b, 0xf5, 0x1b, 0xba, 0x46, 0x47, 0x55, 0xe4, - 0xbe, 0xac, 0x8b, 0xa9, 0x82, 0x71, 0x9b, 0x9e, 0xd1, 0xbb, 0x3f, 0x01, 0x00, 0x00, 0xff, 0xff, - 0xe0, 0xed, 0xc4, 0xaf, 0x8c, 0x04, 0x00, 0x00, + // 512 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x8c, 0x93, 0xd1, 0x6e, 0xd3, 0x30, + 0x14, 0x86, 0x1b, 0x36, 0x0a, 0xb8, 0x43, 0x43, 0x06, 0x89, 0xa8, 0xd2, 0xb2, 0xa9, 0x08, 0x31, + 0x81, 0x96, 0x88, 0xc1, 0x13, 0xb4, 0x17, 0xeb, 0xb4, 0x09, 0x46, 0x9a, 0x2b, 0xa4, 0xc9, 0xb8, + 0x96, 0x95, 0x44, 0xeb, 0xe2, 0x2a, 0xc7, 0x95, 0x32, 0x9e, 0x82, 0xc7, 0xda, 0x1d, 0xbb, 0xe4, + 0x0a, 0xa1, 0xf6, 0x45, 0x90, 0x4f, 0xb2, 0xcd, 0xa1, 0x15, 0xe9, 0x4d, 0x65, 0xe5, 0xfc, 0xff, + 0x77, 0xfe, 0xda, 0xe7, 0x10, 0x57, 0xe4, 0x0a, 0x40, 0x24, 0x3c, 0xcd, 0x82, 0x58, 0x66, 0x12, + 0x52, 0xf0, 0xa7, 0xb9, 0xd2, 0x8a, 0xee, 0x7c, 0x97, 0x9a, 0x63, 0xc1, 0xc7, 0x93, 0xca, 0xa5, + 0x7f, 0x2f, 0xee, 0xee, 0x58, 0x46, 0xfc, 0x65, 0x99, 0xca, 0x84, 0xac, 0xdc, 0xdd, 0x5d, 0xbb, + 0x6c, 0x8e, 0xac, 0x14, 0xe9, 0xa2, 0x12, 0x74, 0xed, 0xc6, 0x1c, 0xd8, 0x34, 0x4f, 0x85, 0xac, + 0x6a, 0xaf, 0xac, 0x1a, 0x7a, 0x58, 0xc2, 0x21, 0x61, 0x5a, 0x31, 0x21, 0xee, 0x00, 0xde, 0x92, + 0x48, 0xe7, 0x5c, 0x5c, 0xc8, 0xbc, 0xaa, 0xf7, 0xac, 0xfa, 0x84, 0x83, 0x66, 0xe3, 0x89, 0x12, + 0x17, 0x2c, 0x91, 0x69, 0x9c, 0xe8, 0x15, 0x29, 0xd5, 0x4c, 0x2f, 0x43, 0x5e, 0x5a, 0x82, 0x29, + 0xcf, 0xf9, 0xe5, 0xed, 0xff, 0x7b, 0x61, 0x15, 0x34, 0xdc, 0x7d, 0x8d, 0x55, 0xac, 0xf0, 0x18, + 0x98, 0x53, 0xf9, 0xb5, 0xf7, 0xb3, 0x4d, 0xb6, 0x8e, 0xca, 0xbb, 0x1d, 0x69, 0xae, 0x25, 0x1d, + 0x90, 0x76, 0x09, 0x73, 0x9d, 0x3d, 0x67, 0xbf, 0x73, 0xf8, 0xda, 0xff, 0xef, 0x5d, 0xfb, 0x67, + 0x28, 0xee, 0x6f, 0x5e, 0xff, 0xde, 0x6d, 0x85, 0x95, 0x95, 0x9e, 0x93, 0x67, 0x6a, 0xa6, 0xa3, + 0x22, 0x2a, 0x03, 0x9f, 0xa6, 0xa0, 0xdd, 0x07, 0x7b, 0x1b, 0xfb, 0x9d, 0xc3, 0x77, 0x0d, 0xb8, + 0xcf, 0x96, 0xad, 0x82, 0x2e, 0xa1, 0xe8, 0x47, 0xb2, 0xa1, 0x01, 0xdc, 0x4d, 0x0c, 0xd8, 0x6b, + 0x20, 0x46, 0xa3, 0x51, 0x68, 0xe4, 0xf4, 0x84, 0x6c, 0xc5, 0x1c, 0xce, 0xcc, 0x5b, 0x62, 0xa0, + 0x87, 0x18, 0xe8, 0x4d, 0x83, 0xfd, 0xa8, 0xb2, 0x84, 0x35, 0x33, 0x8d, 0xc8, 0x36, 0xd6, 0x3f, + 0xe1, 0x60, 0x21, 0xaf, 0x8d, 0xbc, 0xb7, 0x0d, 0xbc, 0xc1, 0xbd, 0x2b, 0xfc, 0x17, 0x41, 0xbf, + 0x90, 0xa7, 0x03, 0x23, 0x45, 0x51, 0x54, 0x80, 0xfb, 0x68, 0xad, 0x4b, 0xb3, 0x3d, 0x61, 0x9d, + 0x40, 0xbf, 0x91, 0xe7, 0x66, 0xc2, 0xfa, 0x66, 0xc0, 0x86, 0x38, 0x5f, 0x18, 0xf6, 0x31, 0x82, + 0xfd, 0x06, 0xf0, 0x69, 0xdd, 0x19, 0xae, 0x42, 0x51, 0x41, 0xa8, 0x69, 0x35, 0xe4, 0x90, 0x44, + 0x6a, 0x20, 0x74, 0x81, 0x0d, 0x9e, 0x60, 0x83, 0x83, 0x86, 0x06, 0xc7, 0x35, 0x63, 0xf5, 0xe0, + 0x2b, 0x70, 0xf4, 0x98, 0x74, 0x34, 0x00, 0x4b, 0x52, 0xd0, 0x2a, 0xbf, 0x72, 0x09, 0xd2, 0xd7, + 0x78, 0xfa, 0x0a, 0x49, 0x34, 0xc0, 0xb0, 0xf4, 0xd2, 0x73, 0x93, 0xd7, 0x5a, 0x27, 0x36, 0x31, + 0x79, 0x3b, 0x6b, 0xbd, 0x9e, 0xc9, 0x5b, 0x9f, 0xce, 0xed, 0x34, 0xab, 0x0d, 0x67, 0xff, 0xe4, + 0x7a, 0xee, 0x39, 0x37, 0x73, 0xcf, 0xf9, 0x33, 0xf7, 0x9c, 0x1f, 0x0b, 0xaf, 0x75, 0xb3, 0xf0, + 0x5a, 0xbf, 0x16, 0x5e, 0xeb, 0xeb, 0xfb, 0x38, 0xd5, 0xc9, 0x6c, 0xec, 0x0b, 0x75, 0x19, 0x18, + 0xf8, 0x41, 0xb9, 0xa2, 0xb7, 0x7d, 0x82, 0x22, 0xb0, 0x17, 0xf7, 0x6a, 0x2a, 0x61, 0xdc, 0xc6, + 0x2d, 0xfd, 0xf0, 0x37, 0x00, 0x00, 0xff, 0xff, 0xeb, 0x12, 0x5d, 0x65, 0x0b, 0x05, 0x00, 0x00, } func (m *GenesisState) Marshal() (dAtA []byte, err error) { @@ -194,6 +203,20 @@ func (m *GenesisState) MarshalToSizedBuffer(dAtA []byte) (int, error) { _ = i var l int _ = l + if len(m.InTxTrackerList) > 0 { + for iNdEx := len(m.InTxTrackerList) - 1; iNdEx >= 0; iNdEx-- { + { + size, err := m.InTxTrackerList[iNdEx].MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarintGenesis(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0x5a + } + } if len(m.TssHistory) > 0 { for iNdEx := len(m.TssHistory) - 1; iNdEx >= 0; iNdEx-- { { @@ -382,6 +405,12 @@ func (m *GenesisState) Size() (n int) { n += 1 + l + sovGenesis(uint64(l)) } } + if len(m.InTxTrackerList) > 0 { + for _, e := range m.InTxTrackerList { + l = e.Size() + n += 1 + l + sovGenesis(uint64(l)) + } + } return n } @@ -727,6 +756,40 @@ func (m *GenesisState) Unmarshal(dAtA []byte) error { return err } iNdEx = postIndex + case 11: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field InTxTrackerList", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowGenesis + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return ErrInvalidLengthGenesis + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return ErrInvalidLengthGenesis + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.InTxTrackerList = append(m.InTxTrackerList, InTxTracker{}) + if err := m.InTxTrackerList[len(m.InTxTrackerList)-1].Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex default: iNdEx = preIndex skippy, err := skipGenesis(dAtA[iNdEx:]) diff --git a/x/crosschain/types/in_tx_tracker.pb.go b/x/crosschain/types/in_tx_tracker.pb.go new file mode 100644 index 0000000000..75074880b6 --- /dev/null +++ b/x/crosschain/types/in_tx_tracker.pb.go @@ -0,0 +1,391 @@ +// Code generated by protoc-gen-gogo. DO NOT EDIT. +// source: crosschain/in_tx_tracker.proto + +package types + +import ( + fmt "fmt" + io "io" + math "math" + math_bits "math/bits" + + proto "github.com/gogo/protobuf/proto" + common "github.com/zeta-chain/zetacore/common" +) + +// Reference imports to suppress errors if they are not otherwise used. +var _ = proto.Marshal +var _ = fmt.Errorf +var _ = math.Inf + +// This is a compile-time assertion to ensure that this generated file +// is compatible with the proto package it is being compiled against. +// A compilation error at this line likely means your copy of the +// proto package needs to be updated. +const _ = proto.GoGoProtoPackageIsVersion3 // please upgrade the proto package + +type InTxTracker struct { + ChainId int64 `protobuf:"varint,1,opt,name=chain_id,json=chainId,proto3" json:"chain_id,omitempty"` + TxHash string `protobuf:"bytes,2,opt,name=tx_hash,json=txHash,proto3" json:"tx_hash,omitempty"` + CoinType common.CoinType `protobuf:"varint,3,opt,name=coin_type,json=coinType,proto3,enum=common.CoinType" json:"coin_type,omitempty"` +} + +func (m *InTxTracker) Reset() { *m = InTxTracker{} } +func (m *InTxTracker) String() string { return proto.CompactTextString(m) } +func (*InTxTracker) ProtoMessage() {} +func (*InTxTracker) Descriptor() ([]byte, []int) { + return fileDescriptor_799b411f065af0ce, []int{0} +} +func (m *InTxTracker) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *InTxTracker) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_InTxTracker.Marshal(b, m, deterministic) + } else { + b = b[:cap(b)] + n, err := m.MarshalToSizedBuffer(b) + if err != nil { + return nil, err + } + return b[:n], nil + } +} +func (m *InTxTracker) XXX_Merge(src proto.Message) { + xxx_messageInfo_InTxTracker.Merge(m, src) +} +func (m *InTxTracker) XXX_Size() int { + return m.Size() +} +func (m *InTxTracker) XXX_DiscardUnknown() { + xxx_messageInfo_InTxTracker.DiscardUnknown(m) +} + +var xxx_messageInfo_InTxTracker proto.InternalMessageInfo + +func (m *InTxTracker) GetChainId() int64 { + if m != nil { + return m.ChainId + } + return 0 +} + +func (m *InTxTracker) GetTxHash() string { + if m != nil { + return m.TxHash + } + return "" +} + +func (m *InTxTracker) GetCoinType() common.CoinType { + if m != nil { + return m.CoinType + } + return common.CoinType_Zeta +} + +func init() { + proto.RegisterType((*InTxTracker)(nil), "zetachain.zetacore.crosschain.InTxTracker") +} + +func init() { proto.RegisterFile("crosschain/in_tx_tracker.proto", fileDescriptor_799b411f065af0ce) } + +var fileDescriptor_799b411f065af0ce = []byte{ + // 237 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xe2, 0x92, 0x4b, 0x2e, 0xca, 0x2f, + 0x2e, 0x4e, 0xce, 0x48, 0xcc, 0xcc, 0xd3, 0xcf, 0xcc, 0x8b, 0x2f, 0xa9, 0x88, 0x2f, 0x29, 0x4a, + 0x4c, 0xce, 0x4e, 0x2d, 0xd2, 0x2b, 0x28, 0xca, 0x2f, 0xc9, 0x17, 0x92, 0xad, 0x4a, 0x2d, 0x49, + 0x04, 0x4b, 0xeb, 0x81, 0x59, 0xf9, 0x45, 0xa9, 0x7a, 0x08, 0x2d, 0x52, 0xc2, 0xc9, 0xf9, 0xb9, + 0xb9, 0xf9, 0x79, 0xfa, 0x10, 0x0a, 0xa2, 0x47, 0xa9, 0x80, 0x8b, 0xdb, 0x33, 0x2f, 0xa4, 0x22, + 0x04, 0x62, 0x90, 0x90, 0x24, 0x17, 0x07, 0x58, 0x71, 0x7c, 0x66, 0x8a, 0x04, 0xa3, 0x02, 0xa3, + 0x06, 0x73, 0x10, 0x3b, 0x98, 0xef, 0x99, 0x22, 0x24, 0xce, 0xc5, 0x5e, 0x52, 0x11, 0x9f, 0x91, + 0x58, 0x9c, 0x21, 0xc1, 0xa4, 0xc0, 0xa8, 0xc1, 0x19, 0xc4, 0x56, 0x52, 0xe1, 0x91, 0x58, 0x9c, + 0x21, 0xa4, 0xcb, 0xc5, 0x99, 0x9c, 0x0f, 0x72, 0x4f, 0x65, 0x41, 0xaa, 0x04, 0xb3, 0x02, 0xa3, + 0x06, 0x9f, 0x91, 0x80, 0x1e, 0xd4, 0x12, 0xe7, 0xfc, 0xcc, 0xbc, 0x90, 0xca, 0x82, 0xd4, 0x20, + 0x8e, 0x64, 0x28, 0xcb, 0xc9, 0xfb, 0xc4, 0x23, 0x39, 0xc6, 0x0b, 0x8f, 0xe4, 0x18, 0x1f, 0x3c, + 0x92, 0x63, 0x9c, 0xf0, 0x58, 0x8e, 0xe1, 0xc2, 0x63, 0x39, 0x86, 0x1b, 0x8f, 0xe5, 0x18, 0xa2, + 0x0c, 0xd3, 0x33, 0x4b, 0x32, 0x4a, 0x93, 0x40, 0x7a, 0xf5, 0x41, 0x1e, 0xd0, 0x85, 0x78, 0x15, + 0xe6, 0x17, 0xfd, 0x0a, 0x7d, 0xa4, 0x00, 0x00, 0xd9, 0x56, 0x9c, 0xc4, 0x06, 0xf6, 0x85, 0x31, + 0x20, 0x00, 0x00, 0xff, 0xff, 0x60, 0xe9, 0x97, 0x6f, 0x1b, 0x01, 0x00, 0x00, +} + +func (m *InTxTracker) Marshal() (dAtA []byte, err error) { + size := m.Size() + dAtA = make([]byte, size) + n, err := m.MarshalToSizedBuffer(dAtA[:size]) + if err != nil { + return nil, err + } + return dAtA[:n], nil +} + +func (m *InTxTracker) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *InTxTracker) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + if m.CoinType != 0 { + i = encodeVarintInTxTracker(dAtA, i, uint64(m.CoinType)) + i-- + dAtA[i] = 0x18 + } + if len(m.TxHash) > 0 { + i -= len(m.TxHash) + copy(dAtA[i:], m.TxHash) + i = encodeVarintInTxTracker(dAtA, i, uint64(len(m.TxHash))) + i-- + dAtA[i] = 0x12 + } + if m.ChainId != 0 { + i = encodeVarintInTxTracker(dAtA, i, uint64(m.ChainId)) + i-- + dAtA[i] = 0x8 + } + return len(dAtA) - i, nil +} + +func encodeVarintInTxTracker(dAtA []byte, offset int, v uint64) int { + offset -= sovInTxTracker(v) + base := offset + for v >= 1<<7 { + dAtA[offset] = uint8(v&0x7f | 0x80) + v >>= 7 + offset++ + } + dAtA[offset] = uint8(v) + return base +} +func (m *InTxTracker) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + if m.ChainId != 0 { + n += 1 + sovInTxTracker(uint64(m.ChainId)) + } + l = len(m.TxHash) + if l > 0 { + n += 1 + l + sovInTxTracker(uint64(l)) + } + if m.CoinType != 0 { + n += 1 + sovInTxTracker(uint64(m.CoinType)) + } + return n +} + +func sovInTxTracker(x uint64) (n int) { + return (math_bits.Len64(x|1) + 6) / 7 +} +func sozInTxTracker(x uint64) (n int) { + return sovInTxTracker(uint64((x << 1) ^ uint64((int64(x) >> 63)))) +} +func (m *InTxTracker) Unmarshal(dAtA []byte) error { + l := len(dAtA) + iNdEx := 0 + for iNdEx < l { + preIndex := iNdEx + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowInTxTracker + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + fieldNum := int32(wire >> 3) + wireType := int(wire & 0x7) + if wireType == 4 { + return fmt.Errorf("proto: InTxTracker: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: InTxTracker: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field ChainId", wireType) + } + m.ChainId = 0 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowInTxTracker + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + m.ChainId |= int64(b&0x7F) << shift + if b < 0x80 { + break + } + } + case 2: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field TxHash", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowInTxTracker + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + stringLen |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + intStringLen := int(stringLen) + if intStringLen < 0 { + return ErrInvalidLengthInTxTracker + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthInTxTracker + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.TxHash = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + case 3: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field CoinType", wireType) + } + m.CoinType = 0 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowInTxTracker + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + m.CoinType |= common.CoinType(b&0x7F) << shift + if b < 0x80 { + break + } + } + default: + iNdEx = preIndex + skippy, err := skipInTxTracker(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return ErrInvalidLengthInTxTracker + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func skipInTxTracker(dAtA []byte) (n int, err error) { + l := len(dAtA) + iNdEx := 0 + depth := 0 + for iNdEx < l { + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return 0, ErrIntOverflowInTxTracker + } + if iNdEx >= l { + return 0, io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= (uint64(b) & 0x7F) << shift + if b < 0x80 { + break + } + } + wireType := int(wire & 0x7) + switch wireType { + case 0: + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return 0, ErrIntOverflowInTxTracker + } + if iNdEx >= l { + return 0, io.ErrUnexpectedEOF + } + iNdEx++ + if dAtA[iNdEx-1] < 0x80 { + break + } + } + case 1: + iNdEx += 8 + case 2: + var length int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return 0, ErrIntOverflowInTxTracker + } + if iNdEx >= l { + return 0, io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + length |= (int(b) & 0x7F) << shift + if b < 0x80 { + break + } + } + if length < 0 { + return 0, ErrInvalidLengthInTxTracker + } + iNdEx += length + case 3: + depth++ + case 4: + if depth == 0 { + return 0, ErrUnexpectedEndOfGroupInTxTracker + } + depth-- + case 5: + iNdEx += 4 + default: + return 0, fmt.Errorf("proto: illegal wireType %d", wireType) + } + if iNdEx < 0 { + return 0, ErrInvalidLengthInTxTracker + } + if depth == 0 { + return iNdEx, nil + } + } + return 0, io.ErrUnexpectedEOF +} + +var ( + ErrInvalidLengthInTxTracker = fmt.Errorf("proto: negative length found during unmarshaling") + ErrIntOverflowInTxTracker = fmt.Errorf("proto: integer overflow") + ErrUnexpectedEndOfGroupInTxTracker = fmt.Errorf("proto: unexpected end of group") +) diff --git a/x/crosschain/types/keys.go b/x/crosschain/types/keys.go index 247ab676ac..5af95e2e3c 100644 --- a/x/crosschain/types/keys.go +++ b/x/crosschain/types/keys.go @@ -54,6 +54,7 @@ const ( TSSHistoryKey = "TSS-History-value-" OutTxTrackerKeyPrefix = "OutTxTracker-value-" + InTxTrackerKeyPrefix = "InTxTracker-value-" NonceToCctxKeyPrefix = "NonceToCctx-value-" PendingNoncesKeyPrefix = "PendingNonces-value-" diff --git a/x/crosschain/types/message_add_to_in_tx_tracker.go b/x/crosschain/types/message_add_to_in_tx_tracker.go new file mode 100644 index 0000000000..c44c15ba8c --- /dev/null +++ b/x/crosschain/types/message_add_to_in_tx_tracker.go @@ -0,0 +1,61 @@ +package types + +import ( + errorsmod "cosmossdk.io/errors" + sdk "github.com/cosmos/cosmos-sdk/types" + sdkerrors "github.com/cosmos/cosmos-sdk/types/errors" + "github.com/zeta-chain/zetacore/common" +) + +const TypeMsgAddToInTxTracker = "AddToInTxTracker" + +var _ sdk.Msg = &MsgAddToInTxTracker{} + +func NewMsgAddToInTxTracker(creator string, chain int64, coinType common.CoinType, txHash string) *MsgAddToInTxTracker { + return &MsgAddToInTxTracker{ + Creator: creator, + ChainId: chain, + TxHash: txHash, + CoinType: coinType, + } +} + +func (msg *MsgAddToInTxTracker) Route() string { + return RouterKey +} + +func (msg *MsgAddToInTxTracker) Type() string { + return TypeMsgAddToInTxTracker +} + +func (msg *MsgAddToInTxTracker) GetSigners() []sdk.AccAddress { + creator, err := sdk.AccAddressFromBech32(msg.Creator) + if err != nil { + panic(err) + } + return []sdk.AccAddress{creator} +} + +func (msg *MsgAddToInTxTracker) GetSignBytes() []byte { + bz := ModuleCdc.MustMarshalJSON(msg) + return sdk.MustSortJSON(bz) +} + +func (msg *MsgAddToInTxTracker) ValidateBasic() error { + _, err := sdk.AccAddressFromBech32(msg.Creator) + if err != nil { + return errorsmod.Wrapf(sdkerrors.ErrInvalidAddress, "invalid creator address (%s)", err) + } + chain := common.GetChainFromChainID(msg.ChainId) + if chain == nil { + return errorsmod.Wrapf(ErrInvalidChainID, "chain id (%d)", msg.ChainId) + } + if msg.Proof != nil && !chain.SupportMerkleProof() { + return errorsmod.Wrapf(ErrCannotVerifyProof, "chain id %d does not support proof-based trackers", msg.ChainId) + } + _, ok := common.CoinType_value[msg.CoinType.String()] + if !ok { + return errorsmod.Wrapf(ErrCannotVerifyProof, "coin-type not supported") + } + return nil +} diff --git a/x/crosschain/types/message_add_to_in_tx_tracker_test.go b/x/crosschain/types/message_add_to_in_tx_tracker_test.go new file mode 100644 index 0000000000..0bd45fbb7a --- /dev/null +++ b/x/crosschain/types/message_add_to_in_tx_tracker_test.go @@ -0,0 +1,64 @@ +//go:build TESTNET +// +build TESTNET + +package types_test + +import ( + "testing" + + errorsmod "cosmossdk.io/errors" + sdkerrors "github.com/cosmos/cosmos-sdk/types/errors" + "github.com/stretchr/testify/require" + "github.com/zeta-chain/zetacore/common" + "github.com/zeta-chain/zetacore/testutil/sample" + "github.com/zeta-chain/zetacore/x/crosschain/types" +) + +func TestMsgAddToInTxTracker_ValidateBasic(t *testing.T) { + tests := []struct { + name string + msg types.MsgAddToInTxTracker + err error + }{ + { + name: "invalid address", + msg: types.MsgAddToInTxTracker{ + Creator: "invalid_address", + ChainId: common.GoerliChain().ChainId, + TxHash: "hash", + CoinType: common.CoinType_Gas, + }, + err: sdkerrors.ErrInvalidAddress, + }, + { + name: "invalid chain id", + msg: types.MsgAddToInTxTracker{ + Creator: sample.AccAddress(), + ChainId: 42, + TxHash: "hash", + CoinType: common.CoinType_Gas, + }, + err: errorsmod.Wrapf(types.ErrInvalidChainID, "chain id (%d)", 42), + }, + { + name: "valid", + msg: types.MsgAddToInTxTracker{ + Creator: sample.AccAddress(), + ChainId: common.GoerliChain().ChainId, + TxHash: "hash", + CoinType: common.CoinType_Gas, + }, + err: nil, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + err := tt.msg.ValidateBasic() + if tt.err != nil { + require.ErrorIs(t, err, tt.err) + return + } + require.NoError(t, err) + }) + } +} diff --git a/x/crosschain/types/query.pb.go b/x/crosschain/types/query.pb.go index dfeacc4365..868abf1169 100644 --- a/x/crosschain/types/query.pb.go +++ b/x/crosschain/types/query.pb.go @@ -490,6 +490,190 @@ func (m *QueryAllOutTxTrackerByChainResponse) GetPagination() *query.PageRespons return nil } +type QueryAllInTxTrackerByChainRequest struct { + ChainId int64 `protobuf:"varint,1,opt,name=chain_id,json=chainId,proto3" json:"chain_id,omitempty"` + Pagination *query.PageRequest `protobuf:"bytes,2,opt,name=pagination,proto3" json:"pagination,omitempty"` +} + +func (m *QueryAllInTxTrackerByChainRequest) Reset() { *m = QueryAllInTxTrackerByChainRequest{} } +func (m *QueryAllInTxTrackerByChainRequest) String() string { return proto.CompactTextString(m) } +func (*QueryAllInTxTrackerByChainRequest) ProtoMessage() {} +func (*QueryAllInTxTrackerByChainRequest) Descriptor() ([]byte, []int) { + return fileDescriptor_65a992045e92a606, []int{10} +} +func (m *QueryAllInTxTrackerByChainRequest) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *QueryAllInTxTrackerByChainRequest) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_QueryAllInTxTrackerByChainRequest.Marshal(b, m, deterministic) + } else { + b = b[:cap(b)] + n, err := m.MarshalToSizedBuffer(b) + if err != nil { + return nil, err + } + return b[:n], nil + } +} +func (m *QueryAllInTxTrackerByChainRequest) XXX_Merge(src proto.Message) { + xxx_messageInfo_QueryAllInTxTrackerByChainRequest.Merge(m, src) +} +func (m *QueryAllInTxTrackerByChainRequest) XXX_Size() int { + return m.Size() +} +func (m *QueryAllInTxTrackerByChainRequest) XXX_DiscardUnknown() { + xxx_messageInfo_QueryAllInTxTrackerByChainRequest.DiscardUnknown(m) +} + +var xxx_messageInfo_QueryAllInTxTrackerByChainRequest proto.InternalMessageInfo + +func (m *QueryAllInTxTrackerByChainRequest) GetChainId() int64 { + if m != nil { + return m.ChainId + } + return 0 +} + +func (m *QueryAllInTxTrackerByChainRequest) GetPagination() *query.PageRequest { + if m != nil { + return m.Pagination + } + return nil +} + +type QueryAllInTxTrackerByChainResponse struct { + InTxTracker []InTxTracker `protobuf:"bytes,1,rep,name=inTxTracker,proto3" json:"inTxTracker"` + Pagination *query.PageResponse `protobuf:"bytes,2,opt,name=pagination,proto3" json:"pagination,omitempty"` +} + +func (m *QueryAllInTxTrackerByChainResponse) Reset() { *m = QueryAllInTxTrackerByChainResponse{} } +func (m *QueryAllInTxTrackerByChainResponse) String() string { return proto.CompactTextString(m) } +func (*QueryAllInTxTrackerByChainResponse) ProtoMessage() {} +func (*QueryAllInTxTrackerByChainResponse) Descriptor() ([]byte, []int) { + return fileDescriptor_65a992045e92a606, []int{11} +} +func (m *QueryAllInTxTrackerByChainResponse) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *QueryAllInTxTrackerByChainResponse) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_QueryAllInTxTrackerByChainResponse.Marshal(b, m, deterministic) + } else { + b = b[:cap(b)] + n, err := m.MarshalToSizedBuffer(b) + if err != nil { + return nil, err + } + return b[:n], nil + } +} +func (m *QueryAllInTxTrackerByChainResponse) XXX_Merge(src proto.Message) { + xxx_messageInfo_QueryAllInTxTrackerByChainResponse.Merge(m, src) +} +func (m *QueryAllInTxTrackerByChainResponse) XXX_Size() int { + return m.Size() +} +func (m *QueryAllInTxTrackerByChainResponse) XXX_DiscardUnknown() { + xxx_messageInfo_QueryAllInTxTrackerByChainResponse.DiscardUnknown(m) +} + +var xxx_messageInfo_QueryAllInTxTrackerByChainResponse proto.InternalMessageInfo + +func (m *QueryAllInTxTrackerByChainResponse) GetInTxTracker() []InTxTracker { + if m != nil { + return m.InTxTracker + } + return nil +} + +func (m *QueryAllInTxTrackerByChainResponse) GetPagination() *query.PageResponse { + if m != nil { + return m.Pagination + } + return nil +} + +type QueryAllInTxTrackersRequest struct { +} + +func (m *QueryAllInTxTrackersRequest) Reset() { *m = QueryAllInTxTrackersRequest{} } +func (m *QueryAllInTxTrackersRequest) String() string { return proto.CompactTextString(m) } +func (*QueryAllInTxTrackersRequest) ProtoMessage() {} +func (*QueryAllInTxTrackersRequest) Descriptor() ([]byte, []int) { + return fileDescriptor_65a992045e92a606, []int{12} +} +func (m *QueryAllInTxTrackersRequest) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *QueryAllInTxTrackersRequest) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_QueryAllInTxTrackersRequest.Marshal(b, m, deterministic) + } else { + b = b[:cap(b)] + n, err := m.MarshalToSizedBuffer(b) + if err != nil { + return nil, err + } + return b[:n], nil + } +} +func (m *QueryAllInTxTrackersRequest) XXX_Merge(src proto.Message) { + xxx_messageInfo_QueryAllInTxTrackersRequest.Merge(m, src) +} +func (m *QueryAllInTxTrackersRequest) XXX_Size() int { + return m.Size() +} +func (m *QueryAllInTxTrackersRequest) XXX_DiscardUnknown() { + xxx_messageInfo_QueryAllInTxTrackersRequest.DiscardUnknown(m) +} + +var xxx_messageInfo_QueryAllInTxTrackersRequest proto.InternalMessageInfo + +type QueryAllInTxTrackersResponse struct { + InTxTracker []InTxTracker `protobuf:"bytes,1,rep,name=inTxTracker,proto3" json:"inTxTracker"` +} + +func (m *QueryAllInTxTrackersResponse) Reset() { *m = QueryAllInTxTrackersResponse{} } +func (m *QueryAllInTxTrackersResponse) String() string { return proto.CompactTextString(m) } +func (*QueryAllInTxTrackersResponse) ProtoMessage() {} +func (*QueryAllInTxTrackersResponse) Descriptor() ([]byte, []int) { + return fileDescriptor_65a992045e92a606, []int{13} +} +func (m *QueryAllInTxTrackersResponse) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *QueryAllInTxTrackersResponse) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_QueryAllInTxTrackersResponse.Marshal(b, m, deterministic) + } else { + b = b[:cap(b)] + n, err := m.MarshalToSizedBuffer(b) + if err != nil { + return nil, err + } + return b[:n], nil + } +} +func (m *QueryAllInTxTrackersResponse) XXX_Merge(src proto.Message) { + xxx_messageInfo_QueryAllInTxTrackersResponse.Merge(m, src) +} +func (m *QueryAllInTxTrackersResponse) XXX_Size() int { + return m.Size() +} +func (m *QueryAllInTxTrackersResponse) XXX_DiscardUnknown() { + xxx_messageInfo_QueryAllInTxTrackersResponse.DiscardUnknown(m) +} + +var xxx_messageInfo_QueryAllInTxTrackersResponse proto.InternalMessageInfo + +func (m *QueryAllInTxTrackersResponse) GetInTxTracker() []InTxTracker { + if m != nil { + return m.InTxTracker + } + return nil +} + type QueryGetInTxHashToCctxRequest struct { InTxHash string `protobuf:"bytes,1,opt,name=inTxHash,proto3" json:"inTxHash,omitempty"` } @@ -498,7 +682,7 @@ func (m *QueryGetInTxHashToCctxRequest) Reset() { *m = QueryGetInTxHashT func (m *QueryGetInTxHashToCctxRequest) String() string { return proto.CompactTextString(m) } func (*QueryGetInTxHashToCctxRequest) ProtoMessage() {} func (*QueryGetInTxHashToCctxRequest) Descriptor() ([]byte, []int) { - return fileDescriptor_65a992045e92a606, []int{10} + return fileDescriptor_65a992045e92a606, []int{14} } func (m *QueryGetInTxHashToCctxRequest) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -542,7 +726,7 @@ func (m *QueryGetInTxHashToCctxResponse) Reset() { *m = QueryGetInTxHash func (m *QueryGetInTxHashToCctxResponse) String() string { return proto.CompactTextString(m) } func (*QueryGetInTxHashToCctxResponse) ProtoMessage() {} func (*QueryGetInTxHashToCctxResponse) Descriptor() ([]byte, []int) { - return fileDescriptor_65a992045e92a606, []int{11} + return fileDescriptor_65a992045e92a606, []int{15} } func (m *QueryGetInTxHashToCctxResponse) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -586,7 +770,7 @@ func (m *QueryInTxHashToCctxDataRequest) Reset() { *m = QueryInTxHashToC func (m *QueryInTxHashToCctxDataRequest) String() string { return proto.CompactTextString(m) } func (*QueryInTxHashToCctxDataRequest) ProtoMessage() {} func (*QueryInTxHashToCctxDataRequest) Descriptor() ([]byte, []int) { - return fileDescriptor_65a992045e92a606, []int{12} + return fileDescriptor_65a992045e92a606, []int{16} } func (m *QueryInTxHashToCctxDataRequest) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -630,7 +814,7 @@ func (m *QueryInTxHashToCctxDataResponse) Reset() { *m = QueryInTxHashTo func (m *QueryInTxHashToCctxDataResponse) String() string { return proto.CompactTextString(m) } func (*QueryInTxHashToCctxDataResponse) ProtoMessage() {} func (*QueryInTxHashToCctxDataResponse) Descriptor() ([]byte, []int) { - return fileDescriptor_65a992045e92a606, []int{13} + return fileDescriptor_65a992045e92a606, []int{17} } func (m *QueryInTxHashToCctxDataResponse) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -674,7 +858,7 @@ func (m *QueryAllInTxHashToCctxRequest) Reset() { *m = QueryAllInTxHashT func (m *QueryAllInTxHashToCctxRequest) String() string { return proto.CompactTextString(m) } func (*QueryAllInTxHashToCctxRequest) ProtoMessage() {} func (*QueryAllInTxHashToCctxRequest) Descriptor() ([]byte, []int) { - return fileDescriptor_65a992045e92a606, []int{14} + return fileDescriptor_65a992045e92a606, []int{18} } func (m *QueryAllInTxHashToCctxRequest) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -719,7 +903,7 @@ func (m *QueryAllInTxHashToCctxResponse) Reset() { *m = QueryAllInTxHash func (m *QueryAllInTxHashToCctxResponse) String() string { return proto.CompactTextString(m) } func (*QueryAllInTxHashToCctxResponse) ProtoMessage() {} func (*QueryAllInTxHashToCctxResponse) Descriptor() ([]byte, []int) { - return fileDescriptor_65a992045e92a606, []int{15} + return fileDescriptor_65a992045e92a606, []int{19} } func (m *QueryAllInTxHashToCctxResponse) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -770,7 +954,7 @@ func (m *QueryGetTssAddressRequest) Reset() { *m = QueryGetTssAddressReq func (m *QueryGetTssAddressRequest) String() string { return proto.CompactTextString(m) } func (*QueryGetTssAddressRequest) ProtoMessage() {} func (*QueryGetTssAddressRequest) Descriptor() ([]byte, []int) { - return fileDescriptor_65a992045e92a606, []int{16} + return fileDescriptor_65a992045e92a606, []int{20} } func (m *QueryGetTssAddressRequest) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -815,7 +999,7 @@ func (m *QueryGetTssAddressResponse) Reset() { *m = QueryGetTssAddressRe func (m *QueryGetTssAddressResponse) String() string { return proto.CompactTextString(m) } func (*QueryGetTssAddressResponse) ProtoMessage() {} func (*QueryGetTssAddressResponse) Descriptor() ([]byte, []int) { - return fileDescriptor_65a992045e92a606, []int{17} + return fileDescriptor_65a992045e92a606, []int{21} } func (m *QueryGetTssAddressResponse) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -865,7 +1049,7 @@ func (m *QueryGetTSSRequest) Reset() { *m = QueryGetTSSRequest{} } func (m *QueryGetTSSRequest) String() string { return proto.CompactTextString(m) } func (*QueryGetTSSRequest) ProtoMessage() {} func (*QueryGetTSSRequest) Descriptor() ([]byte, []int) { - return fileDescriptor_65a992045e92a606, []int{18} + return fileDescriptor_65a992045e92a606, []int{22} } func (m *QueryGetTSSRequest) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -902,7 +1086,7 @@ func (m *QueryGetTSSResponse) Reset() { *m = QueryGetTSSResponse{} } func (m *QueryGetTSSResponse) String() string { return proto.CompactTextString(m) } func (*QueryGetTSSResponse) ProtoMessage() {} func (*QueryGetTSSResponse) Descriptor() ([]byte, []int) { - return fileDescriptor_65a992045e92a606, []int{19} + return fileDescriptor_65a992045e92a606, []int{23} } func (m *QueryGetTSSResponse) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -946,7 +1130,7 @@ func (m *QueryGetGasPriceRequest) Reset() { *m = QueryGetGasPriceRequest func (m *QueryGetGasPriceRequest) String() string { return proto.CompactTextString(m) } func (*QueryGetGasPriceRequest) ProtoMessage() {} func (*QueryGetGasPriceRequest) Descriptor() ([]byte, []int) { - return fileDescriptor_65a992045e92a606, []int{20} + return fileDescriptor_65a992045e92a606, []int{24} } func (m *QueryGetGasPriceRequest) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -990,7 +1174,7 @@ func (m *QueryGetGasPriceResponse) Reset() { *m = QueryGetGasPriceRespon func (m *QueryGetGasPriceResponse) String() string { return proto.CompactTextString(m) } func (*QueryGetGasPriceResponse) ProtoMessage() {} func (*QueryGetGasPriceResponse) Descriptor() ([]byte, []int) { - return fileDescriptor_65a992045e92a606, []int{21} + return fileDescriptor_65a992045e92a606, []int{25} } func (m *QueryGetGasPriceResponse) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -1034,7 +1218,7 @@ func (m *QueryAllGasPriceRequest) Reset() { *m = QueryAllGasPriceRequest func (m *QueryAllGasPriceRequest) String() string { return proto.CompactTextString(m) } func (*QueryAllGasPriceRequest) ProtoMessage() {} func (*QueryAllGasPriceRequest) Descriptor() ([]byte, []int) { - return fileDescriptor_65a992045e92a606, []int{22} + return fileDescriptor_65a992045e92a606, []int{26} } func (m *QueryAllGasPriceRequest) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -1079,7 +1263,7 @@ func (m *QueryAllGasPriceResponse) Reset() { *m = QueryAllGasPriceRespon func (m *QueryAllGasPriceResponse) String() string { return proto.CompactTextString(m) } func (*QueryAllGasPriceResponse) ProtoMessage() {} func (*QueryAllGasPriceResponse) Descriptor() ([]byte, []int) { - return fileDescriptor_65a992045e92a606, []int{23} + return fileDescriptor_65a992045e92a606, []int{27} } func (m *QueryAllGasPriceResponse) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -1130,7 +1314,7 @@ func (m *QueryGetChainNoncesRequest) Reset() { *m = QueryGetChainNoncesR func (m *QueryGetChainNoncesRequest) String() string { return proto.CompactTextString(m) } func (*QueryGetChainNoncesRequest) ProtoMessage() {} func (*QueryGetChainNoncesRequest) Descriptor() ([]byte, []int) { - return fileDescriptor_65a992045e92a606, []int{24} + return fileDescriptor_65a992045e92a606, []int{28} } func (m *QueryGetChainNoncesRequest) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -1174,7 +1358,7 @@ func (m *QueryGetChainNoncesResponse) Reset() { *m = QueryGetChainNonces func (m *QueryGetChainNoncesResponse) String() string { return proto.CompactTextString(m) } func (*QueryGetChainNoncesResponse) ProtoMessage() {} func (*QueryGetChainNoncesResponse) Descriptor() ([]byte, []int) { - return fileDescriptor_65a992045e92a606, []int{25} + return fileDescriptor_65a992045e92a606, []int{29} } func (m *QueryGetChainNoncesResponse) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -1218,7 +1402,7 @@ func (m *QueryAllChainNoncesRequest) Reset() { *m = QueryAllChainNoncesR func (m *QueryAllChainNoncesRequest) String() string { return proto.CompactTextString(m) } func (*QueryAllChainNoncesRequest) ProtoMessage() {} func (*QueryAllChainNoncesRequest) Descriptor() ([]byte, []int) { - return fileDescriptor_65a992045e92a606, []int{26} + return fileDescriptor_65a992045e92a606, []int{30} } func (m *QueryAllChainNoncesRequest) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -1263,7 +1447,7 @@ func (m *QueryAllChainNoncesResponse) Reset() { *m = QueryAllChainNonces func (m *QueryAllChainNoncesResponse) String() string { return proto.CompactTextString(m) } func (*QueryAllChainNoncesResponse) ProtoMessage() {} func (*QueryAllChainNoncesResponse) Descriptor() ([]byte, []int) { - return fileDescriptor_65a992045e92a606, []int{27} + return fileDescriptor_65a992045e92a606, []int{31} } func (m *QueryAllChainNoncesResponse) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -1313,7 +1497,7 @@ func (m *QueryAllPendingNoncesRequest) Reset() { *m = QueryAllPendingNon func (m *QueryAllPendingNoncesRequest) String() string { return proto.CompactTextString(m) } func (*QueryAllPendingNoncesRequest) ProtoMessage() {} func (*QueryAllPendingNoncesRequest) Descriptor() ([]byte, []int) { - return fileDescriptor_65a992045e92a606, []int{28} + return fileDescriptor_65a992045e92a606, []int{32} } func (m *QueryAllPendingNoncesRequest) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -1350,7 +1534,7 @@ func (m *QueryAllPendingNoncesResponse) Reset() { *m = QueryAllPendingNo func (m *QueryAllPendingNoncesResponse) String() string { return proto.CompactTextString(m) } func (*QueryAllPendingNoncesResponse) ProtoMessage() {} func (*QueryAllPendingNoncesResponse) Descriptor() ([]byte, []int) { - return fileDescriptor_65a992045e92a606, []int{29} + return fileDescriptor_65a992045e92a606, []int{33} } func (m *QueryAllPendingNoncesResponse) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -1394,7 +1578,7 @@ func (m *QueryPendingNoncesByChainRequest) Reset() { *m = QueryPendingNo func (m *QueryPendingNoncesByChainRequest) String() string { return proto.CompactTextString(m) } func (*QueryPendingNoncesByChainRequest) ProtoMessage() {} func (*QueryPendingNoncesByChainRequest) Descriptor() ([]byte, []int) { - return fileDescriptor_65a992045e92a606, []int{30} + return fileDescriptor_65a992045e92a606, []int{34} } func (m *QueryPendingNoncesByChainRequest) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -1438,7 +1622,7 @@ func (m *QueryPendingNoncesByChainResponse) Reset() { *m = QueryPendingN func (m *QueryPendingNoncesByChainResponse) String() string { return proto.CompactTextString(m) } func (*QueryPendingNoncesByChainResponse) ProtoMessage() {} func (*QueryPendingNoncesByChainResponse) Descriptor() ([]byte, []int) { - return fileDescriptor_65a992045e92a606, []int{31} + return fileDescriptor_65a992045e92a606, []int{35} } func (m *QueryPendingNoncesByChainResponse) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -1482,7 +1666,7 @@ func (m *QueryGetLastBlockHeightRequest) Reset() { *m = QueryGetLastBloc func (m *QueryGetLastBlockHeightRequest) String() string { return proto.CompactTextString(m) } func (*QueryGetLastBlockHeightRequest) ProtoMessage() {} func (*QueryGetLastBlockHeightRequest) Descriptor() ([]byte, []int) { - return fileDescriptor_65a992045e92a606, []int{32} + return fileDescriptor_65a992045e92a606, []int{36} } func (m *QueryGetLastBlockHeightRequest) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -1526,7 +1710,7 @@ func (m *QueryGetLastBlockHeightResponse) Reset() { *m = QueryGetLastBlo func (m *QueryGetLastBlockHeightResponse) String() string { return proto.CompactTextString(m) } func (*QueryGetLastBlockHeightResponse) ProtoMessage() {} func (*QueryGetLastBlockHeightResponse) Descriptor() ([]byte, []int) { - return fileDescriptor_65a992045e92a606, []int{33} + return fileDescriptor_65a992045e92a606, []int{37} } func (m *QueryGetLastBlockHeightResponse) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -1570,7 +1754,7 @@ func (m *QueryAllLastBlockHeightRequest) Reset() { *m = QueryAllLastBloc func (m *QueryAllLastBlockHeightRequest) String() string { return proto.CompactTextString(m) } func (*QueryAllLastBlockHeightRequest) ProtoMessage() {} func (*QueryAllLastBlockHeightRequest) Descriptor() ([]byte, []int) { - return fileDescriptor_65a992045e92a606, []int{34} + return fileDescriptor_65a992045e92a606, []int{38} } func (m *QueryAllLastBlockHeightRequest) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -1615,7 +1799,7 @@ func (m *QueryAllLastBlockHeightResponse) Reset() { *m = QueryAllLastBlo func (m *QueryAllLastBlockHeightResponse) String() string { return proto.CompactTextString(m) } func (*QueryAllLastBlockHeightResponse) ProtoMessage() {} func (*QueryAllLastBlockHeightResponse) Descriptor() ([]byte, []int) { - return fileDescriptor_65a992045e92a606, []int{35} + return fileDescriptor_65a992045e92a606, []int{39} } func (m *QueryAllLastBlockHeightResponse) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -1666,7 +1850,7 @@ func (m *QueryGetCctxRequest) Reset() { *m = QueryGetCctxRequest{} } func (m *QueryGetCctxRequest) String() string { return proto.CompactTextString(m) } func (*QueryGetCctxRequest) ProtoMessage() {} func (*QueryGetCctxRequest) Descriptor() ([]byte, []int) { - return fileDescriptor_65a992045e92a606, []int{36} + return fileDescriptor_65a992045e92a606, []int{40} } func (m *QueryGetCctxRequest) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -1711,7 +1895,7 @@ func (m *QueryGetCctxByNonceRequest) Reset() { *m = QueryGetCctxByNonceR func (m *QueryGetCctxByNonceRequest) String() string { return proto.CompactTextString(m) } func (*QueryGetCctxByNonceRequest) ProtoMessage() {} func (*QueryGetCctxByNonceRequest) Descriptor() ([]byte, []int) { - return fileDescriptor_65a992045e92a606, []int{37} + return fileDescriptor_65a992045e92a606, []int{41} } func (m *QueryGetCctxByNonceRequest) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -1762,7 +1946,7 @@ func (m *QueryGetCctxResponse) Reset() { *m = QueryGetCctxResponse{} } func (m *QueryGetCctxResponse) String() string { return proto.CompactTextString(m) } func (*QueryGetCctxResponse) ProtoMessage() {} func (*QueryGetCctxResponse) Descriptor() ([]byte, []int) { - return fileDescriptor_65a992045e92a606, []int{38} + return fileDescriptor_65a992045e92a606, []int{42} } func (m *QueryGetCctxResponse) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -1806,7 +1990,7 @@ func (m *QueryAllCctxRequest) Reset() { *m = QueryAllCctxRequest{} } func (m *QueryAllCctxRequest) String() string { return proto.CompactTextString(m) } func (*QueryAllCctxRequest) ProtoMessage() {} func (*QueryAllCctxRequest) Descriptor() ([]byte, []int) { - return fileDescriptor_65a992045e92a606, []int{39} + return fileDescriptor_65a992045e92a606, []int{43} } func (m *QueryAllCctxRequest) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -1851,7 +2035,7 @@ func (m *QueryAllCctxResponse) Reset() { *m = QueryAllCctxResponse{} } func (m *QueryAllCctxResponse) String() string { return proto.CompactTextString(m) } func (*QueryAllCctxResponse) ProtoMessage() {} func (*QueryAllCctxResponse) Descriptor() ([]byte, []int) { - return fileDescriptor_65a992045e92a606, []int{40} + return fileDescriptor_65a992045e92a606, []int{44} } func (m *QueryAllCctxResponse) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -1903,7 +2087,7 @@ func (m *QueryAllCctxPendingRequest) Reset() { *m = QueryAllCctxPendingR func (m *QueryAllCctxPendingRequest) String() string { return proto.CompactTextString(m) } func (*QueryAllCctxPendingRequest) ProtoMessage() {} func (*QueryAllCctxPendingRequest) Descriptor() ([]byte, []int) { - return fileDescriptor_65a992045e92a606, []int{41} + return fileDescriptor_65a992045e92a606, []int{45} } func (m *QueryAllCctxPendingRequest) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -1955,7 +2139,7 @@ func (m *QueryAllCctxPendingResponse) Reset() { *m = QueryAllCctxPending func (m *QueryAllCctxPendingResponse) String() string { return proto.CompactTextString(m) } func (*QueryAllCctxPendingResponse) ProtoMessage() {} func (*QueryAllCctxPendingResponse) Descriptor() ([]byte, []int) { - return fileDescriptor_65a992045e92a606, []int{42} + return fileDescriptor_65a992045e92a606, []int{46} } func (m *QueryAllCctxPendingResponse) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -2005,7 +2189,7 @@ func (m *QueryLastZetaHeightRequest) Reset() { *m = QueryLastZetaHeightR func (m *QueryLastZetaHeightRequest) String() string { return proto.CompactTextString(m) } func (*QueryLastZetaHeightRequest) ProtoMessage() {} func (*QueryLastZetaHeightRequest) Descriptor() ([]byte, []int) { - return fileDescriptor_65a992045e92a606, []int{43} + return fileDescriptor_65a992045e92a606, []int{47} } func (m *QueryLastZetaHeightRequest) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -2042,7 +2226,7 @@ func (m *QueryLastZetaHeightResponse) Reset() { *m = QueryLastZetaHeight func (m *QueryLastZetaHeightResponse) String() string { return proto.CompactTextString(m) } func (*QueryLastZetaHeightResponse) ProtoMessage() {} func (*QueryLastZetaHeightResponse) Descriptor() ([]byte, []int) { - return fileDescriptor_65a992045e92a606, []int{44} + return fileDescriptor_65a992045e92a606, []int{48} } func (m *QueryLastZetaHeightResponse) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -2087,7 +2271,7 @@ func (m *QueryConvertGasToZetaRequest) Reset() { *m = QueryConvertGasToZ func (m *QueryConvertGasToZetaRequest) String() string { return proto.CompactTextString(m) } func (*QueryConvertGasToZetaRequest) ProtoMessage() {} func (*QueryConvertGasToZetaRequest) Descriptor() ([]byte, []int) { - return fileDescriptor_65a992045e92a606, []int{45} + return fileDescriptor_65a992045e92a606, []int{49} } func (m *QueryConvertGasToZetaRequest) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -2140,7 +2324,7 @@ func (m *QueryConvertGasToZetaResponse) Reset() { *m = QueryConvertGasTo func (m *QueryConvertGasToZetaResponse) String() string { return proto.CompactTextString(m) } func (*QueryConvertGasToZetaResponse) ProtoMessage() {} func (*QueryConvertGasToZetaResponse) Descriptor() ([]byte, []int) { - return fileDescriptor_65a992045e92a606, []int{46} + return fileDescriptor_65a992045e92a606, []int{50} } func (m *QueryConvertGasToZetaResponse) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -2197,7 +2381,7 @@ func (m *QueryMessagePassingProtocolFeeRequest) Reset() { *m = QueryMess func (m *QueryMessagePassingProtocolFeeRequest) String() string { return proto.CompactTextString(m) } func (*QueryMessagePassingProtocolFeeRequest) ProtoMessage() {} func (*QueryMessagePassingProtocolFeeRequest) Descriptor() ([]byte, []int) { - return fileDescriptor_65a992045e92a606, []int{47} + return fileDescriptor_65a992045e92a606, []int{51} } func (m *QueryMessagePassingProtocolFeeRequest) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -2236,7 +2420,7 @@ func (m *QueryMessagePassingProtocolFeeResponse) Reset() { func (m *QueryMessagePassingProtocolFeeResponse) String() string { return proto.CompactTextString(m) } func (*QueryMessagePassingProtocolFeeResponse) ProtoMessage() {} func (*QueryMessagePassingProtocolFeeResponse) Descriptor() ([]byte, []int) { - return fileDescriptor_65a992045e92a606, []int{48} + return fileDescriptor_65a992045e92a606, []int{52} } func (m *QueryMessagePassingProtocolFeeResponse) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -2280,7 +2464,7 @@ func (m *QueryZEVMGetTransactionReceiptRequest) Reset() { *m = QueryZEVM func (m *QueryZEVMGetTransactionReceiptRequest) String() string { return proto.CompactTextString(m) } func (*QueryZEVMGetTransactionReceiptRequest) ProtoMessage() {} func (*QueryZEVMGetTransactionReceiptRequest) Descriptor() ([]byte, []int) { - return fileDescriptor_65a992045e92a606, []int{49} + return fileDescriptor_65a992045e92a606, []int{53} } func (m *QueryZEVMGetTransactionReceiptRequest) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -2337,7 +2521,7 @@ func (m *QueryZEVMGetTransactionReceiptResponse) Reset() { func (m *QueryZEVMGetTransactionReceiptResponse) String() string { return proto.CompactTextString(m) } func (*QueryZEVMGetTransactionReceiptResponse) ProtoMessage() {} func (*QueryZEVMGetTransactionReceiptResponse) Descriptor() ([]byte, []int) { - return fileDescriptor_65a992045e92a606, []int{50} + return fileDescriptor_65a992045e92a606, []int{54} } func (m *QueryZEVMGetTransactionReceiptResponse) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -2467,7 +2651,7 @@ func (m *Log) Reset() { *m = Log{} } func (m *Log) String() string { return proto.CompactTextString(m) } func (*Log) ProtoMessage() {} func (*Log) Descriptor() ([]byte, []int) { - return fileDescriptor_65a992045e92a606, []int{51} + return fileDescriptor_65a992045e92a606, []int{55} } func (m *Log) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -2567,7 +2751,7 @@ func (m *QueryZEVMGetTransactionRequest) Reset() { *m = QueryZEVMGetTran func (m *QueryZEVMGetTransactionRequest) String() string { return proto.CompactTextString(m) } func (*QueryZEVMGetTransactionRequest) ProtoMessage() {} func (*QueryZEVMGetTransactionRequest) Descriptor() ([]byte, []int) { - return fileDescriptor_65a992045e92a606, []int{52} + return fileDescriptor_65a992045e92a606, []int{56} } func (m *QueryZEVMGetTransactionRequest) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -2627,7 +2811,7 @@ func (m *QueryZEVMGetTransactionResponse) Reset() { *m = QueryZEVMGetTra func (m *QueryZEVMGetTransactionResponse) String() string { return proto.CompactTextString(m) } func (*QueryZEVMGetTransactionResponse) ProtoMessage() {} func (*QueryZEVMGetTransactionResponse) Descriptor() ([]byte, []int) { - return fileDescriptor_65a992045e92a606, []int{53} + return fileDescriptor_65a992045e92a606, []int{57} } func (m *QueryZEVMGetTransactionResponse) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -2783,7 +2967,7 @@ func (m *QueryZEVMGetBlockByNumberRequest) Reset() { *m = QueryZEVMGetBl func (m *QueryZEVMGetBlockByNumberRequest) String() string { return proto.CompactTextString(m) } func (*QueryZEVMGetBlockByNumberRequest) ProtoMessage() {} func (*QueryZEVMGetBlockByNumberRequest) Descriptor() ([]byte, []int) { - return fileDescriptor_65a992045e92a606, []int{54} + return fileDescriptor_65a992045e92a606, []int{58} } func (m *QueryZEVMGetBlockByNumberRequest) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -2847,7 +3031,7 @@ func (m *QueryZEVMGetBlockByNumberResponse) Reset() { *m = QueryZEVMGetB func (m *QueryZEVMGetBlockByNumberResponse) String() string { return proto.CompactTextString(m) } func (*QueryZEVMGetBlockByNumberResponse) ProtoMessage() {} func (*QueryZEVMGetBlockByNumberResponse) Descriptor() ([]byte, []int) { - return fileDescriptor_65a992045e92a606, []int{55} + return fileDescriptor_65a992045e92a606, []int{59} } func (m *QueryZEVMGetBlockByNumberResponse) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -3034,6 +3218,10 @@ func init() { proto.RegisterType((*QueryAllOutTxTrackerResponse)(nil), "zetachain.zetacore.crosschain.QueryAllOutTxTrackerResponse") proto.RegisterType((*QueryAllOutTxTrackerByChainRequest)(nil), "zetachain.zetacore.crosschain.QueryAllOutTxTrackerByChainRequest") proto.RegisterType((*QueryAllOutTxTrackerByChainResponse)(nil), "zetachain.zetacore.crosschain.QueryAllOutTxTrackerByChainResponse") + proto.RegisterType((*QueryAllInTxTrackerByChainRequest)(nil), "zetachain.zetacore.crosschain.QueryAllInTxTrackerByChainRequest") + proto.RegisterType((*QueryAllInTxTrackerByChainResponse)(nil), "zetachain.zetacore.crosschain.QueryAllInTxTrackerByChainResponse") + proto.RegisterType((*QueryAllInTxTrackersRequest)(nil), "zetachain.zetacore.crosschain.QueryAllInTxTrackersRequest") + proto.RegisterType((*QueryAllInTxTrackersResponse)(nil), "zetachain.zetacore.crosschain.QueryAllInTxTrackersResponse") proto.RegisterType((*QueryGetInTxHashToCctxRequest)(nil), "zetachain.zetacore.crosschain.QueryGetInTxHashToCctxRequest") proto.RegisterType((*QueryGetInTxHashToCctxResponse)(nil), "zetachain.zetacore.crosschain.QueryGetInTxHashToCctxResponse") proto.RegisterType((*QueryInTxHashToCctxDataRequest)(nil), "zetachain.zetacore.crosschain.QueryInTxHashToCctxDataRequest") @@ -3085,197 +3273,204 @@ func init() { func init() { proto.RegisterFile("crosschain/query.proto", fileDescriptor_65a992045e92a606) } var fileDescriptor_65a992045e92a606 = []byte{ - // 3038 bytes of a gzipped FileDescriptorProto - 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xd4, 0x5a, 0xdd, 0x6f, 0x1b, 0xc7, - 0x11, 0xf7, 0x89, 0xfa, 0x5c, 0x7d, 0x7a, 0xad, 0x38, 0x0c, 0x63, 0x8b, 0xce, 0x39, 0xfe, 0x88, - 0x3f, 0xc8, 0x58, 0xb1, 0x9d, 0xc4, 0x76, 0xd2, 0x48, 0x76, 0xac, 0x18, 0x51, 0x12, 0xf5, 0xa4, - 0xf4, 0xc3, 0x45, 0x4b, 0x9c, 0x8e, 0x6b, 0xea, 0xe0, 0x23, 0x8f, 0xb9, 0x5d, 0x0a, 0x52, 0x0c, - 0xb5, 0x40, 0xfe, 0x82, 0x00, 0x05, 0xda, 0x97, 0xbe, 0xf6, 0xe3, 0xa1, 0x0f, 0x01, 0x1a, 0x34, - 0x05, 0x0a, 0xa4, 0x0f, 0x6d, 0xd3, 0x3c, 0x06, 0x2d, 0x50, 0xb4, 0x28, 0x40, 0x14, 0x71, 0x9f, - 0xf8, 0x1f, 0x14, 0xe8, 0x43, 0xb1, 0x73, 0x73, 0xbc, 0x3d, 0xf2, 0x4e, 0x3c, 0x51, 0x6c, 0xd1, - 0xbe, 0x88, 0xbb, 0xb3, 0x3b, 0xb3, 0xbf, 0x99, 0x9d, 0xd9, 0x9d, 0xbd, 0x11, 0x39, 0x6e, 0x79, - 0x2e, 0xe7, 0xd6, 0x96, 0x69, 0xd7, 0x8a, 0xef, 0x35, 0x98, 0xb7, 0x5b, 0xa8, 0x7b, 0xae, 0x70, - 0xe9, 0xc9, 0xf7, 0x99, 0x30, 0x81, 0x5c, 0x80, 0x96, 0xeb, 0xb1, 0x42, 0x38, 0x35, 0x77, 0xc1, - 0x72, 0x79, 0xd5, 0xe5, 0xc5, 0x4d, 0x93, 0x33, 0x9f, 0xaf, 0xb8, 0x7d, 0x65, 0x93, 0x09, 0xf3, - 0x4a, 0xb1, 0x6e, 0x56, 0xec, 0x9a, 0x29, 0x6c, 0xb7, 0xe6, 0x8b, 0xca, 0x9d, 0x54, 0x96, 0x80, - 0xbf, 0xa5, 0x9a, 0x5b, 0xb3, 0x18, 0xc7, 0xe1, 0xbc, 0x3a, 0x2c, 0x9b, 0x25, 0x7f, 0x92, 0xd8, - 0xc1, 0x09, 0x39, 0x65, 0x42, 0xc5, 0xe4, 0xa5, 0xba, 0x67, 0x5b, 0x0c, 0xc7, 0x4e, 0x2b, 0x63, - 0xc0, 0x53, 0xda, 0x32, 0xf9, 0x56, 0x49, 0xb8, 0x25, 0xcb, 0x6a, 0x0b, 0xd0, 0x95, 0x49, 0x8e, - 0xc9, 0x45, 0x69, 0xd3, 0x71, 0xad, 0x87, 0xa5, 0x2d, 0x66, 0x57, 0xb6, 0x04, 0xce, 0x59, 0x50, - 0xe6, 0x00, 0xbc, 0x0e, 0x19, 0x2a, 0x4a, 0xb7, 0x21, 0xe4, 0x4a, 0xc2, 0x33, 0xad, 0x87, 0xcc, - 0xc3, 0x09, 0x4f, 0x2a, 0x13, 0xea, 0xa6, 0x67, 0x56, 0x03, 0xfd, 0xe6, 0x95, 0x01, 0xc1, 0xdb, - 0xd4, 0x8a, 0x5b, 0x71, 0xa1, 0x59, 0x94, 0x2d, 0xa4, 0x9e, 0xa8, 0xb8, 0x6e, 0xc5, 0x61, 0x45, - 0xb3, 0x6e, 0x17, 0xcd, 0x5a, 0xcd, 0x15, 0x60, 0x47, 0xe4, 0xd1, 0xb3, 0xe4, 0xf8, 0x57, 0xa5, - 0xa9, 0x37, 0x38, 0x7f, 0xc3, 0xe6, 0xc2, 0xf5, 0x76, 0x0d, 0xf6, 0x5e, 0x83, 0x71, 0xa1, 0x7f, - 0x87, 0x3c, 0xd9, 0x35, 0xc2, 0xeb, 0x6e, 0x8d, 0x33, 0x7a, 0x9b, 0x8c, 0x0b, 0xce, 0x4b, 0x8e, - 0xcd, 0x45, 0x56, 0x3b, 0x95, 0x39, 0x3f, 0xb9, 0xa8, 0x17, 0xf6, 0xdd, 0xdb, 0xc2, 0xc6, 0xfa, - 0xfa, 0xf2, 0xf0, 0xe7, 0xcd, 0xfc, 0x11, 0x63, 0x4c, 0x70, 0xbe, 0x6a, 0x73, 0xa1, 0xcf, 0x13, - 0x0a, 0xf2, 0xd7, 0x40, 0xb1, 0x60, 0xd5, 0xfb, 0xe4, 0x58, 0x84, 0xda, 0x5e, 0x71, 0xd4, 0x37, - 0x40, 0x56, 0x3b, 0xa5, 0x9d, 0x9f, 0x5c, 0x3c, 0xd3, 0x63, 0x3d, 0x9f, 0x1d, 0x97, 0x44, 0x56, - 0xfd, 0x2d, 0xf2, 0x34, 0xc8, 0x5e, 0x61, 0xe2, 0x9d, 0x86, 0xd8, 0xd8, 0xd9, 0xf0, 0x8d, 0x8d, - 0x4b, 0xd3, 0x2c, 0x19, 0x03, 0xe6, 0x7b, 0x77, 0x60, 0x91, 0x8c, 0x11, 0x74, 0xe9, 0x3c, 0x19, - 0x81, 0xfd, 0xcb, 0x0e, 0x9d, 0xd2, 0xce, 0x0f, 0x1b, 0x7e, 0x47, 0x6f, 0x90, 0x13, 0xf1, 0xe2, - 0x10, 0xf3, 0xbb, 0x64, 0xca, 0x55, 0xe8, 0x88, 0xfc, 0x62, 0x0f, 0xe4, 0xaa, 0x28, 0xc4, 0x1f, - 0x11, 0xa3, 0x33, 0xd4, 0x62, 0xc9, 0x71, 0xe2, 0xb4, 0xb8, 0x4b, 0x48, 0x18, 0x2d, 0xb8, 0xe6, - 0xd9, 0x82, 0x1f, 0x5a, 0x05, 0x19, 0x5a, 0x05, 0x3f, 0x24, 0x31, 0xb4, 0x0a, 0x6b, 0x66, 0x85, - 0x21, 0xaf, 0xa1, 0x70, 0xea, 0x9f, 0x6a, 0xa8, 0x5e, 0xd7, 0x3a, 0x89, 0xea, 0x65, 0x06, 0xa0, - 0x1e, 0x5d, 0x89, 0xe0, 0x1f, 0x02, 0xfc, 0xe7, 0x7a, 0xe2, 0xf7, 0x31, 0x45, 0x14, 0xf8, 0x40, - 0x23, 0x7a, 0x9c, 0x02, 0xcb, 0xbb, 0xb7, 0x25, 0x92, 0xc0, 0x5e, 0xf3, 0x64, 0x04, 0x90, 0xe1, - 0x9e, 0xfb, 0x9d, 0x0e, 0x2b, 0x0e, 0xf5, 0x6d, 0xc5, 0xdf, 0x6b, 0xe4, 0xf4, 0xbe, 0x20, 0xfe, - 0x4f, 0x8c, 0x79, 0x93, 0x9c, 0x0c, 0x7c, 0xfd, 0x5e, 0x6d, 0x63, 0xe7, 0x0d, 0x93, 0x6f, 0x6d, - 0xb8, 0xb7, 0x2d, 0xb1, 0x13, 0x98, 0x31, 0x47, 0xc6, 0x6d, 0x1c, 0x00, 0x4b, 0x4e, 0x18, 0xed, - 0xbe, 0xbe, 0x47, 0x16, 0x92, 0x98, 0x51, 0xfd, 0x6f, 0x91, 0x19, 0x3b, 0x32, 0x82, 0x8e, 0x7b, - 0xb9, 0x87, 0x01, 0xa2, 0xe2, 0xd0, 0x04, 0x1d, 0xa2, 0xf4, 0x5b, 0xb8, 0x7c, 0x74, 0xf2, 0x1d, - 0x53, 0x98, 0x69, 0xc0, 0xbf, 0x4f, 0xf2, 0x89, 0xdc, 0x88, 0xfe, 0xeb, 0x64, 0xfa, 0xb6, 0xc4, - 0x04, 0x5b, 0xba, 0xb1, 0xc3, 0x53, 0xee, 0x9e, 0xca, 0x83, 0xd0, 0xa3, 0x72, 0xf4, 0x0a, 0x5a, - 0x7d, 0xc9, 0x71, 0xe2, 0xad, 0x3e, 0xa8, 0x60, 0xff, 0x4c, 0x43, 0x1b, 0xc5, 0xac, 0xb4, 0xcf, - 0x16, 0x65, 0x06, 0xb4, 0x45, 0x83, 0xf4, 0xd3, 0xa7, 0x02, 0x57, 0xdb, 0xe0, 0x7c, 0xa9, 0x5c, - 0xf6, 0x18, 0x0f, 0xee, 0x16, 0xba, 0x40, 0x26, 0xe5, 0xb5, 0x55, 0x6f, 0x6c, 0x96, 0x1e, 0xb2, - 0x5d, 0xdc, 0xe9, 0x09, 0xc1, 0xf9, 0x5a, 0x63, 0xf3, 0x4d, 0xb6, 0xab, 0xbf, 0x46, 0x72, 0x71, - 0xcc, 0x68, 0x80, 0x39, 0x92, 0x61, 0x22, 0xf0, 0x0f, 0xd9, 0x94, 0x94, 0x4d, 0x61, 0x01, 0xdc, - 0x09, 0x43, 0x36, 0xdb, 0x77, 0x9a, 0x94, 0xb0, 0xbe, 0x1e, 0xdc, 0x69, 0x6f, 0xe2, 0x9d, 0x16, - 0x50, 0x51, 0xe0, 0x55, 0x92, 0xd9, 0x58, 0x5f, 0xc7, 0x5d, 0x4b, 0x71, 0x81, 0x1a, 0x72, 0xba, - 0x5e, 0xc4, 0x6b, 0x79, 0x85, 0x89, 0x15, 0x93, 0xaf, 0xc9, 0xbc, 0x45, 0x39, 0xca, 0xec, 0x5a, - 0x99, 0xed, 0x20, 0x46, 0xbf, 0xa3, 0x97, 0x48, 0xb6, 0x9b, 0x21, 0xbc, 0xc8, 0x03, 0x1a, 0xe2, - 0x38, 0xd7, 0x03, 0x47, 0x5b, 0x44, 0x9b, 0x51, 0x37, 0x11, 0xd1, 0x92, 0xe3, 0x74, 0x22, 0x1a, - 0x94, 0x7f, 0xfe, 0x4c, 0x43, 0x25, 0x22, 0x6b, 0xc4, 0x2a, 0x91, 0xe9, 0x4b, 0x89, 0xc1, 0x79, - 0xe0, 0x62, 0xe8, 0x44, 0x10, 0xc7, 0x6f, 0x43, 0x5e, 0xba, 0xff, 0x16, 0x3d, 0x0c, 0x13, 0x93, - 0x08, 0x0f, 0x2a, 0xb8, 0x4a, 0x26, 0x15, 0x32, 0x9a, 0xf1, 0x42, 0xaf, 0xd3, 0x45, 0x11, 0xa4, - 0xb2, 0xeb, 0x65, 0x04, 0xb8, 0xe4, 0x38, 0x31, 0x00, 0x07, 0xb5, 0x63, 0x1f, 0x6b, 0x61, 0x9a, - 0x92, 0x4a, 0xa7, 0xcc, 0x21, 0x74, 0x1a, 0xdc, 0xee, 0x2d, 0x84, 0x49, 0xcf, 0x1a, 0xab, 0x95, - 0xed, 0x5a, 0x25, 0x62, 0x1e, 0x5d, 0x84, 0x27, 0x72, 0xc7, 0x38, 0xea, 0xb5, 0x4e, 0x66, 0xea, - 0xfe, 0x00, 0xbe, 0x48, 0x50, 0xb5, 0x4b, 0xbd, 0x12, 0xd6, 0x88, 0xb4, 0xe9, 0xba, 0xda, 0xd5, - 0x5f, 0x21, 0xa7, 0xfc, 0xa4, 0x58, 0xa5, 0x76, 0xe4, 0x31, 0x4f, 0x91, 0x71, 0xff, 0x8d, 0x63, - 0x97, 0xa3, 0xe9, 0x6b, 0x59, 0xff, 0x2e, 0x79, 0x66, 0x1f, 0x76, 0x04, 0xfe, 0xcd, 0x18, 0xe0, - 0xda, 0x41, 0x81, 0x07, 0xd7, 0x58, 0x14, 0xfe, 0xf5, 0xf0, 0xfe, 0x5f, 0x35, 0xb9, 0x58, 0x96, - 0x2f, 0xa5, 0x37, 0xe0, 0xa1, 0xb4, 0x7f, 0x58, 0x3c, 0xc2, 0xab, 0x37, 0x8e, 0x0f, 0x51, 0x7f, - 0x83, 0xcc, 0x76, 0x0c, 0x21, 0xec, 0x42, 0x0f, 0xd8, 0x9d, 0x02, 0x3b, 0xc5, 0xe8, 0x5b, 0xe1, - 0x8d, 0x98, 0x00, 0x7a, 0x50, 0xa1, 0xf2, 0x3b, 0x0d, 0xf5, 0x8c, 0x5b, 0x6a, 0x3f, 0x3d, 0x33, - 0x03, 0xd0, 0x73, 0x70, 0xa1, 0x73, 0x31, 0xbc, 0xe5, 0xd4, 0x14, 0x25, 0x7e, 0x6b, 0x57, 0x95, - 0x53, 0x52, 0xa6, 0x05, 0xbb, 0xe0, 0x2a, 0xfd, 0xbe, 0xc4, 0x2a, 0x64, 0x3e, 0xba, 0x34, 0x5a, - 0xed, 0x1d, 0x32, 0xa5, 0x26, 0x54, 0x29, 0x5f, 0x60, 0x2a, 0x8b, 0x11, 0x11, 0xa0, 0x7f, 0x1b, - 0x75, 0x94, 0x87, 0xda, 0x7f, 0x20, 0x0d, 0xfb, 0x48, 0x43, 0x45, 0xda, 0xf2, 0x13, 0x15, 0xc9, - 0x1c, 0x4a, 0x91, 0xc1, 0xed, 0xfa, 0xf7, 0x94, 0xdb, 0xc4, 0x12, 0x3b, 0x78, 0x1a, 0xf4, 0x3e, - 0x94, 0x06, 0xf6, 0xc2, 0xfa, 0x44, 0xbd, 0x68, 0x54, 0x04, 0xff, 0xf3, 0xa6, 0x3b, 0x81, 0xa6, - 0x93, 0x11, 0x79, 0x9f, 0x09, 0x33, 0x72, 0xba, 0xe8, 0xd7, 0x50, 0xad, 0xce, 0x51, 0x54, 0xeb, - 0x38, 0x19, 0x55, 0xce, 0xbb, 0x8c, 0x81, 0x3d, 0x7d, 0x03, 0x2f, 0xb0, 0xdb, 0x6e, 0x6d, 0x9b, - 0x79, 0x32, 0xe3, 0xdb, 0x70, 0x25, 0x7b, 0x57, 0x68, 0x75, 0x6d, 0x48, 0x8e, 0x8c, 0x57, 0x4c, - 0xbe, 0x6a, 0x57, 0x6d, 0x81, 0x29, 0x6d, 0xbb, 0xaf, 0xff, 0x58, 0xc3, 0x7b, 0xaf, 0x5b, 0x2c, - 0xe2, 0xb9, 0x44, 0x8e, 0xba, 0x0d, 0xb1, 0xe9, 0x36, 0x6a, 0xe5, 0x15, 0x93, 0xdf, 0xab, 0xc9, - 0x41, 0x0c, 0xf9, 0xee, 0x01, 0x39, 0x1b, 0x3e, 0x3f, 0x59, 0xae, 0x73, 0x97, 0x31, 0x9c, 0xed, - 0x2f, 0xda, 0x3d, 0x40, 0xcf, 0x93, 0x59, 0xf9, 0xab, 0x1e, 0x7e, 0x19, 0x08, 0xff, 0x4e, 0xb2, - 0x7e, 0x8e, 0x9c, 0x01, 0x98, 0x6f, 0x31, 0xce, 0xcd, 0x0a, 0x5b, 0x33, 0x39, 0xb7, 0x6b, 0x95, - 0xb5, 0x50, 0x62, 0x60, 0xdd, 0xbb, 0xe4, 0x6c, 0xaf, 0x89, 0xa8, 0xd8, 0x09, 0x32, 0xf1, 0xa0, - 0x0d, 0x11, 0x9f, 0x0c, 0x6d, 0x82, 0x7e, 0x13, 0x17, 0xbc, 0xff, 0xfa, 0xd7, 0xde, 0x92, 0xe9, - 0xbd, 0x67, 0xd6, 0xb8, 0x69, 0xc9, 0xed, 0x35, 0x98, 0xc5, 0xec, 0x7a, 0xfb, 0xb2, 0xa0, 0x64, - 0x78, 0x2b, 0x7c, 0x5e, 0x42, 0x5b, 0xff, 0xd7, 0x30, 0xa2, 0xd8, 0x87, 0xbb, 0x6d, 0x5e, 0x82, - 0x1f, 0x18, 0xdb, 0x42, 0x96, 0xa7, 0x5b, 0xcd, 0xfc, 0x04, 0x50, 0xe5, 0x4b, 0xca, 0x08, 0x9b, - 0x74, 0x91, 0x4c, 0xf9, 0xb3, 0x6b, 0x8d, 0xea, 0x26, 0xf3, 0x7c, 0xcb, 0x2e, 0xcf, 0xb6, 0x9a, - 0xf9, 0x49, 0xa0, 0xbf, 0x0d, 0x64, 0x43, 0xed, 0xd0, 0x57, 0xc9, 0x9c, 0xe5, 0xd6, 0x84, 0x67, - 0x5a, 0xa2, 0x64, 0xfa, 0x4f, 0x1f, 0xb0, 0xf2, 0xc4, 0xf2, 0xb1, 0x56, 0x33, 0x3f, 0x1b, 0x8c, - 0x05, 0xaf, 0xa2, 0x4e, 0x02, 0x7d, 0x9d, 0x1c, 0xb3, 0x1a, 0xd5, 0x86, 0x63, 0x0a, 0x7b, 0x9b, - 0x95, 0x2a, 0x26, 0x2f, 0x35, 0x38, 0x2b, 0x67, 0x87, 0x41, 0xc4, 0x13, 0xad, 0x66, 0xfe, 0x68, - 0x38, 0xbc, 0x62, 0xf2, 0x77, 0x39, 0x2b, 0x1b, 0xdd, 0x24, 0x7a, 0x82, 0x0c, 0x3f, 0xf0, 0xdc, - 0x6a, 0x76, 0x04, 0xf8, 0xc6, 0x5b, 0xcd, 0x3c, 0xf4, 0x0d, 0xf8, 0x4b, 0xcf, 0x82, 0x8f, 0xfa, - 0x92, 0x47, 0x61, 0xc6, 0x64, 0xab, 0x99, 0x1f, 0xab, 0xa0, 0xbc, 0xa0, 0x21, 0xcd, 0xe5, 0xb8, - 0x15, 0x5e, 0xda, 0x74, 0x5c, 0xb7, 0x9a, 0x1d, 0x0b, 0xcd, 0x25, 0xa9, 0xcb, 0x92, 0x68, 0x84, - 0x4d, 0xaa, 0x93, 0x51, 0x2e, 0x4c, 0xd1, 0xe0, 0xd9, 0x71, 0x98, 0x49, 0x5a, 0xcd, 0x3c, 0x52, - 0x0c, 0xfc, 0xa5, 0xc7, 0xc9, 0x90, 0x70, 0xb3, 0x13, 0x30, 0x3e, 0xda, 0x6a, 0xe6, 0x87, 0x84, - 0x6b, 0x0c, 0x09, 0x57, 0x9a, 0x4d, 0x84, 0xdb, 0xe6, 0x6f, 0x0f, 0x09, 0xcd, 0xa6, 0x8c, 0xc1, - 0x26, 0x75, 0x12, 0xe8, 0x12, 0x39, 0xaa, 0xf2, 0xfb, 0x57, 0xe5, 0x24, 0x08, 0x98, 0x6f, 0x35, - 0xf3, 0xaa, 0xf0, 0x7b, 0x72, 0xcc, 0xe8, 0xa2, 0xd0, 0xeb, 0x64, 0x58, 0xea, 0x92, 0x9d, 0x4a, - 0xf5, 0x25, 0x76, 0xd5, 0xad, 0x18, 0x30, 0x5f, 0xff, 0x20, 0x43, 0x32, 0xab, 0x6e, 0x45, 0x1e, - 0x09, 0xc1, 0x86, 0xfb, 0xde, 0x19, 0x74, 0xe5, 0x21, 0x23, 0xdc, 0xba, 0x6d, 0xf1, 0xec, 0xd0, - 0xa9, 0xcc, 0xf9, 0x09, 0x03, 0x7b, 0xd2, 0x99, 0xcb, 0xa6, 0x30, 0x7d, 0xff, 0x30, 0xa0, 0xdd, - 0xe5, 0x73, 0x72, 0xe3, 0x87, 0x7b, 0xfb, 0x5c, 0x97, 0xf1, 0x46, 0x0e, 0x6b, 0xbc, 0x51, 0x58, - 0x38, 0xad, 0xf1, 0xa2, 0x81, 0x35, 0xd6, 0x23, 0xb0, 0x9e, 0x23, 0xd2, 0x6d, 0x70, 0xa1, 0x71, - 0x58, 0x68, 0xaa, 0xd5, 0xcc, 0x8f, 0x3b, 0x6e, 0xc5, 0x5f, 0xa0, 0xdd, 0xa2, 0x67, 0xc8, 0x98, - 0xc7, 0xaa, 0xee, 0x36, 0x2b, 0x83, 0xd7, 0x8c, 0xfb, 0x9e, 0x8a, 0x24, 0x23, 0x68, 0xe8, 0x57, - 0x31, 0xcd, 0x8c, 0x3b, 0x02, 0x92, 0x4f, 0x8e, 0x7f, 0x0e, 0x63, 0xca, 0x18, 0xc7, 0xf6, 0x5f, - 0x3b, 0x32, 0x82, 0x58, 0xcd, 0xc4, 0xc6, 0xea, 0x53, 0x24, 0x53, 0x31, 0x39, 0x1e, 0x00, 0x63, - 0xad, 0x66, 0x5e, 0x76, 0x0d, 0xf9, 0x47, 0x9a, 0xb1, 0x5d, 0x74, 0xc1, 0x0d, 0x07, 0x33, 0x56, - 0xda, 0xef, 0xf2, 0xa0, 0x25, 0xd7, 0x00, 0xfc, 0xa3, 0xe1, 0x1a, 0xb2, 0xef, 0xdb, 0x81, 0xe6, - 0x65, 0x72, 0x59, 0x6f, 0x08, 0xdc, 0xb8, 0x89, 0x56, 0x33, 0xef, 0x13, 0x0c, 0xff, 0x47, 0x4e, - 0xf0, 0xf3, 0xc5, 0xf1, 0x70, 0x02, 0x10, 0x30, 0x75, 0x4c, 0x8c, 0xeb, 0x58, 0xd7, 0x22, 0x07, - 0x8a, 0xcb, 0x3c, 0x19, 0xd9, 0x36, 0x9d, 0x06, 0xc3, 0x70, 0x86, 0xb5, 0x81, 0x60, 0xf8, 0x3f, - 0x52, 0x37, 0xb1, 0x5b, 0x67, 0xd9, 0xa9, 0x50, 0x37, 0xd9, 0x37, 0xe0, 0x2f, 0x2d, 0x92, 0x49, - 0xd3, 0xb2, 0x58, 0x50, 0x67, 0x99, 0x96, 0x11, 0xb8, 0x3c, 0xd3, 0x6a, 0xe6, 0x89, 0x4f, 0x5e, - 0xb5, 0x65, 0x26, 0x14, 0xb6, 0xe5, 0xe1, 0xd8, 0x4e, 0xb6, 0x66, 0xc2, 0xc3, 0x11, 0xef, 0xf7, - 0xf0, 0xa2, 0x3f, 0x46, 0xb4, 0xed, 0xec, 0x2c, 0x4c, 0x18, 0x69, 0x35, 0xf3, 0xda, 0xb6, 0xa1, - 0x6d, 0x4b, 0xa2, 0x97, 0x9d, 0x0b, 0x89, 0x9e, 0xa1, 0x79, 0x92, 0xc8, 0xb3, 0x47, 0x43, 0x22, - 0x37, 0x34, 0xae, 0xdf, 0xc0, 0xc7, 0x28, 0xba, 0x1e, 0x5c, 0xbf, 0xcb, 0xbb, 0xe8, 0x1f, 0xe8, - 0xb3, 0xc7, 0xc9, 0xe8, 0x56, 0x98, 0x9d, 0x0c, 0x1b, 0xd8, 0xd3, 0xff, 0x3a, 0x86, 0x4f, 0xd1, - 0x78, 0x66, 0xf4, 0x5c, 0x9d, 0x8c, 0xa2, 0x17, 0x6a, 0xe1, 0x79, 0xec, 0x53, 0x0c, 0xfc, 0x6d, - 0xfb, 0xc5, 0x50, 0xac, 0x5f, 0x14, 0xc9, 0x64, 0xdd, 0xf4, 0x58, 0x4d, 0xf8, 0xce, 0xef, 0x3b, - 0x28, 0xd8, 0xce, 0x27, 0x83, 0xf7, 0x2b, 0xed, 0xd0, 0x4f, 0x86, 0x13, 0xfc, 0xa4, 0x48, 0x26, - 0xf9, 0x96, 0xf9, 0x42, 0xa9, 0x51, 0xb3, 0x1c, 0xc6, 0xd1, 0x69, 0x41, 0xa2, 0x24, 0xbf, 0x0b, - 0x54, 0x43, 0x69, 0x77, 0x5c, 0x41, 0xa3, 0x3d, 0xae, 0xa0, 0xa8, 0xbb, 0xf1, 0x92, 0xe7, 0xba, - 0x81, 0x53, 0x77, 0xba, 0x1b, 0x37, 0x5c, 0x57, 0x18, 0x5d, 0x14, 0xb9, 0xa0, 0xbc, 0xab, 0x98, - 0xcf, 0x3b, 0x1e, 0x2e, 0x08, 0x54, 0x60, 0x0a, 0x9b, 0xf4, 0x1a, 0x99, 0xf6, 0xfc, 0x1c, 0x03, - 0x17, 0xf3, 0x43, 0x60, 0xae, 0xd5, 0xcc, 0x4f, 0x05, 0x03, 0xc0, 0x13, 0xe9, 0x49, 0x3b, 0x55, - 0xed, 0x1a, 0xf3, 0x30, 0x14, 0xc0, 0x4e, 0x40, 0x30, 0xfc, 0x1f, 0x5a, 0x20, 0xa4, 0x6c, 0x3f, - 0x78, 0x60, 0x5b, 0x0d, 0x47, 0xec, 0xa2, 0xe7, 0x83, 0x99, 0x42, 0xaa, 0xa1, 0xb4, 0xe1, 0x0a, - 0x70, 0x85, 0xe9, 0x94, 0x14, 0xae, 0x29, 0xe5, 0x0a, 0x90, 0x63, 0x77, 0x42, 0xd6, 0x4e, 0x82, - 0xd4, 0x9a, 0xed, 0x08, 0xcf, 0x2c, 0xc1, 0x85, 0x34, 0x1d, 0x6a, 0x0d, 0x54, 0xf8, 0x4c, 0x1f, - 0x36, 0xa5, 0xd7, 0x70, 0xfb, 0x7d, 0x86, 0xe1, 0x01, 0x5e, 0x23, 0xfb, 0x06, 0xfc, 0x0d, 0x8e, - 0x25, 0x07, 0x52, 0xe0, 0xd9, 0xc8, 0xb1, 0x04, 0x69, 0x70, 0x98, 0x10, 0x47, 0x12, 0x91, 0xb9, - 0x7d, 0x12, 0x91, 0x8b, 0x64, 0x42, 0xd8, 0x55, 0xc6, 0x85, 0x59, 0xad, 0x63, 0x24, 0x01, 0xba, - 0x36, 0xd1, 0x08, 0x9b, 0xf4, 0x2a, 0x99, 0x52, 0x77, 0x35, 0x4b, 0x21, 0xe4, 0x61, 0x4b, 0x22, - 0xbb, 0x1d, 0xe9, 0xc9, 0x68, 0x41, 0xa7, 0x3c, 0x06, 0xf3, 0x21, 0x5a, 0x7c, 0x8a, 0x81, 0xbf, - 0xf4, 0x06, 0x99, 0x93, 0x2f, 0x93, 0xd2, 0x03, 0xc6, 0x4a, 0x75, 0xe6, 0xc9, 0xf4, 0x2c, 0x3b, - 0x0f, 0x68, 0x8e, 0xb6, 0x9a, 0xf9, 0x69, 0x39, 0x76, 0x97, 0xb1, 0x35, 0xe6, 0xad, 0x98, 0xdc, - 0x88, 0x76, 0xa5, 0xaa, 0x55, 0xdb, 0xaf, 0x81, 0x67, 0x9f, 0x08, 0x55, 0xad, 0xda, 0xf0, 0x01, - 0xdf, 0x08, 0x1a, 0x8b, 0x1f, 0x3d, 0x4b, 0x46, 0x20, 0xb6, 0xe9, 0x0f, 0x34, 0x32, 0xea, 0x17, - 0x60, 0xe9, 0x95, 0x1e, 0xd9, 0x48, 0x77, 0x05, 0x38, 0xb7, 0x78, 0x10, 0x16, 0xff, 0xc4, 0xd0, - 0xcf, 0x7c, 0xf0, 0xa7, 0x7f, 0x7c, 0x7f, 0x28, 0x4f, 0x4f, 0x16, 0x25, 0xc7, 0x65, 0xa5, 0xf0, - 0xaf, 0x16, 0xcf, 0xe9, 0x67, 0x1a, 0x99, 0x52, 0x6b, 0x66, 0xf4, 0x46, 0x9a, 0xb5, 0xe2, 0xcb, - 0xc5, 0xb9, 0x9b, 0x7d, 0xf1, 0x22, 0xe0, 0x57, 0x00, 0xf0, 0x8b, 0xf4, 0x5a, 0x02, 0x60, 0xb5, - 0x8a, 0x57, 0x7c, 0x84, 0x5f, 0x3f, 0xf6, 0x8a, 0x8f, 0xe0, 0x30, 0xda, 0xa3, 0x9f, 0x68, 0x64, - 0x56, 0x95, 0xbb, 0xe4, 0x38, 0xe9, 0x74, 0x89, 0x2f, 0x1a, 0xa7, 0xd3, 0x25, 0xa1, 0x10, 0xac, - 0x5f, 0x04, 0x5d, 0xce, 0xd0, 0xd3, 0x29, 0x74, 0xa1, 0x7f, 0xd3, 0xc8, 0xf1, 0x0e, 0xe4, 0xf8, - 0x25, 0x92, 0x2e, 0xf5, 0x01, 0x22, 0xfa, 0x11, 0x34, 0xb7, 0x7c, 0x18, 0x11, 0xa8, 0xce, 0x0d, - 0x50, 0xe7, 0x2a, 0x5d, 0x4c, 0xa1, 0x0e, 0xf2, 0xe2, 0x0e, 0xed, 0xd1, 0x3f, 0x68, 0x64, 0x26, - 0x5a, 0xf0, 0xa2, 0xb7, 0x52, 0xba, 0x49, 0x6c, 0x81, 0x2f, 0xf7, 0x4a, 0x9f, 0xdc, 0xa8, 0xcb, - 0x4b, 0xa0, 0xcb, 0x22, 0x7d, 0x3e, 0x41, 0x97, 0x68, 0x19, 0xae, 0xf8, 0x28, 0xe8, 0xef, 0xd1, - 0x3f, 0x6b, 0x84, 0x76, 0x97, 0x3c, 0x69, 0x2a, 0x3c, 0x89, 0x85, 0xd6, 0xdc, 0xab, 0xfd, 0xb2, - 0xa3, 0x3e, 0x4b, 0xa0, 0xcf, 0x4d, 0xfa, 0x72, 0xa2, 0x3e, 0x9d, 0xff, 0xae, 0x03, 0xf7, 0x82, - 0xaa, 0xd8, 0x6f, 0x34, 0x72, 0x34, 0xba, 0x82, 0x0c, 0x9e, 0x5b, 0x29, 0x1d, 0xe7, 0x10, 0xbb, - 0x94, 0x58, 0x5a, 0xd5, 0x2f, 0x83, 0x56, 0xe7, 0xe8, 0x99, 0x54, 0xbb, 0x44, 0x3f, 0xd6, 0xc8, - 0x74, 0xa4, 0x44, 0x49, 0x5f, 0x4a, 0xe9, 0x25, 0x5d, 0x25, 0xd1, 0xdc, 0xcb, 0x7d, 0x70, 0x22, - 0xea, 0x02, 0xa0, 0x3e, 0x4f, 0xcf, 0x26, 0xa0, 0xae, 0x30, 0x51, 0x12, 0x9c, 0x07, 0x1f, 0x13, - 0xe8, 0x87, 0x1a, 0xd4, 0x3b, 0xd3, 0x5d, 0x09, 0x91, 0x02, 0x6a, 0xba, 0x2b, 0x21, 0x5a, 0x5d, - 0xd5, 0x75, 0x80, 0x77, 0x82, 0xe6, 0x12, 0xe0, 0x49, 0x28, 0x3f, 0xd7, 0xc2, 0xd2, 0x21, 0xbd, - 0x9e, 0x72, 0x91, 0x8e, 0x1a, 0x67, 0xee, 0xc5, 0x03, 0xf3, 0x21, 0xc2, 0x22, 0x20, 0x7c, 0x8e, - 0x9e, 0x4b, 0x32, 0x20, 0x32, 0x48, 0xef, 0x2d, 0xb3, 0x9d, 0x3d, 0xfa, 0x53, 0x8d, 0x4c, 0x06, - 0x52, 0xa4, 0xd3, 0x5e, 0x4f, 0xe9, 0x76, 0x7d, 0x21, 0x8e, 0xa9, 0xb4, 0xea, 0xe7, 0x00, 0xf1, - 0x33, 0x34, 0xdf, 0x03, 0x31, 0xfd, 0x54, 0x23, 0x73, 0x9d, 0x9f, 0x0a, 0x69, 0xaa, 0x4b, 0x26, - 0xe1, 0xbb, 0x65, 0xee, 0x56, 0x7f, 0xcc, 0x29, 0x4d, 0x6d, 0x75, 0x62, 0xfd, 0x4c, 0x23, 0x93, - 0xca, 0xd7, 0x40, 0x7a, 0x27, 0xcd, 0xf2, 0xbd, 0xbe, 0x3a, 0xe6, 0x5e, 0x3f, 0xa4, 0x14, 0xd4, - 0xe6, 0x02, 0x68, 0xf3, 0x2c, 0xd5, 0x93, 0xb2, 0x1d, 0x05, 0xf8, 0xaf, 0xb4, 0x48, 0xa1, 0x95, - 0xa6, 0x0d, 0xf8, 0xee, 0xd2, 0x70, 0xee, 0x46, 0x3f, 0xac, 0x08, 0x79, 0x11, 0x20, 0x5f, 0xa2, - 0x17, 0x92, 0x36, 0x20, 0xe4, 0x69, 0xbb, 0xfb, 0x2f, 0x34, 0x32, 0xa3, 0xc8, 0x92, 0x1e, 0xff, - 0x72, 0x4a, 0xcf, 0xed, 0x17, 0x7d, 0x7c, 0xb1, 0xba, 0xa7, 0xc1, 0x15, 0xf4, 0xf4, 0xd7, 0x1a, - 0x99, 0x8b, 0xd4, 0x44, 0x25, 0xee, 0xb4, 0xf9, 0x55, 0x5c, 0xcd, 0x39, 0x77, 0xab, 0x3f, 0x66, - 0xc4, 0x7e, 0x09, 0xb0, 0x9f, 0xa5, 0xcf, 0x26, 0x39, 0x8b, 0xca, 0x45, 0xff, 0xa8, 0x91, 0xf9, - 0xb8, 0x32, 0x31, 0xfd, 0x4a, 0xaa, 0xac, 0x3c, 0xb9, 0x3e, 0x9d, 0x7b, 0xad, 0x7f, 0x01, 0xa8, - 0xc9, 0x8b, 0xa0, 0xc9, 0x15, 0x5a, 0x4c, 0xa3, 0x09, 0xa6, 0x64, 0x25, 0xbb, 0xbc, 0x47, 0x3f, - 0xd7, 0xba, 0xaa, 0xa7, 0x34, 0x6d, 0x62, 0x15, 0x5f, 0xfb, 0x4d, 0x97, 0xc8, 0x24, 0xd7, 0xad, - 0xf5, 0xeb, 0xa0, 0xcb, 0xf3, 0xb4, 0x90, 0xa0, 0x8b, 0x13, 0xe5, 0x6b, 0xc7, 0xc4, 0x6f, 0x35, - 0x42, 0x3b, 0x64, 0x4a, 0xff, 0x4a, 0x9b, 0x80, 0x1c, 0x46, 0x9b, 0xe4, 0xea, 0x74, 0xcf, 0x54, - 0xa0, 0x43, 0x1b, 0xfa, 0x23, 0x8d, 0x0c, 0x43, 0x2a, 0x93, 0xf6, 0x62, 0x57, 0x93, 0xad, 0x17, - 0x0e, 0xc4, 0x93, 0xf2, 0x8d, 0x62, 0x61, 0xfa, 0x0b, 0x46, 0xfe, 0x58, 0x9e, 0x99, 0x61, 0x55, - 0x3a, 0xfd, 0x99, 0xd9, 0x55, 0xc9, 0xee, 0x0f, 0xec, 0x35, 0x00, 0x5b, 0xa4, 0x97, 0xf7, 0x05, - 0xdb, 0xf5, 0x28, 0xfc, 0xa1, 0x46, 0xc6, 0x82, 0x7c, 0x76, 0x31, 0xed, 0x69, 0x77, 0x50, 0xc3, - 0x76, 0x54, 0xa6, 0xf5, 0xd3, 0x80, 0xf5, 0x24, 0x7d, 0x7a, 0x1f, 0xac, 0xfe, 0x49, 0xee, 0x23, - 0xc3, 0x08, 0x4f, 0x7f, 0x92, 0x77, 0x15, 0x95, 0xd3, 0x9f, 0xe4, 0xdd, 0xd5, 0xe0, 0xde, 0x27, - 0x79, 0xc8, 0x43, 0x7f, 0xa9, 0x91, 0x99, 0x68, 0xf5, 0x35, 0x1d, 0xea, 0xd8, 0x7a, 0x6e, 0x3a, - 0xd4, 0xf1, 0xc5, 0xde, 0x9e, 0x0f, 0x04, 0x27, 0x8a, 0xf2, 0x27, 0x1a, 0x21, 0xe1, 0x7f, 0xed, - 0xd3, 0x6b, 0x69, 0x56, 0xee, 0xfa, 0xff, 0xff, 0xdc, 0xf5, 0x83, 0xb2, 0x21, 0xd8, 0xe7, 0x00, - 0xec, 0x69, 0xfa, 0x4c, 0x02, 0x58, 0xd1, 0x66, 0x59, 0x7e, 0xf3, 0xf3, 0x2f, 0x17, 0xb4, 0x2f, - 0xbe, 0x5c, 0xd0, 0xfe, 0xfe, 0xe5, 0x82, 0xf6, 0xe1, 0xe3, 0x85, 0x23, 0x5f, 0x3c, 0x5e, 0x38, - 0xf2, 0x97, 0xc7, 0x0b, 0x47, 0xee, 0x5f, 0xa9, 0xd8, 0x62, 0xab, 0xb1, 0x59, 0xb0, 0xdc, 0xaa, - 0x2a, 0x26, 0xc0, 0x51, 0xdc, 0x89, 0x48, 0xdc, 0xad, 0x33, 0xbe, 0x39, 0x0a, 0x69, 0xcf, 0x0b, - 0xff, 0x0e, 0x00, 0x00, 0xff, 0xff, 0xe5, 0x26, 0xeb, 0xed, 0x7e, 0x32, 0x00, 0x00, + // 3151 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xd4, 0x5b, 0xdd, 0x6f, 0x1b, 0xc7, + 0x11, 0xf7, 0x89, 0xfa, 0x5c, 0x4a, 0x96, 0xbc, 0x56, 0x1c, 0x86, 0xb1, 0x45, 0xe7, 0x1c, 0x5b, + 0x8e, 0x3f, 0xc8, 0x58, 0xb1, 0x95, 0xc4, 0x76, 0xd2, 0x48, 0x76, 0xac, 0x18, 0x51, 0x12, 0xf5, + 0xa4, 0xf4, 0xc3, 0x45, 0x4b, 0x9c, 0xc8, 0x35, 0x75, 0x30, 0xc9, 0x63, 0x6e, 0x97, 0x82, 0x14, + 0x43, 0x2d, 0x90, 0x87, 0x3e, 0x07, 0x28, 0xd0, 0xbe, 0xf4, 0xb5, 0x1f, 0x0f, 0x7d, 0x28, 0xd0, + 0xa0, 0x29, 0x50, 0x20, 0x45, 0xd1, 0xd6, 0xcd, 0x63, 0xd0, 0x02, 0x45, 0x3f, 0x00, 0xa2, 0x48, + 0xfa, 0xc4, 0xff, 0xa0, 0x40, 0x1f, 0x8a, 0x9d, 0x9b, 0xe3, 0xed, 0xf1, 0xee, 0xc4, 0x13, 0xc5, + 0x04, 0xed, 0x8b, 0xb8, 0x3b, 0x7b, 0x33, 0xfb, 0x9b, 0xd9, 0x99, 0xdd, 0xd9, 0x9b, 0x13, 0x39, + 0x51, 0x72, 0x6c, 0xce, 0x4b, 0x5b, 0xa6, 0x55, 0x2f, 0xbc, 0xd3, 0x64, 0xce, 0x6e, 0xbe, 0xe1, + 0xd8, 0xc2, 0xa6, 0xa7, 0xde, 0x65, 0xc2, 0x04, 0x72, 0x1e, 0x5a, 0xb6, 0xc3, 0xf2, 0xfe, 0xa3, + 0xd9, 0x0b, 0x25, 0x9b, 0xd7, 0x6c, 0x5e, 0xd8, 0x34, 0x39, 0x73, 0xf9, 0x0a, 0xdb, 0x57, 0x36, + 0x99, 0x30, 0xaf, 0x14, 0x1a, 0x66, 0xc5, 0xaa, 0x9b, 0xc2, 0xb2, 0xeb, 0xae, 0xa8, 0xec, 0x29, + 0x65, 0x0a, 0xf8, 0x5b, 0xac, 0xdb, 0xf5, 0x12, 0xe3, 0x38, 0x9c, 0x53, 0x87, 0x65, 0xb3, 0xe8, + 0x3e, 0x24, 0x76, 0xf0, 0x81, 0xac, 0xf2, 0x40, 0xc5, 0xe4, 0xc5, 0x86, 0x63, 0x95, 0x18, 0x8e, + 0x9d, 0x51, 0xc6, 0x80, 0xa7, 0xb8, 0x65, 0xf2, 0xad, 0xa2, 0xb0, 0x8b, 0xa5, 0x52, 0x47, 0xc0, + 0x5c, 0xe8, 0x21, 0xe1, 0x98, 0xa5, 0x07, 0xcc, 0xc1, 0x71, 0x5d, 0x19, 0xaf, 0x9a, 0x5c, 0x14, + 0x37, 0xab, 0x76, 0xe9, 0x41, 0x71, 0x8b, 0x59, 0x95, 0x2d, 0x11, 0x21, 0x03, 0xe0, 0x77, 0xcd, + 0xa1, 0x6a, 0x61, 0x37, 0x45, 0x78, 0x92, 0xc7, 0x95, 0x07, 0x1a, 0xa6, 0x63, 0xd6, 0x3c, 0xfd, + 0x67, 0x95, 0x01, 0xc1, 0x3b, 0xd4, 0x8a, 0x5d, 0xb1, 0xa1, 0x59, 0x90, 0x2d, 0xa4, 0x9e, 0xac, + 0xd8, 0x76, 0xa5, 0xca, 0x0a, 0x66, 0xc3, 0x2a, 0x98, 0xf5, 0xba, 0x2d, 0xc0, 0xce, 0xc8, 0xa3, + 0x67, 0xc8, 0x89, 0x2f, 0xcb, 0xa5, 0xd8, 0xe0, 0xfc, 0x35, 0x8b, 0x0b, 0xdb, 0xd9, 0x35, 0xd8, + 0x3b, 0x4d, 0xc6, 0x85, 0xfe, 0x2d, 0xf2, 0x78, 0x68, 0x84, 0x37, 0xec, 0x3a, 0x67, 0xf4, 0x16, + 0x19, 0x17, 0x9c, 0x17, 0xab, 0x16, 0x17, 0x19, 0xed, 0x74, 0xea, 0x7c, 0x7a, 0x41, 0xcf, 0xef, + 0xbb, 0xf6, 0xf9, 0x8d, 0xf5, 0xf5, 0xe5, 0xe1, 0x8f, 0x5b, 0xb9, 0x23, 0xc6, 0x98, 0xe0, 0x7c, + 0xd5, 0xe2, 0x42, 0x9f, 0x25, 0x14, 0xe4, 0xaf, 0x81, 0x62, 0xde, 0xac, 0xf7, 0xc8, 0xf1, 0x00, + 0xb5, 0x33, 0xe3, 0xa8, 0x6b, 0x80, 0x8c, 0x76, 0x5a, 0x3b, 0x9f, 0x5e, 0x38, 0xdb, 0x63, 0x3e, + 0x97, 0x1d, 0xa7, 0x44, 0x56, 0xfd, 0x0d, 0xf2, 0x24, 0xc8, 0x5e, 0x61, 0xe2, 0xad, 0xa6, 0xd8, + 0xd8, 0xd9, 0x70, 0x8d, 0x8d, 0x53, 0xd3, 0x0c, 0x19, 0x03, 0xe6, 0xbb, 0xb7, 0x61, 0x92, 0x94, + 0xe1, 0x75, 0xe9, 0x2c, 0x19, 0x81, 0xf5, 0xcb, 0x0c, 0x9d, 0xd6, 0xce, 0x0f, 0x1b, 0x6e, 0x47, + 0x6f, 0x92, 0x93, 0xd1, 0xe2, 0x10, 0xf3, 0xdb, 0x64, 0xd2, 0x56, 0xe8, 0x88, 0xfc, 0x62, 0x0f, + 0xe4, 0xaa, 0x28, 0xc4, 0x1f, 0x10, 0xa3, 0x33, 0xd4, 0x62, 0xa9, 0x5a, 0x8d, 0xd2, 0xe2, 0x0e, + 0x21, 0x7e, 0x34, 0xe1, 0x9c, 0xe7, 0xf2, 0x6e, 0xe8, 0xe5, 0x65, 0xe8, 0xe5, 0xdd, 0x90, 0xc5, + 0xd0, 0xcb, 0xaf, 0x99, 0x15, 0x86, 0xbc, 0x86, 0xc2, 0xa9, 0x7f, 0xa4, 0xa1, 0x7a, 0xa1, 0x79, + 0x62, 0xd5, 0x4b, 0x0d, 0x40, 0x3d, 0xba, 0x12, 0xc0, 0x3f, 0x04, 0xf8, 0xe7, 0x7b, 0xe2, 0x77, + 0x31, 0x05, 0x14, 0x78, 0x4f, 0x23, 0x7a, 0x94, 0x02, 0xcb, 0xbb, 0xb7, 0x24, 0x12, 0xcf, 0x5e, + 0xb3, 0x64, 0x04, 0x90, 0xe1, 0x9a, 0xbb, 0x9d, 0x2e, 0x2b, 0x0e, 0xf5, 0x6d, 0xc5, 0x3f, 0x68, + 0xe4, 0xcc, 0xbe, 0x20, 0xfe, 0x4f, 0x8c, 0xf9, 0x5d, 0x8d, 0x3c, 0xe5, 0xe9, 0x71, 0xb7, 0x1e, + 0x67, 0xcb, 0x27, 0xc8, 0xb8, 0xbb, 0x0f, 0x5b, 0xe5, 0x60, 0x08, 0x95, 0x07, 0x66, 0xd0, 0xdf, + 0x2a, 0xab, 0x1a, 0x05, 0x04, 0xed, 0x69, 0x90, 0xb4, 0x55, 0xef, 0x36, 0xe7, 0x85, 0x1e, 0xe6, + 0x54, 0xe5, 0xb9, 0xd6, 0x54, 0x85, 0x0c, 0xce, 0x98, 0xa7, 0xfc, 0x08, 0x56, 0xa6, 0xec, 0x6c, + 0x81, 0x8e, 0x1f, 0x78, 0xc1, 0xe1, 0xcf, 0x4f, 0x37, 0xfd, 0x06, 0x39, 0xe5, 0xed, 0x65, 0xf2, + 0xc9, 0xd7, 0x4c, 0xbe, 0xb5, 0x61, 0xdf, 0x2a, 0x89, 0x1d, 0x6f, 0x69, 0xb3, 0x64, 0xdc, 0xc2, + 0x01, 0x58, 0xda, 0x09, 0xa3, 0xd3, 0xd7, 0xf7, 0xc8, 0x5c, 0x1c, 0x33, 0x42, 0xfe, 0x06, 0x39, + 0x6a, 0x05, 0x46, 0x70, 0x63, 0xba, 0x9c, 0x00, 0xb5, 0xcf, 0x84, 0xc0, 0xbb, 0x44, 0xe9, 0x37, + 0x71, 0xfa, 0xe0, 0xc3, 0xb7, 0x4d, 0x61, 0x26, 0x01, 0xff, 0x2e, 0xc9, 0xc5, 0x72, 0x23, 0xfa, + 0xaf, 0x92, 0xa9, 0x5b, 0x12, 0x13, 0xb8, 0xd8, 0xc6, 0x0e, 0x4f, 0x18, 0x9d, 0x2a, 0x0f, 0x42, + 0x0f, 0xca, 0xd1, 0x2b, 0x68, 0x75, 0x5c, 0xe9, 0xb0, 0xd5, 0x07, 0xb5, 0x99, 0x3f, 0xd2, 0xd0, + 0x46, 0x11, 0x33, 0xed, 0xb3, 0x44, 0xa9, 0x01, 0x2d, 0xd1, 0xe0, 0x42, 0xe7, 0x06, 0x79, 0xc2, + 0x73, 0xb5, 0x0d, 0xce, 0x97, 0xca, 0x65, 0x87, 0x71, 0x2f, 0x70, 0xe8, 0x1c, 0x49, 0xcb, 0xb4, + 0xa4, 0xd1, 0xdc, 0x2c, 0x3e, 0x60, 0xbb, 0xb8, 0xd2, 0x13, 0x82, 0xf3, 0xb5, 0xe6, 0xe6, 0xeb, + 0x6c, 0x57, 0x7f, 0x85, 0x64, 0xa3, 0x98, 0xd1, 0x00, 0x33, 0x24, 0xc5, 0x84, 0xe7, 0x1f, 0xb2, + 0x29, 0x29, 0x9b, 0xa2, 0x04, 0x70, 0x27, 0x0c, 0xd9, 0xec, 0xe4, 0x2c, 0x52, 0xc2, 0xfa, 0xba, + 0x17, 0xb0, 0xaf, 0x63, 0xce, 0xe2, 0x51, 0x51, 0xe0, 0x55, 0x92, 0xda, 0x58, 0x5f, 0xc7, 0x55, + 0x4b, 0x90, 0x20, 0x19, 0xf2, 0x71, 0xbd, 0x80, 0x69, 0xd7, 0x0a, 0x13, 0x2b, 0x26, 0x5f, 0x93, + 0x79, 0xab, 0x72, 0x54, 0x59, 0xf5, 0x32, 0xdb, 0x41, 0x8c, 0x6e, 0x47, 0x2f, 0x92, 0x4c, 0x98, + 0xc1, 0x4f, 0xd4, 0x3c, 0x1a, 0xe2, 0x98, 0xef, 0x81, 0xa3, 0x23, 0xa2, 0xc3, 0xa8, 0x9b, 0x88, + 0x68, 0xa9, 0x5a, 0xed, 0x46, 0x34, 0x28, 0xff, 0xfc, 0xa9, 0x86, 0x4a, 0x04, 0xe6, 0x88, 0x54, + 0x22, 0xd5, 0x97, 0x12, 0x83, 0xf3, 0xc0, 0x05, 0xdf, 0x89, 0x20, 0x8e, 0xdf, 0x84, 0x7b, 0xc9, + 0xfe, 0x4b, 0xf4, 0xc0, 0x4f, 0x3c, 0x03, 0x3c, 0xa8, 0xe0, 0x2a, 0x49, 0x2b, 0x64, 0x34, 0x63, + 0xaf, 0x0d, 0x5d, 0x15, 0xa4, 0xb2, 0xeb, 0x65, 0x04, 0xb8, 0x54, 0xad, 0x46, 0x00, 0x1c, 0xd4, + 0x8a, 0x7d, 0xa0, 0xf9, 0x87, 0x58, 0x22, 0x9d, 0x52, 0x87, 0xd0, 0x69, 0x70, 0xab, 0x37, 0xe7, + 0x9f, 0xad, 0x6b, 0xac, 0x5e, 0xb6, 0xea, 0x95, 0x80, 0x79, 0x74, 0xe1, 0xef, 0xc8, 0x5d, 0xe3, + 0xa8, 0xd7, 0x3a, 0x39, 0xda, 0x70, 0x07, 0xf0, 0x46, 0x8a, 0xaa, 0x5d, 0xea, 0x75, 0x21, 0x09, + 0x48, 0x9b, 0x6a, 0xa8, 0x5d, 0xfd, 0x25, 0x72, 0xda, 0xbd, 0xf4, 0xa8, 0xd4, 0xc4, 0xb9, 0x95, + 0xfe, 0x6d, 0xcc, 0xcd, 0xa2, 0xd9, 0x11, 0xf8, 0xd7, 0x23, 0x80, 0x6b, 0x07, 0x05, 0xee, 0x1d, + 0x63, 0x41, 0xf8, 0x8b, 0xfe, 0xf9, 0xbf, 0x6a, 0x72, 0xb1, 0x2c, 0x6f, 0xc2, 0xaf, 0xc1, 0x45, + 0x78, 0xff, 0xb0, 0x78, 0x88, 0x47, 0x6f, 0x14, 0x1f, 0xa2, 0xfe, 0x1a, 0x99, 0xee, 0x1a, 0x42, + 0xd8, 0xf9, 0x1e, 0xb0, 0xbb, 0x05, 0x76, 0x8b, 0xd1, 0xb7, 0xfc, 0x13, 0x31, 0x06, 0xf4, 0xa0, + 0x42, 0xe5, 0xf7, 0x1a, 0xea, 0x19, 0x35, 0xd5, 0x7e, 0x7a, 0xa6, 0x06, 0xa0, 0xe7, 0xe0, 0x42, + 0xe7, 0xa2, 0x7f, 0xca, 0xa9, 0x29, 0x4a, 0xf4, 0xd2, 0xae, 0x2a, 0xbb, 0xa4, 0x4c, 0x0b, 0x76, + 0xc1, 0x55, 0xfa, 0xbd, 0x69, 0x57, 0xc8, 0x6c, 0x70, 0x6a, 0xb4, 0xda, 0x5b, 0x64, 0x52, 0x4d, + 0xa8, 0x12, 0xde, 0xb0, 0x55, 0x16, 0x23, 0x20, 0x40, 0xff, 0x26, 0xea, 0x28, 0x37, 0xb5, 0xcf, + 0x21, 0x0d, 0xfb, 0xb9, 0x86, 0x8a, 0x74, 0xe4, 0xc7, 0x2a, 0x92, 0x3a, 0x94, 0x22, 0x83, 0x5b, + 0xf5, 0xef, 0x28, 0xa7, 0x49, 0x49, 0xec, 0xe0, 0x6e, 0xf0, 0x05, 0x5e, 0xf8, 0x3e, 0x54, 0x0f, + 0x1a, 0x15, 0xc1, 0xff, 0xbc, 0xe9, 0x4e, 0xa2, 0xe9, 0x64, 0x44, 0xde, 0x63, 0xc2, 0x0c, 0xec, + 0x2e, 0xfa, 0x35, 0x54, 0xab, 0x7b, 0x14, 0xd5, 0x3a, 0x41, 0x46, 0x95, 0xfd, 0x2e, 0x65, 0x60, + 0x4f, 0xdf, 0xc0, 0x03, 0xec, 0x96, 0x5d, 0xdf, 0x66, 0x8e, 0xcc, 0xf8, 0x36, 0x6c, 0xc9, 0x1e, + 0x0a, 0xad, 0xd0, 0x82, 0x64, 0xc9, 0x78, 0xc5, 0xe4, 0xab, 0x56, 0xcd, 0x12, 0x98, 0xd2, 0x76, + 0xfa, 0xfa, 0x8f, 0x34, 0x3c, 0xf7, 0xc2, 0x62, 0x11, 0xcf, 0x25, 0x72, 0xcc, 0x6e, 0x8a, 0x4d, + 0xbb, 0x59, 0x2f, 0xaf, 0x98, 0xfc, 0x6e, 0x5d, 0x0e, 0x62, 0xc8, 0x87, 0x07, 0xe4, 0xd3, 0xf0, + 0x7a, 0xb1, 0x64, 0x57, 0xef, 0x30, 0x86, 0x4f, 0xbb, 0x93, 0x86, 0x07, 0xe8, 0x79, 0x32, 0x2d, + 0x7f, 0xd5, 0xcd, 0x2f, 0x05, 0xe1, 0xdf, 0x4d, 0xd6, 0xe7, 0xc9, 0x59, 0x80, 0xf9, 0x06, 0xe3, + 0xdc, 0xac, 0xb0, 0x35, 0x93, 0x73, 0xab, 0x5e, 0x59, 0xf3, 0x25, 0x7a, 0xd6, 0xbd, 0x43, 0xce, + 0xf5, 0x7a, 0x10, 0x15, 0x3b, 0x49, 0x26, 0xee, 0x77, 0x20, 0xe2, 0x95, 0xa1, 0x43, 0xd0, 0x6f, + 0xe0, 0x84, 0xf7, 0x5e, 0xfd, 0xca, 0x1b, 0x32, 0xbd, 0x77, 0xcc, 0x3a, 0x37, 0x4b, 0x72, 0x79, + 0x0d, 0x56, 0x62, 0x56, 0xa3, 0x73, 0x58, 0x50, 0x32, 0xbc, 0xe5, 0x5f, 0x2f, 0xa1, 0xad, 0xff, + 0x67, 0x18, 0x51, 0xec, 0xc3, 0xdd, 0x31, 0x2f, 0xc1, 0x17, 0xc8, 0x1d, 0x21, 0xcb, 0x53, 0xed, + 0x56, 0x6e, 0x02, 0xa8, 0xf2, 0x26, 0x65, 0xf8, 0x4d, 0xba, 0x40, 0x26, 0xdd, 0xa7, 0xeb, 0xcd, + 0xda, 0x26, 0x73, 0x5c, 0xcb, 0x2e, 0x4f, 0xb7, 0x5b, 0xb9, 0x34, 0xd0, 0xdf, 0x04, 0xb2, 0xa1, + 0x76, 0xe8, 0xcb, 0x64, 0xa6, 0x64, 0xd7, 0x85, 0x63, 0x96, 0x44, 0xd1, 0x74, 0xaf, 0x3e, 0x60, + 0xe5, 0x89, 0xe5, 0xe3, 0xed, 0x56, 0x6e, 0xda, 0x1b, 0xf3, 0x6e, 0x45, 0xdd, 0x04, 0xfa, 0x2a, + 0x39, 0x5e, 0x6a, 0xd6, 0x9a, 0x55, 0x53, 0x58, 0xdb, 0xac, 0x58, 0x31, 0x79, 0xb1, 0xc9, 0x59, + 0x39, 0x33, 0x0c, 0x22, 0x1e, 0x6b, 0xb7, 0x72, 0xc7, 0xfc, 0xe1, 0x15, 0x93, 0xbf, 0xcd, 0x59, + 0xd9, 0x08, 0x93, 0xe8, 0x49, 0x32, 0x7c, 0xdf, 0xb1, 0x6b, 0x99, 0x11, 0xe0, 0x1b, 0x6f, 0xb7, + 0x72, 0xd0, 0x37, 0xe0, 0x2f, 0x3d, 0x07, 0x3e, 0xea, 0x4a, 0x1e, 0x85, 0x27, 0xd2, 0xed, 0x56, + 0x6e, 0xac, 0x82, 0xf2, 0xbc, 0x86, 0x34, 0x57, 0xd5, 0xae, 0xf0, 0xe2, 0x66, 0xd5, 0xb6, 0x6b, + 0x99, 0x31, 0xdf, 0x5c, 0x92, 0xba, 0x2c, 0x89, 0x86, 0xdf, 0xa4, 0x3a, 0x19, 0xe5, 0xc2, 0x14, + 0x4d, 0x9e, 0x19, 0x87, 0x27, 0x49, 0xbb, 0x95, 0x43, 0x8a, 0x81, 0xbf, 0xf4, 0x04, 0x19, 0x12, + 0x76, 0x66, 0x02, 0xc6, 0x47, 0xdb, 0xad, 0xdc, 0x90, 0xb0, 0x8d, 0x21, 0x61, 0x4b, 0xb3, 0x09, + 0x7f, 0xd9, 0xdc, 0xe5, 0x21, 0xbe, 0xd9, 0x94, 0x31, 0x58, 0xa4, 0x6e, 0x02, 0x5d, 0x22, 0xc7, + 0x54, 0x7e, 0xf7, 0xa8, 0x4c, 0x83, 0x80, 0xd9, 0x76, 0x2b, 0xa7, 0x0a, 0xbf, 0x2b, 0xc7, 0x8c, + 0x10, 0x85, 0x2e, 0x92, 0x61, 0xa9, 0x4b, 0x66, 0x32, 0xd1, 0x9b, 0xf6, 0x55, 0xbb, 0x62, 0xc0, + 0xf3, 0xfa, 0x7b, 0x29, 0x92, 0x5a, 0xb5, 0x2b, 0x72, 0x4b, 0xf0, 0x16, 0xdc, 0xf5, 0x4e, 0xaf, + 0x2b, 0x37, 0x19, 0x61, 0x37, 0xac, 0x12, 0xcf, 0x0c, 0x9d, 0x4e, 0x9d, 0x9f, 0x30, 0xb0, 0x27, + 0x9d, 0xb9, 0x6c, 0x0a, 0xd3, 0xf5, 0x0f, 0x03, 0xda, 0x21, 0x9f, 0x93, 0x0b, 0x3f, 0xdc, 0xdb, + 0xe7, 0x42, 0xc6, 0x1b, 0x39, 0xac, 0xf1, 0x46, 0x61, 0xe2, 0xa4, 0xc6, 0x0b, 0x06, 0xd6, 0x58, + 0x8f, 0xc0, 0x7a, 0x86, 0x48, 0xb7, 0xc1, 0x89, 0xc6, 0x61, 0xa2, 0xc9, 0x76, 0x2b, 0x37, 0x5e, + 0xb5, 0x2b, 0xee, 0x04, 0x9d, 0x16, 0x3d, 0x4b, 0xc6, 0x1c, 0x56, 0xb3, 0xb7, 0x59, 0x19, 0xbc, + 0x66, 0xdc, 0xf5, 0x54, 0x24, 0x19, 0x5e, 0x43, 0xbf, 0x8a, 0x69, 0x66, 0xd4, 0x16, 0x10, 0xbf, + 0x73, 0xfc, 0x7b, 0x18, 0x53, 0xc6, 0x28, 0xb6, 0x2f, 0x6c, 0xcb, 0xf0, 0x62, 0x35, 0x15, 0x19, + 0xab, 0x4f, 0x90, 0x54, 0xc5, 0xe4, 0xb8, 0x01, 0x8c, 0xb5, 0x5b, 0x39, 0xd9, 0x35, 0xe4, 0x1f, + 0x69, 0xc6, 0x4e, 0xd1, 0x0d, 0x17, 0x1c, 0xcc, 0x58, 0xe9, 0xdc, 0xcb, 0xbd, 0x96, 0x9c, 0x03, + 0xf0, 0x8f, 0xfa, 0x73, 0xc8, 0xbe, 0x6b, 0x07, 0x9a, 0x93, 0xc9, 0x65, 0xa3, 0x29, 0x70, 0xe1, + 0x26, 0xda, 0xad, 0x9c, 0x4b, 0x30, 0xdc, 0x1f, 0xf9, 0x80, 0x9b, 0x2f, 0x8e, 0xfb, 0x0f, 0x00, + 0x01, 0x53, 0xc7, 0xd8, 0xb8, 0x8e, 0x74, 0x2d, 0x72, 0xa0, 0xb8, 0xcc, 0x91, 0x91, 0x6d, 0xb3, + 0xda, 0x64, 0x18, 0xce, 0x30, 0x37, 0x10, 0x0c, 0xf7, 0x47, 0xea, 0x26, 0x76, 0x1b, 0x2c, 0x33, + 0xe9, 0xeb, 0x26, 0xfb, 0x06, 0xfc, 0xa5, 0x05, 0x92, 0x36, 0x4b, 0x25, 0xe6, 0xd5, 0xd1, 0xa6, + 0x64, 0x04, 0x2e, 0x1f, 0x6d, 0xb7, 0x72, 0xc4, 0x25, 0xaf, 0x5a, 0x32, 0x13, 0xf2, 0xdb, 0x72, + 0x73, 0xec, 0x24, 0x5b, 0x47, 0xfd, 0xcd, 0x11, 0xcf, 0x77, 0xff, 0xa0, 0x3f, 0x4e, 0xb4, 0xed, + 0xcc, 0x34, 0x3c, 0x30, 0xd2, 0x6e, 0xe5, 0xb4, 0x6d, 0x43, 0xdb, 0x96, 0x44, 0x27, 0x33, 0xe3, + 0x13, 0x1d, 0x43, 0x73, 0x24, 0x91, 0x67, 0x8e, 0xf9, 0x44, 0x6e, 0x68, 0x5c, 0xbf, 0x8e, 0x97, + 0x51, 0x74, 0x3d, 0x38, 0x7e, 0x97, 0x77, 0xd1, 0x3f, 0xd0, 0x67, 0x4f, 0x90, 0xd1, 0x2d, 0x3f, + 0x3b, 0x19, 0x36, 0xb0, 0xa7, 0xff, 0x6d, 0x0c, 0xaf, 0xa2, 0xd1, 0xcc, 0xe8, 0xb9, 0x3a, 0x19, + 0x45, 0x2f, 0xd4, 0xfc, 0xfd, 0xd8, 0xa5, 0x18, 0xf8, 0xdb, 0xf1, 0x8b, 0xa1, 0x48, 0xbf, 0x28, + 0x90, 0x74, 0xc3, 0x74, 0x58, 0x5d, 0xb8, 0xce, 0xef, 0x3a, 0x28, 0xd8, 0xce, 0x25, 0x83, 0xf7, + 0x2b, 0x6d, 0xdf, 0x4f, 0x86, 0x63, 0xfc, 0xa4, 0x40, 0xd2, 0x7c, 0xcb, 0x7c, 0xae, 0xd8, 0xac, + 0x97, 0xaa, 0x8c, 0xa3, 0xd3, 0x82, 0x44, 0x49, 0x7e, 0x1b, 0xa8, 0x86, 0xd2, 0xee, 0x3a, 0x82, + 0x46, 0x7b, 0x1c, 0x41, 0x41, 0x77, 0xe3, 0x45, 0xc7, 0xb6, 0x3d, 0xa7, 0xee, 0x76, 0x37, 0x6e, + 0xd8, 0xb6, 0x30, 0x42, 0x14, 0x39, 0xa1, 0x3c, 0xab, 0x98, 0xcb, 0x3b, 0xee, 0x4f, 0x08, 0x54, + 0x60, 0xf2, 0x9b, 0xf4, 0x1a, 0x99, 0x72, 0xdc, 0x1c, 0x03, 0x27, 0x73, 0x43, 0x60, 0xa6, 0xdd, + 0xca, 0x4d, 0x7a, 0x03, 0xc0, 0x13, 0xe8, 0x49, 0x3b, 0xd5, 0xac, 0x3a, 0x73, 0x30, 0x14, 0xc0, + 0x4e, 0x40, 0x30, 0xdc, 0x1f, 0x9a, 0x27, 0xa4, 0x6c, 0xdd, 0xbf, 0x6f, 0x95, 0x9a, 0x55, 0xb1, + 0x8b, 0x9e, 0x0f, 0x66, 0xf2, 0xa9, 0x86, 0xd2, 0x86, 0x23, 0xc0, 0x16, 0x66, 0xb5, 0xa8, 0x70, + 0x4d, 0x2a, 0x47, 0x80, 0x1c, 0xbb, 0xed, 0xb3, 0x76, 0x13, 0xa4, 0xd6, 0x6c, 0x47, 0x38, 0x66, + 0x11, 0x0e, 0xa4, 0x29, 0x5f, 0x6b, 0xa0, 0xc2, 0x6b, 0x7a, 0xbf, 0x29, 0xbd, 0x86, 0x5b, 0xef, + 0x32, 0x0c, 0x0f, 0xf0, 0x1a, 0xd9, 0x37, 0xe0, 0xaf, 0xb7, 0x2d, 0x55, 0x21, 0x05, 0x9e, 0x0e, + 0x6c, 0x4b, 0x90, 0x06, 0xfb, 0x09, 0x71, 0x20, 0x11, 0x99, 0xd9, 0x27, 0x11, 0xb9, 0x48, 0x26, + 0x84, 0x55, 0x63, 0x5c, 0x98, 0xb5, 0x06, 0x46, 0x12, 0xa0, 0xeb, 0x10, 0x0d, 0xbf, 0x49, 0xaf, + 0x92, 0x49, 0x75, 0x55, 0x33, 0x14, 0x42, 0x1e, 0x96, 0x24, 0xb0, 0xda, 0x81, 0x9e, 0x8c, 0x16, + 0x74, 0xca, 0xe3, 0xf0, 0x3c, 0x44, 0x8b, 0x4b, 0x31, 0xf0, 0x97, 0x5e, 0x27, 0x33, 0xf2, 0x66, + 0x52, 0xbc, 0xcf, 0x58, 0xb1, 0xc1, 0x1c, 0x99, 0x9e, 0x65, 0x66, 0x01, 0xcd, 0xb1, 0x76, 0x2b, + 0x37, 0x25, 0xc7, 0xee, 0x30, 0xb6, 0xc6, 0x9c, 0x15, 0x93, 0x1b, 0xc1, 0xae, 0x54, 0xb5, 0x66, + 0xb9, 0xdf, 0x40, 0x64, 0x1e, 0xf3, 0x55, 0xad, 0x59, 0xf0, 0x02, 0xdf, 0xf0, 0x1a, 0x0b, 0x8f, + 0xe6, 0xc9, 0x08, 0xc4, 0x36, 0xfd, 0xbe, 0x46, 0x46, 0xdd, 0x02, 0x3b, 0xbd, 0xd2, 0x23, 0x1b, + 0x09, 0x57, 0xf8, 0xb3, 0x0b, 0x07, 0x61, 0x71, 0x77, 0x0c, 0xfd, 0xec, 0x7b, 0x7f, 0xfe, 0xd7, + 0xf7, 0x86, 0x72, 0xf4, 0x54, 0x41, 0x72, 0x5c, 0x56, 0x3e, 0xfc, 0x50, 0x3f, 0x8e, 0xa0, 0x8f, + 0x34, 0x32, 0xa9, 0xd6, 0x44, 0xe9, 0xf5, 0x24, 0x73, 0x45, 0x7f, 0x0e, 0x90, 0xbd, 0xd1, 0x17, + 0x2f, 0x02, 0x7e, 0x09, 0x00, 0x3f, 0x4f, 0xaf, 0xc5, 0x00, 0x56, 0xab, 0xb4, 0x85, 0x87, 0xf8, + 0xf6, 0x63, 0xaf, 0xf0, 0x10, 0x36, 0xa3, 0x3d, 0xfa, 0xa1, 0x46, 0xa6, 0x55, 0xb9, 0x4b, 0xd5, + 0x6a, 0x32, 0x5d, 0xa2, 0x3f, 0x0a, 0x48, 0xa6, 0x4b, 0x4c, 0xa1, 0x5f, 0xbf, 0x08, 0xba, 0x9c, + 0xa5, 0x67, 0x12, 0xe8, 0x42, 0xff, 0xa1, 0x91, 0x13, 0x5d, 0xc8, 0xf1, 0x4d, 0x24, 0x5d, 0xea, + 0x03, 0x44, 0xf0, 0x25, 0x68, 0x76, 0xf9, 0x30, 0x22, 0x50, 0x9d, 0xeb, 0xa0, 0xce, 0x55, 0xba, + 0x90, 0x40, 0x1d, 0xe4, 0xc5, 0x15, 0xda, 0xa3, 0x7f, 0xd7, 0xc8, 0x63, 0x4a, 0x25, 0x55, 0x51, + 0xee, 0x95, 0x84, 0xc8, 0x62, 0x8b, 0xe7, 0xd9, 0xa5, 0x43, 0x48, 0x40, 0xd5, 0x6e, 0x82, 0x6a, + 0x8b, 0xf4, 0x6a, 0x8c, 0x6a, 0x56, 0x3d, 0x46, 0xb3, 0xa2, 0x55, 0xde, 0xa3, 0xbf, 0xd4, 0xc8, + 0xd1, 0xa0, 0x72, 0x89, 0x7d, 0x2e, 0xa2, 0x8c, 0x9d, 0xd8, 0xe7, 0xa2, 0x6a, 0xdc, 0x3d, 0x7d, + 0x4e, 0xd1, 0x84, 0xd3, 0x3f, 0x22, 0x70, 0xa5, 0xe0, 0x78, 0x33, 0x61, 0xf0, 0x46, 0x96, 0x5d, + 0xb3, 0x2f, 0xf5, 0xc9, 0x8d, 0xe0, 0x5f, 0x00, 0xf0, 0x0b, 0xf4, 0xd9, 0x7d, 0xc0, 0xfb, 0x6c, + 0x85, 0x87, 0x5e, 0x7f, 0x8f, 0xfe, 0x45, 0x23, 0x34, 0x5c, 0x88, 0xa6, 0x89, 0xf0, 0xc4, 0x96, + 0xbf, 0xb3, 0x2f, 0xf7, 0xcb, 0x8e, 0xfa, 0x2c, 0x81, 0x3e, 0x37, 0xe8, 0x8b, 0xb1, 0xfa, 0x74, + 0x7f, 0x44, 0x07, 0xa7, 0xb5, 0xaa, 0xd8, 0x6f, 0x34, 0x72, 0x2c, 0x38, 0x83, 0x74, 0xaf, 0x9b, + 0x07, 0x70, 0x91, 0x3e, 0x57, 0x29, 0xb6, 0xe0, 0xad, 0x5f, 0x06, 0xad, 0xe6, 0xe9, 0xd9, 0x44, + 0xab, 0x44, 0x3f, 0xd0, 0xc8, 0x54, 0xa0, 0x70, 0x4c, 0x5f, 0x48, 0xe8, 0x25, 0xa1, 0x42, 0x75, + 0xf6, 0xc5, 0x3e, 0x38, 0x11, 0x75, 0x1e, 0x50, 0x9f, 0xa7, 0xe7, 0x62, 0x50, 0x57, 0x98, 0x28, + 0x0a, 0xce, 0xbd, 0x57, 0x3c, 0xf4, 0x7d, 0x0d, 0xaa, 0xd0, 0xc9, 0x0e, 0xea, 0x40, 0x59, 0x3b, + 0xd9, 0x41, 0x1d, 0xac, 0x79, 0xeb, 0x3a, 0xc0, 0x3b, 0x49, 0xb3, 0x31, 0xf0, 0x24, 0x94, 0x9f, + 0x69, 0x7e, 0x41, 0x97, 0x2e, 0x26, 0x9c, 0xa4, 0xab, 0xf2, 0x9c, 0x7d, 0xfe, 0xc0, 0x7c, 0x88, + 0xb0, 0x00, 0x08, 0x9f, 0xa1, 0xf3, 0x71, 0x06, 0x44, 0x06, 0xe9, 0xbd, 0x65, 0xb6, 0xb3, 0x47, + 0x7f, 0xa2, 0x91, 0xb4, 0x27, 0x45, 0x3a, 0xed, 0x62, 0x42, 0xb7, 0xeb, 0x0b, 0x71, 0x44, 0xfd, + 0x5b, 0x9f, 0x07, 0xc4, 0x4f, 0xd1, 0x5c, 0x0f, 0xc4, 0xf4, 0x23, 0x8d, 0xcc, 0x74, 0xbf, 0xc0, + 0xa5, 0x89, 0xb6, 0xe1, 0x98, 0xb7, 0xc9, 0xd9, 0x9b, 0xfd, 0x31, 0x27, 0x34, 0x75, 0xa9, 0x1b, + 0xeb, 0x23, 0x8d, 0xa4, 0x95, 0x77, 0xb4, 0xf4, 0x76, 0x92, 0xe9, 0x7b, 0xbd, 0x0b, 0xce, 0xbe, + 0x7a, 0x48, 0x29, 0xa8, 0xcd, 0x05, 0xd0, 0xe6, 0x69, 0xaa, 0xc7, 0xe5, 0xa0, 0x0a, 0xf0, 0x5f, + 0x69, 0x81, 0xf2, 0x37, 0x4d, 0x1a, 0xf0, 0xe1, 0x82, 0x7d, 0xf6, 0x7a, 0x3f, 0xac, 0x08, 0x79, + 0x01, 0x20, 0x5f, 0xa2, 0x17, 0xe2, 0x16, 0xc0, 0xe7, 0xe9, 0xb8, 0xfb, 0x2f, 0x34, 0x72, 0x54, + 0x91, 0x25, 0x3d, 0xfe, 0xc5, 0x84, 0x9e, 0xdb, 0x2f, 0xfa, 0xe8, 0x4f, 0x08, 0x7a, 0x1a, 0x5c, + 0x41, 0x4f, 0x7f, 0xad, 0x91, 0x99, 0x40, 0xa5, 0x5a, 0xe2, 0x4e, 0x9a, 0x81, 0x44, 0x7d, 0x09, + 0x90, 0xbd, 0xd9, 0x1f, 0x33, 0x62, 0xbf, 0x04, 0xd8, 0xcf, 0xd1, 0xa7, 0xe3, 0x9c, 0x45, 0xe5, + 0xa2, 0x7f, 0xd2, 0xc8, 0x6c, 0x54, 0xf1, 0x9e, 0x7e, 0x29, 0xd1, 0x5d, 0x29, 0xfe, 0xab, 0x81, + 0xec, 0x2b, 0xfd, 0x0b, 0x40, 0x4d, 0x9e, 0x07, 0x4d, 0xae, 0xd0, 0x42, 0x12, 0x4d, 0xd4, 0x74, + 0xf2, 0x63, 0x2d, 0x54, 0xd3, 0xa6, 0x49, 0x13, 0xab, 0xe8, 0x8a, 0x7c, 0xb2, 0x44, 0x26, 0xfe, + 0x6b, 0x02, 0x7d, 0x11, 0x74, 0x79, 0x96, 0xe6, 0x63, 0x74, 0xa9, 0x06, 0xf9, 0x3a, 0x31, 0xf1, + 0x3b, 0x8d, 0xd0, 0x2e, 0x99, 0xd2, 0xbf, 0x92, 0x26, 0x20, 0x87, 0xd1, 0x26, 0xfe, 0x9b, 0x81, + 0x9e, 0xa9, 0x40, 0x97, 0x36, 0xf4, 0x87, 0x1a, 0x19, 0x86, 0x54, 0x26, 0xe9, 0xc1, 0xae, 0x26, + 0x5b, 0xcf, 0x1d, 0x88, 0x27, 0x61, 0x16, 0x5f, 0xc2, 0xf4, 0x17, 0x8c, 0xfc, 0x81, 0xdc, 0x33, + 0xfd, 0x6f, 0x05, 0x92, 0xef, 0x99, 0xa1, 0xef, 0x0b, 0xfa, 0x03, 0x7b, 0x0d, 0xc0, 0x16, 0xe8, + 0xe5, 0x7d, 0xc1, 0x86, 0xae, 0xea, 0x3f, 0xd0, 0xc8, 0x98, 0x97, 0xcf, 0x2e, 0x24, 0xdd, 0xed, + 0x0e, 0x6a, 0xd8, 0xae, 0xef, 0x05, 0xf4, 0x33, 0x80, 0xf5, 0x14, 0x7d, 0x72, 0x1f, 0xac, 0xee, + 0x4e, 0xee, 0x22, 0xc3, 0x08, 0x4f, 0xbe, 0x93, 0x87, 0x4a, 0xfd, 0xc9, 0x77, 0xf2, 0x70, 0x8d, + 0xbe, 0xf7, 0x4e, 0xee, 0xf3, 0xc0, 0x2d, 0x34, 0x58, 0x13, 0x4f, 0x86, 0x3a, 0xb2, 0xca, 0x9e, + 0x0c, 0x75, 0x74, 0x09, 0xbe, 0xe7, 0x05, 0xa1, 0x1a, 0x44, 0xf9, 0x63, 0x8d, 0x10, 0xff, 0x7f, + 0x65, 0xe8, 0xb5, 0x24, 0x33, 0x87, 0xfe, 0xeb, 0x26, 0xbb, 0x78, 0x50, 0x36, 0x04, 0xfb, 0x0c, + 0x80, 0x3d, 0x43, 0x9f, 0x8a, 0x01, 0x2b, 0x3a, 0x2c, 0xcb, 0xaf, 0x7f, 0xfc, 0xe9, 0x9c, 0xf6, + 0xc9, 0xa7, 0x73, 0xda, 0x3f, 0x3f, 0x9d, 0xd3, 0xde, 0xff, 0x6c, 0xee, 0xc8, 0x27, 0x9f, 0xcd, + 0x1d, 0xf9, 0xeb, 0x67, 0x73, 0x47, 0xee, 0x5d, 0xa9, 0x58, 0x62, 0xab, 0xb9, 0x99, 0x2f, 0xd9, + 0x35, 0x55, 0x8c, 0x87, 0xa3, 0xb0, 0x13, 0x90, 0xb8, 0xdb, 0x60, 0x7c, 0x73, 0x14, 0xd2, 0x9e, + 0xe7, 0xfe, 0x1b, 0x00, 0x00, 0xff, 0xff, 0x16, 0xbf, 0x39, 0xb6, 0x14, 0x36, 0x00, 0x00, } // Reference imports to suppress errors if they are not otherwise used. @@ -3297,6 +3492,8 @@ type QueryClient interface { // Queries a list of OutTxTracker items. OutTxTrackerAll(ctx context.Context, in *QueryAllOutTxTrackerRequest, opts ...grpc.CallOption) (*QueryAllOutTxTrackerResponse, error) OutTxTrackerAllByChain(ctx context.Context, in *QueryAllOutTxTrackerByChainRequest, opts ...grpc.CallOption) (*QueryAllOutTxTrackerByChainResponse, error) + InTxTrackerAllByChain(ctx context.Context, in *QueryAllInTxTrackerByChainRequest, opts ...grpc.CallOption) (*QueryAllInTxTrackerByChainResponse, error) + InTxTrackerAll(ctx context.Context, in *QueryAllInTxTrackersRequest, opts ...grpc.CallOption) (*QueryAllInTxTrackersResponse, error) // Queries a InTxHashToCctx by index. InTxHashToCctx(ctx context.Context, in *QueryGetInTxHashToCctxRequest, opts ...grpc.CallOption) (*QueryGetInTxHashToCctxResponse, error) // Queries a InTxHashToCctx data by index. @@ -3380,6 +3577,24 @@ func (c *queryClient) OutTxTrackerAllByChain(ctx context.Context, in *QueryAllOu return out, nil } +func (c *queryClient) InTxTrackerAllByChain(ctx context.Context, in *QueryAllInTxTrackerByChainRequest, opts ...grpc.CallOption) (*QueryAllInTxTrackerByChainResponse, error) { + out := new(QueryAllInTxTrackerByChainResponse) + err := c.cc.Invoke(ctx, "/zetachain.zetacore.crosschain.Query/InTxTrackerAllByChain", in, out, opts...) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *queryClient) InTxTrackerAll(ctx context.Context, in *QueryAllInTxTrackersRequest, opts ...grpc.CallOption) (*QueryAllInTxTrackersResponse, error) { + out := new(QueryAllInTxTrackersResponse) + err := c.cc.Invoke(ctx, "/zetachain.zetacore.crosschain.Query/InTxTrackerAll", in, out, opts...) + if err != nil { + return nil, err + } + return out, nil +} + func (c *queryClient) InTxHashToCctx(ctx context.Context, in *QueryGetInTxHashToCctxRequest, opts ...grpc.CallOption) (*QueryGetInTxHashToCctxResponse, error) { out := new(QueryGetInTxHashToCctxResponse) err := c.cc.Invoke(ctx, "/zetachain.zetacore.crosschain.Query/InTxHashToCctx", in, out, opts...) @@ -3578,6 +3793,8 @@ type QueryServer interface { // Queries a list of OutTxTracker items. OutTxTrackerAll(context.Context, *QueryAllOutTxTrackerRequest) (*QueryAllOutTxTrackerResponse, error) OutTxTrackerAllByChain(context.Context, *QueryAllOutTxTrackerByChainRequest) (*QueryAllOutTxTrackerByChainResponse, error) + InTxTrackerAllByChain(context.Context, *QueryAllInTxTrackerByChainRequest) (*QueryAllInTxTrackerByChainResponse, error) + InTxTrackerAll(context.Context, *QueryAllInTxTrackersRequest) (*QueryAllInTxTrackersResponse, error) // Queries a InTxHashToCctx by index. InTxHashToCctx(context.Context, *QueryGetInTxHashToCctxRequest) (*QueryGetInTxHashToCctxResponse, error) // Queries a InTxHashToCctx data by index. @@ -3633,6 +3850,12 @@ func (*UnimplementedQueryServer) OutTxTrackerAll(ctx context.Context, req *Query func (*UnimplementedQueryServer) OutTxTrackerAllByChain(ctx context.Context, req *QueryAllOutTxTrackerByChainRequest) (*QueryAllOutTxTrackerByChainResponse, error) { return nil, status.Errorf(codes.Unimplemented, "method OutTxTrackerAllByChain not implemented") } +func (*UnimplementedQueryServer) InTxTrackerAllByChain(ctx context.Context, req *QueryAllInTxTrackerByChainRequest) (*QueryAllInTxTrackerByChainResponse, error) { + return nil, status.Errorf(codes.Unimplemented, "method InTxTrackerAllByChain not implemented") +} +func (*UnimplementedQueryServer) InTxTrackerAll(ctx context.Context, req *QueryAllInTxTrackersRequest) (*QueryAllInTxTrackersResponse, error) { + return nil, status.Errorf(codes.Unimplemented, "method InTxTrackerAll not implemented") +} func (*UnimplementedQueryServer) InTxHashToCctx(ctx context.Context, req *QueryGetInTxHashToCctxRequest) (*QueryGetInTxHashToCctxResponse, error) { return nil, status.Errorf(codes.Unimplemented, "method InTxHashToCctx not implemented") } @@ -3773,6 +3996,42 @@ func _Query_OutTxTrackerAllByChain_Handler(srv interface{}, ctx context.Context, return interceptor(ctx, in, info, handler) } +func _Query_InTxTrackerAllByChain_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(QueryAllInTxTrackerByChainRequest) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(QueryServer).InTxTrackerAllByChain(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: "/zetachain.zetacore.crosschain.Query/InTxTrackerAllByChain", + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(QueryServer).InTxTrackerAllByChain(ctx, req.(*QueryAllInTxTrackerByChainRequest)) + } + return interceptor(ctx, in, info, handler) +} + +func _Query_InTxTrackerAll_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(QueryAllInTxTrackersRequest) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(QueryServer).InTxTrackerAll(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: "/zetachain.zetacore.crosschain.Query/InTxTrackerAll", + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(QueryServer).InTxTrackerAll(ctx, req.(*QueryAllInTxTrackersRequest)) + } + return interceptor(ctx, in, info, handler) +} + func _Query_InTxHashToCctx_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { in := new(QueryGetInTxHashToCctxRequest) if err := dec(in); err != nil { @@ -4171,6 +4430,14 @@ var _Query_serviceDesc = grpc.ServiceDesc{ MethodName: "OutTxTrackerAllByChain", Handler: _Query_OutTxTrackerAllByChain_Handler, }, + { + MethodName: "InTxTrackerAllByChain", + Handler: _Query_InTxTrackerAllByChain_Handler, + }, + { + MethodName: "InTxTrackerAll", + Handler: _Query_InTxTrackerAll_Handler, + }, { MethodName: "InTxHashToCctx", Handler: _Query_InTxHashToCctx_Handler, @@ -4615,7 +4882,7 @@ func (m *QueryAllOutTxTrackerByChainResponse) MarshalToSizedBuffer(dAtA []byte) return len(dAtA) - i, nil } -func (m *QueryGetInTxHashToCctxRequest) Marshal() (dAtA []byte, err error) { +func (m *QueryAllInTxTrackerByChainRequest) Marshal() (dAtA []byte, err error) { size := m.Size() dAtA = make([]byte, size) n, err := m.MarshalToSizedBuffer(dAtA[:size]) @@ -4625,18 +4892,167 @@ func (m *QueryGetInTxHashToCctxRequest) Marshal() (dAtA []byte, err error) { return dAtA[:n], nil } -func (m *QueryGetInTxHashToCctxRequest) MarshalTo(dAtA []byte) (int, error) { +func (m *QueryAllInTxTrackerByChainRequest) MarshalTo(dAtA []byte) (int, error) { size := m.Size() return m.MarshalToSizedBuffer(dAtA[:size]) } -func (m *QueryGetInTxHashToCctxRequest) MarshalToSizedBuffer(dAtA []byte) (int, error) { +func (m *QueryAllInTxTrackerByChainRequest) MarshalToSizedBuffer(dAtA []byte) (int, error) { i := len(dAtA) _ = i var l int _ = l - if len(m.InTxHash) > 0 { - i -= len(m.InTxHash) + if m.Pagination != nil { + { + size, err := m.Pagination.MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarintQuery(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0x12 + } + if m.ChainId != 0 { + i = encodeVarintQuery(dAtA, i, uint64(m.ChainId)) + i-- + dAtA[i] = 0x8 + } + return len(dAtA) - i, nil +} + +func (m *QueryAllInTxTrackerByChainResponse) Marshal() (dAtA []byte, err error) { + size := m.Size() + dAtA = make([]byte, size) + n, err := m.MarshalToSizedBuffer(dAtA[:size]) + if err != nil { + return nil, err + } + return dAtA[:n], nil +} + +func (m *QueryAllInTxTrackerByChainResponse) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *QueryAllInTxTrackerByChainResponse) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + if m.Pagination != nil { + { + size, err := m.Pagination.MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarintQuery(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0x12 + } + if len(m.InTxTracker) > 0 { + for iNdEx := len(m.InTxTracker) - 1; iNdEx >= 0; iNdEx-- { + { + size, err := m.InTxTracker[iNdEx].MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarintQuery(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0xa + } + } + return len(dAtA) - i, nil +} + +func (m *QueryAllInTxTrackersRequest) Marshal() (dAtA []byte, err error) { + size := m.Size() + dAtA = make([]byte, size) + n, err := m.MarshalToSizedBuffer(dAtA[:size]) + if err != nil { + return nil, err + } + return dAtA[:n], nil +} + +func (m *QueryAllInTxTrackersRequest) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *QueryAllInTxTrackersRequest) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + return len(dAtA) - i, nil +} + +func (m *QueryAllInTxTrackersResponse) Marshal() (dAtA []byte, err error) { + size := m.Size() + dAtA = make([]byte, size) + n, err := m.MarshalToSizedBuffer(dAtA[:size]) + if err != nil { + return nil, err + } + return dAtA[:n], nil +} + +func (m *QueryAllInTxTrackersResponse) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *QueryAllInTxTrackersResponse) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + if len(m.InTxTracker) > 0 { + for iNdEx := len(m.InTxTracker) - 1; iNdEx >= 0; iNdEx-- { + { + size, err := m.InTxTracker[iNdEx].MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarintQuery(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0xa + } + } + return len(dAtA) - i, nil +} + +func (m *QueryGetInTxHashToCctxRequest) Marshal() (dAtA []byte, err error) { + size := m.Size() + dAtA = make([]byte, size) + n, err := m.MarshalToSizedBuffer(dAtA[:size]) + if err != nil { + return nil, err + } + return dAtA[:n], nil +} + +func (m *QueryGetInTxHashToCctxRequest) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *QueryGetInTxHashToCctxRequest) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + if len(m.InTxHash) > 0 { + i -= len(m.InTxHash) copy(dAtA[i:], m.InTxHash) i = encodeVarintQuery(dAtA, i, uint64(len(m.InTxHash))) i-- @@ -6743,6 +7159,65 @@ func (m *QueryAllOutTxTrackerByChainResponse) Size() (n int) { return n } +func (m *QueryAllInTxTrackerByChainRequest) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + if m.ChainId != 0 { + n += 1 + sovQuery(uint64(m.ChainId)) + } + if m.Pagination != nil { + l = m.Pagination.Size() + n += 1 + l + sovQuery(uint64(l)) + } + return n +} + +func (m *QueryAllInTxTrackerByChainResponse) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + if len(m.InTxTracker) > 0 { + for _, e := range m.InTxTracker { + l = e.Size() + n += 1 + l + sovQuery(uint64(l)) + } + } + if m.Pagination != nil { + l = m.Pagination.Size() + n += 1 + l + sovQuery(uint64(l)) + } + return n +} + +func (m *QueryAllInTxTrackersRequest) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + return n +} + +func (m *QueryAllInTxTrackersResponse) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + if len(m.InTxTracker) > 0 { + for _, e := range m.InTxTracker { + l = e.Size() + n += 1 + l + sovQuery(uint64(l)) + } + } + return n +} + func (m *QueryGetInTxHashToCctxRequest) Size() (n int) { if m == nil { return 0 @@ -8478,6 +8953,365 @@ func (m *QueryAllOutTxTrackerByChainResponse) Unmarshal(dAtA []byte) error { } return nil } +func (m *QueryAllInTxTrackerByChainRequest) Unmarshal(dAtA []byte) error { + l := len(dAtA) + iNdEx := 0 + for iNdEx < l { + preIndex := iNdEx + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowQuery + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + fieldNum := int32(wire >> 3) + wireType := int(wire & 0x7) + if wireType == 4 { + return fmt.Errorf("proto: QueryAllInTxTrackerByChainRequest: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: QueryAllInTxTrackerByChainRequest: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field ChainId", wireType) + } + m.ChainId = 0 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowQuery + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + m.ChainId |= int64(b&0x7F) << shift + if b < 0x80 { + break + } + } + case 2: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Pagination", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowQuery + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return ErrInvalidLengthQuery + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return ErrInvalidLengthQuery + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + if m.Pagination == nil { + m.Pagination = &query.PageRequest{} + } + if err := m.Pagination.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + default: + iNdEx = preIndex + skippy, err := skipQuery(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return ErrInvalidLengthQuery + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func (m *QueryAllInTxTrackerByChainResponse) Unmarshal(dAtA []byte) error { + l := len(dAtA) + iNdEx := 0 + for iNdEx < l { + preIndex := iNdEx + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowQuery + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + fieldNum := int32(wire >> 3) + wireType := int(wire & 0x7) + if wireType == 4 { + return fmt.Errorf("proto: QueryAllInTxTrackerByChainResponse: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: QueryAllInTxTrackerByChainResponse: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field InTxTracker", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowQuery + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return ErrInvalidLengthQuery + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return ErrInvalidLengthQuery + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.InTxTracker = append(m.InTxTracker, InTxTracker{}) + if err := m.InTxTracker[len(m.InTxTracker)-1].Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + case 2: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Pagination", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowQuery + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return ErrInvalidLengthQuery + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return ErrInvalidLengthQuery + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + if m.Pagination == nil { + m.Pagination = &query.PageResponse{} + } + if err := m.Pagination.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + default: + iNdEx = preIndex + skippy, err := skipQuery(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return ErrInvalidLengthQuery + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func (m *QueryAllInTxTrackersRequest) Unmarshal(dAtA []byte) error { + l := len(dAtA) + iNdEx := 0 + for iNdEx < l { + preIndex := iNdEx + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowQuery + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + fieldNum := int32(wire >> 3) + wireType := int(wire & 0x7) + if wireType == 4 { + return fmt.Errorf("proto: QueryAllInTxTrackersRequest: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: QueryAllInTxTrackersRequest: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + default: + iNdEx = preIndex + skippy, err := skipQuery(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return ErrInvalidLengthQuery + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func (m *QueryAllInTxTrackersResponse) Unmarshal(dAtA []byte) error { + l := len(dAtA) + iNdEx := 0 + for iNdEx < l { + preIndex := iNdEx + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowQuery + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + fieldNum := int32(wire >> 3) + wireType := int(wire & 0x7) + if wireType == 4 { + return fmt.Errorf("proto: QueryAllInTxTrackersResponse: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: QueryAllInTxTrackersResponse: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field InTxTracker", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowQuery + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return ErrInvalidLengthQuery + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return ErrInvalidLengthQuery + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.InTxTracker = append(m.InTxTracker, InTxTracker{}) + if err := m.InTxTracker[len(m.InTxTracker)-1].Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + default: + iNdEx = preIndex + skippy, err := skipQuery(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return ErrInvalidLengthQuery + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} func (m *QueryGetInTxHashToCctxRequest) Unmarshal(dAtA []byte) error { l := len(dAtA) iNdEx := 0 diff --git a/x/crosschain/types/query.pb.gw.go b/x/crosschain/types/query.pb.gw.go index 7832f5170c..ee6cee4368 100644 --- a/x/crosschain/types/query.pb.gw.go +++ b/x/crosschain/types/query.pb.gw.go @@ -235,6 +235,96 @@ func local_request_Query_OutTxTrackerAllByChain_0(ctx context.Context, marshaler } +var ( + filter_Query_InTxTrackerAllByChain_0 = &utilities.DoubleArray{Encoding: map[string]int{"chain_id": 0}, Base: []int{1, 1, 0}, Check: []int{0, 1, 2}} +) + +func request_Query_InTxTrackerAllByChain_0(ctx context.Context, marshaler runtime.Marshaler, client QueryClient, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) { + var protoReq QueryAllInTxTrackerByChainRequest + var metadata runtime.ServerMetadata + + var ( + val string + ok bool + err error + _ = err + ) + + val, ok = pathParams["chain_id"] + if !ok { + return nil, metadata, status.Errorf(codes.InvalidArgument, "missing parameter %s", "chain_id") + } + + protoReq.ChainId, err = runtime.Int64(val) + + if err != nil { + return nil, metadata, status.Errorf(codes.InvalidArgument, "type mismatch, parameter: %s, error: %v", "chain_id", err) + } + + if err := req.ParseForm(); err != nil { + return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err) + } + if err := runtime.PopulateQueryParameters(&protoReq, req.Form, filter_Query_InTxTrackerAllByChain_0); err != nil { + return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err) + } + + msg, err := client.InTxTrackerAllByChain(ctx, &protoReq, grpc.Header(&metadata.HeaderMD), grpc.Trailer(&metadata.TrailerMD)) + return msg, metadata, err + +} + +func local_request_Query_InTxTrackerAllByChain_0(ctx context.Context, marshaler runtime.Marshaler, server QueryServer, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) { + var protoReq QueryAllInTxTrackerByChainRequest + var metadata runtime.ServerMetadata + + var ( + val string + ok bool + err error + _ = err + ) + + val, ok = pathParams["chain_id"] + if !ok { + return nil, metadata, status.Errorf(codes.InvalidArgument, "missing parameter %s", "chain_id") + } + + protoReq.ChainId, err = runtime.Int64(val) + + if err != nil { + return nil, metadata, status.Errorf(codes.InvalidArgument, "type mismatch, parameter: %s, error: %v", "chain_id", err) + } + + if err := req.ParseForm(); err != nil { + return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err) + } + if err := runtime.PopulateQueryParameters(&protoReq, req.Form, filter_Query_InTxTrackerAllByChain_0); err != nil { + return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err) + } + + msg, err := server.InTxTrackerAllByChain(ctx, &protoReq) + return msg, metadata, err + +} + +func request_Query_InTxTrackerAll_0(ctx context.Context, marshaler runtime.Marshaler, client QueryClient, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) { + var protoReq QueryAllInTxTrackersRequest + var metadata runtime.ServerMetadata + + msg, err := client.InTxTrackerAll(ctx, &protoReq, grpc.Header(&metadata.HeaderMD), grpc.Trailer(&metadata.TrailerMD)) + return msg, metadata, err + +} + +func local_request_Query_InTxTrackerAll_0(ctx context.Context, marshaler runtime.Marshaler, server QueryServer, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) { + var protoReq QueryAllInTxTrackersRequest + var metadata runtime.ServerMetadata + + msg, err := server.InTxTrackerAll(ctx, &protoReq) + return msg, metadata, err + +} + func request_Query_InTxHashToCctx_0(ctx context.Context, marshaler runtime.Marshaler, client QueryClient, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) { var protoReq QueryGetInTxHashToCctxRequest var metadata runtime.ServerMetadata @@ -1165,6 +1255,52 @@ func RegisterQueryHandlerServer(ctx context.Context, mux *runtime.ServeMux, serv }) + mux.Handle("GET", pattern_Query_InTxTrackerAllByChain_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) { + ctx, cancel := context.WithCancel(req.Context()) + defer cancel() + var stream runtime.ServerTransportStream + ctx = grpc.NewContextWithServerTransportStream(ctx, &stream) + inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req) + rctx, err := runtime.AnnotateIncomingContext(ctx, mux, req) + if err != nil { + runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) + return + } + resp, md, err := local_request_Query_InTxTrackerAllByChain_0(rctx, inboundMarshaler, server, req, pathParams) + md.HeaderMD, md.TrailerMD = metadata.Join(md.HeaderMD, stream.Header()), metadata.Join(md.TrailerMD, stream.Trailer()) + ctx = runtime.NewServerMetadataContext(ctx, md) + if err != nil { + runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) + return + } + + forward_Query_InTxTrackerAllByChain_0(ctx, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...) + + }) + + mux.Handle("GET", pattern_Query_InTxTrackerAll_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) { + ctx, cancel := context.WithCancel(req.Context()) + defer cancel() + var stream runtime.ServerTransportStream + ctx = grpc.NewContextWithServerTransportStream(ctx, &stream) + inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req) + rctx, err := runtime.AnnotateIncomingContext(ctx, mux, req) + if err != nil { + runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) + return + } + resp, md, err := local_request_Query_InTxTrackerAll_0(rctx, inboundMarshaler, server, req, pathParams) + md.HeaderMD, md.TrailerMD = metadata.Join(md.HeaderMD, stream.Header()), metadata.Join(md.TrailerMD, stream.Trailer()) + ctx = runtime.NewServerMetadataContext(ctx, md) + if err != nil { + runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) + return + } + + forward_Query_InTxTrackerAll_0(ctx, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...) + + }) + mux.Handle("GET", pattern_Query_InTxHashToCctx_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) { ctx, cancel := context.WithCancel(req.Context()) defer cancel() @@ -1769,6 +1905,46 @@ func RegisterQueryHandlerClient(ctx context.Context, mux *runtime.ServeMux, clie }) + mux.Handle("GET", pattern_Query_InTxTrackerAllByChain_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) { + ctx, cancel := context.WithCancel(req.Context()) + defer cancel() + inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req) + rctx, err := runtime.AnnotateContext(ctx, mux, req) + if err != nil { + runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) + return + } + resp, md, err := request_Query_InTxTrackerAllByChain_0(rctx, inboundMarshaler, client, req, pathParams) + ctx = runtime.NewServerMetadataContext(ctx, md) + if err != nil { + runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) + return + } + + forward_Query_InTxTrackerAllByChain_0(ctx, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...) + + }) + + mux.Handle("GET", pattern_Query_InTxTrackerAll_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) { + ctx, cancel := context.WithCancel(req.Context()) + defer cancel() + inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req) + rctx, err := runtime.AnnotateContext(ctx, mux, req) + if err != nil { + runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) + return + } + resp, md, err := request_Query_InTxTrackerAll_0(rctx, inboundMarshaler, client, req, pathParams) + ctx = runtime.NewServerMetadataContext(ctx, md) + if err != nil { + runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) + return + } + + forward_Query_InTxTrackerAll_0(ctx, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...) + + }) + mux.Handle("GET", pattern_Query_InTxHashToCctx_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) { ctx, cancel := context.WithCancel(req.Context()) defer cancel() @@ -2201,6 +2377,10 @@ var ( pattern_Query_OutTxTrackerAllByChain_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2, 1, 0, 4, 1, 5, 3}, []string{"zeta-chain", "crosschain", "outTxTrackerByChain", "chain"}, "", runtime.AssumeColonVerbOpt(false))) + pattern_Query_InTxTrackerAllByChain_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2, 1, 0, 4, 1, 5, 3}, []string{"zeta-chain", "crosschain", "inTxTrackerByChain", "chain_id"}, "", runtime.AssumeColonVerbOpt(false))) + + pattern_Query_InTxTrackerAll_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2}, []string{"zeta-chain", "crosschain", "inTxTrackers"}, "", runtime.AssumeColonVerbOpt(false))) + pattern_Query_InTxHashToCctx_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2, 1, 0, 4, 1, 5, 3}, []string{"zeta-chain", "crosschain", "inTxHashToCctx", "inTxHash"}, "", runtime.AssumeColonVerbOpt(false))) pattern_Query_InTxHashToCctxData_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2, 1, 0, 4, 1, 5, 3}, []string{"zeta-chain", "crosschain", "in_tx_hash_to_cctx_data", "inTxHash"}, "", runtime.AssumeColonVerbOpt(false))) @@ -2253,6 +2433,10 @@ var ( forward_Query_OutTxTrackerAllByChain_0 = runtime.ForwardResponseMessage + forward_Query_InTxTrackerAllByChain_0 = runtime.ForwardResponseMessage + + forward_Query_InTxTrackerAll_0 = runtime.ForwardResponseMessage + forward_Query_InTxHashToCctx_0 = runtime.ForwardResponseMessage forward_Query_InTxHashToCctxData_0 = runtime.ForwardResponseMessage diff --git a/x/crosschain/types/tx.pb.go b/x/crosschain/types/tx.pb.go index 6b173e9478..279eeffffd 100644 --- a/x/crosschain/types/tx.pb.go +++ b/x/crosschain/types/tx.pb.go @@ -120,6 +120,134 @@ func (m *MsgMigrateTssFundsResponse) XXX_DiscardUnknown() { var xxx_messageInfo_MsgMigrateTssFundsResponse proto.InternalMessageInfo +type MsgAddToInTxTracker struct { + Creator string `protobuf:"bytes,1,opt,name=creator,proto3" json:"creator,omitempty"` + ChainId int64 `protobuf:"varint,2,opt,name=chain_id,json=chainId,proto3" json:"chain_id,omitempty"` + TxHash string `protobuf:"bytes,3,opt,name=tx_hash,json=txHash,proto3" json:"tx_hash,omitempty"` + CoinType common.CoinType `protobuf:"varint,4,opt,name=coin_type,json=coinType,proto3,enum=common.CoinType" json:"coin_type,omitempty"` + Proof *common.Proof `protobuf:"bytes,5,opt,name=proof,proto3" json:"proof,omitempty"` + BlockHash string `protobuf:"bytes,6,opt,name=block_hash,json=blockHash,proto3" json:"block_hash,omitempty"` + TxIndex int64 `protobuf:"varint,7,opt,name=tx_index,json=txIndex,proto3" json:"tx_index,omitempty"` +} + +func (m *MsgAddToInTxTracker) Reset() { *m = MsgAddToInTxTracker{} } +func (m *MsgAddToInTxTracker) String() string { return proto.CompactTextString(m) } +func (*MsgAddToInTxTracker) ProtoMessage() {} +func (*MsgAddToInTxTracker) Descriptor() ([]byte, []int) { + return fileDescriptor_81d6d611190b7635, []int{2} +} +func (m *MsgAddToInTxTracker) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *MsgAddToInTxTracker) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_MsgAddToInTxTracker.Marshal(b, m, deterministic) + } else { + b = b[:cap(b)] + n, err := m.MarshalToSizedBuffer(b) + if err != nil { + return nil, err + } + return b[:n], nil + } +} +func (m *MsgAddToInTxTracker) XXX_Merge(src proto.Message) { + xxx_messageInfo_MsgAddToInTxTracker.Merge(m, src) +} +func (m *MsgAddToInTxTracker) XXX_Size() int { + return m.Size() +} +func (m *MsgAddToInTxTracker) XXX_DiscardUnknown() { + xxx_messageInfo_MsgAddToInTxTracker.DiscardUnknown(m) +} + +var xxx_messageInfo_MsgAddToInTxTracker proto.InternalMessageInfo + +func (m *MsgAddToInTxTracker) GetCreator() string { + if m != nil { + return m.Creator + } + return "" +} + +func (m *MsgAddToInTxTracker) GetChainId() int64 { + if m != nil { + return m.ChainId + } + return 0 +} + +func (m *MsgAddToInTxTracker) GetTxHash() string { + if m != nil { + return m.TxHash + } + return "" +} + +func (m *MsgAddToInTxTracker) GetCoinType() common.CoinType { + if m != nil { + return m.CoinType + } + return common.CoinType_Zeta +} + +func (m *MsgAddToInTxTracker) GetProof() *common.Proof { + if m != nil { + return m.Proof + } + return nil +} + +func (m *MsgAddToInTxTracker) GetBlockHash() string { + if m != nil { + return m.BlockHash + } + return "" +} + +func (m *MsgAddToInTxTracker) GetTxIndex() int64 { + if m != nil { + return m.TxIndex + } + return 0 +} + +type MsgAddToInTxTrackerResponse struct { +} + +func (m *MsgAddToInTxTrackerResponse) Reset() { *m = MsgAddToInTxTrackerResponse{} } +func (m *MsgAddToInTxTrackerResponse) String() string { return proto.CompactTextString(m) } +func (*MsgAddToInTxTrackerResponse) ProtoMessage() {} +func (*MsgAddToInTxTrackerResponse) Descriptor() ([]byte, []int) { + return fileDescriptor_81d6d611190b7635, []int{3} +} +func (m *MsgAddToInTxTrackerResponse) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *MsgAddToInTxTrackerResponse) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_MsgAddToInTxTrackerResponse.Marshal(b, m, deterministic) + } else { + b = b[:cap(b)] + n, err := m.MarshalToSizedBuffer(b) + if err != nil { + return nil, err + } + return b[:n], nil + } +} +func (m *MsgAddToInTxTrackerResponse) XXX_Merge(src proto.Message) { + xxx_messageInfo_MsgAddToInTxTrackerResponse.Merge(m, src) +} +func (m *MsgAddToInTxTrackerResponse) XXX_Size() int { + return m.Size() +} +func (m *MsgAddToInTxTrackerResponse) XXX_DiscardUnknown() { + xxx_messageInfo_MsgAddToInTxTrackerResponse.DiscardUnknown(m) +} + +var xxx_messageInfo_MsgAddToInTxTrackerResponse proto.InternalMessageInfo + type MsgUpdateTssAddress struct { Creator string `protobuf:"bytes,1,opt,name=creator,proto3" json:"creator,omitempty"` TssPubkey string `protobuf:"bytes,2,opt,name=tss_pubkey,json=tssPubkey,proto3" json:"tss_pubkey,omitempty"` @@ -129,7 +257,7 @@ func (m *MsgUpdateTssAddress) Reset() { *m = MsgUpdateTssAddress{} } func (m *MsgUpdateTssAddress) String() string { return proto.CompactTextString(m) } func (*MsgUpdateTssAddress) ProtoMessage() {} func (*MsgUpdateTssAddress) Descriptor() ([]byte, []int) { - return fileDescriptor_81d6d611190b7635, []int{2} + return fileDescriptor_81d6d611190b7635, []int{4} } func (m *MsgUpdateTssAddress) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -179,7 +307,7 @@ func (m *MsgUpdateTssAddressResponse) Reset() { *m = MsgUpdateTssAddress func (m *MsgUpdateTssAddressResponse) String() string { return proto.CompactTextString(m) } func (*MsgUpdateTssAddressResponse) ProtoMessage() {} func (*MsgUpdateTssAddressResponse) Descriptor() ([]byte, []int) { - return fileDescriptor_81d6d611190b7635, []int{3} + return fileDescriptor_81d6d611190b7635, []int{5} } func (m *MsgUpdateTssAddressResponse) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -222,7 +350,7 @@ func (m *MsgWhitelistERC20) Reset() { *m = MsgWhitelistERC20{} } func (m *MsgWhitelistERC20) String() string { return proto.CompactTextString(m) } func (*MsgWhitelistERC20) ProtoMessage() {} func (*MsgWhitelistERC20) Descriptor() ([]byte, []int) { - return fileDescriptor_81d6d611190b7635, []int{4} + return fileDescriptor_81d6d611190b7635, []int{6} } func (m *MsgWhitelistERC20) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -309,7 +437,7 @@ func (m *MsgWhitelistERC20Response) Reset() { *m = MsgWhitelistERC20Resp func (m *MsgWhitelistERC20Response) String() string { return proto.CompactTextString(m) } func (*MsgWhitelistERC20Response) ProtoMessage() {} func (*MsgWhitelistERC20Response) Descriptor() ([]byte, []int) { - return fileDescriptor_81d6d611190b7635, []int{5} + return fileDescriptor_81d6d611190b7635, []int{7} } func (m *MsgWhitelistERC20Response) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -366,7 +494,7 @@ func (m *MsgAddToOutTxTracker) Reset() { *m = MsgAddToOutTxTracker{} } func (m *MsgAddToOutTxTracker) String() string { return proto.CompactTextString(m) } func (*MsgAddToOutTxTracker) ProtoMessage() {} func (*MsgAddToOutTxTracker) Descriptor() ([]byte, []int) { - return fileDescriptor_81d6d611190b7635, []int{6} + return fileDescriptor_81d6d611190b7635, []int{8} } func (m *MsgAddToOutTxTracker) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -451,7 +579,7 @@ func (m *MsgAddToOutTxTrackerResponse) Reset() { *m = MsgAddToOutTxTrack func (m *MsgAddToOutTxTrackerResponse) String() string { return proto.CompactTextString(m) } func (*MsgAddToOutTxTrackerResponse) ProtoMessage() {} func (*MsgAddToOutTxTrackerResponse) Descriptor() ([]byte, []int) { - return fileDescriptor_81d6d611190b7635, []int{7} + return fileDescriptor_81d6d611190b7635, []int{9} } func (m *MsgAddToOutTxTrackerResponse) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -490,7 +618,7 @@ func (m *MsgRemoveFromOutTxTracker) Reset() { *m = MsgRemoveFromOutTxTra func (m *MsgRemoveFromOutTxTracker) String() string { return proto.CompactTextString(m) } func (*MsgRemoveFromOutTxTracker) ProtoMessage() {} func (*MsgRemoveFromOutTxTracker) Descriptor() ([]byte, []int) { - return fileDescriptor_81d6d611190b7635, []int{8} + return fileDescriptor_81d6d611190b7635, []int{10} } func (m *MsgRemoveFromOutTxTracker) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -547,7 +675,7 @@ func (m *MsgRemoveFromOutTxTrackerResponse) Reset() { *m = MsgRemoveFrom func (m *MsgRemoveFromOutTxTrackerResponse) String() string { return proto.CompactTextString(m) } func (*MsgRemoveFromOutTxTrackerResponse) ProtoMessage() {} func (*MsgRemoveFromOutTxTrackerResponse) Descriptor() ([]byte, []int) { - return fileDescriptor_81d6d611190b7635, []int{9} + return fileDescriptor_81d6d611190b7635, []int{11} } func (m *MsgRemoveFromOutTxTrackerResponse) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -587,7 +715,7 @@ func (m *MsgCreateTSSVoter) Reset() { *m = MsgCreateTSSVoter{} } func (m *MsgCreateTSSVoter) String() string { return proto.CompactTextString(m) } func (*MsgCreateTSSVoter) ProtoMessage() {} func (*MsgCreateTSSVoter) Descriptor() ([]byte, []int) { - return fileDescriptor_81d6d611190b7635, []int{10} + return fileDescriptor_81d6d611190b7635, []int{12} } func (m *MsgCreateTSSVoter) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -651,7 +779,7 @@ func (m *MsgCreateTSSVoterResponse) Reset() { *m = MsgCreateTSSVoterResp func (m *MsgCreateTSSVoterResponse) String() string { return proto.CompactTextString(m) } func (*MsgCreateTSSVoterResponse) ProtoMessage() {} func (*MsgCreateTSSVoterResponse) Descriptor() ([]byte, []int) { - return fileDescriptor_81d6d611190b7635, []int{11} + return fileDescriptor_81d6d611190b7635, []int{13} } func (m *MsgCreateTSSVoterResponse) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -692,7 +820,7 @@ func (m *MsgGasPriceVoter) Reset() { *m = MsgGasPriceVoter{} } func (m *MsgGasPriceVoter) String() string { return proto.CompactTextString(m) } func (*MsgGasPriceVoter) ProtoMessage() {} func (*MsgGasPriceVoter) Descriptor() ([]byte, []int) { - return fileDescriptor_81d6d611190b7635, []int{12} + return fileDescriptor_81d6d611190b7635, []int{14} } func (m *MsgGasPriceVoter) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -763,7 +891,7 @@ func (m *MsgGasPriceVoterResponse) Reset() { *m = MsgGasPriceVoterRespon func (m *MsgGasPriceVoterResponse) String() string { return proto.CompactTextString(m) } func (*MsgGasPriceVoterResponse) ProtoMessage() {} func (*MsgGasPriceVoterResponse) Descriptor() ([]byte, []int) { - return fileDescriptor_81d6d611190b7635, []int{13} + return fileDescriptor_81d6d611190b7635, []int{15} } func (m *MsgGasPriceVoterResponse) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -802,7 +930,7 @@ func (m *MsgNonceVoter) Reset() { *m = MsgNonceVoter{} } func (m *MsgNonceVoter) String() string { return proto.CompactTextString(m) } func (*MsgNonceVoter) ProtoMessage() {} func (*MsgNonceVoter) Descriptor() ([]byte, []int) { - return fileDescriptor_81d6d611190b7635, []int{14} + return fileDescriptor_81d6d611190b7635, []int{16} } func (m *MsgNonceVoter) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -859,7 +987,7 @@ func (m *MsgNonceVoterResponse) Reset() { *m = MsgNonceVoterResponse{} } func (m *MsgNonceVoterResponse) String() string { return proto.CompactTextString(m) } func (*MsgNonceVoterResponse) ProtoMessage() {} func (*MsgNonceVoterResponse) Descriptor() ([]byte, []int) { - return fileDescriptor_81d6d611190b7635, []int{15} + return fileDescriptor_81d6d611190b7635, []int{17} } func (m *MsgNonceVoterResponse) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -907,7 +1035,7 @@ func (m *MsgVoteOnObservedOutboundTx) Reset() { *m = MsgVoteOnObservedOu func (m *MsgVoteOnObservedOutboundTx) String() string { return proto.CompactTextString(m) } func (*MsgVoteOnObservedOutboundTx) ProtoMessage() {} func (*MsgVoteOnObservedOutboundTx) Descriptor() ([]byte, []int) { - return fileDescriptor_81d6d611190b7635, []int{16} + return fileDescriptor_81d6d611190b7635, []int{18} } func (m *MsgVoteOnObservedOutboundTx) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -1013,7 +1141,7 @@ func (m *MsgVoteOnObservedOutboundTxResponse) Reset() { *m = MsgVoteOnOb func (m *MsgVoteOnObservedOutboundTxResponse) String() string { return proto.CompactTextString(m) } func (*MsgVoteOnObservedOutboundTxResponse) ProtoMessage() {} func (*MsgVoteOnObservedOutboundTxResponse) Descriptor() ([]byte, []int) { - return fileDescriptor_81d6d611190b7635, []int{17} + return fileDescriptor_81d6d611190b7635, []int{19} } func (m *MsgVoteOnObservedOutboundTxResponse) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -1064,7 +1192,7 @@ func (m *MsgVoteOnObservedInboundTx) Reset() { *m = MsgVoteOnObservedInb func (m *MsgVoteOnObservedInboundTx) String() string { return proto.CompactTextString(m) } func (*MsgVoteOnObservedInboundTx) ProtoMessage() {} func (*MsgVoteOnObservedInboundTx) Descriptor() ([]byte, []int) { - return fileDescriptor_81d6d611190b7635, []int{18} + return fileDescriptor_81d6d611190b7635, []int{20} } func (m *MsgVoteOnObservedInboundTx) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -1184,7 +1312,7 @@ func (m *MsgVoteOnObservedInboundTxResponse) Reset() { *m = MsgVoteOnObs func (m *MsgVoteOnObservedInboundTxResponse) String() string { return proto.CompactTextString(m) } func (*MsgVoteOnObservedInboundTxResponse) ProtoMessage() {} func (*MsgVoteOnObservedInboundTxResponse) Descriptor() ([]byte, []int) { - return fileDescriptor_81d6d611190b7635, []int{19} + return fileDescriptor_81d6d611190b7635, []int{21} } func (m *MsgVoteOnObservedInboundTxResponse) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -1223,7 +1351,7 @@ func (m *MsgSetNodeKeys) Reset() { *m = MsgSetNodeKeys{} } func (m *MsgSetNodeKeys) String() string { return proto.CompactTextString(m) } func (*MsgSetNodeKeys) ProtoMessage() {} func (*MsgSetNodeKeys) Descriptor() ([]byte, []int) { - return fileDescriptor_81d6d611190b7635, []int{20} + return fileDescriptor_81d6d611190b7635, []int{22} } func (m *MsgSetNodeKeys) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -1280,7 +1408,7 @@ func (m *MsgSetNodeKeysResponse) Reset() { *m = MsgSetNodeKeysResponse{} func (m *MsgSetNodeKeysResponse) String() string { return proto.CompactTextString(m) } func (*MsgSetNodeKeysResponse) ProtoMessage() {} func (*MsgSetNodeKeysResponse) Descriptor() ([]byte, []int) { - return fileDescriptor_81d6d611190b7635, []int{21} + return fileDescriptor_81d6d611190b7635, []int{23} } func (m *MsgSetNodeKeysResponse) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -1312,6 +1440,8 @@ var xxx_messageInfo_MsgSetNodeKeysResponse proto.InternalMessageInfo func init() { proto.RegisterType((*MsgMigrateTssFunds)(nil), "zetachain.zetacore.crosschain.MsgMigrateTssFunds") proto.RegisterType((*MsgMigrateTssFundsResponse)(nil), "zetachain.zetacore.crosschain.MsgMigrateTssFundsResponse") + proto.RegisterType((*MsgAddToInTxTracker)(nil), "zetachain.zetacore.crosschain.MsgAddToInTxTracker") + proto.RegisterType((*MsgAddToInTxTrackerResponse)(nil), "zetachain.zetacore.crosschain.MsgAddToInTxTrackerResponse") proto.RegisterType((*MsgUpdateTssAddress)(nil), "zetachain.zetacore.crosschain.MsgUpdateTssAddress") proto.RegisterType((*MsgUpdateTssAddressResponse)(nil), "zetachain.zetacore.crosschain.MsgUpdateTssAddressResponse") proto.RegisterType((*MsgWhitelistERC20)(nil), "zetachain.zetacore.crosschain.MsgWhitelistERC20") @@ -1337,97 +1467,100 @@ func init() { func init() { proto.RegisterFile("crosschain/tx.proto", fileDescriptor_81d6d611190b7635) } var fileDescriptor_81d6d611190b7635 = []byte{ - // 1440 bytes of a gzipped FileDescriptorProto - 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xb4, 0x58, 0x4f, 0x6f, 0xdb, 0xc6, - 0x12, 0x37, 0x9f, 0x6d, 0x59, 0x1a, 0x5b, 0x8e, 0xbd, 0x76, 0x62, 0x86, 0x8e, 0xe5, 0x84, 0x7e, - 0xc9, 0x0b, 0x1e, 0x62, 0x29, 0x51, 0xde, 0x43, 0x93, 0xb4, 0x87, 0xc6, 0x46, 0xe2, 0xb8, 0xa9, - 0xec, 0x80, 0x56, 0x5a, 0x20, 0x17, 0x82, 0x22, 0xd7, 0x14, 0x61, 0x91, 0x2b, 0x70, 0x57, 0x86, - 0x64, 0x14, 0x28, 0x50, 0xa0, 0x87, 0xde, 0x8a, 0xa2, 0x40, 0x8b, 0x7e, 0x81, 0x7e, 0x95, 0xa0, - 0xa7, 0xa0, 0xa7, 0xa6, 0x87, 0xa0, 0x4d, 0xbe, 0x41, 0x3f, 0x41, 0xb1, 0xbb, 0x24, 0x2d, 0xca, - 0x96, 0x64, 0x39, 0xe8, 0x49, 0x3b, 0xb3, 0xf3, 0x9b, 0x7f, 0x3b, 0xb3, 0x3b, 0x22, 0x2c, 0xd8, - 0x21, 0xa1, 0xd4, 0xae, 0x5b, 0x5e, 0x50, 0x62, 0xed, 0x62, 0x33, 0x24, 0x8c, 0xa0, 0x95, 0x23, - 0xcc, 0x2c, 0xc1, 0x2b, 0x8a, 0x15, 0x09, 0x71, 0xf1, 0x58, 0x4e, 0x5b, 0xb0, 0x89, 0xef, 0x93, - 0xa0, 0x24, 0x7f, 0x24, 0x46, 0x5b, 0x74, 0x89, 0x4b, 0xc4, 0xb2, 0xc4, 0x57, 0x92, 0xab, 0x7f, - 0xa7, 0x00, 0xaa, 0x50, 0xb7, 0xe2, 0xb9, 0xa1, 0xc5, 0x70, 0x95, 0xd2, 0xc7, 0xad, 0xc0, 0xa1, - 0x48, 0x85, 0x29, 0x3b, 0xc4, 0x16, 0x23, 0xa1, 0xaa, 0x5c, 0x55, 0x6e, 0xe6, 0x8c, 0x98, 0x44, - 0x97, 0x21, 0x2b, 0x8c, 0x98, 0x9e, 0xa3, 0xfe, 0xeb, 0xaa, 0x72, 0x73, 0xdc, 0x98, 0x12, 0xf4, - 0xb6, 0x83, 0xb6, 0x20, 0x63, 0xf9, 0xa4, 0x15, 0x30, 0x75, 0x9c, 0x63, 0x36, 0x4a, 0x2f, 0xdf, - 0xac, 0x8e, 0xfd, 0xfe, 0x66, 0xf5, 0x3f, 0xae, 0xc7, 0xea, 0xad, 0x5a, 0xd1, 0x26, 0x7e, 0xc9, - 0x26, 0xd4, 0x27, 0x34, 0xfa, 0x59, 0xa7, 0xce, 0x41, 0x89, 0x75, 0x9a, 0x98, 0x16, 0x9f, 0x7b, - 0x01, 0x33, 0x22, 0xb8, 0x7e, 0x05, 0xb4, 0x93, 0x3e, 0x19, 0x98, 0x36, 0x49, 0x40, 0xb1, 0xbe, - 0x03, 0x0b, 0x15, 0xea, 0x3e, 0x6f, 0x3a, 0x72, 0xf3, 0xa1, 0xe3, 0x84, 0x98, 0x0e, 0x72, 0x79, - 0x05, 0x80, 0x51, 0x6a, 0x36, 0x5b, 0xb5, 0x03, 0xdc, 0x11, 0x4e, 0xe7, 0x8c, 0x1c, 0xa3, 0xf4, - 0x99, 0x60, 0xe8, 0x2b, 0xb0, 0x7c, 0x8a, 0xbe, 0xc4, 0xdc, 0xaf, 0x0a, 0xcc, 0x57, 0xa8, 0xfb, - 0x79, 0xdd, 0x63, 0xb8, 0xe1, 0x51, 0xf6, 0xc8, 0xd8, 0x2c, 0xdf, 0x1e, 0x60, 0x6d, 0x0d, 0xf2, - 0x38, 0xb4, 0xcb, 0xb7, 0x4d, 0x4b, 0x2a, 0x8a, 0x0c, 0xce, 0x08, 0x66, 0xec, 0x6c, 0x77, 0x16, - 0xc7, 0xd3, 0x59, 0x44, 0x30, 0x11, 0x58, 0x3e, 0x56, 0x27, 0x04, 0x4c, 0xac, 0xd1, 0x25, 0xc8, - 0xd0, 0x8e, 0x5f, 0x23, 0x0d, 0x75, 0x52, 0x70, 0x23, 0x0a, 0x69, 0x90, 0x75, 0xb0, 0xed, 0xf9, - 0x56, 0x83, 0xaa, 0x99, 0xab, 0xca, 0xcd, 0xbc, 0x91, 0xd0, 0x68, 0x19, 0x72, 0xae, 0x45, 0xcd, - 0x86, 0xe7, 0x7b, 0x4c, 0x9d, 0x12, 0x36, 0xb2, 0xae, 0x45, 0x3f, 0xe5, 0xb4, 0x6e, 0xc2, 0xe5, - 0x13, 0x31, 0xc5, 0x11, 0xf3, 0x08, 0x8e, 0x52, 0x11, 0xc8, 0x08, 0x67, 0x8e, 0xba, 0x23, 0x58, - 0x01, 0xb0, 0x6d, 0xd6, 0x36, 0xbd, 0xc0, 0xc1, 0xed, 0x38, 0xa9, 0x9c, 0xb3, 0xcd, 0x19, 0xfa, - 0x6b, 0x05, 0x16, 0x2b, 0xd4, 0x7d, 0xe8, 0x38, 0x55, 0xb2, 0xdb, 0x62, 0xd5, 0x76, 0x35, 0xb4, - 0xec, 0x03, 0x1c, 0x9e, 0xaf, 0xb2, 0x16, 0x61, 0x32, 0x20, 0x81, 0x8d, 0x45, 0xae, 0x26, 0x0c, - 0x49, 0xa0, 0x25, 0x98, 0x62, 0x6d, 0xb3, 0x6e, 0xd1, 0x7a, 0x94, 0xac, 0x0c, 0x6b, 0x3f, 0xb1, - 0x68, 0x1d, 0xad, 0xc1, 0x64, 0x33, 0x24, 0x64, 0x5f, 0x64, 0x6b, 0xba, 0x9c, 0x2f, 0x46, 0x8d, - 0xf0, 0x8c, 0x33, 0x0d, 0xb9, 0xc7, 0x03, 0xa8, 0x35, 0x88, 0x7d, 0x20, 0x15, 0x64, 0x64, 0x00, - 0x82, 0x23, 0x74, 0x5c, 0x86, 0x6c, 0x12, 0x9d, 0xcc, 0xde, 0x54, 0x1c, 0x5b, 0x01, 0xae, 0x9c, - 0x16, 0x5a, 0x52, 0x31, 0xfb, 0x22, 0xb9, 0x06, 0xf6, 0xc9, 0x21, 0x7e, 0x1c, 0x12, 0xff, 0x1f, - 0x8a, 0x5f, 0x5f, 0x83, 0x6b, 0x7d, 0xed, 0x24, 0xce, 0xfc, 0x2c, 0xcb, 0x77, 0x93, 0x1b, 0xc1, - 0xd5, 0xbd, 0xbd, 0xcf, 0x08, 0x1b, 0xe8, 0xc5, 0xe0, 0x66, 0x41, 0xff, 0x85, 0xb9, 0x03, 0xdc, - 0xd9, 0xc2, 0xc1, 0x0b, 0xcc, 0xac, 0x27, 0xd8, 0x73, 0xeb, 0x2c, 0x2a, 0xe0, 0x13, 0x7c, 0xb4, - 0x0e, 0x19, 0xca, 0x2c, 0xd6, 0xa2, 0xe2, 0x78, 0x66, 0xcb, 0x17, 0xe3, 0x73, 0x30, 0xb0, 0x8d, - 0xbd, 0x43, 0xbc, 0x27, 0x36, 0x8d, 0x48, 0x48, 0x5f, 0x16, 0x69, 0x4b, 0x3b, 0x9a, 0x84, 0xf1, - 0xa3, 0x02, 0x73, 0x15, 0xea, 0x6e, 0x59, 0xf4, 0x59, 0xe8, 0xd9, 0x78, 0x58, 0x14, 0x83, 0x73, - 0xd9, 0xe4, 0x2a, 0xe2, 0x5c, 0x0a, 0x02, 0x5d, 0x83, 0x19, 0x59, 0x0d, 0x41, 0xcb, 0xaf, 0xe1, - 0x50, 0x78, 0x3c, 0x61, 0x4c, 0x0b, 0xde, 0x8e, 0x60, 0x89, 0x26, 0x6c, 0x35, 0x9b, 0x8d, 0x4e, - 0xd2, 0x84, 0x82, 0xd2, 0x35, 0x50, 0x7b, 0x3d, 0x4b, 0xdc, 0x7e, 0x01, 0xf9, 0x0a, 0x75, 0x77, - 0xf8, 0x71, 0xbd, 0x9f, 0xcb, 0xa7, 0x1c, 0xff, 0x12, 0x5c, 0x4c, 0xe9, 0x4e, 0x8c, 0xbe, 0x9e, - 0x14, 0x37, 0x1a, 0x67, 0xee, 0x06, 0xbb, 0x35, 0x8a, 0xc3, 0x43, 0xec, 0xec, 0xb6, 0x58, 0x8d, - 0xb4, 0x02, 0xa7, 0xda, 0x1e, 0xe0, 0xc3, 0x32, 0x88, 0x16, 0x96, 0x2d, 0x21, 0xcf, 0x3e, 0xcb, - 0x19, 0xa2, 0x23, 0x8a, 0xb0, 0x40, 0x22, 0x65, 0x26, 0xe1, 0xa5, 0x26, 0xc5, 0xc4, 0x5d, 0x6f, - 0xcc, 0x93, 0x63, 0x3b, 0x55, 0x29, 0xff, 0x11, 0x68, 0x3d, 0xf2, 0xb2, 0xbb, 0x64, 0xd1, 0xc8, - 0x04, 0xab, 0x29, 0xd8, 0xc6, 0xf1, 0x3e, 0xfa, 0x3f, 0x2c, 0xf5, 0xa0, 0xf9, 0x6d, 0xd6, 0xa2, - 0xd8, 0x51, 0x41, 0x40, 0x17, 0x53, 0xd0, 0x2d, 0x8b, 0x3e, 0xa7, 0xd8, 0x41, 0x47, 0xa0, 0xf7, - 0xc0, 0xf0, 0xfe, 0x3e, 0xb6, 0x99, 0x77, 0x88, 0x85, 0x02, 0x79, 0xf4, 0xd3, 0xe2, 0x7d, 0x2a, - 0x46, 0xef, 0xd3, 0x8d, 0x33, 0xbc, 0x4f, 0xdb, 0x01, 0x33, 0x0a, 0x29, 0x8b, 0x8f, 0x62, 0xbd, - 0xf1, 0xc9, 0xa3, 0x4f, 0x86, 0xd8, 0x96, 0x57, 0xf1, 0x8c, 0xf0, 0xbe, 0xbf, 0x2e, 0x71, 0x41, - 0x23, 0x02, 0xb3, 0x87, 0x56, 0xa3, 0x85, 0xcd, 0x50, 0xf6, 0x8a, 0x23, 0x8b, 0x6e, 0xe3, 0xc9, - 0x88, 0x6f, 0xea, 0x5f, 0x6f, 0x56, 0x2f, 0x76, 0x2c, 0xbf, 0xf1, 0x40, 0x4f, 0xab, 0xd3, 0x8d, - 0xbc, 0x60, 0x44, 0xad, 0xe8, 0x74, 0x35, 0x6b, 0xe6, 0x0c, 0xcd, 0x8a, 0x56, 0x61, 0x5a, 0x86, - 0x28, 0x6a, 0x34, 0xba, 0x21, 0x41, 0xb0, 0x36, 0x39, 0x07, 0xdd, 0x80, 0x0b, 0x52, 0x80, 0xdf, - 0x26, 0xb2, 0x7a, 0xb3, 0x22, 0xf2, 0xbc, 0x60, 0x57, 0x29, 0x15, 0x95, 0x8b, 0xd6, 0x21, 0x67, - 0x13, 0x2f, 0x30, 0xb9, 0xcb, 0x6a, 0x4e, 0x98, 0x9e, 0x8b, 0x4d, 0x6f, 0x12, 0x2f, 0xa8, 0x76, - 0x9a, 0xd8, 0xc8, 0xda, 0xd1, 0x4a, 0xbf, 0x0e, 0x6b, 0x03, 0x4a, 0x3b, 0x69, 0x81, 0x3f, 0xc7, - 0xc5, 0x08, 0x91, 0x96, 0xdb, 0x0e, 0x86, 0x77, 0x00, 0x6f, 0x72, 0x1c, 0x38, 0x38, 0x8c, 0xca, - 0x3f, 0xa2, 0x78, 0x38, 0x72, 0x65, 0xf6, 0xbc, 0xdb, 0x79, 0xc9, 0xde, 0x8c, 0x5a, 0x55, 0x83, - 0x6c, 0x94, 0xe2, 0x30, 0x7a, 0x94, 0x12, 0x1a, 0x5d, 0x87, 0xd9, 0x78, 0x1d, 0xa5, 0x6d, 0x52, - 0xaa, 0x88, 0xb9, 0x32, 0x73, 0xc7, 0x63, 0x54, 0xe6, 0xbd, 0xc6, 0x28, 0x1e, 0xa5, 0x8f, 0x29, - 0xb5, 0x5c, 0x99, 0xfa, 0x9c, 0x11, 0x93, 0xe8, 0x0a, 0x00, 0x4f, 0x79, 0xd4, 0xc1, 0x39, 0xe9, - 0xa7, 0x17, 0x44, 0x8d, 0x7b, 0x03, 0x2e, 0x78, 0x81, 0x19, 0x3d, 0x8e, 0xb2, 0x5b, 0x65, 0xcb, - 0xe5, 0xbd, 0xa0, 0xbb, 0x45, 0x53, 0x13, 0xc6, 0xb4, 0x90, 0x48, 0x26, 0x8c, 0xf4, 0xb9, 0xce, - 0x0c, 0x3b, 0x57, 0xae, 0x8b, 0xb5, 0x4d, 0x12, 0x7a, 0xae, 0x17, 0xa8, 0x79, 0xe9, 0x10, 0x6b, - 0xef, 0x0a, 0x9a, 0xdf, 0x7f, 0x16, 0xa5, 0x98, 0xa9, 0xb3, 0x62, 0x43, 0x12, 0xfa, 0xbf, 0x41, - 0xef, 0x7f, 0xc4, 0x49, 0x25, 0x7c, 0xa3, 0xc0, 0x6c, 0x85, 0xba, 0x7b, 0x98, 0xed, 0x10, 0x07, - 0x3f, 0xc5, 0x9d, 0x41, 0x93, 0x62, 0x09, 0x72, 0xf2, 0xe1, 0xdb, 0xc3, 0x4c, 0x14, 0xc0, 0x74, - 0x79, 0x3e, 0x19, 0x1e, 0x5a, 0xb5, 0xa7, 0x62, 0xc3, 0x38, 0x96, 0x41, 0xb7, 0x00, 0xf1, 0xfa, - 0xa6, 0x9e, 0x1b, 0xe0, 0xd0, 0x8c, 0x66, 0xa3, 0xe8, 0x4a, 0x9c, 0x63, 0x94, 0xee, 0x89, 0x8d, - 0x88, 0xaf, 0xab, 0x70, 0x29, 0xed, 0x4a, 0xec, 0x65, 0xf9, 0x17, 0x80, 0xf1, 0x0a, 0x75, 0xd1, - 0xd7, 0x0a, 0xcc, 0x9f, 0x9c, 0x99, 0xee, 0x16, 0x07, 0xce, 0xfb, 0xc5, 0xd3, 0xa6, 0x11, 0xed, - 0xc3, 0x73, 0x80, 0x92, 0x11, 0xf0, 0x7b, 0x05, 0x2e, 0xf5, 0x19, 0x60, 0xee, 0x0d, 0xd7, 0x7b, - 0x3a, 0x52, 0xfb, 0xf8, 0xbc, 0xc8, 0xc4, 0xad, 0x2f, 0x60, 0xb6, 0x67, 0x90, 0xb9, 0x3d, 0x5c, - 0x67, 0x1a, 0xa1, 0xdd, 0x1b, 0x15, 0x91, 0x58, 0xef, 0x40, 0x3e, 0x3d, 0x7f, 0x94, 0x86, 0xab, - 0x4a, 0x01, 0xb4, 0x0f, 0x46, 0x04, 0x24, 0xa6, 0x9b, 0x00, 0x5d, 0x43, 0xc4, 0xad, 0xe1, 0x6a, - 0x8e, 0xa5, 0xb5, 0xff, 0x8d, 0x22, 0x9d, 0x58, 0xfc, 0x49, 0x01, 0xb5, 0xef, 0x04, 0xf1, 0x60, - 0xb8, 0xca, 0x7e, 0x58, 0x6d, 0xe3, 0xfc, 0xd8, 0xc4, 0xb9, 0x1f, 0x14, 0x58, 0xea, 0x77, 0xb7, - 0xdf, 0x1f, 0x55, 0x7f, 0x02, 0xd5, 0x1e, 0x9e, 0x1b, 0xda, 0x5d, 0xa1, 0x3d, 0xff, 0x14, 0xcf, - 0x50, 0xa1, 0x69, 0xc4, 0x59, 0x2a, 0xb4, 0xcf, 0x3f, 0xb7, 0xaf, 0x14, 0x98, 0x3b, 0xf1, 0xc7, - 0xb8, 0x3c, 0x5c, 0x5d, 0x2f, 0x46, 0x7b, 0x30, 0x3a, 0x26, 0x71, 0xe2, 0x4b, 0xb8, 0xd0, 0xfb, - 0x39, 0xe1, 0xce, 0x70, 0x75, 0x3d, 0x10, 0xed, 0xfe, 0xc8, 0x90, 0xd8, 0x81, 0x8d, 0xa7, 0x2f, - 0xdf, 0x16, 0x94, 0x57, 0x6f, 0x0b, 0xca, 0x1f, 0x6f, 0x0b, 0xca, 0xb7, 0xef, 0x0a, 0x63, 0xaf, - 0xde, 0x15, 0xc6, 0x7e, 0x7b, 0x57, 0x18, 0x7b, 0x71, 0xa7, 0xeb, 0x09, 0xe5, 0x4a, 0xd7, 0xe5, - 0x77, 0x95, 0x58, 0x7f, 0xa9, 0x5d, 0xea, 0xfe, 0xda, 0xc2, 0x5f, 0xd4, 0x5a, 0x46, 0x7c, 0x27, - 0xb9, 0xfb, 0x77, 0x00, 0x00, 0x00, 0xff, 0xff, 0x59, 0x22, 0xcb, 0x23, 0x88, 0x11, 0x00, 0x00, + // 1487 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xb4, 0x58, 0xdd, 0x4e, 0x1b, 0xc7, + 0x17, 0x67, 0xff, 0x80, 0xb1, 0x8f, 0x31, 0x81, 0x85, 0x84, 0xcd, 0x12, 0x0c, 0x59, 0xfe, 0x49, + 0x51, 0x15, 0xec, 0xc4, 0x69, 0xd5, 0x24, 0xed, 0x45, 0x03, 0x4a, 0x08, 0x4d, 0x0d, 0xd1, 0xe2, + 0xb4, 0x52, 0x6e, 0x56, 0xeb, 0xdd, 0x61, 0xbd, 0xc2, 0xbb, 0x63, 0xed, 0x8c, 0x91, 0x8d, 0x2a, + 0x55, 0xaa, 0xd4, 0x8b, 0xde, 0x55, 0x55, 0xa5, 0x56, 0x7d, 0x81, 0xbe, 0x4a, 0xee, 0x1a, 0xf5, + 0xaa, 0xe9, 0x45, 0xd4, 0x26, 0x4f, 0xd0, 0x3e, 0x41, 0xb5, 0x33, 0xb3, 0x8b, 0xd7, 0xe0, 0x2f, + 0xa2, 0x5c, 0x79, 0xce, 0xd9, 0xf9, 0x9d, 0xef, 0x33, 0x73, 0xc6, 0x30, 0x6f, 0x05, 0x98, 0x10, + 0xab, 0x66, 0xba, 0x7e, 0x91, 0xb6, 0x0a, 0x8d, 0x00, 0x53, 0x2c, 0x2f, 0x1f, 0x23, 0x6a, 0x32, + 0x5e, 0x81, 0xad, 0x70, 0x80, 0x0a, 0x27, 0xfb, 0xd4, 0x79, 0x0b, 0x7b, 0x1e, 0xf6, 0x8b, 0xfc, + 0x87, 0x63, 0xd4, 0x05, 0x07, 0x3b, 0x98, 0x2d, 0x8b, 0xe1, 0x8a, 0x73, 0xb5, 0x1f, 0x24, 0x90, + 0xcb, 0xc4, 0x29, 0xbb, 0x4e, 0x60, 0x52, 0x54, 0x21, 0xe4, 0x61, 0xd3, 0xb7, 0x89, 0xac, 0xc0, + 0x94, 0x15, 0x20, 0x93, 0xe2, 0x40, 0x91, 0x56, 0xa5, 0xf5, 0x8c, 0x1e, 0x91, 0xf2, 0x65, 0x48, + 0x33, 0x25, 0x86, 0x6b, 0x2b, 0xff, 0x5b, 0x95, 0xd6, 0xc7, 0xf5, 0x29, 0x46, 0xef, 0xd8, 0xf2, + 0x36, 0xa4, 0x4c, 0x0f, 0x37, 0x7d, 0xaa, 0x8c, 0x87, 0x98, 0xcd, 0xe2, 0xf3, 0x57, 0x2b, 0x63, + 0x7f, 0xbe, 0x5a, 0x79, 0xcf, 0x71, 0x69, 0xad, 0x59, 0x2d, 0x58, 0xd8, 0x2b, 0x5a, 0x98, 0x78, + 0x98, 0x88, 0x9f, 0x0d, 0x62, 0x1f, 0x16, 0x69, 0xbb, 0x81, 0x48, 0xe1, 0xa9, 0xeb, 0x53, 0x5d, + 0xc0, 0xb5, 0x2b, 0xa0, 0x9e, 0xb6, 0x49, 0x47, 0xa4, 0x81, 0x7d, 0x82, 0xb4, 0x7f, 0x24, 0x98, + 0x2f, 0x13, 0xe7, 0xbe, 0x6d, 0x57, 0xf0, 0x8e, 0x5f, 0x69, 0x55, 0x02, 0xd3, 0x3a, 0x44, 0xc1, + 0xf9, 0x6c, 0x5e, 0x84, 0x29, 0xda, 0x32, 0x6a, 0x26, 0xa9, 0x71, 0xa3, 0xf5, 0x14, 0x6d, 0x3d, + 0x32, 0x49, 0x4d, 0xde, 0x80, 0x8c, 0x85, 0x5d, 0xdf, 0x08, 0xcd, 0x53, 0x26, 0x56, 0xa5, 0xf5, + 0x99, 0xd2, 0x6c, 0x41, 0x04, 0x74, 0x0b, 0xbb, 0x7e, 0xa5, 0xdd, 0x40, 0x7a, 0xda, 0x12, 0x2b, + 0x79, 0x0d, 0x26, 0x1b, 0x01, 0xc6, 0x07, 0xca, 0xe4, 0xaa, 0xb4, 0x9e, 0x2d, 0xe5, 0xa2, 0xad, + 0x4f, 0x42, 0xa6, 0xce, 0xbf, 0xc9, 0xcb, 0x00, 0xd5, 0x3a, 0xb6, 0x0e, 0xb9, 0xbe, 0x14, 0xd3, + 0x97, 0x61, 0x1c, 0xa6, 0xf2, 0x32, 0xa4, 0x69, 0xcb, 0x70, 0x7d, 0x1b, 0xb5, 0x94, 0x29, 0x6e, + 0x26, 0x6d, 0xed, 0x84, 0xa4, 0xb6, 0x0c, 0x4b, 0x67, 0xb8, 0x1c, 0x87, 0x64, 0x97, 0x45, 0xe4, + 0x69, 0xc3, 0xe6, 0xf1, 0xba, 0x6f, 0xdb, 0x01, 0x22, 0xfd, 0xb2, 0xb8, 0x0c, 0x40, 0x09, 0x31, + 0x1a, 0xcd, 0xea, 0x21, 0x6a, 0xb3, 0x98, 0x64, 0xf4, 0x0c, 0x25, 0xe4, 0x09, 0x63, 0x08, 0x75, + 0xdd, 0xf2, 0x62, 0x75, 0xbf, 0x4b, 0x30, 0x57, 0x26, 0xce, 0x97, 0x35, 0x97, 0xa2, 0xba, 0x4b, + 0xe8, 0x03, 0x7d, 0xab, 0x74, 0xb3, 0x8f, 0xb6, 0x35, 0xc8, 0xa1, 0xc0, 0x2a, 0xdd, 0x34, 0x4c, + 0x2e, 0x48, 0x28, 0x9c, 0x66, 0xcc, 0xc8, 0xd8, 0xce, 0x24, 0x8d, 0x27, 0x93, 0x24, 0xc3, 0x84, + 0x6f, 0x7a, 0x3c, 0x0d, 0x19, 0x9d, 0xad, 0xe5, 0x4b, 0x90, 0x22, 0x6d, 0xaf, 0x8a, 0xeb, 0x2c, + 0xe2, 0x19, 0x5d, 0x50, 0xb2, 0x0a, 0x69, 0x1b, 0x59, 0xae, 0x67, 0xd6, 0x09, 0x8b, 0x70, 0x4e, + 0x8f, 0x69, 0x79, 0x09, 0x32, 0x8e, 0x49, 0x8c, 0xba, 0xeb, 0xb9, 0x54, 0x44, 0x38, 0xed, 0x98, + 0xe4, 0xf3, 0x90, 0xd6, 0x0c, 0xb8, 0x7c, 0xca, 0xa7, 0xc8, 0xe3, 0xd0, 0x83, 0xe3, 0x84, 0x07, + 0xdc, 0xc3, 0xe9, 0xe3, 0x4e, 0x0f, 0x96, 0x01, 0x2c, 0x2b, 0xce, 0xa0, 0x08, 0x6a, 0xc8, 0xe1, + 0x39, 0x7c, 0x29, 0xc1, 0x42, 0x94, 0xc4, 0xbd, 0x26, 0x7d, 0xcb, 0xc2, 0x5d, 0x80, 0x49, 0x1f, + 0xfb, 0x16, 0x62, 0xb1, 0x9a, 0xd0, 0x39, 0xd1, 0x59, 0xce, 0x13, 0x89, 0x72, 0x7e, 0xc7, 0xf5, + 0x99, 0x87, 0x2b, 0x67, 0xb9, 0x16, 0x57, 0xcc, 0x01, 0x0b, 0xae, 0x8e, 0x3c, 0x7c, 0x84, 0x1e, + 0x06, 0xd8, 0x7b, 0x47, 0xfe, 0x6b, 0x6b, 0x70, 0xb5, 0xa7, 0x9e, 0xd8, 0x98, 0x5f, 0x79, 0xf9, + 0x6e, 0x85, 0x4a, 0x50, 0x65, 0x7f, 0xff, 0x0b, 0x4c, 0xfb, 0x5a, 0xd1, 0xbf, 0x59, 0xe4, 0xf7, + 0x61, 0xf6, 0x10, 0xb5, 0xb7, 0x91, 0xff, 0x0c, 0x51, 0xf3, 0x11, 0x72, 0x9d, 0x1a, 0x15, 0x05, + 0x7c, 0x8a, 0x2f, 0x6f, 0x40, 0x8a, 0x50, 0x93, 0x36, 0x89, 0x38, 0x52, 0x2e, 0x46, 0x79, 0xd0, + 0x91, 0x85, 0xdc, 0x23, 0xb4, 0xcf, 0x3e, 0xea, 0x62, 0x93, 0xb6, 0xc4, 0xc2, 0x96, 0x34, 0x34, + 0x76, 0xe3, 0x67, 0x09, 0x66, 0xcb, 0xc4, 0xd9, 0x36, 0xc9, 0x93, 0xc0, 0xb5, 0xd0, 0x20, 0x2f, + 0xfa, 0xc7, 0xb2, 0x11, 0x8a, 0x88, 0x62, 0xc9, 0x08, 0xf9, 0x2a, 0x4c, 0xf3, 0x6a, 0xf0, 0x9b, + 0x5e, 0x15, 0x05, 0xcc, 0xe2, 0x09, 0x3d, 0xcb, 0x78, 0xbb, 0x8c, 0xc5, 0x9a, 0xb0, 0xd9, 0x68, + 0xd4, 0xdb, 0x71, 0x13, 0x32, 0x4a, 0x53, 0x41, 0xe9, 0xb6, 0x2c, 0x36, 0xfb, 0x19, 0xe4, 0xca, + 0xc4, 0xd9, 0x0d, 0xd3, 0xf5, 0x76, 0x26, 0x9f, 0x91, 0xfe, 0x45, 0xb8, 0x98, 0x90, 0x1d, 0x2b, + 0x7d, 0x39, 0xc9, 0x4e, 0xb4, 0x90, 0xb9, 0xe7, 0xef, 0x55, 0x09, 0x0a, 0x8e, 0x90, 0xbd, 0xd7, + 0xa4, 0x55, 0xdc, 0xf4, 0xed, 0x4a, 0xab, 0x8f, 0x0d, 0x4b, 0xc0, 0x5a, 0x98, 0xb7, 0x04, 0xcf, + 0x7d, 0x3a, 0x64, 0xb0, 0x8e, 0x28, 0xc0, 0x3c, 0x16, 0xc2, 0x0c, 0x1c, 0x96, 0x5a, 0xe7, 0x4d, + 0x32, 0x87, 0x4f, 0xf4, 0x54, 0xf8, 0xfe, 0x4f, 0x40, 0xed, 0xda, 0xcf, 0xbb, 0x8b, 0x17, 0x0d, + 0x0f, 0xb0, 0x92, 0x80, 0x6d, 0x9e, 0x7c, 0x97, 0x3f, 0x84, 0xc5, 0x2e, 0x74, 0x78, 0x9a, 0x35, + 0x09, 0xb2, 0x15, 0x60, 0xd0, 0x85, 0x04, 0x74, 0xdb, 0x24, 0x4f, 0x09, 0xb2, 0xe5, 0x63, 0xd0, + 0xba, 0x60, 0xe8, 0xe0, 0x00, 0x59, 0xd4, 0x3d, 0x42, 0x4c, 0x00, 0x4f, 0x7d, 0x96, 0x5d, 0xd9, + 0x05, 0x71, 0x65, 0x5f, 0x1f, 0xe2, 0xca, 0xde, 0xf1, 0xa9, 0x9e, 0x4f, 0x68, 0x7c, 0x10, 0xc9, + 0x8d, 0x32, 0x2f, 0x7f, 0x36, 0x40, 0x37, 0x3f, 0x8a, 0xa7, 0x99, 0xf5, 0xbd, 0x65, 0xb1, 0x03, + 0x5a, 0xc6, 0x30, 0x73, 0x64, 0xd6, 0x9b, 0xc8, 0x08, 0x78, 0xaf, 0xd8, 0xbc, 0xe8, 0x36, 0x1f, + 0x8d, 0x38, 0x66, 0xfc, 0xfb, 0x6a, 0xe5, 0x62, 0xdb, 0xf4, 0xea, 0xf7, 0xb4, 0xa4, 0x38, 0x4d, + 0xcf, 0x31, 0x86, 0x68, 0x45, 0xbb, 0xa3, 0x59, 0x53, 0x43, 0x34, 0xab, 0xbc, 0x02, 0x59, 0xee, + 0x22, 0xab, 0x51, 0x71, 0x42, 0x02, 0x63, 0x6d, 0x85, 0x1c, 0xf9, 0x3a, 0x5c, 0xe0, 0x1b, 0xc2, + 0xd3, 0x84, 0x57, 0x6f, 0x9a, 0x79, 0x9e, 0x63, 0xec, 0x0a, 0x21, 0xac, 0x72, 0x93, 0xa3, 0x47, + 0x66, 0xd0, 0xe8, 0xa1, 0x5d, 0x83, 0xb5, 0x3e, 0xa5, 0x1d, 0xb7, 0xc0, 0xdf, 0xe3, 0x6c, 0xaa, + 0x4a, 0xee, 0xdb, 0xf1, 0x07, 0x77, 0x40, 0xd8, 0xe4, 0xc8, 0xb7, 0x51, 0x20, 0xca, 0x5f, 0x50, + 0xa1, 0x3b, 0x7c, 0x65, 0x74, 0xdd, 0xdb, 0x39, 0xce, 0xde, 0x12, 0xad, 0xaa, 0x42, 0x5a, 0x84, + 0x38, 0x10, 0x97, 0x52, 0x4c, 0xcb, 0xd7, 0x60, 0x26, 0x5a, 0x8b, 0xb0, 0x4d, 0x72, 0x11, 0x11, + 0x97, 0x47, 0xee, 0x64, 0xb2, 0x4c, 0xbd, 0xd5, 0x64, 0x19, 0x7a, 0xe9, 0x21, 0x42, 0x4c, 0x87, + 0x87, 0x3e, 0xa3, 0x47, 0xa4, 0x7c, 0x05, 0x20, 0x0c, 0xb9, 0xe8, 0xe0, 0x0c, 0xb7, 0xd3, 0xf5, + 0x45, 0xe3, 0x5e, 0x87, 0x0b, 0xae, 0x6f, 0x88, 0xcb, 0x91, 0x77, 0x2b, 0x6f, 0xb9, 0x9c, 0xeb, + 0x77, 0xb6, 0x68, 0x62, 0xc2, 0xc8, 0xb2, 0x1d, 0xf1, 0x84, 0x91, 0xcc, 0xeb, 0xf4, 0xc0, 0x91, + 0x72, 0x09, 0x32, 0xb4, 0x65, 0xe0, 0xc0, 0x75, 0x5c, 0x5f, 0xc9, 0x71, 0x83, 0x68, 0x6b, 0x8f, + 0xd1, 0xe1, 0xf9, 0x67, 0x12, 0x82, 0xa8, 0x32, 0xc3, 0x3e, 0x70, 0x42, 0xfb, 0x3f, 0x68, 0xbd, + 0x53, 0x1c, 0x57, 0xc2, 0x77, 0x12, 0xcc, 0x94, 0x89, 0xb3, 0x8f, 0xe8, 0x2e, 0xb6, 0xd1, 0x63, + 0xd4, 0xee, 0x37, 0x29, 0x16, 0x21, 0xc3, 0x2f, 0xbe, 0x7d, 0x44, 0x59, 0x01, 0x64, 0x4b, 0x73, + 0xf1, 0xf0, 0xd0, 0xac, 0x3e, 0x66, 0x1f, 0xf4, 0x93, 0x3d, 0xf2, 0x0d, 0x90, 0xc3, 0xfa, 0x26, + 0xae, 0xe3, 0xa3, 0xc0, 0x10, 0xb3, 0x91, 0x38, 0x12, 0x67, 0x29, 0x21, 0xfb, 0xec, 0x83, 0xe0, + 0x6b, 0x0a, 0x5c, 0x4a, 0x9a, 0x12, 0x59, 0x59, 0xfa, 0x2d, 0x0b, 0xe3, 0x65, 0xe2, 0xc8, 0xdf, + 0x4a, 0x30, 0x77, 0x7a, 0x66, 0xba, 0x5d, 0xe8, 0xfb, 0x04, 0x2a, 0x9c, 0x35, 0x8d, 0xa8, 0x1f, + 0x9f, 0x03, 0x14, 0x8f, 0x80, 0xdf, 0x48, 0x30, 0x7b, 0xea, 0xcd, 0x51, 0x1a, 0x52, 0x62, 0x07, + 0x46, 0xbd, 0x37, 0x3a, 0x26, 0x36, 0xe2, 0x47, 0x09, 0x2e, 0xf5, 0x98, 0xa2, 0xee, 0x0c, 0x16, + 0x7b, 0x36, 0x52, 0xfd, 0xf4, 0xbc, 0xc8, 0xd8, 0xac, 0xaf, 0x60, 0xa6, 0x6b, 0x9a, 0xba, 0x39, + 0x58, 0x66, 0x12, 0xa1, 0xde, 0x19, 0x15, 0x11, 0x6b, 0x6f, 0x43, 0x2e, 0x39, 0x04, 0x15, 0x07, + 0x8b, 0x4a, 0x00, 0xd4, 0x8f, 0x46, 0x04, 0xc4, 0xaa, 0x1b, 0x00, 0x1d, 0x93, 0xcc, 0x8d, 0xc1, + 0x62, 0x4e, 0x76, 0xab, 0x1f, 0x8c, 0xb2, 0x3b, 0xd6, 0xf8, 0x8b, 0x04, 0x4a, 0xcf, 0x31, 0x66, + 0x88, 0xd2, 0xea, 0x85, 0x55, 0x37, 0xcf, 0x8f, 0x8d, 0x8d, 0xfb, 0x49, 0x82, 0xc5, 0x5e, 0x17, + 0xcc, 0xdd, 0x51, 0xe5, 0xc7, 0x50, 0xf5, 0xfe, 0xb9, 0xa1, 0x9d, 0x15, 0xda, 0xf5, 0x5c, 0x1d, + 0xa2, 0x42, 0x93, 0x88, 0x61, 0x2a, 0xb4, 0xc7, 0xf3, 0x31, 0x3c, 0x3b, 0x4e, 0xbd, 0xce, 0x87, + 0x38, 0x3b, 0xba, 0x31, 0xc3, 0x9c, 0x1d, 0xbd, 0x5e, 0xed, 0xf2, 0xd7, 0x70, 0xa1, 0xfb, 0x6f, + 0x9e, 0x5b, 0x83, 0xc5, 0x75, 0x41, 0xd4, 0xbb, 0x23, 0x43, 0x22, 0x03, 0x36, 0x1f, 0x3f, 0x7f, + 0x9d, 0x97, 0x5e, 0xbc, 0xce, 0x4b, 0x7f, 0xbd, 0xce, 0x4b, 0xdf, 0xbf, 0xc9, 0x8f, 0xbd, 0x78, + 0x93, 0x1f, 0xfb, 0xe3, 0x4d, 0x7e, 0xec, 0xd9, 0xad, 0x8e, 0x7b, 0x3c, 0x14, 0xba, 0xc1, 0xff, + 0xef, 0x8a, 0xe4, 0x17, 0x5b, 0xc5, 0xce, 0x7f, 0xc1, 0xc2, 0x6b, 0xbd, 0x9a, 0x62, 0xff, 0x5f, + 0xdd, 0xfe, 0x2f, 0x00, 0x00, 0xff, 0xff, 0x49, 0x4b, 0x22, 0xc9, 0x20, 0x13, 0x00, 0x00, } // Reference imports to suppress errors if they are not otherwise used. @@ -1443,6 +1576,7 @@ const _ = grpc.SupportPackageIsVersion4 // For semantics around ctx use and closing/ending streaming RPCs, please refer to https://godoc.org/google.golang.org/grpc#ClientConn.NewStream. type MsgClient interface { AddToOutTxTracker(ctx context.Context, in *MsgAddToOutTxTracker, opts ...grpc.CallOption) (*MsgAddToOutTxTrackerResponse, error) + AddToInTxTracker(ctx context.Context, in *MsgAddToInTxTracker, opts ...grpc.CallOption) (*MsgAddToInTxTrackerResponse, error) RemoveFromOutTxTracker(ctx context.Context, in *MsgRemoveFromOutTxTracker, opts ...grpc.CallOption) (*MsgRemoveFromOutTxTrackerResponse, error) CreateTSSVoter(ctx context.Context, in *MsgCreateTSSVoter, opts ...grpc.CallOption) (*MsgCreateTSSVoterResponse, error) GasPriceVoter(ctx context.Context, in *MsgGasPriceVoter, opts ...grpc.CallOption) (*MsgGasPriceVoterResponse, error) @@ -1471,6 +1605,15 @@ func (c *msgClient) AddToOutTxTracker(ctx context.Context, in *MsgAddToOutTxTrac return out, nil } +func (c *msgClient) AddToInTxTracker(ctx context.Context, in *MsgAddToInTxTracker, opts ...grpc.CallOption) (*MsgAddToInTxTrackerResponse, error) { + out := new(MsgAddToInTxTrackerResponse) + err := c.cc.Invoke(ctx, "/zetachain.zetacore.crosschain.Msg/AddToInTxTracker", in, out, opts...) + if err != nil { + return nil, err + } + return out, nil +} + func (c *msgClient) RemoveFromOutTxTracker(ctx context.Context, in *MsgRemoveFromOutTxTracker, opts ...grpc.CallOption) (*MsgRemoveFromOutTxTrackerResponse, error) { out := new(MsgRemoveFromOutTxTrackerResponse) err := c.cc.Invoke(ctx, "/zetachain.zetacore.crosschain.Msg/RemoveFromOutTxTracker", in, out, opts...) @@ -1555,6 +1698,7 @@ func (c *msgClient) MigrateTssFunds(ctx context.Context, in *MsgMigrateTssFunds, // MsgServer is the server API for Msg service. type MsgServer interface { AddToOutTxTracker(context.Context, *MsgAddToOutTxTracker) (*MsgAddToOutTxTrackerResponse, error) + AddToInTxTracker(context.Context, *MsgAddToInTxTracker) (*MsgAddToInTxTrackerResponse, error) RemoveFromOutTxTracker(context.Context, *MsgRemoveFromOutTxTracker) (*MsgRemoveFromOutTxTrackerResponse, error) CreateTSSVoter(context.Context, *MsgCreateTSSVoter) (*MsgCreateTSSVoterResponse, error) GasPriceVoter(context.Context, *MsgGasPriceVoter) (*MsgGasPriceVoterResponse, error) @@ -1573,6 +1717,9 @@ type UnimplementedMsgServer struct { func (*UnimplementedMsgServer) AddToOutTxTracker(ctx context.Context, req *MsgAddToOutTxTracker) (*MsgAddToOutTxTrackerResponse, error) { return nil, status.Errorf(codes.Unimplemented, "method AddToOutTxTracker not implemented") } +func (*UnimplementedMsgServer) AddToInTxTracker(ctx context.Context, req *MsgAddToInTxTracker) (*MsgAddToInTxTrackerResponse, error) { + return nil, status.Errorf(codes.Unimplemented, "method AddToInTxTracker not implemented") +} func (*UnimplementedMsgServer) RemoveFromOutTxTracker(ctx context.Context, req *MsgRemoveFromOutTxTracker) (*MsgRemoveFromOutTxTrackerResponse, error) { return nil, status.Errorf(codes.Unimplemented, "method RemoveFromOutTxTracker not implemented") } @@ -1623,6 +1770,24 @@ func _Msg_AddToOutTxTracker_Handler(srv interface{}, ctx context.Context, dec fu return interceptor(ctx, in, info, handler) } +func _Msg_AddToInTxTracker_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(MsgAddToInTxTracker) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(MsgServer).AddToInTxTracker(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: "/zetachain.zetacore.crosschain.Msg/AddToInTxTracker", + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(MsgServer).AddToInTxTracker(ctx, req.(*MsgAddToInTxTracker)) + } + return interceptor(ctx, in, info, handler) +} + func _Msg_RemoveFromOutTxTracker_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { in := new(MsgRemoveFromOutTxTracker) if err := dec(in); err != nil { @@ -1793,6 +1958,10 @@ var _Msg_serviceDesc = grpc.ServiceDesc{ MethodName: "AddToOutTxTracker", Handler: _Msg_AddToOutTxTracker_Handler, }, + { + MethodName: "AddToInTxTracker", + Handler: _Msg_AddToInTxTracker_Handler, + }, { MethodName: "RemoveFromOutTxTracker", Handler: _Msg_RemoveFromOutTxTracker_Handler, @@ -1902,6 +2071,100 @@ func (m *MsgMigrateTssFundsResponse) MarshalToSizedBuffer(dAtA []byte) (int, err return len(dAtA) - i, nil } +func (m *MsgAddToInTxTracker) Marshal() (dAtA []byte, err error) { + size := m.Size() + dAtA = make([]byte, size) + n, err := m.MarshalToSizedBuffer(dAtA[:size]) + if err != nil { + return nil, err + } + return dAtA[:n], nil +} + +func (m *MsgAddToInTxTracker) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *MsgAddToInTxTracker) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + if m.TxIndex != 0 { + i = encodeVarintTx(dAtA, i, uint64(m.TxIndex)) + i-- + dAtA[i] = 0x38 + } + if len(m.BlockHash) > 0 { + i -= len(m.BlockHash) + copy(dAtA[i:], m.BlockHash) + i = encodeVarintTx(dAtA, i, uint64(len(m.BlockHash))) + i-- + dAtA[i] = 0x32 + } + if m.Proof != nil { + { + size, err := m.Proof.MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarintTx(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0x2a + } + if m.CoinType != 0 { + i = encodeVarintTx(dAtA, i, uint64(m.CoinType)) + i-- + dAtA[i] = 0x20 + } + if len(m.TxHash) > 0 { + i -= len(m.TxHash) + copy(dAtA[i:], m.TxHash) + i = encodeVarintTx(dAtA, i, uint64(len(m.TxHash))) + i-- + dAtA[i] = 0x1a + } + if m.ChainId != 0 { + i = encodeVarintTx(dAtA, i, uint64(m.ChainId)) + i-- + dAtA[i] = 0x10 + } + if len(m.Creator) > 0 { + i -= len(m.Creator) + copy(dAtA[i:], m.Creator) + i = encodeVarintTx(dAtA, i, uint64(len(m.Creator))) + i-- + dAtA[i] = 0xa + } + return len(dAtA) - i, nil +} + +func (m *MsgAddToInTxTrackerResponse) Marshal() (dAtA []byte, err error) { + size := m.Size() + dAtA = make([]byte, size) + n, err := m.MarshalToSizedBuffer(dAtA[:size]) + if err != nil { + return nil, err + } + return dAtA[:n], nil +} + +func (m *MsgAddToInTxTrackerResponse) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *MsgAddToInTxTrackerResponse) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + return len(dAtA) - i, nil +} + func (m *MsgUpdateTssAddress) Marshal() (dAtA []byte, err error) { size := m.Size() dAtA = make([]byte, size) @@ -2792,7 +3055,7 @@ func (m *MsgMigrateTssFundsResponse) Size() (n int) { return n } -func (m *MsgUpdateTssAddress) Size() (n int) { +func (m *MsgAddToInTxTracker) Size() (n int) { if m == nil { return 0 } @@ -2802,14 +3065,31 @@ func (m *MsgUpdateTssAddress) Size() (n int) { if l > 0 { n += 1 + l + sovTx(uint64(l)) } - l = len(m.TssPubkey) + if m.ChainId != 0 { + n += 1 + sovTx(uint64(m.ChainId)) + } + l = len(m.TxHash) + if l > 0 { + n += 1 + l + sovTx(uint64(l)) + } + if m.CoinType != 0 { + n += 1 + sovTx(uint64(m.CoinType)) + } + if m.Proof != nil { + l = m.Proof.Size() + n += 1 + l + sovTx(uint64(l)) + } + l = len(m.BlockHash) if l > 0 { n += 1 + l + sovTx(uint64(l)) } + if m.TxIndex != 0 { + n += 1 + sovTx(uint64(m.TxIndex)) + } return n } -func (m *MsgUpdateTssAddressResponse) Size() (n int) { +func (m *MsgAddToInTxTrackerResponse) Size() (n int) { if m == nil { return 0 } @@ -2818,7 +3098,7 @@ func (m *MsgUpdateTssAddressResponse) Size() (n int) { return n } -func (m *MsgWhitelistERC20) Size() (n int) { +func (m *MsgUpdateTssAddress) Size() (n int) { if m == nil { return 0 } @@ -2828,7 +3108,33 @@ func (m *MsgWhitelistERC20) Size() (n int) { if l > 0 { n += 1 + l + sovTx(uint64(l)) } - l = len(m.Erc20Address) + l = len(m.TssPubkey) + if l > 0 { + n += 1 + l + sovTx(uint64(l)) + } + return n +} + +func (m *MsgUpdateTssAddressResponse) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + return n +} + +func (m *MsgWhitelistERC20) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + l = len(m.Creator) + if l > 0 { + n += 1 + l + sovTx(uint64(l)) + } + l = len(m.Erc20Address) if l > 0 { n += 1 + l + sovTx(uint64(l)) } @@ -3374,6 +3680,295 @@ func (m *MsgMigrateTssFundsResponse) Unmarshal(dAtA []byte) error { } return nil } +func (m *MsgAddToInTxTracker) Unmarshal(dAtA []byte) error { + l := len(dAtA) + iNdEx := 0 + for iNdEx < l { + preIndex := iNdEx + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowTx + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + fieldNum := int32(wire >> 3) + wireType := int(wire & 0x7) + if wireType == 4 { + return fmt.Errorf("proto: MsgAddToInTxTracker: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: MsgAddToInTxTracker: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Creator", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowTx + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + stringLen |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + intStringLen := int(stringLen) + if intStringLen < 0 { + return ErrInvalidLengthTx + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthTx + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.Creator = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + case 2: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field ChainId", wireType) + } + m.ChainId = 0 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowTx + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + m.ChainId |= int64(b&0x7F) << shift + if b < 0x80 { + break + } + } + case 3: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field TxHash", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowTx + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + stringLen |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + intStringLen := int(stringLen) + if intStringLen < 0 { + return ErrInvalidLengthTx + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthTx + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.TxHash = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + case 4: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field CoinType", wireType) + } + m.CoinType = 0 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowTx + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + m.CoinType |= common.CoinType(b&0x7F) << shift + if b < 0x80 { + break + } + } + case 5: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Proof", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowTx + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return ErrInvalidLengthTx + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return ErrInvalidLengthTx + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + if m.Proof == nil { + m.Proof = &common.Proof{} + } + if err := m.Proof.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + case 6: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field BlockHash", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowTx + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + stringLen |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + intStringLen := int(stringLen) + if intStringLen < 0 { + return ErrInvalidLengthTx + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthTx + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.BlockHash = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + case 7: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field TxIndex", wireType) + } + m.TxIndex = 0 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowTx + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + m.TxIndex |= int64(b&0x7F) << shift + if b < 0x80 { + break + } + } + default: + iNdEx = preIndex + skippy, err := skipTx(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return ErrInvalidLengthTx + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func (m *MsgAddToInTxTrackerResponse) Unmarshal(dAtA []byte) error { + l := len(dAtA) + iNdEx := 0 + for iNdEx < l { + preIndex := iNdEx + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowTx + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + fieldNum := int32(wire >> 3) + wireType := int(wire & 0x7) + if wireType == 4 { + return fmt.Errorf("proto: MsgAddToInTxTrackerResponse: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: MsgAddToInTxTrackerResponse: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + default: + iNdEx = preIndex + skippy, err := skipTx(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return ErrInvalidLengthTx + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} func (m *MsgUpdateTssAddress) Unmarshal(dAtA []byte) error { l := len(dAtA) iNdEx := 0 diff --git a/x/emissions/types/events.pb.go b/x/emissions/types/events.pb.go index a1a96178cc..201211e96f 100644 --- a/x/emissions/types/events.pb.go +++ b/x/emissions/types/events.pb.go @@ -51,8 +51,8 @@ func (EmissionType) EnumDescriptor() ([]byte, []int) { } type ObserverEmission struct { - EmissionType EmissionType `protobuf:"varint,1,opt,name=emission_type,json=emissionType,proto3,enum=zetachain.zetacore.emissions.EmissionType" json:"emission_type,omitempty"` - ObserverAddress string `protobuf:"bytes,2,opt,name=observer_address,json=observerAddress,proto3" json:"observer_address,omitempty"` + EmissionType EmissionType `protobuf:"varint,1,opt,name=emission_type,json=emissionType,proto3,enum=zetachain.zetacore.emissions.EmissionType" json:"emission_type,omitempty"` + ObserverAddress string `protobuf:"bytes,2,opt,name=observer_address,json=observerAddress,proto3" json:"observer_address,omitempty"` Amount github_com_cosmos_cosmos_sdk_types.Int `protobuf:"bytes,3,opt,name=amount,proto3,customtype=github.com/cosmos/cosmos-sdk/types.Int" json:"amount"` } diff --git a/x/observer/keeper/keeper.go b/x/observer/keeper/keeper.go index 10c8c9e21f..bb0d40e9c8 100644 --- a/x/observer/keeper/keeper.go +++ b/x/observer/keeper/keeper.go @@ -47,3 +47,11 @@ func NewKeeper( func (k Keeper) Logger(ctx sdk.Context) log.Logger { return ctx.Logger().With("module", fmt.Sprintf("x/%s", types.ModuleName)) } + +func (k Keeper) StoreKey() storetypes.StoreKey { + return k.storeKey +} + +func (k Keeper) Codec() codec.BinaryCodec { + return k.cdc +} diff --git a/x/observer/keeper/migrator.go b/x/observer/keeper/migrator.go index daed1e08f8..190de610cd 100644 --- a/x/observer/keeper/migrator.go +++ b/x/observer/keeper/migrator.go @@ -4,6 +4,7 @@ import ( sdk "github.com/cosmos/cosmos-sdk/types" v2 "github.com/zeta-chain/zetacore/x/observer/migrations/v2" v3 "github.com/zeta-chain/zetacore/x/observer/migrations/v3" + v4 "github.com/zeta-chain/zetacore/x/observer/migrations/v4" ) // Migrator is a struct for handling in-place store migrations. @@ -27,3 +28,7 @@ func (m Migrator) Migrate1to2(ctx sdk.Context) error { func (m Migrator) Migrate2to3(ctx sdk.Context) error { return v3.MigrateStore(ctx, m.observerKeeper) } + +func (m Migrator) Migrate3to4(ctx sdk.Context) error { + return v4.MigrateStore(ctx, m.observerKeeper.storeKey, m.observerKeeper.cdc) +} diff --git a/x/observer/keeper/msg_server_update_crosschain_flags.go b/x/observer/keeper/msg_server_update_crosschain_flags.go index 57d4478163..8d9a9fc98e 100644 --- a/x/observer/keeper/msg_server_update_crosschain_flags.go +++ b/x/observer/keeper/msg_server_update_crosschain_flags.go @@ -36,14 +36,19 @@ func (k msgServer) UpdateCrosschainFlags(goCtx context.Context, msg *types.MsgUp flags.GasPriceIncreaseFlags = msg.GasPriceIncreaseFlags } + if msg.BlockHeaderVerificationFlags != nil { + flags.BlockHeaderVerificationFlags = msg.BlockHeaderVerificationFlags + } + k.SetCrosschainFlags(ctx, flags) err := ctx.EventManager().EmitTypedEvents(&types.EventCrosschainFlagsUpdated{ - MsgTypeUrl: sdk.MsgTypeURL(&types.MsgUpdateCrosschainFlags{}), - IsInboundEnabled: msg.IsInboundEnabled, - IsOutboundEnabled: msg.IsOutboundEnabled, - GasPriceIncreaseFlags: msg.GasPriceIncreaseFlags, - Signer: msg.Creator, + MsgTypeUrl: sdk.MsgTypeURL(&types.MsgUpdateCrosschainFlags{}), + IsInboundEnabled: msg.IsInboundEnabled, + IsOutboundEnabled: msg.IsOutboundEnabled, + GasPriceIncreaseFlags: msg.GasPriceIncreaseFlags, + BlockHeaderVerificationFlags: msg.BlockHeaderVerificationFlags, + Signer: msg.Creator, }) if err != nil { ctx.Logger().Error("Error emitting EventCrosschainFlagsUpdated :", err) diff --git a/x/observer/keeper/msg_server_update_crosschain_flags_test.go b/x/observer/keeper/msg_server_update_crosschain_flags_test.go index 73c8a4d9de..6481b44ee0 100644 --- a/x/observer/keeper/msg_server_update_crosschain_flags_test.go +++ b/x/observer/keeper/msg_server_update_crosschain_flags_test.go @@ -41,6 +41,10 @@ func TestMsgServer_UpdateCrosschainFlags(t *testing.T) { RetryInterval: time.Minute * 42, GasPriceIncreasePercent: 42, }, + BlockHeaderVerificationFlags: &types.BlockHeaderVerificationFlags{ + IsEthTypeChainEnabled: true, + IsBtcTypeChainEnabled: false, + }, }) require.NoError(t, err) @@ -51,7 +55,8 @@ func TestMsgServer_UpdateCrosschainFlags(t *testing.T) { require.Equal(t, int64(42), flags.GasPriceIncreaseFlags.EpochLength) require.Equal(t, time.Minute*42, flags.GasPriceIncreaseFlags.RetryInterval) require.Equal(t, uint32(42), flags.GasPriceIncreaseFlags.GasPriceIncreasePercent) - + require.True(t, flags.BlockHeaderVerificationFlags.IsEthTypeChainEnabled) + require.False(t, flags.BlockHeaderVerificationFlags.IsBtcTypeChainEnabled) setAdminCrossChainFlags(ctx, k, admin, types.Policy_Type_group2) // can update flags again @@ -64,6 +69,10 @@ func TestMsgServer_UpdateCrosschainFlags(t *testing.T) { RetryInterval: time.Minute * 43, GasPriceIncreasePercent: 43, }, + BlockHeaderVerificationFlags: &types.BlockHeaderVerificationFlags{ + IsEthTypeChainEnabled: false, + IsBtcTypeChainEnabled: false, + }, }) require.NoError(t, err) @@ -74,7 +83,8 @@ func TestMsgServer_UpdateCrosschainFlags(t *testing.T) { require.Equal(t, int64(43), flags.GasPriceIncreaseFlags.EpochLength) require.Equal(t, time.Minute*43, flags.GasPriceIncreaseFlags.RetryInterval) require.Equal(t, uint32(43), flags.GasPriceIncreaseFlags.GasPriceIncreasePercent) - + require.False(t, flags.BlockHeaderVerificationFlags.IsEthTypeChainEnabled) + require.False(t, flags.BlockHeaderVerificationFlags.IsBtcTypeChainEnabled) // group 1 should be able to disable inbound and outbound setAdminCrossChainFlags(ctx, k, admin, types.Policy_Type_group1) diff --git a/x/observer/migrations/v4/migrate.go b/x/observer/migrations/v4/migrate.go new file mode 100644 index 0000000000..dbf1e5c7df --- /dev/null +++ b/x/observer/migrations/v4/migrate.go @@ -0,0 +1,30 @@ +package v4 + +import ( + "github.com/cosmos/cosmos-sdk/codec" + "github.com/cosmos/cosmos-sdk/store/prefix" + storetypes "github.com/cosmos/cosmos-sdk/store/types" + sdk "github.com/cosmos/cosmos-sdk/types" + "github.com/zeta-chain/zetacore/x/observer/types" +) + +func MigrateStore(ctx sdk.Context, observerStoreKey storetypes.StoreKey, cdc codec.BinaryCodec) error { + newCrossChainFlags := types.DefaultCrosschainFlags() + var val types.LegacyCrosschainFlags + store := prefix.NewStore(ctx.KVStore(observerStoreKey), types.KeyPrefix(types.CrosschainFlagsKey)) + b := store.Get([]byte{0}) + if b != nil { + cdc.MustUnmarshal(b, &val) + if val.GasPriceIncreaseFlags != nil { + newCrossChainFlags.GasPriceIncreaseFlags = val.GasPriceIncreaseFlags + } + newCrossChainFlags.IsOutboundEnabled = val.IsOutboundEnabled + newCrossChainFlags.IsInboundEnabled = val.IsInboundEnabled + } + b, err := cdc.Marshal(newCrossChainFlags) + if err != nil { + return err + } + store.Set([]byte{0}, b) + return nil +} diff --git a/x/observer/migrations/v4/migrate_test.go b/x/observer/migrations/v4/migrate_test.go new file mode 100644 index 0000000000..98f4439403 --- /dev/null +++ b/x/observer/migrations/v4/migrate_test.go @@ -0,0 +1,30 @@ +package v4_test + +import ( + "testing" + + "github.com/cosmos/cosmos-sdk/store/prefix" + "github.com/stretchr/testify/assert" + keepertest "github.com/zeta-chain/zetacore/testutil/keeper" + v4 "github.com/zeta-chain/zetacore/x/observer/migrations/v4" + "github.com/zeta-chain/zetacore/x/observer/types" +) + +func TestMigrateStore(t *testing.T) { + + k, ctx := keepertest.ObserverKeeper(t) + store := prefix.NewStore(ctx.KVStore(k.StoreKey()), types.KeyPrefix(types.CrosschainFlagsKey)) + legacyFlags := types.LegacyCrosschainFlags{ + IsInboundEnabled: false, + IsOutboundEnabled: false, + GasPriceIncreaseFlags: &types.DefaultGasPriceIncreaseFlags, + } + val := k.Codec().MustMarshal(&legacyFlags) + store.Set([]byte{0}, val) + err := v4.MigrateStore(ctx, k.StoreKey(), k.Codec()) + assert.NoError(t, err) + flags, found := k.GetCrosschainFlags(ctx) + assert.True(t, found) + assert.False(t, flags.BlockHeaderVerificationFlags.IsBtcTypeChainEnabled) + assert.False(t, flags.BlockHeaderVerificationFlags.IsEthTypeChainEnabled) +} diff --git a/x/observer/module.go b/x/observer/module.go index 1f991b978c..0e63ab0e08 100644 --- a/x/observer/module.go +++ b/x/observer/module.go @@ -150,6 +150,9 @@ func (am AppModule) RegisterServices(cfg module.Configurator) { if err := cfg.RegisterMigration(types.ModuleName, 2, m.Migrate2to3); err != nil { panic(err) } + if err := cfg.RegisterMigration(types.ModuleName, 3, m.Migrate3to4); err != nil { + panic(err) + } } // RegisterInvariants registers the observer module's invariants. diff --git a/x/observer/types/crosschain_flags.go b/x/observer/types/crosschain_flags.go index f85fce5130..696bc94ff6 100644 --- a/x/observer/types/crosschain_flags.go +++ b/x/observer/types/crosschain_flags.go @@ -20,5 +20,9 @@ func DefaultCrosschainFlags() *CrosschainFlags { IsInboundEnabled: true, IsOutboundEnabled: true, GasPriceIncreaseFlags: &DefaultGasPriceIncreaseFlags, + BlockHeaderVerificationFlags: &BlockHeaderVerificationFlags{ + IsEthTypeChainEnabled: false, + IsBtcTypeChainEnabled: false, + }, } } diff --git a/x/observer/types/crosschain_flags.pb.go b/x/observer/types/crosschain_flags.pb.go index 8bb7de6ad7..d50542a509 100644 --- a/x/observer/types/crosschain_flags.pb.go +++ b/x/observer/types/crosschain_flags.pb.go @@ -88,17 +88,70 @@ func (m *GasPriceIncreaseFlags) GetGasPriceIncreasePercent() uint32 { return 0 } +type BlockHeaderVerificationFlags struct { + IsEthTypeChainEnabled bool `protobuf:"varint,1,opt,name=isEthTypeChainEnabled,proto3" json:"isEthTypeChainEnabled,omitempty"` + IsBtcTypeChainEnabled bool `protobuf:"varint,2,opt,name=isBtcTypeChainEnabled,proto3" json:"isBtcTypeChainEnabled,omitempty"` +} + +func (m *BlockHeaderVerificationFlags) Reset() { *m = BlockHeaderVerificationFlags{} } +func (m *BlockHeaderVerificationFlags) String() string { return proto.CompactTextString(m) } +func (*BlockHeaderVerificationFlags) ProtoMessage() {} +func (*BlockHeaderVerificationFlags) Descriptor() ([]byte, []int) { + return fileDescriptor_b948b59e4d986f49, []int{1} +} +func (m *BlockHeaderVerificationFlags) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *BlockHeaderVerificationFlags) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_BlockHeaderVerificationFlags.Marshal(b, m, deterministic) + } else { + b = b[:cap(b)] + n, err := m.MarshalToSizedBuffer(b) + if err != nil { + return nil, err + } + return b[:n], nil + } +} +func (m *BlockHeaderVerificationFlags) XXX_Merge(src proto.Message) { + xxx_messageInfo_BlockHeaderVerificationFlags.Merge(m, src) +} +func (m *BlockHeaderVerificationFlags) XXX_Size() int { + return m.Size() +} +func (m *BlockHeaderVerificationFlags) XXX_DiscardUnknown() { + xxx_messageInfo_BlockHeaderVerificationFlags.DiscardUnknown(m) +} + +var xxx_messageInfo_BlockHeaderVerificationFlags proto.InternalMessageInfo + +func (m *BlockHeaderVerificationFlags) GetIsEthTypeChainEnabled() bool { + if m != nil { + return m.IsEthTypeChainEnabled + } + return false +} + +func (m *BlockHeaderVerificationFlags) GetIsBtcTypeChainEnabled() bool { + if m != nil { + return m.IsBtcTypeChainEnabled + } + return false +} + type CrosschainFlags struct { - IsInboundEnabled bool `protobuf:"varint,1,opt,name=isInboundEnabled,proto3" json:"isInboundEnabled,omitempty"` - IsOutboundEnabled bool `protobuf:"varint,2,opt,name=isOutboundEnabled,proto3" json:"isOutboundEnabled,omitempty"` - GasPriceIncreaseFlags *GasPriceIncreaseFlags `protobuf:"bytes,3,opt,name=gasPriceIncreaseFlags,proto3" json:"gasPriceIncreaseFlags,omitempty"` + IsInboundEnabled bool `protobuf:"varint,1,opt,name=isInboundEnabled,proto3" json:"isInboundEnabled,omitempty"` + IsOutboundEnabled bool `protobuf:"varint,2,opt,name=isOutboundEnabled,proto3" json:"isOutboundEnabled,omitempty"` + GasPriceIncreaseFlags *GasPriceIncreaseFlags `protobuf:"bytes,3,opt,name=gasPriceIncreaseFlags,proto3" json:"gasPriceIncreaseFlags,omitempty"` + BlockHeaderVerificationFlags *BlockHeaderVerificationFlags `protobuf:"bytes,4,opt,name=blockHeaderVerificationFlags,proto3" json:"blockHeaderVerificationFlags,omitempty"` } func (m *CrosschainFlags) Reset() { *m = CrosschainFlags{} } func (m *CrosschainFlags) String() string { return proto.CompactTextString(m) } func (*CrosschainFlags) ProtoMessage() {} func (*CrosschainFlags) Descriptor() ([]byte, []int) { - return fileDescriptor_b948b59e4d986f49, []int{1} + return fileDescriptor_b948b59e4d986f49, []int{2} } func (m *CrosschainFlags) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -148,38 +201,113 @@ func (m *CrosschainFlags) GetGasPriceIncreaseFlags() *GasPriceIncreaseFlags { return nil } +func (m *CrosschainFlags) GetBlockHeaderVerificationFlags() *BlockHeaderVerificationFlags { + if m != nil { + return m.BlockHeaderVerificationFlags + } + return nil +} + +type LegacyCrosschainFlags struct { + IsInboundEnabled bool `protobuf:"varint,1,opt,name=isInboundEnabled,proto3" json:"isInboundEnabled,omitempty"` + IsOutboundEnabled bool `protobuf:"varint,2,opt,name=isOutboundEnabled,proto3" json:"isOutboundEnabled,omitempty"` + GasPriceIncreaseFlags *GasPriceIncreaseFlags `protobuf:"bytes,3,opt,name=gasPriceIncreaseFlags,proto3" json:"gasPriceIncreaseFlags,omitempty"` +} + +func (m *LegacyCrosschainFlags) Reset() { *m = LegacyCrosschainFlags{} } +func (m *LegacyCrosschainFlags) String() string { return proto.CompactTextString(m) } +func (*LegacyCrosschainFlags) ProtoMessage() {} +func (*LegacyCrosschainFlags) Descriptor() ([]byte, []int) { + return fileDescriptor_b948b59e4d986f49, []int{3} +} +func (m *LegacyCrosschainFlags) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *LegacyCrosschainFlags) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_LegacyCrosschainFlags.Marshal(b, m, deterministic) + } else { + b = b[:cap(b)] + n, err := m.MarshalToSizedBuffer(b) + if err != nil { + return nil, err + } + return b[:n], nil + } +} +func (m *LegacyCrosschainFlags) XXX_Merge(src proto.Message) { + xxx_messageInfo_LegacyCrosschainFlags.Merge(m, src) +} +func (m *LegacyCrosschainFlags) XXX_Size() int { + return m.Size() +} +func (m *LegacyCrosschainFlags) XXX_DiscardUnknown() { + xxx_messageInfo_LegacyCrosschainFlags.DiscardUnknown(m) +} + +var xxx_messageInfo_LegacyCrosschainFlags proto.InternalMessageInfo + +func (m *LegacyCrosschainFlags) GetIsInboundEnabled() bool { + if m != nil { + return m.IsInboundEnabled + } + return false +} + +func (m *LegacyCrosschainFlags) GetIsOutboundEnabled() bool { + if m != nil { + return m.IsOutboundEnabled + } + return false +} + +func (m *LegacyCrosschainFlags) GetGasPriceIncreaseFlags() *GasPriceIncreaseFlags { + if m != nil { + return m.GasPriceIncreaseFlags + } + return nil +} + func init() { proto.RegisterType((*GasPriceIncreaseFlags)(nil), "zetachain.zetacore.observer.GasPriceIncreaseFlags") + proto.RegisterType((*BlockHeaderVerificationFlags)(nil), "zetachain.zetacore.observer.BlockHeaderVerificationFlags") proto.RegisterType((*CrosschainFlags)(nil), "zetachain.zetacore.observer.CrosschainFlags") + proto.RegisterType((*LegacyCrosschainFlags)(nil), "zetachain.zetacore.observer.LegacyCrosschainFlags") } func init() { proto.RegisterFile("observer/crosschain_flags.proto", fileDescriptor_b948b59e4d986f49) } var fileDescriptor_b948b59e4d986f49 = []byte{ - // 364 bytes of a gzipped FileDescriptorProto - 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x7c, 0x92, 0xcf, 0x6b, 0xe2, 0x40, - 0x14, 0xc7, 0x33, 0x0a, 0x8b, 0x8c, 0xc8, 0xee, 0x86, 0x95, 0x75, 0x5d, 0x88, 0xc1, 0x93, 0x2c, - 0xdb, 0x19, 0xb0, 0x97, 0x9e, 0xed, 0x2f, 0x02, 0x85, 0x4a, 0x8e, 0xbd, 0x94, 0x49, 0x7c, 0x4e, - 0x02, 0xe9, 0x8c, 0xcc, 0x4c, 0xa4, 0xf6, 0xaf, 0xe8, 0xb1, 0x7f, 0x4d, 0xcf, 0x1e, 0xbd, 0x14, - 0x7a, 0x6a, 0x8b, 0xfe, 0x23, 0xc5, 0x49, 0x95, 0x5a, 0x6d, 0x6f, 0x2f, 0xef, 0xbd, 0x6f, 0x3e, - 0x5f, 0xbe, 0x6f, 0x70, 0x4b, 0x46, 0x1a, 0xd4, 0x18, 0x14, 0x8d, 0x95, 0xd4, 0x3a, 0x4e, 0x58, - 0x2a, 0x2e, 0x87, 0x19, 0xe3, 0x9a, 0x8c, 0x94, 0x34, 0xd2, 0xfd, 0x7b, 0x03, 0x86, 0xd9, 0x36, - 0xb1, 0x95, 0x54, 0x40, 0x56, 0x9a, 0xe6, 0x2f, 0x2e, 0xb9, 0xb4, 0x7b, 0x74, 0x59, 0x15, 0x92, - 0xa6, 0xc7, 0xa5, 0xe4, 0x19, 0x50, 0xfb, 0x15, 0xe5, 0x43, 0x3a, 0xc8, 0x15, 0x33, 0xa9, 0x14, - 0xc5, 0xbc, 0x7d, 0x8f, 0x70, 0xfd, 0x94, 0xe9, 0xbe, 0x4a, 0x63, 0x08, 0x44, 0xac, 0x80, 0x69, - 0x38, 0x59, 0x22, 0x5d, 0x1f, 0x57, 0x61, 0x24, 0xe3, 0xe4, 0x0c, 0x04, 0x37, 0x49, 0x03, 0xf9, - 0xa8, 0x53, 0x0e, 0xdf, 0xb7, 0xdc, 0x00, 0xd7, 0x14, 0x18, 0x35, 0x09, 0x84, 0x01, 0x35, 0x66, - 0x59, 0xa3, 0xe4, 0xa3, 0x4e, 0xb5, 0xfb, 0x87, 0x14, 0x4c, 0xb2, 0x62, 0x92, 0xa3, 0x37, 0x66, - 0xaf, 0x32, 0x7d, 0x6a, 0x39, 0x77, 0xcf, 0x2d, 0x14, 0x6e, 0x2a, 0xdd, 0x03, 0xfc, 0x9b, 0x7f, - 0x70, 0xd1, 0x07, 0x15, 0x83, 0x30, 0x8d, 0xb2, 0x8f, 0x3a, 0xb5, 0xf0, 0xb3, 0x71, 0xfb, 0x01, - 0xe1, 0xef, 0x87, 0xeb, 0xb8, 0x0a, 0xeb, 0xff, 0xf0, 0x8f, 0x54, 0x07, 0x22, 0x92, 0xb9, 0x18, - 0x1c, 0x0b, 0x16, 0x65, 0x30, 0xb0, 0xfe, 0x2b, 0xe1, 0x56, 0xdf, 0xfd, 0x8f, 0x7f, 0xa6, 0xfa, - 0x3c, 0x37, 0x1b, 0xcb, 0x25, 0xbb, 0xbc, 0x3d, 0x70, 0x13, 0x5c, 0xe7, 0xbb, 0xd2, 0xb2, 0x2e, - 0xab, 0xdd, 0x2e, 0xf9, 0xe2, 0x42, 0x64, 0x67, 0xce, 0xe1, 0xee, 0x1f, 0xf6, 0x82, 0xe9, 0xdc, - 0x43, 0xb3, 0xb9, 0x87, 0x5e, 0xe6, 0x1e, 0xba, 0x5d, 0x78, 0xce, 0x6c, 0xe1, 0x39, 0x8f, 0x0b, - 0xcf, 0xb9, 0xa0, 0x3c, 0x35, 0x49, 0x1e, 0x91, 0x58, 0x5e, 0xd1, 0x25, 0x64, 0xcf, 0xf2, 0xe8, - 0x8a, 0x47, 0xaf, 0xe9, 0xfa, 0x1d, 0x99, 0xc9, 0x08, 0x74, 0xf4, 0xcd, 0x1e, 0x62, 0xff, 0x35, - 0x00, 0x00, 0xff, 0xff, 0xc1, 0xe4, 0x6d, 0x3a, 0x60, 0x02, 0x00, 0x00, + // 452 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xdc, 0x94, 0xc1, 0x8a, 0xd3, 0x40, + 0x18, 0xc7, 0x3b, 0x5d, 0x91, 0x65, 0xca, 0xa2, 0x06, 0x8b, 0x75, 0x5d, 0xd2, 0xd2, 0x53, 0x11, + 0x9d, 0x81, 0xea, 0x41, 0xaf, 0x5d, 0x57, 0x0d, 0x2c, 0xb8, 0x04, 0xf1, 0xe0, 0x45, 0x26, 0xd3, + 0xaf, 0x93, 0xc1, 0x38, 0x53, 0x66, 0x26, 0x8b, 0x11, 0x7c, 0x01, 0x4f, 0x1e, 0x7d, 0x1a, 0xcf, + 0x7b, 0xdc, 0x83, 0x07, 0x41, 0x50, 0x69, 0x5f, 0x44, 0x32, 0x31, 0x8b, 0xb5, 0x31, 0x0f, 0xe0, + 0x6d, 0xf2, 0xfd, 0xe7, 0x3f, 0xbf, 0x7c, 0xdf, 0x3f, 0x19, 0x3c, 0xd4, 0x89, 0x05, 0x73, 0x0a, + 0x86, 0x72, 0xa3, 0xad, 0xe5, 0x29, 0x93, 0xea, 0xd5, 0x22, 0x63, 0xc2, 0x92, 0xa5, 0xd1, 0x4e, + 0x07, 0xb7, 0xde, 0x81, 0x63, 0xbe, 0x4c, 0xfc, 0x4a, 0x1b, 0x20, 0xb5, 0x67, 0xff, 0xba, 0xd0, + 0x42, 0xfb, 0x7d, 0xb4, 0x5c, 0x55, 0x96, 0xfd, 0x50, 0x68, 0x2d, 0x32, 0xa0, 0xfe, 0x29, 0xc9, + 0x17, 0x74, 0x9e, 0x1b, 0xe6, 0xa4, 0x56, 0x95, 0x3e, 0xfe, 0x8c, 0x70, 0xff, 0x09, 0xb3, 0x27, + 0x46, 0x72, 0x88, 0x14, 0x37, 0xc0, 0x2c, 0x3c, 0x2e, 0x91, 0xc1, 0x08, 0xf7, 0x60, 0xa9, 0x79, + 0x7a, 0x0c, 0x4a, 0xb8, 0x74, 0x80, 0x46, 0x68, 0xb2, 0x13, 0xff, 0x59, 0x0a, 0x22, 0xbc, 0x67, + 0xc0, 0x99, 0x22, 0x52, 0x0e, 0xcc, 0x29, 0xcb, 0x06, 0xdd, 0x11, 0x9a, 0xf4, 0xa6, 0x37, 0x49, + 0xc5, 0x24, 0x35, 0x93, 0x3c, 0xfa, 0xcd, 0x9c, 0xed, 0x9e, 0x7d, 0x1f, 0x76, 0x3e, 0xfd, 0x18, + 0xa2, 0x78, 0xd3, 0x19, 0x3c, 0xc0, 0x37, 0xc4, 0x5f, 0x6f, 0x71, 0x02, 0x86, 0x83, 0x72, 0x83, + 0x9d, 0x11, 0x9a, 0xec, 0xc5, 0xff, 0x92, 0xc7, 0x1f, 0x10, 0x3e, 0x98, 0x65, 0x9a, 0xbf, 0x7e, + 0x0a, 0x6c, 0x0e, 0xe6, 0x05, 0x18, 0xb9, 0x90, 0xdc, 0xe3, 0xaa, 0x3e, 0xee, 0xe3, 0xbe, 0xb4, + 0x47, 0x2e, 0x7d, 0x5e, 0x2c, 0xe1, 0xb0, 0x9c, 0xdd, 0x91, 0x62, 0x49, 0x06, 0x73, 0xdf, 0xd1, + 0x6e, 0xdc, 0x2c, 0x56, 0xae, 0x99, 0xe3, 0x5b, 0xae, 0x6e, 0xed, 0x6a, 0x10, 0xc7, 0x5f, 0xba, + 0xf8, 0xca, 0xe1, 0x45, 0x76, 0x15, 0xff, 0x36, 0xbe, 0x2a, 0x6d, 0xa4, 0x12, 0x9d, 0xab, 0xf9, + 0x26, 0x7a, 0xab, 0x1e, 0xdc, 0xc1, 0xd7, 0xa4, 0x7d, 0x96, 0xbb, 0x8d, 0xcd, 0x15, 0x71, 0x5b, + 0x08, 0x52, 0xdc, 0x17, 0x4d, 0xd1, 0xf9, 0x91, 0xf5, 0xa6, 0x53, 0xd2, 0xf2, 0xb9, 0x90, 0xc6, + 0xd0, 0xe3, 0xe6, 0x03, 0x83, 0xf7, 0xf8, 0x20, 0x69, 0x99, 0xf1, 0xe0, 0x92, 0x07, 0x3e, 0x6c, + 0x05, 0xb6, 0x85, 0x14, 0xb7, 0x1e, 0x3f, 0xfe, 0x86, 0x70, 0xff, 0x18, 0x04, 0xe3, 0xc5, 0x7f, + 0x38, 0xdc, 0x59, 0x74, 0xb6, 0x0a, 0xd1, 0xf9, 0x2a, 0x44, 0x3f, 0x57, 0x21, 0xfa, 0xb8, 0x0e, + 0x3b, 0xe7, 0xeb, 0xb0, 0xf3, 0x75, 0x1d, 0x76, 0x5e, 0x52, 0x21, 0x5d, 0x9a, 0x27, 0x84, 0xeb, + 0x37, 0xb4, 0x84, 0xdc, 0xf5, 0x3c, 0x5a, 0xf3, 0xe8, 0x5b, 0x7a, 0x71, 0x63, 0xb8, 0x62, 0x09, + 0x36, 0xb9, 0xec, 0x7f, 0xb9, 0x7b, 0xbf, 0x02, 0x00, 0x00, 0xff, 0xff, 0x23, 0xb8, 0x6d, 0xec, + 0x4a, 0x04, 0x00, 0x00, } func (m *GasPriceIncreaseFlags) Marshal() (dAtA []byte, err error) { @@ -223,6 +351,49 @@ func (m *GasPriceIncreaseFlags) MarshalToSizedBuffer(dAtA []byte) (int, error) { return len(dAtA) - i, nil } +func (m *BlockHeaderVerificationFlags) Marshal() (dAtA []byte, err error) { + size := m.Size() + dAtA = make([]byte, size) + n, err := m.MarshalToSizedBuffer(dAtA[:size]) + if err != nil { + return nil, err + } + return dAtA[:n], nil +} + +func (m *BlockHeaderVerificationFlags) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *BlockHeaderVerificationFlags) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + if m.IsBtcTypeChainEnabled { + i-- + if m.IsBtcTypeChainEnabled { + dAtA[i] = 1 + } else { + dAtA[i] = 0 + } + i-- + dAtA[i] = 0x10 + } + if m.IsEthTypeChainEnabled { + i-- + if m.IsEthTypeChainEnabled { + dAtA[i] = 1 + } else { + dAtA[i] = 0 + } + i-- + dAtA[i] = 0x8 + } + return len(dAtA) - i, nil +} + func (m *CrosschainFlags) Marshal() (dAtA []byte, err error) { size := m.Size() dAtA = make([]byte, size) @@ -239,6 +410,73 @@ func (m *CrosschainFlags) MarshalTo(dAtA []byte) (int, error) { } func (m *CrosschainFlags) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + if m.BlockHeaderVerificationFlags != nil { + { + size, err := m.BlockHeaderVerificationFlags.MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarintCrosschainFlags(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0x22 + } + if m.GasPriceIncreaseFlags != nil { + { + size, err := m.GasPriceIncreaseFlags.MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarintCrosschainFlags(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0x1a + } + if m.IsOutboundEnabled { + i-- + if m.IsOutboundEnabled { + dAtA[i] = 1 + } else { + dAtA[i] = 0 + } + i-- + dAtA[i] = 0x10 + } + if m.IsInboundEnabled { + i-- + if m.IsInboundEnabled { + dAtA[i] = 1 + } else { + dAtA[i] = 0 + } + i-- + dAtA[i] = 0x8 + } + return len(dAtA) - i, nil +} + +func (m *LegacyCrosschainFlags) Marshal() (dAtA []byte, err error) { + size := m.Size() + dAtA = make([]byte, size) + n, err := m.MarshalToSizedBuffer(dAtA[:size]) + if err != nil { + return nil, err + } + return dAtA[:n], nil +} + +func (m *LegacyCrosschainFlags) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *LegacyCrosschainFlags) MarshalToSizedBuffer(dAtA []byte) (int, error) { i := len(dAtA) _ = i var l int @@ -306,7 +544,45 @@ func (m *GasPriceIncreaseFlags) Size() (n int) { return n } +func (m *BlockHeaderVerificationFlags) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + if m.IsEthTypeChainEnabled { + n += 2 + } + if m.IsBtcTypeChainEnabled { + n += 2 + } + return n +} + func (m *CrosschainFlags) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + if m.IsInboundEnabled { + n += 2 + } + if m.IsOutboundEnabled { + n += 2 + } + if m.GasPriceIncreaseFlags != nil { + l = m.GasPriceIncreaseFlags.Size() + n += 1 + l + sovCrosschainFlags(uint64(l)) + } + if m.BlockHeaderVerificationFlags != nil { + l = m.BlockHeaderVerificationFlags.Size() + n += 1 + l + sovCrosschainFlags(uint64(l)) + } + return n +} + +func (m *LegacyCrosschainFlags) Size() (n int) { if m == nil { return 0 } @@ -452,6 +728,96 @@ func (m *GasPriceIncreaseFlags) Unmarshal(dAtA []byte) error { } return nil } +func (m *BlockHeaderVerificationFlags) Unmarshal(dAtA []byte) error { + l := len(dAtA) + iNdEx := 0 + for iNdEx < l { + preIndex := iNdEx + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowCrosschainFlags + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + fieldNum := int32(wire >> 3) + wireType := int(wire & 0x7) + if wireType == 4 { + return fmt.Errorf("proto: BlockHeaderVerificationFlags: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: BlockHeaderVerificationFlags: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field IsEthTypeChainEnabled", wireType) + } + var v int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowCrosschainFlags + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + v |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + m.IsEthTypeChainEnabled = bool(v != 0) + case 2: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field IsBtcTypeChainEnabled", wireType) + } + var v int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowCrosschainFlags + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + v |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + m.IsBtcTypeChainEnabled = bool(v != 0) + default: + iNdEx = preIndex + skippy, err := skipCrosschainFlags(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return ErrInvalidLengthCrosschainFlags + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} func (m *CrosschainFlags) Unmarshal(dAtA []byte) error { l := len(dAtA) iNdEx := 0 @@ -481,6 +847,168 @@ func (m *CrosschainFlags) Unmarshal(dAtA []byte) error { return fmt.Errorf("proto: CrosschainFlags: illegal tag %d (wire type %d)", fieldNum, wire) } switch fieldNum { + case 1: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field IsInboundEnabled", wireType) + } + var v int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowCrosschainFlags + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + v |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + m.IsInboundEnabled = bool(v != 0) + case 2: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field IsOutboundEnabled", wireType) + } + var v int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowCrosschainFlags + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + v |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + m.IsOutboundEnabled = bool(v != 0) + case 3: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field GasPriceIncreaseFlags", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowCrosschainFlags + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return ErrInvalidLengthCrosschainFlags + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return ErrInvalidLengthCrosschainFlags + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + if m.GasPriceIncreaseFlags == nil { + m.GasPriceIncreaseFlags = &GasPriceIncreaseFlags{} + } + if err := m.GasPriceIncreaseFlags.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + case 4: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field BlockHeaderVerificationFlags", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowCrosschainFlags + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return ErrInvalidLengthCrosschainFlags + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return ErrInvalidLengthCrosschainFlags + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + if m.BlockHeaderVerificationFlags == nil { + m.BlockHeaderVerificationFlags = &BlockHeaderVerificationFlags{} + } + if err := m.BlockHeaderVerificationFlags.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + default: + iNdEx = preIndex + skippy, err := skipCrosschainFlags(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return ErrInvalidLengthCrosschainFlags + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func (m *LegacyCrosschainFlags) Unmarshal(dAtA []byte) error { + l := len(dAtA) + iNdEx := 0 + for iNdEx < l { + preIndex := iNdEx + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowCrosschainFlags + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + fieldNum := int32(wire >> 3) + wireType := int(wire & 0x7) + if wireType == 4 { + return fmt.Errorf("proto: LegacyCrosschainFlags: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: LegacyCrosschainFlags: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { case 1: if wireType != 0 { return fmt.Errorf("proto: wrong wireType = %d for field IsInboundEnabled", wireType) diff --git a/x/observer/types/events.pb.go b/x/observer/types/events.pb.go index 14068f968d..dbbaef3f5a 100644 --- a/x/observer/types/events.pb.go +++ b/x/observer/types/events.pb.go @@ -237,11 +237,12 @@ func (m *EventNewObserverAdded) GetObserverLastBlockCount() uint64 { } type EventCrosschainFlagsUpdated struct { - MsgTypeUrl string `protobuf:"bytes,1,opt,name=msg_type_url,json=msgTypeUrl,proto3" json:"msg_type_url,omitempty"` - IsInboundEnabled bool `protobuf:"varint,2,opt,name=isInboundEnabled,proto3" json:"isInboundEnabled,omitempty"` - IsOutboundEnabled bool `protobuf:"varint,3,opt,name=isOutboundEnabled,proto3" json:"isOutboundEnabled,omitempty"` - GasPriceIncreaseFlags *GasPriceIncreaseFlags `protobuf:"bytes,4,opt,name=gasPriceIncreaseFlags,proto3" json:"gasPriceIncreaseFlags,omitempty"` - Signer string `protobuf:"bytes,5,opt,name=signer,proto3" json:"signer,omitempty"` + MsgTypeUrl string `protobuf:"bytes,1,opt,name=msg_type_url,json=msgTypeUrl,proto3" json:"msg_type_url,omitempty"` + IsInboundEnabled bool `protobuf:"varint,2,opt,name=isInboundEnabled,proto3" json:"isInboundEnabled,omitempty"` + IsOutboundEnabled bool `protobuf:"varint,3,opt,name=isOutboundEnabled,proto3" json:"isOutboundEnabled,omitempty"` + GasPriceIncreaseFlags *GasPriceIncreaseFlags `protobuf:"bytes,4,opt,name=gasPriceIncreaseFlags,proto3" json:"gasPriceIncreaseFlags,omitempty"` + Signer string `protobuf:"bytes,5,opt,name=signer,proto3" json:"signer,omitempty"` + BlockHeaderVerificationFlags *BlockHeaderVerificationFlags `protobuf:"bytes,6,opt,name=blockHeaderVerificationFlags,proto3" json:"blockHeaderVerificationFlags,omitempty"` } func (m *EventCrosschainFlagsUpdated) Reset() { *m = EventCrosschainFlagsUpdated{} } @@ -312,6 +313,13 @@ func (m *EventCrosschainFlagsUpdated) GetSigner() string { return "" } +func (m *EventCrosschainFlagsUpdated) GetBlockHeaderVerificationFlags() *BlockHeaderVerificationFlags { + if m != nil { + return m.BlockHeaderVerificationFlags + } + return nil +} + func init() { proto.RegisterType((*EventBallotCreated)(nil), "zetachain.zetacore.observer.EventBallotCreated") proto.RegisterType((*EventKeygenBlockUpdated)(nil), "zetachain.zetacore.observer.EventKeygenBlockUpdated") @@ -322,43 +330,45 @@ func init() { func init() { proto.RegisterFile("observer/events.proto", fileDescriptor_1f1ca57368474456) } var fileDescriptor_1f1ca57368474456 = []byte{ - // 564 bytes of a gzipped FileDescriptorProto - 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x8c, 0x53, 0xcf, 0x6f, 0xd3, 0x30, - 0x14, 0x6e, 0xba, 0x31, 0x81, 0x3b, 0x58, 0x67, 0xd1, 0x35, 0xeb, 0xa4, 0x6c, 0x54, 0x42, 0xe2, - 0x67, 0x22, 0x8d, 0x13, 0x88, 0x0b, 0xad, 0xc6, 0xa8, 0x40, 0x6c, 0xaa, 0xd8, 0x85, 0x4b, 0xe4, - 0x24, 0x6f, 0x49, 0xd4, 0xd4, 0xae, 0x6c, 0x67, 0x50, 0xee, 0xdc, 0xb9, 0x22, 0xfe, 0x21, 0x8e, - 0x3b, 0x72, 0xe0, 0x80, 0xda, 0x7f, 0x04, 0xd9, 0x4e, 0xd3, 0xa2, 0x56, 0xa8, 0x37, 0xfb, 0x7b, - 0xdf, 0xf7, 0xfc, 0xbd, 0x1f, 0x46, 0x0d, 0x16, 0x08, 0xe0, 0x57, 0xc0, 0x3d, 0xb8, 0x02, 0x2a, - 0x85, 0x3b, 0xe2, 0x4c, 0x32, 0x7c, 0xf0, 0x05, 0x24, 0x09, 0x13, 0x92, 0x52, 0x57, 0x9f, 0x18, - 0x07, 0x77, 0xc6, 0x6c, 0xdd, 0x8d, 0x59, 0xcc, 0x34, 0xcf, 0x53, 0x27, 0x23, 0x69, 0x1d, 0x96, - 0x99, 0x42, 0xce, 0x84, 0xd0, 0x62, 0xff, 0x32, 0x23, 0x71, 0x91, 0xb3, 0xd5, 0x2c, 0x09, 0xb3, - 0x83, 0x09, 0xb4, 0x7f, 0x5b, 0x08, 0x9f, 0xa8, 0xd7, 0x3b, 0x24, 0xcb, 0x98, 0xec, 0x72, 0x20, - 0x12, 0x22, 0x7c, 0x84, 0xb6, 0x87, 0x22, 0xf6, 0xe5, 0x78, 0x04, 0x7e, 0xce, 0x33, 0xdb, 0x3a, - 0xb2, 0x1e, 0xdc, 0xea, 0xa3, 0xa1, 0x88, 0x3f, 0x8c, 0x47, 0x70, 0xc1, 0x33, 0xfc, 0x18, 0xed, - 0x06, 0x5a, 0xe2, 0xa7, 0x11, 0x50, 0x99, 0x5e, 0xa6, 0xc0, 0xed, 0xaa, 0xa6, 0xd5, 0x4d, 0xa0, - 0x57, 0xe2, 0xf8, 0x21, 0xaa, 0x9b, 0x77, 0x89, 0x4c, 0x19, 0xf5, 0x13, 0x22, 0x12, 0x7b, 0x43, - 0x73, 0x77, 0x16, 0xf0, 0x37, 0x44, 0x24, 0x2a, 0xef, 0x22, 0x55, 0x97, 0x62, 0x6f, 0x9a, 0xbc, - 0x0b, 0x81, 0xae, 0xc2, 0xf1, 0x21, 0xaa, 0x15, 0x26, 0x94, 0x53, 0xfb, 0x86, 0x71, 0x69, 0x20, - 0x65, 0xb4, 0xfd, 0xd5, 0x42, 0x4d, 0x5d, 0xde, 0x5b, 0x18, 0xc7, 0x40, 0x3b, 0x19, 0x0b, 0x07, - 0x17, 0xa3, 0x68, 0xcd, 0x1a, 0xef, 0xa1, 0xed, 0x81, 0xd6, 0xf9, 0x81, 0x12, 0x16, 0xe5, 0xd5, - 0x06, 0xf3, 0x5c, 0xf8, 0x3e, 0xba, 0x53, 0x50, 0x46, 0x79, 0x30, 0x80, 0xb1, 0x28, 0xea, 0xba, - 0x6d, 0xd0, 0x73, 0x03, 0xb6, 0xbf, 0x57, 0x51, 0x43, 0xfb, 0x78, 0x0f, 0x9f, 0xce, 0x8a, 0x09, - 0xbc, 0x8a, 0xa2, 0xb5, 0x5c, 0x94, 0xcd, 0x03, 0xee, 0x93, 0x28, 0xe2, 0x20, 0x44, 0xe1, 0x64, - 0x87, 0xcd, 0x53, 0x29, 0x18, 0xbf, 0x44, 0x2d, 0xbd, 0x32, 0x59, 0x0a, 0x54, 0xfa, 0x31, 0x27, - 0x54, 0x02, 0x94, 0x22, 0xe3, 0xcc, 0x9e, 0x33, 0x4e, 0x0d, 0x61, 0xa6, 0x7e, 0x81, 0xf6, 0x57, - 0xa8, 0x4d, 0x5d, 0xc5, 0x08, 0x9a, 0x4b, 0x62, 0x53, 0x21, 0x7e, 0x8e, 0xf6, 0x4b, 0x93, 0x19, - 0x11, 0xd2, 0x74, 0xcc, 0x0f, 0x59, 0x4e, 0xa5, 0x9e, 0xcb, 0x66, 0x7f, 0x6f, 0x46, 0x78, 0x47, - 0x84, 0xd4, 0xdd, 0xeb, 0xaa, 0x68, 0xfb, 0x47, 0x15, 0x1d, 0xe8, 0xde, 0x74, 0xcb, 0xdd, 0x7d, - 0xad, 0x56, 0x77, 0xfd, 0x39, 0x3d, 0x42, 0xf5, 0x54, 0xf4, 0x68, 0xc0, 0x72, 0x1a, 0x9d, 0x50, - 0x12, 0x64, 0x10, 0xe9, 0x0e, 0xdd, 0xec, 0x2f, 0xe1, 0xf8, 0x09, 0xda, 0x4d, 0xc5, 0x59, 0x2e, - 0xff, 0x21, 0x6f, 0x68, 0xf2, 0x72, 0x00, 0x27, 0xa8, 0x11, 0x13, 0x71, 0xce, 0xd3, 0x10, 0x7a, - 0x34, 0xe4, 0x40, 0x04, 0x68, 0x6f, 0xba, 0x1d, 0xb5, 0xe3, 0x63, 0xf7, 0x3f, 0x7f, 0xd5, 0x3d, - 0x5d, 0xa5, 0xec, 0xaf, 0x4e, 0x88, 0xf7, 0xd0, 0x96, 0x48, 0x63, 0x0a, 0xbc, 0xd8, 0xe2, 0xe2, - 0xd6, 0xe9, 0xfd, 0x9c, 0x38, 0xd6, 0xf5, 0xc4, 0xb1, 0xfe, 0x4c, 0x1c, 0xeb, 0xdb, 0xd4, 0xa9, - 0x5c, 0x4f, 0x9d, 0xca, 0xaf, 0xa9, 0x53, 0xf9, 0xe8, 0xc5, 0xa9, 0x4c, 0xf2, 0xc0, 0x0d, 0xd9, - 0xd0, 0x53, 0x8f, 0x3f, 0xd5, 0x3e, 0xbc, 0x99, 0x0f, 0xef, 0x73, 0xf9, 0xd7, 0x3d, 0xd5, 0x3b, - 0x11, 0x6c, 0xe9, 0x2f, 0xff, 0xec, 0x6f, 0x00, 0x00, 0x00, 0xff, 0xff, 0x25, 0x1b, 0xca, 0x44, - 0x78, 0x04, 0x00, 0x00, + // 599 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x8c, 0x54, 0xcf, 0x6f, 0xd3, 0x30, + 0x14, 0x5e, 0xb6, 0x31, 0x81, 0x37, 0xd8, 0x66, 0xb1, 0x2d, 0xeb, 0x50, 0x36, 0x2a, 0x21, 0xf1, + 0x33, 0x91, 0xc6, 0x69, 0x88, 0x0b, 0xad, 0xc6, 0x56, 0x81, 0xd8, 0x54, 0x31, 0x0e, 0x5c, 0x22, + 0x27, 0x79, 0x4b, 0xac, 0x66, 0x76, 0x65, 0x3b, 0x83, 0x22, 0x71, 0xe4, 0xce, 0x15, 0xfe, 0x22, + 0x8e, 0x3b, 0x72, 0xe0, 0x80, 0xd6, 0x7f, 0x04, 0xd9, 0x4e, 0xd3, 0xa2, 0x56, 0x55, 0x6f, 0xce, + 0x7b, 0xdf, 0xf7, 0xbd, 0xef, 0xbd, 0xe7, 0x18, 0x6d, 0xf0, 0x48, 0x82, 0xb8, 0x04, 0x11, 0xc0, + 0x25, 0x30, 0x25, 0xfd, 0xae, 0xe0, 0x8a, 0xe3, 0x9d, 0x2f, 0xa0, 0x48, 0x9c, 0x11, 0xca, 0x7c, + 0x73, 0xe2, 0x02, 0xfc, 0x01, 0xb2, 0x76, 0x37, 0xe5, 0x29, 0x37, 0xb8, 0x40, 0x9f, 0x2c, 0xa5, + 0xb6, 0x5b, 0x29, 0xc5, 0x82, 0x4b, 0x69, 0xc8, 0xe1, 0x79, 0x4e, 0xd2, 0x52, 0xb3, 0xb6, 0x55, + 0x01, 0x06, 0x07, 0x9b, 0xa8, 0xff, 0x71, 0x10, 0x3e, 0xd4, 0xd5, 0x1b, 0x24, 0xcf, 0xb9, 0x6a, + 0x0a, 0x20, 0x0a, 0x12, 0xbc, 0x87, 0x56, 0x2e, 0x64, 0x1a, 0xaa, 0x5e, 0x17, 0xc2, 0x42, 0xe4, + 0xae, 0xb3, 0xe7, 0x3c, 0xbc, 0xd5, 0x46, 0x17, 0x32, 0x7d, 0xdf, 0xeb, 0xc2, 0x99, 0xc8, 0xf1, + 0x13, 0xb4, 0x1e, 0x19, 0x4a, 0x48, 0x13, 0x60, 0x8a, 0x9e, 0x53, 0x10, 0xee, 0xbc, 0x81, 0xad, + 0xd9, 0x44, 0xab, 0x8a, 0xe3, 0x47, 0x68, 0xcd, 0xd6, 0x25, 0x8a, 0x72, 0x16, 0x66, 0x44, 0x66, + 0xee, 0x82, 0xc1, 0xae, 0x8e, 0xc4, 0x8f, 0x89, 0xcc, 0xb4, 0xee, 0x28, 0xd4, 0xb4, 0xe2, 0x2e, + 0x5a, 0xdd, 0x91, 0x44, 0x53, 0xc7, 0xf1, 0x2e, 0x5a, 0x2e, 0x4d, 0x68, 0xa7, 0xee, 0x0d, 0xeb, + 0xd2, 0x86, 0xb4, 0xd1, 0xfa, 0x37, 0x07, 0x6d, 0x99, 0xf6, 0xde, 0x40, 0x2f, 0x05, 0xd6, 0xc8, + 0x79, 0xdc, 0x39, 0xeb, 0x26, 0x33, 0xf6, 0x78, 0x1f, 0xad, 0x74, 0x0c, 0x2f, 0x8c, 0x34, 0xb1, + 0x6c, 0x6f, 0xb9, 0x33, 0xd4, 0xc2, 0x0f, 0xd0, 0x9d, 0x12, 0xd2, 0x2d, 0xa2, 0x0e, 0xf4, 0x64, + 0xd9, 0xd7, 0x6d, 0x1b, 0x3d, 0xb5, 0xc1, 0xfa, 0x8f, 0x79, 0xb4, 0x61, 0x7c, 0xbc, 0x83, 0x4f, + 0x27, 0xe5, 0x06, 0x5e, 0x25, 0xc9, 0x4c, 0x2e, 0xaa, 0xe1, 0x81, 0x08, 0x49, 0x92, 0x08, 0x90, + 0xb2, 0x74, 0xb2, 0xca, 0x87, 0x52, 0x3a, 0x8c, 0x5f, 0xa2, 0x9a, 0xb9, 0x32, 0x39, 0x05, 0xa6, + 0xc2, 0x54, 0x10, 0xa6, 0x00, 0x2a, 0x92, 0x75, 0xe6, 0x0e, 0x11, 0x47, 0x16, 0x30, 0x60, 0xbf, + 0x40, 0xdb, 0x13, 0xd8, 0xb6, 0xaf, 0x72, 0x05, 0x5b, 0x63, 0x64, 0xdb, 0x21, 0x3e, 0x40, 0xdb, + 0x95, 0xc9, 0x9c, 0x48, 0x65, 0x27, 0x16, 0xc6, 0xbc, 0x60, 0xca, 0xec, 0x65, 0xb1, 0xbd, 0x39, + 0x00, 0xbc, 0x25, 0x52, 0x99, 0xe9, 0x35, 0x75, 0xb6, 0xfe, 0x73, 0x01, 0xed, 0x98, 0xd9, 0x34, + 0xab, 0xbb, 0xfb, 0x5a, 0x5f, 0xdd, 0xd9, 0xf7, 0xf4, 0x18, 0xad, 0x51, 0xd9, 0x62, 0x11, 0x2f, + 0x58, 0x72, 0xc8, 0x48, 0x94, 0x43, 0x62, 0x26, 0x74, 0xb3, 0x3d, 0x16, 0xc7, 0x4f, 0xd1, 0x3a, + 0x95, 0x27, 0x85, 0xfa, 0x0f, 0xbc, 0x60, 0xc0, 0xe3, 0x09, 0x9c, 0xa1, 0x8d, 0x94, 0xc8, 0x53, + 0x41, 0x63, 0x68, 0xb1, 0x58, 0x00, 0x91, 0x60, 0xbc, 0x99, 0x71, 0x2c, 0xef, 0xef, 0xfb, 0x53, + 0xfe, 0x55, 0xff, 0x68, 0x12, 0xb3, 0x3d, 0x59, 0x10, 0x6f, 0xa2, 0x25, 0x49, 0x53, 0x06, 0xa2, + 0xbc, 0xc5, 0xe5, 0x17, 0xfe, 0x8a, 0xee, 0x99, 0x51, 0x1e, 0x03, 0x49, 0x40, 0x7c, 0x00, 0x41, + 0xcf, 0x69, 0x6c, 0x7e, 0x01, 0x6b, 0x64, 0xc9, 0x18, 0x39, 0x98, 0x6a, 0xa4, 0x31, 0x45, 0xa0, + 0x3d, 0x55, 0xbe, 0xd1, 0xfa, 0x75, 0xed, 0x39, 0x57, 0xd7, 0x9e, 0xf3, 0xf7, 0xda, 0x73, 0xbe, + 0xf7, 0xbd, 0xb9, 0xab, 0xbe, 0x37, 0xf7, 0xbb, 0xef, 0xcd, 0x7d, 0x0c, 0x52, 0xaa, 0xb2, 0x22, + 0xf2, 0x63, 0x7e, 0x11, 0xe8, 0x92, 0xcf, 0x4c, 0xf5, 0x60, 0x50, 0x3d, 0xf8, 0x5c, 0x3d, 0x35, + 0x81, 0x5e, 0x9d, 0x8c, 0x96, 0xcc, 0x8b, 0xf3, 0xfc, 0x5f, 0x00, 0x00, 0x00, 0xff, 0xff, 0xea, + 0x9e, 0x8b, 0x9e, 0xf7, 0x04, 0x00, 0x00, } func (m *EventBallotCreated) Marshal() (dAtA []byte, err error) { @@ -539,6 +549,18 @@ func (m *EventCrosschainFlagsUpdated) MarshalToSizedBuffer(dAtA []byte) (int, er _ = i var l int _ = l + if m.BlockHeaderVerificationFlags != nil { + { + size, err := m.BlockHeaderVerificationFlags.MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarintEvents(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0x32 + } if len(m.Signer) > 0 { i -= len(m.Signer) copy(dAtA[i:], m.Signer) @@ -701,6 +723,10 @@ func (m *EventCrosschainFlagsUpdated) Size() (n int) { if l > 0 { n += 1 + l + sovEvents(uint64(l)) } + if m.BlockHeaderVerificationFlags != nil { + l = m.BlockHeaderVerificationFlags.Size() + n += 1 + l + sovEvents(uint64(l)) + } return n } @@ -1432,6 +1458,42 @@ func (m *EventCrosschainFlagsUpdated) Unmarshal(dAtA []byte) error { } m.Signer = string(dAtA[iNdEx:postIndex]) iNdEx = postIndex + case 6: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field BlockHeaderVerificationFlags", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowEvents + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return ErrInvalidLengthEvents + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return ErrInvalidLengthEvents + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + if m.BlockHeaderVerificationFlags == nil { + m.BlockHeaderVerificationFlags = &BlockHeaderVerificationFlags{} + } + if err := m.BlockHeaderVerificationFlags.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex default: iNdEx = preIndex skippy, err := skipEvents(dAtA[iNdEx:]) diff --git a/x/observer/types/tx.pb.go b/x/observer/types/tx.pb.go index e7cfe8f234..567b27d987 100644 --- a/x/observer/types/tx.pb.go +++ b/x/observer/types/tx.pb.go @@ -431,10 +431,11 @@ func (m *MsgAddBlameVoteResponse) XXX_DiscardUnknown() { var xxx_messageInfo_MsgAddBlameVoteResponse proto.InternalMessageInfo type MsgUpdateCrosschainFlags struct { - Creator string `protobuf:"bytes,1,opt,name=creator,proto3" json:"creator,omitempty"` - IsInboundEnabled bool `protobuf:"varint,3,opt,name=isInboundEnabled,proto3" json:"isInboundEnabled,omitempty"` - IsOutboundEnabled bool `protobuf:"varint,4,opt,name=isOutboundEnabled,proto3" json:"isOutboundEnabled,omitempty"` - GasPriceIncreaseFlags *GasPriceIncreaseFlags `protobuf:"bytes,5,opt,name=gasPriceIncreaseFlags,proto3" json:"gasPriceIncreaseFlags,omitempty"` + Creator string `protobuf:"bytes,1,opt,name=creator,proto3" json:"creator,omitempty"` + IsInboundEnabled bool `protobuf:"varint,3,opt,name=isInboundEnabled,proto3" json:"isInboundEnabled,omitempty"` + IsOutboundEnabled bool `protobuf:"varint,4,opt,name=isOutboundEnabled,proto3" json:"isOutboundEnabled,omitempty"` + GasPriceIncreaseFlags *GasPriceIncreaseFlags `protobuf:"bytes,5,opt,name=gasPriceIncreaseFlags,proto3" json:"gasPriceIncreaseFlags,omitempty"` + BlockHeaderVerificationFlags *BlockHeaderVerificationFlags `protobuf:"bytes,6,opt,name=blockHeaderVerificationFlags,proto3" json:"blockHeaderVerificationFlags,omitempty"` } func (m *MsgUpdateCrosschainFlags) Reset() { *m = MsgUpdateCrosschainFlags{} } @@ -498,6 +499,13 @@ func (m *MsgUpdateCrosschainFlags) GetGasPriceIncreaseFlags() *GasPriceIncreaseF return nil } +func (m *MsgUpdateCrosschainFlags) GetBlockHeaderVerificationFlags() *BlockHeaderVerificationFlags { + if m != nil { + return m.BlockHeaderVerificationFlags + } + return nil +} + type MsgUpdateCrosschainFlagsResponse struct { } @@ -640,56 +648,58 @@ func init() { func init() { proto.RegisterFile("observer/tx.proto", fileDescriptor_1bcd40fa296a2b1d) } var fileDescriptor_1bcd40fa296a2b1d = []byte{ - // 774 bytes of a gzipped FileDescriptorProto - 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x9c, 0x56, 0x4d, 0x4f, 0xdb, 0x48, - 0x18, 0x8e, 0x97, 0xcf, 0xbc, 0x41, 0x7c, 0x18, 0x02, 0x4e, 0x10, 0x21, 0xf2, 0x65, 0xb3, 0xbb, - 0x6c, 0xcc, 0x86, 0xdd, 0x55, 0x55, 0xa9, 0x87, 0xd0, 0x0f, 0x88, 0x2a, 0x0a, 0xb2, 0xd4, 0x1e, - 0x7a, 0xb1, 0xc6, 0x9e, 0xc1, 0xb6, 0x48, 0x66, 0x22, 0x8f, 0x53, 0x25, 0x3d, 0xf4, 0xde, 0x43, - 0xa5, 0xfe, 0x95, 0xfe, 0x87, 0x1e, 0x38, 0x72, 0xec, 0xa9, 0xaa, 0xe0, 0xd2, 0x9f, 0xd0, 0x63, - 0xe5, 0xf1, 0x47, 0x12, 0x92, 0x9a, 0x84, 0x13, 0x33, 0xef, 0x3c, 0xef, 0xf3, 0x3e, 0xef, 0x17, - 0x0e, 0xac, 0x31, 0x93, 0x13, 0xef, 0x0d, 0xf1, 0x34, 0xbf, 0x5b, 0x6d, 0x7b, 0xcc, 0x67, 0xf2, - 0xf6, 0x5b, 0xe2, 0x23, 0xcb, 0x41, 0x2e, 0xad, 0x8a, 0x13, 0xf3, 0x48, 0x35, 0x46, 0x15, 0xd7, - 0x2d, 0xd6, 0x6a, 0x31, 0xaa, 0x85, 0x7f, 0x42, 0x8f, 0xe2, 0x86, 0xcd, 0x6c, 0x26, 0x8e, 0x5a, - 0x70, 0x8a, 0xad, 0x09, 0xb5, 0xd9, 0x44, 0x2d, 0x12, 0x59, 0x77, 0x13, 0xab, 0xe5, 0x31, 0xce, - 0x45, 0x1c, 0xe3, 0xbc, 0x89, 0x6c, 0x1e, 0x01, 0xb6, 0x12, 0x40, 0x7c, 0x88, 0x1e, 0xf2, 0xc9, - 0x43, 0x1b, 0x79, 0xa8, 0x15, 0xe1, 0xd5, 0x4f, 0x12, 0xac, 0x9d, 0x70, 0xbb, 0x8e, 0xf1, 0x61, - 0x93, 0x59, 0x17, 0xc7, 0x04, 0x61, 0xe2, 0xc9, 0x0a, 0x2c, 0x58, 0x1e, 0x41, 0x3e, 0xf3, 0x14, - 0xa9, 0x2c, 0x55, 0xb2, 0x7a, 0x7c, 0x95, 0x0b, 0xb0, 0x18, 0x06, 0x75, 0xb1, 0xf2, 0x5b, 0x59, - 0xaa, 0xcc, 0xe8, 0x0b, 0xe2, 0xde, 0xc0, 0xf2, 0x0e, 0x80, 0x19, 0x70, 0x18, 0x0e, 0xe2, 0x8e, - 0x32, 0x53, 0x96, 0x2a, 0x4b, 0x7a, 0x56, 0x58, 0x8e, 0x11, 0x77, 0xe4, 0x4d, 0x98, 0x77, 0x88, - 0x6b, 0x3b, 0xbe, 0x32, 0x2b, 0xfc, 0xa2, 0x9b, 0xbc, 0x1f, 0xd8, 0x83, 0xa8, 0xca, 0x5c, 0x59, - 0xaa, 0xe4, 0x6a, 0x72, 0x35, 0xaa, 0x4e, 0xa8, 0xe5, 0x09, 0xf2, 0xd1, 0xe1, 0xec, 0xe5, 0xd7, - 0xdd, 0x8c, 0x1e, 0xe1, 0xd4, 0x6d, 0x28, 0x8c, 0x48, 0xd6, 0x09, 0x6f, 0x33, 0xca, 0x89, 0xda, - 0x85, 0xf5, 0x13, 0x6e, 0xbf, 0x6c, 0x63, 0xe4, 0x93, 0xc7, 0xcc, 0x23, 0x67, 0x22, 0xdb, 0x94, - 0x8c, 0x8e, 0x00, 0xac, 0x04, 0x27, 0x72, 0xca, 0xd5, 0x7e, 0xaf, 0xa6, 0x74, 0xb1, 0xda, 0xa7, - 0xd5, 0x07, 0x5c, 0xd5, 0x1d, 0xd8, 0x1e, 0x13, 0x39, 0x11, 0xf6, 0x59, 0x82, 0xe5, 0x50, 0xf6, - 0x69, 0x44, 0x94, 0x22, 0xea, 0x0f, 0x58, 0x8d, 0xc3, 0x19, 0x08, 0x63, 0x8f, 0xf0, 0x50, 0x5a, - 0x56, 0x5f, 0x89, 0xed, 0xf5, 0xd0, 0x2c, 0x3f, 0x84, 0x82, 0x90, 0xd8, 0x74, 0x09, 0xf5, 0x0d, - 0xdb, 0x43, 0xd4, 0x27, 0xc4, 0x68, 0x77, 0xcc, 0x0b, 0xd2, 0x13, 0x5d, 0xc8, 0xea, 0x5b, 0x7d, - 0xc0, 0x51, 0xf8, 0x7e, 0x26, 0x9e, 0xe5, 0x7f, 0x20, 0x8f, 0x30, 0x36, 0x28, 0xc3, 0xc4, 0x40, - 0x96, 0xc5, 0x3a, 0xd4, 0x37, 0x18, 0x6d, 0xf6, 0x44, 0x8b, 0x16, 0x75, 0x19, 0x61, 0xfc, 0x82, - 0x61, 0x52, 0x0f, 0x9f, 0x4e, 0x69, 0xb3, 0xa7, 0x2a, 0xb0, 0x39, 0x9c, 0x45, 0x92, 0xe0, 0x7b, - 0x09, 0x56, 0xe2, 0xbe, 0xa0, 0x16, 0x79, 0xc5, 0x7c, 0x72, 0xbf, 0x41, 0xaa, 0x07, 0x83, 0x84, - 0x5a, 0xc4, 0x70, 0xe9, 0x39, 0x13, 0x29, 0xe4, 0x6a, 0x6a, 0x6a, 0x47, 0x44, 0xc0, 0x60, 0xd8, - 0x50, 0x8b, 0x34, 0xe8, 0x39, 0x53, 0x0b, 0xb0, 0x75, 0x4b, 0x4a, 0x22, 0xf3, 0x87, 0x04, 0x4a, - 0xbf, 0x4f, 0xc9, 0x16, 0x3d, 0x0b, 0x96, 0x28, 0x45, 0xef, 0x9f, 0xb0, 0xea, 0xf2, 0x06, 0x35, - 0x59, 0x87, 0xe2, 0xa7, 0x14, 0x99, 0x4d, 0x82, 0x85, 0xb4, 0x45, 0x7d, 0xc4, 0x2e, 0xef, 0xc1, - 0x9a, 0xcb, 0x4f, 0x3b, 0xfe, 0x10, 0x38, 0x2c, 0xe9, 0xe8, 0x83, 0xec, 0x40, 0xde, 0x46, 0xfc, - 0xcc, 0x73, 0x2d, 0xd2, 0xa0, 0x41, 0x38, 0x4e, 0x84, 0x98, 0x68, 0x1f, 0x6a, 0xa9, 0x99, 0x1f, - 0x8d, 0xf3, 0xd4, 0xc7, 0x13, 0xaa, 0x2a, 0x94, 0x7f, 0x95, 0x79, 0x52, 0x9e, 0xba, 0x68, 0x62, - 0x88, 0x79, 0x4e, 0x7a, 0x36, 0xa1, 0x29, 0x45, 0xd9, 0x80, 0x39, 0xb1, 0xe0, 0x51, 0x07, 0xc3, - 0x4b, 0x54, 0xfc, 0x41, 0x8a, 0x98, 0xbd, 0xf6, 0x7d, 0x0e, 0x66, 0x4e, 0xb8, 0x2d, 0x33, 0xc8, - 0x0d, 0x2e, 0xc2, 0x5f, 0xa9, 0x39, 0x0e, 0xcf, 0x5b, 0xf1, 0x60, 0x0a, 0x70, 0x1c, 0x58, 0x7e, - 0x07, 0xab, 0x23, 0xff, 0x13, 0xf6, 0xef, 0x22, 0xba, 0xed, 0x51, 0x7c, 0x30, 0xad, 0x47, 0x12, - 0xdf, 0x83, 0xa5, 0xa1, 0xc5, 0xd8, 0x9b, 0x20, 0x89, 0x04, 0x5d, 0xfc, 0x77, 0x1a, 0x74, 0x12, - 0xf3, 0x83, 0x04, 0xf9, 0xf1, 0x63, 0xfe, 0xdf, 0x84, 0x79, 0x0c, 0xbb, 0x15, 0x1f, 0xdd, 0xcb, - 0x6d, 0xb0, 0x06, 0x43, 0x73, 0xb5, 0x37, 0x19, 0x5d, 0x88, 0xbe, 0xbb, 0x06, 0xe3, 0x06, 0x4e, - 0xee, 0xc2, 0xf2, 0xad, 0x6f, 0x5b, 0x75, 0xa2, 0x5a, 0x26, 0xf8, 0xe2, 0xff, 0xd3, 0xe1, 0xe3, - 0xc8, 0x87, 0x8d, 0xcb, 0xeb, 0x92, 0x74, 0x75, 0x5d, 0x92, 0xbe, 0x5d, 0x97, 0xa4, 0x8f, 0x37, - 0xa5, 0xcc, 0xd5, 0x4d, 0x29, 0xf3, 0xe5, 0xa6, 0x94, 0x79, 0xad, 0xd9, 0xae, 0xef, 0x74, 0xcc, - 0xe0, 0x3b, 0xa7, 0x05, 0x8c, 0x7f, 0x0b, 0x72, 0x2d, 0x26, 0xd7, 0xba, 0x5a, 0xff, 0x67, 0x45, - 0xaf, 0x4d, 0xb8, 0x39, 0x2f, 0xbe, 0xd5, 0x07, 0x3f, 0x03, 0x00, 0x00, 0xff, 0xff, 0xa1, 0x60, - 0xf7, 0xb4, 0x6f, 0x08, 0x00, 0x00, + // 803 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x9c, 0x56, 0x4b, 0x4f, 0xeb, 0x46, + 0x14, 0x8e, 0x2f, 0x17, 0x2e, 0x39, 0x41, 0x3c, 0x06, 0x02, 0x4e, 0x28, 0x21, 0xf2, 0xa6, 0x69, + 0x4b, 0x63, 0x1a, 0xda, 0xaa, 0xad, 0xd4, 0x45, 0xe8, 0x03, 0xa2, 0x8a, 0x82, 0x2c, 0x95, 0x45, + 0x37, 0xd6, 0xd8, 0x33, 0xb1, 0x2d, 0x92, 0x99, 0xc8, 0xe3, 0x54, 0x49, 0xa5, 0x76, 0xdf, 0x45, + 0xa5, 0xfe, 0x95, 0xfe, 0x87, 0x2e, 0x58, 0xb2, 0xec, 0xaa, 0xaa, 0x60, 0xd3, 0x7f, 0xd0, 0xed, + 0x95, 0xc7, 0x8f, 0x24, 0x24, 0x98, 0x84, 0x15, 0x33, 0x67, 0xbe, 0xf3, 0x7d, 0xe7, 0x49, 0x0c, + 0x5b, 0xdc, 0x12, 0xd4, 0xff, 0x89, 0xfa, 0x7a, 0x30, 0xa8, 0xf7, 0x7c, 0x1e, 0x70, 0xb4, 0xff, + 0x33, 0x0d, 0xb0, 0xed, 0x62, 0x8f, 0xd5, 0xe5, 0x89, 0xfb, 0xb4, 0x9e, 0xa0, 0xca, 0xdb, 0x36, + 0xef, 0x76, 0x39, 0xd3, 0xa3, 0x3f, 0x91, 0x47, 0x79, 0xc7, 0xe1, 0x0e, 0x97, 0x47, 0x3d, 0x3c, + 0x25, 0xd6, 0x94, 0xda, 0xea, 0xe0, 0x2e, 0x8d, 0xad, 0x87, 0xa9, 0xd5, 0xf6, 0xb9, 0x10, 0x52, + 0xc7, 0x6c, 0x77, 0xb0, 0x23, 0x62, 0xc0, 0x5e, 0x0a, 0x48, 0x0e, 0xf1, 0x43, 0x31, 0x7d, 0xe8, + 0x61, 0x1f, 0x77, 0x63, 0xbc, 0xf6, 0xa7, 0x02, 0x5b, 0x17, 0xc2, 0x69, 0x12, 0x72, 0xda, 0xe1, + 0xf6, 0xcd, 0x39, 0xc5, 0x84, 0xfa, 0x48, 0x85, 0x37, 0xb6, 0x4f, 0x71, 0xc0, 0x7d, 0x55, 0xa9, + 0x2a, 0xb5, 0xbc, 0x91, 0x5c, 0x51, 0x09, 0x56, 0x23, 0x51, 0x8f, 0xa8, 0xaf, 0xaa, 0x4a, 0x6d, + 0xc9, 0x78, 0x23, 0xef, 0x2d, 0x82, 0x0e, 0x00, 0xac, 0x90, 0xc3, 0x74, 0xb1, 0x70, 0xd5, 0xa5, + 0xaa, 0x52, 0x5b, 0x33, 0xf2, 0xd2, 0x72, 0x8e, 0x85, 0x8b, 0x76, 0x61, 0xc5, 0xa5, 0x9e, 0xe3, + 0x06, 0xea, 0x6b, 0xe9, 0x17, 0xdf, 0xd0, 0x71, 0x68, 0x0f, 0x55, 0xd5, 0xe5, 0xaa, 0x52, 0x2b, + 0x34, 0x50, 0x3d, 0xae, 0x4e, 0x14, 0xcb, 0xd7, 0x38, 0xc0, 0xa7, 0xaf, 0x6f, 0xff, 0x39, 0xcc, + 0x19, 0x31, 0x4e, 0xdb, 0x87, 0xd2, 0x54, 0xc8, 0x06, 0x15, 0x3d, 0xce, 0x04, 0xd5, 0x06, 0xb0, + 0x7d, 0x21, 0x9c, 0x1f, 0x7a, 0x04, 0x07, 0xf4, 0x2b, 0xee, 0xd3, 0x2b, 0x99, 0x6d, 0x46, 0x46, + 0x67, 0x00, 0x76, 0x8a, 0x93, 0x39, 0x15, 0x1a, 0xef, 0xd6, 0x33, 0xba, 0x58, 0x1f, 0xd1, 0x1a, + 0x63, 0xae, 0xda, 0x01, 0xec, 0xcf, 0x50, 0x4e, 0x03, 0xfb, 0x4b, 0x81, 0xf5, 0x28, 0xec, 0xcb, + 0x98, 0x28, 0x23, 0xa8, 0xf7, 0x60, 0x33, 0x91, 0x33, 0x31, 0x21, 0x3e, 0x15, 0x51, 0x68, 0x79, + 0x63, 0x23, 0xb1, 0x37, 0x23, 0x33, 0xfa, 0x02, 0x4a, 0x32, 0xc4, 0x8e, 0x47, 0x59, 0x60, 0x3a, + 0x3e, 0x66, 0x01, 0xa5, 0x66, 0xaf, 0x6f, 0xdd, 0xd0, 0xa1, 0xec, 0x42, 0xde, 0xd8, 0x1b, 0x01, + 0xce, 0xa2, 0xf7, 0x2b, 0xf9, 0x8c, 0x3e, 0x82, 0x22, 0x26, 0xc4, 0x64, 0x9c, 0x50, 0x13, 0xdb, + 0x36, 0xef, 0xb3, 0xc0, 0xe4, 0xac, 0x33, 0x94, 0x2d, 0x5a, 0x35, 0x10, 0x26, 0xe4, 0x7b, 0x4e, + 0x68, 0x33, 0x7a, 0xba, 0x64, 0x9d, 0xa1, 0xa6, 0xc2, 0xee, 0x64, 0x16, 0x69, 0x82, 0xbf, 0x29, + 0xb0, 0x91, 0xf4, 0x05, 0x77, 0xe9, 0x35, 0x0f, 0xe8, 0xcb, 0x06, 0xa9, 0x19, 0x0e, 0x12, 0xee, + 0x52, 0xd3, 0x63, 0x6d, 0x2e, 0x53, 0x28, 0x34, 0xb4, 0xcc, 0x8e, 0x48, 0xc1, 0x70, 0xd8, 0x70, + 0x97, 0xb6, 0x58, 0x9b, 0x6b, 0x25, 0xd8, 0x7b, 0x14, 0x4a, 0x1a, 0xe6, 0xff, 0xaf, 0x40, 0x1d, + 0xf5, 0x29, 0xdd, 0xa2, 0x6f, 0xc3, 0x25, 0xca, 0x88, 0xf7, 0x7d, 0xd8, 0xf4, 0x44, 0x8b, 0x59, + 0xbc, 0xcf, 0xc8, 0x37, 0x0c, 0x5b, 0x1d, 0x4a, 0x64, 0x68, 0xab, 0xc6, 0x94, 0x1d, 0x1d, 0xc1, + 0x96, 0x27, 0x2e, 0xfb, 0xc1, 0x04, 0x38, 0x2a, 0xe9, 0xf4, 0x03, 0x72, 0xa1, 0xe8, 0x60, 0x71, + 0xe5, 0x7b, 0x36, 0x6d, 0xb1, 0x50, 0x4e, 0x50, 0x19, 0x4c, 0xbc, 0x0f, 0x8d, 0xcc, 0xcc, 0xcf, + 0x66, 0x79, 0x1a, 0xb3, 0x09, 0xd1, 0x2f, 0xf0, 0x8e, 0x35, 0x5a, 0x99, 0x6b, 0xea, 0x7b, 0x6d, + 0xcf, 0xc6, 0x81, 0xc7, 0xa3, 0xec, 0xd5, 0x15, 0x29, 0xf8, 0xf9, 0x33, 0xa5, 0x7e, 0x9a, 0xc0, + 0xc8, 0xa4, 0xd7, 0x34, 0xa8, 0x3e, 0x55, 0xf8, 0xb4, 0x3b, 0x4d, 0x39, 0x43, 0x11, 0xe6, 0x3b, + 0x3a, 0x74, 0x28, 0xcb, 0xe8, 0xc9, 0x0e, 0x2c, 0x4b, 0xc1, 0x78, 0x80, 0xa2, 0x4b, 0xdc, 0xfb, + 0x71, 0x8a, 0x84, 0xbd, 0xf1, 0xdf, 0x32, 0x2c, 0x5d, 0x08, 0x07, 0x71, 0x28, 0x8c, 0xef, 0xe1, + 0x07, 0x99, 0x19, 0x4f, 0x8e, 0x7b, 0xf9, 0x64, 0x01, 0x70, 0x22, 0x8c, 0x7e, 0x85, 0xcd, 0xa9, + 0x7f, 0x49, 0xc7, 0xcf, 0x11, 0x3d, 0xf6, 0x28, 0x7f, 0xb6, 0xa8, 0x47, 0xaa, 0xef, 0xc3, 0xda, + 0xc4, 0x5e, 0x1e, 0xcd, 0x91, 0x44, 0x8a, 0x2e, 0x7f, 0xbc, 0x08, 0x3a, 0xd5, 0xfc, 0x5d, 0x81, + 0xe2, 0xec, 0x2d, 0xfb, 0x64, 0xce, 0x3c, 0x26, 0xdd, 0xca, 0x5f, 0xbe, 0xc8, 0x6d, 0xbc, 0x06, + 0x13, 0x73, 0x75, 0x34, 0x1f, 0x5d, 0x84, 0x7e, 0xbe, 0x06, 0xb3, 0x06, 0x0e, 0x0d, 0x60, 0xfd, + 0xd1, 0x4f, 0x6b, 0x7d, 0xae, 0x5a, 0xa6, 0xf8, 0xf2, 0xa7, 0x8b, 0xe1, 0x13, 0xe5, 0xd3, 0xd6, + 0xed, 0x7d, 0x45, 0xb9, 0xbb, 0xaf, 0x28, 0xff, 0xde, 0x57, 0x94, 0x3f, 0x1e, 0x2a, 0xb9, 0xbb, + 0x87, 0x4a, 0xee, 0xef, 0x87, 0x4a, 0xee, 0x47, 0xdd, 0xf1, 0x02, 0xb7, 0x6f, 0x85, 0x3f, 0xb3, + 0x7a, 0xc8, 0xf8, 0xa1, 0x24, 0xd7, 0x13, 0x72, 0x7d, 0xa0, 0x8f, 0xbe, 0x6a, 0x86, 0x3d, 0x2a, + 0xac, 0x15, 0xf9, 0xa9, 0x70, 0xf2, 0x36, 0x00, 0x00, 0xff, 0xff, 0x46, 0x18, 0xe1, 0x9b, 0xee, + 0x08, 0x00, 0x00, } // Reference imports to suppress errors if they are not otherwise used. @@ -1264,6 +1274,18 @@ func (m *MsgUpdateCrosschainFlags) MarshalToSizedBuffer(dAtA []byte) (int, error _ = i var l int _ = l + if m.BlockHeaderVerificationFlags != nil { + { + size, err := m.BlockHeaderVerificationFlags.MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarintTx(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0x32 + } if m.GasPriceIncreaseFlags != nil { { size, err := m.GasPriceIncreaseFlags.MarshalToSizedBuffer(dAtA[:i]) @@ -1540,6 +1562,10 @@ func (m *MsgUpdateCrosschainFlags) Size() (n int) { l = m.GasPriceIncreaseFlags.Size() n += 1 + l + sovTx(uint64(l)) } + if m.BlockHeaderVerificationFlags != nil { + l = m.BlockHeaderVerificationFlags.Size() + n += 1 + l + sovTx(uint64(l)) + } return n } @@ -2528,6 +2554,42 @@ func (m *MsgUpdateCrosschainFlags) Unmarshal(dAtA []byte) error { return err } iNdEx = postIndex + case 6: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field BlockHeaderVerificationFlags", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowTx + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return ErrInvalidLengthTx + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return ErrInvalidLengthTx + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + if m.BlockHeaderVerificationFlags == nil { + m.BlockHeaderVerificationFlags = &BlockHeaderVerificationFlags{} + } + if err := m.BlockHeaderVerificationFlags.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex default: iNdEx = preIndex skippy, err := skipTx(dAtA[iNdEx:]) diff --git a/zetaclient/bitcoin_client.go b/zetaclient/bitcoin_client.go index 42a31c39dd..4fc07e89bd 100644 --- a/zetaclient/bitcoin_client.go +++ b/zetaclient/bitcoin_client.go @@ -57,8 +57,8 @@ type BitcoinChainClient struct { lastBlockScanned int64 BlockTime uint64 // block time in seconds - mu *sync.Mutex // lock for pending nonce, all the maps, utxos and core params - pendingNonce uint64 // the artificial pending nonce (next nonce to process) for outTx + Mu *sync.Mutex // lock for all the maps, utxos and core params + pendingNonce uint64 includedTxHashes map[string]uint64 // key: tx hash includedTxResults map[string]btcjson.GetTransactionResult // key: chain-tss-nonce broadcastedTx map[string]string // key: chain-tss-nonce, value: outTx hash @@ -76,20 +76,48 @@ type BitcoinChainClient struct { const ( minConfirmations = 0 maxHeightDiff = 10000 - dustOffset = 2000 - bytesPerKB = 1000 btcBlocksPerDay = 144 + bytesPerKB = 1000 ) +func (ob *BitcoinChainClient) WithZetaClient(bridge *ZetaCoreBridge) { + ob.Mu.Lock() + defer ob.Mu.Unlock() + ob.zetaClient = bridge +} +func (ob *BitcoinChainClient) WithLogger(logger zerolog.Logger) { + ob.Mu.Lock() + defer ob.Mu.Unlock() + ob.logger = BTCLog{ + ChainLogger: logger, + WatchInTx: logger.With().Str("module", "WatchInTx").Logger(), + ObserveOutTx: logger.With().Str("module", "observeOutTx").Logger(), + WatchUTXOS: logger.With().Str("module", "WatchUTXOS").Logger(), + WatchGasPrice: logger.With().Str("module", "WatchGasPrice").Logger(), + } +} + +func (ob *BitcoinChainClient) WithBtcClient(client *rpcclient.Client) { + ob.Mu.Lock() + defer ob.Mu.Unlock() + ob.rpcClient = client +} + +func (ob *BitcoinChainClient) WithChain(chain common.Chain) { + ob.Mu.Lock() + defer ob.Mu.Unlock() + ob.chain = chain +} + func (ob *BitcoinChainClient) SetCoreParams(params observertypes.CoreParams) { - ob.mu.Lock() - defer ob.mu.Unlock() + ob.Mu.Lock() + defer ob.Mu.Unlock() ob.params = params } func (ob *BitcoinChainClient) GetCoreParams() observertypes.CoreParams { - ob.mu.Lock() - defer ob.mu.Unlock() + ob.Mu.Lock() + defer ob.Mu.Unlock() return ob.params } @@ -101,7 +129,7 @@ func NewBitcoinClient(chain common.Chain, bridge *ZetaCoreBridge, tss TSSSigner, } ob.stop = make(chan struct{}) ob.chain = chain - ob.mu = &sync.Mutex{} + ob.Mu = &sync.Mutex{} chainLogger := logger.With().Str("chain", chain.ChainName.String()).Logger() ob.logger = BTCLog{ ChainLogger: chainLogger, @@ -164,6 +192,7 @@ func (ob *BitcoinChainClient) Start() { go ob.observeOutTx() go ob.WatchUTXOS() go ob.WatchGasPrice() + go ob.ExternalChainWatcherForNewInboundTrackerSuggestions() } func (ob *BitcoinChainClient) Stop() { @@ -216,8 +245,8 @@ func (ob *BitcoinChainClient) GetLastBlockHeightScanned() int64 { } func (ob *BitcoinChainClient) GetPendingNonce() uint64 { - ob.mu.Lock() - defer ob.mu.Unlock() + ob.Mu.Lock() + defer ob.Mu.Unlock() return ob.pendingNonce } @@ -317,29 +346,8 @@ func (ob *BitcoinChainClient) observeInTx() error { inTxs := FilterAndParseIncomingTx(res.Block.Tx, uint64(res.Block.Height), tssAddress, &ob.logger.WatchInTx) for _, inTx := range inTxs { - ob.logger.WatchInTx.Debug().Msgf("Processing inTx: %s", inTx.TxHash) - sats, err := getSatoshis(inTx.Value) - if err != nil { - ob.logger.WatchInTx.Error().Err(err).Msgf("getSatoshis error: %s", err) - continue - } - amountInt := big.NewInt(sats) - message := hex.EncodeToString(inTx.MemoBytes) - zetaHash, err := ob.zetaClient.PostSend( - inTx.FromAddress, - ob.chain.ChainId, - inTx.FromAddress, - inTx.FromAddress, - common.ZetaChain().ChainId, - math.NewUintFromBigInt(amountInt), - message, - inTx.TxHash, - inTx.BlockNumber, - 0, - common.CoinType_Gas, - PostSendEVMGasLimit, - "", - ) + msg := ob.GetInboundVoteMessageFromBtcEvent(inTx) + zetaHash, err := ob.zetaClient.PostSend(PostSendEVMGasLimit, msg) if err != nil { ob.logger.WatchInTx.Error().Err(err).Msg("error posting to zeta core") continue @@ -370,10 +378,10 @@ func (ob *BitcoinChainClient) IsSendOutTxProcessed(sendHash string, nonce uint64 outTxID := ob.GetTxID(nonce) logger.Info().Msgf("IsSendOutTxProcessed %s", outTxID) - ob.mu.Lock() + ob.Mu.Lock() txnHash, broadcasted := ob.broadcastedTx[outTxID] res, included := ob.includedTxResults[outTxID] - ob.mu.Unlock() + ob.Mu.Unlock() // Get original cctx parameters params, err := ob.GetPendingCctxParams(nonce) @@ -382,6 +390,20 @@ func (ob *BitcoinChainClient) IsSendOutTxProcessed(sendHash string, nonce uint64 return false, false, err } + // Get original cctx parameters + params, err = ob.GetPendingCctxParams(nonce) + if err != nil { + ob.logger.ObserveOutTx.Info().Msgf("IsSendOutTxProcessed: can't find pending cctx for nonce %d", nonce) + return false, false, err + } + + // Get original cctx parameters + params, err = ob.GetPendingCctxParams(nonce) + if err != nil { + ob.logger.ObserveOutTx.Info().Msgf("IsSendOutTxProcessed: can't find pending cctx for nonce %d", nonce) + return false, false, err + } + if !included { if !broadcasted { return false, false, nil @@ -407,9 +429,9 @@ func (ob *BitcoinChainClient) IsSendOutTxProcessed(sendHash string, nonce uint64 } // Get tx result again in case it is just included - ob.mu.Lock() + ob.Mu.Lock() res, included = ob.includedTxResults[outTxID] - ob.mu.Unlock() + ob.Mu.Unlock() if !included { return false, false, nil } @@ -526,86 +548,117 @@ func FilterAndParseIncomingTx(txs []btcjson.TxRawResult, blockNumber uint64, tar if idx == 0 { continue // the first tx is coinbase; we do not process coinbase tx } - found := false - var value float64 - var memo []byte - if len(tx.Vout) >= 2 { - // first vout must to addressed to the targetAddress with p2wpkh scriptPubKey - out := tx.Vout[0] - script := out.ScriptPubKey.Hex - if len(script) == 44 && script[:4] == "0014" { // segwit output: 0x00 + 20 bytes of pubkey hash - hash, err := hex.DecodeString(script[4:]) + inTx, err := GetBtcEvent(tx, targetAddress, blockNumber, logger) + if err != nil { + logger.Error().Err(err).Msg("error getting btc event") + continue + } + if inTx != nil { + inTxs = append(inTxs, inTx) + } + } + return inTxs +} + +func (ob *BitcoinChainClient) GetInboundVoteMessageFromBtcEvent(inTx *BTCInTxEvnet) *types.MsgVoteOnObservedInboundTx { + ob.logger.WatchInTx.Debug().Msgf("Processing inTx: %s", inTx.TxHash) + amount := big.NewFloat(inTx.Value) + amount = amount.Mul(amount, big.NewFloat(1e8)) + amountInt, _ := amount.Int(nil) + message := hex.EncodeToString(inTx.MemoBytes) + return GetInBoundVoteMessage( + inTx.FromAddress, + ob.chain.ChainId, + inTx.FromAddress, + inTx.FromAddress, + common.ZetaChain().ChainId, + math.NewUintFromBigInt(amountInt), + message, + inTx.TxHash, + inTx.BlockNumber, + 0, + common.CoinType_Gas, + "", + ob.zetaClient.keys.GetOperatorAddress().String(), + ) +} + +func GetBtcEvent(tx btcjson.TxRawResult, targetAddress string, blockNumber uint64, logger *zerolog.Logger) (*BTCInTxEvnet, error) { + found := false + var value float64 + var memo []byte + if len(tx.Vout) >= 2 { + // first vout must to addressed to the targetAddress with p2wpkh scriptPubKey + out := tx.Vout[0] + script := out.ScriptPubKey.Hex + if len(script) == 44 && script[:4] == "0014" { // segwit output: 0x00 + 20 bytes of pubkey hash + hash, err := hex.DecodeString(script[4:]) + if err != nil { + return nil, err + } + wpkhAddress, err := btcutil.NewAddressWitnessPubKeyHash(hash, config.BitconNetParams) + if err != nil { + return nil, err + } + if wpkhAddress.EncodeAddress() != targetAddress { + return nil, err + } + value = out.Value + out = tx.Vout[1] + script = out.ScriptPubKey.Hex + if len(script) >= 4 && script[:2] == "6a" { // OP_RETURN + memoSize, err := strconv.ParseInt(script[2:4], 16, 32) if err != nil { - continue + return nil, errors.Wrapf(err, "error decoding pubkey hash") } - wpkhAddress, err := btcutil.NewAddressWitnessPubKeyHash(hash, config.BitconNetParams) - if err != nil { - continue + if int(memoSize) != (len(script)-4)/2 { + return nil, fmt.Errorf("memo size mismatch: %d != %d", memoSize, (len(script)-4)/2) } - if wpkhAddress.EncodeAddress() != targetAddress { - continue + memoBytes, err := hex.DecodeString(script[4:]) + if err != nil { + logger.Warn().Err(err).Msgf("error hex decoding memo") + return nil, fmt.Errorf("error hex decoding memo: %s", err) } - value = out.Value - out = tx.Vout[1] - script = out.ScriptPubKey.Hex - if len(script) >= 4 && script[:2] == "6a" { // OP_RETURN - memoSize, err := strconv.ParseInt(script[2:4], 16, 32) - if err != nil { - logger.Warn().Err(err).Msgf("error decoding pubkey hash") - continue - } - if int(memoSize) != (len(script)-4)/2 { - logger.Warn().Msgf("memo size mismatch: %d != %d", memoSize, (len(script)-4)/2) - continue - } - memoBytes, err := hex.DecodeString(script[4:]) - if err != nil { - logger.Warn().Err(err).Msgf("error hex decoding memo") - continue - } - if bytes.Compare(memoBytes, []byte(DonationMessage)) == 0 { - logger.Info().Msgf("donation tx: %s; value %f", tx.Txid, value) - continue - } - memo = memoBytes - found = true - + if bytes.Compare(memoBytes, []byte(DonationMessage)) == 0 { + logger.Info().Msgf("donation tx: %s; value %f", tx.Txid, value) + return nil, fmt.Errorf("donation tx: %s; value %f", tx.Txid, value) } + memo = memoBytes + found = true } - } - if found { - var fromAddress string - if len(tx.Vin) > 0 { - vin := tx.Vin[0] - //log.Info().Msgf("vin: %v", vin.Witness) - if len(vin.Witness) == 2 { - pk := vin.Witness[1] - pkBytes, err := hex.DecodeString(pk) - if err != nil { - logger.Warn().Msgf("error decoding pubkey: %s", err) - break - } - hash := btcutil.Hash160(pkBytes) - addr, err := btcutil.NewAddressWitnessPubKeyHash(hash, config.BitconNetParams) - if err != nil { - logger.Warn().Msgf("error decoding pubkey hash: %s", err) - break - } - fromAddress = addr.EncodeAddress() + + } + if found { + fmt.Println("found tx: ", tx.Txid) + var fromAddress string + if len(tx.Vin) > 0 { + vin := tx.Vin[0] + //log.Info().Msgf("vin: %v", vin.Witness) + if len(vin.Witness) == 2 { + pk := vin.Witness[1] + pkBytes, err := hex.DecodeString(pk) + if err != nil { + return nil, errors.Wrapf(err, "error decoding pubkey") + } + hash := btcutil.Hash160(pkBytes) + addr, err := btcutil.NewAddressWitnessPubKeyHash(hash, config.BitconNetParams) + if err != nil { + return nil, errors.Wrapf(err, "error decoding pubkey hash") } + fromAddress = addr.EncodeAddress() } - inTxs = append(inTxs, &BTCInTxEvnet{ - FromAddress: fromAddress, - ToAddress: targetAddress, - Value: value, - MemoBytes: memo, - BlockNumber: blockNumber, - TxHash: tx.Txid, - }) } - } - return inTxs + return &BTCInTxEvnet{ + FromAddress: fromAddress, + ToAddress: targetAddress, + Value: value, + MemoBytes: memo, + BlockNumber: blockNumber, + TxHash: tx.Txid, + }, nil + } + return nil, nil } func (ob *BitcoinChainClient) WatchUTXOS() { @@ -669,10 +722,10 @@ func (ob *BitcoinChainClient) FetchUTXOS() error { return utxos[i].Amount < utxos[j].Amount }) - ob.mu.Lock() + ob.Mu.Lock() ob.ts.SetNumberOfUTXOs(len(utxos)) ob.utxos = utxos - ob.mu.Unlock() + ob.Mu.Unlock() return nil } @@ -688,9 +741,9 @@ func (ob *BitcoinChainClient) refreshPendingNonce() { } // increase pending nonce if lagged behind - ob.mu.Lock() + ob.Mu.Lock() pendingNonce := ob.pendingNonce - ob.mu.Unlock() + ob.Mu.Unlock() // #nosec G701 always non-negative nonceLow := uint64(p.NonceLow) @@ -702,18 +755,17 @@ func (ob *BitcoinChainClient) refreshPendingNonce() { } // set 'NonceLow' as the new pending nonce - ob.mu.Lock() - defer ob.mu.Unlock() + ob.Mu.Lock() + defer ob.Mu.Unlock() ob.pendingNonce = nonceLow ob.logger.ChainLogger.Info().Msgf("refreshPendingNonce: increase pending nonce to %d with txid %s", ob.pendingNonce, txid) } } -// Set `test` flag to true in unit test to bypass query to zetacore func (ob *BitcoinChainClient) getOutTxidByNonce(nonce uint64, test bool) (string, error) { - ob.mu.Lock() + ob.Mu.Lock() res, included := ob.includedTxResults[ob.GetTxID(nonce)] - ob.mu.Unlock() + ob.Mu.Unlock() // There are 2 types of txids an observer can trust // 1. The ones had been verified and saved by observer self. @@ -772,16 +824,16 @@ func (ob *BitcoinChainClient) SelectUTXOs(amount float64, utxoCap uint8, nonce u idx := -1 if nonce == 0 { // for nonce = 0; make exception; no need to include nonce-mark utxo - ob.mu.Lock() - defer ob.mu.Unlock() + ob.Mu.Lock() + defer ob.Mu.Unlock() } else { // for nonce > 0; we proceed only when we see the nonce-mark utxo preTxid, err := ob.getOutTxidByNonce(nonce-1, test) if err != nil { return nil, 0, err } - ob.mu.Lock() - defer ob.mu.Unlock() + ob.Mu.Lock() + defer ob.Mu.Unlock() idx, err = ob.findNonceMarkUTXO(nonce-1, preTxid) if err != nil { return nil, 0, err @@ -826,9 +878,9 @@ func (ob *BitcoinChainClient) SelectUTXOs(amount float64, utxoCap uint8, nonce u // Save successfully broadcasted transaction func (ob *BitcoinChainClient) SaveBroadcastedTx(txHash string, nonce uint64) { outTxID := ob.GetTxID(nonce) - ob.mu.Lock() + ob.Mu.Lock() ob.broadcastedTx[outTxID] = txHash - ob.mu.Unlock() + ob.Mu.Unlock() broadcastEntry := clienttypes.ToOutTxHashSQLType(txHash, outTxID) if err := ob.db.Save(&broadcastEntry).Error; err != nil { @@ -906,8 +958,8 @@ func (ob *BitcoinChainClient) checkNSaveIncludedTx(txHash string, params types.O return false, errors.Wrapf(err, "checkNSaveIncludedTx: error verify bitcoin outTx %s outTxID %s", txHash, outTxID) } - ob.mu.Lock() - defer ob.mu.Unlock() + ob.Mu.Lock() + defer ob.Mu.Unlock() nonce, foundHash := ob.includedTxHashes[txHash] res, foundRes := ob.includedTxResults[outTxID] @@ -1205,9 +1257,3 @@ func (ob *BitcoinChainClient) GetBlockByNumberCached(blockNumber int64) (*BTCBlo ob.BlockCache.Add(hash, blockNheader) return blockNheader, nil } - -// A very special value to mark current nonce in UTXO -func NonceMarkAmount(nonce uint64) int64 { - // #nosec G701 always in range - return int64(nonce) + config.DustOffset // +2000 to avoid being a dust rejection -} diff --git a/zetaclient/btc_signer_test.go b/zetaclient/btc_signer_test.go index 631f110982..5f3eb9a250 100644 --- a/zetaclient/btc_signer_test.go +++ b/zetaclient/btc_signer_test.go @@ -213,7 +213,7 @@ func createTestClient(t *testing.T) *BitcoinChainClient { // Create BitcoinChainClient client := &BitcoinChainClient{ Tss: tss, - mu: &sync.Mutex{}, + Mu: &sync.Mutex{}, includedTxResults: make(map[string]btcjson.GetTransactionResult), } diff --git a/zetaclient/chainclient.go b/zetaclient/chainclient.go index 25f9e895cb..c92f29a77e 100644 --- a/zetaclient/chainclient.go +++ b/zetaclient/chainclient.go @@ -22,4 +22,5 @@ type ChainClient interface { GetPromGauge(name string) (prometheus.Gauge, error) GetPromCounter(name string) (prometheus.Counter, error) GetTxID(nonce uint64) string + ExternalChainWatcherForNewInboundTrackerSuggestions() } diff --git a/zetaclient/config/config_mainnet.go b/zetaclient/config/config_mainnet.go index 2a52abfc24..646b8b3460 100644 --- a/zetaclient/config/config_mainnet.go +++ b/zetaclient/config/config_mainnet.go @@ -9,7 +9,6 @@ import ( ) const ( - DustOffset = 0 BtcConfirmationCount = 1 DevEthConfirmationCount = 2 ) diff --git a/zetaclient/config/config_mock_mainnet.go b/zetaclient/config/config_mock_mainnet.go index 1f3f82970b..fe7195d1cd 100644 --- a/zetaclient/config/config_mock_mainnet.go +++ b/zetaclient/config/config_mock_mainnet.go @@ -9,7 +9,6 @@ import ( ) const ( - DustOffset = 2000 BtcConfirmationCount = 1 DevEthConfirmationCount = 2 ) diff --git a/zetaclient/config/config_privnet.go b/zetaclient/config/config_privnet.go index 7d8063310b..d801c8dbd7 100644 --- a/zetaclient/config/config_privnet.go +++ b/zetaclient/config/config_privnet.go @@ -9,7 +9,6 @@ import ( ) const ( - DustOffset = 2000 TssTestPrivkey = "2082bc9775d6ee5a05ef221a9d1c00b3cc3ecb274a4317acc0a182bc1e05d1bb" TssTestAddress = "0xE80B6467863EbF8865092544f441da8fD3cF6074" ) diff --git a/zetaclient/config/config_testnet.go b/zetaclient/config/config_testnet.go index b7524e22ca..5a3bf948e0 100644 --- a/zetaclient/config/config_testnet.go +++ b/zetaclient/config/config_testnet.go @@ -9,7 +9,6 @@ import ( ) const ( - DustOffset = 2000 TssTestPrivkey = "2082bc9775d6ee5a05ef221a9d1c00b3cc3ecb274a4317acc0a182bc1e05d1bb" TssTestAddress = "0xE80B6467863EbF8865092544f441da8fD3cF6074" //TestReceiver = "0x566bF3b1993FFd4BA134c107A63bb2aebAcCdbA0" diff --git a/zetaclient/evm_client.go b/zetaclient/evm_client.go index d828364f63..43ecf196e2 100644 --- a/zetaclient/evm_client.go +++ b/zetaclient/evm_client.go @@ -3,28 +3,24 @@ package zetaclient import ( "bytes" "context" - "encoding/base64" - "encoding/hex" "fmt" math2 "math" "math/big" "os" "sort" "strconv" - "strings" "sync" "sync/atomic" "time" - "cosmossdk.io/math" - "github.com/ethereum/go-ethereum/rlp" - lru "github.com/hashicorp/golang-lru" - "github.com/pkg/errors" "gorm.io/driver/sqlite" "gorm.io/gorm" "github.com/ethereum/go-ethereum/accounts/abi/bind" ethtypes "github.com/ethereum/go-ethereum/core/types" + "github.com/ethereum/go-ethereum/rlp" + lru "github.com/hashicorp/golang-lru" + "github.com/pkg/errors" erc20custody "github.com/zeta-chain/protocol-contracts/pkg/contracts/evm/erc20custody.sol" "github.com/zeta-chain/protocol-contracts/pkg/contracts/evm/zetaconnector.non-eth.sol" @@ -70,7 +66,7 @@ const ( type EVMChainClient struct { *ChainMetrics chain common.Chain - EvmClient *ethclient.Client + evmClient *ethclient.Client KlaytnClient *KlaytnClient zetaClient *ZetaCoreBridge Tss TSSSigner @@ -78,7 +74,7 @@ type EVMChainClient struct { lastBlock int64 BlockTimeExternalChain uint64 // block time in seconds txWatchList map[ethcommon.Hash]string - mu *sync.Mutex + Mu *sync.Mutex db *gorm.DB outTXConfirmedReceipts map[string]*ethtypes.Receipt outTXConfirmedTransaction map[string]*ethtypes.Transaction @@ -114,7 +110,7 @@ func NewEVMChainClient(bridge *ZetaCoreBridge, tss TSSSigner, dbpath string, met ob.params = evmCfg.CoreParams ob.stop = make(chan struct{}) ob.chain = evmCfg.Chain - ob.mu = &sync.Mutex{} + ob.Mu = &sync.Mutex{} ob.zetaClient = bridge ob.txWatchList = make(map[ethcommon.Hash]string) ob.Tss = tss @@ -135,7 +131,7 @@ func NewEVMChainClient(bridge *ZetaCoreBridge, tss TSSSigner, dbpath string, met ob.logger.ChainLogger.Error().Err(err).Msg("eth Client Dial") return nil, err } - ob.EvmClient = client + ob.evmClient = client ob.BlockCache, err = lru.New(1000) if err != nil { @@ -175,30 +171,77 @@ func NewEVMChainClient(bridge *ZetaCoreBridge, tss TSSSigner, dbpath string, met return &ob, nil } +func (ob *EVMChainClient) WithChain(chain common.Chain) { + ob.Mu.Lock() + defer ob.Mu.Unlock() + ob.chain = chain +} +func (ob *EVMChainClient) WithLogger(logger zerolog.Logger) { + ob.Mu.Lock() + defer ob.Mu.Unlock() + ob.logger = EVMLog{ + ChainLogger: logger, + ExternalChainWatcher: logger.With().Str("module", "ExternalChainWatcher").Logger(), + WatchGasPrice: logger.With().Str("module", "WatchGasPrice").Logger(), + ObserveOutTx: logger.With().Str("module", "ObserveOutTx").Logger(), + } +} + +func (ob *EVMChainClient) WithEvmClient(client *ethclient.Client) { + ob.Mu.Lock() + defer ob.Mu.Unlock() + ob.evmClient = client +} + +func (ob *EVMChainClient) WithZetaClient(bridge *ZetaCoreBridge) { + ob.Mu.Lock() + defer ob.Mu.Unlock() + ob.zetaClient = bridge +} + +func (ob *EVMChainClient) WithParams(params observertypes.CoreParams) { + ob.Mu.Lock() + defer ob.Mu.Unlock() + ob.params = params +} + +func (ob *EVMChainClient) SetConfig(cfg *config.Config) { + ob.Mu.Lock() + defer ob.Mu.Unlock() + ob.cfg = cfg +} func (ob *EVMChainClient) SetCoreParams(params observertypes.CoreParams) { - ob.mu.Lock() - defer ob.mu.Unlock() + ob.Mu.Lock() + defer ob.Mu.Unlock() ob.params = params } func (ob *EVMChainClient) GetCoreParams() observertypes.CoreParams { - ob.mu.Lock() - defer ob.mu.Unlock() + ob.Mu.Lock() + defer ob.Mu.Unlock() return ob.params } func (ob *EVMChainClient) GetConnectorContract() (*zetaconnector.ZetaConnectorNonEth, error) { addr := ethcommon.HexToAddress(ob.GetCoreParams().ConnectorContractAddress) - return zetaconnector.NewZetaConnectorNonEth(addr, ob.EvmClient) + return FetchConnectorContract(addr, ob.evmClient) } +func FetchConnectorContract(addr ethcommon.Address, client *ethclient.Client) (*zetaconnector.ZetaConnectorNonEth, error) { + return zetaconnector.NewZetaConnectorNonEth(addr, client) +} func (ob *EVMChainClient) GetERC20CustodyContract() (*erc20custody.ERC20Custody, error) { addr := ethcommon.HexToAddress(ob.GetCoreParams().Erc20CustodyContractAddress) - return erc20custody.NewERC20Custody(addr, ob.EvmClient) + return FetchERC20CustodyContract(addr, ob.evmClient) +} + +func FetchERC20CustodyContract(addr ethcommon.Address, client *ethclient.Client) (*erc20custody.ERC20Custody, error) { + return erc20custody.NewERC20Custody(addr, client) } func (ob *EVMChainClient) Start() { + go ob.ExternalChainWatcherForNewInboundTrackerSuggestions() go ob.ExternalChainWatcher() // Observes external Chains for incoming trasnactions go ob.WatchGasPrice() // Observes external Chains for Gas prices and posts to core go ob.observeOutTx() // Populates receipts and confirmed outbound transactions @@ -224,11 +267,11 @@ func (ob *EVMChainClient) Stop() { // returns: isIncluded, isConfirmed, Error // If isConfirmed, it also post to ZetaCore func (ob *EVMChainClient) IsSendOutTxProcessed(sendHash string, nonce uint64, cointype common.CoinType, logger zerolog.Logger) (bool, bool, error) { - ob.mu.Lock() + ob.Mu.Lock() params := ob.params receipt, found1 := ob.outTXConfirmedReceipts[ob.GetTxID(nonce)] transaction, found2 := ob.outTXConfirmedTransaction[ob.GetTxID(nonce)] - ob.mu.Unlock() + ob.Mu.Unlock() found := found1 && found2 if !found { return false, false, nil @@ -509,9 +552,9 @@ func (ob *EVMChainClient) observeOutTx() { ob.logger.ObserveOutTx.Warn().Msgf("observeOutTx timeout on chain %d nonce %d", ob.chain.ChainId, nonceInt) break TRACKERLOOP default: - ob.mu.Lock() + ob.Mu.Lock() _, found := ob.outTXConfirmedReceipts[ob.GetTxID(nonceInt)] - ob.mu.Unlock() + ob.Mu.Unlock() if found { continue } @@ -519,10 +562,10 @@ func (ob *EVMChainClient) observeOutTx() { receipt, transaction, err := ob.queryTxByHash(txHash.TxHash, nonceInt) time.Sleep(time.Duration(rpcRestTime) * time.Millisecond) if err == nil && receipt != nil { // confirmed - ob.mu.Lock() + ob.Mu.Lock() ob.outTXConfirmedReceipts[ob.GetTxID(nonceInt)] = receipt ob.outTXConfirmedTransaction[ob.GetTxID(nonceInt)] = transaction - ob.mu.Unlock() + ob.Mu.Unlock() break TXHASHLOOP } @@ -553,14 +596,14 @@ func (ob *EVMChainClient) queryTxByHash(txHash string, nonce uint64) (*ethtypes. ctxt, cancel := context.WithTimeout(context.Background(), 3*time.Second) defer cancel() - receipt, err := ob.EvmClient.TransactionReceipt(ctxt, ethcommon.HexToHash(txHash)) + receipt, err := ob.evmClient.TransactionReceipt(ctxt, ethcommon.HexToHash(txHash)) if err != nil { if err != ethereum.NotFound { logger.Warn().Err(err).Msg("TransactionReceipt/TransactionByHash error") } return nil, nil, err } - transaction, _, err := ob.EvmClient.TransactionByHash(ctxt, ethcommon.HexToHash(txHash)) + transaction, _, err := ob.evmClient.TransactionByHash(ctxt, ethcommon.HexToHash(txHash)) if err != nil { return nil, nil, err } @@ -648,7 +691,7 @@ func (ob *EVMChainClient) ExternalChainWatcher() { } func (ob *EVMChainClient) observeInTX() error { - header, err := ob.EvmClient.HeaderByNumber(context.Background(), nil) + header, err := ob.evmClient.HeaderByNumber(context.Background(), nil) if err != nil { return err } @@ -723,43 +766,16 @@ func (ob *EVMChainClient) observeInTX() error { } // Pull out arguments from logs for logs.Next() { - event := logs.Event - ob.logger.ExternalChainWatcher.Info().Msgf("TxBlockNumber %d Transaction Hash: %s Message : %s", event.Raw.BlockNumber, event.Raw.TxHash, event.Message) - destChain := common.GetChainFromChainID(event.DestinationChainId.Int64()) - if destChain == nil { - ob.logger.ExternalChainWatcher.Warn().Msgf("chain id not supported %d", event.DestinationChainId.Int64()) + msg, err := ob.GetInboundVoteMsgForZetaSentEvent(logs.Event) + if err != nil { + ob.logger.ExternalChainWatcher.Error().Err(err).Msg("error getting inbound vote msg") continue } - destAddr := clienttypes.BytesToEthHex(event.DestinationAddress) - if destChain.IsExternalChain() { - cfgDest, found := ob.cfg.GetEVMConfig(destChain.ChainId) - if !found { - ob.logger.ExternalChainWatcher.Warn().Msgf("chain id not present in EVMChainConfigs %d", event.DestinationChainId.Int64()) - continue - } - if strings.EqualFold(destAddr, cfgDest.ZetaTokenContractAddress) { - ob.logger.ExternalChainWatcher.Warn().Msgf("potential attack attempt: %s destination address is ZETA token contract address %s", destChain, destAddr) - continue - } - } - zetaHash, err := ob.zetaClient.PostSend( - event.ZetaTxSenderAddress.Hex(), - ob.chain.ChainId, - event.SourceTxOriginAddress.Hex(), - clienttypes.BytesToEthHex(event.DestinationAddress), - destChain.ChainId, - math.NewUintFromBigInt(event.ZetaValueAndGas), - base64.StdEncoding.EncodeToString(event.Message), - event.Raw.TxHash.Hex(), - event.Raw.BlockNumber, - event.DestinationGasLimit.Uint64(), - common.CoinType_Zeta, - PostSendNonEVMGasLimit, - "", - ) + + zetaHash, err := ob.zetaClient.PostSend(PostSendNonEVMGasLimit, &msg) if err != nil { ob.logger.ExternalChainWatcher.Error().Err(err).Msg("error posting to zeta core") - continue + return } ob.logger.ExternalChainWatcher.Info().Msgf("ZetaSent event detected and reported: PostSend zeta tx: %s", zetaHash) } @@ -794,45 +810,14 @@ func (ob *EVMChainClient) observeInTX() error { // Pull out arguments from logs for depositedLogs.Next() { - event := depositedLogs.Event - ob.logger.ExternalChainWatcher.Info().Msgf("TxBlockNumber %d Transaction Hash: %s Message : %s", event.Raw.BlockNumber, event.Raw.TxHash, event.Message) - // TODO :add logger to POSTSEND - if bytes.Compare(event.Message, []byte(DonationMessage)) == 0 { - ob.logger.ExternalChainWatcher.Info().Msgf("thank you rich folk for your donation!: %s", event.Raw.TxHash.Hex()) - continue - } - - // get the sender of the event's transaction - tx, _, err := ob.EvmClient.TransactionByHash(context.Background(), event.Raw.TxHash) - if err != nil { - ob.logger.ExternalChainWatcher.Error().Err(err).Msg(fmt.Sprintf("failed to get transaction by hash: %s", event.Raw.TxHash.Hex())) - continue - } - signer := ethtypes.NewLondonSigner(big.NewInt(ob.chain.ChainId)) - sender, err := signer.Sender(tx) + msg, err := ob.GetInboundVoteMsgForDepositedEvent(depositedLogs.Event) if err != nil { - ob.logger.ExternalChainWatcher.Error().Err(err).Msg(fmt.Sprintf("can't recover the sender from the tx hash: %s", event.Raw.TxHash.Hex())) continue } - - zetaHash, err := ob.zetaClient.PostSend( - sender.Hex(), - ob.chain.ChainId, - "", - clienttypes.BytesToEthHex(event.Recipient), - common.ZetaChain().ChainId, - math.NewUintFromBigInt(event.Amount), - hex.EncodeToString(event.Message), - event.Raw.TxHash.Hex(), - event.Raw.BlockNumber, - 1_500_000, - common.CoinType_ERC20, - PostSendEVMGasLimit, - event.Asset.String(), - ) + zetaHash, err := ob.zetaClient.PostSend(PostSendEVMGasLimit, &msg) if err != nil { ob.logger.ExternalChainWatcher.Error().Err(err).Msg("error posting to zeta core") - continue + return } ob.logger.ExternalChainWatcher.Info().Msgf("ZRC20Custody Deposited event detected and reported: PostSend zeta tx: %s", zetaHash) } @@ -881,17 +866,17 @@ func (ob *EVMChainClient) observeInTX() error { } if *tx.To() == tssAddress { - receipt, err := ob.EvmClient.TransactionReceipt(context.Background(), tx.Hash()) + receipt, err := ob.evmClient.TransactionReceipt(context.Background(), tx.Hash()) if err != nil { ob.logger.ExternalChainWatcher.Err(err).Msg("TransactionReceipt error") continue } if receipt.Status != 1 { // 1: successful, 0: failed - ob.logger.ExternalChainWatcher.Info().Msgf("tx %s failed; don't act", tx.Hash().Hex()) + ob.logger.ExternalChainWatcher.Info().Msgf("tx %s failed; don't act", tx.Hash()) continue } - from, err := ob.EvmClient.TransactionSender(context.Background(), tx, block.Hash(), receipt.TransactionIndex) + from, err := ob.evmClient.TransactionSender(context.Background(), tx, block.Hash(), receipt.TransactionIndex) if err != nil { ob.logger.ExternalChainWatcher.Err(err).Msg("TransactionSender error; trying local recovery (assuming LondonSigner dynamic fee tx type) of sender address") signer := ethtypes.NewLondonSigner(big.NewInt(ob.chain.ChainId)) @@ -901,8 +886,11 @@ func (ob *EVMChainClient) observeInTX() error { continue } } - - zetaHash, err := ob.ReportTokenSentToTSS(tx.Hash(), tx.Value(), receipt, from, tx.Data()) + msg := ob.GetInboundVoteMsgForTokenSentToTSS(tx.Hash(), tx.Value(), receipt, from, tx.Data()) + if msg == nil { + continue + } + zetaHash, err := ob.zetaClient.PostSend(PostSendEVMGasLimit, msg) if err != nil { ob.logger.ExternalChainWatcher.Error().Err(err).Msg("error posting to zeta core") continue @@ -924,7 +912,7 @@ func (ob *EVMChainClient) observeInTX() error { continue } if *tx.To == tssAddress { - receipt, err := ob.EvmClient.TransactionReceipt(context.Background(), tx.Hash) + receipt, err := ob.evmClient.TransactionReceipt(context.Background(), tx.Hash) if err != nil { ob.logger.ExternalChainWatcher.Err(err).Msg("TransactionReceipt error") continue @@ -936,8 +924,11 @@ func (ob *EVMChainClient) observeInTX() error { from := *tx.From value := tx.Value.ToInt() - - zetaHash, err := ob.ReportTokenSentToTSS(tx.Hash, value, receipt, from, tx.Input) + msg := ob.GetInboundVoteMsgForTokenSentToTSS(tx.Hash, value, receipt, from, tx.Input) + if msg == nil { + continue + } + zetaHash, err := ob.zetaClient.PostSend(PostSendEVMGasLimit, msg) if err != nil { ob.logger.ExternalChainWatcher.Error().Err(err).Msg("error posting to zeta core") continue @@ -956,32 +947,6 @@ func (ob *EVMChainClient) observeInTX() error { return nil } -func (ob *EVMChainClient) ReportTokenSentToTSS(txhash ethcommon.Hash, value *big.Int, receipt *ethtypes.Receipt, from ethcommon.Address, data []byte) (string, error) { - ob.logger.ExternalChainWatcher.Info().Msgf("TSS inTx detected: %s, blocknum %d", txhash.Hex(), receipt.BlockNumber) - ob.logger.ExternalChainWatcher.Info().Msgf("TSS inTx value: %s", value.String()) - ob.logger.ExternalChainWatcher.Info().Msgf("TSS inTx from: %s", from.Hex()) - message := "" - if len(data) != 0 { - message = hex.EncodeToString(data) - } - zetaHash, err := ob.zetaClient.PostSend( - from.Hex(), - ob.chain.ChainId, - from.Hex(), - from.Hex(), - common.ZetaChain().ChainId, - math.NewUintFromBigInt(value), - message, - txhash.Hex(), - receipt.BlockNumber.Uint64(), - 90_000, - common.CoinType_Gas, - PostSendEVMGasLimit, - "", - ) - return zetaHash, err -} - func (ob *EVMChainClient) WatchGasPrice() { err := ob.PostGasPrice() @@ -1017,12 +982,12 @@ func (ob *EVMChainClient) WatchGasPrice() { func (ob *EVMChainClient) PostGasPrice() error { // GAS PRICE - gasPrice, err := ob.EvmClient.SuggestGasPrice(context.TODO()) + gasPrice, err := ob.evmClient.SuggestGasPrice(context.TODO()) if err != nil { ob.logger.WatchGasPrice.Err(err).Msg("Err SuggestGasPrice:") return err } - blockNum, err := ob.EvmClient.BlockNumber(context.TODO()) + blockNum, err := ob.evmClient.BlockNumber(context.TODO()) if err != nil { ob.logger.WatchGasPrice.Err(err).Msg("Err Fetching Most recent Block : ") return err @@ -1061,7 +1026,7 @@ func (ob *EVMChainClient) BuildBlockIndex() error { if scanFromBlock != "" { logger.Info().Msgf("envvar %s is set; scan from block %s", envvar, scanFromBlock) if scanFromBlock == clienttypes.EnvVarLatest { - header, err := ob.EvmClient.HeaderByNumber(context.Background(), nil) + header, err := ob.evmClient.HeaderByNumber(context.Background(), nil) if err != nil { return err } @@ -1084,7 +1049,7 @@ func (ob *EVMChainClient) BuildBlockIndex() error { ob.SetLastBlockHeightScanned(lastheight) // if ZetaCore does not have last heard block height, then use current if ob.GetLastBlockHeightScanned() == 0 { - header, err := ob.EvmClient.HeaderByNumber(context.Background(), nil) + header, err := ob.evmClient.HeaderByNumber(context.Background(), nil) if err != nil { return err } @@ -1212,7 +1177,7 @@ func (ob *EVMChainClient) GetBlockByNumberCached(blockNumber int64) (*ethtypes.B if block, ok := ob.BlockCache.Get(blockNumber); ok { return block.(*ethtypes.Block), nil } - block, err := ob.EvmClient.BlockByNumber(context.Background(), big.NewInt(blockNumber)) + block, err := ob.evmClient.BlockByNumber(context.Background(), big.NewInt(blockNumber)) if err != nil { return nil, err } diff --git a/zetaclient/inbound_tracker.go b/zetaclient/inbound_tracker.go new file mode 100644 index 0000000000..8e6c7c01d2 --- /dev/null +++ b/zetaclient/inbound_tracker.go @@ -0,0 +1,260 @@ +package zetaclient + +import ( + "errors" + "fmt" + "math/big" + + "github.com/btcsuite/btcd/chaincfg/chainhash" + ethcommon "github.com/ethereum/go-ethereum/common" + ethtypes "github.com/ethereum/go-ethereum/core/types" + "github.com/zeta-chain/zetacore/common" + "github.com/zeta-chain/zetacore/x/crosschain/types" + "golang.org/x/net/context" +) + +// ExternalChainWatcherForNewInboundTrackerSuggestions At each tick, gets a list of Inbound tracker suggestions from zeta-core and tries to check if the in-tx was confirmed. +// If it was, it tries to broadcast the confirmation vote. If this zeta client has previously broadcast the vote, the tx would be rejected +func (ob *EVMChainClient) ExternalChainWatcherForNewInboundTrackerSuggestions() { + ticker := NewDynamicTicker(fmt.Sprintf("EVM_ExternalChainWatcher_InboundTrackerSuggestions_%d", ob.chain.ChainId), ob.GetCoreParams().InTxTicker) + defer ticker.Stop() + ob.logger.ExternalChainWatcher.Info().Msg("ExternalChainWatcher for inboundTrackerSuggestions started") + for { + select { + case <-ticker.C(): + err := ob.ObserveTrackerSuggestions() + if err != nil { + ob.logger.ExternalChainWatcher.Err(err).Msg("ObserveTrackerSuggestions error") + } + ticker.UpdateInterval(ob.GetCoreParams().InTxTicker, ob.logger.ExternalChainWatcher) + case <-ob.stop: + ob.logger.ExternalChainWatcher.Info().Msg("ExternalChainWatcher for inboundTrackerSuggestions stopped") + return + } + } +} + +func (ob *BitcoinChainClient) ExternalChainWatcherForNewInboundTrackerSuggestions() { + ticker := NewDynamicTicker("Bitcoin_WatchInTx_InboundTrackerSuggestions", ob.GetCoreParams().InTxTicker) + defer ticker.Stop() + for { + select { + case <-ticker.C(): + err := ob.ObserveTrackerSuggestions() + if err != nil { + ob.logger.WatchInTx.Error().Err(err).Msg("error observing in tx") + } + ticker.UpdateInterval(ob.GetCoreParams().InTxTicker, ob.logger.WatchInTx) + case <-ob.stop: + ob.logger.WatchInTx.Info().Msg("ExternalChainWatcher for BTC inboundTrackerSuggestions stopped") + return + } + } +} + +func (ob *BitcoinChainClient) ObserveTrackerSuggestions() error { + trackers, err := ob.zetaClient.GetInboundTrackersForChain(ob.chain.ChainId) + if err != nil { + return err + } + for _, tracker := range trackers { + ob.logger.WatchInTx.Info().Msgf("checking tracker with hash :%s and coin-type :%s ", tracker.TxHash, tracker.CoinType) + ballotIdentifier, err := ob.CheckReceiptForBtcTxHash(tracker.TxHash, true) + if err != nil { + return err + } + ob.logger.WatchInTx.Info().Msgf("Vote submitted for inbound Tracker,Chain : %s,Ballot Identifier : %s, coin-type %s", ob.chain.ChainName, ballotIdentifier, common.CoinType_Gas.String()) + } + return nil +} + +func (ob *BitcoinChainClient) CheckReceiptForBtcTxHash(txHash string, vote bool) (string, error) { + hash, err := chainhash.NewHashFromStr(txHash) + if err != nil { + return "", err + } + tx, err := ob.rpcClient.GetRawTransactionVerbose(hash) + if err != nil { + return "", err + } + blockHash, err := chainhash.NewHashFromStr(tx.BlockHash) + if err != nil { + return "", err + } + block, err := ob.rpcClient.GetBlockVerbose(blockHash) + if err != nil { + return "", err + } + tss, err := ob.zetaClient.GetBtcTssAddress() + if err != nil { + return "", err + } + // #nosec G701 always positive + event, err := GetBtcEvent(*tx, tss, uint64(block.Height), &ob.logger.WatchInTx) + if err != nil { + return "", err + } + if event == nil { + return "", errors.New("no btc deposit event found") + } + msg := ob.GetInboundVoteMessageFromBtcEvent(event) + if !vote { + return msg.Digest(), nil + } + zetaHash, err := ob.zetaClient.PostSend(PostSendEVMGasLimit, msg) + if err != nil { + ob.logger.WatchInTx.Error().Err(err).Msg("error posting to zeta core") + return "", err + } + ob.logger.WatchInTx.Info().Msgf("ZetaSent event detected and reported: PostSend zeta tx: %s", zetaHash) + return msg.Digest(), nil +} + +func (ob *EVMChainClient) ObserveTrackerSuggestions() error { + trackers, err := ob.zetaClient.GetInboundTrackersForChain(ob.chain.ChainId) + if err != nil { + return err + } + for _, tracker := range trackers { + ob.logger.ExternalChainWatcher.Info().Msgf("checking tracker with hash :%s and coin-type :%s ", tracker.TxHash, tracker.CoinType) + switch tracker.CoinType { + case common.CoinType_Zeta: + ballotIdentifier, err := ob.CheckReceiptForCoinTypeZeta(tracker.TxHash, true) + if err != nil { + return err + } + ob.logger.ExternalChainWatcher.Info().Msgf("Vote submitted for inbound Tracker,Chain : %s,Ballot Identifier : %s, coin-type %s", ob.chain.ChainName, ballotIdentifier, common.CoinType_Zeta.String()) + case common.CoinType_ERC20: + ballotIdentifier, err := ob.CheckReceiptForCoinTypeERC20(tracker.TxHash, true) + if err != nil { + return err + } + ob.logger.ExternalChainWatcher.Info().Msgf("Vote submitted for inbound Tracker,Chain : %s,Ballot Identifier : %s, coin-type %s", ob.chain.ChainName, ballotIdentifier, common.CoinType_ERC20.String()) + case common.CoinType_Gas: + ballotIdentifier, err := ob.CheckReceiptForCoinTypeGas(tracker.TxHash, true) + if err != nil { + return err + } + ob.logger.ExternalChainWatcher.Info().Msgf("Vote submitted for inbound Tracker,Chain : %s,Ballot Identifier : %s, coin-type %s", ob.chain.ChainName, ballotIdentifier, common.CoinType_Gas.String()) + } + } + return nil +} + +func (ob *EVMChainClient) CheckReceiptForCoinTypeZeta(txHash string, vote bool) (string, error) { + connector, err := ob.GetConnectorContract() + if err != nil { + return "", err + } + hash := ethcommon.HexToHash(txHash) + receipt, err := ob.evmClient.TransactionReceipt(context.Background(), hash) + if err != nil { + return "", err + } + + var msg types.MsgVoteOnObservedInboundTx + for _, log := range receipt.Logs { + event, err := connector.ParseZetaSent(*log) + if err == nil && event != nil { + msg, err = ob.GetInboundVoteMsgForZetaSentEvent(event) + if err == nil { + break + } + } + } + if !vote { + return msg.Digest(), nil + } + + zetaHash, err := ob.zetaClient.PostSend(PostSendNonEVMGasLimit, &msg) + if err != nil { + ob.logger.ExternalChainWatcher.Error().Err(err).Msg("error posting to zeta core") + return "", err + } + ob.logger.ExternalChainWatcher.Info().Msgf("ZetaSent event detected and reported: PostSend zeta tx: %s", zetaHash) + + return msg.Digest(), nil +} + +func (ob *EVMChainClient) CheckReceiptForCoinTypeERC20(txHash string, vote bool) (string, error) { + custody, err := ob.GetERC20CustodyContract() + if err != nil { + return "", err + } + hash := ethcommon.HexToHash(txHash) + receipt, err := ob.evmClient.TransactionReceipt(context.Background(), hash) + if err != nil { + return "", err + } + var msg types.MsgVoteOnObservedInboundTx + for _, log := range receipt.Logs { + zetaDeposited, err := custody.ParseDeposited(*log) + if err == nil && zetaDeposited != nil { + msg, err = ob.GetInboundVoteMsgForDepositedEvent(zetaDeposited) + if err == nil { + break + } + } + } + if !vote { + return msg.Digest(), nil + } + + zetaHash, err := ob.zetaClient.PostSend(PostSendEVMGasLimit, &msg) + if err != nil { + ob.logger.ExternalChainWatcher.Error().Err(err).Msg("error posting to zeta core") + return "", err + } + ob.logger.ExternalChainWatcher.Info().Msgf("ZetaSent event detected and reported: PostSend zeta tx: %s", zetaHash) + + return msg.Digest(), nil +} + +func (ob *EVMChainClient) CheckReceiptForCoinTypeGas(txHash string, vote bool) (string, error) { + hash := ethcommon.HexToHash(txHash) + tx, isPending, err := ob.evmClient.TransactionByHash(context.Background(), hash) + if err != nil { + return "", err + } + if isPending { + return "", errors.New("tx is still pending") + } + + receipt, err := ob.evmClient.TransactionReceipt(context.Background(), hash) + if err != nil { + ob.logger.ExternalChainWatcher.Err(err).Msg("TransactionReceipt error") + return "", err + } + if receipt.Status != 1 { // 1: successful, 0: failed + ob.logger.ExternalChainWatcher.Info().Msgf("tx %s failed; don't act", tx.Hash().Hex()) + return "", errors.New("tx not successful yet") + } + block, err := ob.evmClient.BlockByNumber(context.Background(), receipt.BlockNumber) + if err != nil { + ob.logger.ExternalChainWatcher.Err(err).Msg("BlockByNumber error") + return "", err + } + from, err := ob.evmClient.TransactionSender(context.Background(), tx, block.Hash(), receipt.TransactionIndex) + if err != nil { + ob.logger.ExternalChainWatcher.Err(err).Msg("TransactionSender error; trying local recovery (assuming LondonSigner dynamic fee tx type) of sender address") + signer := ethtypes.NewLondonSigner(big.NewInt(ob.chain.ChainId)) + from, err = signer.Sender(tx) + if err != nil { + ob.logger.ExternalChainWatcher.Err(err).Msg("local recovery of sender address failed") + return "", err + } + } + msg := ob.GetInboundVoteMsgForTokenSentToTSS(tx.Hash(), tx.Value(), receipt, from, tx.Data()) + if !vote { + return msg.Digest(), nil + } + + zetaHash, err := ob.zetaClient.PostSend(PostSendEVMGasLimit, msg) + if err != nil { + ob.logger.ExternalChainWatcher.Error().Err(err).Msg("error posting to zeta core") + return "", err + } + ob.logger.ExternalChainWatcher.Info().Msgf("Gas Deposit detected and reported: PostSend zeta tx: %s", zetaHash) + + return msg.Digest(), nil +} diff --git a/zetaclient/keys.go b/zetaclient/keys.go index 5519e0b884..af45452275 100644 --- a/zetaclient/keys.go +++ b/zetaclient/keys.go @@ -24,7 +24,7 @@ type Keys struct { signerName string password string // TODO this is a bad way , need to fix it kb ckeys.Keyring - operatorAddress sdk.AccAddress + OperatorAddress sdk.AccAddress } // NewKeysWithKeybase create a new instance of Keys @@ -33,7 +33,7 @@ func NewKeysWithKeybase(kb ckeys.Keyring, granterAddress sdk.AccAddress, grantee signerName: granteeName, password: password, kb: kb, - operatorAddress: granterAddress, + OperatorAddress: granterAddress, } } @@ -106,7 +106,7 @@ func (k *Keys) GetSignerInfo() *ckeys.Record { } func (k *Keys) GetOperatorAddress() sdk.AccAddress { - return k.operatorAddress + return k.OperatorAddress } func (k *Keys) GetAddress() sdk.AccAddress { diff --git a/zetaclient/query.go b/zetaclient/query.go index 909e2bdc56..d84d335e0c 100644 --- a/zetaclient/query.go +++ b/zetaclient/query.go @@ -230,6 +230,24 @@ func (b *ZetaCoreBridge) GetKeyGen() (*zetaObserverTypes.Keygen, error) { } +func (b *ZetaCoreBridge) GetBallot(ballotIdentifier string) (*zetaObserverTypes.QueryBallotByIdentifierResponse, error) { + client := zetaObserverTypes.NewQueryClient(b.grpcConn) + resp, err := client.BallotByIdentifier(context.Background(), &zetaObserverTypes.QueryBallotByIdentifierRequest{BallotIdentifier: ballotIdentifier}) + if err != nil { + return nil, err + } + return resp, nil +} + +func (b *ZetaCoreBridge) GetInboundTrackersForChain(chainID int64) ([]types.InTxTracker, error) { + client := types.NewQueryClient(b.grpcConn) + resp, err := client.InTxTrackerAllByChain(context.Background(), &types.QueryAllInTxTrackerByChainRequest{ChainId: chainID}) + if err != nil { + return nil, err + } + return resp.InTxTracker, nil +} + func (b *ZetaCoreBridge) GetCurrentTss() (*types.TSS, error) { client := types.NewQueryClient(b.grpcConn) resp, err := client.TSS(context.Background(), &types.QueryGetTSSRequest{}) @@ -239,6 +257,24 @@ func (b *ZetaCoreBridge) GetCurrentTss() (*types.TSS, error) { return resp.TSS, nil } +func (b *ZetaCoreBridge) GetEthTssAddress() (string, error) { + client := types.NewQueryClient(b.grpcConn) + resp, err := client.GetTssAddress(context.Background(), &types.QueryGetTssAddressRequest{}) + if err != nil { + return "", err + } + return resp.Eth, nil +} + +func (b *ZetaCoreBridge) GetBtcTssAddress() (string, error) { + client := types.NewQueryClient(b.grpcConn) + resp, err := client.GetTssAddress(context.Background(), &types.QueryGetTssAddressRequest{}) + if err != nil { + return "", err + } + return resp.Btc, nil +} + func (b *ZetaCoreBridge) GetTssHistory() ([]types.TSS, error) { client := types.NewQueryClient(b.grpcConn) resp, err := client.TssHistory(context.Background(), &types.QueryTssHistoryRequest{}) diff --git a/zetaclient/tx.go b/zetaclient/tx.go index 85505d5623..872062b6ce 100644 --- a/zetaclient/tx.go +++ b/zetaclient/tx.go @@ -31,6 +31,11 @@ const ( DefaultRetryInterval = 5 ) +func GetInBoundVoteMessage(sender string, senderChain int64, txOrigin string, receiver string, receiverChain int64, amount math.Uint, message string, inTxHash string, inBlockHeight uint64, gasLimit uint64, coinType common.CoinType, asset string, signerAddress string) *types.MsgVoteOnObservedInboundTx { + msg := types.NewMsgVoteOnObservedInboundTx(signerAddress, sender, senderChain, txOrigin, receiver, receiverChain, amount, message, inTxHash, inBlockHeight, gasLimit, coinType, asset) + return msg +} + func (b *ZetaCoreBridge) WrapMessageWithAuthz(msg sdk.Msg) (sdk.Msg, AuthZSigner) { msgURL := sdk.MsgTypeURL(msg) authzSigner := GetSigner(msgURL) @@ -66,11 +71,8 @@ func (b *ZetaCoreBridge) AddTxHashToOutTxTracker(chainID int64, nonce uint64, tx return zetaTxHash, nil } -func (b *ZetaCoreBridge) PostSend(sender string, senderChain int64, txOrigin string, receiver string, receiverChain int64, amount math.Uint, message string, inTxHash string, inBlockHeight uint64, gasLimit uint64, coinType common.CoinType, zetaGasLimit uint64, asset string) (string, error) { - signerAddress := b.keys.GetOperatorAddress().String() - msg := types.NewMsgVoteOnObservedInboundTx(signerAddress, sender, senderChain, txOrigin, receiver, receiverChain, amount, message, inTxHash, inBlockHeight, gasLimit, coinType, asset) +func (b *ZetaCoreBridge) PostSend(zetaGasLimit uint64, msg *types.MsgVoteOnObservedInboundTx) (string, error) { authzMsg, authzSigner := b.WrapMessageWithAuthz(msg) - for i := 0; i < DefaultRetryCount; i++ { zetaTxHash, err := b.Broadcast(zetaGasLimit, authzMsg, authzSigner) if err == nil { @@ -79,7 +81,6 @@ func (b *ZetaCoreBridge) PostSend(sender string, senderChain int64, txOrigin str b.logger.Debug().Err(err).Msgf("PostSend broadcast fail | Retry count : %d", i+1) time.Sleep(DefaultRetryInterval * time.Second) } - return "", fmt.Errorf("post send failed after %d retries", DefaultRetryInterval) } diff --git a/zetaclient/utils.go b/zetaclient/utils.go index 56ba3000d9..1983396152 100644 --- a/zetaclient/utils.go +++ b/zetaclient/utils.go @@ -1,12 +1,27 @@ package zetaclient import ( - "errors" + "bytes" + "context" + "encoding/base64" + "encoding/hex" + "fmt" "math" + "math/big" + "strings" "time" + sdkmath "cosmossdk.io/math" "github.com/btcsuite/btcd/txscript" + ethcommon "github.com/ethereum/go-ethereum/common" + ethtypes "github.com/ethereum/go-ethereum/core/types" + "github.com/pkg/errors" "github.com/rs/zerolog" + "github.com/zeta-chain/protocol-contracts/pkg/contracts/evm/erc20custody.sol" + "github.com/zeta-chain/protocol-contracts/pkg/contracts/evm/zetaconnector.non-eth.sol" + "github.com/zeta-chain/zetacore/common" + "github.com/zeta-chain/zetacore/x/crosschain/types" + clienttypes "github.com/zeta-chain/zetacore/zetaclient/types" ) const ( @@ -76,3 +91,99 @@ func (t *DynamicTicker) UpdateInterval(newInterval uint64, logger zerolog.Logger func (t *DynamicTicker) Stop() { t.impl.Stop() } + +func (ob *EVMChainClient) GetInboundVoteMsgForDepositedEvent(event *erc20custody.ERC20CustodyDeposited) (types.MsgVoteOnObservedInboundTx, error) { + ob.logger.ExternalChainWatcher.Info().Msgf("TxBlockNumber %d Transaction Hash: %s Message : %s", event.Raw.BlockNumber, event.Raw.TxHash, event.Message) + if bytes.Compare(event.Message, []byte(DonationMessage)) == 0 { + ob.logger.ExternalChainWatcher.Info().Msgf("thank you rich folk for your donation!: %s", event.Raw.TxHash.Hex()) + return types.MsgVoteOnObservedInboundTx{}, fmt.Errorf("thank you rich folk for your donation!: %s", event.Raw.TxHash.Hex()) + } + // get the sender of the event's transaction + tx, _, err := ob.evmClient.TransactionByHash(context.Background(), event.Raw.TxHash) + if err != nil { + ob.logger.ExternalChainWatcher.Error().Err(err).Msg(fmt.Sprintf("failed to get transaction by hash: %s", event.Raw.TxHash.Hex())) + return types.MsgVoteOnObservedInboundTx{}, errors.Wrap(err, fmt.Sprintf("failed to get transaction by hash: %s", event.Raw.TxHash.Hex())) + } + signer := ethtypes.NewLondonSigner(big.NewInt(ob.chain.ChainId)) + sender, err := signer.Sender(tx) + if err != nil { + ob.logger.ExternalChainWatcher.Error().Err(err).Msg(fmt.Sprintf("can't recover the sender from the tx hash: %s", event.Raw.TxHash.Hex())) + return types.MsgVoteOnObservedInboundTx{}, errors.Wrap(err, fmt.Sprintf("can't recover the sender from the tx hash: %s", event.Raw.TxHash.Hex())) + + } + return *GetInBoundVoteMessage( + sender.Hex(), + ob.chain.ChainId, + "", + clienttypes.BytesToEthHex(event.Recipient), + common.ZetaChain().ChainId, + sdkmath.NewUintFromBigInt(event.Amount), + hex.EncodeToString(event.Message), + event.Raw.TxHash.Hex(), + event.Raw.BlockNumber, + 1_500_000, + common.CoinType_ERC20, + event.Asset.String(), + ob.zetaClient.keys.GetOperatorAddress().String(), + ), nil +} + +func (ob *EVMChainClient) GetInboundVoteMsgForZetaSentEvent(event *zetaconnector.ZetaConnectorNonEthZetaSent) (types.MsgVoteOnObservedInboundTx, error) { + ob.logger.ExternalChainWatcher.Info().Msgf("TxBlockNumber %d Transaction Hash: %s Message : %s", event.Raw.BlockNumber, event.Raw.TxHash, event.Message) + destChain := common.GetChainFromChainID(event.DestinationChainId.Int64()) + if destChain == nil { + ob.logger.ExternalChainWatcher.Warn().Msgf("chain id not supported %d", event.DestinationChainId.Int64()) + return types.MsgVoteOnObservedInboundTx{}, fmt.Errorf("chain id not supported %d", event.DestinationChainId.Int64()) + } + destAddr := clienttypes.BytesToEthHex(event.DestinationAddress) + if *destChain != common.ZetaChain() { + cfgDest, found := ob.cfg.GetEVMConfig(destChain.ChainId) + if !found { + return types.MsgVoteOnObservedInboundTx{}, fmt.Errorf("chain id not present in EVMChainConfigs %d", event.DestinationChainId.Int64()) + } + if strings.EqualFold(destAddr, cfgDest.ZetaTokenContractAddress) { + ob.logger.ExternalChainWatcher.Warn().Msgf("potential attack attempt: %s destination address is ZETA token contract address %s", destChain, destAddr) + return types.MsgVoteOnObservedInboundTx{}, fmt.Errorf("potential attack attempt: %s destination address is ZETA token contract address %s", destChain, destAddr) + } + } + return *GetInBoundVoteMessage( + event.ZetaTxSenderAddress.Hex(), + ob.chain.ChainId, + event.SourceTxOriginAddress.Hex(), + clienttypes.BytesToEthHex(event.DestinationAddress), + destChain.ChainId, + sdkmath.NewUintFromBigInt(event.ZetaValueAndGas), + base64.StdEncoding.EncodeToString(event.Message), + event.Raw.TxHash.Hex(), + event.Raw.BlockNumber, + event.DestinationGasLimit.Uint64(), + common.CoinType_Zeta, + "", + ob.zetaClient.keys.GetOperatorAddress().String(), + ), nil +} + +func (ob *EVMChainClient) GetInboundVoteMsgForTokenSentToTSS(txhash ethcommon.Hash, value *big.Int, receipt *ethtypes.Receipt, from ethcommon.Address, data []byte) *types.MsgVoteOnObservedInboundTx { + ob.logger.ExternalChainWatcher.Info().Msgf("TSS inTx detected: %s, blocknum %d", txhash.Hex(), receipt.BlockNumber) + ob.logger.ExternalChainWatcher.Info().Msgf("TSS inTx value: %s", value.String()) + ob.logger.ExternalChainWatcher.Info().Msgf("TSS inTx from: %s", from.Hex()) + message := "" + if len(data) != 0 { + message = hex.EncodeToString(data) + } + return GetInBoundVoteMessage( + from.Hex(), + ob.chain.ChainId, + from.Hex(), + from.Hex(), + common.ZetaChain().ChainId, + sdkmath.NewUintFromBigInt(value), + message, + txhash.Hex(), + receipt.BlockNumber.Uint64(), + 90_000, + common.CoinType_Gas, + "", + ob.zetaClient.keys.GetOperatorAddress().String(), + ) +}