From a37c467a0492a049dd15980ae7ef1729ff2f33cf Mon Sep 17 00:00:00 2001 From: Reece Williams Date: Wed, 23 Aug 2023 18:28:18 -0500 Subject: [PATCH 01/79] comments --- app/ante.go | 26 ++++++++++++++++++++++++-- app/app.go | 2 +- 2 files changed, 25 insertions(+), 3 deletions(-) diff --git a/app/ante.go b/app/ante.go index b3d3e0289..0059eff85 100644 --- a/app/ante.go +++ b/app/ante.go @@ -24,6 +24,7 @@ import ( feesharekeeper "github.com/CosmosContracts/juno/v17/x/feeshare/keeper" globalfeeante "github.com/CosmosContracts/juno/v17/x/globalfee/ante" globalfeekeeper "github.com/CosmosContracts/juno/v17/x/globalfee/keeper" + bankkeeper "github.com/cosmos/cosmos-sdk/x/bank/keeper" ) // Lower back to 1 mil after https://github.com/cosmos/relayer/issues/1255 @@ -37,7 +38,7 @@ type HandlerOptions struct { GovKeeper govkeeper.Keeper IBCKeeper *ibckeeper.Keeper FeeShareKeeper feesharekeeper.Keeper - BankKeeperFork feeshareante.BankKeeper + BankKeeper bankkeeper.Keeper TxCounterStoreKey storetypes.StoreKey WasmConfig wasmtypes.WasmConfig Cdc codec.BinaryCodec @@ -73,8 +74,29 @@ func NewAnteHandler(options HandlerOptions) (sdk.AnteHandler, error) { sigGasConsumer = ante.DefaultSigVerificationGasConsumer } + // inactive account (brand new, no tokens) + // mint tokens (with x/Bank) to the account and set the fee to be valid (for FREE for the user, cost to the chain in the POC) - modify Tx for the fees ONLY + + // tx.GetGas() * minGasprice = the amount of fee to mint them from x/bank + // update the Tx Fee Amount of be the amount of fee we minted them from x/bank OR just give them the funds and use that directly or something + + // get account + // p := k.GetParams(ctx) + // var minGasprice sdk.DecCoins + // for _, c := range p.MinimumGasPrices { + // if c.Denom == "ujuno" { + // // get that amount + // amt := c.Amount + // } + // } + // + // junod tx tokenfactory create-denom joel --gas=2200000 --from carbonator + anteDecorators := []sdk.AnteDecorator{ + // check if account exists, if not, mint it tokens and use that as the fee. Then create the account (may be a future ante handler since it has fees now) + // GLobalFee query params for minimum fee ante.NewSetUpContextDecorator(), // outermost AnteDecorator. SetUpContext must be called first + // ADD DECORATOR HERE wasmkeeper.NewLimitSimulationGasDecorator(options.WasmConfig.SimulationGasLimit), wasmkeeper.NewCountTXDecorator(options.TxCounterStoreKey), ante.NewExtensionOptionsDecorator(options.ExtensionOptionChecker), @@ -85,7 +107,7 @@ func NewAnteHandler(options HandlerOptions) (sdk.AnteHandler, error) { ante.NewConsumeGasForTxSizeDecorator(options.AccountKeeper), globalfeeante.NewFeeDecorator(options.BypassMinFeeMsgTypes, options.GlobalFeeKeeper, options.StakingKeeper, maxBypassMinFeeMsgGasUsage), ante.NewDeductFeeDecorator(options.AccountKeeper, options.BankKeeper, options.FeegrantKeeper, options.TxFeeChecker), - feeshareante.NewFeeSharePayoutDecorator(options.BankKeeperFork, options.FeeShareKeeper), + feeshareante.NewFeeSharePayoutDecorator(options.BankKeeper, options.FeeShareKeeper), // SetPubKeyDecorator must be called before all signature verification decorators ante.NewSetPubKeyDecorator(options.AccountKeeper), ante.NewValidateSigCountDecorator(options.AccountKeeper), diff --git a/app/app.go b/app/app.go index fc664bdcf..5c5f57742 100644 --- a/app/app.go +++ b/app/app.go @@ -353,7 +353,7 @@ func New( GovKeeper: app.AppKeepers.GovKeeper, IBCKeeper: app.AppKeepers.IBCKeeper, FeeShareKeeper: app.AppKeepers.FeeShareKeeper, - BankKeeperFork: app.AppKeepers.BankKeeper, // since we need extra methods + BankKeeper: app.AppKeepers.BankKeeper, TxCounterStoreKey: app.AppKeepers.GetKey(wasmtypes.StoreKey), WasmConfig: wasmConfig, Cdc: appCodec, From 11a04496e14864f583e34bf4fa0dc692fa4bb639 Mon Sep 17 00:00:00 2001 From: Reece Williams Date: Wed, 23 Aug 2023 18:31:24 -0500 Subject: [PATCH 02/79] decorator --- app/ante.go | 3 ++- app/decorators/feeprepay_poc.go | 32 ++++++++++++++++++++++++++++++++ 2 files changed, 34 insertions(+), 1 deletion(-) create mode 100644 app/decorators/feeprepay_poc.go diff --git a/app/ante.go b/app/ante.go index 0059eff85..1ebb26c04 100644 --- a/app/ante.go +++ b/app/ante.go @@ -96,7 +96,8 @@ func NewAnteHandler(options HandlerOptions) (sdk.AnteHandler, error) { // check if account exists, if not, mint it tokens and use that as the fee. Then create the account (may be a future ante handler since it has fees now) // GLobalFee query params for minimum fee ante.NewSetUpContextDecorator(), // outermost AnteDecorator. SetUpContext must be called first - // ADD DECORATOR HERE + // TODO: joel + decorators.NewMsgFeePrepayDecorator(), wasmkeeper.NewLimitSimulationGasDecorator(options.WasmConfig.SimulationGasLimit), wasmkeeper.NewCountTXDecorator(options.TxCounterStoreKey), ante.NewExtensionOptionsDecorator(options.ExtensionOptionChecker), diff --git a/app/decorators/feeprepay_poc.go b/app/decorators/feeprepay_poc.go new file mode 100644 index 000000000..206d477de --- /dev/null +++ b/app/decorators/feeprepay_poc.go @@ -0,0 +1,32 @@ +package decorators + +import ( + "fmt" + + sdk "github.com/cosmos/cosmos-sdk/types" +) + +type MsgFeePrepayDecorator struct{} + +func NewMsgFeePrepayDecorator() MsgFeePrepayDecorator { + return MsgFeePrepayDecorator{} +} + +func (mfd MsgFeePrepayDecorator) AnteHandle(ctx sdk.Context, tx sdk.Tx, simulate bool, next sdk.AnteHandler) (newCtx sdk.Context, err error) { + if hasInvalidMsgs(tx.GetMsgs()) { + currHeight := ctx.BlockHeight() + return ctx, fmt.Errorf("tx contains unsupported message types at height %d", currHeight) + } + + return next(ctx, tx, simulate) +} + +// func hasInvalidMsgs(msgs []sdk.Msg) bool { +// for _, msg := range msgs { +// if _, ok := msg.(*ibcchanneltypes.MsgTimeoutOnClose); ok { +// return true +// } +// } + +// return false +// } From 6f27f2d7b30d66463ae226152311f89e5145bea1 Mon Sep 17 00:00:00 2001 From: Joel Smith Date: Wed, 23 Aug 2023 19:02:55 -0500 Subject: [PATCH 03/79] Base POC setup --- app/ante.go | 15 +++------ app/decorators/feeprepay_poc.go | 56 ++++++++++++++++++++++++++------- 2 files changed, 49 insertions(+), 22 deletions(-) diff --git a/app/ante.go b/app/ante.go index 1ebb26c04..fc87c45c4 100644 --- a/app/ante.go +++ b/app/ante.go @@ -43,6 +43,8 @@ type HandlerOptions struct { WasmConfig wasmtypes.WasmConfig Cdc codec.BinaryCodec + // TODO: may need the FeeGrantKeeper here as well if you go down that road + BypassMinFeeMsgTypes []string GlobalFeeKeeper globalfeekeeper.Keeper @@ -81,23 +83,16 @@ func NewAnteHandler(options HandlerOptions) (sdk.AnteHandler, error) { // update the Tx Fee Amount of be the amount of fee we minted them from x/bank OR just give them the funds and use that directly or something // get account - // p := k.GetParams(ctx) - // var minGasprice sdk.DecCoins - // for _, c := range p.MinimumGasPrices { - // if c.Denom == "ujuno" { - // // get that amount - // amt := c.Amount - // } - // } - // + // junod q bank balances // junod tx tokenfactory create-denom joel --gas=2200000 --from carbonator + // junod q tokenfactory denoms-from-creator $(junod keys show carbonator -a) anteDecorators := []sdk.AnteDecorator{ // check if account exists, if not, mint it tokens and use that as the fee. Then create the account (may be a future ante handler since it has fees now) // GLobalFee query params for minimum fee ante.NewSetUpContextDecorator(), // outermost AnteDecorator. SetUpContext must be called first // TODO: joel - decorators.NewMsgFeePrepayDecorator(), + decorators.NewMsgFeePrepayDecorator(options.BankKeeper, options.AccountKeeper, options.GlobalFeeKeeper), wasmkeeper.NewLimitSimulationGasDecorator(options.WasmConfig.SimulationGasLimit), wasmkeeper.NewCountTXDecorator(options.TxCounterStoreKey), ante.NewExtensionOptionsDecorator(options.ExtensionOptionChecker), diff --git a/app/decorators/feeprepay_poc.go b/app/decorators/feeprepay_poc.go index 206d477de..2928c11f9 100644 --- a/app/decorators/feeprepay_poc.go +++ b/app/decorators/feeprepay_poc.go @@ -1,29 +1,61 @@ package decorators import ( - "fmt" - + globalfeekeeper "github.com/CosmosContracts/juno/v17/x/globalfee/keeper" sdk "github.com/cosmos/cosmos-sdk/types" + authante "github.com/cosmos/cosmos-sdk/x/auth/ante" + bankkeeper "github.com/cosmos/cosmos-sdk/x/bank/keeper" ) -type MsgFeePrepayDecorator struct{} - -func NewMsgFeePrepayDecorator() MsgFeePrepayDecorator { - return MsgFeePrepayDecorator{} +type MsgFeePrepayDecorator struct { + BankKeeper bankkeeper.Keeper + // TODO: This could be incorrect. We may need the full AuthKeeper/AccountKeeper, not just from the ante + AccountKeeper authante.AccountKeeper + GlobalFeeKeeper globalfeekeeper.Keeper } -func (mfd MsgFeePrepayDecorator) AnteHandle(ctx sdk.Context, tx sdk.Tx, simulate bool, next sdk.AnteHandler) (newCtx sdk.Context, err error) { - if hasInvalidMsgs(tx.GetMsgs()) { - currHeight := ctx.BlockHeight() - return ctx, fmt.Errorf("tx contains unsupported message types at height %d", currHeight) +func NewMsgFeePrepayDecorator(bank bankkeeper.Keeper, auth authante.AccountKeeper, globalFee globalfeekeeper.Keeper) MsgFeePrepayDecorator { + return MsgFeePrepayDecorator{ + BankKeeper: bank, + AccountKeeper: auth, + GlobalFeeKeeper: globalFee, } +} + +func (fpd MsgFeePrepayDecorator) AnteHandle(ctx sdk.Context, tx sdk.Tx, simulate bool, next sdk.AnteHandler) (newCtx sdk.Context, err error) { + // if tx is read only + // tx := new sdk.Tx(...tx, set the new fee) + + // This may not be a FeeTx, so if error then don't exit early + // feeTx, ok := tx.(sdk.FeeTx) + // if !ok { + // return ctx, errorsmod.Wrap(sdkerrors.ErrTxDecode, "Tx must implement the sdk.FeeTx interface") + // } + + // get gas + + // p := fpd.GlobalFeeKeeper.GetParams(ctx) + // var minGasprice sdk.DecCoins + // for _, c := range p.MinimumGasPrices { + // if c.Denom == "ujuno" { + // // get that amount + // amt := c.Amount + // } + // } + + // TODOL: Thuis could give you funds and then make your next Tx successful. + // fpd.BankKeeper.MintCoins(ctx, "bank", coinsAmt) + // fpd.BankKeeper.SendCoinsFromModuleToAccount(ctx, "bank", "userAccount", coinsAmt) + // auto feeprepay with the TxFee or somethuing here? as an option + // set the Tx fee to be correct, set the accoiunt to be new and work, and then continue on return next(ctx, tx, simulate) } -// func hasInvalidMsgs(msgs []sdk.Msg) bool { +// TODO: Future: execute contract only. +// func hasInvalidExecuteMsgs(msgs []sdk.Msg) bool { // for _, msg := range msgs { -// if _, ok := msg.(*ibcchanneltypes.MsgTimeoutOnClose); ok { +// if _, ok := msg.(*wasmtypes.msgExecuteContract); ok { // return true // } // } From 34157f3e2143c8138ff08169aed819d4caf23459 Mon Sep 17 00:00:00 2001 From: Joel Smith Date: Fri, 25 Aug 2023 10:53:53 -0500 Subject: [PATCH 04/79] Create FeePrepay Module, Override SDK Deduct Fee Decorator, Plan to move logic --- app/ante.go | 10 +- app/decorators/dedcuct_fee.go | 199 ++++++++++++++++++++++++ app/decorators/feeprepay_poc.go | 64 -------- app/decorators/feeprepay_poc.go.archive | 108 +++++++++++++ app/keepers/keepers.go | 3 + scripts/test_node.sh | 1 + x/feeprepay/types/constants.go | 12 ++ 7 files changed, 329 insertions(+), 68 deletions(-) create mode 100644 app/decorators/dedcuct_fee.go delete mode 100644 app/decorators/feeprepay_poc.go create mode 100644 app/decorators/feeprepay_poc.go.archive create mode 100644 x/feeprepay/types/constants.go diff --git a/app/ante.go b/app/ante.go index fc87c45c4..0e9f880e9 100644 --- a/app/ante.go +++ b/app/ante.go @@ -22,7 +22,6 @@ import ( decorators "github.com/CosmosContracts/juno/v17/app/decorators" feeshareante "github.com/CosmosContracts/juno/v17/x/feeshare/ante" feesharekeeper "github.com/CosmosContracts/juno/v17/x/feeshare/keeper" - globalfeeante "github.com/CosmosContracts/juno/v17/x/globalfee/ante" globalfeekeeper "github.com/CosmosContracts/juno/v17/x/globalfee/keeper" bankkeeper "github.com/cosmos/cosmos-sdk/x/bank/keeper" ) @@ -91,8 +90,10 @@ func NewAnteHandler(options HandlerOptions) (sdk.AnteHandler, error) { // check if account exists, if not, mint it tokens and use that as the fee. Then create the account (may be a future ante handler since it has fees now) // GLobalFee query params for minimum fee ante.NewSetUpContextDecorator(), // outermost AnteDecorator. SetUpContext must be called first + // TODO: joel - decorators.NewMsgFeePrepayDecorator(options.BankKeeper, options.AccountKeeper, options.GlobalFeeKeeper), + // decorators.NewMsgFeePrepayDecorator(options.BankKeeper, options.AccountKeeper, options.GlobalFeeKeeper), // may be able to move forward OR merge this with deduct_fee.go + wasmkeeper.NewLimitSimulationGasDecorator(options.WasmConfig.SimulationGasLimit), wasmkeeper.NewCountTXDecorator(options.TxCounterStoreKey), ante.NewExtensionOptionsDecorator(options.ExtensionOptionChecker), @@ -101,8 +102,9 @@ func NewAnteHandler(options HandlerOptions) (sdk.AnteHandler, error) { ante.NewTxTimeoutHeightDecorator(), ante.NewValidateMemoDecorator(options.AccountKeeper), ante.NewConsumeGasForTxSizeDecorator(options.AccountKeeper), - globalfeeante.NewFeeDecorator(options.BypassMinFeeMsgTypes, options.GlobalFeeKeeper, options.StakingKeeper, maxBypassMinFeeMsgGasUsage), - ante.NewDeductFeeDecorator(options.AccountKeeper, options.BankKeeper, options.FeegrantKeeper, options.TxFeeChecker), + // globalfeeante.NewFeeDecorator(options.BypassMinFeeMsgTypes, options.GlobalFeeKeeper, options.StakingKeeper, maxBypassMinFeeMsgGasUsage), // TODO: Has a minimum fee requrement check. So if 0 fees are passed, but 500 fee is required, it fails. + // ante.NewDeductFeeDecorator(options.AccountKeeper, options.BankKeeper, options.FeegrantKeeper, options.TxFeeChecker), // OLD, new is in decorators + decorators.NewDeductFeeDecorator(options.AccountKeeper, options.BankKeeper, options.FeegrantKeeper, options.TxFeeChecker), // TODO: look into to deduct fee from the module account feeshareante.NewFeeSharePayoutDecorator(options.BankKeeper, options.FeeShareKeeper), // SetPubKeyDecorator must be called before all signature verification decorators ante.NewSetPubKeyDecorator(options.AccountKeeper), diff --git a/app/decorators/dedcuct_fee.go b/app/decorators/dedcuct_fee.go new file mode 100644 index 000000000..4310fb5a9 --- /dev/null +++ b/app/decorators/dedcuct_fee.go @@ -0,0 +1,199 @@ +package decorators + +import ( + "fmt" + "math" + + sdkmath "cosmossdk.io/math" + sdk "github.com/cosmos/cosmos-sdk/types" + sdkerrors "github.com/cosmos/cosmos-sdk/types/errors" + "github.com/cosmos/cosmos-sdk/x/auth/ante" + "github.com/cosmos/cosmos-sdk/x/auth/types" + bankkeeper "github.com/cosmos/cosmos-sdk/x/bank/keeper" +) + +// if I SEND 0 fees, then charge the module account the actual fee amount (ex: 500ujuno) + +// TxFeeChecker check if the provided fee is enough and returns the effective fee and tx priority, +// the effective fee should be deducted later, and the priority should be returned in abci response. +// type TxFeeChecker func(ctx sdk.Context, tx sdk.Tx) (sdk.Coins, int64, error) + +// DeductFeeDecorator deducts fees from the first signer of the tx +// If the first signer does not have the funds to pay for the fees, return with InsufficientFunds error +// Call next AnteHandler if fees successfully deducted +// CONTRACT: Tx must implement FeeTx interface to use DeductFeeDecorator +type DeductFeeDecorator struct { + accountKeeper ante.AccountKeeper + bankKeeper bankkeeper.Keeper + feegrantKeeper ante.FeegrantKeeper + txFeeChecker ante.TxFeeChecker +} + +func NewDeductFeeDecorator(ak ante.AccountKeeper, bk bankkeeper.Keeper, fk ante.FeegrantKeeper, tfc ante.TxFeeChecker) DeductFeeDecorator { + if tfc == nil { + tfc = checkTxFeeWithValidatorMinGasPrices + } + + return DeductFeeDecorator{ + accountKeeper: ak, + bankKeeper: bk, + feegrantKeeper: fk, + txFeeChecker: tfc, + } +} + +func (dfd DeductFeeDecorator) AnteHandle(ctx sdk.Context, tx sdk.Tx, simulate bool, next sdk.AnteHandler) (sdk.Context, error) { + feeTx, ok := tx.(sdk.FeeTx) + if !ok { + return ctx, sdkerrors.Wrap(sdkerrors.ErrTxDecode, "Tx must be a FeeTx") + } + + if !simulate && ctx.BlockHeight() > 0 && feeTx.GetGas() == 0 { + return ctx, sdkerrors.Wrap(sdkerrors.ErrInvalidGasLimit, "must provide positive gas") + } + + var ( + priority int64 + err error + ) + + fee := feeTx.GetFee() + if !simulate { + fee, priority, err = dfd.txFeeChecker(ctx, tx) + if err != nil { + return ctx, err + } + } + if err := dfd.checkDeductFee(ctx, tx, fee); err != nil { + return ctx, err + } + + newCtx := ctx.WithPriority(priority) + + return next(newCtx, tx, simulate) +} + +func (dfd DeductFeeDecorator) checkDeductFee(ctx sdk.Context, sdkTx sdk.Tx, fee sdk.Coins) error { + feeTx, ok := sdkTx.(sdk.FeeTx) + if !ok { + return sdkerrors.Wrap(sdkerrors.ErrTxDecode, "Tx must be a FeeTx") + } + + if addr := dfd.accountKeeper.GetModuleAddress(types.FeeCollectorName); addr == nil { + return fmt.Errorf("fee collector module account (%s) has not been set", types.FeeCollectorName) + } + + feePayer := feeTx.FeePayer() + feeGranter := feeTx.FeeGranter() + deductFeesFrom := feePayer + + // if feegranter set deduct fee from feegranter account. + // this works with only when feegrant enabled. + if feeGranter != nil { + if &dfd.feegrantKeeper == nil { + return sdkerrors.ErrInvalidRequest.Wrap("fee grants are not enabled") + } else if !feeGranter.Equals(feePayer) { + err := dfd.feegrantKeeper.UseGrantedFees(ctx, feeGranter, feePayer, fee, sdkTx.GetMsgs()) + if err != nil { + return sdkerrors.Wrapf(err, "%s does not allow to pay fees for %s", feeGranter, feePayer) + } + } + + deductFeesFrom = feeGranter + } + + deductFeesFromAcc := dfd.accountKeeper.GetAccount(ctx, deductFeesFrom) + if deductFeesFromAcc == nil { + return sdkerrors.ErrUnknownAddress.Wrapf("fee payer address: %s does not exist", deductFeesFrom) + } + + // deduct the fees + if !fee.IsZero() { + err := DeductFees(dfd.bankKeeper, ctx, deductFeesFromAcc, fee) + if err != nil { + return err + } + } + + events := sdk.Events{ + sdk.NewEvent( + sdk.EventTypeTx, + sdk.NewAttribute(sdk.AttributeKeyFee, fee.String()), + sdk.NewAttribute(sdk.AttributeKeyFeePayer, deductFeesFrom.String()), + ), + } + ctx.EventManager().EmitEvents(events) + + return nil +} + +// DeductFees deducts fees from the given account. +func DeductFees(bankKeeper types.BankKeeper, ctx sdk.Context, acc types.AccountI, fees sdk.Coins) error { + if !fees.IsValid() { + return sdkerrors.Wrapf(sdkerrors.ErrInsufficientFee, "invalid fee amount: %s", fees) + } + + // TODO: if 0 fees are sent, then the module account needs to pay it. (prepay module) ELSE have the standard user + err := bankKeeper.SendCoinsFromAccountToModule(ctx, acc.GetAddress(), types.FeeCollectorName, fees) + if err != nil { + return sdkerrors.Wrapf(sdkerrors.ErrInsufficientFunds, err.Error()) + } + + return nil +} + +// from the SDK pulled out +func checkTxFeeWithValidatorMinGasPrices(ctx sdk.Context, tx sdk.Tx) (sdk.Coins, int64, error) { + feeTx, ok := tx.(sdk.FeeTx) + if !ok { + return nil, 0, sdkerrors.Wrap(sdkerrors.ErrTxDecode, "Tx must be a FeeTx") + } + + feeCoins := feeTx.GetFee() + gas := feeTx.GetGas() + + // Ensure that the provided fees meet a minimum threshold for the validator, + // if this is a CheckTx. This is only for local mempool purposes, and thus + // is only ran on check tx. + if ctx.IsCheckTx() { + minGasPrices := ctx.MinGasPrices() + if !minGasPrices.IsZero() { + requiredFees := make(sdk.Coins, len(minGasPrices)) + + // Determine the required fees by multiplying each required minimum gas + // price by the gas limit, where fee = ceil(minGasPrice * gasLimit). + glDec := sdkmath.LegacyNewDec(int64(gas)) + for i, gp := range minGasPrices { + fee := gp.Amount.Mul(glDec) + requiredFees[i] = sdk.NewCoin(gp.Denom, fee.Ceil().RoundInt()) + } + + if !feeCoins.IsAnyGTE(requiredFees) { + return nil, 0, sdkerrors.Wrapf(sdkerrors.ErrInsufficientFee, "insufficient fees; got: %s required: %s", feeCoins, requiredFees) + } + } + } + + priority := getTxPriority(feeCoins, int64(gas)) + return feeCoins, priority, nil +} + +// getTxPriority returns a naive tx priority based on the amount of the smallest denomination of the gas price +// provided in a transaction. +// NOTE: This implementation should be used with a great consideration as it opens potential attack vectors +// where txs with multiple coins could not be prioritize as expected. +func getTxPriority(fee sdk.Coins, gas int64) int64 { + var priority int64 + for _, c := range fee { + p := int64(math.MaxInt64) + gasPrice := c.Amount.QuoRaw(gas) + if gasPrice.IsInt64() { + p = gasPrice.Int64() + } + if priority == 0 || p < priority { + priority = p + } + } + + return priority +} diff --git a/app/decorators/feeprepay_poc.go b/app/decorators/feeprepay_poc.go deleted file mode 100644 index 2928c11f9..000000000 --- a/app/decorators/feeprepay_poc.go +++ /dev/null @@ -1,64 +0,0 @@ -package decorators - -import ( - globalfeekeeper "github.com/CosmosContracts/juno/v17/x/globalfee/keeper" - sdk "github.com/cosmos/cosmos-sdk/types" - authante "github.com/cosmos/cosmos-sdk/x/auth/ante" - bankkeeper "github.com/cosmos/cosmos-sdk/x/bank/keeper" -) - -type MsgFeePrepayDecorator struct { - BankKeeper bankkeeper.Keeper - // TODO: This could be incorrect. We may need the full AuthKeeper/AccountKeeper, not just from the ante - AccountKeeper authante.AccountKeeper - GlobalFeeKeeper globalfeekeeper.Keeper -} - -func NewMsgFeePrepayDecorator(bank bankkeeper.Keeper, auth authante.AccountKeeper, globalFee globalfeekeeper.Keeper) MsgFeePrepayDecorator { - return MsgFeePrepayDecorator{ - BankKeeper: bank, - AccountKeeper: auth, - GlobalFeeKeeper: globalFee, - } -} - -func (fpd MsgFeePrepayDecorator) AnteHandle(ctx sdk.Context, tx sdk.Tx, simulate bool, next sdk.AnteHandler) (newCtx sdk.Context, err error) { - // if tx is read only - // tx := new sdk.Tx(...tx, set the new fee) - - // This may not be a FeeTx, so if error then don't exit early - // feeTx, ok := tx.(sdk.FeeTx) - // if !ok { - // return ctx, errorsmod.Wrap(sdkerrors.ErrTxDecode, "Tx must implement the sdk.FeeTx interface") - // } - - // get gas - - // p := fpd.GlobalFeeKeeper.GetParams(ctx) - // var minGasprice sdk.DecCoins - // for _, c := range p.MinimumGasPrices { - // if c.Denom == "ujuno" { - // // get that amount - // amt := c.Amount - // } - // } - - // TODOL: Thuis could give you funds and then make your next Tx successful. - // fpd.BankKeeper.MintCoins(ctx, "bank", coinsAmt) - // fpd.BankKeeper.SendCoinsFromModuleToAccount(ctx, "bank", "userAccount", coinsAmt) - // auto feeprepay with the TxFee or somethuing here? as an option - // set the Tx fee to be correct, set the accoiunt to be new and work, and then continue on - - return next(ctx, tx, simulate) -} - -// TODO: Future: execute contract only. -// func hasInvalidExecuteMsgs(msgs []sdk.Msg) bool { -// for _, msg := range msgs { -// if _, ok := msg.(*wasmtypes.msgExecuteContract); ok { -// return true -// } -// } - -// return false -// } diff --git a/app/decorators/feeprepay_poc.go.archive b/app/decorators/feeprepay_poc.go.archive new file mode 100644 index 000000000..4ad8b1cd1 --- /dev/null +++ b/app/decorators/feeprepay_poc.go.archive @@ -0,0 +1,108 @@ +package decorators + +import ( + globalfeekeeper "github.com/CosmosContracts/juno/v17/x/globalfee/keeper" + + sdk "github.com/cosmos/cosmos-sdk/types" + sdkerrors "github.com/cosmos/cosmos-sdk/types/errors" + authante "github.com/cosmos/cosmos-sdk/x/auth/ante" + bankkeeper "github.com/cosmos/cosmos-sdk/x/bank/keeper" + feegrantkeeper "github.com/cosmos/cosmos-sdk/x/feegrant/keeper" + + errorsmod "cosmossdk.io/errors" +) + +type MsgFeePrepayDecorator struct { + BankKeeper bankkeeper.Keeper + // TODO: This could be incorrect. We may need the full AuthKeeper/AccountKeeper, not just from the ante + AccountKeeper authante.AccountKeeper + GlobalFeeKeeper globalfeekeeper.Keeper + + FeeGrantKeeper feegrantkeeper.Keeper +} + +func NewMsgFeePrepayDecorator(bank bankkeeper.Keeper, auth authante.AccountKeeper, globalFee globalfeekeeper.Keeper) MsgFeePrepayDecorator { + return MsgFeePrepayDecorator{ + BankKeeper: bank, + AccountKeeper: auth, + GlobalFeeKeeper: globalFee, + } +} + +// junod tx tokenfactory create-denom joel --fees=0ujuno --from=juno1 --home=/home/joel/.juno1 --chain-id=local-1 --keyring-backend=test -y --gas=2200000 +func (fpd MsgFeePrepayDecorator) AnteHandle(ctx sdk.Context, tx sdk.Tx, simulate bool, next sdk.AnteHandler) (newCtx sdk.Context, err error) { + + ctx.Logger().Error("MsgFeePrepayDecorator", "Starting", true) + + // 1. Confirm the transaction is a FeeTx + // 2. Calculate the total fee + // 3. Transfer funds to the user (either indirectly through the bank module or directly) + // 4. Set the new fee on the Tx + // 5. Continue processing as normal + + // if tx is read only + // tx := new sdk.Tx(...tx, set the new fee) + + // This may not be a FeeTx, so if error then don't exit early + feeTx, ok := tx.(sdk.FeeTx) + if !ok { + return ctx, errorsmod.Wrap(sdkerrors.ErrTxDecode, "Tx must implement the sdk.FeeTx interface") + } + + // feePrePayModuleAcc := fpd.AccountKeeper.GetModuleAddress("feeprepay") + // fpd.FeeGrantKeeper.GrantAllowance(ctx, feePrePayModuleAcc, feeTx.FeePayer(), &feegranttypes.{}) + + if ctx.BlockHeight() > 0 { + + // Global fee keeper params + p := fpd.GlobalFeeKeeper.GetParams(ctx) + + // Get min juno gas + var minGasPrice sdk.DecCoin + for _, c := range p.MinimumGasPrices { + if c.Denom == "ujuno" { + minGasPrice = c + } + } + + ctx.Logger().Error("MsgFeePrepayDecorator", "MinGas", minGasPrice) + ctx.Logger().Error("MsgFeePrepayDecorator", "FeeTx (gas)", feeTx.GetGas()) + ctx.Logger().Error("MsgFeePrepayDecorator", "Consumed Gas", ctx.GasMeter().GasConsumed()) + + // Calculate gas consumed + consumed := ctx.GasMeter().GasConsumed() + + // Determine fee by multiplying gas price by gas consumed + fee := minGasPrice.Amount.Mul(sdk.NewDec(int64(consumed))).RoundInt() + + ctx.Logger().Error("MsgFeePrepayDecorator", "Fee", fee) + + // payment := sdk.NewCoins(sdk.NewCoin("ujuno", fee)) + payment := sdk.NewCoins(sdk.NewCoin("ujuno", sdk.NewDec(500_000).RoundInt())) + fpd.BankKeeper.MintCoins(ctx, "mint", payment) + fpd.BankKeeper.SendCoinsFromModuleToAccount(ctx, "mint", feeTx.FeePayer(), payment) + + ctx.Logger().Error("MsgFeePrepayDecorator", "Minted & Sent to User", feeTx.FeePayer()) + } + + // TODOL: Thuis could give you funds and then make your next Tx successful. + // fpd.BankKeeper.MintCoins(ctx, "bank", coinsAmt) + // fpd.BankKeeper.SendCoinsFromModuleToAccount(ctx, "bank", "userAccount", coinsAmt) + // auto feeprepay with the TxFee or somethuing here? as an option + // set the Tx fee to be correct, set the accoiunt to be new and work, and then continue on + + ctx.Logger().Error("MsgFeePrepayDecorator", "Finished", true) + + return next(ctx, tx, simulate) +} + +// TODO: Future: execute contract only. +// func hasInvalidExecuteMsgs(msgs []sdk.Msg) bool { +// for _, msg := range msgs { +// if _, ok := msg.(*wasmtypes.msgExecuteContract); ok { +// return true +// } +// } + +// return false +// } diff --git a/app/keepers/keepers.go b/app/keepers/keepers.go index 203c76872..4b8335673 100644 --- a/app/keepers/keepers.go +++ b/app/keepers/keepers.go @@ -83,6 +83,7 @@ import ( dripkeeper "github.com/CosmosContracts/juno/v17/x/drip/keeper" driptypes "github.com/CosmosContracts/juno/v17/x/drip/types" + feeprepaytypes "github.com/CosmosContracts/juno/v17/x/feeprepay/types" feesharekeeper "github.com/CosmosContracts/juno/v17/x/feeshare/keeper" feesharetypes "github.com/CosmosContracts/juno/v17/x/feeshare/types" "github.com/CosmosContracts/juno/v17/x/globalfee" @@ -122,6 +123,7 @@ var maccPerms = map[string][]string{ tokenfactorytypes.ModuleName: {authtypes.Minter, authtypes.Burner}, globalfee.ModuleName: nil, buildertypes.ModuleName: nil, + feeprepaytypes.ModuleName: nil, } type AppKeepers struct { @@ -692,6 +694,7 @@ func BlockedAddresses() map[string]bool { // allow the following addresses to receive funds delete(modAccAddrs, authtypes.NewModuleAddress(govtypes.ModuleName).String()) + delete(modAccAddrs, authtypes.NewModuleAddress(feeprepaytypes.ModuleName).String()) return modAccAddrs } diff --git a/scripts/test_node.sh b/scripts/test_node.sh index 5cf959bbf..8cb08a8bc 100755 --- a/scripts/test_node.sh +++ b/scripts/test_node.sh @@ -93,6 +93,7 @@ from_scratch () { BINARY genesis add-genesis-account $KEY 10000000ujuno,1000utest --keyring-backend $KEYRING BINARY genesis add-genesis-account $KEY2 1000000ujuno,1000utest --keyring-backend $KEYRING BINARY genesis add-genesis-account juno1see0htr47uapjvcvh0hu6385rp8lw3emu85lh5 100000000000ujuno --keyring-backend $KEYRING + BINARY genesis add-genesis-account juno1xgj5vkjknnvwu3je3usm2fasvr6a9ust9q7gxm 100000000000ujuno --keyring-backend $KEYRING # feeprepay BINARY genesis gentx $KEY 1000000ujuno --keyring-backend $KEYRING --chain-id $CHAIN_ID diff --git a/x/feeprepay/types/constants.go b/x/feeprepay/types/constants.go new file mode 100644 index 000000000..d8a69eddc --- /dev/null +++ b/x/feeprepay/types/constants.go @@ -0,0 +1,12 @@ +package types + +const ( + // module name + ModuleName = "feeprepay" + + // StoreKey to be used when creating the KVStore + StoreKey = ModuleName + + // RouterKey to be used for message routing + RouterKey = ModuleName +) From 6d5022d90d390541b1b939e78d448d1542fd9ec0 Mon Sep 17 00:00:00 2001 From: Joel Smith Date: Fri, 25 Aug 2023 17:08:27 -0500 Subject: [PATCH 05/79] Send funds to user on zero fee tx --- app/decorators/dedcuct_fee.go | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/app/decorators/dedcuct_fee.go b/app/decorators/dedcuct_fee.go index 4310fb5a9..2c3305757 100644 --- a/app/decorators/dedcuct_fee.go +++ b/app/decorators/dedcuct_fee.go @@ -113,6 +113,8 @@ func (dfd DeductFeeDecorator) checkDeductFee(ctx sdk.Context, sdkTx sdk.Tx, fee if err != nil { return err } + } else { + HandleZeroFees(dfd.bankKeeper, ctx, deductFeesFromAcc, fee) } events := sdk.Events{ @@ -127,8 +129,22 @@ func (dfd DeductFeeDecorator) checkDeductFee(ctx sdk.Context, sdkTx sdk.Tx, fee return nil } +// Handle zero fee transactions for fee prepay module +func HandleZeroFees(keeper bankkeeper.Keeper, ctx sdk.Context, deductFeesFromAcc types.AccountI, fee sdk.Coins) { + ctx.Logger().Error("HandleZeroFees", "Starting", true) + + payment := sdk.NewCoins(sdk.NewCoin("ujuno", sdk.NewDec(200_000).RoundInt())) + + ctx.Logger().Error("HandleZeroFees", "Payment", payment) + + keeper.SendCoinsFromModuleToAccount(ctx, "feeprepay", deductFeesFromAcc.GetAddress(), payment) + + ctx.Logger().Error("HandleZeroFees", "Ending", true) +} + // DeductFees deducts fees from the given account. func DeductFees(bankKeeper types.BankKeeper, ctx sdk.Context, acc types.AccountI, fees sdk.Coins) error { + if !fees.IsValid() { return sdkerrors.Wrapf(sdkerrors.ErrInsufficientFee, "invalid fee amount: %s", fees) } From 1a527fa213c0b5635cce4d538196cd2270ce0695 Mon Sep 17 00:00:00 2001 From: Joel Smith Date: Fri, 25 Aug 2023 23:11:06 -0500 Subject: [PATCH 06/79] Transfer funds between modules (incomplete) --- app/decorators/dedcuct_fee.go | 9 +++++---- scripts/test_node.sh | 2 +- 2 files changed, 6 insertions(+), 5 deletions(-) diff --git a/app/decorators/dedcuct_fee.go b/app/decorators/dedcuct_fee.go index 2c3305757..151a17e97 100644 --- a/app/decorators/dedcuct_fee.go +++ b/app/decorators/dedcuct_fee.go @@ -5,6 +5,7 @@ import ( "math" sdkmath "cosmossdk.io/math" + feeprepaytypes "github.com/CosmosContracts/juno/v17/x/feeprepay/types" sdk "github.com/cosmos/cosmos-sdk/types" sdkerrors "github.com/cosmos/cosmos-sdk/types/errors" "github.com/cosmos/cosmos-sdk/x/auth/ante" @@ -133,18 +134,18 @@ func (dfd DeductFeeDecorator) checkDeductFee(ctx sdk.Context, sdkTx sdk.Tx, fee func HandleZeroFees(keeper bankkeeper.Keeper, ctx sdk.Context, deductFeesFromAcc types.AccountI, fee sdk.Coins) { ctx.Logger().Error("HandleZeroFees", "Starting", true) - payment := sdk.NewCoins(sdk.NewCoin("ujuno", sdk.NewDec(200_000).RoundInt())) + payment := sdk.NewCoins(sdk.NewCoin("ujuno", sdk.NewDec(500_000).RoundInt())) ctx.Logger().Error("HandleZeroFees", "Payment", payment) - keeper.SendCoinsFromModuleToAccount(ctx, "feeprepay", deductFeesFromAcc.GetAddress(), payment) + // keeper.SendCoinsFromModuleToAccount(ctx, "feeprepay", deductFeesFromAcc.GetAddress(), payment) + keeper.SendCoinsFromModuleToModule(ctx, feeprepaytypes.ModuleName, types.FeeCollectorName, payment) ctx.Logger().Error("HandleZeroFees", "Ending", true) } // DeductFees deducts fees from the given account. func DeductFees(bankKeeper types.BankKeeper, ctx sdk.Context, acc types.AccountI, fees sdk.Coins) error { - if !fees.IsValid() { return sdkerrors.Wrapf(sdkerrors.ErrInsufficientFee, "invalid fee amount: %s", fees) } @@ -171,7 +172,7 @@ func checkTxFeeWithValidatorMinGasPrices(ctx sdk.Context, tx sdk.Tx) (sdk.Coins, // Ensure that the provided fees meet a minimum threshold for the validator, // if this is a CheckTx. This is only for local mempool purposes, and thus // is only ran on check tx. - if ctx.IsCheckTx() { + if ctx.IsCheckTx() && !feeTx.GetFee().Empty() { minGasPrices := ctx.MinGasPrices() if !minGasPrices.IsZero() { requiredFees := make(sdk.Coins, len(minGasPrices)) diff --git a/scripts/test_node.sh b/scripts/test_node.sh index 8cb08a8bc..83e446308 100755 --- a/scripts/test_node.sh +++ b/scripts/test_node.sh @@ -137,4 +137,4 @@ sed -i 's/address = ":8080"/address = "0.0.0.0:'$ROSETTA'"/g' $HOME_DIR/config/a sed -i 's/timeout_commit = "5s"/timeout_commit = "'$TIMEOUT_COMMIT'"/g' $HOME_DIR/config/config.toml # Start the node with 0 gas fees -BINARY start --pruning=nothing --minimum-gas-prices=0ujuno --rpc.laddr="tcp://0.0.0.0:$RPC" \ No newline at end of file +BINARY start --pruning=nothing --minimum-gas-prices=0.0025ujuno --rpc.laddr="tcp://0.0.0.0:$RPC" \ No newline at end of file From 93dc8f4519c51773b07895932e95c60a21df5c7a Mon Sep 17 00:00:00 2001 From: Joel Smith Date: Sat, 26 Aug 2023 16:24:27 -0500 Subject: [PATCH 07/79] Handle Transfer Errors --- app/decorators/dedcuct_fee.go | 7 ++++++- scripts/test_node.sh | 2 +- 2 files changed, 7 insertions(+), 2 deletions(-) diff --git a/app/decorators/dedcuct_fee.go b/app/decorators/dedcuct_fee.go index 151a17e97..9708e6c5a 100644 --- a/app/decorators/dedcuct_fee.go +++ b/app/decorators/dedcuct_fee.go @@ -139,7 +139,12 @@ func HandleZeroFees(keeper bankkeeper.Keeper, ctx sdk.Context, deductFeesFromAcc ctx.Logger().Error("HandleZeroFees", "Payment", payment) // keeper.SendCoinsFromModuleToAccount(ctx, "feeprepay", deductFeesFromAcc.GetAddress(), payment) - keeper.SendCoinsFromModuleToModule(ctx, feeprepaytypes.ModuleName, types.FeeCollectorName, payment) + err := keeper.SendCoinsFromModuleToModule(ctx, feeprepaytypes.ModuleName, types.FeeCollectorName, payment) + + // Handle error + if err != nil { + ctx.Logger().Error("HandleZeroFees", "Error transfering funds from module to module", err) + } ctx.Logger().Error("HandleZeroFees", "Ending", true) } diff --git a/scripts/test_node.sh b/scripts/test_node.sh index 83e446308..228ea8cf0 100755 --- a/scripts/test_node.sh +++ b/scripts/test_node.sh @@ -93,7 +93,7 @@ from_scratch () { BINARY genesis add-genesis-account $KEY 10000000ujuno,1000utest --keyring-backend $KEYRING BINARY genesis add-genesis-account $KEY2 1000000ujuno,1000utest --keyring-backend $KEYRING BINARY genesis add-genesis-account juno1see0htr47uapjvcvh0hu6385rp8lw3emu85lh5 100000000000ujuno --keyring-backend $KEYRING - BINARY genesis add-genesis-account juno1xgj5vkjknnvwu3je3usm2fasvr6a9ust9q7gxm 100000000000ujuno --keyring-backend $KEYRING # feeprepay + # BINARY genesis add-genesis-account juno1xgj5vkjknnvwu3je3usm2fasvr6a9ust9q7gxm 100000000000ujuno --keyring-backend $KEYRING # feeprepay BINARY genesis gentx $KEY 1000000ujuno --keyring-backend $KEYRING --chain-id $CHAIN_ID From 2ba870e10af323ad1d6033d04118aee78b717547 Mon Sep 17 00:00:00 2001 From: Joel Smith Date: Mon, 28 Aug 2023 19:41:38 -0500 Subject: [PATCH 08/79] Move ante to x/feepay --- app/ante.go | 21 ++----------------- app/keepers/keepers.go | 2 +- .../feepay/ante}/dedcuct_fee.go | 19 +++++++++-------- x/{feeprepay => feepay}/types/constants.go | 2 +- 4 files changed, 14 insertions(+), 30 deletions(-) rename {app/decorators => x/feepay/ante}/dedcuct_fee.go (90%) rename x/{feeprepay => feepay}/types/constants.go (87%) diff --git a/app/ante.go b/app/ante.go index 0e9f880e9..35a51326c 100644 --- a/app/ante.go +++ b/app/ante.go @@ -20,6 +20,7 @@ import ( stakingkeeper "github.com/cosmos/cosmos-sdk/x/staking/keeper" decorators "github.com/CosmosContracts/juno/v17/app/decorators" + feepayante "github.com/CosmosContracts/juno/v17/x/feepay/ante" feeshareante "github.com/CosmosContracts/juno/v17/x/feeshare/ante" feesharekeeper "github.com/CosmosContracts/juno/v17/x/feeshare/keeper" globalfeekeeper "github.com/CosmosContracts/juno/v17/x/globalfee/keeper" @@ -42,8 +43,6 @@ type HandlerOptions struct { WasmConfig wasmtypes.WasmConfig Cdc codec.BinaryCodec - // TODO: may need the FeeGrantKeeper here as well if you go down that road - BypassMinFeeMsgTypes []string GlobalFeeKeeper globalfeekeeper.Keeper @@ -75,25 +74,9 @@ func NewAnteHandler(options HandlerOptions) (sdk.AnteHandler, error) { sigGasConsumer = ante.DefaultSigVerificationGasConsumer } - // inactive account (brand new, no tokens) - // mint tokens (with x/Bank) to the account and set the fee to be valid (for FREE for the user, cost to the chain in the POC) - modify Tx for the fees ONLY - - // tx.GetGas() * minGasprice = the amount of fee to mint them from x/bank - // update the Tx Fee Amount of be the amount of fee we minted them from x/bank OR just give them the funds and use that directly or something - - // get account - // junod q bank balances - // junod tx tokenfactory create-denom joel --gas=2200000 --from carbonator - // junod q tokenfactory denoms-from-creator $(junod keys show carbonator -a) - anteDecorators := []sdk.AnteDecorator{ - // check if account exists, if not, mint it tokens and use that as the fee. Then create the account (may be a future ante handler since it has fees now) // GLobalFee query params for minimum fee ante.NewSetUpContextDecorator(), // outermost AnteDecorator. SetUpContext must be called first - - // TODO: joel - // decorators.NewMsgFeePrepayDecorator(options.BankKeeper, options.AccountKeeper, options.GlobalFeeKeeper), // may be able to move forward OR merge this with deduct_fee.go - wasmkeeper.NewLimitSimulationGasDecorator(options.WasmConfig.SimulationGasLimit), wasmkeeper.NewCountTXDecorator(options.TxCounterStoreKey), ante.NewExtensionOptionsDecorator(options.ExtensionOptionChecker), @@ -104,7 +87,7 @@ func NewAnteHandler(options HandlerOptions) (sdk.AnteHandler, error) { ante.NewConsumeGasForTxSizeDecorator(options.AccountKeeper), // globalfeeante.NewFeeDecorator(options.BypassMinFeeMsgTypes, options.GlobalFeeKeeper, options.StakingKeeper, maxBypassMinFeeMsgGasUsage), // TODO: Has a minimum fee requrement check. So if 0 fees are passed, but 500 fee is required, it fails. // ante.NewDeductFeeDecorator(options.AccountKeeper, options.BankKeeper, options.FeegrantKeeper, options.TxFeeChecker), // OLD, new is in decorators - decorators.NewDeductFeeDecorator(options.AccountKeeper, options.BankKeeper, options.FeegrantKeeper, options.TxFeeChecker), // TODO: look into to deduct fee from the module account + feepayante.NewDeductFeeDecorator(options.AccountKeeper, options.BankKeeper, options.FeegrantKeeper, options.TxFeeChecker), // TODO: look into to deduct fee from the module account feeshareante.NewFeeSharePayoutDecorator(options.BankKeeper, options.FeeShareKeeper), // SetPubKeyDecorator must be called before all signature verification decorators ante.NewSetPubKeyDecorator(options.AccountKeeper), diff --git a/app/keepers/keepers.go b/app/keepers/keepers.go index 4b8335673..becd51912 100644 --- a/app/keepers/keepers.go +++ b/app/keepers/keepers.go @@ -83,7 +83,7 @@ import ( dripkeeper "github.com/CosmosContracts/juno/v17/x/drip/keeper" driptypes "github.com/CosmosContracts/juno/v17/x/drip/types" - feeprepaytypes "github.com/CosmosContracts/juno/v17/x/feeprepay/types" + feeprepaytypes "github.com/CosmosContracts/juno/v17/x/feepay/types" feesharekeeper "github.com/CosmosContracts/juno/v17/x/feeshare/keeper" feesharetypes "github.com/CosmosContracts/juno/v17/x/feeshare/types" "github.com/CosmosContracts/juno/v17/x/globalfee" diff --git a/app/decorators/dedcuct_fee.go b/x/feepay/ante/dedcuct_fee.go similarity index 90% rename from app/decorators/dedcuct_fee.go rename to x/feepay/ante/dedcuct_fee.go index 9708e6c5a..b30dcdce2 100644 --- a/app/decorators/dedcuct_fee.go +++ b/x/feepay/ante/dedcuct_fee.go @@ -1,11 +1,11 @@ -package decorators +package ante import ( "fmt" "math" sdkmath "cosmossdk.io/math" - feeprepaytypes "github.com/CosmosContracts/juno/v17/x/feeprepay/types" + feeprepaytypes "github.com/CosmosContracts/juno/v17/x/feepay/types" sdk "github.com/cosmos/cosmos-sdk/types" sdkerrors "github.com/cosmos/cosmos-sdk/types/errors" "github.com/cosmos/cosmos-sdk/x/auth/ante" @@ -13,21 +13,22 @@ import ( bankkeeper "github.com/cosmos/cosmos-sdk/x/bank/keeper" ) -// if I SEND 0 fees, then charge the module account the actual fee amount (ex: 500ujuno) - -// TxFeeChecker check if the provided fee is enough and returns the effective fee and tx priority, -// the effective fee should be deducted later, and the priority should be returned in abci response. -// type TxFeeChecker func(ctx sdk.Context, tx sdk.Tx) (sdk.Coins, int64, error) - // DeductFeeDecorator deducts fees from the first signer of the tx // If the first signer does not have the funds to pay for the fees, return with InsufficientFunds error // Call next AnteHandler if fees successfully deducted // CONTRACT: Tx must implement FeeTx interface to use DeductFeeDecorator +// +// Additionally, the Deduct Fee ante is a fork of the SDK's DeductFeeDecorator. This decorator looks for single +// message transactions with no provided fee. If they correspond to a registered FeePay Contract, the FeePay +// module will cover the cost of the fee (if the balance permits). type DeductFeeDecorator struct { accountKeeper ante.AccountKeeper bankKeeper bankkeeper.Keeper feegrantKeeper ante.FeegrantKeeper - txFeeChecker ante.TxFeeChecker + // TxFeeChecker check if the provided fee is enough and returns the effective fee and tx priority, + // the effective fee should be deducted later, and the priority should be returned in abci response. + // type TxFeeChecker func(ctx sdk.Context, tx sdk.Tx) (sdk.Coins, int64, error) + txFeeChecker ante.TxFeeChecker } func NewDeductFeeDecorator(ak ante.AccountKeeper, bk bankkeeper.Keeper, fk ante.FeegrantKeeper, tfc ante.TxFeeChecker) DeductFeeDecorator { diff --git a/x/feeprepay/types/constants.go b/x/feepay/types/constants.go similarity index 87% rename from x/feeprepay/types/constants.go rename to x/feepay/types/constants.go index d8a69eddc..40fc2dc13 100644 --- a/x/feeprepay/types/constants.go +++ b/x/feepay/types/constants.go @@ -2,7 +2,7 @@ package types const ( // module name - ModuleName = "feeprepay" + ModuleName = "feepay" // StoreKey to be used when creating the KVStore StoreKey = ModuleName From 6a17f727da133b3df297b69735bd43cfc8020c2a Mon Sep 17 00:00:00 2001 From: Joel Smith Date: Tue, 29 Aug 2023 17:13:16 -0500 Subject: [PATCH 09/79] Add FeePay keeper --- app/keepers/keepers.go | 18 +++++++++-- x/feepay/keeper/keeper.go | 63 +++++++++++++++++++++++++++++++++++++++ 2 files changed, 78 insertions(+), 3 deletions(-) create mode 100644 x/feepay/keeper/keeper.go diff --git a/app/keepers/keepers.go b/app/keepers/keepers.go index becd51912..d66a65184 100644 --- a/app/keepers/keepers.go +++ b/app/keepers/keepers.go @@ -83,7 +83,8 @@ import ( dripkeeper "github.com/CosmosContracts/juno/v17/x/drip/keeper" driptypes "github.com/CosmosContracts/juno/v17/x/drip/types" - feeprepaytypes "github.com/CosmosContracts/juno/v17/x/feepay/types" + feepaykeeper "github.com/CosmosContracts/juno/v17/x/feepay/keeper" + feepaytypes "github.com/CosmosContracts/juno/v17/x/feepay/types" feesharekeeper "github.com/CosmosContracts/juno/v17/x/feeshare/keeper" feesharetypes "github.com/CosmosContracts/juno/v17/x/feeshare/types" "github.com/CosmosContracts/juno/v17/x/globalfee" @@ -123,7 +124,7 @@ var maccPerms = map[string][]string{ tokenfactorytypes.ModuleName: {authtypes.Minter, authtypes.Burner}, globalfee.ModuleName: nil, buildertypes.ModuleName: nil, - feeprepaytypes.ModuleName: nil, + feepaytypes.ModuleName: nil, } type AppKeepers struct { @@ -155,6 +156,7 @@ type AppKeepers struct { AuthzKeeper authzkeeper.Keeper FeeGrantKeeper feegrantkeeper.Keeper NFTKeeper nftkeeper.Keeper + FeePayKeeper feepaykeeper.Keeper FeeShareKeeper feesharekeeper.Keeper GlobalFeeKeeper globalfeekeeper.Keeper ContractKeeper *wasmkeeper.PermissionedKeeper @@ -541,6 +543,16 @@ func NewAppKeepers( wasmOpts..., ) + appKeepers.FeePayKeeper = feepaykeeper.NewKeeper( + appKeepers.keys[feepaytypes.StoreKey], + appCodec, + appKeepers.BankKeeper, + appKeepers.WasmKeeper, + appKeepers.AccountKeeper, + authtypes.FeeCollectorName, + govModAddress, + ) + appKeepers.FeeShareKeeper = feesharekeeper.NewKeeper( appKeepers.keys[feesharetypes.StoreKey], appCodec, @@ -694,7 +706,7 @@ func BlockedAddresses() map[string]bool { // allow the following addresses to receive funds delete(modAccAddrs, authtypes.NewModuleAddress(govtypes.ModuleName).String()) - delete(modAccAddrs, authtypes.NewModuleAddress(feeprepaytypes.ModuleName).String()) + delete(modAccAddrs, authtypes.NewModuleAddress(feepaytypes.ModuleName).String()) return modAccAddrs } diff --git a/x/feepay/keeper/keeper.go b/x/feepay/keeper/keeper.go new file mode 100644 index 000000000..0d2a86330 --- /dev/null +++ b/x/feepay/keeper/keeper.go @@ -0,0 +1,63 @@ +package keeper + +import ( + "fmt" + + wasmkeeper "github.com/CosmWasm/wasmd/x/wasm/keeper" + + "github.com/cometbft/cometbft/libs/log" + + "github.com/cosmos/cosmos-sdk/codec" + storetypes "github.com/cosmos/cosmos-sdk/store/types" + sdk "github.com/cosmos/cosmos-sdk/types" + + revtypes "github.com/CosmosContracts/juno/v17/x/feeshare/types" +) + +// Keeper of this module maintains collections of feeshares for contracts +// registered to receive transaction fees. +type Keeper struct { + storeKey storetypes.StoreKey + cdc codec.BinaryCodec + + bankKeeper revtypes.BankKeeper + wasmKeeper wasmkeeper.Keeper + accountKeeper revtypes.AccountKeeper + + feeCollectorName string + + // the address capable of executing a MsgUpdateParams message. Typically, this + // should be the x/gov module account. + authority string +} + +// NewKeeper creates new instances of the fees Keeper +func NewKeeper( + storeKey storetypes.StoreKey, + cdc codec.BinaryCodec, + bk revtypes.BankKeeper, + wk wasmkeeper.Keeper, + ak revtypes.AccountKeeper, + feeCollector string, + authority string, +) Keeper { + return Keeper{ + storeKey: storeKey, + cdc: cdc, + bankKeeper: bk, + wasmKeeper: wk, + accountKeeper: ak, + feeCollectorName: feeCollector, + authority: authority, + } +} + +// GetAuthority returns the x/feeshare module's authority. +func (k Keeper) GetAuthority() string { + return k.authority +} + +// Logger returns a module-specific logger. +func (k Keeper) Logger(ctx sdk.Context) log.Logger { + return ctx.Logger().With("module", fmt.Sprintf("x/%s", revtypes.ModuleName)) +} From 71d6de91a711d89092e8e4360ece159d2a400738 Mon Sep 17 00:00:00 2001 From: Reece Williams Date: Tue, 29 Aug 2023 17:36:32 -0500 Subject: [PATCH 10/79] Add example contract and script for fee pay --- scripts/feepay.sh | 20 ++++++++++++++++++++ scripts/fpexample.wasm | Bin 0 -> 141386 bytes 2 files changed, 20 insertions(+) create mode 100644 scripts/feepay.sh create mode 100644 scripts/fpexample.wasm diff --git a/scripts/feepay.sh b/scripts/feepay.sh new file mode 100644 index 000000000..6f758964a --- /dev/null +++ b/scripts/feepay.sh @@ -0,0 +1,20 @@ +# Script to upload a contract to the chain +# Run this in the root of the directly. Cltr + alt + space can be used to run a command in VSCode terminal + +CONTRACT_FILE=scripts/fpexample.wasm +JUNOD_NODE=http://localhost:26657 + +# only run this 1 time per chain start. + +junod tx wasm store $CONTRACT_FILE --from juno1 --gas 2000000 -y --chain-id=local-1 --fees=75000ujuno +# Code id from THis is 1 - it is in the above Txhash, just hardcoding since we only need to upload once + +# instantiate and get an address +junod tx wasm instantiate 1 '{}' --from juno1 --label "test" --gas 2000000 -y --chain-id=local-1 --fees=75000ujuno --no-admin + +# execute on the contract +CONTRACT_ADDR=juno14hj2tavq8fpesdwxxcu44rty3hh90vhujrvcmstl4zr3txmfvw9skjuwg8 +junod tx wasm execute $CONTRACT_ADDR '{"increment":{}}' --gas 2000000 -y --chain-id=local-1 --fees=75000ujuno --from=juno1 + +# Query to ensure it went through, else you need to junod q tx from the above command +junod q wasm contract-state smart $CONTRACT_ADDR '{"get_config":{}}' --chain-id=local-1 \ No newline at end of file diff --git a/scripts/fpexample.wasm b/scripts/fpexample.wasm new file mode 100644 index 0000000000000000000000000000000000000000..e2d99f71c55b2204fd7e9867e1e45447f107e987 GIT binary patch literal 141386 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 literal 0 HcmV?d00001 From 81730afcd0259684bcd9735f28440a0a2c5ffdf4 Mon Sep 17 00:00:00 2001 From: Reece Williams Date: Tue, 29 Aug 2023 19:23:06 -0500 Subject: [PATCH 11/79] fix errors --- x/feepay/ante/dedcuct_fee.go | 18 ++++++++++-------- 1 file changed, 10 insertions(+), 8 deletions(-) diff --git a/x/feepay/ante/dedcuct_fee.go b/x/feepay/ante/dedcuct_fee.go index b30dcdce2..3fa592400 100644 --- a/x/feepay/ante/dedcuct_fee.go +++ b/x/feepay/ante/dedcuct_fee.go @@ -4,6 +4,7 @@ import ( "fmt" "math" + errorsmod "cosmossdk.io/errors" sdkmath "cosmossdk.io/math" feeprepaytypes "github.com/CosmosContracts/juno/v17/x/feepay/types" sdk "github.com/cosmos/cosmos-sdk/types" @@ -47,11 +48,12 @@ func NewDeductFeeDecorator(ak ante.AccountKeeper, bk bankkeeper.Keeper, fk ante. func (dfd DeductFeeDecorator) AnteHandle(ctx sdk.Context, tx sdk.Tx, simulate bool, next sdk.AnteHandler) (sdk.Context, error) { feeTx, ok := tx.(sdk.FeeTx) if !ok { - return ctx, sdkerrors.Wrap(sdkerrors.ErrTxDecode, "Tx must be a FeeTx") + // return ctx, errorsmod.Wrap(sdkerrors.ErrTxDecode, "Tx must be a FeeTx") + return ctx, errorsmod.Wrap(sdkerrors.ErrTxDecode, "Tx must be a FeeTx") } if !simulate && ctx.BlockHeight() > 0 && feeTx.GetGas() == 0 { - return ctx, sdkerrors.Wrap(sdkerrors.ErrInvalidGasLimit, "must provide positive gas") + return ctx, errorsmod.Wrap(sdkerrors.ErrInvalidGasLimit, "must provide positive gas") } var ( @@ -78,7 +80,7 @@ func (dfd DeductFeeDecorator) AnteHandle(ctx sdk.Context, tx sdk.Tx, simulate bo func (dfd DeductFeeDecorator) checkDeductFee(ctx sdk.Context, sdkTx sdk.Tx, fee sdk.Coins) error { feeTx, ok := sdkTx.(sdk.FeeTx) if !ok { - return sdkerrors.Wrap(sdkerrors.ErrTxDecode, "Tx must be a FeeTx") + return errorsmod.Wrap(sdkerrors.ErrTxDecode, "Tx must be a FeeTx") } if addr := dfd.accountKeeper.GetModuleAddress(types.FeeCollectorName); addr == nil { @@ -97,7 +99,7 @@ func (dfd DeductFeeDecorator) checkDeductFee(ctx sdk.Context, sdkTx sdk.Tx, fee } else if !feeGranter.Equals(feePayer) { err := dfd.feegrantKeeper.UseGrantedFees(ctx, feeGranter, feePayer, fee, sdkTx.GetMsgs()) if err != nil { - return sdkerrors.Wrapf(err, "%s does not allow to pay fees for %s", feeGranter, feePayer) + return errorsmod.Wrapf(err, "%s does not allow to pay fees for %s", feeGranter, feePayer) } } @@ -153,13 +155,13 @@ func HandleZeroFees(keeper bankkeeper.Keeper, ctx sdk.Context, deductFeesFromAcc // DeductFees deducts fees from the given account. func DeductFees(bankKeeper types.BankKeeper, ctx sdk.Context, acc types.AccountI, fees sdk.Coins) error { if !fees.IsValid() { - return sdkerrors.Wrapf(sdkerrors.ErrInsufficientFee, "invalid fee amount: %s", fees) + return errorsmod.Wrapf(sdkerrors.ErrInsufficientFee, "invalid fee amount: %s", fees) } // TODO: if 0 fees are sent, then the module account needs to pay it. (prepay module) ELSE have the standard user err := bankKeeper.SendCoinsFromAccountToModule(ctx, acc.GetAddress(), types.FeeCollectorName, fees) if err != nil { - return sdkerrors.Wrapf(sdkerrors.ErrInsufficientFunds, err.Error()) + return errorsmod.Wrapf(sdkerrors.ErrInsufficientFunds, err.Error()) } return nil @@ -169,7 +171,7 @@ func DeductFees(bankKeeper types.BankKeeper, ctx sdk.Context, acc types.AccountI func checkTxFeeWithValidatorMinGasPrices(ctx sdk.Context, tx sdk.Tx) (sdk.Coins, int64, error) { feeTx, ok := tx.(sdk.FeeTx) if !ok { - return nil, 0, sdkerrors.Wrap(sdkerrors.ErrTxDecode, "Tx must be a FeeTx") + return nil, 0, errorsmod.Wrap(sdkerrors.ErrTxDecode, "Tx must be a FeeTx") } feeCoins := feeTx.GetFee() @@ -192,7 +194,7 @@ func checkTxFeeWithValidatorMinGasPrices(ctx sdk.Context, tx sdk.Tx) (sdk.Coins, } if !feeCoins.IsAnyGTE(requiredFees) { - return nil, 0, sdkerrors.Wrapf(sdkerrors.ErrInsufficientFee, "insufficient fees; got: %s required: %s", feeCoins, requiredFees) + return nil, 0, errorsmod.Wrapf(sdkerrors.ErrInsufficientFee, "insufficient fees; got: %s required: %s", feeCoins, requiredFees) } } } From 2f0d2020842d81a9a0c4b1450790d963fb6128b8 Mon Sep 17 00:00:00 2001 From: Joel Smith Date: Tue, 29 Aug 2023 20:21:48 -0500 Subject: [PATCH 12/79] Hook Keeper Into Ante, Start Work on Proto (copy from FeeShare) --- app/ante.go | 4 +- app/app.go | 1 + proto/juno/feepay/v1/feepay.proto | 19 + proto/juno/feepay/v1/genesis.proto | 31 + proto/juno/feepay/v1/query.proto | 97 +++ proto/juno/feepay/v1/tx.proto | 61 ++ scripts/feepay.sh | 6 + x/feepay/ante/dedcuct_fee.go | 33 +- x/feepay/keeper/keeper.go | 14 + x/feepay/types/feepay.pb.go | 527 ++++++++++++++ x/feepay/types/genesis.pb.go | 507 ++++++++++++++ x/feepay/types/tx.pb.go | 1044 ++++++++++++++++++++++++++++ x/feepay/types/tx.pb.gw.go | 171 +++++ 13 files changed, 2504 insertions(+), 11 deletions(-) create mode 100644 proto/juno/feepay/v1/feepay.proto create mode 100644 proto/juno/feepay/v1/genesis.proto create mode 100644 proto/juno/feepay/v1/query.proto create mode 100644 proto/juno/feepay/v1/tx.proto create mode 100644 x/feepay/types/feepay.pb.go create mode 100644 x/feepay/types/genesis.pb.go create mode 100644 x/feepay/types/tx.pb.go create mode 100644 x/feepay/types/tx.pb.gw.go diff --git a/app/ante.go b/app/ante.go index 35a51326c..000f9e51d 100644 --- a/app/ante.go +++ b/app/ante.go @@ -21,6 +21,7 @@ import ( decorators "github.com/CosmosContracts/juno/v17/app/decorators" feepayante "github.com/CosmosContracts/juno/v17/x/feepay/ante" + feepaykeeper "github.com/CosmosContracts/juno/v17/x/feepay/keeper" feeshareante "github.com/CosmosContracts/juno/v17/x/feeshare/ante" feesharekeeper "github.com/CosmosContracts/juno/v17/x/feeshare/keeper" globalfeekeeper "github.com/CosmosContracts/juno/v17/x/globalfee/keeper" @@ -37,6 +38,7 @@ type HandlerOptions struct { GovKeeper govkeeper.Keeper IBCKeeper *ibckeeper.Keeper + FeePayKeeper feepaykeeper.Keeper FeeShareKeeper feesharekeeper.Keeper BankKeeper bankkeeper.Keeper TxCounterStoreKey storetypes.StoreKey @@ -87,7 +89,7 @@ func NewAnteHandler(options HandlerOptions) (sdk.AnteHandler, error) { ante.NewConsumeGasForTxSizeDecorator(options.AccountKeeper), // globalfeeante.NewFeeDecorator(options.BypassMinFeeMsgTypes, options.GlobalFeeKeeper, options.StakingKeeper, maxBypassMinFeeMsgGasUsage), // TODO: Has a minimum fee requrement check. So if 0 fees are passed, but 500 fee is required, it fails. // ante.NewDeductFeeDecorator(options.AccountKeeper, options.BankKeeper, options.FeegrantKeeper, options.TxFeeChecker), // OLD, new is in decorators - feepayante.NewDeductFeeDecorator(options.AccountKeeper, options.BankKeeper, options.FeegrantKeeper, options.TxFeeChecker), // TODO: look into to deduct fee from the module account + feepayante.NewDeductFeeDecorator(options.FeePayKeeper, options.AccountKeeper, options.BankKeeper, options.FeegrantKeeper, options.TxFeeChecker), // TODO: look into to deduct fee from the module account feeshareante.NewFeeSharePayoutDecorator(options.BankKeeper, options.FeeShareKeeper), // SetPubKeyDecorator must be called before all signature verification decorators ante.NewSetPubKeyDecorator(options.AccountKeeper), diff --git a/app/app.go b/app/app.go index 5c5f57742..0a6aa96c3 100644 --- a/app/app.go +++ b/app/app.go @@ -352,6 +352,7 @@ func New( GovKeeper: app.AppKeepers.GovKeeper, IBCKeeper: app.AppKeepers.IBCKeeper, + FeePayKeeper: app.AppKeepers.FeePayKeeper, FeeShareKeeper: app.AppKeepers.FeeShareKeeper, BankKeeper: app.AppKeepers.BankKeeper, TxCounterStoreKey: app.AppKeepers.GetKey(wasmtypes.StoreKey), diff --git a/proto/juno/feepay/v1/feepay.proto b/proto/juno/feepay/v1/feepay.proto new file mode 100644 index 000000000..4bbe3b764 --- /dev/null +++ b/proto/juno/feepay/v1/feepay.proto @@ -0,0 +1,19 @@ +syntax = "proto3"; +package juno.feepay.v1; + +option go_package = "github.com/CosmosContracts/juno/x/feepay/types"; + +// FeeShare defines an instance that organizes fee distribution conditions for +// the owner of a given smart contract +message FeePayContract { + string contract_address = 1; + // balance of the contract (ledger balance) uint64 + // limit per wallet uint64 + +} + +message FeePayUserUsage { + // not used as a Tx, just a storage device + string user_address = 1; + uint64 num_uses = 2; +} diff --git a/proto/juno/feepay/v1/genesis.proto b/proto/juno/feepay/v1/genesis.proto new file mode 100644 index 000000000..064e8ba44 --- /dev/null +++ b/proto/juno/feepay/v1/genesis.proto @@ -0,0 +1,31 @@ +syntax = "proto3"; +package juno.feepay.v1; + +import "juno/feepay/v1/feepay.proto"; +import "gogoproto/gogo.proto"; +option go_package = "github.com/CosmosContracts/juno/x/feepay/types"; + +// GenesisState defines the module's genesis state. +message GenesisState { + // params are the feeshare module parameters + Params params = 1 [ (gogoproto.nullable) = false ]; + + repeated FeePayContract fee_contract = 2 [ (gogoproto.nullable) = false ]; +} + +// Params defines the feeshare module params +message Params { + // // enable_feeshare defines a parameter to enable the feeshare module + // bool enable_fee_share = 1; + // // developer_shares defines the proportion of the transaction fees to be + // // distributed to the registered contract owner + // string developer_shares = 2 [ + // (gogoproto.customtype) = "github.com/cosmos/cosmos-sdk/types.Dec", + // (gogoproto.nullable) = false + // ]; + // // allowed_denoms defines the list of denoms that are allowed to be paid to + // // the contract withdraw addresses. If said denom is not in the list, the fees + // // will ONLY be sent to the community pool. + // // If this list is empty, all denoms are allowed. + // repeated string allowed_denoms = 3; +} diff --git a/proto/juno/feepay/v1/query.proto b/proto/juno/feepay/v1/query.proto new file mode 100644 index 000000000..2468c42e2 --- /dev/null +++ b/proto/juno/feepay/v1/query.proto @@ -0,0 +1,97 @@ +syntax = "proto3"; +package juno.feepay.v1; + +import "cosmos/base/query/v1beta1/pagination.proto"; +import "juno/feepay/v1/genesis.proto"; +import "juno/feepay/v1/feepay.proto"; +import "gogoproto/gogo.proto"; +import "google/api/annotations.proto"; + +option go_package = "github.com/CosmosContracts/juno/x/feepay/types"; + +// Query defines the gRPC querier service. +service Query { + // FeeShares retrieves all registered FeeShares + rpc FeePrepays(QueryFeeSharesRequest) returns (QueryFeeSharesResponse) { + option (google.api.http).get = "/juno/feepay/v1/feepay"; + } + + // Params retrieves the FeeShare module params + rpc Params(QueryParamsRequest) returns (QueryParamsResponse) { + option (google.api.http).get = "/juno/feeshare/v1/params"; + } +} + +// QueryFeeSharesRequest is the request type for the Query/FeeShares RPC method. +message QueryFeeSharesRequest { + // pagination defines an optional pagination for the request. + cosmos.base.query.v1beta1.PageRequest pagination = 1; +} + +// QueryFeeSharesResponse is the response type for the Query/FeeShares RPC +// method. +message QueryFeeSharesResponse { + // FeeShare is a slice of all stored Reveneue + repeated FeeShare feeshare = 1 [ (gogoproto.nullable) = false ]; + // pagination defines the pagination in the response. + cosmos.base.query.v1beta1.PageResponse pagination = 2; +} + +// QueryFeeShareRequest is the request type for the Query/FeeShare RPC method. +message QueryFeeShareRequest { + // contract_address of a registered contract in bech32 format + string contract_address = 1; +} + +// QueryFeeShareResponse is the response type for the Query/FeeShare RPC method. +message QueryFeeShareResponse { + // FeeShare is a stored Reveneue for the queried contract + FeeShare feeshare = 1 [ (gogoproto.nullable) = false ]; +} + +// QueryParamsRequest is the request type for the Query/Params RPC method. +message QueryParamsRequest {} + +// QueryParamsResponse is the response type for the Query/Params RPC method. +message QueryParamsResponse { + // params is the returned FeeShare parameter + Params params = 1 [ (gogoproto.nullable) = false ]; +} + +// QueryDeployerFeeSharesRequest is the request type for the +// Query/DeployerFeeShares RPC method. +message QueryDeployerFeeSharesRequest { + // deployer_address in bech32 format + string deployer_address = 1; + // pagination defines an optional pagination for the request. + cosmos.base.query.v1beta1.PageRequest pagination = 2; +} + +// QueryDeployerFeeSharesResponse is the response type for the +// Query/DeployerFeeShares RPC method. +message QueryDeployerFeeSharesResponse { + // contract_addresses is the slice of registered contract addresses for a + // deployer + repeated string contract_addresses = 1; + // pagination defines the pagination in the response. + cosmos.base.query.v1beta1.PageResponse pagination = 2; +} + +// QueryWithdrawerFeeSharesRequest is the request type for the +// Query/WithdrawerFeeShares RPC method. +message QueryWithdrawerFeeSharesRequest { + // withdrawer_address in bech32 format + string withdrawer_address = 1; + // pagination defines an optional pagination for the request. + cosmos.base.query.v1beta1.PageRequest pagination = 2; +} + +// QueryWithdrawerFeeSharesResponse is the response type for the +// Query/WithdrawerFeeShares RPC method. +message QueryWithdrawerFeeSharesResponse { + // contract_addresses is the slice of registered contract addresses for a + // withdrawer + repeated string contract_addresses = 1; + // pagination defines the pagination in the response. + cosmos.base.query.v1beta1.PageResponse pagination = 2; +} diff --git a/proto/juno/feepay/v1/tx.proto b/proto/juno/feepay/v1/tx.proto new file mode 100644 index 000000000..640e14893 --- /dev/null +++ b/proto/juno/feepay/v1/tx.proto @@ -0,0 +1,61 @@ +syntax = "proto3"; +package juno.feepay.v1; + +import "gogoproto/gogo.proto"; +import "google/api/annotations.proto"; +import "cosmos/msg/v1/msg.proto"; +import "cosmos_proto/cosmos.proto"; +import "juno/feepay/v1/genesis.proto"; +import "juno/feepay/v1/feepay.proto"; + +option go_package = "github.com/CosmosContracts/juno/x/feepay/types"; + +// Msg defines the fees Msg service. +service Msg { + // RegisterFeeShare registers a new contract for receiving transaction fees + rpc RegisterFeeShare(MsgRegisterFeeShare) + returns (MsgRegisterFeeShareResponse) { + option (google.api.http).post = "/juno/feepay/v1/tx/register"; + }; + + // Update the params of the module through gov v1 type. + rpc UpdateParams(MsgUpdateParams) returns (MsgUpdateParamsResponse); +} + +// MsgRegisterFeeShare defines a message that registers a FeeShare +message MsgRegisterFeeShare { + option (gogoproto.equal) = false; + // contract_address in bech32 format + string sender_address = 1; + // // deployer_address is the bech32 address of message sender. It must be the + // // same the contract's admin address + // string deployer_address = 2; + // // withdrawer_address is the bech32 address of account receiving the + // // transaction fees + // string withdrawer_address = 3; + FeePayContract contract = 2; +} + +// MsgRegisterFeeShareResponse defines the MsgRegisterFeeShare response type +message MsgRegisterFeeShareResponse {} + +// MsgUpdateParams is the Msg/UpdateParams request type. +// +// Since: cosmos-sdk 0.47 +message MsgUpdateParams { + option (cosmos.msg.v1.signer) = "authority"; + + // authority is the address that controls the module (defaults to x/gov unless overwritten). + string authority = 1 [(cosmos_proto.scalar) = "cosmos.AddressString"]; + + // params defines the x/feeshare parameters to update. + // + // NOTE: All parameters must be supplied. + Params params = 2 [(gogoproto.nullable) = false]; +} + +// MsgUpdateParamsResponse defines the response structure for executing a +// MsgUpdateParams message. +// +// Since: cosmos-sdk 0.47 +message MsgUpdateParamsResponse {} \ No newline at end of file diff --git a/scripts/feepay.sh b/scripts/feepay.sh index 6f758964a..39d86c734 100644 --- a/scripts/feepay.sh +++ b/scripts/feepay.sh @@ -9,12 +9,18 @@ JUNOD_NODE=http://localhost:26657 junod tx wasm store $CONTRACT_FILE --from juno1 --gas 2000000 -y --chain-id=local-1 --fees=75000ujuno # Code id from THis is 1 - it is in the above Txhash, just hardcoding since we only need to upload once +sleep 6 + # instantiate and get an address junod tx wasm instantiate 1 '{}' --from juno1 --label "test" --gas 2000000 -y --chain-id=local-1 --fees=75000ujuno --no-admin +sleep 6 + # execute on the contract CONTRACT_ADDR=juno14hj2tavq8fpesdwxxcu44rty3hh90vhujrvcmstl4zr3txmfvw9skjuwg8 junod tx wasm execute $CONTRACT_ADDR '{"increment":{}}' --gas 2000000 -y --chain-id=local-1 --fees=75000ujuno --from=juno1 +sleep 6 + # Query to ensure it went through, else you need to junod q tx from the above command junod q wasm contract-state smart $CONTRACT_ADDR '{"get_config":{}}' --chain-id=local-1 \ No newline at end of file diff --git a/x/feepay/ante/dedcuct_fee.go b/x/feepay/ante/dedcuct_fee.go index b30dcdce2..95783379d 100644 --- a/x/feepay/ante/dedcuct_fee.go +++ b/x/feepay/ante/dedcuct_fee.go @@ -5,7 +5,9 @@ import ( "math" sdkmath "cosmossdk.io/math" - feeprepaytypes "github.com/CosmosContracts/juno/v17/x/feepay/types" + wasmtypes "github.com/CosmWasm/wasmd/x/wasm/types" + feepaykeeper "github.com/CosmosContracts/juno/v17/x/feepay/keeper" + feepaytypes "github.com/CosmosContracts/juno/v17/x/feepay/types" sdk "github.com/cosmos/cosmos-sdk/types" sdkerrors "github.com/cosmos/cosmos-sdk/types/errors" "github.com/cosmos/cosmos-sdk/x/auth/ante" @@ -22,6 +24,7 @@ import ( // message transactions with no provided fee. If they correspond to a registered FeePay Contract, the FeePay // module will cover the cost of the fee (if the balance permits). type DeductFeeDecorator struct { + feepayKeeper feepaykeeper.Keeper accountKeeper ante.AccountKeeper bankKeeper bankkeeper.Keeper feegrantKeeper ante.FeegrantKeeper @@ -31,15 +34,16 @@ type DeductFeeDecorator struct { txFeeChecker ante.TxFeeChecker } -func NewDeductFeeDecorator(ak ante.AccountKeeper, bk bankkeeper.Keeper, fk ante.FeegrantKeeper, tfc ante.TxFeeChecker) DeductFeeDecorator { +func NewDeductFeeDecorator(fpk feepaykeeper.Keeper, ak ante.AccountKeeper, bk bankkeeper.Keeper, fgk ante.FeegrantKeeper, tfc ante.TxFeeChecker) DeductFeeDecorator { if tfc == nil { tfc = checkTxFeeWithValidatorMinGasPrices } return DeductFeeDecorator{ + feepayKeeper: fpk, accountKeeper: ak, bankKeeper: bk, - feegrantKeeper: fk, + feegrantKeeper: fgk, txFeeChecker: tfc, } } @@ -109,14 +113,20 @@ func (dfd DeductFeeDecorator) checkDeductFee(ctx sdk.Context, sdkTx sdk.Tx, fee return sdkerrors.ErrUnknownAddress.Wrapf("fee payer address: %s does not exist", deductFeesFrom) } - // deduct the fees - if !fee.IsZero() { - err := DeductFees(dfd.bankKeeper, ctx, deductFeesFromAcc, fee) + msg := sdkTx.GetMsgs()[0] + _, isCWMsg := msg.(*wasmtypes.MsgExecuteContract) + + if fee.IsZero() && len(sdkTx.GetMsgs()) == 1 && isCWMsg { + err := HandleZeroFees(dfd.bankKeeper, ctx, deductFeesFromAcc, fee) if err != nil { return err } } else { - HandleZeroFees(dfd.bankKeeper, ctx, deductFeesFromAcc, fee) + // Std sdk route + err := DeductFees(dfd.bankKeeper, ctx, deductFeesFromAcc, fee) + if err != nil { + return err + } } events := sdk.Events{ @@ -132,7 +142,7 @@ func (dfd DeductFeeDecorator) checkDeductFee(ctx sdk.Context, sdkTx sdk.Tx, fee } // Handle zero fee transactions for fee prepay module -func HandleZeroFees(keeper bankkeeper.Keeper, ctx sdk.Context, deductFeesFromAcc types.AccountI, fee sdk.Coins) { +func HandleZeroFees(keeper bankkeeper.Keeper, ctx sdk.Context, deductFeesFromAcc types.AccountI, fee sdk.Coins) error { ctx.Logger().Error("HandleZeroFees", "Starting", true) payment := sdk.NewCoins(sdk.NewCoin("ujuno", sdk.NewDec(500_000).RoundInt())) @@ -140,14 +150,17 @@ func HandleZeroFees(keeper bankkeeper.Keeper, ctx sdk.Context, deductFeesFromAcc ctx.Logger().Error("HandleZeroFees", "Payment", payment) // keeper.SendCoinsFromModuleToAccount(ctx, "feeprepay", deductFeesFromAcc.GetAddress(), payment) - err := keeper.SendCoinsFromModuleToModule(ctx, feeprepaytypes.ModuleName, types.FeeCollectorName, payment) + err := keeper.SendCoinsFromModuleToModule(ctx, feepaytypes.ModuleName, types.FeeCollectorName, payment) // Handle error if err != nil { ctx.Logger().Error("HandleZeroFees", "Error transfering funds from module to module", err) + return sdkerrors.ErrInsufficientFunds.Wrapf("error transfering funds from module to module: %s", err) + // return nil } ctx.Logger().Error("HandleZeroFees", "Ending", true) + return nil } // DeductFees deducts fees from the given account. @@ -178,7 +191,7 @@ func checkTxFeeWithValidatorMinGasPrices(ctx sdk.Context, tx sdk.Tx) (sdk.Coins, // Ensure that the provided fees meet a minimum threshold for the validator, // if this is a CheckTx. This is only for local mempool purposes, and thus // is only ran on check tx. - if ctx.IsCheckTx() && !feeTx.GetFee().Empty() { + if ctx.IsCheckTx() && (!feeTx.GetFee().Empty() || len(tx.GetMsgs()) > 0) { minGasPrices := ctx.MinGasPrices() if !minGasPrices.IsZero() { requiredFees := make(sdk.Coins, len(minGasPrices)) diff --git a/x/feepay/keeper/keeper.go b/x/feepay/keeper/keeper.go index 0d2a86330..278500d90 100644 --- a/x/feepay/keeper/keeper.go +++ b/x/feepay/keeper/keeper.go @@ -61,3 +61,17 @@ func (k Keeper) GetAuthority() string { func (k Keeper) Logger(ctx sdk.Context) log.Logger { return ctx.Logger().With("module", fmt.Sprintf("x/%s", revtypes.ModuleName)) } + +// Check if a contract is associated with a FeePay contract +func (k Keeper) IsValidContract(ctx sdk.Context, contractAddr sdk.AccAddress) bool { + return true +} + +// FeeShare - how to do a map. store.Get() + +// KV +// -> KVs `string -> []bytes` +// Store users interactions on a contract -> int +// "user-interaction" < key +// "userAddr-contractAddr" -> []byte(1) +// feeshare.go < how to do kvs diff --git a/x/feepay/types/feepay.pb.go b/x/feepay/types/feepay.pb.go new file mode 100644 index 000000000..498ca3b0c --- /dev/null +++ b/x/feepay/types/feepay.pb.go @@ -0,0 +1,527 @@ +// Code generated by protoc-gen-gogo. DO NOT EDIT. +// source: juno/feepay/v1/feepay.proto + +package types + +import ( + fmt "fmt" + proto "github.com/cosmos/gogoproto/proto" + io "io" + math "math" + math_bits "math/bits" +) + +// 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 + +// FeeShare defines an instance that organizes fee distribution conditions for +// the owner of a given smart contract +type FeePayContract struct { + ContractAddress string `protobuf:"bytes,1,opt,name=contract_address,json=contractAddress,proto3" json:"contract_address,omitempty"` +} + +func (m *FeePayContract) Reset() { *m = FeePayContract{} } +func (m *FeePayContract) String() string { return proto.CompactTextString(m) } +func (*FeePayContract) ProtoMessage() {} +func (*FeePayContract) Descriptor() ([]byte, []int) { + return fileDescriptor_14ea6771eacbfed1, []int{0} +} +func (m *FeePayContract) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *FeePayContract) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_FeePayContract.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 *FeePayContract) XXX_Merge(src proto.Message) { + xxx_messageInfo_FeePayContract.Merge(m, src) +} +func (m *FeePayContract) XXX_Size() int { + return m.Size() +} +func (m *FeePayContract) XXX_DiscardUnknown() { + xxx_messageInfo_FeePayContract.DiscardUnknown(m) +} + +var xxx_messageInfo_FeePayContract proto.InternalMessageInfo + +func (m *FeePayContract) GetContractAddress() string { + if m != nil { + return m.ContractAddress + } + return "" +} + +type FeePayUserUsage struct { + // not used as a Tx, just a storage device + UserAddress string `protobuf:"bytes,1,opt,name=user_address,json=userAddress,proto3" json:"user_address,omitempty"` + NumUses uint64 `protobuf:"varint,2,opt,name=num_uses,json=numUses,proto3" json:"num_uses,omitempty"` +} + +func (m *FeePayUserUsage) Reset() { *m = FeePayUserUsage{} } +func (m *FeePayUserUsage) String() string { return proto.CompactTextString(m) } +func (*FeePayUserUsage) ProtoMessage() {} +func (*FeePayUserUsage) Descriptor() ([]byte, []int) { + return fileDescriptor_14ea6771eacbfed1, []int{1} +} +func (m *FeePayUserUsage) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *FeePayUserUsage) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_FeePayUserUsage.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 *FeePayUserUsage) XXX_Merge(src proto.Message) { + xxx_messageInfo_FeePayUserUsage.Merge(m, src) +} +func (m *FeePayUserUsage) XXX_Size() int { + return m.Size() +} +func (m *FeePayUserUsage) XXX_DiscardUnknown() { + xxx_messageInfo_FeePayUserUsage.DiscardUnknown(m) +} + +var xxx_messageInfo_FeePayUserUsage proto.InternalMessageInfo + +func (m *FeePayUserUsage) GetUserAddress() string { + if m != nil { + return m.UserAddress + } + return "" +} + +func (m *FeePayUserUsage) GetNumUses() uint64 { + if m != nil { + return m.NumUses + } + return 0 +} + +func init() { + proto.RegisterType((*FeePayContract)(nil), "juno.feepay.v1.FeePayContract") + proto.RegisterType((*FeePayUserUsage)(nil), "juno.feepay.v1.FeePayUserUsage") +} + +func init() { proto.RegisterFile("juno/feepay/v1/feepay.proto", fileDescriptor_14ea6771eacbfed1) } + +var fileDescriptor_14ea6771eacbfed1 = []byte{ + // 226 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xe2, 0x92, 0xce, 0x2a, 0xcd, 0xcb, + 0xd7, 0x4f, 0x4b, 0x4d, 0x2d, 0x48, 0xac, 0xd4, 0x2f, 0x33, 0x84, 0xb2, 0xf4, 0x0a, 0x8a, 0xf2, + 0x4b, 0xf2, 0x85, 0xf8, 0x40, 0x92, 0x7a, 0x50, 0xa1, 0x32, 0x43, 0x25, 0x6b, 0x2e, 0x3e, 0xb7, + 0xd4, 0xd4, 0x80, 0xc4, 0x4a, 0xe7, 0xfc, 0xbc, 0x92, 0xa2, 0xc4, 0xe4, 0x12, 0x21, 0x4d, 0x2e, + 0x81, 0x64, 0x28, 0x3b, 0x3e, 0x31, 0x25, 0xa5, 0x28, 0xb5, 0xb8, 0x58, 0x82, 0x51, 0x81, 0x51, + 0x83, 0x33, 0x88, 0x1f, 0x26, 0xee, 0x08, 0x11, 0x56, 0xf2, 0xe7, 0xe2, 0x87, 0x68, 0x0e, 0x2d, + 0x4e, 0x2d, 0x0a, 0x2d, 0x4e, 0x4c, 0x4f, 0x15, 0x52, 0xe4, 0xe2, 0x29, 0x2d, 0x4e, 0x2d, 0x42, + 0xd3, 0xc9, 0x0d, 0x12, 0x83, 0xea, 0x12, 0x92, 0xe4, 0xe2, 0xc8, 0x2b, 0xcd, 0x8d, 0x2f, 0x2d, + 0x4e, 0x2d, 0x96, 0x60, 0x52, 0x60, 0xd4, 0x60, 0x09, 0x62, 0xcf, 0x2b, 0xcd, 0x0d, 0x2d, 0x4e, + 0x2d, 0x76, 0xf2, 0x38, 0xf1, 0x48, 0x8e, 0xf1, 0xc2, 0x23, 0x39, 0xc6, 0x07, 0x8f, 0xe4, 0x18, + 0x27, 0x3c, 0x96, 0x63, 0xb8, 0xf0, 0x58, 0x8e, 0xe1, 0xc6, 0x63, 0x39, 0x86, 0x28, 0xbd, 0xf4, + 0xcc, 0x92, 0x8c, 0xd2, 0x24, 0xbd, 0xe4, 0xfc, 0x5c, 0x7d, 0xe7, 0xfc, 0xe2, 0xdc, 0xfc, 0x62, + 0x98, 0x83, 0x8b, 0xf5, 0xc1, 0xfe, 0xad, 0x80, 0xf9, 0xb8, 0xa4, 0xb2, 0x20, 0xb5, 0x38, 0x89, + 0x0d, 0xec, 0x5d, 0x63, 0x40, 0x00, 0x00, 0x00, 0xff, 0xff, 0x68, 0xa5, 0x09, 0x5f, 0x0d, 0x01, + 0x00, 0x00, +} + +func (m *FeePayContract) 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 *FeePayContract) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *FeePayContract) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + if len(m.ContractAddress) > 0 { + i -= len(m.ContractAddress) + copy(dAtA[i:], m.ContractAddress) + i = encodeVarintFeepay(dAtA, i, uint64(len(m.ContractAddress))) + i-- + dAtA[i] = 0xa + } + return len(dAtA) - i, nil +} + +func (m *FeePayUserUsage) 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 *FeePayUserUsage) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *FeePayUserUsage) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + if m.NumUses != 0 { + i = encodeVarintFeepay(dAtA, i, uint64(m.NumUses)) + i-- + dAtA[i] = 0x10 + } + if len(m.UserAddress) > 0 { + i -= len(m.UserAddress) + copy(dAtA[i:], m.UserAddress) + i = encodeVarintFeepay(dAtA, i, uint64(len(m.UserAddress))) + i-- + dAtA[i] = 0xa + } + return len(dAtA) - i, nil +} + +func encodeVarintFeepay(dAtA []byte, offset int, v uint64) int { + offset -= sovFeepay(v) + base := offset + for v >= 1<<7 { + dAtA[offset] = uint8(v&0x7f | 0x80) + v >>= 7 + offset++ + } + dAtA[offset] = uint8(v) + return base +} +func (m *FeePayContract) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + l = len(m.ContractAddress) + if l > 0 { + n += 1 + l + sovFeepay(uint64(l)) + } + return n +} + +func (m *FeePayUserUsage) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + l = len(m.UserAddress) + if l > 0 { + n += 1 + l + sovFeepay(uint64(l)) + } + if m.NumUses != 0 { + n += 1 + sovFeepay(uint64(m.NumUses)) + } + return n +} + +func sovFeepay(x uint64) (n int) { + return (math_bits.Len64(x|1) + 6) / 7 +} +func sozFeepay(x uint64) (n int) { + return sovFeepay(uint64((x << 1) ^ uint64((int64(x) >> 63)))) +} +func (m *FeePayContract) 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 ErrIntOverflowFeepay + } + 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: FeePayContract: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: FeePayContract: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field ContractAddress", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowFeepay + } + 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 ErrInvalidLengthFeepay + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthFeepay + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.ContractAddress = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + default: + iNdEx = preIndex + skippy, err := skipFeepay(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return ErrInvalidLengthFeepay + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func (m *FeePayUserUsage) 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 ErrIntOverflowFeepay + } + 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: FeePayUserUsage: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: FeePayUserUsage: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field UserAddress", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowFeepay + } + 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 ErrInvalidLengthFeepay + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthFeepay + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.UserAddress = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + case 2: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field NumUses", wireType) + } + m.NumUses = 0 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowFeepay + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + m.NumUses |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + default: + iNdEx = preIndex + skippy, err := skipFeepay(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return ErrInvalidLengthFeepay + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func skipFeepay(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, ErrIntOverflowFeepay + } + 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, ErrIntOverflowFeepay + } + 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, ErrIntOverflowFeepay + } + 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, ErrInvalidLengthFeepay + } + iNdEx += length + case 3: + depth++ + case 4: + if depth == 0 { + return 0, ErrUnexpectedEndOfGroupFeepay + } + depth-- + case 5: + iNdEx += 4 + default: + return 0, fmt.Errorf("proto: illegal wireType %d", wireType) + } + if iNdEx < 0 { + return 0, ErrInvalidLengthFeepay + } + if depth == 0 { + return iNdEx, nil + } + } + return 0, io.ErrUnexpectedEOF +} + +var ( + ErrInvalidLengthFeepay = fmt.Errorf("proto: negative length found during unmarshaling") + ErrIntOverflowFeepay = fmt.Errorf("proto: integer overflow") + ErrUnexpectedEndOfGroupFeepay = fmt.Errorf("proto: unexpected end of group") +) diff --git a/x/feepay/types/genesis.pb.go b/x/feepay/types/genesis.pb.go new file mode 100644 index 000000000..3caef7ab9 --- /dev/null +++ b/x/feepay/types/genesis.pb.go @@ -0,0 +1,507 @@ +// Code generated by protoc-gen-gogo. DO NOT EDIT. +// source: juno/feepay/v1/genesis.proto + +package types + +import ( + fmt "fmt" + _ "github.com/cosmos/gogoproto/gogoproto" + proto "github.com/cosmos/gogoproto/proto" + io "io" + math "math" + math_bits "math/bits" +) + +// 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 + +// GenesisState defines the module's genesis state. +type GenesisState struct { + // params are the feeshare module parameters + Params Params `protobuf:"bytes,1,opt,name=params,proto3" json:"params"` + FeeContract []FeePayContract `protobuf:"bytes,2,rep,name=fee_contract,json=feeContract,proto3" json:"fee_contract"` +} + +func (m *GenesisState) Reset() { *m = GenesisState{} } +func (m *GenesisState) String() string { return proto.CompactTextString(m) } +func (*GenesisState) ProtoMessage() {} +func (*GenesisState) Descriptor() ([]byte, []int) { + return fileDescriptor_ac1bd21601b5f553, []int{0} +} +func (m *GenesisState) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *GenesisState) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_GenesisState.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 *GenesisState) XXX_Merge(src proto.Message) { + xxx_messageInfo_GenesisState.Merge(m, src) +} +func (m *GenesisState) XXX_Size() int { + return m.Size() +} +func (m *GenesisState) XXX_DiscardUnknown() { + xxx_messageInfo_GenesisState.DiscardUnknown(m) +} + +var xxx_messageInfo_GenesisState proto.InternalMessageInfo + +func (m *GenesisState) GetParams() Params { + if m != nil { + return m.Params + } + return Params{} +} + +func (m *GenesisState) GetFeeContract() []FeePayContract { + if m != nil { + return m.FeeContract + } + return nil +} + +// Params defines the feeshare module params +type Params struct { +} + +func (m *Params) Reset() { *m = Params{} } +func (m *Params) String() string { return proto.CompactTextString(m) } +func (*Params) ProtoMessage() {} +func (*Params) Descriptor() ([]byte, []int) { + return fileDescriptor_ac1bd21601b5f553, []int{1} +} +func (m *Params) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *Params) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_Params.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 *Params) XXX_Merge(src proto.Message) { + xxx_messageInfo_Params.Merge(m, src) +} +func (m *Params) XXX_Size() int { + return m.Size() +} +func (m *Params) XXX_DiscardUnknown() { + xxx_messageInfo_Params.DiscardUnknown(m) +} + +var xxx_messageInfo_Params proto.InternalMessageInfo + +func init() { + proto.RegisterType((*GenesisState)(nil), "juno.feepay.v1.GenesisState") + proto.RegisterType((*Params)(nil), "juno.feepay.v1.Params") +} + +func init() { proto.RegisterFile("juno/feepay/v1/genesis.proto", fileDescriptor_ac1bd21601b5f553) } + +var fileDescriptor_ac1bd21601b5f553 = []byte{ + // 246 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xe2, 0x92, 0xc9, 0x2a, 0xcd, 0xcb, + 0xd7, 0x4f, 0x4b, 0x4d, 0x2d, 0x48, 0xac, 0xd4, 0x2f, 0x33, 0xd4, 0x4f, 0x4f, 0xcd, 0x4b, 0x2d, + 0xce, 0x2c, 0xd6, 0x2b, 0x28, 0xca, 0x2f, 0xc9, 0x17, 0xe2, 0x03, 0xc9, 0xea, 0x41, 0x64, 0xf5, + 0xca, 0x0c, 0xa5, 0xa4, 0xd1, 0x54, 0x43, 0x65, 0xc0, 0x8a, 0xa5, 0x44, 0xd2, 0xf3, 0xd3, 0xf3, + 0xc1, 0x4c, 0x7d, 0x10, 0x0b, 0x22, 0xaa, 0xd4, 0xcb, 0xc8, 0xc5, 0xe3, 0x0e, 0x31, 0x34, 0xb8, + 0x24, 0xb1, 0x24, 0x55, 0xc8, 0x84, 0x8b, 0xad, 0x20, 0xb1, 0x28, 0x31, 0xb7, 0x58, 0x82, 0x51, + 0x81, 0x51, 0x83, 0xdb, 0x48, 0x4c, 0x0f, 0xd5, 0x12, 0xbd, 0x00, 0xb0, 0xac, 0x13, 0xcb, 0x89, + 0x7b, 0xf2, 0x0c, 0x41, 0x50, 0xb5, 0x42, 0xee, 0x5c, 0x3c, 0x69, 0xa9, 0xa9, 0xf1, 0xc9, 0xf9, + 0x79, 0x25, 0x45, 0x89, 0xc9, 0x25, 0x12, 0x4c, 0x0a, 0xcc, 0x1a, 0xdc, 0x46, 0x72, 0xe8, 0x7a, + 0xdd, 0x52, 0x53, 0x03, 0x12, 0x2b, 0x9d, 0xa1, 0xaa, 0xa0, 0x66, 0x70, 0xa7, 0xa5, 0xa6, 0xc2, + 0x84, 0x94, 0x38, 0xb8, 0xd8, 0xa0, 0x16, 0x78, 0x9c, 0x78, 0x24, 0xc7, 0x78, 0xe1, 0x91, 0x1c, + 0xe3, 0x83, 0x47, 0x72, 0x8c, 0x13, 0x1e, 0xcb, 0x31, 0x5c, 0x78, 0x2c, 0xc7, 0x70, 0xe3, 0xb1, + 0x1c, 0x43, 0x94, 0x5e, 0x7a, 0x66, 0x49, 0x46, 0x69, 0x92, 0x5e, 0x72, 0x7e, 0xae, 0xbe, 0x73, + 0x7e, 0x71, 0x6e, 0x7e, 0x31, 0x4c, 0x7b, 0xb1, 0x3e, 0x38, 0x04, 0x2a, 0x60, 0x61, 0x50, 0x52, + 0x59, 0x90, 0x5a, 0x9c, 0xc4, 0x06, 0xf6, 0xaa, 0x31, 0x20, 0x00, 0x00, 0xff, 0xff, 0xc2, 0xf7, + 0x70, 0x02, 0x4d, 0x01, 0x00, 0x00, +} + +func (m *GenesisState) 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 *GenesisState) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *GenesisState) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + if len(m.FeeContract) > 0 { + for iNdEx := len(m.FeeContract) - 1; iNdEx >= 0; iNdEx-- { + { + size, err := m.FeeContract[iNdEx].MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarintGenesis(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0x12 + } + } + { + size, err := m.Params.MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarintGenesis(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0xa + return len(dAtA) - i, nil +} + +func (m *Params) 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 *Params) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *Params) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + return len(dAtA) - i, nil +} + +func encodeVarintGenesis(dAtA []byte, offset int, v uint64) int { + offset -= sovGenesis(v) + base := offset + for v >= 1<<7 { + dAtA[offset] = uint8(v&0x7f | 0x80) + v >>= 7 + offset++ + } + dAtA[offset] = uint8(v) + return base +} +func (m *GenesisState) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + l = m.Params.Size() + n += 1 + l + sovGenesis(uint64(l)) + if len(m.FeeContract) > 0 { + for _, e := range m.FeeContract { + l = e.Size() + n += 1 + l + sovGenesis(uint64(l)) + } + } + return n +} + +func (m *Params) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + return n +} + +func sovGenesis(x uint64) (n int) { + return (math_bits.Len64(x|1) + 6) / 7 +} +func sozGenesis(x uint64) (n int) { + return sovGenesis(uint64((x << 1) ^ uint64((int64(x) >> 63)))) +} +func (m *GenesisState) 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 ErrIntOverflowGenesis + } + 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: GenesisState: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: GenesisState: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Params", 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 + } + if err := m.Params.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + case 2: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field FeeContract", 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.FeeContract = append(m.FeeContract, FeePayContract{}) + if err := m.FeeContract[len(m.FeeContract)-1].Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + default: + iNdEx = preIndex + skippy, err := skipGenesis(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return ErrInvalidLengthGenesis + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func (m *Params) 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 ErrIntOverflowGenesis + } + 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: Params: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: Params: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + default: + iNdEx = preIndex + skippy, err := skipGenesis(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return ErrInvalidLengthGenesis + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func skipGenesis(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, ErrIntOverflowGenesis + } + 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, ErrIntOverflowGenesis + } + 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, ErrIntOverflowGenesis + } + 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, ErrInvalidLengthGenesis + } + iNdEx += length + case 3: + depth++ + case 4: + if depth == 0 { + return 0, ErrUnexpectedEndOfGroupGenesis + } + depth-- + case 5: + iNdEx += 4 + default: + return 0, fmt.Errorf("proto: illegal wireType %d", wireType) + } + if iNdEx < 0 { + return 0, ErrInvalidLengthGenesis + } + if depth == 0 { + return iNdEx, nil + } + } + return 0, io.ErrUnexpectedEOF +} + +var ( + ErrInvalidLengthGenesis = fmt.Errorf("proto: negative length found during unmarshaling") + ErrIntOverflowGenesis = fmt.Errorf("proto: integer overflow") + ErrUnexpectedEndOfGroupGenesis = fmt.Errorf("proto: unexpected end of group") +) diff --git a/x/feepay/types/tx.pb.go b/x/feepay/types/tx.pb.go new file mode 100644 index 000000000..fdcc903d2 --- /dev/null +++ b/x/feepay/types/tx.pb.go @@ -0,0 +1,1044 @@ +// Code generated by protoc-gen-gogo. DO NOT EDIT. +// source: juno/feepay/v1/tx.proto + +package types + +import ( + context "context" + fmt "fmt" + _ "github.com/cosmos/cosmos-proto" + _ "github.com/cosmos/cosmos-sdk/types/msgservice" + _ "github.com/cosmos/gogoproto/gogoproto" + grpc1 "github.com/cosmos/gogoproto/grpc" + proto "github.com/cosmos/gogoproto/proto" + _ "google.golang.org/genproto/googleapis/api/annotations" + grpc "google.golang.org/grpc" + codes "google.golang.org/grpc/codes" + status "google.golang.org/grpc/status" + io "io" + math "math" + math_bits "math/bits" +) + +// 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 + +// MsgRegisterFeeShare defines a message that registers a FeeShare +type MsgRegisterFeeShare struct { + // contract_address in bech32 format + ContractAddress string `protobuf:"bytes,1,opt,name=contract_address,json=contractAddress,proto3" json:"contract_address,omitempty"` + // deployer_address is the bech32 address of message sender. It must be the + // same the contract's admin address + DeployerAddress string `protobuf:"bytes,2,opt,name=deployer_address,json=deployerAddress,proto3" json:"deployer_address,omitempty"` + // withdrawer_address is the bech32 address of account receiving the + // transaction fees + WithdrawerAddress string `protobuf:"bytes,3,opt,name=withdrawer_address,json=withdrawerAddress,proto3" json:"withdrawer_address,omitempty"` +} + +func (m *MsgRegisterFeeShare) Reset() { *m = MsgRegisterFeeShare{} } +func (m *MsgRegisterFeeShare) String() string { return proto.CompactTextString(m) } +func (*MsgRegisterFeeShare) ProtoMessage() {} +func (*MsgRegisterFeeShare) Descriptor() ([]byte, []int) { + return fileDescriptor_d739bd30c8846fd5, []int{0} +} +func (m *MsgRegisterFeeShare) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *MsgRegisterFeeShare) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_MsgRegisterFeeShare.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 *MsgRegisterFeeShare) XXX_Merge(src proto.Message) { + xxx_messageInfo_MsgRegisterFeeShare.Merge(m, src) +} +func (m *MsgRegisterFeeShare) XXX_Size() int { + return m.Size() +} +func (m *MsgRegisterFeeShare) XXX_DiscardUnknown() { + xxx_messageInfo_MsgRegisterFeeShare.DiscardUnknown(m) +} + +var xxx_messageInfo_MsgRegisterFeeShare proto.InternalMessageInfo + +func (m *MsgRegisterFeeShare) GetContractAddress() string { + if m != nil { + return m.ContractAddress + } + return "" +} + +func (m *MsgRegisterFeeShare) GetDeployerAddress() string { + if m != nil { + return m.DeployerAddress + } + return "" +} + +func (m *MsgRegisterFeeShare) GetWithdrawerAddress() string { + if m != nil { + return m.WithdrawerAddress + } + return "" +} + +// MsgRegisterFeeShareResponse defines the MsgRegisterFeeShare response type +type MsgRegisterFeeShareResponse struct { +} + +func (m *MsgRegisterFeeShareResponse) Reset() { *m = MsgRegisterFeeShareResponse{} } +func (m *MsgRegisterFeeShareResponse) String() string { return proto.CompactTextString(m) } +func (*MsgRegisterFeeShareResponse) ProtoMessage() {} +func (*MsgRegisterFeeShareResponse) Descriptor() ([]byte, []int) { + return fileDescriptor_d739bd30c8846fd5, []int{1} +} +func (m *MsgRegisterFeeShareResponse) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *MsgRegisterFeeShareResponse) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_MsgRegisterFeeShareResponse.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 *MsgRegisterFeeShareResponse) XXX_Merge(src proto.Message) { + xxx_messageInfo_MsgRegisterFeeShareResponse.Merge(m, src) +} +func (m *MsgRegisterFeeShareResponse) XXX_Size() int { + return m.Size() +} +func (m *MsgRegisterFeeShareResponse) XXX_DiscardUnknown() { + xxx_messageInfo_MsgRegisterFeeShareResponse.DiscardUnknown(m) +} + +var xxx_messageInfo_MsgRegisterFeeShareResponse proto.InternalMessageInfo + +// MsgUpdateParams is the Msg/UpdateParams request type. +// +// Since: cosmos-sdk 0.47 +type MsgUpdateParams struct { + // authority is the address that controls the module (defaults to x/gov unless overwritten). + Authority string `protobuf:"bytes,1,opt,name=authority,proto3" json:"authority,omitempty"` + // params defines the x/feeshare parameters to update. + // + // NOTE: All parameters must be supplied. + Params Params `protobuf:"bytes,2,opt,name=params,proto3" json:"params"` +} + +func (m *MsgUpdateParams) Reset() { *m = MsgUpdateParams{} } +func (m *MsgUpdateParams) String() string { return proto.CompactTextString(m) } +func (*MsgUpdateParams) ProtoMessage() {} +func (*MsgUpdateParams) Descriptor() ([]byte, []int) { + return fileDescriptor_d739bd30c8846fd5, []int{2} +} +func (m *MsgUpdateParams) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *MsgUpdateParams) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_MsgUpdateParams.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 *MsgUpdateParams) XXX_Merge(src proto.Message) { + xxx_messageInfo_MsgUpdateParams.Merge(m, src) +} +func (m *MsgUpdateParams) XXX_Size() int { + return m.Size() +} +func (m *MsgUpdateParams) XXX_DiscardUnknown() { + xxx_messageInfo_MsgUpdateParams.DiscardUnknown(m) +} + +var xxx_messageInfo_MsgUpdateParams proto.InternalMessageInfo + +func (m *MsgUpdateParams) GetAuthority() string { + if m != nil { + return m.Authority + } + return "" +} + +func (m *MsgUpdateParams) GetParams() Params { + if m != nil { + return m.Params + } + return Params{} +} + +// MsgUpdateParamsResponse defines the response structure for executing a +// MsgUpdateParams message. +// +// Since: cosmos-sdk 0.47 +type MsgUpdateParamsResponse struct { +} + +func (m *MsgUpdateParamsResponse) Reset() { *m = MsgUpdateParamsResponse{} } +func (m *MsgUpdateParamsResponse) String() string { return proto.CompactTextString(m) } +func (*MsgUpdateParamsResponse) ProtoMessage() {} +func (*MsgUpdateParamsResponse) Descriptor() ([]byte, []int) { + return fileDescriptor_d739bd30c8846fd5, []int{3} +} +func (m *MsgUpdateParamsResponse) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *MsgUpdateParamsResponse) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_MsgUpdateParamsResponse.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 *MsgUpdateParamsResponse) XXX_Merge(src proto.Message) { + xxx_messageInfo_MsgUpdateParamsResponse.Merge(m, src) +} +func (m *MsgUpdateParamsResponse) XXX_Size() int { + return m.Size() +} +func (m *MsgUpdateParamsResponse) XXX_DiscardUnknown() { + xxx_messageInfo_MsgUpdateParamsResponse.DiscardUnknown(m) +} + +var xxx_messageInfo_MsgUpdateParamsResponse proto.InternalMessageInfo + +func init() { + proto.RegisterType((*MsgRegisterFeeShare)(nil), "juno.feepay.v1.MsgRegisterFeeShare") + proto.RegisterType((*MsgRegisterFeeShareResponse)(nil), "juno.feepay.v1.MsgRegisterFeeShareResponse") + proto.RegisterType((*MsgUpdateParams)(nil), "juno.feepay.v1.MsgUpdateParams") + proto.RegisterType((*MsgUpdateParamsResponse)(nil), "juno.feepay.v1.MsgUpdateParamsResponse") +} + +func init() { proto.RegisterFile("juno/feepay/v1/tx.proto", fileDescriptor_d739bd30c8846fd5) } + +var fileDescriptor_d739bd30c8846fd5 = []byte{ + // 474 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x8c, 0x92, 0xcf, 0x6a, 0x14, 0x41, + 0x10, 0xc6, 0xa7, 0x93, 0x10, 0x48, 0x2b, 0x49, 0x1c, 0x83, 0x9b, 0x6c, 0xcc, 0xac, 0x4c, 0x0e, + 0xfe, 0x23, 0xd3, 0x24, 0x8a, 0x87, 0xdc, 0xdc, 0x80, 0x78, 0x59, 0x90, 0x09, 0x82, 0x78, 0x09, + 0x9d, 0x9d, 0xb2, 0x77, 0x24, 0x33, 0xdd, 0x74, 0xf5, 0x26, 0xd9, 0x6b, 0x6e, 0x9e, 0x14, 0x7c, + 0x81, 0x3c, 0x82, 0x07, 0x1f, 0x22, 0xc7, 0xa0, 0x17, 0x4f, 0x22, 0xbb, 0x82, 0x82, 0x2f, 0x21, + 0x33, 0xdd, 0x93, 0x4d, 0x76, 0x17, 0xf4, 0x36, 0x53, 0xdf, 0xaf, 0xbf, 0xfa, 0xba, 0xba, 0x68, + 0xed, 0x6d, 0x37, 0x97, 0xec, 0x0d, 0x80, 0xe2, 0x3d, 0x76, 0xb8, 0xc9, 0xcc, 0x71, 0xa4, 0xb4, + 0x34, 0xd2, 0x9f, 0x2f, 0x84, 0xc8, 0x0a, 0xd1, 0xe1, 0x66, 0x7d, 0x49, 0x48, 0x21, 0x4b, 0x89, + 0x15, 0x5f, 0x96, 0xaa, 0xdf, 0x16, 0x52, 0x8a, 0x03, 0x60, 0x5c, 0xa5, 0x8c, 0xe7, 0xb9, 0x34, + 0xdc, 0xa4, 0x32, 0x47, 0xa7, 0xd6, 0xda, 0x12, 0x33, 0x89, 0x2c, 0x43, 0x51, 0x78, 0x67, 0x28, + 0x9c, 0xb0, 0x62, 0x85, 0x3d, 0xeb, 0x67, 0x7f, 0x2a, 0xc7, 0x91, 0x40, 0x02, 0x72, 0xc0, 0xd4, + 0xa9, 0xe1, 0x29, 0xa1, 0x37, 0x5b, 0x28, 0x62, 0x10, 0x29, 0x1a, 0xd0, 0xcf, 0x00, 0x76, 0x3b, + 0x5c, 0x83, 0x7f, 0x9f, 0x2e, 0xb6, 0x65, 0x6e, 0x34, 0x6f, 0x9b, 0x3d, 0x9e, 0x24, 0x1a, 0x10, + 0x97, 0xc9, 0x1d, 0x72, 0x6f, 0x2e, 0x5e, 0xa8, 0xea, 0x4f, 0x6d, 0xb9, 0x40, 0x13, 0x50, 0x07, + 0xb2, 0x07, 0xfa, 0x02, 0x9d, 0xb2, 0x68, 0x55, 0xaf, 0xd0, 0x0d, 0xea, 0x1f, 0xa5, 0xa6, 0x93, + 0x68, 0x7e, 0x74, 0x09, 0x9e, 0x2e, 0xe1, 0x1b, 0x43, 0xc5, 0xe1, 0xdb, 0x33, 0xbf, 0x4f, 0x1b, + 0x5e, 0xb8, 0x46, 0x57, 0x27, 0x24, 0x8c, 0x01, 0x95, 0xcc, 0x11, 0xc2, 0xf7, 0x84, 0x2e, 0xb4, + 0x50, 0xbc, 0x54, 0x09, 0x37, 0xf0, 0x82, 0x6b, 0x9e, 0xa1, 0xff, 0x84, 0xce, 0xf1, 0xae, 0xe9, + 0x48, 0x9d, 0x9a, 0x9e, 0x8d, 0xdd, 0x5c, 0xfe, 0xf2, 0x79, 0x63, 0xc9, 0x0d, 0xc6, 0xf9, 0xef, + 0x1a, 0x9d, 0xe6, 0x22, 0x1e, 0xa2, 0xfe, 0x63, 0x3a, 0xab, 0x4a, 0x87, 0xf2, 0x02, 0xd7, 0xb6, + 0x6e, 0x45, 0x57, 0x1f, 0x2d, 0xb2, 0xfe, 0xcd, 0x99, 0xb3, 0xef, 0x0d, 0x2f, 0x76, 0xec, 0xf6, + 0xfc, 0xc9, 0xaf, 0x4f, 0x0f, 0x86, 0x2e, 0xe1, 0x0a, 0xad, 0x8d, 0x04, 0xaa, 0xc2, 0x6e, 0xfd, + 0x21, 0x74, 0xba, 0x85, 0xc2, 0x7f, 0x47, 0xe8, 0xe2, 0xd8, 0xcc, 0xd7, 0x47, 0xbb, 0x4d, 0xb8, + 0x76, 0xfd, 0xe1, 0x7f, 0x40, 0x17, 0xb3, 0x59, 0x3f, 0xf9, 0xfa, 0xf3, 0xe3, 0xd4, 0x5a, 0xb8, + 0xca, 0xc6, 0xb6, 0x92, 0x69, 0x77, 0xc8, 0x7f, 0x45, 0xaf, 0x5f, 0x19, 0x5e, 0x63, 0x42, 0x87, + 0xcb, 0x40, 0xfd, 0xee, 0x3f, 0x80, 0xaa, 0x7d, 0xf3, 0xf9, 0x59, 0x3f, 0x20, 0xe7, 0xfd, 0x80, + 0xfc, 0xe8, 0x07, 0xe4, 0xc3, 0x20, 0xf0, 0xce, 0x07, 0x81, 0xf7, 0x6d, 0x10, 0x78, 0xaf, 0x23, + 0x91, 0x9a, 0x4e, 0x77, 0x3f, 0x6a, 0xcb, 0x8c, 0xed, 0x94, 0x8f, 0xb2, 0xe3, 0xb6, 0x0a, 0x6d, + 0xd4, 0xe3, 0x2a, 0xac, 0xe9, 0x29, 0xc0, 0xfd, 0xd9, 0x72, 0x5b, 0x1f, 0xfd, 0x0d, 0x00, 0x00, + 0xff, 0xff, 0x11, 0xc7, 0x08, 0xcc, 0x5e, 0x03, 0x00, 0x00, +} + +// Reference imports to suppress errors if they are not otherwise used. +var _ context.Context +var _ grpc.ClientConn + +// This is a compile-time assertion to ensure that this generated file +// is compatible with the grpc package it is being compiled against. +const _ = grpc.SupportPackageIsVersion4 + +// MsgClient is the client API for Msg service. +// +// 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 { + // RegisterFeeShare registers a new contract for receiving transaction fees + RegisterFeeShare(ctx context.Context, in *MsgRegisterFeeShare, opts ...grpc.CallOption) (*MsgRegisterFeeShareResponse, error) + // Update the params of the module through gov v1 type. + UpdateParams(ctx context.Context, in *MsgUpdateParams, opts ...grpc.CallOption) (*MsgUpdateParamsResponse, error) +} + +type msgClient struct { + cc grpc1.ClientConn +} + +func NewMsgClient(cc grpc1.ClientConn) MsgClient { + return &msgClient{cc} +} + +func (c *msgClient) RegisterFeeShare(ctx context.Context, in *MsgRegisterFeeShare, opts ...grpc.CallOption) (*MsgRegisterFeeShareResponse, error) { + out := new(MsgRegisterFeeShareResponse) + err := c.cc.Invoke(ctx, "/juno.feepay.v1.Msg/RegisterFeeShare", in, out, opts...) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *msgClient) UpdateParams(ctx context.Context, in *MsgUpdateParams, opts ...grpc.CallOption) (*MsgUpdateParamsResponse, error) { + out := new(MsgUpdateParamsResponse) + err := c.cc.Invoke(ctx, "/juno.feepay.v1.Msg/UpdateParams", in, out, opts...) + if err != nil { + return nil, err + } + return out, nil +} + +// MsgServer is the server API for Msg service. +type MsgServer interface { + // RegisterFeeShare registers a new contract for receiving transaction fees + RegisterFeeShare(context.Context, *MsgRegisterFeeShare) (*MsgRegisterFeeShareResponse, error) + // Update the params of the module through gov v1 type. + UpdateParams(context.Context, *MsgUpdateParams) (*MsgUpdateParamsResponse, error) +} + +// UnimplementedMsgServer can be embedded to have forward compatible implementations. +type UnimplementedMsgServer struct { +} + +func (*UnimplementedMsgServer) RegisterFeeShare(ctx context.Context, req *MsgRegisterFeeShare) (*MsgRegisterFeeShareResponse, error) { + return nil, status.Errorf(codes.Unimplemented, "method RegisterFeeShare not implemented") +} +func (*UnimplementedMsgServer) UpdateParams(ctx context.Context, req *MsgUpdateParams) (*MsgUpdateParamsResponse, error) { + return nil, status.Errorf(codes.Unimplemented, "method UpdateParams not implemented") +} + +func RegisterMsgServer(s grpc1.Server, srv MsgServer) { + s.RegisterService(&_Msg_serviceDesc, srv) +} + +func _Msg_RegisterFeeShare_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(MsgRegisterFeeShare) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(MsgServer).RegisterFeeShare(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: "/juno.feepay.v1.Msg/RegisterFeeShare", + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(MsgServer).RegisterFeeShare(ctx, req.(*MsgRegisterFeeShare)) + } + return interceptor(ctx, in, info, handler) +} + +func _Msg_UpdateParams_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(MsgUpdateParams) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(MsgServer).UpdateParams(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: "/juno.feepay.v1.Msg/UpdateParams", + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(MsgServer).UpdateParams(ctx, req.(*MsgUpdateParams)) + } + return interceptor(ctx, in, info, handler) +} + +var _Msg_serviceDesc = grpc.ServiceDesc{ + ServiceName: "juno.feepay.v1.Msg", + HandlerType: (*MsgServer)(nil), + Methods: []grpc.MethodDesc{ + { + MethodName: "RegisterFeeShare", + Handler: _Msg_RegisterFeeShare_Handler, + }, + { + MethodName: "UpdateParams", + Handler: _Msg_UpdateParams_Handler, + }, + }, + Streams: []grpc.StreamDesc{}, + Metadata: "juno/feepay/v1/tx.proto", +} + +func (m *MsgRegisterFeeShare) 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 *MsgRegisterFeeShare) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *MsgRegisterFeeShare) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + if len(m.WithdrawerAddress) > 0 { + i -= len(m.WithdrawerAddress) + copy(dAtA[i:], m.WithdrawerAddress) + i = encodeVarintTx(dAtA, i, uint64(len(m.WithdrawerAddress))) + i-- + dAtA[i] = 0x1a + } + if len(m.DeployerAddress) > 0 { + i -= len(m.DeployerAddress) + copy(dAtA[i:], m.DeployerAddress) + i = encodeVarintTx(dAtA, i, uint64(len(m.DeployerAddress))) + i-- + dAtA[i] = 0x12 + } + if len(m.ContractAddress) > 0 { + i -= len(m.ContractAddress) + copy(dAtA[i:], m.ContractAddress) + i = encodeVarintTx(dAtA, i, uint64(len(m.ContractAddress))) + i-- + dAtA[i] = 0xa + } + return len(dAtA) - i, nil +} + +func (m *MsgRegisterFeeShareResponse) 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 *MsgRegisterFeeShareResponse) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *MsgRegisterFeeShareResponse) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + return len(dAtA) - i, nil +} + +func (m *MsgUpdateParams) 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 *MsgUpdateParams) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *MsgUpdateParams) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + { + size, err := m.Params.MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarintTx(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0x12 + if len(m.Authority) > 0 { + i -= len(m.Authority) + copy(dAtA[i:], m.Authority) + i = encodeVarintTx(dAtA, i, uint64(len(m.Authority))) + i-- + dAtA[i] = 0xa + } + return len(dAtA) - i, nil +} + +func (m *MsgUpdateParamsResponse) 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 *MsgUpdateParamsResponse) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *MsgUpdateParamsResponse) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + return len(dAtA) - i, nil +} + +func encodeVarintTx(dAtA []byte, offset int, v uint64) int { + offset -= sovTx(v) + base := offset + for v >= 1<<7 { + dAtA[offset] = uint8(v&0x7f | 0x80) + v >>= 7 + offset++ + } + dAtA[offset] = uint8(v) + return base +} +func (m *MsgRegisterFeeShare) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + l = len(m.ContractAddress) + if l > 0 { + n += 1 + l + sovTx(uint64(l)) + } + l = len(m.DeployerAddress) + if l > 0 { + n += 1 + l + sovTx(uint64(l)) + } + l = len(m.WithdrawerAddress) + if l > 0 { + n += 1 + l + sovTx(uint64(l)) + } + return n +} + +func (m *MsgRegisterFeeShareResponse) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + return n +} + +func (m *MsgUpdateParams) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + l = len(m.Authority) + if l > 0 { + n += 1 + l + sovTx(uint64(l)) + } + l = m.Params.Size() + n += 1 + l + sovTx(uint64(l)) + return n +} + +func (m *MsgUpdateParamsResponse) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + return n +} + +func sovTx(x uint64) (n int) { + return (math_bits.Len64(x|1) + 6) / 7 +} +func sozTx(x uint64) (n int) { + return sovTx(uint64((x << 1) ^ uint64((int64(x) >> 63)))) +} +func (m *MsgRegisterFeeShare) 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: MsgRegisterFeeShare: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: MsgRegisterFeeShare: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field ContractAddress", 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.ContractAddress = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + case 2: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field DeployerAddress", 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.DeployerAddress = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + case 3: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field WithdrawerAddress", 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.WithdrawerAddress = string(dAtA[iNdEx:postIndex]) + 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 *MsgRegisterFeeShareResponse) 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: MsgRegisterFeeShareResponse: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: MsgRegisterFeeShareResponse: 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 *MsgUpdateParams) 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: MsgUpdateParams: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: MsgUpdateParams: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Authority", 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.Authority = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + case 2: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Params", 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 err := m.Params.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 *MsgUpdateParamsResponse) 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: MsgUpdateParamsResponse: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: MsgUpdateParamsResponse: 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 skipTx(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, ErrIntOverflowTx + } + 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, ErrIntOverflowTx + } + 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, ErrIntOverflowTx + } + 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, ErrInvalidLengthTx + } + iNdEx += length + case 3: + depth++ + case 4: + if depth == 0 { + return 0, ErrUnexpectedEndOfGroupTx + } + depth-- + case 5: + iNdEx += 4 + default: + return 0, fmt.Errorf("proto: illegal wireType %d", wireType) + } + if iNdEx < 0 { + return 0, ErrInvalidLengthTx + } + if depth == 0 { + return iNdEx, nil + } + } + return 0, io.ErrUnexpectedEOF +} + +var ( + ErrInvalidLengthTx = fmt.Errorf("proto: negative length found during unmarshaling") + ErrIntOverflowTx = fmt.Errorf("proto: integer overflow") + ErrUnexpectedEndOfGroupTx = fmt.Errorf("proto: unexpected end of group") +) diff --git a/x/feepay/types/tx.pb.gw.go b/x/feepay/types/tx.pb.gw.go new file mode 100644 index 000000000..f6442a242 --- /dev/null +++ b/x/feepay/types/tx.pb.gw.go @@ -0,0 +1,171 @@ +// Code generated by protoc-gen-grpc-gateway. DO NOT EDIT. +// source: juno/feepay/v1/tx.proto + +/* +Package types is a reverse proxy. + +It translates gRPC into RESTful JSON APIs. +*/ +package types + +import ( + "context" + "io" + "net/http" + + "github.com/golang/protobuf/descriptor" + "github.com/golang/protobuf/proto" + "github.com/grpc-ecosystem/grpc-gateway/runtime" + "github.com/grpc-ecosystem/grpc-gateway/utilities" + "google.golang.org/grpc" + "google.golang.org/grpc/codes" + "google.golang.org/grpc/grpclog" + "google.golang.org/grpc/metadata" + "google.golang.org/grpc/status" +) + +// Suppress "imported and not used" errors +var _ codes.Code +var _ io.Reader +var _ status.Status +var _ = runtime.String +var _ = utilities.NewDoubleArray +var _ = descriptor.ForMessage +var _ = metadata.Join + +var ( + filter_Msg_RegisterFeeShare_0 = &utilities.DoubleArray{Encoding: map[string]int{}, Base: []int(nil), Check: []int(nil)} +) + +func request_Msg_RegisterFeeShare_0(ctx context.Context, marshaler runtime.Marshaler, client MsgClient, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) { + var protoReq MsgRegisterFeeShare + 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_Msg_RegisterFeeShare_0); err != nil { + return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err) + } + + msg, err := client.RegisterFeeShare(ctx, &protoReq, grpc.Header(&metadata.HeaderMD), grpc.Trailer(&metadata.TrailerMD)) + return msg, metadata, err + +} + +func local_request_Msg_RegisterFeeShare_0(ctx context.Context, marshaler runtime.Marshaler, server MsgServer, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) { + var protoReq MsgRegisterFeeShare + 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_Msg_RegisterFeeShare_0); err != nil { + return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err) + } + + msg, err := server.RegisterFeeShare(ctx, &protoReq) + return msg, metadata, err + +} + +// RegisterMsgHandlerServer registers the http handlers for service Msg to "mux". +// UnaryRPC :call MsgServer directly. +// StreamingRPC :currently unsupported pending https://github.com/grpc/grpc-go/issues/906. +// Note that using this registration option will cause many gRPC library features to stop working. Consider using RegisterMsgHandlerFromEndpoint instead. +func RegisterMsgHandlerServer(ctx context.Context, mux *runtime.ServeMux, server MsgServer) error { + + mux.Handle("POST", pattern_Msg_RegisterFeeShare_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_Msg_RegisterFeeShare_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_Msg_RegisterFeeShare_0(ctx, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...) + + }) + + return nil +} + +// RegisterMsgHandlerFromEndpoint is same as RegisterMsgHandler but +// automatically dials to "endpoint" and closes the connection when "ctx" gets done. +func RegisterMsgHandlerFromEndpoint(ctx context.Context, mux *runtime.ServeMux, endpoint string, opts []grpc.DialOption) (err error) { + conn, err := grpc.Dial(endpoint, opts...) + if err != nil { + return err + } + defer func() { + if err != nil { + if cerr := conn.Close(); cerr != nil { + grpclog.Infof("Failed to close conn to %s: %v", endpoint, cerr) + } + return + } + go func() { + <-ctx.Done() + if cerr := conn.Close(); cerr != nil { + grpclog.Infof("Failed to close conn to %s: %v", endpoint, cerr) + } + }() + }() + + return RegisterMsgHandler(ctx, mux, conn) +} + +// RegisterMsgHandler registers the http handlers for service Msg to "mux". +// The handlers forward requests to the grpc endpoint over "conn". +func RegisterMsgHandler(ctx context.Context, mux *runtime.ServeMux, conn *grpc.ClientConn) error { + return RegisterMsgHandlerClient(ctx, mux, NewMsgClient(conn)) +} + +// RegisterMsgHandlerClient registers the http handlers for service Msg +// to "mux". The handlers forward requests to the grpc endpoint over the given implementation of "MsgClient". +// Note: the gRPC framework executes interceptors within the gRPC handler. If the passed in "MsgClient" +// doesn't go through the normal gRPC flow (creating a gRPC client etc.) then it will be up to the passed in +// "MsgClient" to call the correct interceptors. +func RegisterMsgHandlerClient(ctx context.Context, mux *runtime.ServeMux, client MsgClient) error { + + mux.Handle("POST", pattern_Msg_RegisterFeeShare_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_Msg_RegisterFeeShare_0(rctx, inboundMarshaler, client, req, pathParams) + ctx = runtime.NewServerMetadataContext(ctx, md) + if err != nil { + runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) + return + } + + forward_Msg_RegisterFeeShare_0(ctx, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...) + + }) + + return nil +} + +var ( + pattern_Msg_RegisterFeeShare_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2, 2, 3, 2, 4}, []string{"juno", "feepay", "v1", "tx", "register"}, "", runtime.AssumeColonVerbOpt(false))) +) + +var ( + forward_Msg_RegisterFeeShare_0 = runtime.ForwardResponseMessage +) From 4a2d7937ab0991a041cbf1bf4f89e6792cbcb29f Mon Sep 17 00:00:00 2001 From: Joel Smith Date: Thu, 31 Aug 2023 22:27:50 -0500 Subject: [PATCH 13/79] Register FeePay Module, Add Tx for Registering Contract, Update Ante to Handle FeePay Contracts, Etc. --- app/ante.go | 2 +- app/keepers/keys.go | 2 + app/modules.go | 8 + proto/juno/feepay/v1/feepay.proto | 23 ++- proto/juno/feepay/v1/query.proto | 150 +++++++-------- proto/juno/feepay/v1/tx.proto | 25 ++- x/feepay/ante/dedcuct_fee.go | 68 +++++-- x/feepay/client/cli/tx.go | 76 ++++++++ x/feepay/genesis.go | 22 +++ x/feepay/keeper/keeper.go | 29 ++- x/feepay/keeper/msg_server.go | 33 ++++ x/feepay/keeper/params.go | 32 ++++ x/feepay/module.go | 206 ++++++++++++++++++++ x/feepay/types/codec.go | 60 ++++++ x/feepay/types/feepay.pb.go | 191 +++++++++++++------ x/feepay/types/genesis.go | 21 +++ x/feepay/types/msg.go | 60 ++++++ x/feepay/types/query.pb.go | 44 +++++ x/feepay/types/tx.pb.go | 303 +++++++++++++----------------- x/feepay/types/tx.pb.gw.go | 34 ++-- 20 files changed, 1023 insertions(+), 366 deletions(-) create mode 100644 x/feepay/client/cli/tx.go create mode 100644 x/feepay/genesis.go create mode 100644 x/feepay/keeper/msg_server.go create mode 100644 x/feepay/keeper/params.go create mode 100644 x/feepay/module.go create mode 100644 x/feepay/types/codec.go create mode 100644 x/feepay/types/genesis.go create mode 100644 x/feepay/types/msg.go create mode 100644 x/feepay/types/query.pb.go diff --git a/app/ante.go b/app/ante.go index 000f9e51d..b91522092 100644 --- a/app/ante.go +++ b/app/ante.go @@ -89,7 +89,7 @@ func NewAnteHandler(options HandlerOptions) (sdk.AnteHandler, error) { ante.NewConsumeGasForTxSizeDecorator(options.AccountKeeper), // globalfeeante.NewFeeDecorator(options.BypassMinFeeMsgTypes, options.GlobalFeeKeeper, options.StakingKeeper, maxBypassMinFeeMsgGasUsage), // TODO: Has a minimum fee requrement check. So if 0 fees are passed, but 500 fee is required, it fails. // ante.NewDeductFeeDecorator(options.AccountKeeper, options.BankKeeper, options.FeegrantKeeper, options.TxFeeChecker), // OLD, new is in decorators - feepayante.NewDeductFeeDecorator(options.FeePayKeeper, options.AccountKeeper, options.BankKeeper, options.FeegrantKeeper, options.TxFeeChecker), // TODO: look into to deduct fee from the module account + feepayante.NewDeductFeeDecorator(options.FeePayKeeper, options.GlobalFeeKeeper, options.AccountKeeper, options.BankKeeper, options.FeegrantKeeper, options.TxFeeChecker), // TODO: look into to deduct fee from the module account feeshareante.NewFeeSharePayoutDecorator(options.BankKeeper, options.FeeShareKeeper), // SetPubKeyDecorator must be called before all signature verification decorators ante.NewSetPubKeyDecorator(options.AccountKeeper), diff --git a/app/keepers/keys.go b/app/keepers/keys.go index 62f3476ab..bde992cac 100644 --- a/app/keepers/keys.go +++ b/app/keepers/keys.go @@ -32,6 +32,7 @@ import ( upgradetypes "github.com/cosmos/cosmos-sdk/x/upgrade/types" driptypes "github.com/CosmosContracts/juno/v17/x/drip/types" + feepaytypes "github.com/CosmosContracts/juno/v17/x/feepay/types" feesharetypes "github.com/CosmosContracts/juno/v17/x/feeshare/types" globalfeetypes "github.com/CosmosContracts/juno/v17/x/globalfee/types" minttypes "github.com/CosmosContracts/juno/v17/x/mint/types" @@ -53,6 +54,7 @@ func (appKeepers *AppKeepers) GenerateKeys() { packetforwardtypes.StoreKey, ibchookstypes.StoreKey, tokenfactorytypes.StoreKey, + feepaytypes.StoreKey, feesharetypes.StoreKey, globalfeetypes.StoreKey, buildertypes.StoreKey, diff --git a/app/modules.go b/app/modules.go index e085d2124..d9ed90cf3 100644 --- a/app/modules.go +++ b/app/modules.go @@ -62,6 +62,8 @@ import ( encparams "github.com/CosmosContracts/juno/v17/app/params" "github.com/CosmosContracts/juno/v17/x/drip" driptypes "github.com/CosmosContracts/juno/v17/x/drip/types" + feepay "github.com/CosmosContracts/juno/v17/x/feepay" + feepaytypes "github.com/CosmosContracts/juno/v17/x/feepay/types" feeshare "github.com/CosmosContracts/juno/v17/x/feeshare" feesharetypes "github.com/CosmosContracts/juno/v17/x/feeshare/types" "github.com/CosmosContracts/juno/v17/x/globalfee" @@ -104,6 +106,7 @@ var ModuleBasics = module.NewBasicManager( feegrantmodule.AppModuleBasic{}, tokenfactory.AppModuleBasic{}, drip.AppModuleBasic{}, + feepay.AppModuleBasic{}, feeshare.AppModuleBasic{}, globalfee.AppModuleBasic{}, ibc_hooks.AppModuleBasic{}, @@ -147,6 +150,7 @@ func appModules( ibcfee.NewAppModule(app.AppKeepers.IBCFeeKeeper), tokenfactory.NewAppModule(app.AppKeepers.TokenFactoryKeeper, app.AppKeepers.AccountKeeper, app.AppKeepers.BankKeeper, app.GetSubspace(tokenfactorytypes.ModuleName)), globalfee.NewAppModule(appCodec, app.AppKeepers.GlobalFeeKeeper, bondDenom), + feepay.NewAppModule(app.AppKeepers.FeePayKeeper, app.AppKeepers.AccountKeeper, app.GetSubspace(feepaytypes.ModuleName)), feeshare.NewAppModule(app.AppKeepers.FeeShareKeeper, app.AppKeepers.AccountKeeper, app.GetSubspace(feesharetypes.ModuleName)), wasm.NewAppModule(appCodec, &app.AppKeepers.WasmKeeper, app.AppKeepers.StakingKeeper, app.AppKeepers.AccountKeeper, app.AppKeepers.BankKeeper, app.MsgServiceRouter(), app.GetSubspace(wasmtypes.ModuleName)), ica.NewAppModule(&app.AppKeepers.ICAControllerKeeper, &app.AppKeepers.ICAHostKeeper), @@ -187,6 +191,7 @@ func simulationModules( wasm.NewAppModule(appCodec, &app.AppKeepers.WasmKeeper, app.AppKeepers.StakingKeeper, app.AppKeepers.AccountKeeper, app.AppKeepers.BankKeeper, app.MsgServiceRouter(), app.GetSubspace(wasmtypes.ModuleName)), ibc.NewAppModule(app.AppKeepers.IBCKeeper), transfer.NewAppModule(app.AppKeepers.TransferKeeper), + feepay.NewAppModule(app.AppKeepers.FeePayKeeper, app.AppKeepers.AccountKeeper, app.GetSubspace(feepaytypes.ModuleName)), feeshare.NewAppModule(app.AppKeepers.FeeShareKeeper, app.AppKeepers.AccountKeeper, app.GetSubspace(feesharetypes.ModuleName)), ibcfee.NewAppModule(app.AppKeepers.IBCFeeKeeper), } @@ -224,6 +229,7 @@ func orderBeginBlockers() []string { icqtypes.ModuleName, tokenfactorytypes.ModuleName, driptypes.ModuleName, + feepaytypes.ModuleName, feesharetypes.ModuleName, globalfee.ModuleName, wasmtypes.ModuleName, @@ -261,6 +267,7 @@ func orderEndBlockers() []string { icqtypes.ModuleName, tokenfactorytypes.ModuleName, driptypes.ModuleName, + feepaytypes.ModuleName, feesharetypes.ModuleName, globalfee.ModuleName, wasmtypes.ModuleName, @@ -298,6 +305,7 @@ func orderInitBlockers() []string { icqtypes.ModuleName, tokenfactorytypes.ModuleName, driptypes.ModuleName, + feepaytypes.ModuleName, feesharetypes.ModuleName, globalfee.ModuleName, wasmtypes.ModuleName, diff --git a/proto/juno/feepay/v1/feepay.proto b/proto/juno/feepay/v1/feepay.proto index 4bbe3b764..fe5c2b786 100644 --- a/proto/juno/feepay/v1/feepay.proto +++ b/proto/juno/feepay/v1/feepay.proto @@ -3,17 +3,22 @@ package juno.feepay.v1; option go_package = "github.com/CosmosContracts/juno/x/feepay/types"; -// FeeShare defines an instance that organizes fee distribution conditions for -// the owner of a given smart contract +// This defines the address, balance, and wallet limit +// of a fee pay contract. message FeePayContract { + // The address of the contract. string contract_address = 1; - // balance of the contract (ledger balance) uint64 - // limit per wallet uint64 - + // The ledger balance of the contract. + uint64 balance = 2; + // The number of times a wallet may interact with the contract. + uint64 limit = 3; } -message FeePayUserUsage { - // not used as a Tx, just a storage device - string user_address = 1; - uint64 num_uses = 2; +// This object is used to store the number of times a wallet has +// interacted with a contract. +message FeePayWalletUsage { + // The wallet address. + string wallet_address = 1; + // The number of uses corresponding to a wallet. + uint64 uses = 2; } diff --git a/proto/juno/feepay/v1/query.proto b/proto/juno/feepay/v1/query.proto index 2468c42e2..a0113c5e3 100644 --- a/proto/juno/feepay/v1/query.proto +++ b/proto/juno/feepay/v1/query.proto @@ -9,89 +9,89 @@ import "google/api/annotations.proto"; option go_package = "github.com/CosmosContracts/juno/x/feepay/types"; -// Query defines the gRPC querier service. -service Query { - // FeeShares retrieves all registered FeeShares - rpc FeePrepays(QueryFeeSharesRequest) returns (QueryFeeSharesResponse) { - option (google.api.http).get = "/juno/feepay/v1/feepay"; - } +// // Query defines the gRPC querier service. +// service Query { +// // FeeShares retrieves all registered FeeShares +// rpc FeePrepays(QueryFeeSharesRequest) returns (QueryFeeSharesResponse) { +// option (google.api.http).get = "/juno/feepay/v1/feepay"; +// } - // Params retrieves the FeeShare module params - rpc Params(QueryParamsRequest) returns (QueryParamsResponse) { - option (google.api.http).get = "/juno/feeshare/v1/params"; - } -} +// // Params retrieves the FeeShare module params +// rpc Params(QueryParamsRequest) returns (QueryParamsResponse) { +// option (google.api.http).get = "/juno/feeshare/v1/params"; +// } +// } -// QueryFeeSharesRequest is the request type for the Query/FeeShares RPC method. -message QueryFeeSharesRequest { - // pagination defines an optional pagination for the request. - cosmos.base.query.v1beta1.PageRequest pagination = 1; -} +// // QueryFeeSharesRequest is the request type for the Query/FeeShares RPC method. +// message QueryFeeSharesRequest { +// // pagination defines an optional pagination for the request. +// cosmos.base.query.v1beta1.PageRequest pagination = 1; +// } -// QueryFeeSharesResponse is the response type for the Query/FeeShares RPC -// method. -message QueryFeeSharesResponse { - // FeeShare is a slice of all stored Reveneue - repeated FeeShare feeshare = 1 [ (gogoproto.nullable) = false ]; - // pagination defines the pagination in the response. - cosmos.base.query.v1beta1.PageResponse pagination = 2; -} +// // QueryFeeSharesResponse is the response type for the Query/FeeShares RPC +// // method. +// message QueryFeeSharesResponse { +// // FeeShare is a slice of all stored Reveneue +// repeated FeeShare feeshare = 1 [ (gogoproto.nullable) = false ]; +// // pagination defines the pagination in the response. +// cosmos.base.query.v1beta1.PageResponse pagination = 2; +// } -// QueryFeeShareRequest is the request type for the Query/FeeShare RPC method. -message QueryFeeShareRequest { - // contract_address of a registered contract in bech32 format - string contract_address = 1; -} +// // QueryFeeShareRequest is the request type for the Query/FeeShare RPC method. +// message QueryFeeShareRequest { +// // contract_address of a registered contract in bech32 format +// string contract_address = 1; +// } -// QueryFeeShareResponse is the response type for the Query/FeeShare RPC method. -message QueryFeeShareResponse { - // FeeShare is a stored Reveneue for the queried contract - FeeShare feeshare = 1 [ (gogoproto.nullable) = false ]; -} +// // QueryFeeShareResponse is the response type for the Query/FeeShare RPC method. +// message QueryFeeShareResponse { +// // FeeShare is a stored Reveneue for the queried contract +// FeeShare feeshare = 1 [ (gogoproto.nullable) = false ]; +// } -// QueryParamsRequest is the request type for the Query/Params RPC method. -message QueryParamsRequest {} +// // QueryParamsRequest is the request type for the Query/Params RPC method. +// message QueryParamsRequest {} -// QueryParamsResponse is the response type for the Query/Params RPC method. -message QueryParamsResponse { - // params is the returned FeeShare parameter - Params params = 1 [ (gogoproto.nullable) = false ]; -} +// // QueryParamsResponse is the response type for the Query/Params RPC method. +// message QueryParamsResponse { +// // params is the returned FeeShare parameter +// Params params = 1 [ (gogoproto.nullable) = false ]; +// } -// QueryDeployerFeeSharesRequest is the request type for the -// Query/DeployerFeeShares RPC method. -message QueryDeployerFeeSharesRequest { - // deployer_address in bech32 format - string deployer_address = 1; - // pagination defines an optional pagination for the request. - cosmos.base.query.v1beta1.PageRequest pagination = 2; -} +// // QueryDeployerFeeSharesRequest is the request type for the +// // Query/DeployerFeeShares RPC method. +// message QueryDeployerFeeSharesRequest { +// // deployer_address in bech32 format +// string deployer_address = 1; +// // pagination defines an optional pagination for the request. +// cosmos.base.query.v1beta1.PageRequest pagination = 2; +// } -// QueryDeployerFeeSharesResponse is the response type for the -// Query/DeployerFeeShares RPC method. -message QueryDeployerFeeSharesResponse { - // contract_addresses is the slice of registered contract addresses for a - // deployer - repeated string contract_addresses = 1; - // pagination defines the pagination in the response. - cosmos.base.query.v1beta1.PageResponse pagination = 2; -} +// // QueryDeployerFeeSharesResponse is the response type for the +// // Query/DeployerFeeShares RPC method. +// message QueryDeployerFeeSharesResponse { +// // contract_addresses is the slice of registered contract addresses for a +// // deployer +// repeated string contract_addresses = 1; +// // pagination defines the pagination in the response. +// cosmos.base.query.v1beta1.PageResponse pagination = 2; +// } -// QueryWithdrawerFeeSharesRequest is the request type for the -// Query/WithdrawerFeeShares RPC method. -message QueryWithdrawerFeeSharesRequest { - // withdrawer_address in bech32 format - string withdrawer_address = 1; - // pagination defines an optional pagination for the request. - cosmos.base.query.v1beta1.PageRequest pagination = 2; -} +// // QueryWithdrawerFeeSharesRequest is the request type for the +// // Query/WithdrawerFeeShares RPC method. +// message QueryWithdrawerFeeSharesRequest { +// // withdrawer_address in bech32 format +// string withdrawer_address = 1; +// // pagination defines an optional pagination for the request. +// cosmos.base.query.v1beta1.PageRequest pagination = 2; +// } -// QueryWithdrawerFeeSharesResponse is the response type for the -// Query/WithdrawerFeeShares RPC method. -message QueryWithdrawerFeeSharesResponse { - // contract_addresses is the slice of registered contract addresses for a - // withdrawer - repeated string contract_addresses = 1; - // pagination defines the pagination in the response. - cosmos.base.query.v1beta1.PageResponse pagination = 2; -} +// // QueryWithdrawerFeeSharesResponse is the response type for the +// // Query/WithdrawerFeeShares RPC method. +// message QueryWithdrawerFeeSharesResponse { +// // contract_addresses is the slice of registered contract addresses for a +// // withdrawer +// repeated string contract_addresses = 1; +// // pagination defines the pagination in the response. +// cosmos.base.query.v1beta1.PageResponse pagination = 2; +// } diff --git a/proto/juno/feepay/v1/tx.proto b/proto/juno/feepay/v1/tx.proto index 640e14893..7ced3ba12 100644 --- a/proto/juno/feepay/v1/tx.proto +++ b/proto/juno/feepay/v1/tx.proto @@ -13,31 +13,28 @@ option go_package = "github.com/CosmosContracts/juno/x/feepay/types"; // Msg defines the fees Msg service. service Msg { // RegisterFeeShare registers a new contract for receiving transaction fees - rpc RegisterFeeShare(MsgRegisterFeeShare) - returns (MsgRegisterFeeShareResponse) { - option (google.api.http).post = "/juno/feepay/v1/tx/register"; + rpc RegisterFeePayContract(MsgRegisterFeePayContract) + returns (MsgRegisterFeePayContractResponse) { + option (google.api.http).post = "/juno/feepay/v1/tx/registerFeePayContract"; }; // Update the params of the module through gov v1 type. rpc UpdateParams(MsgUpdateParams) returns (MsgUpdateParamsResponse); } -// MsgRegisterFeeShare defines a message that registers a FeeShare -message MsgRegisterFeeShare { +// The message to register a fee pay contract. +message MsgRegisterFeePayContract { option (gogoproto.equal) = false; - // contract_address in bech32 format + + // The wallet address of the sender. string sender_address = 1; - // // deployer_address is the bech32 address of message sender. It must be the - // // same the contract's admin address - // string deployer_address = 2; - // // withdrawer_address is the bech32 address of account receiving the - // // transaction fees - // string withdrawer_address = 3; + + // The fee pay contract to register. FeePayContract contract = 2; } -// MsgRegisterFeeShareResponse defines the MsgRegisterFeeShare response type -message MsgRegisterFeeShareResponse {} +// The response message for registering a fee pay contract. +message MsgRegisterFeePayContractResponse {} // MsgUpdateParams is the Msg/UpdateParams request type. // diff --git a/x/feepay/ante/dedcuct_fee.go b/x/feepay/ante/dedcuct_fee.go index 826561b17..2479d2d1d 100644 --- a/x/feepay/ante/dedcuct_fee.go +++ b/x/feepay/ante/dedcuct_fee.go @@ -9,6 +9,7 @@ import ( wasmtypes "github.com/CosmWasm/wasmd/x/wasm/types" feepaykeeper "github.com/CosmosContracts/juno/v17/x/feepay/keeper" feepaytypes "github.com/CosmosContracts/juno/v17/x/feepay/types" + globalfeekeeper "github.com/CosmosContracts/juno/v17/x/globalfee/keeper" sdk "github.com/cosmos/cosmos-sdk/types" sdkerrors "github.com/cosmos/cosmos-sdk/types/errors" "github.com/cosmos/cosmos-sdk/x/auth/ante" @@ -25,27 +26,29 @@ import ( // message transactions with no provided fee. If they correspond to a registered FeePay Contract, the FeePay // module will cover the cost of the fee (if the balance permits). type DeductFeeDecorator struct { - feepayKeeper feepaykeeper.Keeper - accountKeeper ante.AccountKeeper - bankKeeper bankkeeper.Keeper - feegrantKeeper ante.FeegrantKeeper + feepayKeeper feepaykeeper.Keeper + globalfeeKeeper globalfeekeeper.Keeper + accountKeeper ante.AccountKeeper + bankKeeper bankkeeper.Keeper + feegrantKeeper ante.FeegrantKeeper // TxFeeChecker check if the provided fee is enough and returns the effective fee and tx priority, // the effective fee should be deducted later, and the priority should be returned in abci response. // type TxFeeChecker func(ctx sdk.Context, tx sdk.Tx) (sdk.Coins, int64, error) txFeeChecker ante.TxFeeChecker } -func NewDeductFeeDecorator(fpk feepaykeeper.Keeper, ak ante.AccountKeeper, bk bankkeeper.Keeper, fgk ante.FeegrantKeeper, tfc ante.TxFeeChecker) DeductFeeDecorator { +func NewDeductFeeDecorator(fpk feepaykeeper.Keeper, gfk globalfeekeeper.Keeper, ak ante.AccountKeeper, bk bankkeeper.Keeper, fgk ante.FeegrantKeeper, tfc ante.TxFeeChecker) DeductFeeDecorator { if tfc == nil { tfc = checkTxFeeWithValidatorMinGasPrices } return DeductFeeDecorator{ - feepayKeeper: fpk, - accountKeeper: ak, - bankKeeper: bk, - feegrantKeeper: fgk, - txFeeChecker: tfc, + feepayKeeper: fpk, + globalfeeKeeper: gfk, + accountKeeper: ak, + bankKeeper: bk, + feegrantKeeper: fgk, + txFeeChecker: tfc, } } @@ -115,11 +118,8 @@ func (dfd DeductFeeDecorator) checkDeductFee(ctx sdk.Context, sdkTx sdk.Tx, fee return sdkerrors.ErrUnknownAddress.Wrapf("fee payer address: %s does not exist", deductFeesFrom) } - msg := sdkTx.GetMsgs()[0] - _, isCWMsg := msg.(*wasmtypes.MsgExecuteContract) - - if fee.IsZero() && len(sdkTx.GetMsgs()) == 1 && isCWMsg { - err := HandleZeroFees(dfd.bankKeeper, ctx, deductFeesFromAcc, fee) + if isValidFeePayTransaction(ctx, sdkTx, fee) { + err := dfd.handleZeroFees(ctx, deductFeesFromAcc, sdkTx, fee) if err != nil { return err } @@ -144,15 +144,27 @@ func (dfd DeductFeeDecorator) checkDeductFee(ctx sdk.Context, sdkTx sdk.Tx, fee } // Handle zero fee transactions for fee prepay module -func HandleZeroFees(keeper bankkeeper.Keeper, ctx sdk.Context, deductFeesFromAcc types.AccountI, fee sdk.Coins) error { +func (dfd DeductFeeDecorator) handleZeroFees(ctx sdk.Context, deductFeesFromAcc types.AccountI, tx sdk.Tx, fee sdk.Coins) error { ctx.Logger().Error("HandleZeroFees", "Starting", true) + msg := tx.GetMsgs()[0] + cw := msg.(*wasmtypes.MsgExecuteContract) + + // We need to check if it is a valid contract. Utilize the FeePay Keeper for validation + if !dfd.feepayKeeper.IsValidContract(ctx, cw.GetContract()) { + return sdkerrors.ErrInvalidRequest.Wrapf("contract %s is not registered for fee pay", cw.GetContract()) + } + + // TODO: instead of hardcoding payment, GetGas() * globalFeeParam.GetParams(ctx).MinimumGasPrices of ujuno or ujunox (app.GetDenom() func). + // feeTx := tx.(sdk.FeeTx) + // gas := feeTx.GetGas() + payment := sdk.NewCoins(sdk.NewCoin("ujuno", sdk.NewDec(500_000).RoundInt())) ctx.Logger().Error("HandleZeroFees", "Payment", payment) // keeper.SendCoinsFromModuleToAccount(ctx, "feeprepay", deductFeesFromAcc.GetAddress(), payment) - err := keeper.SendCoinsFromModuleToModule(ctx, feepaytypes.ModuleName, types.FeeCollectorName, payment) + err := dfd.bankKeeper.SendCoinsFromModuleToModule(ctx, feepaytypes.ModuleName, types.FeeCollectorName, payment) // Handle error if err != nil { @@ -193,7 +205,7 @@ func checkTxFeeWithValidatorMinGasPrices(ctx sdk.Context, tx sdk.Tx) (sdk.Coins, // Ensure that the provided fees meet a minimum threshold for the validator, // if this is a CheckTx. This is only for local mempool purposes, and thus // is only ran on check tx. - if ctx.IsCheckTx() && (!feeTx.GetFee().Empty() || len(tx.GetMsgs()) > 0) { + if ctx.IsCheckTx() && !isValidFeePayTransaction(ctx, tx, feeTx.GetFee()) { minGasPrices := ctx.MinGasPrices() if !minGasPrices.IsZero() { requiredFees := make(sdk.Coins, len(minGasPrices)) @@ -235,3 +247,23 @@ func getTxPriority(fee sdk.Coins, gas int64) int64 { return priority } + +// Check if a transaction should be processed as a FeePay transaction. +// A valid FeePay transaction has no fee, and only 1 message for executing a contract. +func isValidFeePayTransaction(ctx sdk.Context, tx sdk.Tx, fee sdk.Coins) bool { + + ctx.Logger().Error("FeePayAnte", "IsZero", fee.IsZero(), "Msgs", len(tx.GetMsgs())) + + // Check if fee is zero, and tx has only 1 message for executing a contract + if fee.IsZero() && len(tx.GetMsgs()) == 1 { + _, ok := (tx.GetMsgs()[0]).(*wasmtypes.MsgExecuteContract) + + ctx.Logger().Error("FeePayAnte", "IsCWExecuteContract", ok) + + return ok + } + + // The transaction includes a fee, has more than 1 message, or + // has a single message that is not for executing a contract + return false +} diff --git a/x/feepay/client/cli/tx.go b/x/feepay/client/cli/tx.go new file mode 100644 index 000000000..eef74cc0d --- /dev/null +++ b/x/feepay/client/cli/tx.go @@ -0,0 +1,76 @@ +package cli + +import ( + "strconv" + + "github.com/spf13/cobra" + + "github.com/cosmos/cosmos-sdk/client" + "github.com/cosmos/cosmos-sdk/client/flags" + "github.com/cosmos/cosmos-sdk/client/tx" + + "github.com/CosmosContracts/juno/v17/x/feepay/types" +) + +// NewTxCmd returns a root CLI command handler for certain modules/FeeShare +// transaction commands. +func NewTxCmd() *cobra.Command { + txCmd := &cobra.Command{ + Use: types.ModuleName, + Short: "FeePay subcommands", + DisableFlagParsing: true, + SuggestionsMinimumDistance: 2, + RunE: client.ValidateCmd, + } + + txCmd.AddCommand( + NewRegisterFeePayContract(), + ) + return txCmd +} + +// NewRegisterFeeShare returns a CLI command handler for registering a +// contract for fee pay. +func NewRegisterFeePayContract() *cobra.Command { + cmd := &cobra.Command{ + Use: "register [contract_bech32] [wallet_limit]", + Short: "Register a contract for fee pay. Only the contract admin can register a contract.", + Long: "Register a contract for fee pay. Only the contract admin can register a contract.", + Args: cobra.ExactArgs(2), + RunE: func(cmd *cobra.Command, args []string) error { + cliCtx, err := client.GetClientTxContext(cmd) + if err != nil { + return err + } + + deployer_address := cliCtx.GetFromAddress() + contract_address := args[0] + wallet_limit := args[1] + dec_limit, err := strconv.ParseUint(wallet_limit, 10, 64) + + if err != nil { + return err + } + + fpc := &types.FeePayContract{ + ContractAddress: contract_address, + Balance: uint64(0), + Limit: dec_limit, + } + + msg := &types.MsgRegisterFeePayContract{ + SenderAddress: deployer_address.String(), + Contract: fpc, + } + + if err := msg.ValidateBasic(); err != nil { + return err + } + + return tx.GenerateOrBroadcastTxCLI(cliCtx, cmd.Flags(), msg) + }, + } + + flags.AddTxFlagsToCmd(cmd) + return cmd +} diff --git a/x/feepay/genesis.go b/x/feepay/genesis.go new file mode 100644 index 000000000..afe5520cc --- /dev/null +++ b/x/feepay/genesis.go @@ -0,0 +1,22 @@ +package feepay + +import ( + sdk "github.com/cosmos/cosmos-sdk/types" + + "github.com/CosmosContracts/juno/v17/x/feepay/keeper" + "github.com/CosmosContracts/juno/v17/x/feepay/types" +) + +// InitGenesis import module genesis +func InitGenesis( + ctx sdk.Context, + k keeper.Keeper, + data types.GenesisState, +) { + +} + +// ExportGenesis export module state +func ExportGenesis(ctx sdk.Context, k keeper.Keeper) *types.GenesisState { + return &types.GenesisState{} +} diff --git a/x/feepay/keeper/keeper.go b/x/feepay/keeper/keeper.go index 278500d90..622f68e29 100644 --- a/x/feepay/keeper/keeper.go +++ b/x/feepay/keeper/keeper.go @@ -8,9 +8,11 @@ import ( "github.com/cometbft/cometbft/libs/log" "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" + types "github.com/CosmosContracts/juno/v17/x/feepay/types" revtypes "github.com/CosmosContracts/juno/v17/x/feeshare/types" ) @@ -63,7 +65,32 @@ func (k Keeper) Logger(ctx sdk.Context) log.Logger { } // Check if a contract is associated with a FeePay contract -func (k Keeper) IsValidContract(ctx sdk.Context, contractAddr sdk.AccAddress) bool { +func (k Keeper) IsValidContract(ctx sdk.Context, contractAddr string) bool { + + // Get store + store := prefix.NewStore(ctx.KVStore(k.storeKey), []byte("contracts")) + + // Get data + hasData := store.Has([]byte(contractAddr)) + + // Return true if data is not nil + return hasData +} + +// Register the contract in the module store +func (k Keeper) RegisterContract(ctx sdk.Context, fpc types.FeePayContract) bool { + + // Get store + store := prefix.NewStore(ctx.KVStore(k.storeKey), []byte("contracts")) + + // Get key/val pair + key := []byte(fpc.ContractAddress) + bz := k.cdc.MustMarshal(&fpc) + + // Set in store + store.Set(key, bz) + + // Return true by default (for now) return true } diff --git a/x/feepay/keeper/msg_server.go b/x/feepay/keeper/msg_server.go new file mode 100644 index 000000000..5072a6e18 --- /dev/null +++ b/x/feepay/keeper/msg_server.go @@ -0,0 +1,33 @@ +package keeper + +import ( + "context" + + errorsmod "cosmossdk.io/errors" + + sdk "github.com/cosmos/cosmos-sdk/types" + govtypes "github.com/cosmos/cosmos-sdk/x/gov/types" + + "github.com/CosmosContracts/juno/v17/x/feepay/types" +) + +var _ types.MsgServer = &Keeper{} + +func (k Keeper) RegisterFeePayContract(goCtx context.Context, msg *types.MsgRegisterFeePayContract) (*types.MsgRegisterFeePayContractResponse, error) { + ctx := sdk.UnwrapSDKContext(goCtx) + k.RegisterContract(ctx, *msg.Contract) + return &types.MsgRegisterFeePayContractResponse{}, nil +} + +func (k Keeper) UpdateParams(goCtx context.Context, req *types.MsgUpdateParams) (*types.MsgUpdateParamsResponse, error) { + if k.authority != req.Authority { + return nil, errorsmod.Wrapf(govtypes.ErrInvalidSigner, "invalid authority; expected %s, got %s", k.authority, req.Authority) + } + + ctx := sdk.UnwrapSDKContext(goCtx) + if err := k.SetParams(ctx, req.Params); err != nil { + return nil, err + } + + return &types.MsgUpdateParamsResponse{}, nil +} diff --git a/x/feepay/keeper/params.go b/x/feepay/keeper/params.go new file mode 100644 index 000000000..d0cce8e4e --- /dev/null +++ b/x/feepay/keeper/params.go @@ -0,0 +1,32 @@ +package keeper + +import ( + sdk "github.com/cosmos/cosmos-sdk/types" + + "github.com/CosmosContracts/juno/v17/x/feepay/types" +) + +// GetParams returns the total set of fees parameters. +func (k Keeper) GetParams(ctx sdk.Context) (p types.Params) { + // store := ctx.KVStore(k.storeKey) + // bz := store.Get(types.ParamsKey) + // if bz == nil { + // return p + // } + + // k.cdc.MustUnmarshal(bz, &p) + return p +} + +// SetParams sets the fees parameters to the param space. +func (k Keeper) SetParams(ctx sdk.Context, p types.Params) error { + // if err := p.Validate(); err != nil { + // return err + // } + + // store := ctx.KVStore(k.storeKey) + // bz := k.cdc.MustMarshal(&p) + // store.Set(types.ParamsKey, bz) + + return nil +} diff --git a/x/feepay/module.go b/x/feepay/module.go new file mode 100644 index 000000000..5c15b094e --- /dev/null +++ b/x/feepay/module.go @@ -0,0 +1,206 @@ +package feepay + +import ( + "encoding/json" + "fmt" + + "github.com/gorilla/mux" + "github.com/grpc-ecosystem/grpc-gateway/runtime" + "github.com/spf13/cobra" + + abci "github.com/cometbft/cometbft/abci/types" + + "github.com/cosmos/cosmos-sdk/client" + "github.com/cosmos/cosmos-sdk/codec" + codectypes "github.com/cosmos/cosmos-sdk/codec/types" + sdk "github.com/cosmos/cosmos-sdk/types" + "github.com/cosmos/cosmos-sdk/types/module" + simtypes "github.com/cosmos/cosmos-sdk/types/simulation" + authkeeper "github.com/cosmos/cosmos-sdk/x/auth/keeper" + + "github.com/CosmosContracts/juno/v17/x/feepay/client/cli" + "github.com/CosmosContracts/juno/v17/x/feepay/keeper" + "github.com/CosmosContracts/juno/v17/x/feepay/types" + "github.com/CosmosContracts/juno/v17/x/mint/exported" +) + +// type check to ensure the interface is properly implemented +var ( + _ module.AppModule = AppModule{} + _ module.AppModuleBasic = AppModuleBasic{} + _ module.AppModuleSimulation = AppModule{} +) + +// ConsensusVersion defines the current x/feepay module consensus version. +const ConsensusVersion = 2 + +// AppModuleBasic type for the fees module +type AppModuleBasic struct{} + +// Name returns the fees module's name. +func (AppModuleBasic) Name() string { + return types.ModuleName +} + +// RegisterLegacyAminoCodec performs a no-op as the fees do not support Amino +// encoding. +func (AppModuleBasic) RegisterLegacyAminoCodec(cdc *codec.LegacyAmino) { + types.RegisterLegacyAminoCodec(cdc) +} + +// ConsensusVersion returns the consensus state-breaking version for the module. +func (AppModuleBasic) ConsensusVersion() uint64 { + return ConsensusVersion +} + +// RegisterInterfaces registers interfaces and implementations of the fees +// module. +func (AppModuleBasic) RegisterInterfaces(interfaceRegistry codectypes.InterfaceRegistry) { + types.RegisterInterfaces(interfaceRegistry) +} + +// DefaultGenesis returns default genesis state as raw bytes for the fees +// module. +func (AppModuleBasic) DefaultGenesis(cdc codec.JSONCodec) json.RawMessage { + return cdc.MustMarshalJSON(types.DefaultGenesisState()) +} + +// ValidateGenesis performs genesis state validation for the fees module. +func (b AppModuleBasic) ValidateGenesis(cdc codec.JSONCodec, _ client.TxEncodingConfig, bz json.RawMessage) error { + var genesisState types.GenesisState + if err := cdc.UnmarshalJSON(bz, &genesisState); err != nil { + return fmt.Errorf("failed to unmarshal %s genesis state: %w", types.ModuleName, err) + } + + return genesisState.Validate() +} + +// RegisterRESTRoutes performs a no-op as the fees module doesn't expose REST +// endpoints +func (AppModuleBasic) RegisterRESTRoutes(_ client.Context, _ *mux.Router) {} + +// RegisterGRPCGatewayRoutes registers the gRPC Gateway routes for the fees +// module. +func (b AppModuleBasic) RegisterGRPCGatewayRoutes(c client.Context, serveMux *runtime.ServeMux) { + + // TODO: UNCOMMENT FOR QUERIES + // if err := types.RegisterQueryHandlerClient(context.Background(), serveMux, types.NewQueryClient(c)); err != nil { + // panic(err) + // } +} + +// GetTxCmd returns the root tx command for the fees module. +func (AppModuleBasic) GetTxCmd() *cobra.Command { + return cli.NewTxCmd() +} + +// GetQueryCmd returns the fees module's root query command. +func (AppModuleBasic) GetQueryCmd() *cobra.Command { + return nil +} + +// ___________________________________________________________________________ + +// AppModule implements the AppModule interface for the fees module. +type AppModule struct { + AppModuleBasic + keeper keeper.Keeper + ak authkeeper.AccountKeeper + + // legacySubspace is used solely for migration of x/params managed parameters + legacySubspace exported.Subspace +} + +// NewAppModule creates a new AppModule Object +func NewAppModule( + k keeper.Keeper, + ak authkeeper.AccountKeeper, + ss exported.Subspace, +) AppModule { + return AppModule{ + AppModuleBasic: AppModuleBasic{}, + keeper: k, + ak: ak, + legacySubspace: ss, + } +} + +// Name returns the fees module's name. +func (AppModule) Name() string { + return types.ModuleName +} + +// RegisterInvariants registers the fees module's invariants. +func (am AppModule) RegisterInvariants(_ sdk.InvariantRegistry) {} + +// NewHandler returns nil - fees module doesn't expose tx gRPC endpoints +func (am AppModule) NewHandler() sdk.Handler { + return nil +} + +// QuerierRoute returns the claim module's query routing key. +func (am AppModule) QuerierRoute() string { + return types.RouterKey +} + +// 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(), am.keeper) + + // TODO: UNCOMMENT FOR QUERIES + // types.RegisterQueryServer(cfg.QueryServer(), keeper.NewQuerier(am.keeper)) + + // m := keeper.NewMigrator(am.keeper, am.legacySubspace) + // if err := cfg.RegisterMigration(types.ModuleName, 1, m.Migrate1to2); err != nil { + // panic(fmt.Sprintf("failed to migrate x/%s from version 1 to 2: %v", types.ModuleName, err)) + // } +} + +// BeginBlock executes all ABCI BeginBlock logic respective to the fees module. +func (am AppModule) BeginBlock(_ sdk.Context, _ abci.RequestBeginBlock) { +} + +// EndBlock executes all ABCI EndBlock logic respective to the fee-share module. It +// returns no validator updates. +func (am AppModule) EndBlock(_ sdk.Context, _ abci.RequestEndBlock) []abci.ValidatorUpdate { + return []abci.ValidatorUpdate{} +} + +// InitGenesis performs the fees module's genesis initialization. It returns +// no validator updates. +func (am AppModule) InitGenesis(ctx sdk.Context, cdc codec.JSONCodec, data json.RawMessage) []abci.ValidatorUpdate { + var genesisState types.GenesisState + + cdc.MustUnmarshalJSON(data, &genesisState) + InitGenesis(ctx, am.keeper, genesisState) + return []abci.ValidatorUpdate{} +} + +// ExportGenesis returns the fees module's exported genesis state as raw JSON bytes. +func (am AppModule) ExportGenesis(ctx sdk.Context, cdc codec.JSONCodec) json.RawMessage { + gs := ExportGenesis(ctx, am.keeper) + return cdc.MustMarshalJSON(gs) +} + +// ___________________________________________________________________________ + +// AppModuleSimulation functions + +// GenerateGenesisState creates a randomized GenState of the fees module. +func (am AppModule) GenerateGenesisState(_ *module.SimulationState) { +} + +// ProposalContents returns content functions for governance proposals. +func (am AppModule) ProposalContents(_ module.SimulationState) []simtypes.WeightedProposalMsg { + return []simtypes.WeightedProposalMsg{} +} + +// RegisterStoreDecoder registers a decoder for fees module's types. +func (am AppModule) RegisterStoreDecoder(_ sdk.StoreDecoderRegistry) { +} + +// WeightedOperations returns fees module weighted operations +func (am AppModule) WeightedOperations(_ module.SimulationState) []simtypes.WeightedOperation { + return []simtypes.WeightedOperation{} +} diff --git a/x/feepay/types/codec.go b/x/feepay/types/codec.go new file mode 100644 index 000000000..3ce0e8201 --- /dev/null +++ b/x/feepay/types/codec.go @@ -0,0 +1,60 @@ +package types + +import ( + "github.com/cosmos/cosmos-sdk/codec" + codectypes "github.com/cosmos/cosmos-sdk/codec/types" + sdk "github.com/cosmos/cosmos-sdk/types" + "github.com/cosmos/cosmos-sdk/types/msgservice" + authzcodec "github.com/cosmos/cosmos-sdk/x/authz/codec" +) + +var ( + amino = codec.NewLegacyAmino() + + // ModuleCdc references the global erc20 module codec. Note, the codec should + // ONLY be used in certain instances of tests and for JSON encoding. + // + // The actual codec used for serialization should be provided to modules/erc20 and + // defined at the application level. + ModuleCdc = codec.NewProtoCodec(codectypes.NewInterfaceRegistry()) + + // AminoCdc is a amino codec created to support amino JSON compatible msgs. + AminoCdc = codec.NewAminoCodec(amino) +) + +const ( + // Amino names + registerFeePayContract = "juno/MsgRegisterFeePayContract" + updateFeeShareParams = "juno/MsgFeePayUpdateParams" +) + +// NOTE: This is required for the GetSignBytes function +func init() { + RegisterLegacyAminoCodec(amino) + + sdk.RegisterLegacyAminoCodec(amino) + + // Register all Amino interfaces and concrete types on the authz Amino codec + // so that this can later be used to properly serialize MsgGrant and MsgExec + // instances. + RegisterLegacyAminoCodec(authzcodec.Amino) +} + +// RegisterInterfaces register implementations +func RegisterInterfaces(registry codectypes.InterfaceRegistry) { + registry.RegisterImplementations( + (*sdk.Msg)(nil), + &MsgRegisterFeePayContract{}, + &MsgUpdateParams{}, + ) + + msgservice.RegisterMsgServiceDesc(registry, &_Msg_serviceDesc) +} + +// RegisterLegacyAminoCodec registers the necessary x/FeeShare interfaces and +// concrete types on the provided LegacyAmino codec. These types are used for +// Amino JSON serialization and EIP-712 compatibility. +func RegisterLegacyAminoCodec(cdc *codec.LegacyAmino) { + cdc.RegisterConcrete(&MsgRegisterFeePayContract{}, registerFeePayContract, nil) + cdc.RegisterConcrete(&MsgUpdateParams{}, updateFeeShareParams, nil) +} diff --git a/x/feepay/types/feepay.pb.go b/x/feepay/types/feepay.pb.go index 498ca3b0c..8a939e991 100644 --- a/x/feepay/types/feepay.pb.go +++ b/x/feepay/types/feepay.pb.go @@ -22,10 +22,15 @@ var _ = math.Inf // proto package needs to be updated. const _ = proto.GoGoProtoPackageIsVersion3 // please upgrade the proto package -// FeeShare defines an instance that organizes fee distribution conditions for -// the owner of a given smart contract +// This defines the address, balance, and wallet limit +// of a fee pay contract. type FeePayContract struct { + // The address of the contract. ContractAddress string `protobuf:"bytes,1,opt,name=contract_address,json=contractAddress,proto3" json:"contract_address,omitempty"` + // The ledger balance of the contract. + Balance uint64 `protobuf:"varint,2,opt,name=balance,proto3" json:"balance,omitempty"` + // The number of times a wallet may interact with the contract. + Limit uint64 `protobuf:"varint,3,opt,name=limit,proto3" json:"limit,omitempty"` } func (m *FeePayContract) Reset() { *m = FeePayContract{} } @@ -68,24 +73,41 @@ func (m *FeePayContract) GetContractAddress() string { return "" } -type FeePayUserUsage struct { - // not used as a Tx, just a storage device - UserAddress string `protobuf:"bytes,1,opt,name=user_address,json=userAddress,proto3" json:"user_address,omitempty"` - NumUses uint64 `protobuf:"varint,2,opt,name=num_uses,json=numUses,proto3" json:"num_uses,omitempty"` +func (m *FeePayContract) GetBalance() uint64 { + if m != nil { + return m.Balance + } + return 0 } -func (m *FeePayUserUsage) Reset() { *m = FeePayUserUsage{} } -func (m *FeePayUserUsage) String() string { return proto.CompactTextString(m) } -func (*FeePayUserUsage) ProtoMessage() {} -func (*FeePayUserUsage) Descriptor() ([]byte, []int) { +func (m *FeePayContract) GetLimit() uint64 { + if m != nil { + return m.Limit + } + return 0 +} + +// This object is used to store the number of times a wallet has +// interacted with a contract. +type FeePayWalletUsage struct { + // The wallet address. + WalletAddress string `protobuf:"bytes,1,opt,name=wallet_address,json=walletAddress,proto3" json:"wallet_address,omitempty"` + // The number of uses corresponding to a wallet. + Uses uint64 `protobuf:"varint,2,opt,name=uses,proto3" json:"uses,omitempty"` +} + +func (m *FeePayWalletUsage) Reset() { *m = FeePayWalletUsage{} } +func (m *FeePayWalletUsage) String() string { return proto.CompactTextString(m) } +func (*FeePayWalletUsage) ProtoMessage() {} +func (*FeePayWalletUsage) Descriptor() ([]byte, []int) { return fileDescriptor_14ea6771eacbfed1, []int{1} } -func (m *FeePayUserUsage) XXX_Unmarshal(b []byte) error { +func (m *FeePayWalletUsage) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) } -func (m *FeePayUserUsage) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { +func (m *FeePayWalletUsage) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { if deterministic { - return xxx_messageInfo_FeePayUserUsage.Marshal(b, m, deterministic) + return xxx_messageInfo_FeePayWalletUsage.Marshal(b, m, deterministic) } else { b = b[:cap(b)] n, err := m.MarshalToSizedBuffer(b) @@ -95,56 +117,57 @@ func (m *FeePayUserUsage) XXX_Marshal(b []byte, deterministic bool) ([]byte, err return b[:n], nil } } -func (m *FeePayUserUsage) XXX_Merge(src proto.Message) { - xxx_messageInfo_FeePayUserUsage.Merge(m, src) +func (m *FeePayWalletUsage) XXX_Merge(src proto.Message) { + xxx_messageInfo_FeePayWalletUsage.Merge(m, src) } -func (m *FeePayUserUsage) XXX_Size() int { +func (m *FeePayWalletUsage) XXX_Size() int { return m.Size() } -func (m *FeePayUserUsage) XXX_DiscardUnknown() { - xxx_messageInfo_FeePayUserUsage.DiscardUnknown(m) +func (m *FeePayWalletUsage) XXX_DiscardUnknown() { + xxx_messageInfo_FeePayWalletUsage.DiscardUnknown(m) } -var xxx_messageInfo_FeePayUserUsage proto.InternalMessageInfo +var xxx_messageInfo_FeePayWalletUsage proto.InternalMessageInfo -func (m *FeePayUserUsage) GetUserAddress() string { +func (m *FeePayWalletUsage) GetWalletAddress() string { if m != nil { - return m.UserAddress + return m.WalletAddress } return "" } -func (m *FeePayUserUsage) GetNumUses() uint64 { +func (m *FeePayWalletUsage) GetUses() uint64 { if m != nil { - return m.NumUses + return m.Uses } return 0 } func init() { proto.RegisterType((*FeePayContract)(nil), "juno.feepay.v1.FeePayContract") - proto.RegisterType((*FeePayUserUsage)(nil), "juno.feepay.v1.FeePayUserUsage") + proto.RegisterType((*FeePayWalletUsage)(nil), "juno.feepay.v1.FeePayWalletUsage") } func init() { proto.RegisterFile("juno/feepay/v1/feepay.proto", fileDescriptor_14ea6771eacbfed1) } var fileDescriptor_14ea6771eacbfed1 = []byte{ - // 226 bytes of a gzipped FileDescriptorProto + // 245 bytes of a gzipped FileDescriptorProto 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xe2, 0x92, 0xce, 0x2a, 0xcd, 0xcb, 0xd7, 0x4f, 0x4b, 0x4d, 0x2d, 0x48, 0xac, 0xd4, 0x2f, 0x33, 0x84, 0xb2, 0xf4, 0x0a, 0x8a, 0xf2, - 0x4b, 0xf2, 0x85, 0xf8, 0x40, 0x92, 0x7a, 0x50, 0xa1, 0x32, 0x43, 0x25, 0x6b, 0x2e, 0x3e, 0xb7, + 0x4b, 0xf2, 0x85, 0xf8, 0x40, 0x92, 0x7a, 0x50, 0xa1, 0x32, 0x43, 0xa5, 0x6c, 0x2e, 0x3e, 0xb7, 0xd4, 0xd4, 0x80, 0xc4, 0x4a, 0xe7, 0xfc, 0xbc, 0x92, 0xa2, 0xc4, 0xe4, 0x12, 0x21, 0x4d, 0x2e, 0x81, 0x64, 0x28, 0x3b, 0x3e, 0x31, 0x25, 0xa5, 0x28, 0xb5, 0xb8, 0x58, 0x82, 0x51, 0x81, 0x51, - 0x83, 0x33, 0x88, 0x1f, 0x26, 0xee, 0x08, 0x11, 0x56, 0xf2, 0xe7, 0xe2, 0x87, 0x68, 0x0e, 0x2d, - 0x4e, 0x2d, 0x0a, 0x2d, 0x4e, 0x4c, 0x4f, 0x15, 0x52, 0xe4, 0xe2, 0x29, 0x2d, 0x4e, 0x2d, 0x42, - 0xd3, 0xc9, 0x0d, 0x12, 0x83, 0xea, 0x12, 0x92, 0xe4, 0xe2, 0xc8, 0x2b, 0xcd, 0x8d, 0x2f, 0x2d, - 0x4e, 0x2d, 0x96, 0x60, 0x52, 0x60, 0xd4, 0x60, 0x09, 0x62, 0xcf, 0x2b, 0xcd, 0x0d, 0x2d, 0x4e, - 0x2d, 0x76, 0xf2, 0x38, 0xf1, 0x48, 0x8e, 0xf1, 0xc2, 0x23, 0x39, 0xc6, 0x07, 0x8f, 0xe4, 0x18, - 0x27, 0x3c, 0x96, 0x63, 0xb8, 0xf0, 0x58, 0x8e, 0xe1, 0xc6, 0x63, 0x39, 0x86, 0x28, 0xbd, 0xf4, - 0xcc, 0x92, 0x8c, 0xd2, 0x24, 0xbd, 0xe4, 0xfc, 0x5c, 0x7d, 0xe7, 0xfc, 0xe2, 0xdc, 0xfc, 0x62, - 0x98, 0x83, 0x8b, 0xf5, 0xc1, 0xfe, 0xad, 0x80, 0xf9, 0xb8, 0xa4, 0xb2, 0x20, 0xb5, 0x38, 0x89, - 0x0d, 0xec, 0x5d, 0x63, 0x40, 0x00, 0x00, 0x00, 0xff, 0xff, 0x68, 0xa5, 0x09, 0x5f, 0x0d, 0x01, - 0x00, 0x00, + 0x83, 0x33, 0x88, 0x1f, 0x26, 0xee, 0x08, 0x11, 0x16, 0x92, 0xe0, 0x62, 0x4f, 0x4a, 0xcc, 0x49, + 0xcc, 0x4b, 0x4e, 0x95, 0x60, 0x52, 0x60, 0xd4, 0x60, 0x09, 0x82, 0x71, 0x85, 0x44, 0xb8, 0x58, + 0x73, 0x32, 0x73, 0x33, 0x4b, 0x24, 0x98, 0xc1, 0xe2, 0x10, 0x8e, 0x92, 0x1f, 0x97, 0x20, 0xc4, + 0xb2, 0xf0, 0xc4, 0x9c, 0x9c, 0xd4, 0x92, 0xd0, 0xe2, 0xc4, 0xf4, 0x54, 0x21, 0x55, 0x2e, 0xbe, + 0x72, 0x30, 0x17, 0xcd, 0x36, 0x5e, 0x88, 0x28, 0xcc, 0x2e, 0x21, 0x2e, 0x96, 0xd2, 0xe2, 0xd4, + 0x62, 0xa8, 0x45, 0x60, 0xb6, 0x93, 0xc7, 0x89, 0x47, 0x72, 0x8c, 0x17, 0x1e, 0xc9, 0x31, 0x3e, + 0x78, 0x24, 0xc7, 0x38, 0xe1, 0xb1, 0x1c, 0xc3, 0x85, 0xc7, 0x72, 0x0c, 0x37, 0x1e, 0xcb, 0x31, + 0x44, 0xe9, 0xa5, 0x67, 0x96, 0x64, 0x94, 0x26, 0xe9, 0x25, 0xe7, 0xe7, 0xea, 0x3b, 0xe7, 0x17, + 0xe7, 0xe6, 0x17, 0xc3, 0xfc, 0x57, 0xac, 0x0f, 0x0e, 0x9e, 0x0a, 0x58, 0x00, 0x95, 0x54, 0x16, + 0xa4, 0x16, 0x27, 0xb1, 0x81, 0x43, 0xc7, 0x18, 0x10, 0x00, 0x00, 0xff, 0xff, 0x88, 0xdb, 0x97, + 0xc5, 0x3c, 0x01, 0x00, 0x00, } func (m *FeePayContract) Marshal() (dAtA []byte, err error) { @@ -167,6 +190,16 @@ func (m *FeePayContract) MarshalToSizedBuffer(dAtA []byte) (int, error) { _ = i var l int _ = l + if m.Limit != 0 { + i = encodeVarintFeepay(dAtA, i, uint64(m.Limit)) + i-- + dAtA[i] = 0x18 + } + if m.Balance != 0 { + i = encodeVarintFeepay(dAtA, i, uint64(m.Balance)) + i-- + dAtA[i] = 0x10 + } if len(m.ContractAddress) > 0 { i -= len(m.ContractAddress) copy(dAtA[i:], m.ContractAddress) @@ -177,7 +210,7 @@ func (m *FeePayContract) MarshalToSizedBuffer(dAtA []byte) (int, error) { return len(dAtA) - i, nil } -func (m *FeePayUserUsage) Marshal() (dAtA []byte, err error) { +func (m *FeePayWalletUsage) Marshal() (dAtA []byte, err error) { size := m.Size() dAtA = make([]byte, size) n, err := m.MarshalToSizedBuffer(dAtA[:size]) @@ -187,25 +220,25 @@ func (m *FeePayUserUsage) Marshal() (dAtA []byte, err error) { return dAtA[:n], nil } -func (m *FeePayUserUsage) MarshalTo(dAtA []byte) (int, error) { +func (m *FeePayWalletUsage) MarshalTo(dAtA []byte) (int, error) { size := m.Size() return m.MarshalToSizedBuffer(dAtA[:size]) } -func (m *FeePayUserUsage) MarshalToSizedBuffer(dAtA []byte) (int, error) { +func (m *FeePayWalletUsage) MarshalToSizedBuffer(dAtA []byte) (int, error) { i := len(dAtA) _ = i var l int _ = l - if m.NumUses != 0 { - i = encodeVarintFeepay(dAtA, i, uint64(m.NumUses)) + if m.Uses != 0 { + i = encodeVarintFeepay(dAtA, i, uint64(m.Uses)) i-- dAtA[i] = 0x10 } - if len(m.UserAddress) > 0 { - i -= len(m.UserAddress) - copy(dAtA[i:], m.UserAddress) - i = encodeVarintFeepay(dAtA, i, uint64(len(m.UserAddress))) + if len(m.WalletAddress) > 0 { + i -= len(m.WalletAddress) + copy(dAtA[i:], m.WalletAddress) + i = encodeVarintFeepay(dAtA, i, uint64(len(m.WalletAddress))) i-- dAtA[i] = 0xa } @@ -233,21 +266,27 @@ func (m *FeePayContract) Size() (n int) { if l > 0 { n += 1 + l + sovFeepay(uint64(l)) } + if m.Balance != 0 { + n += 1 + sovFeepay(uint64(m.Balance)) + } + if m.Limit != 0 { + n += 1 + sovFeepay(uint64(m.Limit)) + } return n } -func (m *FeePayUserUsage) Size() (n int) { +func (m *FeePayWalletUsage) Size() (n int) { if m == nil { return 0 } var l int _ = l - l = len(m.UserAddress) + l = len(m.WalletAddress) if l > 0 { n += 1 + l + sovFeepay(uint64(l)) } - if m.NumUses != 0 { - n += 1 + sovFeepay(uint64(m.NumUses)) + if m.Uses != 0 { + n += 1 + sovFeepay(uint64(m.Uses)) } return n } @@ -319,6 +358,44 @@ func (m *FeePayContract) Unmarshal(dAtA []byte) error { } m.ContractAddress = string(dAtA[iNdEx:postIndex]) iNdEx = postIndex + case 2: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field Balance", wireType) + } + m.Balance = 0 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowFeepay + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + m.Balance |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + case 3: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field Limit", wireType) + } + m.Limit = 0 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowFeepay + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + m.Limit |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } default: iNdEx = preIndex skippy, err := skipFeepay(dAtA[iNdEx:]) @@ -340,7 +417,7 @@ func (m *FeePayContract) Unmarshal(dAtA []byte) error { } return nil } -func (m *FeePayUserUsage) Unmarshal(dAtA []byte) error { +func (m *FeePayWalletUsage) Unmarshal(dAtA []byte) error { l := len(dAtA) iNdEx := 0 for iNdEx < l { @@ -363,15 +440,15 @@ func (m *FeePayUserUsage) Unmarshal(dAtA []byte) error { fieldNum := int32(wire >> 3) wireType := int(wire & 0x7) if wireType == 4 { - return fmt.Errorf("proto: FeePayUserUsage: wiretype end group for non-group") + return fmt.Errorf("proto: FeePayWalletUsage: wiretype end group for non-group") } if fieldNum <= 0 { - return fmt.Errorf("proto: FeePayUserUsage: illegal tag %d (wire type %d)", fieldNum, wire) + return fmt.Errorf("proto: FeePayWalletUsage: illegal tag %d (wire type %d)", fieldNum, wire) } switch fieldNum { case 1: if wireType != 2 { - return fmt.Errorf("proto: wrong wireType = %d for field UserAddress", wireType) + return fmt.Errorf("proto: wrong wireType = %d for field WalletAddress", wireType) } var stringLen uint64 for shift := uint(0); ; shift += 7 { @@ -399,13 +476,13 @@ func (m *FeePayUserUsage) Unmarshal(dAtA []byte) error { if postIndex > l { return io.ErrUnexpectedEOF } - m.UserAddress = string(dAtA[iNdEx:postIndex]) + m.WalletAddress = string(dAtA[iNdEx:postIndex]) iNdEx = postIndex case 2: if wireType != 0 { - return fmt.Errorf("proto: wrong wireType = %d for field NumUses", wireType) + return fmt.Errorf("proto: wrong wireType = %d for field Uses", wireType) } - m.NumUses = 0 + m.Uses = 0 for shift := uint(0); ; shift += 7 { if shift >= 64 { return ErrIntOverflowFeepay @@ -415,7 +492,7 @@ func (m *FeePayUserUsage) Unmarshal(dAtA []byte) error { } b := dAtA[iNdEx] iNdEx++ - m.NumUses |= uint64(b&0x7F) << shift + m.Uses |= uint64(b&0x7F) << shift if b < 0x80 { break } diff --git a/x/feepay/types/genesis.go b/x/feepay/types/genesis.go new file mode 100644 index 000000000..2e539e9b3 --- /dev/null +++ b/x/feepay/types/genesis.go @@ -0,0 +1,21 @@ +package types + +// NewGenesisState creates a new genesis state. +func NewGenesisState(params Params, feecontract []FeePayContract) GenesisState { + return GenesisState{ + Params: params, + FeeContract: feecontract, + } +} + +// DefaultGenesisState sets default evm genesis state with empty accounts and +// default params and chain config values. +func DefaultGenesisState() *GenesisState { + return &GenesisState{} +} + +// Validate performs basic genesis state validation returning an error upon any +// failure. +func (gs GenesisState) Validate() error { + return nil +} diff --git a/x/feepay/types/msg.go b/x/feepay/types/msg.go new file mode 100644 index 000000000..a74b8b183 --- /dev/null +++ b/x/feepay/types/msg.go @@ -0,0 +1,60 @@ +package types + +import ( + sdk "github.com/cosmos/cosmos-sdk/types" +) + +var ( + _ sdk.Msg = &MsgRegisterFeePayContract{} + _ sdk.Msg = &MsgUpdateParams{} +) + +const ( + TypeMsgRegisterFeePayContract = "register_feepay_contract" + TypeMsgUpdateParams = "msg_update_params" +) + +// Route returns the name of the module +func (msg MsgRegisterFeePayContract) Route() string { return RouterKey } + +// Type returns the the action +func (msg MsgRegisterFeePayContract) Type() string { return TypeMsgRegisterFeePayContract } + +// ValidateBasic runs stateless checks on the message +func (msg MsgRegisterFeePayContract) ValidateBasic() error { + return nil +} + +// GetSignBytes encodes the message for signing +func (msg *MsgRegisterFeePayContract) GetSignBytes() []byte { + return sdk.MustSortJSON(AminoCdc.MustMarshalJSON(msg)) +} + +// GetSigners defines whose signature is required +func (msg MsgRegisterFeePayContract) GetSigners() []sdk.AccAddress { + from, _ := sdk.AccAddressFromBech32(msg.SenderAddress) + return []sdk.AccAddress{from} +} + +// Route returns the name of the module +func (msg MsgUpdateParams) Route() string { return RouterKey } + +// Type returns the the action +func (msg MsgUpdateParams) Type() string { return TypeMsgUpdateParams } + +// ValidateBasic does a sanity check on the provided data. +func (m *MsgUpdateParams) ValidateBasic() error { + // TODO: LATER + return nil +} + +// GetSignBytes implements the LegacyMsg interface. +func (m MsgUpdateParams) GetSignBytes() []byte { + return sdk.MustSortJSON(ModuleCdc.MustMarshalJSON(&m)) +} + +// GetSigners returns the expected signers for a MsgUpdateParams message. +func (m *MsgUpdateParams) GetSigners() []sdk.AccAddress { + addr, _ := sdk.AccAddressFromBech32(m.Authority) + return []sdk.AccAddress{addr} +} diff --git a/x/feepay/types/query.pb.go b/x/feepay/types/query.pb.go new file mode 100644 index 000000000..9a008d27a --- /dev/null +++ b/x/feepay/types/query.pb.go @@ -0,0 +1,44 @@ +// Code generated by protoc-gen-gogo. DO NOT EDIT. +// source: juno/feepay/v1/query.proto + +package types + +import ( + fmt "fmt" + _ "github.com/cosmos/cosmos-sdk/types/query" + _ "github.com/cosmos/gogoproto/gogoproto" + proto "github.com/cosmos/gogoproto/proto" + _ "google.golang.org/genproto/googleapis/api/annotations" + math "math" +) + +// 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 + +func init() { proto.RegisterFile("juno/feepay/v1/query.proto", fileDescriptor_d6539df905bf35ca) } + +var fileDescriptor_d6539df905bf35ca = []byte{ + // 210 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x5c, 0x8e, 0x31, 0x4e, 0xc4, 0x30, + 0x10, 0x45, 0x93, 0x86, 0x82, 0x82, 0x02, 0x51, 0x05, 0xe4, 0x03, 0x50, 0x78, 0x64, 0x71, 0x03, + 0xb6, 0xe1, 0x0c, 0x74, 0xe3, 0x68, 0x30, 0x46, 0xac, 0xc7, 0xc4, 0x93, 0x88, 0xdc, 0x82, 0x63, + 0x51, 0xa6, 0xa4, 0x44, 0xc9, 0x45, 0x56, 0xb1, 0x93, 0x26, 0xdd, 0x97, 0xde, 0xcc, 0xfb, 0xff, + 0xba, 0xf9, 0xe8, 0x03, 0xc3, 0x1b, 0x51, 0xc4, 0x11, 0x06, 0x03, 0x5f, 0x3d, 0x75, 0xa3, 0x8e, + 0x1d, 0x0b, 0xdf, 0xde, 0xac, 0x4c, 0x17, 0xa6, 0x07, 0xd3, 0x3c, 0xb6, 0x9c, 0xce, 0x9c, 0xc0, + 0x62, 0xa2, 0x72, 0x08, 0x83, 0xb1, 0x24, 0x68, 0x20, 0xa2, 0xf3, 0x01, 0xc5, 0x73, 0x28, 0xbf, + 0xcd, 0xc3, 0xc1, 0xeb, 0x28, 0x50, 0xf2, 0x69, 0xa3, 0xf7, 0x07, 0xba, 0x75, 0x14, 0x78, 0xe7, + 0xd8, 0x71, 0x8e, 0xb0, 0xa6, 0x5d, 0xe8, 0x98, 0xdd, 0x27, 0x01, 0x46, 0x0f, 0x18, 0x02, 0x4b, + 0x6e, 0xdb, 0x84, 0xcf, 0x2f, 0xbf, 0xb3, 0xaa, 0xa7, 0x59, 0xd5, 0xff, 0xb3, 0xaa, 0x7f, 0x16, + 0x55, 0x4d, 0x8b, 0xaa, 0xfe, 0x16, 0x55, 0xbd, 0x6a, 0xe7, 0xe5, 0xbd, 0xb7, 0xba, 0xe5, 0x33, + 0x9c, 0xf2, 0xfe, 0x13, 0x07, 0xe9, 0xb0, 0x95, 0x04, 0x79, 0xc5, 0xf7, 0xbe, 0x43, 0xc6, 0x48, + 0xc9, 0x5e, 0x65, 0xe1, 0xd3, 0x25, 0x00, 0x00, 0xff, 0xff, 0x82, 0xb6, 0xd6, 0xb1, 0x19, 0x01, + 0x00, 0x00, +} diff --git a/x/feepay/types/tx.pb.go b/x/feepay/types/tx.pb.go index fdcc903d2..ed5b05408 100644 --- a/x/feepay/types/tx.pb.go +++ b/x/feepay/types/tx.pb.go @@ -31,30 +31,26 @@ var _ = math.Inf // proto package needs to be updated. const _ = proto.GoGoProtoPackageIsVersion3 // please upgrade the proto package -// MsgRegisterFeeShare defines a message that registers a FeeShare -type MsgRegisterFeeShare struct { - // contract_address in bech32 format - ContractAddress string `protobuf:"bytes,1,opt,name=contract_address,json=contractAddress,proto3" json:"contract_address,omitempty"` - // deployer_address is the bech32 address of message sender. It must be the - // same the contract's admin address - DeployerAddress string `protobuf:"bytes,2,opt,name=deployer_address,json=deployerAddress,proto3" json:"deployer_address,omitempty"` - // withdrawer_address is the bech32 address of account receiving the - // transaction fees - WithdrawerAddress string `protobuf:"bytes,3,opt,name=withdrawer_address,json=withdrawerAddress,proto3" json:"withdrawer_address,omitempty"` -} - -func (m *MsgRegisterFeeShare) Reset() { *m = MsgRegisterFeeShare{} } -func (m *MsgRegisterFeeShare) String() string { return proto.CompactTextString(m) } -func (*MsgRegisterFeeShare) ProtoMessage() {} -func (*MsgRegisterFeeShare) Descriptor() ([]byte, []int) { +// The message to register a fee pay contract. +type MsgRegisterFeePayContract struct { + // The wallet address of the sender. + SenderAddress string `protobuf:"bytes,1,opt,name=sender_address,json=senderAddress,proto3" json:"sender_address,omitempty"` + // The fee pay contract to register. + Contract *FeePayContract `protobuf:"bytes,2,opt,name=contract,proto3" json:"contract,omitempty"` +} + +func (m *MsgRegisterFeePayContract) Reset() { *m = MsgRegisterFeePayContract{} } +func (m *MsgRegisterFeePayContract) String() string { return proto.CompactTextString(m) } +func (*MsgRegisterFeePayContract) ProtoMessage() {} +func (*MsgRegisterFeePayContract) Descriptor() ([]byte, []int) { return fileDescriptor_d739bd30c8846fd5, []int{0} } -func (m *MsgRegisterFeeShare) XXX_Unmarshal(b []byte) error { +func (m *MsgRegisterFeePayContract) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) } -func (m *MsgRegisterFeeShare) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { +func (m *MsgRegisterFeePayContract) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { if deterministic { - return xxx_messageInfo_MsgRegisterFeeShare.Marshal(b, m, deterministic) + return xxx_messageInfo_MsgRegisterFeePayContract.Marshal(b, m, deterministic) } else { b = b[:cap(b)] n, err := m.MarshalToSizedBuffer(b) @@ -64,55 +60,48 @@ func (m *MsgRegisterFeeShare) XXX_Marshal(b []byte, deterministic bool) ([]byte, return b[:n], nil } } -func (m *MsgRegisterFeeShare) XXX_Merge(src proto.Message) { - xxx_messageInfo_MsgRegisterFeeShare.Merge(m, src) +func (m *MsgRegisterFeePayContract) XXX_Merge(src proto.Message) { + xxx_messageInfo_MsgRegisterFeePayContract.Merge(m, src) } -func (m *MsgRegisterFeeShare) XXX_Size() int { +func (m *MsgRegisterFeePayContract) XXX_Size() int { return m.Size() } -func (m *MsgRegisterFeeShare) XXX_DiscardUnknown() { - xxx_messageInfo_MsgRegisterFeeShare.DiscardUnknown(m) +func (m *MsgRegisterFeePayContract) XXX_DiscardUnknown() { + xxx_messageInfo_MsgRegisterFeePayContract.DiscardUnknown(m) } -var xxx_messageInfo_MsgRegisterFeeShare proto.InternalMessageInfo - -func (m *MsgRegisterFeeShare) GetContractAddress() string { - if m != nil { - return m.ContractAddress - } - return "" -} +var xxx_messageInfo_MsgRegisterFeePayContract proto.InternalMessageInfo -func (m *MsgRegisterFeeShare) GetDeployerAddress() string { +func (m *MsgRegisterFeePayContract) GetSenderAddress() string { if m != nil { - return m.DeployerAddress + return m.SenderAddress } return "" } -func (m *MsgRegisterFeeShare) GetWithdrawerAddress() string { +func (m *MsgRegisterFeePayContract) GetContract() *FeePayContract { if m != nil { - return m.WithdrawerAddress + return m.Contract } - return "" + return nil } -// MsgRegisterFeeShareResponse defines the MsgRegisterFeeShare response type -type MsgRegisterFeeShareResponse struct { +// The response message for registering a fee pay contract. +type MsgRegisterFeePayContractResponse struct { } -func (m *MsgRegisterFeeShareResponse) Reset() { *m = MsgRegisterFeeShareResponse{} } -func (m *MsgRegisterFeeShareResponse) String() string { return proto.CompactTextString(m) } -func (*MsgRegisterFeeShareResponse) ProtoMessage() {} -func (*MsgRegisterFeeShareResponse) Descriptor() ([]byte, []int) { +func (m *MsgRegisterFeePayContractResponse) Reset() { *m = MsgRegisterFeePayContractResponse{} } +func (m *MsgRegisterFeePayContractResponse) String() string { return proto.CompactTextString(m) } +func (*MsgRegisterFeePayContractResponse) ProtoMessage() {} +func (*MsgRegisterFeePayContractResponse) Descriptor() ([]byte, []int) { return fileDescriptor_d739bd30c8846fd5, []int{1} } -func (m *MsgRegisterFeeShareResponse) XXX_Unmarshal(b []byte) error { +func (m *MsgRegisterFeePayContractResponse) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) } -func (m *MsgRegisterFeeShareResponse) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { +func (m *MsgRegisterFeePayContractResponse) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { if deterministic { - return xxx_messageInfo_MsgRegisterFeeShareResponse.Marshal(b, m, deterministic) + return xxx_messageInfo_MsgRegisterFeePayContractResponse.Marshal(b, m, deterministic) } else { b = b[:cap(b)] n, err := m.MarshalToSizedBuffer(b) @@ -122,17 +111,17 @@ func (m *MsgRegisterFeeShareResponse) XXX_Marshal(b []byte, deterministic bool) return b[:n], nil } } -func (m *MsgRegisterFeeShareResponse) XXX_Merge(src proto.Message) { - xxx_messageInfo_MsgRegisterFeeShareResponse.Merge(m, src) +func (m *MsgRegisterFeePayContractResponse) XXX_Merge(src proto.Message) { + xxx_messageInfo_MsgRegisterFeePayContractResponse.Merge(m, src) } -func (m *MsgRegisterFeeShareResponse) XXX_Size() int { +func (m *MsgRegisterFeePayContractResponse) XXX_Size() int { return m.Size() } -func (m *MsgRegisterFeeShareResponse) XXX_DiscardUnknown() { - xxx_messageInfo_MsgRegisterFeeShareResponse.DiscardUnknown(m) +func (m *MsgRegisterFeePayContractResponse) XXX_DiscardUnknown() { + xxx_messageInfo_MsgRegisterFeePayContractResponse.DiscardUnknown(m) } -var xxx_messageInfo_MsgRegisterFeeShareResponse proto.InternalMessageInfo +var xxx_messageInfo_MsgRegisterFeePayContractResponse proto.InternalMessageInfo // MsgUpdateParams is the Msg/UpdateParams request type. // @@ -234,8 +223,8 @@ func (m *MsgUpdateParamsResponse) XXX_DiscardUnknown() { var xxx_messageInfo_MsgUpdateParamsResponse proto.InternalMessageInfo func init() { - proto.RegisterType((*MsgRegisterFeeShare)(nil), "juno.feepay.v1.MsgRegisterFeeShare") - proto.RegisterType((*MsgRegisterFeeShareResponse)(nil), "juno.feepay.v1.MsgRegisterFeeShareResponse") + proto.RegisterType((*MsgRegisterFeePayContract)(nil), "juno.feepay.v1.MsgRegisterFeePayContract") + proto.RegisterType((*MsgRegisterFeePayContractResponse)(nil), "juno.feepay.v1.MsgRegisterFeePayContractResponse") proto.RegisterType((*MsgUpdateParams)(nil), "juno.feepay.v1.MsgUpdateParams") proto.RegisterType((*MsgUpdateParamsResponse)(nil), "juno.feepay.v1.MsgUpdateParamsResponse") } @@ -243,37 +232,37 @@ func init() { func init() { proto.RegisterFile("juno/feepay/v1/tx.proto", fileDescriptor_d739bd30c8846fd5) } var fileDescriptor_d739bd30c8846fd5 = []byte{ - // 474 bytes of a gzipped FileDescriptorProto - 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x8c, 0x92, 0xcf, 0x6a, 0x14, 0x41, - 0x10, 0xc6, 0xa7, 0x93, 0x10, 0x48, 0x2b, 0x49, 0x1c, 0x83, 0x9b, 0x6c, 0xcc, 0xac, 0x4c, 0x0e, - 0xfe, 0x23, 0xd3, 0x24, 0x8a, 0x87, 0xdc, 0xdc, 0x80, 0x78, 0x59, 0x90, 0x09, 0x82, 0x78, 0x09, - 0x9d, 0x9d, 0xb2, 0x77, 0x24, 0x33, 0xdd, 0x74, 0xf5, 0x26, 0xd9, 0x6b, 0x6e, 0x9e, 0x14, 0x7c, - 0x81, 0x3c, 0x82, 0x07, 0x1f, 0x22, 0xc7, 0xa0, 0x17, 0x4f, 0x22, 0xbb, 0x82, 0x82, 0x2f, 0x21, - 0x33, 0xdd, 0x93, 0x4d, 0x76, 0x17, 0xf4, 0x36, 0x53, 0xdf, 0xaf, 0xbf, 0xfa, 0xba, 0xba, 0x68, - 0xed, 0x6d, 0x37, 0x97, 0xec, 0x0d, 0x80, 0xe2, 0x3d, 0x76, 0xb8, 0xc9, 0xcc, 0x71, 0xa4, 0xb4, - 0x34, 0xd2, 0x9f, 0x2f, 0x84, 0xc8, 0x0a, 0xd1, 0xe1, 0x66, 0x7d, 0x49, 0x48, 0x21, 0x4b, 0x89, - 0x15, 0x5f, 0x96, 0xaa, 0xdf, 0x16, 0x52, 0x8a, 0x03, 0x60, 0x5c, 0xa5, 0x8c, 0xe7, 0xb9, 0x34, - 0xdc, 0xa4, 0x32, 0x47, 0xa7, 0xd6, 0xda, 0x12, 0x33, 0x89, 0x2c, 0x43, 0x51, 0x78, 0x67, 0x28, - 0x9c, 0xb0, 0x62, 0x85, 0x3d, 0xeb, 0x67, 0x7f, 0x2a, 0xc7, 0x91, 0x40, 0x02, 0x72, 0xc0, 0xd4, - 0xa9, 0xe1, 0x29, 0xa1, 0x37, 0x5b, 0x28, 0x62, 0x10, 0x29, 0x1a, 0xd0, 0xcf, 0x00, 0x76, 0x3b, - 0x5c, 0x83, 0x7f, 0x9f, 0x2e, 0xb6, 0x65, 0x6e, 0x34, 0x6f, 0x9b, 0x3d, 0x9e, 0x24, 0x1a, 0x10, - 0x97, 0xc9, 0x1d, 0x72, 0x6f, 0x2e, 0x5e, 0xa8, 0xea, 0x4f, 0x6d, 0xb9, 0x40, 0x13, 0x50, 0x07, - 0xb2, 0x07, 0xfa, 0x02, 0x9d, 0xb2, 0x68, 0x55, 0xaf, 0xd0, 0x0d, 0xea, 0x1f, 0xa5, 0xa6, 0x93, - 0x68, 0x7e, 0x74, 0x09, 0x9e, 0x2e, 0xe1, 0x1b, 0x43, 0xc5, 0xe1, 0xdb, 0x33, 0xbf, 0x4f, 0x1b, - 0x5e, 0xb8, 0x46, 0x57, 0x27, 0x24, 0x8c, 0x01, 0x95, 0xcc, 0x11, 0xc2, 0xf7, 0x84, 0x2e, 0xb4, - 0x50, 0xbc, 0x54, 0x09, 0x37, 0xf0, 0x82, 0x6b, 0x9e, 0xa1, 0xff, 0x84, 0xce, 0xf1, 0xae, 0xe9, - 0x48, 0x9d, 0x9a, 0x9e, 0x8d, 0xdd, 0x5c, 0xfe, 0xf2, 0x79, 0x63, 0xc9, 0x0d, 0xc6, 0xf9, 0xef, - 0x1a, 0x9d, 0xe6, 0x22, 0x1e, 0xa2, 0xfe, 0x63, 0x3a, 0xab, 0x4a, 0x87, 0xf2, 0x02, 0xd7, 0xb6, - 0x6e, 0x45, 0x57, 0x1f, 0x2d, 0xb2, 0xfe, 0xcd, 0x99, 0xb3, 0xef, 0x0d, 0x2f, 0x76, 0xec, 0xf6, - 0xfc, 0xc9, 0xaf, 0x4f, 0x0f, 0x86, 0x2e, 0xe1, 0x0a, 0xad, 0x8d, 0x04, 0xaa, 0xc2, 0x6e, 0xfd, - 0x21, 0x74, 0xba, 0x85, 0xc2, 0x7f, 0x47, 0xe8, 0xe2, 0xd8, 0xcc, 0xd7, 0x47, 0xbb, 0x4d, 0xb8, - 0x76, 0xfd, 0xe1, 0x7f, 0x40, 0x17, 0xb3, 0x59, 0x3f, 0xf9, 0xfa, 0xf3, 0xe3, 0xd4, 0x5a, 0xb8, - 0xca, 0xc6, 0xb6, 0x92, 0x69, 0x77, 0xc8, 0x7f, 0x45, 0xaf, 0x5f, 0x19, 0x5e, 0x63, 0x42, 0x87, - 0xcb, 0x40, 0xfd, 0xee, 0x3f, 0x80, 0xaa, 0x7d, 0xf3, 0xf9, 0x59, 0x3f, 0x20, 0xe7, 0xfd, 0x80, - 0xfc, 0xe8, 0x07, 0xe4, 0xc3, 0x20, 0xf0, 0xce, 0x07, 0x81, 0xf7, 0x6d, 0x10, 0x78, 0xaf, 0x23, - 0x91, 0x9a, 0x4e, 0x77, 0x3f, 0x6a, 0xcb, 0x8c, 0xed, 0x94, 0x8f, 0xb2, 0xe3, 0xb6, 0x0a, 0x6d, - 0xd4, 0xe3, 0x2a, 0xac, 0xe9, 0x29, 0xc0, 0xfd, 0xd9, 0x72, 0x5b, 0x1f, 0xfd, 0x0d, 0x00, 0x00, - 0xff, 0xff, 0x11, 0xc7, 0x08, 0xcc, 0x5e, 0x03, 0x00, 0x00, + // 465 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x8c, 0x92, 0x4f, 0x6b, 0x13, 0x41, + 0x18, 0xc6, 0x77, 0x62, 0x29, 0x76, 0xd4, 0x08, 0x4b, 0x69, 0xfe, 0x28, 0x9b, 0xba, 0x22, 0xb6, + 0x8a, 0x3b, 0xa4, 0x8a, 0x87, 0xdc, 0x4c, 0x41, 0xbc, 0x04, 0xca, 0x8a, 0x20, 0x5e, 0xca, 0x34, + 0x79, 0x9d, 0xae, 0xb8, 0x33, 0xcb, 0xbc, 0x93, 0xd2, 0x5c, 0x8b, 0x37, 0x0f, 0x0a, 0x7e, 0x01, + 0xaf, 0xde, 0x3c, 0xf8, 0x21, 0x7a, 0x2c, 0x7a, 0xf1, 0x24, 0x92, 0x08, 0xfa, 0x31, 0x24, 0x3b, + 0xb3, 0xad, 0x59, 0x13, 0xf4, 0xb6, 0xfb, 0x3e, 0xcf, 0x3e, 0xef, 0x8f, 0x67, 0x5f, 0x5a, 0x7b, + 0x31, 0x94, 0x8a, 0x3d, 0x07, 0xc8, 0xf8, 0x88, 0x1d, 0xb4, 0x99, 0x39, 0x8c, 0x32, 0xad, 0x8c, + 0xf2, 0xab, 0x53, 0x21, 0xb2, 0x42, 0x74, 0xd0, 0x6e, 0xae, 0x0a, 0x25, 0x54, 0x2e, 0xb1, 0xe9, + 0x93, 0x75, 0x35, 0xaf, 0x0a, 0xa5, 0xc4, 0x4b, 0x60, 0x3c, 0x4b, 0x18, 0x97, 0x52, 0x19, 0x6e, + 0x12, 0x25, 0xd1, 0xa9, 0xb5, 0xbe, 0xc2, 0x54, 0x21, 0x4b, 0x51, 0x4c, 0xb3, 0x53, 0x14, 0x4e, + 0x68, 0x58, 0x61, 0xd7, 0xe6, 0xd9, 0x97, 0x22, 0xb1, 0x04, 0x24, 0x40, 0x02, 0x26, 0x85, 0x7a, + 0xa5, 0xa4, 0x3a, 0xbe, 0x5c, 0x0c, 0x5f, 0x11, 0xda, 0xe8, 0xa1, 0x88, 0x41, 0x24, 0x68, 0x40, + 0x3f, 0x04, 0xd8, 0xe1, 0xa3, 0x6d, 0x25, 0x8d, 0xe6, 0x7d, 0xe3, 0xdf, 0xa0, 0x55, 0x04, 0x39, + 0x00, 0xbd, 0xcb, 0x07, 0x03, 0x0d, 0x88, 0x75, 0xb2, 0x4e, 0x36, 0x56, 0xe2, 0x4b, 0x76, 0xfa, + 0xc0, 0x0e, 0xfd, 0x0e, 0x3d, 0xdf, 0x77, 0x9f, 0xd4, 0x2b, 0xeb, 0x64, 0xe3, 0xc2, 0x56, 0x10, + 0xcd, 0x56, 0x11, 0xcd, 0x06, 0xc7, 0xa7, 0xfe, 0xce, 0xd2, 0xaf, 0xf7, 0x2d, 0x2f, 0xbc, 0x4e, + 0xaf, 0x2d, 0xa4, 0x88, 0x01, 0x33, 0x25, 0x11, 0xc2, 0x37, 0x84, 0x5e, 0xee, 0xa1, 0x78, 0x92, + 0x0d, 0xb8, 0x81, 0x1d, 0xae, 0x79, 0x8a, 0xfe, 0x7d, 0xba, 0xc2, 0x87, 0x66, 0x5f, 0xe9, 0xc4, + 0x8c, 0x2c, 0x5c, 0xb7, 0xfe, 0xf9, 0xd3, 0x9d, 0x55, 0xd7, 0x8f, 0x23, 0x7c, 0x6c, 0x74, 0x22, + 0x45, 0x7c, 0x66, 0xf5, 0xef, 0xd1, 0xe5, 0x2c, 0x4f, 0x70, 0xc0, 0x6b, 0x65, 0x60, 0x9b, 0xdf, + 0x5d, 0x3a, 0xfe, 0xd6, 0xf2, 0x62, 0xe7, 0xed, 0x54, 0x8f, 0x7e, 0x7e, 0xbc, 0x75, 0x96, 0x12, + 0x36, 0x68, 0xad, 0x04, 0x54, 0xc0, 0x6e, 0xbd, 0xae, 0xd0, 0x73, 0x3d, 0x14, 0xfe, 0x07, 0x42, + 0xd7, 0x16, 0xb4, 0xbb, 0x59, 0xde, 0xb9, 0xb0, 0x82, 0x66, 0xfb, 0xbf, 0xad, 0xa7, 0x6d, 0xb5, + 0x8f, 0xbe, 0xfc, 0x78, 0x57, 0xb9, 0x1d, 0x6e, 0xb2, 0xbf, 0xce, 0x95, 0xe9, 0xf9, 0x40, 0x4f, + 0xe9, 0xc5, 0x99, 0x72, 0x5b, 0x73, 0xb6, 0xfe, 0x69, 0x68, 0xde, 0xfc, 0x87, 0xa1, 0x80, 0xe9, + 0x3e, 0x3a, 0x1e, 0x07, 0xe4, 0x64, 0x1c, 0x90, 0xef, 0xe3, 0x80, 0xbc, 0x9d, 0x04, 0xde, 0xc9, + 0x24, 0xf0, 0xbe, 0x4e, 0x02, 0xef, 0x59, 0x24, 0x12, 0xb3, 0x3f, 0xdc, 0x8b, 0xfa, 0x2a, 0x65, + 0xdb, 0xf9, 0x4f, 0x2b, 0x70, 0xd0, 0x82, 0x1f, 0x16, 0xe8, 0x66, 0x94, 0x01, 0xee, 0x2d, 0xe7, + 0x77, 0x7b, 0xf7, 0x77, 0x00, 0x00, 0x00, 0xff, 0xff, 0xdb, 0xd1, 0xc0, 0x0b, 0x85, 0x03, 0x00, + 0x00, } // Reference imports to suppress errors if they are not otherwise used. @@ -289,7 +278,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 { // RegisterFeeShare registers a new contract for receiving transaction fees - RegisterFeeShare(ctx context.Context, in *MsgRegisterFeeShare, opts ...grpc.CallOption) (*MsgRegisterFeeShareResponse, error) + RegisterFeePayContract(ctx context.Context, in *MsgRegisterFeePayContract, opts ...grpc.CallOption) (*MsgRegisterFeePayContractResponse, error) // Update the params of the module through gov v1 type. UpdateParams(ctx context.Context, in *MsgUpdateParams, opts ...grpc.CallOption) (*MsgUpdateParamsResponse, error) } @@ -302,9 +291,9 @@ func NewMsgClient(cc grpc1.ClientConn) MsgClient { return &msgClient{cc} } -func (c *msgClient) RegisterFeeShare(ctx context.Context, in *MsgRegisterFeeShare, opts ...grpc.CallOption) (*MsgRegisterFeeShareResponse, error) { - out := new(MsgRegisterFeeShareResponse) - err := c.cc.Invoke(ctx, "/juno.feepay.v1.Msg/RegisterFeeShare", in, out, opts...) +func (c *msgClient) RegisterFeePayContract(ctx context.Context, in *MsgRegisterFeePayContract, opts ...grpc.CallOption) (*MsgRegisterFeePayContractResponse, error) { + out := new(MsgRegisterFeePayContractResponse) + err := c.cc.Invoke(ctx, "/juno.feepay.v1.Msg/RegisterFeePayContract", in, out, opts...) if err != nil { return nil, err } @@ -323,7 +312,7 @@ func (c *msgClient) UpdateParams(ctx context.Context, in *MsgUpdateParams, opts // MsgServer is the server API for Msg service. type MsgServer interface { // RegisterFeeShare registers a new contract for receiving transaction fees - RegisterFeeShare(context.Context, *MsgRegisterFeeShare) (*MsgRegisterFeeShareResponse, error) + RegisterFeePayContract(context.Context, *MsgRegisterFeePayContract) (*MsgRegisterFeePayContractResponse, error) // Update the params of the module through gov v1 type. UpdateParams(context.Context, *MsgUpdateParams) (*MsgUpdateParamsResponse, error) } @@ -332,8 +321,8 @@ type MsgServer interface { type UnimplementedMsgServer struct { } -func (*UnimplementedMsgServer) RegisterFeeShare(ctx context.Context, req *MsgRegisterFeeShare) (*MsgRegisterFeeShareResponse, error) { - return nil, status.Errorf(codes.Unimplemented, "method RegisterFeeShare not implemented") +func (*UnimplementedMsgServer) RegisterFeePayContract(ctx context.Context, req *MsgRegisterFeePayContract) (*MsgRegisterFeePayContractResponse, error) { + return nil, status.Errorf(codes.Unimplemented, "method RegisterFeePayContract not implemented") } func (*UnimplementedMsgServer) UpdateParams(ctx context.Context, req *MsgUpdateParams) (*MsgUpdateParamsResponse, error) { return nil, status.Errorf(codes.Unimplemented, "method UpdateParams not implemented") @@ -343,20 +332,20 @@ func RegisterMsgServer(s grpc1.Server, srv MsgServer) { s.RegisterService(&_Msg_serviceDesc, srv) } -func _Msg_RegisterFeeShare_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { - in := new(MsgRegisterFeeShare) +func _Msg_RegisterFeePayContract_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(MsgRegisterFeePayContract) if err := dec(in); err != nil { return nil, err } if interceptor == nil { - return srv.(MsgServer).RegisterFeeShare(ctx, in) + return srv.(MsgServer).RegisterFeePayContract(ctx, in) } info := &grpc.UnaryServerInfo{ Server: srv, - FullMethod: "/juno.feepay.v1.Msg/RegisterFeeShare", + FullMethod: "/juno.feepay.v1.Msg/RegisterFeePayContract", } handler := func(ctx context.Context, req interface{}) (interface{}, error) { - return srv.(MsgServer).RegisterFeeShare(ctx, req.(*MsgRegisterFeeShare)) + return srv.(MsgServer).RegisterFeePayContract(ctx, req.(*MsgRegisterFeePayContract)) } return interceptor(ctx, in, info, handler) } @@ -384,8 +373,8 @@ var _Msg_serviceDesc = grpc.ServiceDesc{ HandlerType: (*MsgServer)(nil), Methods: []grpc.MethodDesc{ { - MethodName: "RegisterFeeShare", - Handler: _Msg_RegisterFeeShare_Handler, + MethodName: "RegisterFeePayContract", + Handler: _Msg_RegisterFeePayContract_Handler, }, { MethodName: "UpdateParams", @@ -396,7 +385,7 @@ var _Msg_serviceDesc = grpc.ServiceDesc{ Metadata: "juno/feepay/v1/tx.proto", } -func (m *MsgRegisterFeeShare) Marshal() (dAtA []byte, err error) { +func (m *MsgRegisterFeePayContract) Marshal() (dAtA []byte, err error) { size := m.Size() dAtA = make([]byte, size) n, err := m.MarshalToSizedBuffer(dAtA[:size]) @@ -406,41 +395,39 @@ func (m *MsgRegisterFeeShare) Marshal() (dAtA []byte, err error) { return dAtA[:n], nil } -func (m *MsgRegisterFeeShare) MarshalTo(dAtA []byte) (int, error) { +func (m *MsgRegisterFeePayContract) MarshalTo(dAtA []byte) (int, error) { size := m.Size() return m.MarshalToSizedBuffer(dAtA[:size]) } -func (m *MsgRegisterFeeShare) MarshalToSizedBuffer(dAtA []byte) (int, error) { +func (m *MsgRegisterFeePayContract) MarshalToSizedBuffer(dAtA []byte) (int, error) { i := len(dAtA) _ = i var l int _ = l - if len(m.WithdrawerAddress) > 0 { - i -= len(m.WithdrawerAddress) - copy(dAtA[i:], m.WithdrawerAddress) - i = encodeVarintTx(dAtA, i, uint64(len(m.WithdrawerAddress))) - i-- - dAtA[i] = 0x1a - } - if len(m.DeployerAddress) > 0 { - i -= len(m.DeployerAddress) - copy(dAtA[i:], m.DeployerAddress) - i = encodeVarintTx(dAtA, i, uint64(len(m.DeployerAddress))) + if m.Contract != nil { + { + size, err := m.Contract.MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarintTx(dAtA, i, uint64(size)) + } i-- dAtA[i] = 0x12 } - if len(m.ContractAddress) > 0 { - i -= len(m.ContractAddress) - copy(dAtA[i:], m.ContractAddress) - i = encodeVarintTx(dAtA, i, uint64(len(m.ContractAddress))) + if len(m.SenderAddress) > 0 { + i -= len(m.SenderAddress) + copy(dAtA[i:], m.SenderAddress) + i = encodeVarintTx(dAtA, i, uint64(len(m.SenderAddress))) i-- dAtA[i] = 0xa } return len(dAtA) - i, nil } -func (m *MsgRegisterFeeShareResponse) Marshal() (dAtA []byte, err error) { +func (m *MsgRegisterFeePayContractResponse) Marshal() (dAtA []byte, err error) { size := m.Size() dAtA = make([]byte, size) n, err := m.MarshalToSizedBuffer(dAtA[:size]) @@ -450,12 +437,12 @@ func (m *MsgRegisterFeeShareResponse) Marshal() (dAtA []byte, err error) { return dAtA[:n], nil } -func (m *MsgRegisterFeeShareResponse) MarshalTo(dAtA []byte) (int, error) { +func (m *MsgRegisterFeePayContractResponse) MarshalTo(dAtA []byte) (int, error) { size := m.Size() return m.MarshalToSizedBuffer(dAtA[:size]) } -func (m *MsgRegisterFeeShareResponse) MarshalToSizedBuffer(dAtA []byte) (int, error) { +func (m *MsgRegisterFeePayContractResponse) MarshalToSizedBuffer(dAtA []byte) (int, error) { i := len(dAtA) _ = i var l int @@ -537,28 +524,24 @@ func encodeVarintTx(dAtA []byte, offset int, v uint64) int { dAtA[offset] = uint8(v) return base } -func (m *MsgRegisterFeeShare) Size() (n int) { +func (m *MsgRegisterFeePayContract) Size() (n int) { if m == nil { return 0 } var l int _ = l - l = len(m.ContractAddress) + l = len(m.SenderAddress) if l > 0 { n += 1 + l + sovTx(uint64(l)) } - l = len(m.DeployerAddress) - if l > 0 { - n += 1 + l + sovTx(uint64(l)) - } - l = len(m.WithdrawerAddress) - if l > 0 { + if m.Contract != nil { + l = m.Contract.Size() n += 1 + l + sovTx(uint64(l)) } return n } -func (m *MsgRegisterFeeShareResponse) Size() (n int) { +func (m *MsgRegisterFeePayContractResponse) Size() (n int) { if m == nil { return 0 } @@ -597,7 +580,7 @@ func sovTx(x uint64) (n int) { func sozTx(x uint64) (n int) { return sovTx(uint64((x << 1) ^ uint64((int64(x) >> 63)))) } -func (m *MsgRegisterFeeShare) Unmarshal(dAtA []byte) error { +func (m *MsgRegisterFeePayContract) Unmarshal(dAtA []byte) error { l := len(dAtA) iNdEx := 0 for iNdEx < l { @@ -620,15 +603,15 @@ func (m *MsgRegisterFeeShare) Unmarshal(dAtA []byte) error { fieldNum := int32(wire >> 3) wireType := int(wire & 0x7) if wireType == 4 { - return fmt.Errorf("proto: MsgRegisterFeeShare: wiretype end group for non-group") + return fmt.Errorf("proto: MsgRegisterFeePayContract: wiretype end group for non-group") } if fieldNum <= 0 { - return fmt.Errorf("proto: MsgRegisterFeeShare: illegal tag %d (wire type %d)", fieldNum, wire) + return fmt.Errorf("proto: MsgRegisterFeePayContract: illegal tag %d (wire type %d)", fieldNum, wire) } switch fieldNum { case 1: if wireType != 2 { - return fmt.Errorf("proto: wrong wireType = %d for field ContractAddress", wireType) + return fmt.Errorf("proto: wrong wireType = %d for field SenderAddress", wireType) } var stringLen uint64 for shift := uint(0); ; shift += 7 { @@ -656,13 +639,13 @@ func (m *MsgRegisterFeeShare) Unmarshal(dAtA []byte) error { if postIndex > l { return io.ErrUnexpectedEOF } - m.ContractAddress = string(dAtA[iNdEx:postIndex]) + m.SenderAddress = string(dAtA[iNdEx:postIndex]) iNdEx = postIndex case 2: if wireType != 2 { - return fmt.Errorf("proto: wrong wireType = %d for field DeployerAddress", wireType) + return fmt.Errorf("proto: wrong wireType = %d for field Contract", wireType) } - var stringLen uint64 + var msglen int for shift := uint(0); ; shift += 7 { if shift >= 64 { return ErrIntOverflowTx @@ -672,55 +655,27 @@ func (m *MsgRegisterFeeShare) Unmarshal(dAtA []byte) error { } b := dAtA[iNdEx] iNdEx++ - stringLen |= uint64(b&0x7F) << shift + msglen |= int(b&0x7F) << shift if b < 0x80 { break } } - intStringLen := int(stringLen) - if intStringLen < 0 { + if msglen < 0 { return ErrInvalidLengthTx } - postIndex := iNdEx + intStringLen + postIndex := iNdEx + msglen if postIndex < 0 { return ErrInvalidLengthTx } if postIndex > l { return io.ErrUnexpectedEOF } - m.DeployerAddress = string(dAtA[iNdEx:postIndex]) - iNdEx = postIndex - case 3: - if wireType != 2 { - return fmt.Errorf("proto: wrong wireType = %d for field WithdrawerAddress", 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 + if m.Contract == nil { + m.Contract = &FeePayContract{} } - postIndex := iNdEx + intStringLen - if postIndex < 0 { - return ErrInvalidLengthTx - } - if postIndex > l { - return io.ErrUnexpectedEOF + if err := m.Contract.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err } - m.WithdrawerAddress = string(dAtA[iNdEx:postIndex]) iNdEx = postIndex default: iNdEx = preIndex @@ -743,7 +698,7 @@ func (m *MsgRegisterFeeShare) Unmarshal(dAtA []byte) error { } return nil } -func (m *MsgRegisterFeeShareResponse) Unmarshal(dAtA []byte) error { +func (m *MsgRegisterFeePayContractResponse) Unmarshal(dAtA []byte) error { l := len(dAtA) iNdEx := 0 for iNdEx < l { @@ -766,10 +721,10 @@ func (m *MsgRegisterFeeShareResponse) Unmarshal(dAtA []byte) error { fieldNum := int32(wire >> 3) wireType := int(wire & 0x7) if wireType == 4 { - return fmt.Errorf("proto: MsgRegisterFeeShareResponse: wiretype end group for non-group") + return fmt.Errorf("proto: MsgRegisterFeePayContractResponse: wiretype end group for non-group") } if fieldNum <= 0 { - return fmt.Errorf("proto: MsgRegisterFeeShareResponse: illegal tag %d (wire type %d)", fieldNum, wire) + return fmt.Errorf("proto: MsgRegisterFeePayContractResponse: illegal tag %d (wire type %d)", fieldNum, wire) } switch fieldNum { default: diff --git a/x/feepay/types/tx.pb.gw.go b/x/feepay/types/tx.pb.gw.go index f6442a242..3e14f4681 100644 --- a/x/feepay/types/tx.pb.gw.go +++ b/x/feepay/types/tx.pb.gw.go @@ -34,37 +34,37 @@ var _ = descriptor.ForMessage var _ = metadata.Join var ( - filter_Msg_RegisterFeeShare_0 = &utilities.DoubleArray{Encoding: map[string]int{}, Base: []int(nil), Check: []int(nil)} + filter_Msg_RegisterFeePayContract_0 = &utilities.DoubleArray{Encoding: map[string]int{}, Base: []int(nil), Check: []int(nil)} ) -func request_Msg_RegisterFeeShare_0(ctx context.Context, marshaler runtime.Marshaler, client MsgClient, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) { - var protoReq MsgRegisterFeeShare +func request_Msg_RegisterFeePayContract_0(ctx context.Context, marshaler runtime.Marshaler, client MsgClient, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) { + var protoReq MsgRegisterFeePayContract 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_Msg_RegisterFeeShare_0); err != nil { + if err := runtime.PopulateQueryParameters(&protoReq, req.Form, filter_Msg_RegisterFeePayContract_0); err != nil { return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err) } - msg, err := client.RegisterFeeShare(ctx, &protoReq, grpc.Header(&metadata.HeaderMD), grpc.Trailer(&metadata.TrailerMD)) + msg, err := client.RegisterFeePayContract(ctx, &protoReq, grpc.Header(&metadata.HeaderMD), grpc.Trailer(&metadata.TrailerMD)) return msg, metadata, err } -func local_request_Msg_RegisterFeeShare_0(ctx context.Context, marshaler runtime.Marshaler, server MsgServer, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) { - var protoReq MsgRegisterFeeShare +func local_request_Msg_RegisterFeePayContract_0(ctx context.Context, marshaler runtime.Marshaler, server MsgServer, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) { + var protoReq MsgRegisterFeePayContract 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_Msg_RegisterFeeShare_0); err != nil { + if err := runtime.PopulateQueryParameters(&protoReq, req.Form, filter_Msg_RegisterFeePayContract_0); err != nil { return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err) } - msg, err := server.RegisterFeeShare(ctx, &protoReq) + msg, err := server.RegisterFeePayContract(ctx, &protoReq) return msg, metadata, err } @@ -75,7 +75,7 @@ func local_request_Msg_RegisterFeeShare_0(ctx context.Context, marshaler runtime // Note that using this registration option will cause many gRPC library features to stop working. Consider using RegisterMsgHandlerFromEndpoint instead. func RegisterMsgHandlerServer(ctx context.Context, mux *runtime.ServeMux, server MsgServer) error { - mux.Handle("POST", pattern_Msg_RegisterFeeShare_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) { + mux.Handle("POST", pattern_Msg_RegisterFeePayContract_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) { ctx, cancel := context.WithCancel(req.Context()) defer cancel() var stream runtime.ServerTransportStream @@ -86,7 +86,7 @@ func RegisterMsgHandlerServer(ctx context.Context, mux *runtime.ServeMux, server runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) return } - resp, md, err := local_request_Msg_RegisterFeeShare_0(rctx, inboundMarshaler, server, req, pathParams) + resp, md, err := local_request_Msg_RegisterFeePayContract_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 { @@ -94,7 +94,7 @@ func RegisterMsgHandlerServer(ctx context.Context, mux *runtime.ServeMux, server return } - forward_Msg_RegisterFeeShare_0(ctx, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...) + forward_Msg_RegisterFeePayContract_0(ctx, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...) }) @@ -139,7 +139,7 @@ func RegisterMsgHandler(ctx context.Context, mux *runtime.ServeMux, conn *grpc.C // "MsgClient" to call the correct interceptors. func RegisterMsgHandlerClient(ctx context.Context, mux *runtime.ServeMux, client MsgClient) error { - mux.Handle("POST", pattern_Msg_RegisterFeeShare_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) { + mux.Handle("POST", pattern_Msg_RegisterFeePayContract_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) @@ -148,14 +148,14 @@ func RegisterMsgHandlerClient(ctx context.Context, mux *runtime.ServeMux, client runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) return } - resp, md, err := request_Msg_RegisterFeeShare_0(rctx, inboundMarshaler, client, req, pathParams) + resp, md, err := request_Msg_RegisterFeePayContract_0(rctx, inboundMarshaler, client, req, pathParams) ctx = runtime.NewServerMetadataContext(ctx, md) if err != nil { runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) return } - forward_Msg_RegisterFeeShare_0(ctx, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...) + forward_Msg_RegisterFeePayContract_0(ctx, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...) }) @@ -163,9 +163,9 @@ func RegisterMsgHandlerClient(ctx context.Context, mux *runtime.ServeMux, client } var ( - pattern_Msg_RegisterFeeShare_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2, 2, 3, 2, 4}, []string{"juno", "feepay", "v1", "tx", "register"}, "", runtime.AssumeColonVerbOpt(false))) + pattern_Msg_RegisterFeePayContract_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2, 2, 3, 2, 4}, []string{"juno", "feepay", "v1", "tx", "registerFeePayContract"}, "", runtime.AssumeColonVerbOpt(false))) ) var ( - forward_Msg_RegisterFeeShare_0 = runtime.ForwardResponseMessage + forward_Msg_RegisterFeePayContract_0 = runtime.ForwardResponseMessage ) From 4d558ea786274ceb3de8901aadcda30321a47bcd Mon Sep 17 00:00:00 2001 From: Reece Williams Date: Thu, 31 Aug 2023 22:57:09 -0500 Subject: [PATCH 14/79] Add BondDenom to ante --- app/ante.go | 4 +++- app/app.go | 1 + x/feepay/ante/dedcuct_fee.go | 5 ++++- 3 files changed, 8 insertions(+), 2 deletions(-) diff --git a/app/ante.go b/app/ante.go index b91522092..766a33142 100644 --- a/app/ante.go +++ b/app/ante.go @@ -53,6 +53,8 @@ type HandlerOptions struct { BuilderKeeper builderkeeper.Keeper TxEncoder sdk.TxEncoder Mempool builderante.Mempool + + BondDenom string } // NewAnteHandler returns an AnteHandler that checks and increments sequence @@ -89,7 +91,7 @@ func NewAnteHandler(options HandlerOptions) (sdk.AnteHandler, error) { ante.NewConsumeGasForTxSizeDecorator(options.AccountKeeper), // globalfeeante.NewFeeDecorator(options.BypassMinFeeMsgTypes, options.GlobalFeeKeeper, options.StakingKeeper, maxBypassMinFeeMsgGasUsage), // TODO: Has a minimum fee requrement check. So if 0 fees are passed, but 500 fee is required, it fails. // ante.NewDeductFeeDecorator(options.AccountKeeper, options.BankKeeper, options.FeegrantKeeper, options.TxFeeChecker), // OLD, new is in decorators - feepayante.NewDeductFeeDecorator(options.FeePayKeeper, options.GlobalFeeKeeper, options.AccountKeeper, options.BankKeeper, options.FeegrantKeeper, options.TxFeeChecker), // TODO: look into to deduct fee from the module account + feepayante.NewDeductFeeDecorator(options.FeePayKeeper, options.GlobalFeeKeeper, options.AccountKeeper, options.BankKeeper, options.FeegrantKeeper, options.TxFeeChecker, options.BondDenom), // TODO: look into to deduct fee from the module account feeshareante.NewFeeSharePayoutDecorator(options.BankKeeper, options.FeeShareKeeper), // SetPubKeyDecorator must be called before all signature verification decorators ante.NewSetPubKeyDecorator(options.AccountKeeper), diff --git a/app/app.go b/app/app.go index 0a6aa96c3..13ac2674d 100644 --- a/app/app.go +++ b/app/app.go @@ -366,6 +366,7 @@ func New( TxEncoder: app.txConfig.TxEncoder(), BuilderKeeper: app.AppKeepers.BuildKeeper, Mempool: mempool, + BondDenom: app.GetChainBondDenom(), }, ) if err != nil { diff --git a/x/feepay/ante/dedcuct_fee.go b/x/feepay/ante/dedcuct_fee.go index 2479d2d1d..1f70b6077 100644 --- a/x/feepay/ante/dedcuct_fee.go +++ b/x/feepay/ante/dedcuct_fee.go @@ -35,9 +35,11 @@ type DeductFeeDecorator struct { // the effective fee should be deducted later, and the priority should be returned in abci response. // type TxFeeChecker func(ctx sdk.Context, tx sdk.Tx) (sdk.Coins, int64, error) txFeeChecker ante.TxFeeChecker + + bondDenom string } -func NewDeductFeeDecorator(fpk feepaykeeper.Keeper, gfk globalfeekeeper.Keeper, ak ante.AccountKeeper, bk bankkeeper.Keeper, fgk ante.FeegrantKeeper, tfc ante.TxFeeChecker) DeductFeeDecorator { +func NewDeductFeeDecorator(fpk feepaykeeper.Keeper, gfk globalfeekeeper.Keeper, ak ante.AccountKeeper, bk bankkeeper.Keeper, fgk ante.FeegrantKeeper, tfc ante.TxFeeChecker, bondDenom string) DeductFeeDecorator { if tfc == nil { tfc = checkTxFeeWithValidatorMinGasPrices } @@ -49,6 +51,7 @@ func NewDeductFeeDecorator(fpk feepaykeeper.Keeper, gfk globalfeekeeper.Keeper, bankKeeper: bk, feegrantKeeper: fgk, txFeeChecker: tfc, + bondDenom: bondDenom, } } From 282301fa2071f4e4a6ce67d96d8d70787cd86fa8 Mon Sep 17 00:00:00 2001 From: Joel Smith Date: Fri, 1 Sep 2023 12:56:38 -0500 Subject: [PATCH 15/79] Cover exact fee --- x/feepay/ante/dedcuct_fee.go | 30 +++++++++++++++++++++++------- x/feepay/keeper/keeper.go | 9 --------- 2 files changed, 23 insertions(+), 16 deletions(-) diff --git a/x/feepay/ante/dedcuct_fee.go b/x/feepay/ante/dedcuct_fee.go index 1f70b6077..37bc41351 100644 --- a/x/feepay/ante/dedcuct_fee.go +++ b/x/feepay/ante/dedcuct_fee.go @@ -158,22 +158,38 @@ func (dfd DeductFeeDecorator) handleZeroFees(ctx sdk.Context, deductFeesFromAcc return sdkerrors.ErrInvalidRequest.Wrapf("contract %s is not registered for fee pay", cw.GetContract()) } - // TODO: instead of hardcoding payment, GetGas() * globalFeeParam.GetParams(ctx).MinimumGasPrices of ujuno or ujunox (app.GetDenom() func). - // feeTx := tx.(sdk.FeeTx) - // gas := feeTx.GetGas() + // Get the fee price in the chain denom + var feePrice sdk.DecCoin + for _, c := range dfd.globalfeeKeeper.GetParams(ctx).MinimumGasPrices { + if c.Denom == dfd.bondDenom { + feePrice = c + } + } + + ctx.Logger().Error("HandleZeroFees", "FeePrice", feePrice) + + // Get the tx gas + feeTx := tx.(sdk.FeeTx) + gas := sdkmath.LegacyNewDec(int64(feeTx.GetGas())) + + ctx.Logger().Error("HandleZeroFees", "Gas", gas) + + requiredFee := feePrice.Amount.Mul(gas).Ceil().RoundInt() + + ctx.Logger().Error("HandleZeroFees", "RequiredFee", requiredFee) - payment := sdk.NewCoins(sdk.NewCoin("ujuno", sdk.NewDec(500_000).RoundInt())) + // Create an array of coins, storing the required fee + payment := sdk.NewCoins(sdk.NewCoin(feePrice.Denom, requiredFee)) ctx.Logger().Error("HandleZeroFees", "Payment", payment) - // keeper.SendCoinsFromModuleToAccount(ctx, "feeprepay", deductFeesFromAcc.GetAddress(), payment) + // Cover the fees of the transaction, send from FeePay Module to FeeCollector Module err := dfd.bankKeeper.SendCoinsFromModuleToModule(ctx, feepaytypes.ModuleName, types.FeeCollectorName, payment) - // Handle error + // Throw transfer errors if err != nil { ctx.Logger().Error("HandleZeroFees", "Error transfering funds from module to module", err) return sdkerrors.ErrInsufficientFunds.Wrapf("error transfering funds from module to module: %s", err) - // return nil } ctx.Logger().Error("HandleZeroFees", "Ending", true) diff --git a/x/feepay/keeper/keeper.go b/x/feepay/keeper/keeper.go index 622f68e29..4a6826137 100644 --- a/x/feepay/keeper/keeper.go +++ b/x/feepay/keeper/keeper.go @@ -93,12 +93,3 @@ func (k Keeper) RegisterContract(ctx sdk.Context, fpc types.FeePayContract) bool // Return true by default (for now) return true } - -// FeeShare - how to do a map. store.Get() - -// KV -// -> KVs `string -> []bytes` -// Store users interactions on a contract -> int -// "user-interaction" < key -// "userAddr-contractAddr" -> []byte(1) -// feeshare.go < how to do kvs From 845ae4b410f9562a6307a893f482cecd3dc0ac3a Mon Sep 17 00:00:00 2001 From: Joel Smith Date: Fri, 1 Sep 2023 13:17:49 -0500 Subject: [PATCH 16/79] Start fund contract tx --- app/ante.go | 3 +- proto/juno/feepay/v1/tx.proto | 30 ++ x/feepay/client/cli/tx.go | 45 +++ x/feepay/keeper/msg_server.go | 8 + x/feepay/types/codec.go | 3 + x/feepay/types/msg.go | 24 ++ x/feepay/types/tx.pb.go | 524 +++++++++++++++++++++++++++++++--- x/feepay/types/tx.pb.gw.go | 83 ++++++ 8 files changed, 685 insertions(+), 35 deletions(-) diff --git a/app/ante.go b/app/ante.go index 766a33142..c750fb534 100644 --- a/app/ante.go +++ b/app/ante.go @@ -90,8 +90,7 @@ func NewAnteHandler(options HandlerOptions) (sdk.AnteHandler, error) { ante.NewValidateMemoDecorator(options.AccountKeeper), ante.NewConsumeGasForTxSizeDecorator(options.AccountKeeper), // globalfeeante.NewFeeDecorator(options.BypassMinFeeMsgTypes, options.GlobalFeeKeeper, options.StakingKeeper, maxBypassMinFeeMsgGasUsage), // TODO: Has a minimum fee requrement check. So if 0 fees are passed, but 500 fee is required, it fails. - // ante.NewDeductFeeDecorator(options.AccountKeeper, options.BankKeeper, options.FeegrantKeeper, options.TxFeeChecker), // OLD, new is in decorators - feepayante.NewDeductFeeDecorator(options.FeePayKeeper, options.GlobalFeeKeeper, options.AccountKeeper, options.BankKeeper, options.FeegrantKeeper, options.TxFeeChecker, options.BondDenom), // TODO: look into to deduct fee from the module account + feepayante.NewDeductFeeDecorator(options.FeePayKeeper, options.GlobalFeeKeeper, options.AccountKeeper, options.BankKeeper, options.FeegrantKeeper, options.TxFeeChecker, options.BondDenom), feeshareante.NewFeeSharePayoutDecorator(options.BankKeeper, options.FeeShareKeeper), // SetPubKeyDecorator must be called before all signature verification decorators ante.NewSetPubKeyDecorator(options.AccountKeeper), diff --git a/proto/juno/feepay/v1/tx.proto b/proto/juno/feepay/v1/tx.proto index 7ced3ba12..fae3f66df 100644 --- a/proto/juno/feepay/v1/tx.proto +++ b/proto/juno/feepay/v1/tx.proto @@ -3,7 +3,9 @@ package juno.feepay.v1; import "gogoproto/gogo.proto"; import "google/api/annotations.proto"; +import "amino/amino.proto"; import "cosmos/msg/v1/msg.proto"; +import "cosmos/base/v1beta1/coin.proto"; import "cosmos_proto/cosmos.proto"; import "juno/feepay/v1/genesis.proto"; import "juno/feepay/v1/feepay.proto"; @@ -17,6 +19,12 @@ service Msg { returns (MsgRegisterFeePayContractResponse) { option (google.api.http).post = "/juno/feepay/v1/tx/registerFeePayContract"; }; + + // Fund a fee pay contract + rpc FundFeePayContract(MsgFundFeePayContract) + returns (MsgFundFeePayContractResponse) { + option (google.api.http).post = "/juno/feepay/v1/tx/fundFeePayContract"; + }; // Update the params of the module through gov v1 type. rpc UpdateParams(MsgUpdateParams) returns (MsgUpdateParamsResponse); @@ -36,6 +44,28 @@ message MsgRegisterFeePayContract { // The response message for registering a fee pay contract. message MsgRegisterFeePayContractResponse {} +// The message to fund a fee pay contract +message MsgFundFeePayContract { + option (gogoproto.equal) = false; + + // The wallet address of the sender. + string sender_address = 1; + + // The fee pay contract to fund. + string contract_address = 2; + + // The coins to fund the contract with. + repeated cosmos.base.v1beta1.Coin amount = 3 [ + (gogoproto.nullable) = false, + (amino.dont_omitempty) = true, + (amino.encoding) = "legacy_coins", + (gogoproto.castrepeated) = "github.com/cosmos/cosmos-sdk/types.Coins" + ]; +} + +// The response message for funding a fee pay contract. +message MsgFundFeePayContractResponse {} + // MsgUpdateParams is the Msg/UpdateParams request type. // // Since: cosmos-sdk 0.47 diff --git a/x/feepay/client/cli/tx.go b/x/feepay/client/cli/tx.go index eef74cc0d..1995916e8 100644 --- a/x/feepay/client/cli/tx.go +++ b/x/feepay/client/cli/tx.go @@ -8,6 +8,7 @@ import ( "github.com/cosmos/cosmos-sdk/client" "github.com/cosmos/cosmos-sdk/client/flags" "github.com/cosmos/cosmos-sdk/client/tx" + sdk "github.com/cosmos/cosmos-sdk/types" "github.com/CosmosContracts/juno/v17/x/feepay/types" ) @@ -74,3 +75,47 @@ func NewRegisterFeePayContract() *cobra.Command { flags.AddTxFlagsToCmd(cmd) return cmd } + +// NewRegisterFeeShare returns a CLI command handler for +// funding a fee pay contract. +func NewFundFeePayContract() *cobra.Command { + cmd := &cobra.Command{ + Use: "fund [contract_bech32] [ujuno]", + Short: "Send funds to a registered fee pay contract.", + Long: "Send funds to a registered fee pay contract.", + Args: cobra.ExactArgs(2), + RunE: func(cmd *cobra.Command, args []string) error { + cliCtx, err := client.GetClientTxContext(cmd) + if err != nil { + return err + } + + sender_address := cliCtx.GetFromAddress() + contract_address := args[0] + ujuno_string := args[1] + ujuno, err := strconv.ParseUint(ujuno_string, 10, 64) + + if err != nil { + return err + } + + // TODO: GET REFERENCE TO DENOM + amount := sdk.NewCoin(cliCtx.Denom, ujuno) + + msg := &types.MsgFundFeePayContract{ + SenderAddress: sender_address.String(), + ContractAddress: contract_address, + Amount: amount, + } + + if err := msg.ValidateBasic(); err != nil { + return err + } + + return tx.GenerateOrBroadcastTxCLI(cliCtx, cmd.Flags(), msg) + }, + } + + flags.AddTxFlagsToCmd(cmd) + return cmd +} diff --git a/x/feepay/keeper/msg_server.go b/x/feepay/keeper/msg_server.go index 5072a6e18..970303b62 100644 --- a/x/feepay/keeper/msg_server.go +++ b/x/feepay/keeper/msg_server.go @@ -19,6 +19,14 @@ func (k Keeper) RegisterFeePayContract(goCtx context.Context, msg *types.MsgRegi return &types.MsgRegisterFeePayContractResponse{}, nil } +// FundFeePayContract funds a contract with the given amount of tokens. +func (k Keeper) FundFeePayContract(goCtx context.Context, msg *types.MsgFundFeePayContract) (*types.MsgFundFeePayContractResponse, error) { + + // TODO: IMPLEMENT + + return nil, nil +} + func (k Keeper) UpdateParams(goCtx context.Context, req *types.MsgUpdateParams) (*types.MsgUpdateParamsResponse, error) { if k.authority != req.Authority { return nil, errorsmod.Wrapf(govtypes.ErrInvalidSigner, "invalid authority; expected %s, got %s", k.authority, req.Authority) diff --git a/x/feepay/types/codec.go b/x/feepay/types/codec.go index 3ce0e8201..5fee01649 100644 --- a/x/feepay/types/codec.go +++ b/x/feepay/types/codec.go @@ -25,6 +25,7 @@ var ( const ( // Amino names registerFeePayContract = "juno/MsgRegisterFeePayContract" + FundFeePayContract = "juno/MsgFundFeePayContract" updateFeeShareParams = "juno/MsgFeePayUpdateParams" ) @@ -45,6 +46,7 @@ func RegisterInterfaces(registry codectypes.InterfaceRegistry) { registry.RegisterImplementations( (*sdk.Msg)(nil), &MsgRegisterFeePayContract{}, + &MsgFundFeePayContract{}, &MsgUpdateParams{}, ) @@ -56,5 +58,6 @@ func RegisterInterfaces(registry codectypes.InterfaceRegistry) { // Amino JSON serialization and EIP-712 compatibility. func RegisterLegacyAminoCodec(cdc *codec.LegacyAmino) { cdc.RegisterConcrete(&MsgRegisterFeePayContract{}, registerFeePayContract, nil) + cdc.RegisterConcrete(&MsgFundFeePayContract{}, FundFeePayContract, nil) cdc.RegisterConcrete(&MsgUpdateParams{}, updateFeeShareParams, nil) } diff --git a/x/feepay/types/msg.go b/x/feepay/types/msg.go index a74b8b183..16c7a6400 100644 --- a/x/feepay/types/msg.go +++ b/x/feepay/types/msg.go @@ -6,11 +6,13 @@ import ( var ( _ sdk.Msg = &MsgRegisterFeePayContract{} + _ sdk.Msg = &MsgFundFeePayContract{} _ sdk.Msg = &MsgUpdateParams{} ) const ( TypeMsgRegisterFeePayContract = "register_feepay_contract" + TypeMsgFundFeePayContract = "fund_feepay_contract" TypeMsgUpdateParams = "msg_update_params" ) @@ -36,6 +38,28 @@ func (msg MsgRegisterFeePayContract) GetSigners() []sdk.AccAddress { return []sdk.AccAddress{from} } +// Route returns the name of the module +func (msg MsgFundFeePayContract) Route() string { return RouterKey } + +// Type returns the the action +func (msg MsgFundFeePayContract) Type() string { return TypeMsgFundFeePayContract } + +// ValidateBasic runs stateless checks on the message +func (msg MsgFundFeePayContract) ValidateBasic() error { + return nil +} + +// GetSignBytes encodes the message for signing +func (msg *MsgFundFeePayContract) GetSignBytes() []byte { + return sdk.MustSortJSON(AminoCdc.MustMarshalJSON(msg)) +} + +// GetSigners defines whose signature is required +func (msg MsgFundFeePayContract) GetSigners() []sdk.AccAddress { + from, _ := sdk.AccAddressFromBech32(msg.SenderAddress) + return []sdk.AccAddress{from} +} + // Route returns the name of the module func (msg MsgUpdateParams) Route() string { return RouterKey } diff --git a/x/feepay/types/tx.pb.go b/x/feepay/types/tx.pb.go index ed5b05408..033834489 100644 --- a/x/feepay/types/tx.pb.go +++ b/x/feepay/types/tx.pb.go @@ -7,7 +7,10 @@ import ( context "context" fmt "fmt" _ "github.com/cosmos/cosmos-proto" + github_com_cosmos_cosmos_sdk_types "github.com/cosmos/cosmos-sdk/types" + types "github.com/cosmos/cosmos-sdk/types" _ "github.com/cosmos/cosmos-sdk/types/msgservice" + _ "github.com/cosmos/cosmos-sdk/types/tx/amino" _ "github.com/cosmos/gogoproto/gogoproto" grpc1 "github.com/cosmos/gogoproto/grpc" proto "github.com/cosmos/gogoproto/proto" @@ -123,6 +126,107 @@ func (m *MsgRegisterFeePayContractResponse) XXX_DiscardUnknown() { var xxx_messageInfo_MsgRegisterFeePayContractResponse proto.InternalMessageInfo +// The message to fund a fee pay contract +type MsgFundFeePayContract struct { + // The wallet address of the sender. + SenderAddress string `protobuf:"bytes,1,opt,name=sender_address,json=senderAddress,proto3" json:"sender_address,omitempty"` + // The fee pay contract to fund. + ContractAddress string `protobuf:"bytes,2,opt,name=contract_address,json=contractAddress,proto3" json:"contract_address,omitempty"` + // The coins to fund the contract with. + Amount github_com_cosmos_cosmos_sdk_types.Coins `protobuf:"bytes,3,rep,name=amount,proto3,castrepeated=github.com/cosmos/cosmos-sdk/types.Coins" json:"amount"` +} + +func (m *MsgFundFeePayContract) Reset() { *m = MsgFundFeePayContract{} } +func (m *MsgFundFeePayContract) String() string { return proto.CompactTextString(m) } +func (*MsgFundFeePayContract) ProtoMessage() {} +func (*MsgFundFeePayContract) Descriptor() ([]byte, []int) { + return fileDescriptor_d739bd30c8846fd5, []int{2} +} +func (m *MsgFundFeePayContract) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *MsgFundFeePayContract) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_MsgFundFeePayContract.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 *MsgFundFeePayContract) XXX_Merge(src proto.Message) { + xxx_messageInfo_MsgFundFeePayContract.Merge(m, src) +} +func (m *MsgFundFeePayContract) XXX_Size() int { + return m.Size() +} +func (m *MsgFundFeePayContract) XXX_DiscardUnknown() { + xxx_messageInfo_MsgFundFeePayContract.DiscardUnknown(m) +} + +var xxx_messageInfo_MsgFundFeePayContract proto.InternalMessageInfo + +func (m *MsgFundFeePayContract) GetSenderAddress() string { + if m != nil { + return m.SenderAddress + } + return "" +} + +func (m *MsgFundFeePayContract) GetContractAddress() string { + if m != nil { + return m.ContractAddress + } + return "" +} + +func (m *MsgFundFeePayContract) GetAmount() github_com_cosmos_cosmos_sdk_types.Coins { + if m != nil { + return m.Amount + } + return nil +} + +// The response message for funding a fee pay contract. +type MsgFundFeePayContractResponse struct { +} + +func (m *MsgFundFeePayContractResponse) Reset() { *m = MsgFundFeePayContractResponse{} } +func (m *MsgFundFeePayContractResponse) String() string { return proto.CompactTextString(m) } +func (*MsgFundFeePayContractResponse) ProtoMessage() {} +func (*MsgFundFeePayContractResponse) Descriptor() ([]byte, []int) { + return fileDescriptor_d739bd30c8846fd5, []int{3} +} +func (m *MsgFundFeePayContractResponse) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *MsgFundFeePayContractResponse) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_MsgFundFeePayContractResponse.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 *MsgFundFeePayContractResponse) XXX_Merge(src proto.Message) { + xxx_messageInfo_MsgFundFeePayContractResponse.Merge(m, src) +} +func (m *MsgFundFeePayContractResponse) XXX_Size() int { + return m.Size() +} +func (m *MsgFundFeePayContractResponse) XXX_DiscardUnknown() { + xxx_messageInfo_MsgFundFeePayContractResponse.DiscardUnknown(m) +} + +var xxx_messageInfo_MsgFundFeePayContractResponse proto.InternalMessageInfo + // MsgUpdateParams is the Msg/UpdateParams request type. // // Since: cosmos-sdk 0.47 @@ -139,7 +243,7 @@ func (m *MsgUpdateParams) Reset() { *m = MsgUpdateParams{} } func (m *MsgUpdateParams) String() string { return proto.CompactTextString(m) } func (*MsgUpdateParams) ProtoMessage() {} func (*MsgUpdateParams) Descriptor() ([]byte, []int) { - return fileDescriptor_d739bd30c8846fd5, []int{2} + return fileDescriptor_d739bd30c8846fd5, []int{4} } func (m *MsgUpdateParams) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -193,7 +297,7 @@ func (m *MsgUpdateParamsResponse) Reset() { *m = MsgUpdateParamsResponse func (m *MsgUpdateParamsResponse) String() string { return proto.CompactTextString(m) } func (*MsgUpdateParamsResponse) ProtoMessage() {} func (*MsgUpdateParamsResponse) Descriptor() ([]byte, []int) { - return fileDescriptor_d739bd30c8846fd5, []int{3} + return fileDescriptor_d739bd30c8846fd5, []int{5} } func (m *MsgUpdateParamsResponse) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -225,6 +329,8 @@ var xxx_messageInfo_MsgUpdateParamsResponse proto.InternalMessageInfo func init() { proto.RegisterType((*MsgRegisterFeePayContract)(nil), "juno.feepay.v1.MsgRegisterFeePayContract") proto.RegisterType((*MsgRegisterFeePayContractResponse)(nil), "juno.feepay.v1.MsgRegisterFeePayContractResponse") + proto.RegisterType((*MsgFundFeePayContract)(nil), "juno.feepay.v1.MsgFundFeePayContract") + proto.RegisterType((*MsgFundFeePayContractResponse)(nil), "juno.feepay.v1.MsgFundFeePayContractResponse") proto.RegisterType((*MsgUpdateParams)(nil), "juno.feepay.v1.MsgUpdateParams") proto.RegisterType((*MsgUpdateParamsResponse)(nil), "juno.feepay.v1.MsgUpdateParamsResponse") } @@ -232,37 +338,47 @@ func init() { func init() { proto.RegisterFile("juno/feepay/v1/tx.proto", fileDescriptor_d739bd30c8846fd5) } var fileDescriptor_d739bd30c8846fd5 = []byte{ - // 465 bytes of a gzipped FileDescriptorProto - 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x8c, 0x92, 0x4f, 0x6b, 0x13, 0x41, - 0x18, 0xc6, 0x77, 0x62, 0x29, 0x76, 0xd4, 0x08, 0x4b, 0x69, 0xfe, 0x28, 0x9b, 0xba, 0x22, 0xb6, - 0x8a, 0x3b, 0xa4, 0x8a, 0x87, 0xdc, 0x4c, 0x41, 0xbc, 0x04, 0xca, 0x8a, 0x20, 0x5e, 0xca, 0x34, - 0x79, 0x9d, 0xae, 0xb8, 0x33, 0xcb, 0xbc, 0x93, 0xd2, 0x5c, 0x8b, 0x37, 0x0f, 0x0a, 0x7e, 0x01, - 0xaf, 0xde, 0x3c, 0xf8, 0x21, 0x7a, 0x2c, 0x7a, 0xf1, 0x24, 0x92, 0x08, 0xfa, 0x31, 0x24, 0x3b, - 0xb3, 0xad, 0x59, 0x13, 0xf4, 0xb6, 0xfb, 0x3e, 0xcf, 0x3e, 0xef, 0x8f, 0x67, 0x5f, 0x5a, 0x7b, - 0x31, 0x94, 0x8a, 0x3d, 0x07, 0xc8, 0xf8, 0x88, 0x1d, 0xb4, 0x99, 0x39, 0x8c, 0x32, 0xad, 0x8c, - 0xf2, 0xab, 0x53, 0x21, 0xb2, 0x42, 0x74, 0xd0, 0x6e, 0xae, 0x0a, 0x25, 0x54, 0x2e, 0xb1, 0xe9, - 0x93, 0x75, 0x35, 0xaf, 0x0a, 0xa5, 0xc4, 0x4b, 0x60, 0x3c, 0x4b, 0x18, 0x97, 0x52, 0x19, 0x6e, - 0x12, 0x25, 0xd1, 0xa9, 0xb5, 0xbe, 0xc2, 0x54, 0x21, 0x4b, 0x51, 0x4c, 0xb3, 0x53, 0x14, 0x4e, - 0x68, 0x58, 0x61, 0xd7, 0xe6, 0xd9, 0x97, 0x22, 0xb1, 0x04, 0x24, 0x40, 0x02, 0x26, 0x85, 0x7a, - 0xa5, 0xa4, 0x3a, 0xbe, 0x5c, 0x0c, 0x5f, 0x11, 0xda, 0xe8, 0xa1, 0x88, 0x41, 0x24, 0x68, 0x40, - 0x3f, 0x04, 0xd8, 0xe1, 0xa3, 0x6d, 0x25, 0x8d, 0xe6, 0x7d, 0xe3, 0xdf, 0xa0, 0x55, 0x04, 0x39, - 0x00, 0xbd, 0xcb, 0x07, 0x03, 0x0d, 0x88, 0x75, 0xb2, 0x4e, 0x36, 0x56, 0xe2, 0x4b, 0x76, 0xfa, - 0xc0, 0x0e, 0xfd, 0x0e, 0x3d, 0xdf, 0x77, 0x9f, 0xd4, 0x2b, 0xeb, 0x64, 0xe3, 0xc2, 0x56, 0x10, - 0xcd, 0x56, 0x11, 0xcd, 0x06, 0xc7, 0xa7, 0xfe, 0xce, 0xd2, 0xaf, 0xf7, 0x2d, 0x2f, 0xbc, 0x4e, - 0xaf, 0x2d, 0xa4, 0x88, 0x01, 0x33, 0x25, 0x11, 0xc2, 0x37, 0x84, 0x5e, 0xee, 0xa1, 0x78, 0x92, - 0x0d, 0xb8, 0x81, 0x1d, 0xae, 0x79, 0x8a, 0xfe, 0x7d, 0xba, 0xc2, 0x87, 0x66, 0x5f, 0xe9, 0xc4, - 0x8c, 0x2c, 0x5c, 0xb7, 0xfe, 0xf9, 0xd3, 0x9d, 0x55, 0xd7, 0x8f, 0x23, 0x7c, 0x6c, 0x74, 0x22, - 0x45, 0x7c, 0x66, 0xf5, 0xef, 0xd1, 0xe5, 0x2c, 0x4f, 0x70, 0xc0, 0x6b, 0x65, 0x60, 0x9b, 0xdf, - 0x5d, 0x3a, 0xfe, 0xd6, 0xf2, 0x62, 0xe7, 0xed, 0x54, 0x8f, 0x7e, 0x7e, 0xbc, 0x75, 0x96, 0x12, - 0x36, 0x68, 0xad, 0x04, 0x54, 0xc0, 0x6e, 0xbd, 0xae, 0xd0, 0x73, 0x3d, 0x14, 0xfe, 0x07, 0x42, - 0xd7, 0x16, 0xb4, 0xbb, 0x59, 0xde, 0xb9, 0xb0, 0x82, 0x66, 0xfb, 0xbf, 0xad, 0xa7, 0x6d, 0xb5, - 0x8f, 0xbe, 0xfc, 0x78, 0x57, 0xb9, 0x1d, 0x6e, 0xb2, 0xbf, 0xce, 0x95, 0xe9, 0xf9, 0x40, 0x4f, - 0xe9, 0xc5, 0x99, 0x72, 0x5b, 0x73, 0xb6, 0xfe, 0x69, 0x68, 0xde, 0xfc, 0x87, 0xa1, 0x80, 0xe9, - 0x3e, 0x3a, 0x1e, 0x07, 0xe4, 0x64, 0x1c, 0x90, 0xef, 0xe3, 0x80, 0xbc, 0x9d, 0x04, 0xde, 0xc9, - 0x24, 0xf0, 0xbe, 0x4e, 0x02, 0xef, 0x59, 0x24, 0x12, 0xb3, 0x3f, 0xdc, 0x8b, 0xfa, 0x2a, 0x65, - 0xdb, 0xf9, 0x4f, 0x2b, 0x70, 0xd0, 0x82, 0x1f, 0x16, 0xe8, 0x66, 0x94, 0x01, 0xee, 0x2d, 0xe7, - 0x77, 0x7b, 0xf7, 0x77, 0x00, 0x00, 0x00, 0xff, 0xff, 0xdb, 0xd1, 0xc0, 0x0b, 0x85, 0x03, 0x00, - 0x00, + // 628 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x9c, 0x94, 0x4d, 0x4f, 0x13, 0x41, + 0x18, 0xc7, 0x3b, 0x94, 0x10, 0x19, 0x10, 0x74, 0x83, 0xd0, 0x56, 0xdd, 0xe2, 0x1a, 0x42, 0xc1, + 0x74, 0x27, 0x8b, 0xc6, 0x03, 0x37, 0x4b, 0x42, 0xbc, 0x34, 0x21, 0x6b, 0x4c, 0x8c, 0x17, 0x32, + 0xdd, 0x1d, 0x86, 0x55, 0x76, 0x66, 0xb3, 0x33, 0x25, 0xec, 0x95, 0x78, 0xd7, 0xc4, 0x93, 0x9e, + 0xbc, 0xf9, 0x72, 0xe2, 0xe0, 0x87, 0xe0, 0x48, 0xf4, 0xe2, 0x49, 0x0d, 0x35, 0xa9, 0xf1, 0x53, + 0x98, 0xdd, 0x9d, 0x2d, 0xb4, 0xdd, 0x46, 0xe2, 0xa5, 0x2f, 0xcf, 0xff, 0xbf, 0xcf, 0xf3, 0x7b, + 0x5e, 0x5a, 0xb8, 0xf0, 0xac, 0xcd, 0x38, 0xda, 0x21, 0x24, 0xc0, 0x11, 0xda, 0xb7, 0x90, 0x3c, + 0x30, 0x83, 0x90, 0x4b, 0xae, 0xcd, 0xc4, 0x82, 0x99, 0x0a, 0xe6, 0xbe, 0x55, 0x99, 0xa3, 0x9c, + 0xf2, 0x44, 0x42, 0xf1, 0xa7, 0xd4, 0x55, 0xb9, 0x41, 0x39, 0xa7, 0x7b, 0x04, 0xe1, 0xc0, 0x43, + 0x98, 0x31, 0x2e, 0xb1, 0xf4, 0x38, 0x13, 0x4a, 0xbd, 0x8a, 0x7d, 0x8f, 0x71, 0x94, 0xbc, 0xaa, + 0xd0, 0x82, 0xc3, 0x85, 0xcf, 0x05, 0xf2, 0x05, 0x8d, 0xcb, 0xf9, 0x82, 0x2a, 0x41, 0x57, 0x42, + 0x0b, 0x0b, 0x82, 0xf6, 0xad, 0x16, 0x91, 0xd8, 0x42, 0x0e, 0xf7, 0x98, 0xd2, 0xcb, 0xa9, 0xbe, + 0x9d, 0x22, 0xa4, 0x5f, 0x32, 0x88, 0x81, 0x1e, 0x28, 0x61, 0x44, 0x78, 0x99, 0x7a, 0x7d, 0x40, + 0x55, 0x2d, 0x25, 0xa2, 0xf1, 0x02, 0xc0, 0x72, 0x53, 0x50, 0x9b, 0x50, 0x4f, 0x48, 0x12, 0x6e, + 0x12, 0xb2, 0x85, 0xa3, 0x0d, 0xce, 0x64, 0x88, 0x1d, 0xa9, 0x2d, 0xc1, 0x19, 0x41, 0x98, 0x4b, + 0xc2, 0x6d, 0xec, 0xba, 0x21, 0x11, 0xa2, 0x04, 0x16, 0x41, 0x6d, 0xd2, 0xbe, 0x9c, 0x46, 0x1f, + 0xa4, 0x41, 0x6d, 0x1d, 0x5e, 0x72, 0xd4, 0x23, 0xa5, 0xb1, 0x45, 0x50, 0x9b, 0x5a, 0xd3, 0xcd, + 0xfe, 0xe9, 0x99, 0xfd, 0x89, 0xed, 0x9e, 0x7f, 0x7d, 0xfc, 0xf7, 0xbb, 0x6a, 0xc1, 0xb8, 0x0d, + 0x6f, 0x8d, 0xa4, 0xb0, 0x89, 0x08, 0x38, 0x13, 0xc4, 0xf8, 0x03, 0xe0, 0xb5, 0xa6, 0xa0, 0x9b, + 0x6d, 0xe6, 0xfe, 0x1f, 0xe7, 0x0a, 0xbc, 0x92, 0xd5, 0xed, 0x19, 0xc7, 0x12, 0xe3, 0x6c, 0x16, + 0xcf, 0xac, 0x11, 0x9c, 0xc0, 0x3e, 0x6f, 0x33, 0x59, 0x2a, 0x2e, 0x16, 0x6b, 0x53, 0x6b, 0x65, + 0x53, 0x4d, 0x3c, 0x5e, 0x8f, 0xa9, 0xd6, 0x63, 0x6e, 0x70, 0x8f, 0x35, 0x36, 0x8f, 0xbf, 0x57, + 0x0b, 0x9f, 0x7e, 0x54, 0x6b, 0xd4, 0x93, 0xbb, 0xed, 0x96, 0xe9, 0x70, 0x5f, 0xad, 0x47, 0xbd, + 0xd5, 0x85, 0xfb, 0x1c, 0xc9, 0x28, 0x20, 0x22, 0x79, 0x40, 0xbc, 0xed, 0x1e, 0xad, 0x4e, 0xef, + 0x11, 0x8a, 0x9d, 0x68, 0x3b, 0x5e, 0xb0, 0xf8, 0xd0, 0x3d, 0x5a, 0x05, 0xb6, 0x2a, 0xa8, 0x26, + 0x52, 0x85, 0x37, 0x73, 0x7b, 0xed, 0x4d, 0xe3, 0x25, 0x80, 0xb3, 0x4d, 0x41, 0x1f, 0x07, 0x2e, + 0x96, 0x64, 0x0b, 0x87, 0xd8, 0x17, 0xda, 0x7d, 0x38, 0x89, 0xdb, 0x72, 0x97, 0x87, 0x9e, 0x8c, + 0xd2, 0x11, 0x34, 0x4a, 0x5f, 0x3e, 0xd7, 0xe7, 0x14, 0xbb, 0x6a, 0xee, 0x91, 0x0c, 0x3d, 0x46, + 0xed, 0x33, 0xab, 0x76, 0x0f, 0x4e, 0x04, 0x49, 0x06, 0xb5, 0xbe, 0xf9, 0xc1, 0xf5, 0xa5, 0xf9, + 0x1b, 0xe3, 0x71, 0xab, 0xb6, 0xf2, 0xae, 0xcf, 0x1c, 0x76, 0x8f, 0x56, 0xcf, 0xb2, 0x18, 0x65, + 0xb8, 0x30, 0x00, 0x94, 0xc1, 0xae, 0xbd, 0x2f, 0xc2, 0x62, 0x53, 0x50, 0xed, 0x23, 0x80, 0xf3, + 0x23, 0x6e, 0x6d, 0x65, 0xb0, 0xe6, 0xc8, 0x83, 0xa8, 0x58, 0x17, 0xb6, 0xf6, 0xa6, 0x65, 0x1d, + 0x7e, 0xfd, 0xf5, 0x7a, 0xec, 0x8e, 0xb1, 0x82, 0x86, 0x7e, 0xef, 0x28, 0xcc, 0x07, 0x7a, 0x03, + 0xa0, 0x96, 0x77, 0x6b, 0x39, 0xc5, 0x87, 0x6d, 0x95, 0xfa, 0x85, 0x6c, 0x3d, 0xbe, 0x7a, 0xc2, + 0xb7, 0x6c, 0x2c, 0xe5, 0xf0, 0xed, 0x0c, 0x43, 0x3c, 0x81, 0xd3, 0x7d, 0x8b, 0xaf, 0xe6, 0x54, + 0x3b, 0x6f, 0xa8, 0x2c, 0xff, 0xc3, 0x90, 0x81, 0x34, 0x1e, 0x1e, 0x9f, 0xea, 0xe0, 0xe4, 0x54, + 0x07, 0x3f, 0x4f, 0x75, 0xf0, 0xaa, 0xa3, 0x17, 0x4e, 0x3a, 0x7a, 0xe1, 0x5b, 0x47, 0x2f, 0x3c, + 0x35, 0xcf, 0xdd, 0xf7, 0x46, 0x72, 0x50, 0x19, 0x8e, 0x48, 0xa1, 0x0f, 0x32, 0xec, 0xe4, 0xd6, + 0x5b, 0x13, 0xc9, 0x3f, 0xcc, 0xdd, 0xbf, 0x01, 0x00, 0x00, 0xff, 0xff, 0x93, 0x1a, 0x53, 0xb8, + 0x62, 0x05, 0x00, 0x00, } // Reference imports to suppress errors if they are not otherwise used. @@ -279,6 +395,8 @@ const _ = grpc.SupportPackageIsVersion4 type MsgClient interface { // RegisterFeeShare registers a new contract for receiving transaction fees RegisterFeePayContract(ctx context.Context, in *MsgRegisterFeePayContract, opts ...grpc.CallOption) (*MsgRegisterFeePayContractResponse, error) + // Fund a fee pay contract + FundFeePayContract(ctx context.Context, in *MsgFundFeePayContract, opts ...grpc.CallOption) (*MsgFundFeePayContractResponse, error) // Update the params of the module through gov v1 type. UpdateParams(ctx context.Context, in *MsgUpdateParams, opts ...grpc.CallOption) (*MsgUpdateParamsResponse, error) } @@ -300,6 +418,15 @@ func (c *msgClient) RegisterFeePayContract(ctx context.Context, in *MsgRegisterF return out, nil } +func (c *msgClient) FundFeePayContract(ctx context.Context, in *MsgFundFeePayContract, opts ...grpc.CallOption) (*MsgFundFeePayContractResponse, error) { + out := new(MsgFundFeePayContractResponse) + err := c.cc.Invoke(ctx, "/juno.feepay.v1.Msg/FundFeePayContract", in, out, opts...) + if err != nil { + return nil, err + } + return out, nil +} + func (c *msgClient) UpdateParams(ctx context.Context, in *MsgUpdateParams, opts ...grpc.CallOption) (*MsgUpdateParamsResponse, error) { out := new(MsgUpdateParamsResponse) err := c.cc.Invoke(ctx, "/juno.feepay.v1.Msg/UpdateParams", in, out, opts...) @@ -313,6 +440,8 @@ func (c *msgClient) UpdateParams(ctx context.Context, in *MsgUpdateParams, opts type MsgServer interface { // RegisterFeeShare registers a new contract for receiving transaction fees RegisterFeePayContract(context.Context, *MsgRegisterFeePayContract) (*MsgRegisterFeePayContractResponse, error) + // Fund a fee pay contract + FundFeePayContract(context.Context, *MsgFundFeePayContract) (*MsgFundFeePayContractResponse, error) // Update the params of the module through gov v1 type. UpdateParams(context.Context, *MsgUpdateParams) (*MsgUpdateParamsResponse, error) } @@ -324,6 +453,9 @@ type UnimplementedMsgServer struct { func (*UnimplementedMsgServer) RegisterFeePayContract(ctx context.Context, req *MsgRegisterFeePayContract) (*MsgRegisterFeePayContractResponse, error) { return nil, status.Errorf(codes.Unimplemented, "method RegisterFeePayContract not implemented") } +func (*UnimplementedMsgServer) FundFeePayContract(ctx context.Context, req *MsgFundFeePayContract) (*MsgFundFeePayContractResponse, error) { + return nil, status.Errorf(codes.Unimplemented, "method FundFeePayContract not implemented") +} func (*UnimplementedMsgServer) UpdateParams(ctx context.Context, req *MsgUpdateParams) (*MsgUpdateParamsResponse, error) { return nil, status.Errorf(codes.Unimplemented, "method UpdateParams not implemented") } @@ -350,6 +482,24 @@ func _Msg_RegisterFeePayContract_Handler(srv interface{}, ctx context.Context, d return interceptor(ctx, in, info, handler) } +func _Msg_FundFeePayContract_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(MsgFundFeePayContract) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(MsgServer).FundFeePayContract(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: "/juno.feepay.v1.Msg/FundFeePayContract", + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(MsgServer).FundFeePayContract(ctx, req.(*MsgFundFeePayContract)) + } + return interceptor(ctx, in, info, handler) +} + func _Msg_UpdateParams_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { in := new(MsgUpdateParams) if err := dec(in); err != nil { @@ -376,6 +526,10 @@ var _Msg_serviceDesc = grpc.ServiceDesc{ MethodName: "RegisterFeePayContract", Handler: _Msg_RegisterFeePayContract_Handler, }, + { + MethodName: "FundFeePayContract", + Handler: _Msg_FundFeePayContract_Handler, + }, { MethodName: "UpdateParams", Handler: _Msg_UpdateParams_Handler, @@ -450,6 +604,80 @@ func (m *MsgRegisterFeePayContractResponse) MarshalToSizedBuffer(dAtA []byte) (i return len(dAtA) - i, nil } +func (m *MsgFundFeePayContract) 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 *MsgFundFeePayContract) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *MsgFundFeePayContract) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + if len(m.Amount) > 0 { + for iNdEx := len(m.Amount) - 1; iNdEx >= 0; iNdEx-- { + { + size, err := m.Amount[iNdEx].MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarintTx(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0x1a + } + } + if len(m.ContractAddress) > 0 { + i -= len(m.ContractAddress) + copy(dAtA[i:], m.ContractAddress) + i = encodeVarintTx(dAtA, i, uint64(len(m.ContractAddress))) + i-- + dAtA[i] = 0x12 + } + if len(m.SenderAddress) > 0 { + i -= len(m.SenderAddress) + copy(dAtA[i:], m.SenderAddress) + i = encodeVarintTx(dAtA, i, uint64(len(m.SenderAddress))) + i-- + dAtA[i] = 0xa + } + return len(dAtA) - i, nil +} + +func (m *MsgFundFeePayContractResponse) 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 *MsgFundFeePayContractResponse) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *MsgFundFeePayContractResponse) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + return len(dAtA) - i, nil +} + func (m *MsgUpdateParams) Marshal() (dAtA []byte, err error) { size := m.Size() dAtA = make([]byte, size) @@ -550,6 +778,38 @@ func (m *MsgRegisterFeePayContractResponse) Size() (n int) { return n } +func (m *MsgFundFeePayContract) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + l = len(m.SenderAddress) + if l > 0 { + n += 1 + l + sovTx(uint64(l)) + } + l = len(m.ContractAddress) + if l > 0 { + n += 1 + l + sovTx(uint64(l)) + } + if len(m.Amount) > 0 { + for _, e := range m.Amount { + l = e.Size() + n += 1 + l + sovTx(uint64(l)) + } + } + return n +} + +func (m *MsgFundFeePayContractResponse) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + return n +} + func (m *MsgUpdateParams) Size() (n int) { if m == nil { return 0 @@ -748,6 +1008,204 @@ func (m *MsgRegisterFeePayContractResponse) Unmarshal(dAtA []byte) error { } return nil } +func (m *MsgFundFeePayContract) 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: MsgFundFeePayContract: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: MsgFundFeePayContract: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field SenderAddress", 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.SenderAddress = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + case 2: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field ContractAddress", 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.ContractAddress = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + case 3: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Amount", 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 + } + m.Amount = append(m.Amount, types.Coin{}) + if err := m.Amount[len(m.Amount)-1].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 *MsgFundFeePayContractResponse) 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: MsgFundFeePayContractResponse: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: MsgFundFeePayContractResponse: 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 *MsgUpdateParams) Unmarshal(dAtA []byte) error { l := len(dAtA) iNdEx := 0 diff --git a/x/feepay/types/tx.pb.gw.go b/x/feepay/types/tx.pb.gw.go index 3e14f4681..6a1b0e548 100644 --- a/x/feepay/types/tx.pb.gw.go +++ b/x/feepay/types/tx.pb.gw.go @@ -69,6 +69,42 @@ func local_request_Msg_RegisterFeePayContract_0(ctx context.Context, marshaler r } +var ( + filter_Msg_FundFeePayContract_0 = &utilities.DoubleArray{Encoding: map[string]int{}, Base: []int(nil), Check: []int(nil)} +) + +func request_Msg_FundFeePayContract_0(ctx context.Context, marshaler runtime.Marshaler, client MsgClient, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) { + var protoReq MsgFundFeePayContract + 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_Msg_FundFeePayContract_0); err != nil { + return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err) + } + + msg, err := client.FundFeePayContract(ctx, &protoReq, grpc.Header(&metadata.HeaderMD), grpc.Trailer(&metadata.TrailerMD)) + return msg, metadata, err + +} + +func local_request_Msg_FundFeePayContract_0(ctx context.Context, marshaler runtime.Marshaler, server MsgServer, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) { + var protoReq MsgFundFeePayContract + 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_Msg_FundFeePayContract_0); err != nil { + return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err) + } + + msg, err := server.FundFeePayContract(ctx, &protoReq) + return msg, metadata, err + +} + // RegisterMsgHandlerServer registers the http handlers for service Msg to "mux". // UnaryRPC :call MsgServer directly. // StreamingRPC :currently unsupported pending https://github.com/grpc/grpc-go/issues/906. @@ -98,6 +134,29 @@ func RegisterMsgHandlerServer(ctx context.Context, mux *runtime.ServeMux, server }) + mux.Handle("POST", pattern_Msg_FundFeePayContract_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_Msg_FundFeePayContract_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_Msg_FundFeePayContract_0(ctx, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...) + + }) + return nil } @@ -159,13 +218,37 @@ func RegisterMsgHandlerClient(ctx context.Context, mux *runtime.ServeMux, client }) + mux.Handle("POST", pattern_Msg_FundFeePayContract_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_Msg_FundFeePayContract_0(rctx, inboundMarshaler, client, req, pathParams) + ctx = runtime.NewServerMetadataContext(ctx, md) + if err != nil { + runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) + return + } + + forward_Msg_FundFeePayContract_0(ctx, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...) + + }) + return nil } var ( pattern_Msg_RegisterFeePayContract_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2, 2, 3, 2, 4}, []string{"juno", "feepay", "v1", "tx", "registerFeePayContract"}, "", runtime.AssumeColonVerbOpt(false))) + + pattern_Msg_FundFeePayContract_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2, 2, 3, 2, 4}, []string{"juno", "feepay", "v1", "tx", "fundFeePayContract"}, "", runtime.AssumeColonVerbOpt(false))) ) var ( forward_Msg_RegisterFeePayContract_0 = runtime.ForwardResponseMessage + + forward_Msg_FundFeePayContract_0 = runtime.ForwardResponseMessage ) From 575b98d5e85d8954792887eea69629a5ae29c5ec Mon Sep 17 00:00:00 2001 From: Reece Williams Date: Tue, 5 Sep 2023 19:37:35 -0500 Subject: [PATCH 17/79] Add bond denom from main --- app/app.go | 1 + app/keepers/keepers.go | 2 ++ x/feepay/keeper/keeper.go | 4 ++++ 3 files changed, 7 insertions(+) diff --git a/app/app.go b/app/app.go index 13ac2674d..acd759d54 100644 --- a/app/app.go +++ b/app/app.go @@ -265,6 +265,7 @@ func New( enabledProposals, appOpts, wasmOpts, + app.GetChainBondDenom(), ) app.keys = app.AppKeepers.GetKVStoreKey() diff --git a/app/keepers/keepers.go b/app/keepers/keepers.go index d66a65184..edac33381 100644 --- a/app/keepers/keepers.go +++ b/app/keepers/keepers.go @@ -193,6 +193,7 @@ func NewAppKeepers( enabledProposals []wasmtypes.ProposalType, appOpts servertypes.AppOptions, wasmOpts []wasmkeeper.Option, + bondDenom string, ) AppKeepers { appKeepers := AppKeepers{} @@ -550,6 +551,7 @@ func NewAppKeepers( appKeepers.WasmKeeper, appKeepers.AccountKeeper, authtypes.FeeCollectorName, + bondDenom, govModAddress, ) diff --git a/x/feepay/keeper/keeper.go b/x/feepay/keeper/keeper.go index 4a6826137..4c7e15e76 100644 --- a/x/feepay/keeper/keeper.go +++ b/x/feepay/keeper/keeper.go @@ -27,6 +27,7 @@ type Keeper struct { accountKeeper revtypes.AccountKeeper feeCollectorName string + bondDenom string // the address capable of executing a MsgUpdateParams message. Typically, this // should be the x/gov module account. @@ -41,8 +42,10 @@ func NewKeeper( wk wasmkeeper.Keeper, ak revtypes.AccountKeeper, feeCollector string, + bondDenom string, authority string, ) Keeper { + panic(bondDenom) return Keeper{ storeKey: storeKey, cdc: cdc, @@ -50,6 +53,7 @@ func NewKeeper( wasmKeeper: wk, accountKeeper: ak, feeCollectorName: feeCollector, + bondDenom: bondDenom, authority: authority, } } From ca2dce9f7d0a31e74112f2b2f28f50dd4890b41e Mon Sep 17 00:00:00 2001 From: Joel Smith Date: Tue, 5 Sep 2023 19:51:24 -0500 Subject: [PATCH 18/79] Update Fund CLI --- x/feepay/client/cli/tx.go | 10 +++------ x/feepay/keeper/keeper.go | 40 +++++++++++++++++++++++++++++------ x/feepay/keeper/msg_server.go | 5 ++++- 3 files changed, 40 insertions(+), 15 deletions(-) diff --git a/x/feepay/client/cli/tx.go b/x/feepay/client/cli/tx.go index 1995916e8..ee6a7e53d 100644 --- a/x/feepay/client/cli/tx.go +++ b/x/feepay/client/cli/tx.go @@ -26,6 +26,7 @@ func NewTxCmd() *cobra.Command { txCmd.AddCommand( NewRegisterFeePayContract(), + NewFundFeePayContract(), ) return txCmd } @@ -80,7 +81,7 @@ func NewRegisterFeePayContract() *cobra.Command { // funding a fee pay contract. func NewFundFeePayContract() *cobra.Command { cmd := &cobra.Command{ - Use: "fund [contract_bech32] [ujuno]", + Use: "fund [contract_bech32] [amount]", Short: "Send funds to a registered fee pay contract.", Long: "Send funds to a registered fee pay contract.", Args: cobra.ExactArgs(2), @@ -92,16 +93,11 @@ func NewFundFeePayContract() *cobra.Command { sender_address := cliCtx.GetFromAddress() contract_address := args[0] - ujuno_string := args[1] - ujuno, err := strconv.ParseUint(ujuno_string, 10, 64) - + amount, err := sdk.ParseCoinsNormalized(args[1]) if err != nil { return err } - // TODO: GET REFERENCE TO DENOM - amount := sdk.NewCoin(cliCtx.Denom, ujuno) - msg := &types.MsgFundFeePayContract{ SenderAddress: sender_address.String(), ContractAddress: contract_address, diff --git a/x/feepay/keeper/keeper.go b/x/feepay/keeper/keeper.go index 4a6826137..67e15474a 100644 --- a/x/feepay/keeper/keeper.go +++ b/x/feepay/keeper/keeper.go @@ -78,18 +78,44 @@ func (k Keeper) IsValidContract(ctx sdk.Context, contractAddr string) bool { } // Register the contract in the module store -func (k Keeper) RegisterContract(ctx sdk.Context, fpc types.FeePayContract) bool { +func (k Keeper) RegisterContract(ctx sdk.Context, fpc *types.FeePayContract) bool { - // Get store - store := prefix.NewStore(ctx.KVStore(k.storeKey), []byte("contracts")) + // Return false because the contract was already registered + if k.IsValidContract(ctx, fpc.ContractAddress) { + return false + } - // Get key/val pair + // Register the new fee pay contract in the KV store + store := prefix.NewStore(ctx.KVStore(k.storeKey), []byte("contracts")) key := []byte(fpc.ContractAddress) bz := k.cdc.MustMarshal(&fpc) - - // Set in store store.Set(key, bz) + return true +} + +func (k Keeper) FundContract(ctx sdk.Context, mfc *types.MsgFundFeePayContract) bool { + + // Return false because the contract was already registered + if !k.IsValidContract(ctx, mfc.ContractAddress) { + return false + } + + // Get existing fee pay contract from store + store := prefix.NewStore(ctx.KVStore(k.storeKey), []byte("contracts")) + key := []byte(mfc.ContractAddress) + bz := store.Get(key) + + var fpc types.FeePayContract + k.cdc.MustUnmarshal(bz, &fpc) + + // Increment the fpc balance with the correct denom, ignore all others + for _, c := range mfc.Amount { + if c.Denom == PUT_DENOM_HERE { + fpc.Balance += c.Amount.Uint64() + } + } - // Return true by default (for now) + // Update the balance in KV store, return success + store.Set(key, k.cdc.MustMarshal(&fpc)) return true } diff --git a/x/feepay/keeper/msg_server.go b/x/feepay/keeper/msg_server.go index 970303b62..785e6df68 100644 --- a/x/feepay/keeper/msg_server.go +++ b/x/feepay/keeper/msg_server.go @@ -23,8 +23,11 @@ func (k Keeper) RegisterFeePayContract(goCtx context.Context, msg *types.MsgRegi func (k Keeper) FundFeePayContract(goCtx context.Context, msg *types.MsgFundFeePayContract) (*types.MsgFundFeePayContractResponse, error) { // TODO: IMPLEMENT + ctx := sdk.UnwrapSDKContext(goCtx) + + ctx.Logger().Error("FundFeePay", "Balance", msg.Amount) - return nil, nil + return &types.MsgFundFeePayContractResponse{}, nil } func (k Keeper) UpdateParams(goCtx context.Context, req *types.MsgUpdateParams) (*types.MsgUpdateParamsResponse, error) { From 8e130b6520504936fe2437d936d45921406b67c9 Mon Sep 17 00:00:00 2001 From: Joel Smith Date: Tue, 5 Sep 2023 21:05:00 -0500 Subject: [PATCH 19/79] Fund Contract via User Wallet --- x/feepay/ante/dedcuct_fee.go | 2 +- x/feepay/keeper/keeper.go | 62 ++++++++++++++++++++++------------- x/feepay/keeper/msg_server.go | 10 ++---- 3 files changed, 43 insertions(+), 31 deletions(-) diff --git a/x/feepay/ante/dedcuct_fee.go b/x/feepay/ante/dedcuct_fee.go index 37bc41351..7b82a841f 100644 --- a/x/feepay/ante/dedcuct_fee.go +++ b/x/feepay/ante/dedcuct_fee.go @@ -154,7 +154,7 @@ func (dfd DeductFeeDecorator) handleZeroFees(ctx sdk.Context, deductFeesFromAcc cw := msg.(*wasmtypes.MsgExecuteContract) // We need to check if it is a valid contract. Utilize the FeePay Keeper for validation - if !dfd.feepayKeeper.IsValidContract(ctx, cw.GetContract()) { + if err := dfd.feepayKeeper.IsValidContract(ctx, cw.GetContract()); err != nil { return sdkerrors.ErrInvalidRequest.Wrapf("contract %s is not registered for fee pay", cw.GetContract()) } diff --git a/x/feepay/keeper/keeper.go b/x/feepay/keeper/keeper.go index bfd6fabf9..ef45186d6 100644 --- a/x/feepay/keeper/keeper.go +++ b/x/feepay/keeper/keeper.go @@ -1,6 +1,7 @@ package keeper import ( + "errors" "fmt" wasmkeeper "github.com/CosmWasm/wasmd/x/wasm/keeper" @@ -12,6 +13,7 @@ import ( storetypes "github.com/cosmos/cosmos-sdk/store/types" sdk "github.com/cosmos/cosmos-sdk/types" + errorsmod "cosmossdk.io/errors" types "github.com/CosmosContracts/juno/v17/x/feepay/types" revtypes "github.com/CosmosContracts/juno/v17/x/feeshare/types" ) @@ -45,7 +47,6 @@ func NewKeeper( bondDenom string, authority string, ) Keeper { - panic(bondDenom) return Keeper{ storeKey: storeKey, cdc: cdc, @@ -69,39 +70,60 @@ func (k Keeper) Logger(ctx sdk.Context) log.Logger { } // Check if a contract is associated with a FeePay contract -func (k Keeper) IsValidContract(ctx sdk.Context, contractAddr string) bool { - - // Get store +func (k Keeper) IsValidContract(ctx sdk.Context, contractAddr string) error { store := prefix.NewStore(ctx.KVStore(k.storeKey), []byte("contracts")) - // Get data hasData := store.Has([]byte(contractAddr)) - // Return true if data is not nil - return hasData + if hasData { + return nil + } else { + return errorsmod.Wrapf(errors.New("invalid contract address"), "contract %s not registered", contractAddr) + } } // Register the contract in the module store -func (k Keeper) RegisterContract(ctx sdk.Context, fpc *types.FeePayContract) bool { +func (k Keeper) RegisterContract(ctx sdk.Context, fpc *types.FeePayContract) error { // Return false because the contract was already registered - if k.IsValidContract(ctx, fpc.ContractAddress) { - return false + if err := k.IsValidContract(ctx, fpc.ContractAddress); err != nil { + return err } // Register the new fee pay contract in the KV store store := prefix.NewStore(ctx.KVStore(k.storeKey), []byte("contracts")) key := []byte(fpc.ContractAddress) - bz := k.cdc.MustMarshal(&fpc) + bz := k.cdc.MustMarshal(fpc) + store.Set(key, bz) - return true + return nil } -func (k Keeper) FundContract(ctx sdk.Context, mfc *types.MsgFundFeePayContract) bool { +// Fund an existing fee pay contract +func (k Keeper) FundContract(ctx sdk.Context, mfc *types.MsgFundFeePayContract) error { // Return false because the contract was already registered - if !k.IsValidContract(ctx, mfc.ContractAddress) { - return false + if err := k.IsValidContract(ctx, mfc.ContractAddress); err != nil { + return err + } + + // Only transfer the bond denom + var transferCoin sdk.Coin + for _, c := range mfc.Amount { + if c.Denom == k.bondDenom { + transferCoin = c + } + } + + // Confirm the sender has enough funds to fund the contract + addr, err := sdk.AccAddressFromBech32(mfc.SenderAddress) + if err != nil { + return err + } + + err = k.bankKeeper.SendCoinsFromAccountToModule(ctx, addr, types.ModuleName, sdk.NewCoins(transferCoin)) + if err != nil { + return err } // Get existing fee pay contract from store @@ -112,14 +134,10 @@ func (k Keeper) FundContract(ctx sdk.Context, mfc *types.MsgFundFeePayContract) var fpc types.FeePayContract k.cdc.MustUnmarshal(bz, &fpc) - // Increment the fpc balance with the correct denom, ignore all others - for _, c := range mfc.Amount { - if c.Denom == PUT_DENOM_HERE { - fpc.Balance += c.Amount.Uint64() - } - } + // Increment the fpc balance + fpc.Balance += transferCoin.Amount.Uint64() // Update the balance in KV store, return success store.Set(key, k.cdc.MustMarshal(&fpc)) - return true + return nil } diff --git a/x/feepay/keeper/msg_server.go b/x/feepay/keeper/msg_server.go index 785e6df68..6e306eabd 100644 --- a/x/feepay/keeper/msg_server.go +++ b/x/feepay/keeper/msg_server.go @@ -15,19 +15,13 @@ var _ types.MsgServer = &Keeper{} func (k Keeper) RegisterFeePayContract(goCtx context.Context, msg *types.MsgRegisterFeePayContract) (*types.MsgRegisterFeePayContractResponse, error) { ctx := sdk.UnwrapSDKContext(goCtx) - k.RegisterContract(ctx, *msg.Contract) - return &types.MsgRegisterFeePayContractResponse{}, nil + return &types.MsgRegisterFeePayContractResponse{}, k.RegisterContract(ctx, msg.Contract) } // FundFeePayContract funds a contract with the given amount of tokens. func (k Keeper) FundFeePayContract(goCtx context.Context, msg *types.MsgFundFeePayContract) (*types.MsgFundFeePayContractResponse, error) { - - // TODO: IMPLEMENT ctx := sdk.UnwrapSDKContext(goCtx) - - ctx.Logger().Error("FundFeePay", "Balance", msg.Amount) - - return &types.MsgFundFeePayContractResponse{}, nil + return &types.MsgFundFeePayContractResponse{}, k.FundContract(ctx, msg) } func (k Keeper) UpdateParams(goCtx context.Context, req *types.MsgUpdateParams) (*types.MsgUpdateParamsResponse, error) { From 5101407bae91de4f63eb127817d3fb53163e0874 Mon Sep 17 00:00:00 2001 From: Joel Smith Date: Thu, 7 Sep 2023 19:27:07 -0500 Subject: [PATCH 20/79] Fix contract funding, Add contract querying --- app/keepers/keepers.go | 9 +- proto/juno/feepay/v1/query.proto | 124 ++-- scripts/feepay.sh | 27 +- state_export.json | 787 ++++++++++++++++++++++ x/feepay/client/cli/query.go | 100 +++ x/feepay/client/cli/tx.go | 2 + x/feepay/keeper/grpc_query.go | 52 ++ x/feepay/keeper/keeper.go | 108 ++- x/feepay/keeper/msg_server.go | 1 + x/feepay/module.go | 11 +- x/feepay/types/codec.go | 4 +- x/feepay/types/query.pb.go | 1057 +++++++++++++++++++++++++++++- x/feepay/types/query.pb.gw.go | 272 ++++++++ 13 files changed, 2416 insertions(+), 138 deletions(-) create mode 100644 state_export.json create mode 100644 x/feepay/client/cli/query.go create mode 100644 x/feepay/keeper/grpc_query.go create mode 100644 x/feepay/types/query.pb.gw.go diff --git a/app/keepers/keepers.go b/app/keepers/keepers.go index edac33381..e32e51373 100644 --- a/app/keepers/keepers.go +++ b/app/keepers/keepers.go @@ -547,7 +547,7 @@ func NewAppKeepers( appKeepers.FeePayKeeper = feepaykeeper.NewKeeper( appKeepers.keys[feepaytypes.StoreKey], appCodec, - appKeepers.BankKeeper, + &appKeepers.BankKeeper, appKeepers.WasmKeeper, appKeepers.AccountKeeper, authtypes.FeeCollectorName, @@ -715,10 +715,5 @@ func BlockedAddresses() map[string]bool { // GetMaccPerms returns a copy of the module account permissions func GetMaccPerms() map[string][]string { - dupMaccPerms := make(map[string][]string) - for k, v := range maccPerms { - dupMaccPerms[k] = v - } - - return dupMaccPerms + return maccPerms } diff --git a/proto/juno/feepay/v1/query.proto b/proto/juno/feepay/v1/query.proto index a0113c5e3..4d060fd29 100644 --- a/proto/juno/feepay/v1/query.proto +++ b/proto/juno/feepay/v1/query.proto @@ -9,89 +9,41 @@ import "google/api/annotations.proto"; option go_package = "github.com/CosmosContracts/juno/x/feepay/types"; -// // Query defines the gRPC querier service. -// service Query { -// // FeeShares retrieves all registered FeeShares -// rpc FeePrepays(QueryFeeSharesRequest) returns (QueryFeeSharesResponse) { -// option (google.api.http).get = "/juno/feepay/v1/feepay"; -// } - -// // Params retrieves the FeeShare module params -// rpc Params(QueryParamsRequest) returns (QueryParamsResponse) { -// option (google.api.http).get = "/juno/feeshare/v1/params"; -// } -// } - -// // QueryFeeSharesRequest is the request type for the Query/FeeShares RPC method. -// message QueryFeeSharesRequest { -// // pagination defines an optional pagination for the request. -// cosmos.base.query.v1beta1.PageRequest pagination = 1; -// } - -// // QueryFeeSharesResponse is the response type for the Query/FeeShares RPC -// // method. -// message QueryFeeSharesResponse { -// // FeeShare is a slice of all stored Reveneue -// repeated FeeShare feeshare = 1 [ (gogoproto.nullable) = false ]; -// // pagination defines the pagination in the response. -// cosmos.base.query.v1beta1.PageResponse pagination = 2; -// } - -// // QueryFeeShareRequest is the request type for the Query/FeeShare RPC method. -// message QueryFeeShareRequest { -// // contract_address of a registered contract in bech32 format -// string contract_address = 1; -// } - -// // QueryFeeShareResponse is the response type for the Query/FeeShare RPC method. -// message QueryFeeShareResponse { -// // FeeShare is a stored Reveneue for the queried contract -// FeeShare feeshare = 1 [ (gogoproto.nullable) = false ]; -// } - -// // QueryParamsRequest is the request type for the Query/Params RPC method. -// message QueryParamsRequest {} - -// // QueryParamsResponse is the response type for the Query/Params RPC method. -// message QueryParamsResponse { -// // params is the returned FeeShare parameter -// Params params = 1 [ (gogoproto.nullable) = false ]; -// } - -// // QueryDeployerFeeSharesRequest is the request type for the -// // Query/DeployerFeeShares RPC method. -// message QueryDeployerFeeSharesRequest { -// // deployer_address in bech32 format -// string deployer_address = 1; -// // pagination defines an optional pagination for the request. -// cosmos.base.query.v1beta1.PageRequest pagination = 2; -// } - -// // QueryDeployerFeeSharesResponse is the response type for the -// // Query/DeployerFeeShares RPC method. -// message QueryDeployerFeeSharesResponse { -// // contract_addresses is the slice of registered contract addresses for a -// // deployer -// repeated string contract_addresses = 1; -// // pagination defines the pagination in the response. -// cosmos.base.query.v1beta1.PageResponse pagination = 2; -// } - -// // QueryWithdrawerFeeSharesRequest is the request type for the -// // Query/WithdrawerFeeShares RPC method. -// message QueryWithdrawerFeeSharesRequest { -// // withdrawer_address in bech32 format -// string withdrawer_address = 1; -// // pagination defines an optional pagination for the request. -// cosmos.base.query.v1beta1.PageRequest pagination = 2; -// } - -// // QueryWithdrawerFeeSharesResponse is the response type for the -// // Query/WithdrawerFeeShares RPC method. -// message QueryWithdrawerFeeSharesResponse { -// // contract_addresses is the slice of registered contract addresses for a -// // withdrawer -// repeated string contract_addresses = 1; -// // pagination defines the pagination in the response. -// cosmos.base.query.v1beta1.PageResponse pagination = 2; -// } +// Query defines the gRPC querier service. +service Query { + // FeePayContract queries a single fee pay contract by address + rpc FeePayContract(QueryFeePayContract) returns (QueryFeePayContractResponse) { + option (google.api.http).get = "/juno/feepay/v1/feepay/{contract_address}"; + } + + // Retrieve all fee pay contracts + rpc FeePayContracts(QueryFeePayContracts) returns (QueryFeePayContractsResponse) { + option (google.api.http).get = "/juno/feepay/v1/feepay"; + } +} + +// QueryFeePayContract retrieves a single fee pay contract +message QueryFeePayContract { + // contract_address defines the address of the fee pay contract + string contract_address = 1; +} + +// QueryFeePayContractResponse defines the response for retrieving a single fee pay contract +message QueryFeePayContractResponse { + // contract defines the fee pay contract + FeePayContract contract = 1; +} + +// Message for querying a list of fee pay contracts +message QueryFeePayContracts { + // Pagination defines an optional pagination for the request. + cosmos.base.query.v1beta1.PageRequest pagination = 1; +} + +// The response for querying all fee pay contracts +message QueryFeePayContractsResponse { + // A slice of all the stored fee pay contracts + repeated FeePayContract contracts = 1 [ (gogoproto.nullable) = false ]; + // pagination defines the pagination in the response. + cosmos.base.query.v1beta1.PageResponse pagination = 2; +} diff --git a/scripts/feepay.sh b/scripts/feepay.sh index 39d86c734..f01b6c293 100644 --- a/scripts/feepay.sh +++ b/scripts/feepay.sh @@ -9,18 +9,37 @@ JUNOD_NODE=http://localhost:26657 junod tx wasm store $CONTRACT_FILE --from juno1 --gas 2000000 -y --chain-id=local-1 --fees=75000ujuno # Code id from THis is 1 - it is in the above Txhash, just hardcoding since we only need to upload once -sleep 6 +sleep 3 # instantiate and get an address junod tx wasm instantiate 1 '{}' --from juno1 --label "test" --gas 2000000 -y --chain-id=local-1 --fees=75000ujuno --no-admin -sleep 6 +sleep 3 # execute on the contract CONTRACT_ADDR=juno14hj2tavq8fpesdwxxcu44rty3hh90vhujrvcmstl4zr3txmfvw9skjuwg8 junod tx wasm execute $CONTRACT_ADDR '{"increment":{}}' --gas 2000000 -y --chain-id=local-1 --fees=75000ujuno --from=juno1 -sleep 6 +sleep 3 # Query to ensure it went through, else you need to junod q tx from the above command -junod q wasm contract-state smart $CONTRACT_ADDR '{"get_config":{}}' --chain-id=local-1 \ No newline at end of file +junod q wasm contract-state smart $CONTRACT_ADDR '{"get_config":{}}' --chain-id=local-1 + +sleep 3 + +# Register Contract +junod tx feepay register juno14hj2tavq8fpesdwxxcu44rty3hh90vhujrvcmstl4zr3txmfvw9skjuwg8 3 --home /home/joel/.juno1 --chain-id local-1 --from juno1 --keyring-backend=test --fees=500ujuno -y + +sleep 3 + +# Transfer funds from juno1 to fee pay module +# junod tx bank send juno1 juno1f7f2eapsz6w4s2fytlm34yu5w89ueaesg7x9v5 5000000ujuno --home /home/joel/.juno1 --chain-id local-1 --keyring-backend=test --fees=5000ujuno -y + +# sleep 3 + +# Fund the contract +junod tx feepay fund juno14hj2tavq8fpesdwxxcu44rty3hh90vhujrvcmstl4zr3txmfvw9skjuwg8 100ujuno --gas=200000 --fees=5000ujuno --home /home/joel/.juno1 --chain-id local-1 --keyring-backend=test -y --from juno1 + +sleep 3 + +junod q feepay contract juno14hj2tavq8fpesdwxxcu44rty3hh90vhujrvcmstl4zr3txmfvw9skjuwg8 --home /home/joel/.juno1 --chain-id local-1 diff --git a/state_export.json b/state_export.json new file mode 100644 index 000000000..e62a0a7e6 --- /dev/null +++ b/state_export.json @@ -0,0 +1,787 @@ +{ + "app_hash": "", + "app_state": { + "auth": { + "accounts": [ + { + "@type": "/cosmos.auth.v1beta1.ModuleAccount", + "base_account": { + "account_number": "0", + "address": "juno19ejy8n9qsectrf4semdp9cpknflld0j6tj7k2a", + "pub_key": null, + "sequence": "0" + }, + "name": "tokenfactory", + "permissions": [ + "minter", + "burner" + ] + }, + { + "@type": "/cosmos.auth.v1beta1.BaseAccount", + "account_number": "10", + "address": "juno1f7f2eapsz6w4s2fytlm34yu5w89ueaesg7x9v5", + "pub_key": null, + "sequence": "0" + }, + { + "@type": "/cosmos.auth.v1beta1.ModuleAccount", + "base_account": { + "account_number": "5", + "address": "juno1fl48vsnmsdzcv85q5d2q4z5ajdha8yu3rf257t", + "pub_key": null, + "sequence": "0" + }, + "name": "bonded_tokens_pool", + "permissions": [ + "burner", + "staking" + ] + }, + { + "@type": "/cosmos.auth.v1beta1.ModuleAccount", + "base_account": { + "account_number": "6", + "address": "juno1tygms3xhhs3yv487phx3dw4a95jn7t7lhfk9gl", + "pub_key": null, + "sequence": "0" + }, + "name": "not_bonded_tokens_pool", + "permissions": [ + "burner", + "staking" + ] + }, + { + "@type": "/cosmos.auth.v1beta1.ModuleAccount", + "base_account": { + "account_number": "7", + "address": "juno10d07y265gmmuvt4z0w9aw880jnsr700jvss730", + "pub_key": null, + "sequence": "0" + }, + "name": "gov", + "permissions": [ + "burner" + ] + }, + { + "@type": "/cosmos.auth.v1beta1.BaseAccount", + "account_number": "2", + "address": "juno1see0htr47uapjvcvh0hu6385rp8lw3emu85lh5", + "pub_key": null, + "sequence": "0" + }, + { + "@type": "/cosmos.auth.v1beta1.ModuleAccount", + "base_account": { + "account_number": "4", + "address": "juno1jv65s3grqf6v6jl3dp4t6c9t9rk99cd83d88wr", + "pub_key": null, + "sequence": "0" + }, + "name": "distribution", + "permissions": [] + }, + { + "@type": "/cosmos.auth.v1beta1.BaseAccount", + "account_number": "9", + "address": "juno14hj2tavq8fpesdwxxcu44rty3hh90vhujrvcmstl4zr3txmfvw9skjuwg8", + "pub_key": null, + "sequence": "0" + }, + { + "@type": "/cosmos.auth.v1beta1.BaseAccount", + "account_number": "0", + "address": "juno1hj5fveer5cjtn4wd6wstzugjfdxzl0xps73ftl", + "pub_key": { + "@type": "/cosmos.crypto.secp256k1.PubKey", + "key": "ApZa31BR3NWLylRT6Qi5+f+zXtj2OpqtC76vgkUGLyww" + }, + "sequence": "8" + }, + { + "@type": "/cosmos.auth.v1beta1.BaseAccount", + "account_number": "1", + "address": "juno1efd63aw40lxf3n4mhf7dzhjkr453axurv2zdzk", + "pub_key": null, + "sequence": "0" + }, + { + "@type": "/cosmos.auth.v1beta1.ModuleAccount", + "base_account": { + "account_number": "8", + "address": "juno1m3h30wlvsf8llruxtpukdvsy0km2kum87ryrqu", + "pub_key": null, + "sequence": "0" + }, + "name": "mint", + "permissions": [ + "minter" + ] + }, + { + "@type": "/cosmos.auth.v1beta1.ModuleAccount", + "base_account": { + "account_number": "3", + "address": "juno17xpfvakm2amg962yls6f84z3kell8c5lxtqmvp", + "pub_key": null, + "sequence": "0" + }, + "name": "fee_collector", + "permissions": [] + } + ], + "params": { + "max_memo_characters": "256", + "sig_verify_cost_ed25519": "590", + "sig_verify_cost_secp256k1": "1000", + "tx_sig_limit": "7", + "tx_size_cost_per_byte": "10" + } + }, + "authz": { + "authorization": [] + }, + "bank": { + "balances": [ + { + "address": "juno1f7f2eapsz6w4s2fytlm34yu5w89ueaesg7x9v5", + "coins": [ + { + "amount": "5000000", + "denom": "ujuno" + } + ] + }, + { + "address": "juno1fl48vsnmsdzcv85q5d2q4z5ajdha8yu3rf257t", + "coins": [ + { + "amount": "1000000", + "denom": "ujuno" + } + ] + }, + { + "address": "juno1see0htr47uapjvcvh0hu6385rp8lw3emu85lh5", + "coins": [ + { + "amount": "100000000000", + "denom": "ujuno" + } + ] + }, + { + "address": "juno1jv65s3grqf6v6jl3dp4t6c9t9rk99cd83d88wr", + "coins": [ + { + "amount": "684160", + "denom": "ujuno" + } + ] + }, + { + "address": "juno1hj5fveer5cjtn4wd6wstzugjfdxzl0xps73ftl", + "coins": [ + { + "amount": "3759500", + "denom": "ujuno" + }, + { + "amount": "1000", + "denom": "utest" + } + ] + }, + { + "address": "juno1efd63aw40lxf3n4mhf7dzhjkr453axurv2zdzk", + "coins": [ + { + "amount": "1000000", + "denom": "ujuno" + }, + { + "amount": "1000", + "denom": "utest" + } + ] + } + ], + "denom_metadata": [], + "params": { + "default_send_enabled": true, + "send_enabled": [] + }, + "send_enabled": [], + "supply": [ + { + "amount": "100011443660", + "denom": "ujuno" + }, + { + "amount": "2000", + "denom": "utest" + } + ] + }, + "builder": { + "params": { + "escrow_account_address": "32sHF2qbF8xMmvwle9QEcy59Cbc=", + "front_running_protection": false, + "max_bundle_size": 4, + "min_bid_increment": { + "amount": "1000000", + "denom": "ujuno" + }, + "proposer_fee": "0.000000000000000000", + "reserve_fee": { + "amount": "1000000", + "denom": "ujuno" + } + } + }, + "capability": { + "index": "4", + "owners": [ + { + "index": "1", + "index_owners": { + "owners": [ + { + "module": "ibc", + "name": "ports/transfer" + }, + { + "module": "transfer", + "name": "ports/transfer" + } + ] + } + }, + { + "index": "2", + "index_owners": { + "owners": [ + { + "module": "ibc", + "name": "ports/icahost" + }, + { + "module": "icahost", + "name": "ports/icahost" + } + ] + } + }, + { + "index": "3", + "index_owners": { + "owners": [ + { + "module": "ibc", + "name": "ports/icqhost" + }, + { + "module": "interchainquery", + "name": "ports/icqhost" + } + ] + } + } + ] + }, + "consensus": null, + "crisis": { + "constant_fee": { + "amount": "1000", + "denom": "ujuno" + } + }, + "distribution": { + "delegator_starting_infos": [ + { + "delegator_address": "juno1hj5fveer5cjtn4wd6wstzugjfdxzl0xps73ftl", + "starting_info": { + "height": "0", + "previous_period": "1", + "stake": "1000000.000000000000000000" + }, + "validator_address": "junovaloper1hj5fveer5cjtn4wd6wstzugjfdxzl0xp0r8xsx" + } + ], + "delegator_withdraw_infos": [], + "fee_pool": { + "community_pool": [ + { + "amount": "13683.200000000000000000", + "denom": "ujuno" + } + ] + }, + "outstanding_rewards": [ + { + "outstanding_rewards": [ + { + "amount": "670476.800000000000000000", + "denom": "ujuno" + } + ], + "validator_address": "junovaloper1hj5fveer5cjtn4wd6wstzugjfdxzl0xp0r8xsx" + } + ], + "params": { + "base_proposer_reward": "0.000000000000000000", + "bonus_proposer_reward": "0.000000000000000000", + "community_tax": "0.020000000000000000", + "withdraw_addr_enabled": true + }, + "previous_proposer": "junovalcons1y8fgw9974fcxp9ghn3duftjt9v7q66vguel7cc", + "validator_accumulated_commissions": [ + { + "accumulated": { + "commission": [ + { + "amount": "67047.680000000000000000", + "denom": "ujuno" + } + ] + }, + "validator_address": "junovaloper1hj5fveer5cjtn4wd6wstzugjfdxzl0xp0r8xsx" + } + ], + "validator_current_rewards": [ + { + "rewards": { + "period": "2", + "rewards": [ + { + "amount": "603429.120000000000000000", + "denom": "ujuno" + } + ] + }, + "validator_address": "junovaloper1hj5fveer5cjtn4wd6wstzugjfdxzl0xp0r8xsx" + } + ], + "validator_historical_rewards": [ + { + "period": "1", + "rewards": { + "cumulative_reward_ratio": [], + "reference_count": 2 + }, + "validator_address": "junovaloper1hj5fveer5cjtn4wd6wstzugjfdxzl0xp0r8xsx" + } + ], + "validator_slash_events": [] + }, + "drip": { + "params": { + "allowed_addresses": [ + "juno1hj5fveer5cjtn4wd6wstzugjfdxzl0xps73ftl", + "juno1efd63aw40lxf3n4mhf7dzhjkr453axurv2zdzk" + ], + "enable_drip": true + } + }, + "evidence": { + "evidence": [] + }, + "feegrant": { + "allowances": [] + }, + "feeibc": { + "fee_enabled_channels": [], + "forward_relayers": [], + "identified_fees": [], + "registered_counterparty_payees": [], + "registered_payees": [] + }, + "feepay": { + "fee_contract": [], + "params": {} + }, + "feeshare": { + "fee_share": [], + "params": { + "allowed_denoms": [ + "ujuno" + ], + "developer_shares": "0.500000000000000000", + "enable_fee_share": true + } + }, + "genutil": { + "gen_txs": [] + }, + "globalfee": { + "params": { + "minimum_gas_prices": [ + { + "amount": "0.002500000000000000", + "denom": "ujuno" + } + ] + } + }, + "gov": { + "deposit_params": null, + "deposits": [], + "params": { + "burn_proposal_deposit_prevote": false, + "burn_vote_quorum": false, + "burn_vote_veto": true, + "max_deposit_period": "172800s", + "min_deposit": [ + { + "amount": "1000000", + "denom": "ujuno" + } + ], + "min_initial_deposit_ratio": "0.000000000000000000", + "quorum": "0.334000000000000000", + "threshold": "0.500000000000000000", + "veto_threshold": "0.334000000000000000", + "voting_period": "172800s" + }, + "proposals": [], + "starting_proposal_id": "1", + "tally_params": null, + "votes": [], + "voting_params": null + }, + "ibc": { + "channel_genesis": { + "ack_sequences": [], + "acknowledgements": [], + "channels": [], + "commitments": [], + "next_channel_sequence": "0", + "receipts": [], + "recv_sequences": [], + "send_sequences": [] + }, + "client_genesis": { + "clients": [ + { + "client_id": "09-localhost", + "client_state": { + "@type": "/ibc.lightclients.localhost.v2.ClientState", + "latest_height": { + "revision_height": "70", + "revision_number": "1" + } + } + } + ], + "clients_consensus": [], + "clients_metadata": [], + "create_localhost": false, + "next_client_sequence": "0", + "params": { + "allowed_clients": [ + "06-solomachine", + "07-tendermint", + "09-localhost" + ] + } + }, + "connection_genesis": { + "client_connection_paths": [], + "connections": [ + { + "client_id": "09-localhost", + "counterparty": { + "client_id": "09-localhost", + "connection_id": "connection-localhost", + "prefix": { + "key_prefix": "aWJj" + } + }, + "delay_period": "0", + "id": "connection-localhost", + "state": "STATE_OPEN", + "versions": [ + { + "features": [ + "ORDER_ORDERED", + "ORDER_UNORDERED" + ], + "identifier": "1" + } + ] + } + ], + "next_connection_sequence": "0", + "params": { + "max_expected_time_per_block": "30000000000" + } + } + }, + "ibchooks": {}, + "interchainaccounts": { + "controller_genesis_state": { + "active_channels": [], + "interchain_accounts": [], + "params": { + "controller_enabled": true + }, + "ports": [] + }, + "host_genesis_state": { + "active_channels": [], + "interchain_accounts": [], + "params": { + "allow_messages": [ + "*" + ], + "host_enabled": true + }, + "port": "icahost" + } + }, + "interchainquery": { + "host_port": "icqhost", + "params": { + "allow_queries": [], + "host_enabled": true + } + }, + "mint": { + "minter": { + "annual_provisions": "40004400000.000000000000000000", + "inflation": "0.400000000000000000", + "phase": "1", + "start_phase_block": "1", + "target_supply": "140015400000" + }, + "params": { + "blocks_per_year": "6311520", + "mint_denom": "ujuno" + } + }, + "nft": { + "classes": [], + "entries": [] + }, + "packetfowardmiddleware": { + "in_flight_packets": {}, + "params": { + "fee_percentage": "0.000000000000000000" + } + }, + "params": null, + "slashing": { + "missed_blocks": [ + { + "address": "junovalcons1y8fgw9974fcxp9ghn3duftjt9v7q66vguel7cc", + "missed_blocks": [] + } + ], + "params": { + "downtime_jail_duration": "600s", + "min_signed_per_window": "0.500000000000000000", + "signed_blocks_window": "100", + "slash_fraction_double_sign": "0.050000000000000000", + "slash_fraction_downtime": "0.010000000000000000" + }, + "signing_infos": [ + { + "address": "junovalcons1y8fgw9974fcxp9ghn3duftjt9v7q66vguel7cc", + "validator_signing_info": { + "address": "junovalcons1y8fgw9974fcxp9ghn3duftjt9v7q66vguel7cc", + "index_offset": "69", + "jailed_until": "1970-01-01T00:00:00Z", + "missed_blocks_counter": "0", + "start_height": "0", + "tombstoned": false + } + } + ] + }, + "staking": { + "delegations": [ + { + "delegator_address": "juno1hj5fveer5cjtn4wd6wstzugjfdxzl0xps73ftl", + "shares": "1000000.000000000000000000", + "validator_address": "junovaloper1hj5fveer5cjtn4wd6wstzugjfdxzl0xp0r8xsx" + } + ], + "exported": true, + "last_total_power": "1", + "last_validator_powers": [ + { + "address": "junovaloper1hj5fveer5cjtn4wd6wstzugjfdxzl0xp0r8xsx", + "power": "1" + } + ], + "params": { + "bond_denom": "ujuno", + "historical_entries": 10000, + "max_entries": 7, + "max_validators": 100, + "min_commission_rate": "0.050000000000000000", + "unbonding_time": "1814400s" + }, + "redelegations": [], + "unbonding_delegations": [], + "validators": [ + { + "commission": { + "commission_rates": { + "max_change_rate": "0.010000000000000000", + "max_rate": "0.200000000000000000", + "rate": "0.100000000000000000" + }, + "update_time": "2023-09-07T23:21:17.073977743Z" + }, + "consensus_pubkey": { + "@type": "/cosmos.crypto.ed25519.PubKey", + "key": "9cSyCx910OX4PtUt+iYO6sF6TXi4OIDclvVEDxThXu8=" + }, + "delegator_shares": "1000000.000000000000000000", + "description": { + "details": "", + "identity": "", + "moniker": "localjuno", + "security_contact": "", + "website": "" + }, + "jailed": false, + "min_self_delegation": "1", + "operator_address": "junovaloper1hj5fveer5cjtn4wd6wstzugjfdxzl0xp0r8xsx", + "status": "BOND_STATUS_BONDED", + "tokens": "1000000", + "unbonding_height": "0", + "unbonding_ids": [], + "unbonding_on_hold_ref_count": "0", + "unbonding_time": "1970-01-01T00:00:00Z" + } + ] + }, + "tokenfactory": { + "factory_denoms": [], + "params": { + "denom_creation_fee": [], + "denom_creation_gas_consume": "2000000" + } + }, + "transfer": { + "denom_traces": [], + "params": { + "receive_enabled": true, + "send_enabled": true + }, + "port_id": "transfer", + "total_escrowed": [] + }, + "upgrade": {}, + "vesting": {}, + "wasm": { + "codes": [ + { + "code_bytes": "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DRQgA0HQAWogA0GYAWoQlwEgAygC0AEiBEEVRg0FIAMoAtQBIQIgAygC3AEhCiADKALYASENIAkEQCAFELcBCyABBEAgAUEFdCEFIAZBFGohAQNAIAFBBGsoAgAEQCABKAIAELcBCyABQSBqIQEgBUEgayIFDQALCyACQQh2IQEgCEUNFSAGELcBDBULIBFFIQIgA0G8AWogAygC3AE2AgAgA0G0AWogAykC1AE3AgAgAyABNgKwASAJRQ0SIAUQtwEMEgsgA0G8AWogAygC3AE2AgAgA0G0AWogAykC1AE3AgAMCwsgA0HQAWogDBCYAQJAIAMoAtABIgJBFUcEQCADQfwBaiADQdwBaigCADYCACADIAMpAtQBNwL0AQwBCyADQfABaiAMEBwgAygC8AEiAkEVRg0GCyADQbQBaiADKQL0ATcCACADQbwBaiADQfwBaigCADYCACADIAI2ArABIAYNDgwPCyAGRQ0DIANBsAFqQa2CwABBBRAdIANBADYCrAEMDQsgEUUNASADQbABakGngsAAQQYQHSAGDQwMDQsgA0HQAWogA0GYAWoQlQEgAygC0AEiBEEVRwRAIAMoAtwBIQogAygC2AEhDSADKALUASECIAkEQCAFELcBCyABBEAgAUEFdCEFIAZBFGohAQNAIAFBBGsoAgAEQCABKAIAELcBCyABQSBqIQEgBUEgayIFDQALCyAIRQ0RIAYQtwEMEQsgAEEYaiABNgIAIABBFGogBjYCACAAQRBqIAg2AgAgAEEMaiAUNgIAIABBCGogBTYCACAAIAk2AgQgAEENNgIADBELIANB0AFqIAwQmAECfyADKALQASICQRVGBEAgA0HQAWogDBAeIAMoAtwBIRQgAygC2AEhESADKALUASIKIAMoAtABIgJBFUcNARogCiEcDAMLIAMoAtwBIRQgAygC2AEhESADKALUAQshBSADQbwBaiAUNgIAIANBuAFqIBE2AgAgA0G0AWogBTYCAAwGCyADQdABaiAMEJgBAn8CQAJAAkACQAJAAn8CQAJAAkAgAygC0AEiB0EVRgRAIANB6ABqIAwQmgEgAy0AaSEFAn8gAy0AaEEBcQRAIAVB/wFxQdsARwRAIAghBUEODAILIAwQlAEgA0HgAGogDBCSASADLQBkIAMoAmAhBkEAIRIgA0EANgLIASADQoCA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BEEVRg0AIAIoApgBIQUgByEDDA8LQQAhByADQYB+cUEBcgsiA0H/AXFFBEAgAkGIAWogARCXASACKAKIASIBQRVHDQMgAEEVNgIADBALIAJBiAFqIAUQmAECQAJAIAIoAogBIgRBFUcEQCACQYABaiAJQQhqKAIAIgE2AgAgAiAJKQIAIgs3A3ggCEEIaiABNgIAIAggCzcCAAwBCyACQegAaiAFEBwgAigCaCIEQRVGDQELIAIoAnQhBSACKAJwIQYgAi0AbCEDIAIvAG0gAi0Ab0EQdHIMDwsgAkEwaiAFEJoBIAItADEhBCACLQAwQQFxDQALCyADQYB+cSAEQf8BcXIhA0ECIQQMCwsgAkHwAGogAkGUAWooAgAiAzYCACACIAIpAowBIgs3A2ggAEEMaiADNgIAIAAgCzcCBCAAIAE2AgAMDAsgACADOgAEIABBBDYCAAwLCyACQfAAaiACQZQBaigCACIBNgIAIAIgAikCjAEiCzcDaCAAQQxqIAE2AgAgACALNwIEIAAgAzYCAAwKCyAAQQ42AgAMCQsgACADOgAEIABBBDYCAAwICyACKQKMASELIAAgAkGUAWopAgA3AgggACALNwIADAcLIABBDjYCAAwGCyAAIAM6AAQgAEEENgIADAULIABBFTYCAAwECyAAQQs2AgAMAwsgAEEONgIADAILIANBCHYLIgE7AAUgACAFNgAMIAAgBjYACCAAIAM6AAQgACAENgIAIABBB2ogAUEQdjoAAAsgAkGgAWokAAvTAQEBfyMAQfAAayIDJAAgAyACNgIMIAMgATYCCCADQRxqQQI2AgAgA0EkakEBNgIAIANBpI3AADYCGCADQQA2AhAgA0EBNgIsIAMgA0EoajYCICADIANBCGo2AiggA0EANgI4IANCgICAgBA3AzAgA0FAayIBIANBMGpBtIfAABD/ASADQRBqIAEQ9QEEQEHMh8AAQTcgA0HoAGpBhIjAAEHgiMAAEPYBAAsgACADKQMwNwIEIABBFDYCACAAQQxqIANBOGooAgA2AgAgA0HwAGokAAu7AgIEfwF+IwBBIGsiAiQAIAIgARCaASACLQABIQMCQAJAAkACQAJAIAItAABBAXEEQCADQSJHDQEgARCUASACQQhqIAEQmQEgAigCCA0CIAJBFGooAgAhASACQRBqKAIAIQMgAigC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QCACQdwBaiACQfwBaigAADYAACACQdgBaiADOgAAIAIgAigA+QE2ANkBIAIgBTYC1AEgAkEBNgLQAQwVCyACIAM6AOQBIAIgBTYC4AEgAkHwAWogAkHgAWpB64TAAEEIIAdBIGooAgAgB0EkaigCABATIAIoAvABBEAgAkHcAWogAkH8AWooAgA2AgAgAiACKQL0ATcC1AEgAkEBNgLQAQwVCyACQfABaiACQeABakHzhMAAQQUgB0EoahAWIAIoAvABBEAgAkHcAWogAkH8AWooAgA2AgAgAiACKQL0ATcC1AEgAkEBNgLQAQwVCyACQdABaiACKALgASACLQDkARCfASACKALQAQ0UIAQoAgghAwwVCyAEKAIIIgMgBCgCAEcNEgwRCyACQdwBaiACQfwBaigCADYCACACIAIpAvQBNwLUAQwSCyACQdwBaiACQfwBaigCADYCACACIAIpAvQBNwLUAQwRCyACQdwBaiACQfwBaigCADYCACACIAIpAvQBNwLUASACQQE2AtABDBALIAJBADoAvAEgAygCACAFRgRAIAMgBRAQIAMoAgghBQsgAygCBCAFakEiOgAAIAMgBUEBaiIFNgIIIAMoAgAgBWtBA00EQCADIAVBBBARIAMoAgghBQsgAygCBCAFakH23tGrBjYAACADIAVBBGoiBTYCCCADKAIAIAVrQQFNBEAgAyAFQQIQESADKAIIIQULIAMoAgQgBWpBovQAOwAAIAMgBUECajYCCAJAAkACQAJAAkAgDkEBaw4DAQIDAAsgAkHwAWogA0GohsAAQQMQowEMAwsgAkHwAWogA0GmhsAAQQIQowEMAgsgAkHwAWogA0GfhsAAQQcQowEMAQsgAkHwAWogA0GThsAAQQwQowELIAIoAvABBEAgAkHsAWogAkH8AWooAgA2AgAgAiACKQL0ATcC5AEMAQsgAkHgAWogA0EAEJ8BIAIoAuABDQAgBCgCCCIDIAQoAgBGDQ0MDgsgAkHcAWogAkHsAWooAgA2AgAgAiACKQLkATcC1AEgAkEBNgLQAQwOCyACQeABaiACKALAASACLQDEARCfAQwECyACIAM2ArgBIAdBLGooAgAhESAHQShqKAIAIQ4CQCAFBEAgAygCCCEFDAELIAMoAggiCiADKAIARgRAIAMgChAQIAMoAgghCgsgAyAKQQFqIgU2AgggAygCBCAKakEsOgAACyACQQA6ALwBIAMoAgAgBUYEQCADIAUQECADKAIIIQULIAMoAgQgBWpBIjoAACADIAVBAWoiBTYCCCADKAIAIAVrQQRNBEAgAyAFQQUQESADKAIIIQULIAMoAgQgBWoiCkHRhcAAKAAANgAAIApBBGpB1YXAAC0AADoAACADIAVBBWoiBTYCCCADKAIAIAVrQQFNBEAgAyAFQQIQESADKAIIIQULIAMoAgQgBWpBovQAOwAAIAMgBUECajYCCAJAIA5FBEAgAkHwAWogAxCiAQwBCyACQfABaiADIA4gERCdAQsCQAJAAkACQCACKALwAUUEQCACQfABaiACQbgBakH2hcAAQQcgB0HYAGopAwAQFSACKALwAQ0BIAJB8AFqIAJBuAFqQeiFwABBAyAHQTBqEBYgAigC8AENAiACQfABaiACQbgBakGtgsAAQQUgB0FAaygCACAHQcQAaigCABAPIAIoAvABDQMgAkHwAWogAkG4AWpB/YXAAEEFIAdBzABqKAIAIAdB0ABqKAIAEBMgAigC8AENBCACQeABaiACKAK4ASACLQC8ARCfAQwICyACQcgBaiAIQQhqKAIAIgM2AgAgAiAIKQIAIhI3A8ABIAZBCGogAzYCACAGIBI3AgAMBAsgBiAIKQIANwIAIAZBCGogCEEIaigCADYCAAwDCyAGIAgpAgA3AgAgBkEIaiAIQQhqKAIANgIADAILIAYgCCkCADcCACAGQQhqIAhBCGooAgA2AgAMAQsgBiAIKQIANwIAIAZBCGogCEEIaigCADYCAAsgAkEBNgLgAQwCCyACQeABaiACKALAASACLQDEARCfAQwBCyACQeABaiACKALAASACLQDEARCfAQsgAigC4AENACAEKAIIIgMgBCgCAEYNBgwHCyACQdwBaiAGQQhqKAIANgIAIAJBATYC0AEgAiAGKQIANwLUAQwHCyACKAK4ASEDAkAgAi0AvAEEQCADKAIIIQUMAQsgAygCCCIKIAMoAgBGBEAgAyAKEBAgAygCCCEKCyADIApBAWoiBTYCCCADKAIEIApqQSw6AAALIAJBADoAvAEgAygCACAFRgRAIAMgBRAQIAMoAgghBQsgAygCBCAFakEiOgAAIAMgBUEBaiIFNgIIIAMoAgAgBWtBBU0EQCADIAVBBhAR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KALwAQ0GIAJB8AFqIAJBwAFqIARBBGsoAgAgBCgCABAmIAIoAvABBEAgAkHsAWogAkH8AWooAgA2AgAgAiACKQL0ATcC5AEMCQsgAkHgAWogAigCwAEgAi0AxAEQnAEgAigC4AENCCAEQRhqIQRBASEDIA1BGGsiDQ0AC0EABSADC0H/AXFBAEcQngEgAigC0AENByAFKAIIIgQgBSgCAEYEQCAFIAQQECAFKAIIIQQLIAUoAgQgBGpBLDoAACAFIARBAWoiBDYCCCACQQA6AEwgBSgCACAERgRAIAUgBBAQIAUoAgghBAsgBSgCBCAEakEiOgAAIAUgBEEBaiIENgIIIAUoAgAgBGtBA00EQCAFIARBBBARIAUoAgghBAsgBSgCBCAEakHkwtGLBjYAACAFIARBBGoiBDYCCCAFKAIAIARrQQFNBEAgBSAEQQIQESAFKAIIIQQLIAUoAgQgBGpBovQAOwAAIAUgBEECajYCCCABKAIEDQEgAkHwAWogBRCiAQwCCyACQewBaiACQfwBaigAADYAACACQegBaiADOgAAIAIgAigA+QE2AOkBIAIgBzYC5AEMBQsgAkHgAWogARB3IAJB8AFqIAUgAigC5AEiASACKALoARCdASACKALgAUUNACABELcBCyACKALwAQRAIAJBxABqIAJB/AFqKAIANgIAIAIgAikC9AE3AjwMCQsgAkE4aiAFQQAQnAEgAigCOA0IIAIoAhAiBCACKAIIRgRAIAJBCGogBBAQIAIoAhAhBAsgAigCDCAEakH9ADoAACACIARBAWo2AhALIAJB6AFqIAJBEGooAgAiATYCACACIAIpAwgiEjcD4AEgAEEMaiABNgIAIAAgEjcCBCAAQQ02AgAMCQsgAkHsAWogAkH8AWooAgA2AgAgAiACKQL0ATcC5AEMAQsgAkHcAWogAkH8AWooAgA2AgAgAiACKQL0ATcC1AEMAQsgAkHcAWogAkHsAWooAgA2AgAgAiACKQLkATcC1AELIAJBxABqIAJB3AFqKAIANgIAIAIgAikC1AE3AjwMAwsgAkHsAGogAkH8AWooAgA2AgAgAiACKQL0ATcCZAwBCyACQewAaiACQYwBaigCADYCACACIAIpAoQBNwJkCyACQcQAaiACQewAaigCADYCACACIAIpAmQ3AjwLIAJBJGogAkHEAGoo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HEUNBAsgBigCABC3AQwDCyABQRxqKAIABEAgAUEgaigCABC3AQsgAUEoaigCAEUNAiABQSxqKAIAELcBDAILAn8CQAJAAkAgAw4CAQIACyABQRxqKAIARQ0EIAFBIGoMAgsgAUEcaigCAARAIAFBIGooAgAQtwELIAFBKGooAgAEQCABQSxqKAIAELcBCyABQfAAaigCAEUNAyABQfQAagwBCyABQRxqKAIABEAgAUEgaigCABC3AQsgAUEoaigCAEUNAiABQSxqCygCABC3AQwBCwJAAkACQAJAAkAgAUEgaigCAA4EAQIDBAALIAFBJGooAgBFDQQgAUEoaigCABC3AQwECyABQSRqKAIABEAgAUEoaigCABC3AQsgAUEwaigCAARAIAFBNGooAgAQtwELIAFBQGshBiABQcQAaigCACIDBEAgA0EFdCEDIAYoAgBBFGohAgNAIAJBBGsoAgAEQCACKAIAELcBCyACQSBqIQIgA0EgayIDDQALCyABKAI8RQ0DIAYoAgAQtwEMAwsCQCABQShqKAIAIgNFDQAgAUEkaigCAEUNACADELcBCyABQTBqKAIABEAgAUE0aigCABC3AQsgAUFAayEGIAFBxABqKAIAIgMEQCADQQV0IQMgBigCAEEUaiECA0AgAkEEaygCAARAIAIoAgAQtwELIAJBIGohAiADQSBrIgMNAAsLIAEoAjwEQCAGKAIAELcBCyABQcgAaigCAEUNAiABQcwAaigCABC3AQwCCyABQSRqKAIABEAgAUEoaigCABC3AQsgAUEwaigCAEUNASABQTRqKAIAELcBDAELIAFBJGooAgAEQCABQShqKAIAELcBCyABQTBqKAIARQ0AIAFBNGooAgAQtwELIAQgBUcNAAsLIAAoAgwEQCAAQRBqKAIAELcBCyAAQSBqKAIAIgQEQCAAQRxqKAIAIgIgBEEYbGohBANAIAIoAgAEQCACQQRqKAIAELcBCyACQQxqKAIABEAgAkEQaigCABC3AQsgAkEYaiICIARHDQALCyAAKAIYBEAgAEEcaigCABC3AQsgAEEsaigCACIEBEAgAEEoaigCACIFIARBGGxqIQEDQCAFKAIABEAgBUEEaigCABC3AQsgBUEQaiEDIAVBFGooAgAiBARAIAMoAgAiAiAEQRhsaiEEA0AgAigCAARAIAJBBGooAgAQtwELIAJBDGooAgAEQCACQRBqKAIAELcBCyACQRhqIgIgBEcNAAsLIAUoAgwEQCADKAIAELcBCyAFQRhqIgQhBSABIARHDQALCyAAKAIkBEAgAEEoaigCABC3AQsgAEEEaigCACIERQ0BIAAoAgBFDQEgBBC3AQ8LIAAoAgBFDQAgAEEEaigCABC3AQsLAwABCzUBAX8gACgCACAAKAIEKAIAEQUAIAAoAgQiAUEEaigCAARAIAFBCGooAgAaIAAoAgAQtwELCxUAIAAoAgAEQCAAQQRqKAIAELcBCwuTAgACQAJ/AkACQAJAAkACQAJAAkACQAJAAkAgACgCAA4MCwsBAgsDBAUGBwgJAAsgAEEUaigCAEUNCiAAQRhqDAkLIAAoAgRFDQkgAEEIagwICyAAKAIERQ0IIABBCGoMBwsgACgCBEUNByAAQQhqDAYLIAAoAgRFDQYgAEEIagwFCyAAKAIERQ0FIABBCGoMBAsgACgCBARAIABBCGooAgAQtwELIAAoAhBFDQQgAEEUagwDCyAAKAIEBEAgAEEIaigCABC3AQsgACgCEEUNAyAAQRRqDAILIAAoAgQEQCAAQQhqKAIAELcBCyAAQRBqKAIARQ0CIABBFGoMAQsgACgCBEUNASAAQQhqCygCABC3AQsLpgEBBn8jAEEgayIDJAACfyACRQRAQQAhAUEADAELIAFBBGooAgAoAgwhBSABKAIAIQZBACEBA0AgA0EIaiAGIAURAQBBASADKAIMIgdFDQEaIAMoAhghBCADKAIUIAMoAggEQCAHELcBC0EBIARFDQEaIAFBAWohAQRAIAQQtwELIAEgAkcNAAsgAiEBQQALIQIgACABNgIEIAAgAjYCACADQSBqJAALmgEBBH8jAEEgayIDJAACfyACRQRAQQAhAUEADAELIAFBBGooAgAoAgwhBCABKAIAIQVBACEBA0AgA0EIaiAFIAQRAQBBASADKAIMIgZFDQEaIAMoAhQEQCADKAIYELcBCyABQQFqIQEgAygCCARAIAYQtwELIAEgAkcNAAsgAiEBQQALIQIgACABNgIEIAAgAjYCACADQSBqJAALngIBB38jAEFAaiIDJAACQCACRQ0AIAFBBGooAgAoAgwhBiABKAIAIQcDQCADQQhqIAcgBhEBACADKAIMIghFBEBBASEEDAILIAMoAhghBSADKAIUIAMoAggEQCAIELcBCyAFRQRAQQEhBAwCCwRAIAUQtwELIAJBAWsiAg0ACwsCQCAERQRAIANBCGogASgCACABQQRqKAIAKAIMEQEAIAMoAgwiAUUEQCAAQQA2AgQMAgsgAygCCCADQThqIANBGGopAwA3AwAgA0EoaiIEIANBPGooAgA2AgAgAyADKQMQNwMwIAMgAykCNDcDIARAIAEQtwELIAAgAykDIDcCACAAQQhqIAQoAgA2AgAMAQsgAEEANgIECyADQUBrJAAL3AEBBX8jAEEgayIDJAACQCACRQ0AIAFBBGooAgAoAgwhBCABKAIAIQUDQCADQQhqIAUgBBEBACADKAIMIgZFBEBBASEHDAILIAMoAhQEQCADKAIYELcBCyADKAIIBEAgBhC3AQsgAkEBayICDQALCwJAIAdFBEAgA0EIaiABKAIAIAFBBGooAgAoAgwRAQAgAygCDEUEQCAAQQA2AgQMAgsgAygCFARAIAMoAhgQtwELIAAgAykDCDcCACAAQQhqIANBEGooAgA2AgAMAQsgAEEANgIECyADQSBqJAALDgAgACgCACABEDsaQQALzgIBAn8jAEEQayICJAACQAJ/AkACQCABQYABTwRAIAJBADYCDCABQYAQSQ0BIAFBgIAETw0CIAIgAUE/cUGAAXI6AA4gAiABQQx2QeABcjoADCACIAFBBnZBP3FBgAFyOgANQQMMAwsgACgCCCIDIAAoAgBGBEAgACADEBAgACgCCCEDCyAAIANBAWo2AgggACgCBCADaiABOgAADAMLIAIgAUE/cUGAAXI6AA0gAiABQQZ2QcABcjoADEECDAELIAIgAUE/cUGAAXI6AA8gAiABQQZ2QT9xQYABcjoADiACIAFBDHZBP3FBgAFyOgANIAIgAUESdkEHcUHwAXI6AAxBBAshASABIAAoAgAgACgCCCIDa0sEQCAAIAMgARARIAAoAgghAwsgACgCBCADaiACQQxqIAEQlwIaIAAgASADajYCCAsgAkEQaiQAQQALWgEBfyMAQSBrIgIkACACIAAoAgA2AgQgAkEYaiABQRBqKQIANwMAIAJBEGogAUEIaikCADcDACACIAEpAgA3AwggAkEEakGEjMAAIAJBCGoQ7AEgAkEgaiQAC0cBAX8gAiAAKAIAIgAoAgAgACgCCCIDa0sEQCAAIAMgAhARIAAoAgghAwsgACgCBCADaiABIAIQlwIaIAAgAiADajYCCEEAC/gFAQV/IwBBkAFrIgIkACACQQhqIAFBDGopAgA3AwAgAkEQaiABQRRqKQIANwMAIAJBGGogAUEcaikCADcDACACQSBqIAFBJGopAgA3AwAgAkEoaiABQSxqKQIANwMAIAIgASkCBDcDAAJAAkAgASgCAEUEQCAAIAFBBGoiASkCADcCACAAQShqIAFBKGopAgA3AgAgAEEgaiABQSBqKQIANwIAIABBGGogAUEYaikCADcCACAAQRBqIAFBEGopAgA3AgAgAEEIaiABQQhqKQIANwIADAELIAJByABqIAJBHGopAgA3AwAgAkFAayACQRRqKQIANwMAIAJBOGogAkEMaikCADcDACACIAIpAgQ3AzAgAkEANgJYIAJCgICAgBA3A1AgAkHgAGoiBCACQdAAakG0h8AAEP8BIwBBMGsiASQAAkACQAJAAkBBACACQTBqIgMoAgAiBUEMayIGIAUgBkkbQQFrDgIBAgALIAFBDGpBATYCACABQRRqQQE2AgAgAUHkj8AANgIIIAFBADYCACABQQQ2AhwgASADNgIsIAEgAUEYajYCECABIAFBLGo2AhgMAgsgAUEMakEBNgIAIAFBFGpBADYCACABQdyPwAA2AgggAUGcjMAANgIQIAFBADYCAAwBCyABQSRqQQU2AgAgAUEMakEDNgIAIAFBFGpBAjYCACABIANBBGo2AiggAUGcj8AANgIIIAFBADYCACABQQU2AhwgASADQRBqNgIsIAEgAUEYajYCECABIAFBLGo2AiAgASABQShqNgIYCyAEIAEQhAIgAUEwaiQADQEgACACKQNQNwIAIABBADYCECAAQQhqIAJB2ABqKAIANgIAAkACQEEAIAIoAjAiAEEMayIBIAAgAUkbDgIBAgALIAIoAjQEQCACQThqKAIAELcBCyACKAJARQ0BIAJBxABqKAIAELcBDAELIAJBMGoQNQsgAkGQAWokAA8LQcyHwABBNyACQYgBakGEiMAAQeCIwAAQ9gEAC0IBAX8gAiAAKAIAIAAoAggiA2tLBEAgACADIAIQESAAKAIIIQMLIAAoAgQgA2ogASACEJcCGiAAIAIgA2o2AghBAAurAQEBfwJAIAIEQAJ/AkACQAJAIAFBAE4EQCADKAIIRQ0CIAMoAgQiBA0BIAENAyACDAQLIABBCGpBADYCAAwFCyADKAIAIAQgAiABEEsMAgsgAQ0AIAIMAQsgASACEEoLIgMEQCAAIAM2AgQgAEEIaiABNgIAIABBADYCAA8LIAAgATYCBCAAQQhqIAI2AgAMAQsgACABNgIEIABBCGpBADYCAAsgAEEBNgIAC/cBAQF/IwBBgAFrIgQkACAEIAI2AgwgBCABNgIIIARBHGpBAjYCACAEQSRqQQI2AgAgBEE0akEDNgIAIARByI3AADYCGCAEQQA2AhAgBEEBNgIsIARBATYCPCAEIAM2AjggBCAEQShqNgIgIAQgBEE4ajYCMCAEIARBCGo2AiggBEEANgJIIARCgICAgBA3A0AgBEHQAGoiASAEQUBrQbSHwAAQ/wEgBEEQaiABEPUBBEBBzIfAAEE3IARB+ABqQYSIwABB4IjAABD2AQALIAAgBCkDQDcCBCAAQRQ2AgAgAEEMaiAEQcgAaigCADYCACAEQYABaiQAC58CAgN/AX4jAEEgayICJAAgAiABEJoBIAItAAEhAwJAAkACQCACLQAAQQFxBEAgA0EiRw0BIAEQlAEgAkEIaiABEJkBIAIoAggNAiACQRRqKAIAIQEgAkEQaigCACEDIAIoAgxFBEACQCABQQpGBEAgA0GYkMAAQQoQmQJFDQELIAAgAyABQaSQwAAQQQwFCyAAQRU2AgAMBAsCQAJAIAJBGGooAgAiBEEKRgRAIAFBmJDAAEEKEJkCRQ0BCyAAIAEgBEGkkMAAEEEMAQsgAEEVNgIACyADRQ0DIAEQtwEMAwsgACADOgAEIABBBDYCAAwCCyAAQQ42AgAMAQsgAikCDCEFIAAgAkEUaikCADcCCCAAIAU3AgALIAJBIGokAAufAgIDfwF+IwBBIGsiAiQAIAIgARCaASACLQABIQMCQAJAAkAgAi0AAEEBcQRAIANBIkcNASABEJQBIAJBCGogARCZASACKAIIDQIgAkEUaigCACEBIAJBEGooAgAhAyACKAIMRQRAAkAgAUEJRgRAIANB7I/AAEEJEJkCRQ0BCyAAIAMgAUH4j8AAEEEMBQsgAEEVNgIADAQLAkACQCACQRhqKAIAIgRBCUYEQCABQeyPwABBCRCZAkUNAQsgACABIARB+I/AABBBDAELIABBFTYCAAsgA0UNAyABELcBDAMLIAAgAzoABCAAQQQ2AgAMAgsgAEEONgIADAELIAIpAgwhBSAAIAJBFGopAgA3AgggACAFNwIACyACQSBqJAALnwICA38BfiMAQSBrIgIkACACIAEQmgEgAi0AASEDAkACQAJAIAItAABBAXEEQCADQSJHDQEgARCUASACQQhqIAEQmQEgAigCCA0CIAJBFGooAgAhASACQRBqKAIAIQMgAigCDEUEQAJAIAFBD0YEQCADQYCQwABBDxCZAkUNAQsgACADIAFBkJDAABBBDAULIABBFTYCAAwECwJAAkAgAkEYaigCACIEQQ9GBEAgAUGAkMAAQQ8QmQJFDQELIAAgASAEQZCQwAAQQQwBCyAAQRU2AgALIANFDQMgARC3AQwDCyAAIAM6AAQgAEEENgIADAILIABBDjYCAAwBCyACKQIMIQUgACACQRRqKQIANwIIIAAgBTcCAAsgAkEgaiQAC9wCAgJ/A34jAEFAaiIDJAAgA0EgaiABIAJBDGooAgAQKwJAAkAgAygCICIEQQ1GBEAgAygCJEEBaiIERQ0BIANBIGogBBAoIAMoAiAiBEENRgRAIAMoAiQgAUGjjsAAQQYgA0EoaigCACIBIANBLGooAgAgAigCHBEHAARAIAEQtwELIABBDzYCAAwDCyADQRBqIANBOGopAwAiBTcDACADIAMpAzAiBjcDCCADKQIkIQcgAygCLCEBIABBGGogBTcDACAAIAY3AxAgACABNgIMIAAgBzcCBCAAIAQ2AgAMAgsgA0EQaiADQTBqKQMAIgU3AwAgA0EYaiADQThqKQMAIgY3AwAgAyADKQMoIgc3AwggAygCJCEBIABBGGogBjcDACAAQRBqIAU3AwAgACAHNwMIIAAgATYCBCAAIAQ2AgAMAQtBgIDAAEEcQbiOwAAQ5wEACyADQUBrJAALxB8CD38DfiMAQaADayIDJAAQuQEgA0HgAGogABCMASADQfAAaiABEIwBIANBgAFqIAIQjAEgA0G4AmogAygCZCIPIAMoAmgQIQJAAkACQAJAAkACQAJAAkACQAJAAkACQCADKALYAkECRwRAIANBqAFqIANBwAJqKQMANwMAIANBmAFqIANB2AJqKQMANwMAIAMgAykDuAI3A6ABIAMgAykD0AI3A5ABIAMoAsgCIQUgAygCzAIhCCADKALgAiEJIAMoAuQCIQYgAykD6AIhEiADQbABaiADKAJ0IhAgAygCeBAaIAMoArABQQ1HDQIgA0HIAWooAgAhBCADQcQBaigCACEKIANBwAFqKAIAIQcgA0G8AWooAgAhDSADQbgBaigCACELIAMoArQBIQwgA0EwaiIAIAMoAoQBIhEgAygCiAEQkwEgA0EoaiAAEJoBQQQhASADLQApIQAgAy0AKEEBcUUNBSAAQf8BcUH7AEYNAUEOIQEMBQsgA0HIAWogA0HQAmopAwA3AwAgA0HAAWogA0HIAmopAwA3AwAgA0G4AWogA0HAAmopAwA3AwAgAyADKQO4AjcDsAEgA0EANgLYASADQoCAgIAQNwPQASADQeABaiIAIANB0AFqQbSHwAAQ/wEgA0GwAWogABCKAQ0LIANBOGogA0HYAWooAgA2AgAgAyADKQPQATcDMCADQQA2AkAgA0GwAWoQNQwJCyADQTBqIgAQlAEgA0EgaiAAEJIBIAMtACQgA0EYaiADKAIgIgIQmgFBAiEBIAMtABkhACADLQAYQQFxRQ0CQQFxIQECQAJAIABB/wFxIg5BLEcEQCAOQf0ARg0CIAENAUEJIQEMBQsgAQ0DIAIQlAEgA0EQaiACEJoBQQQhASADLQARIQAgAy0AEEEBcUUNBAsgAEH/AXEiAEH9AEcEQCAAQSJHDQMgA0EIaiACEJoBQQQhASADLQAJIQAgAy0ACEEBcUUNBEEOIQEgAEH/AXFBIkcNBCACEJQBIANBuAJqIAIQmQECQCADKAK4AkUEQCADQcQCaigCACEAIANBwAJqKAIAIQEgAygCvAJFBEAgA0HgAWogASAAQZyMwABBABAsDAILIANB4AFqIAAgA0HIAmooAgBBnIzAAEEAECwgAUUNASAAELcBDAELIAMgAykCvAI3A+ABIAMgA0HEAmopAgA3A+gBCyADIAMpAOUBNwPQASADIANB7AFqKAAANgDXASADKALgASIBQRVGDQEgAy0A5AEhAAwEC0ETIQEMAwsgA0G4AmogA0EwahCXASADKAK4AiIBQRVHBEAgAyADKQC9AjcDqAIgAyADQcQCaigAADYArwIgAy0AvAIhAAwECyADQbgCaiADQTBqEJUBIAMoArgCIgFBFUYNBSADIAMpAL0CNwOYAiADIANBxAJqKAAANgCfAiADLQC8AiEADAQLIANB+AFqIANByAFqKQMANwMAIANB8AFqIANBwAFqKQMANwMAIANB6AFqIANBuAFqKQMANwMAIAMgAykDsAE3A+ABIANBADYC2AEgA0KAgICAEDcD0AEgA0G4AmoiACADQdABakG0h8AAEP8BIANB4AFqIAAQigENCSADQThqIANB2AFqKAIANgIAIAMgAykD0AE3AzAgA0EANgJAIANB4AFqEDUMBgtBECEBCyADIAMoANcBNgCvAiADIAMpA9ABNwOoAgsgAyADKACvAjYAnwIgAyADKQOoAjcDmAILIANBxAJqIAMoAJ8CNgAAIAMgADoAvAIgAyABNgK4AiADIAMpA5gCNwC9AiADQbABakGOicAAQSIgA0G4AmoQICADKAKwAUENRw0BCyADQfACaiADQagBaikDADcDACADQfwCaiAINgIAIANB+AJqIAU2AgAgA0GAA2ogAykDkAE3AwAgA0GIA2ogA0GYAWopAwA3AwAgA0GYA2ogEjcDACADQZQDaiAGNgIAIANBkANqIAk2AgAgA0H4gcAANgLMAiADQcyBwAA2AsQCIANBqIHAADYCvAIgAyADKQOgATcD6AIgAyADQagCaiIANgLIAiADIAA2AsACIAMgADYCuAIgA0HkAmogBDYCACADQeACaiAKNgIAIANB3AJqIAc2AgAgA0HYAmogDTYCACADQdQCaiALNgIAIAMgDDYC0AIgA0HgAWoiDSEBIANB6AJqIQogA0HQAmohAkEAIQcjAEGgAWsiACQAIANBuAJqIgQoAgQhCyAEKAIAIQwCQAJAAkACQAJAAkACQAJAQRhBARBKIgUEQCAFQRBqQdiOwAApAAA3AAAgBUEIakHQjsAAKQAANwAAIAVByI7AACkAADcAAEEFQQEQSiIIRQ0BIAhBBGpB5I7AAC0AADoAACAIQeCOwAAoAAA2AAAgAEHoAGoiBBCgASAAQZABaiAEEKUBIAAoApABDQIgACAAKAKUATYCiAEgACAAQZgBai0AADoAjAEgAEGQAWogAEGIAWpBk4LAAEEIIAVBGBATIAAoApABDQMgAEGQAWogAEGIAWpBnYfAAEEHIAhBBRATIAAoApABBEAgAEGEAWogAEGcAWooAgA2AgAgACAAKQKUATcCfAwGCyAAQfgAaiAAKAKIASAALQCMARCcASAAKAJ4RQ0EDAULQRhBARDcAQALQQVBARDcAQALIABBhAFqIABBnAFqKAAANgAAIABBgAFqIABBmAFqLQAAOgAAIAAgACgAmQE2AIEBIAAgACgClAE2AnwMAgsgAEGEAWogAEGcAWooAgA2AgAgACAAKQKUATcCfAwBCyAAQTRqIABB8ABqKAIANgIAIAAgACkDaDcCLAwBCyAAQeAAaiIEIABBhAFqKAIANgIAIAAgACkCfDcDWCAAKAJoBEAgACgCbBC3AQsgAEGYAWogBCgCADYCACAAIAApA1g3A5ABIABBKGpBsInAAEEUIABBkAFqECcgACgCKCIJQQ1HDQELIAAoAiwhBkENIQkgDEGkh8AAQQ0gAEEwaigCACIEIABBNGooAgAgCygCHBEHACAGRQ0BIAQQtwEMAQsgAEEgaiAAQUBrKQMANwMAIAAgACkDODcDGCAAKAI0IQYgACgCMCEEIAAoAiwhBwsgBRC3ASAIELcBAkACQAJAAkACQCAJQQ1GBEAgAEEoakEAECggACgCKCIEQQ1HDQEgACgCLCAMQaOOwABBBiAAQTBqKAIAIgUgAEE0aigCACALKAIcEQcABEAgBRC3AQsgAEHUAGpBADYCACAAQcQAakIENwIAIABBPGpCADcCACAAQoCAgIDAADcCTCAAQoCAgICAATcCNCAAQQA2AixBBkEBEEoiCEUNAiAIQQRqQemOwAAvAAA7AAAgCEHljsAAKAAANgAAQQtBARBKIglFDQMgCUEHakHyhcAAKAAANgAAIAlB64XAACkAADcAACMAQSBrIgQkACAAQUBrIgUoAgAiBkEBdCIHQQEgB0EBSxsiB0EEIAdBBEsbIgdBGGwhCyAHQdaq1SpJQQJ0IQwCQCAGBEAgBCAGQRhsNgIUIARBBDYCGCAEIAVBBGooAgA2AhAMAQsgBEEANgIYCyAEIAsgDCAEQRBqEEAgBCgCBCEGAkAgBCgCAEUEQCAFIAc2AgAgBSAGNgIEDAELIARBCGooAgAiB0GBgICAeEYNACAHBEAgBiAHENwBAAsQ3QEACyAEQSBqJAAgAEHIAGoiBiAGKAIAIgRBAWo2AgAgASAAKQMoNwIEIAFBDGogAEEwaikDADcCACABQRRqIABBOGopAwA3AgAgAUEcaiAFKQMANwIAIAFBLGogAEHQAGopAwA3AgAgACgCRCAEQRhsaiIEQQs2AhQgBCAJNgIQIARChoCAgLABNwIIIAQgCDYCBCAEQQY2AgAgAUEkaiAGKQMANwIAIAFBADYCACACKAIABEAgAkEEaigCABC3AQsgAkEQaigCACEFIAJBFGooAgAiAQRAIAFBBXQhBCAFQRRqIQEDQCABQQRrKAIABEAgASgCABC3AQsgAUEgaiEBIARBIGsiBA0ACwsgAigCDARAIAUQtwELIAooAhBFDQUgCkEUaigCABC3AQwFCyAAQRBqIABBIGopAwAiEjcDACAAIAApAxgiEzcDCCABQSBqIBI3AgAgAUEYaiATNwIAIAFBFGogBjYCACABQRBqIAQ2AgAgAUEMaiAHNgIAIAEgCTYCCAwDCyAAQZgBaiAAQUBrKQMAIhI3AwAgACAAKQM4IhM3A5ABIAApAiwhFCAAKAI0IQUgAUEgaiASNwMAIAFBGGogEzcDACABQRRqIAU2AgAgAUEMaiAUNwIAIAEgBDYCCAwCC0EGQQEQ3AEAC0ELQQEQ3AEACyABQQE2AgAgAigCAARAIAJBBGooAgAQtwELIAJBEGooAgAhBSACQRRqKAIAIgEEQCABQQV0IQQgBUEUaiEBA0AgAUEEaygCAARAIAEoAgAQtwELIAFBIGohASAEQSBrIgQNAAsLIAIoAgwEQCAFELcBCyAKKAIQRQ0AIApBFGooAgAQtwELIAooAigEQCAKQSxqKAIAELcBCyAAQaABaiQAIANBMGogDRA+IAMoAoABBEAgERC3AQsgAygCcARAIBAQtwELIAMoAmBFDQMgDxC3AQwDCyADQfgBaiADQcgBaikDADcDACADQfABaiADQcABaikDADcDACADQegBaiADQbgBaikDADcDACADIAMpA7ABNwPgASADQQA2AtgBIANCgICAgBA3A9ABIANBuAJqIgAgA0HQAWpBtIfAABD/ASADQeABaiAAEIoBRQRAIANBOGogA0HYAWooAgA2AgAgAyADKQPQATcDMCADQQA2AkAgA0HgAWoQNSAMBEAgCxC3AQsgBARAIARBBXQhASAKQRRqIQADQCAAQQRrKAIABEAgACgCABC3AQsgAEEgaiEAIAFBIGsiAQ0ACwsgB0UNASAKELcBDAELDAMLIAUEQCAIELcBCyAJRQ0AIAYQtwELIAMoAoABBEAgAygChAEQtwELIAMoAnAEQCADKAJ0ELcBCyADKAJgRQ0AIA8QtwELIANB4AFqIANBMGoQJCADKALgAUENRgRAIANBuAFqIANB7AFqKAIAIgA2AgAgAyADKQLkASISNwOwASADQcACaiAANgIAIAMgEjcDuAIgA0G4AmoQiwEgA0EwahAxIANBoANqJAAPCyADQdACaiADQfgBaikDADcDACADQcgCaiADQfABaikDADcDACADQcACaiADQegBaikDADcDACADIAMpA+ABNwO4AkH4gsAAQSsgA0G4AmpBpIPAAEGghMAAEPYBAAtBzIfAAEE3IANBqAJqQYSIwABB4IjAABD2AQALwBYCEH8DfiMAQZADayIDJAAQuQEgA0HoAGogABCMASADQfgAaiABEIwBIANBiAFqIAIQjAEgA0GgAmogAygCbCIJIAMoAnAQIQJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkAgAygCwAJBAkcEQCADQbABaiADQagCaikDADcDACADQaABaiADQcACaikDADcDACADIAMpA6ACNwOoASADIAMpA7gCNwOYASADKAKwAiEHIAMoArQCIQogAygCyAIhCyADKALMAiEMIAMpA9ACIRQgA0G4AWogAygCfCIQIAMoAoABEBogAygCuAFBDUcNBSADQdABaigCACEFIANBzAFqKAIAIQYgA0HIAWooAgAhDSADQcQBaigCACERIANBwAFqKAIAIQ4gAygCvAEhDyADQThqIgAgAygCjAEiEiADKAKQARCTASADQTBqIAAQmgEgAy0AMSEAIAMtADBBAXFFDQEgAEEiRg0CIABB+wBGDQNBCiEBDAgLIANB0AFqIANBuAJqKQMANwMAIANByAFqIANBsAJqKQMANwMAIANBwAFqIANBqAJqKQMANwMAIAMgAykDoAI3A7gBIANBADYC4AEgA0KAgICAEDcD2AEgA0HoAWoiACADQdgBakG0h8AAEP8BIANBuAFqIAAQigENDSADQUBrIANB4AFqKAIANgIAIAMgAykD2AE3AzggA0EANgJIIANBuAFqEDUMCwsgACEEQQQhAQwGCyADQaACaiADQThqEEMgAygCoAIiAUEVRw0BQQ4hAQwFCyADQThqIgQQlAEgA0GgAmogBBBDIAMoAqACIgFBFUcNACADQaACaiAEEJgBIAMoAqACIgFB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EP8BIANB6AFqIAAQigFFBEAgA0FAayADQeABaigCADYCACADIAMpA9gBNwM4IANBADYCSCADQegBahA1IA8EQCAOELcBCyAFBEAgBUEFdCEBIAZBFGohAANAIABBBGsoAgAEQCAAKAIAELcBCyAAQSBqIQAgAUEgayIBDQALCyANRQ0BIAYQtwEMAQsMAwsgBwRAIAoQtwELIAtFDQAgDBC3AQsgAygCiAEEQCADKAKMARC3AQsgAygCeARAIAMoAnwQtwELIAMoAmhFDQAgCRC3AQsgA0HoAWogA0E4ahAkIAMoAugBQQ1GBEAgA0HAAWogA0H0AWooAgAiADYCACADIAMpAuwBIhM3A7gBIANBqAJqIAA2AgAgAyATNwOgAiADQaACahCLASADQThqEDEgA0GQA2okAA8LIANBuAJqIANBgAJqKQMANwMAIANBsAJqIANB+AFqKQMANwMAIANBqAJqIANB8AFqKQMANwMAIAMgAykD6AE3A6ACQfiCwABBKyADQaACakGkg8AAQZCEwAAQ9gEAC0HMh8AAQTcgA0GIA2pBhIjAAEHgiMAAEPYBAAvODgIKfwF+IwBBoAJrIgIkABC5ASACQegAaiAAEIwBIAJB+ABqIAEQjAEgAkG4AWogAigCbCIJIAIoAnAQIQJAAkACQAJAAkACQAJAAkAgAigC2AFBAkcEQCACKALkASEKIAIoAuABIQYgAigCzAEhByACKALIASEIIAJB8AFqIgAgAigCfCILIAIoAoABEJMBIAJBMGogABCaASACLQAxIQACQAJAAkAgAi0AMEEBcQRAIABBIkYNASAAQfsARg0CQQohAQwHCyAAIQNBBCEBDAYLIAJBuAFqIAJB8AFqEEQgAigCuAEiAUEVRw0BQQ4hAQwFCyACQfABaiIDEJQBIAJBuAFqIAMQRCACKAK4ASIBQRVHDQAgAkG4AWogAxCYASACKAK4ASIBQRVHDQAgAkEoaiADEJoBQQQhASACLQApIQAgAi0AKEEBcUUNAyAAQfsARwRAQQ4hAQwECyADEJQBIAJBIGogAxCSASACLQAkIAJBGGogAigCICIEEJoBIAItABkhACACLQAYQQFxRQRAQQIhAQwEC0EBcSEFAkACQCAAQSxHBEAgAEH9AEYNAiAFDQFBCSEBDAYLIAUNBCAEEJQBIAJBEGogBBCaASACLQARIQAgAi0AEEEBcUUNBQsCQAJAIABB/QBHBEAgAEEiRw0GIAJBCGogBBCaASACLQAJIQAgAi0ACEEBcUUNB0EOIQEgAEEiRw0HIAQQlAEgAkG4AWogBBCZASACKAK4AQ0BIAJBxAFqKAIAIQAgAkHAAWooAgAhASACKAK8AUUEQCACQThqIAEgAEGcjMAAQQAQLAwDCyACQThqIAAgAkHIAWooAgBBnIzAAEEAECwgAUUNAiAAELcBDAILQRMhAQwGCyACIAIpArwBNwM4IAIgAkHEAWopAgA3A0ALIAIoAjgiAUEVRg0AIAIvAD0gAi0AP0EQdHIhAyACKQNAIQwgAi0APCEADAQLIAJBuAFqIAMQlwEgAigCuAEiAUEVRwRAIAIvAL0BIAItAL8BQRB0ciEDIAIpA8ABIQwgAi0AvAEhAAwECyACIAMQmgEgAi0AASEAAkAgAi0AAEEBcQRAIABB/QBGDQFBCyEBDAYLIAAhA0EEIQEMBQsgAxCUASACQbgBaiACQfABahCVASACKAK4ASIBQRVGDQULIAIpA8ABIQwgAigCvAEhAwwDCyACQaABaiACQdABaikDADcDACACQZgBaiACQcgBaikDADcDACACQZABaiACQcABaikDADcDACACIAIpA7gBNwOIASACQQA2ArABIAJCgICAgBA3A6gBIAJB8AFqIgAgAkGoAWpBtIfAABD/ASACQYgBaiAAEIoBRQRAIAJBQGsgAkGwAWooAgA2AgAgAiACKQOoATcDOCACQQA2AkggAkGIAWoQNQwGCwwHC0EQIQELIANBCHQgAHIhAwsgAiAMNwPAASACIAM2ArwBIAIgATYCuAEgAkGIAWpBgIrAAEEbIAJBuAFqECAgAigCiAFBDUcNAQsgAkE4aiACQZgCakGogcAAEEUCQAJAIAIoAjgiAEEPRgRAIAJB6AFqQQA2AgAgAkHgAWpCgICAgMAANwMAIAJB2AFqQgQ3AwAgAkHQAWpCADcDACACQcgBakKAgICAgAE3AwAgAkHAAWpBADYCACACQQA2ArgBIAgEQCAHELcBCyAGDQEMAgsgAkHEAWogAikCPDcCACACQdwBaiACQdQAaigCADYCACACQdQBaiACQcwAaikCADcCACACQcwBaiACQcQAaikCADcCACACIAA2AsABIAJBATYCuAEgCARAIAcQtwELIAZFDQELIAoQtwELIAJBOGogAkG4AWoQPiACKAJ4BEAgCxC3AQsgAigCaEUNAiAJELcBDAILIAJBiAJqIAJBoAFqKQMANwMAIAJBgAJqIAJBmAFqKQMANwMAIAJB+AFqIAJBkAFqKQMANwMAIAIgAikDiAE3A/ABIAJBADYCsAEgAkKAgICAEDcDqAEgAkG4AWoiACACQagBakG0h8AAEP8BIAJB8AFqIAAQigFFBEAgAkFAayACQbABaigCADYCACACIAIpA6gBNwM4IAJBADYCSCACQfABahA1IAgEQCAHELcBCyAGRQ0BIAoQtwEMAQsMAgsgAigCeARAIAIoAnwQtwELIAIoAmhFDQAgCRC3AQsgAkHwAWogAkE4ahAkIAIoAvABQQ1GBEAgAkGQAWogAkH8AWooAgAiADYCACACIAIpAvQBIgw3A4gBIAJBwAFqIAA2AgAgAiAMNwO4ASACQbgBahCLASACQThqEDEgAkGgAmokAA8LIAJB0AFqIAJBiAJqKQMANwMAIAJByAFqIAJBgAJqKQMANwMAIAJBwAFqIAJB+AFqKQMANwMAIAIgAikD8AE3A7gBQfiCwABBKyACQbgBakGkg8AAQbCEwAAQ9gEAC0HMh8AAQTcgAkGYAmpBhIjAAEHgiMAAEPYBAAu7FwIKfwN+IwBBwAJrIgIkABC5ASACQdAAaiAAEIwBIAJBmAJqIAEQjAEgAkHIAWogAigCVCIHIAIoAlgQIQJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkAgAigC6AFBAkcEQCACQfgAaiACQdABaikDADcDACACQegAaiACQegBaikDADcDACACIAIpA8gBNwNwIAIgAikD4AE3A2AgAigC2AEhBSACKALcASEIIAIoAvABIQkgAigC9AEhCiACKQP4ASENIAJBQGsiACACKAKcAiILIAIoAqACEJMBIAJBOGogABCaASACLQA5IQACQAJAAkAgAi0AOEEBcQRAIABBIkYNASAAQfsARg0CQQohAQwHCyAAIQNBBCEBDAYLIAJByAFqIAJBQGsQQiACKALIASIBQRVHDQFBDiEBDAULIAJBQGsiAxCUASACQcgBaiADEEIgAigCyAEiAUEVRw0AIAJByAFqIAMQmAEgAigCyAEiAUEVRw0AIAJBMGogAxCaAUEEIQEgAi0AMSEAIAItADBBAXFFDQMgAEH7AEcEQEEOIQEMBAsgAxCUASACQShqIAMQkgEgAi0ALCACQSBqIAIoAigiBBCaASACLQAhIQAgAi0AIEEBcUUEQEECIQEMBAtBAXEhBgJAAkAgAEEsRwRAIABB/QBGDQIgBg0BQQkhAQwGCyAGDQQgBBCUASACQRhqIAQQmgEgAi0AGSEAIAItABhBAXFFDQULAkACQCAAQf0ARwRAIABBIkcNBiACQRBqIAQQmgEgAi0AESEAIAItABBBAXFFDQdBDiEBIABBIkcNByAEEJQBIAJByAFqIAQQmQEgAigCyAENASACQdQBaigCACEAIAJB0AFqKAIAIQEgAigCzAFFBEAgAkGgAWogASAAQZyMwABBABAsDAMLIAJBoAFqIAAgAkHYAWooAgBBnIzAAEEAECwgAUUNAiAAELcBDAILQRMhAQwGCyACIAIpAswBNwOgASACIAJB1AFqKQIANwOoAQsgAigCoAEiAUEVRg0AIAIvAKUBIAItAKcBQRB0ciEDIAIpA6gBIQwgAi0ApAEhAAwECyACQcgBaiADEJcBIAIoAsgBIgFBFUcEQCACLwDNASACLQDPAUEQdHIhAyACKQPQASEMIAItAMwBIQAMBAsgAkEIaiADEJoBIAItAAkhAAJAIAItAAhBAXEEQCAAQf0ARg0BQQshAQwGCyAAIQNBBCEBDAULIAMQlAEgAkHIAWogAkFAaxCVASACKALIASIBQRVGDQULIAIpA9ABIQwgAigCzAEhAwwDCyACQZgBaiACQeABaikDADcDACACQZABaiACQdgBaikDADcDACACQYgBaiACQdABaikDADcDACACIAIpA8gBNwOAASACQQA2ArACIAJCgICAgBA3A6gCIAJBoAFqIgAgAkGoAmpBtIfAABD/ASACQYABaiAAEIoBRQRAIAJBzABqIAJBsAJqKAIANgIAIAIgAikDqAI3AkQgAkEBNgJAIAJBgAFqEDUMCAsMDQtBECEBCyADQQh0IAByIQMLIAIgDDcD0AEgAiADNgLMASACIAE2AsgBIAJBgAFqQeiLwABBHCACQcgBahAgIAIoAoABQQ1HDQELIAJB6AFqIAJB+ABqKQMANwMAIAJB9AFqIAg2AgAgAkHwAWogBTYCACACQfgBaiACKQNgNwMAIAJBgAJqIAJB6ABqKQMANwMAIAJBkAJqIA03AwAgAkGMAmogCjYCACACQYgCaiAJNgIAIAJB+IHAADYC3AEgAkHMgcAANgLUASACQaiBwAA2AswBIAIgAikDcDcD4AEgAiACQbgCaiIANgLYASACIAA2AtABIAIgADYCyAEgAkGAAWohASACQeABaiEDIwBBQGoiACQAIABBIGogAkHIAWoiBCgCACAEKAIEQQxqKAIAECsCQCAAKAIgIgRBDUYEQCAAQSBqIAAoAiQQKAJAIAAoAiBBDUYEQCABIAApAiQ3AgQgAUENNgIAIAFBDGogAEEsaigCADYCAAwBCyABIAApAyA3AwAgAUEYaiAAQThqKQMANwMAIAFBEGogAEEwaikDADcDACABQQhqIABBKGopAwA3AwALIAMoAhBFDQEgA0EUaigCABC3AQwBCyAAQRBqIABBMGopAwAiDDcDACAAQRhqIABBOGopAwAiDTcDACAAIAApAygiDjcDCCAAKAIkIQUgAUEYaiANNwMAIAFBEGogDDcDACABIA43AwggASAFNgIEIAEgBDYCACADKAIQRQ0AIANBFGooAgAQtwELIAMoAigEQCADQSxqKAIAELcBCyAAQUBrJAAgAUEEciEAAkAgAigCgAEiAUENRgRAIAJBzABqIABBCGooAgA2AgAgAkEANgJAIAIgACkCADcCRAwBCyACQawBaiAAQQhqKAIANgIAIAJBuAFqIAJBmAFqKQMANwMAIAIgATYCoAEgAiACKQOQATcDsAEgAiAAKQIANwKkASACQQA2ArACIAJCgICAgBA3A6gCIAJByAFqIgAgAkGoAmpBtIfAABD/ASACQaABaiAAEIoBDQogAkHMAGogAkGwAmooAgA2AgAgAiACKQOoAjcCRCACQQE2AkAgAkGgAWoQNQsgAigCmAIEQCALELcBCyACKAJQBEAgBxC3AQsgAkGoAmoQoAEgAUENRw0EIAIoArACIgAgAigCqAJGBEAgAkGoAmogABAQIAIoArACIQALIAIoAqwCIABqQfsAOgAAIAIgAEEBajYCsAIgAkHIAWogAkGoAmpB2obAAEECEJ0BIAIoAsgBDQIgAigCsAIiACACKAKoAkYEQCACQagCaiAAEBAgAigCsAIhAAsgAigCrAIgAGpBOjoAACACIABBAWo2ArACIAJB8ABqIAJBQGtBBHIQdyACQcgBaiACQagCaiACKAJ0IgAgAigCeBCdASACKAJwBEAgABC3AQsgAigCyAENASACKAKwAiIAIAIoAqgCRgRAIAJBqAJqIAAQECACKAKwAiEACyACKAKsAiAAakH9ADoAACACIABBAWo2ArACDAULIAJBuAFqIAJBmAFqKQMANwMAIAJBsAFqIAJBkAFqKQMANwMAIAJBqAFqIAJBiAFqKQMANwMAIAIgAikDgAE3A6ABIAJBADYCsAIgAkKAgICAEDcDqAIgAkHIAWoiACACQagCakG0h8AAEP8BIAJBoAFqIAAQigENCCACQcwAaiACQbACaigCADYCACACIAIpA6gCNwJEIAJBATYCQCACQaABahA1IAUEQCAIELcBCyAJRQ0CIAoQtwEMAgsgAkGMAWogAkHUAWooAgA2AgAgAiACKQLMATcChAEMBAsgAkGMAWogAkHUAWooAgA2AgAgAiACKQLMATcChAEMAwsgAigCmAIEQCACKAKcAhC3AQsgAigCUARAIAcQtwELIAJBqAJqEKABCyACQYABaiACQagCaiACQcgAaigCACACQcwAaigCABAlIAIoAoABDQELIAJBrAFqIAJBsAJqKAIANgIAIAIgAikDqAI3AqQBDAELIAJBoAJqIgAgAkGMAWooAgA2AgAgAiACKQKEATcDmAIgAigCqAIEQCACKAKsAhC3AQsgAkHQAWogACgCADYCACACIAIpA5gCNwPIASACQaABakGUi8AAQdQAIAJByAFqECcgAigCoAFBDUcNAQsgAkHYAGogAkGsAWooAgAiADYCACACIAIpAqQBIgw3A1AgAkHQAWogADYCACACIAw3A8gBIAJByAFqEIsBIAIoAkAaIAIoAkQEQCACKAJIELcBCyACQcACaiQADwsgAkHgAWogAkG4AWopAwA3AwAgAkHYAWogAkGwAWopAwA3AwAgAkHQAWogAkGoAWopAwA3AwAgAiACKQOgATcDyAFB+ILAAEErIAJByAFqQaSDwABBwITAABD2AQALQcyHwABBNyACQbgCakGEiMAAQeCIwAAQ9gEACwkAIAAgARCxAQuWBwEGfwJ/AkACQAJAIAJBCU8EQCADIAIQsQEiBw0BQQAMBAtBCEEIEL8BIQFBFEEIEL8BIQJBEEEIEL8BIQRBAEEQQQgQvwFBAnRr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QYABayIDJAAgAigCACECA0AgACADakH/AGpBMEE3IAJBD3EiBEEKSRsgBGo6AAAgAEEBayEAIAJBD0sgAkEEdiECDQALIABBgAFqIgJBgQFPBEAgAkGAAUHs4sAAEOQBAAsgAUH84sAAQQIgACADakGAAWpBACAAaxD5ASADQYABaiQADwtBACEAIwBBgAFrIgMkACACKAIAIQIDQCAAIANqQf8AakEwQdcAIAJBD3EiBEEKSRsgBGo6AAAgAEEBayEAIAJBD0sgAkEEdiECDQALIABBgAFqIgJBgQFPBEAgAkGAAUHs4sAAEOQBAAsgAUH84sAAQQIgACADakGAAWpBACAAaxD5ASADQYABaiQAC24BAX8jAEEQayICJAAgAiAAKAIAIgA2AgQgAiAAQQhqNgIIIAIgAEEQajYCDCABQZizwABBF0HYsMAAQQsgAkEEakGws8AAQe6wwABBCyACQQhqQbCzwABBwLPAAEEFIAJBDGoQiQIgAkEQaiQACxkAIAAoAgAiACgCACAAQQRqKAIAIAEQigILbgEBfyMAQRBrIgIkACACIAAoAgAiAEEYajYCBCACIAA2AgggAiAAQQxqNgIMIAFB4LLAAEENQe2ywABBCSACQQRqQfiywABBiLPAAEEIIAJBCGpBlJXAAEGQs8AAQQggAkEMahCJAiACQRBqJAALHQAgASAAKAIALQAAQQJ0Qai2wABqKAIAQQMQgwIL+gMBAX8gACgCACECIwBBMGsiACQAAn8CQAJAAkACQAJAAkACQCACKAIAQQFrDgYBAgMEBQYACyAAQRRqQQE2AgAgAEEcakEANgIAIABB8LXAADYCECAAQcyRwAA2AhggAEEANgIIIAEgAEEIahCEAgwGCyAAQRRqQQE2AgAgAEEcakEANgIAIABB3LXAADYCECAAQcyRwAA2AhggAEEANgIIIAEgAEEIahCEAgwFCyAAQRRqQQE2AgAgAEEcakEANgIAIABB3KvAADYCECAAQcyRwAA2AhggAEEANgIIIAEgAEEIahCEAgwECyAAQRRqQQE2AgAgAEEcakEANgIAIABBwKvAADYCECAAQcyRwAA2AhggAEEANgIIIAEgAEEIahCEAgwDCyAAQRRqQQE2AgAgAEEcakEANgIAIABBxLXAADYCECAAQcyRwAA2AhggAEEANgIIIAEgAEEIahCEAgwCCyAAQRRqQQE2AgAgAEEcakEANgIAIABBoKvAADYCECAAQcyRwAA2AhggAEEANgIIIAEgAEEIahCEAgwBCyAAQRRqQQE2AgAgAEEcakEBNgIAIABB4KrAADYCECAAQQA2AgggAEEoNgIkIAAgAkEEajYCLCAAIABBIGo2AhggACAAQSxqNgIgIAEgAEEIahCEAgsgAEEwaiQAC70CAQF/IAAoAgAhAiMAQTBrIgAkAAJ/AkACQAJAAkAgAigCAEEBaw4DAQIDAAsgAEEUakEBNgIAIABBHGpBADYCACAAQdyrwAA2AhAgAEHMkcAANgIYIABBADYCCCABIABBCGoQhAIMAwsgAEEUakEBNgIAIABBHGpBADYCACAAQcCrwAA2AhAgAEHMkcAANgIYIABBADYCCCABIABBCGoQhAIMAgsgAEEUakEBNgIAIABBHGpBADYCACAAQaCrwAA2AhAgAEHMkcAANgIYIABBADYCCCABIABBCGoQhAIMAQsgAEEUakEBNgIAIABBHGpBATYCACAAQeCqwAA2AhAgAEEANgIIIABBKDYCJCAAIAJBBGo2AiwgACAAQSBqNgIYIAAgAEEsajYCICABIABBCGoQhAILIABBMGokAAtsAQF/IwBBMGsiAiQAIAAoAgAhACACQRRqQQI2AgAgAkEcakEBNgIAIAJB3LPAADYCECACQQA2AgggAkEpNgIkIAIgADYCLCACIAJBIGo2AhggAiACQSxqNgIgIAEgAkEIahCEAiACQTBqJAALDAAgACgCACABEOoBC2gBAX8jAEEwayICJAAgAiAAKAIANgIMIAJBHGpBATYCACACQSRqQQE2AgAgAkHEk8AANgIYIAJBADYCECACQSo2AiwgAiACQShqNgIgIAIgAkEMajYCKCABIAJBEGoQhAIgAkEwaiQAC6UBAQF/IwBBQGoiAiQAIAAoAgAhACACQQxqQQM2AgAgAkEUakEDNgIAIAJBLGpBKTYCACACQSRqQSk2AgAgAiAAQRhqNgI0IAIgADYCOCACQciywAA2AgggAkEANgIAIAJBKzYCHCACIABBDGo2AjwgAiACQRhqNgIQIAIgAkE8ajYCKCACIAJBOGo2AiAgAiACQTRqNgIYIAEgAhCEAiACQUBrJAALDAAgACgCACABEJACC1cBAX8jAEEgayICJAAgAiAANgIEIAJBGGogAUEQaikCADcDACACQRBqIAFBCGopAgA3AwAgAiABKQIANwMIIAJBBGpB/JTAACACQQhqEOwBIAJBIGokAAsIACABIAEQYQuwBAEEfyMAQUBqIgAkACAAQQA2AgggAEKAgICAEDcDACAAQRBqIgQgAEGIksAAEP8BIwBBQGoiAiQAQQEhAwJAIAQoAgAiBUHE4cAAQQwgBCgCBCIEKAIMEQIADQACQCABKAIIIgMEQCACIAM2AgwgAkHwADYCFCACIAJBDGo2AhBBASEDIAJBATYCPCACQQI2AjQgAkHU4cAANgIwIAJBADYCKCACIAJBEGo2AjggBSAEIAJBKGoQ7AFFDQEMAgsgASgCACIDIAEoAgRBDGooAgARCQBCyLXgz8qG29OJf1INACACIAM2AgwgAkHxADYCFCACIAJBDGo2AhBBASEDIAJBATYCPCACQQI2AjQgAkHU4cAANgIwIAJBADYCKCACIAJBEGo2AjggBSAEIAJBKGoQ7AENAQsgASgCDCEBIAJBJGpB0gA2AgAgAkEcakHSADYCACACIAFBDGo2AiAgAiABQQhqNgIYIAJB8gA2AhQgAiABNgIQIAJBAzYCPCACQQM2AjQgAkGs4cAANgIwIAJBADYCKCACIAJBEGo2AjggBSAEIAJBKGoQ7AEhAwsgAkFAayQAAkAgA0UEQCAAKAIIIQIgACgCBCEDQQxBBBBKIgFFDQEgASACNgIIIAEgAjYCBCABIAM2AgAgARAAIAEQtwEgACgCAARAIAAoAgQQtwELIABBQGskAA8LQaCSwABBNyAAQThqQdiSwABBtJPAABD2AQALQQxBBBDcAQALFQAgACgCCARAIABBDGooAgAQtwELC3YBBX8jAEEgayIDJAACfyACBEADQCADQQhqIAEQZEEBIAMoAgwiBUUNAhogAygCGCEGIAMoAhQgAygCCARAIAUQtwELIARBAWohBARAIAYQtwELIAIgBEcNAAsLQQALIQEgACAENgIEIAAgATYCACADQSBqJAALqwMCCH8BfiMAQUBqIgIkAAJAIAEoAgAQBSIBBEAgASgCACIFRQ0BIAEoAgQhAyABKAIIIQQgARC3ASACIAQ2AjggAiAFNgI0IAIgAzYCMCACQRhqIgMgAkEwaiIEEHkgAkEQaiACQSBqKAIAIgY2AgAgAiACKQMYIgo3AwggAkEoaiIHKAIAIQEgAkEsaiIIKAIAIQkgAigCJCEFIAJBOGogBjYCACACIAo3AzAgAyAEEHkgCCgCACEDIAcoAgAhBCACKAIkIQYgAigCGARAIAIoAhwQtwELAkAgA0UEQCAAQQA2AgQgBQRAIAEQtwELIAZFDQEgBBC3AQwBCyAAIAk2AhQgACABNgIQIAAgBTYCDCAAIAM2AgggACAENgIEIAAgBjYCAAsgAkFAayQADwsgAkEkakEBNgIAIAJBLGpBADYCACACQaSpwAA2AiAgAkHMkcAANgIoIAJBADYCGCACQRhqQYiqwAAQ4gEACyACQSRqQQE2AgAgAkEsakEANgIAIAJBuKrAADYCICACQcyRwAA2AiggAkEANgIYIAJBGGpBwKrAABDiAQALewEFfyMAQSBrIgMkAAJAIAJFDQADQCADQQhqIAEQZCADKAIMIgRFBEBBASEFDAILIAMoAhghBiADKAIUIAMoAggEQCAEELcBCwRAIAYQtwELIAJBAWsiAg0ACwsCQCAFRQRAIAAgARBkDAELIABBADYCBAsgA0EgaiQACwkAIABCADcCAAsNACAAKAIAIAEQaEEAC8oCAQJ/IwBBEGsiAiQAAkACfwJAIAFBgAFPBEAgAkEANgIMIAFBgBBPDQEgAiABQT9xQYABcjoADSACIAFBBnZBwAFyOgAMQQIMAgsgACgCCCIDIAAoAgBGBEAgACADEBAgACgCCCEDCyAAIANBAWo2AgggACgCBCADaiABOgAADAILIAFBgIAETwRAIAIgAUE/cUGAAXI6AA8gAiABQQZ2QT9xQYABcjoADiACIAFBDHZBP3FBgAFyOgANIAIgAUESdkEHcUHwAXI6AAxBBAwBCyACIAFBP3FBgAFyOgAOIAIgAUEMdkHgAXI6AAwgAiABQQZ2QT9xQYABcjoADUEDCyEBIAEgACgCACAAKAIIIgNrSwRAIAAgAyABEBEgACgCCCEDCyAAKAIEIANqIAJBDGogARCXAhogACABIANqNgIICyACQRBqJAALWgEBfyMAQSBrIgIkACACIAAoAgA2AgQgAkEYaiABQRBqKQIANwMAIAJBEGogAUEIaikCADcDACACIAEpAgA3AwggAkEEakH8lMAAIAJBCGoQ7AEgAkEgaiQACwoAIAAgARBoQQAL0wEBAX8jAEHwAGsiAyQAIAMgAjYCDCADIAE2AgggA0EcakECNgIAIANBJGpBATYCACADQdCWwAA2AhggA0EANgIQIANBLDYCLCADIANBKGo2AiAgAyADQQhqNgIoIANBADYCOCADQoCAgIAQNwMwIANBQGsiASADQTBqQYiSwAAQ/wEgA0EQaiABEPUBBEBBoJLAAEE3IANB6ABqQdiSwABBtJPAABD2AQALIAAgAykDMDcCBCAAQRQ2AgAgAEEMaiADQThqKAIANgIAIANB8ABqJAAL0wEBAX8jAEHwAGsiAyQAIAMgAjYCDCADIAE2AgggA0EcakECNgIAIANBJGpBATYCACADQfSWwAA2AhggA0EANgIQIANBLDYCLCADIANBKGo2AiAgAyADQQhqNgIoIANBADYCOCADQoCAgIAQNwMwIANBQGsiASADQTBqQYiSwAAQ/wEgA0EQaiABEPUBBEBBoJLAAEE3IANB6ABqQdiSwABBtJPAABD2AQALIAAgAykDMDcCBCAAQRQ2AgAgAEEMaiADQThqKAIANgIAIANB8ABqJAAL9wEBAX8jAEGAAWsiBSQAIAUgAjYCDCAFIAE2AgggBUEcakECNgIAIAVBJGpBAjYCACAFQTRqQQM2AgAgBUGkl8AANgIYIAVBADYCECAFQSw2AiwgBSAENgI8IAUgAzYCOCAFIAVBKGo2AiAgBSAFQThqNgIwIAUgBUEIajYCKCAFQQA2AkggBUKAgICAEDcDQCAFQdAAaiIBIAVBQGtBiJLAABD/ASAFQRBqIAEQ9QEEQEGgksAAQTcgBUH4AGpB2JLAAEG0k8AAEPYBAAsgACAFKQNANwIEIABBFDYCACAAQQxqIAVByABqKAIANgIAIAVBgAFqJAAL+AICBH8BfiMAQSBrIgIkACACQQhqIAEQmAECQAJAAkACQAJAAkAgAigCCCIDQRVGBEAgAiABEJoBIAItAAEhAyACLQAAQQFxRQ0BIANBIkcNAiABEJQBIAJBCGogARCZASACKAIIDQMgAkEUaigCACEBIAJBEGooAgAhAyACKAIMRQRAAkAgAUUEQEEBIQQMAQsgAUEATiIFRQ0GIAEgBRBKIgRFDQcLIAQgAyABEJcCIQMgAEEMaiABNgIAIABBCGogAzYCACAAIAE2AgQgAEEVNgIADAcLIAJBGGooAgAhBCAAIAM2AgQgAEEVNgIAIABBDGogBDYCACAAQQhqIAE2AgAMBgsgACACKQIMNwIEIABBDGogAkEUaigCADYCACAAIAM2AgAMBQsgACADOgAEIABBBDYCAAwECyAAQQ42AgAMAwsgAikCDCEGIAAgAkEUaikCADcCCCAAIAY3AgAMAgsQ3QEACyABIAUQ3AEACyACQSBqJAALsw4CCX8BfiMAQaABayICJAAgAkHgAGogARCaASACLQBhIQMCQCAAAn8CQAJAAkACQAJAAkACQAJAAkACQAJAAkACQCACLQBgQQFxBEACQAJAIANB2wBrDiMEAQ0BAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQUBDQALIANBImsOCwIAAAAAAAAAAAAMAAsgAkEQaiABEJsBIAItABBBAXEEQCACLQARIQUDQCAFQf8BcSIDQSxGIANB3QBGciADQf0ARnINDCABEJQBIAJBCGogARCbASACLQAJIQUgAi0ACEEBcQ0ACwsgAEEDNgIADA8LIAAgAzoABCAAQQQ2AgAMDgsgAkEYaiABEJoBIAItABkhAyACLQAYQQFxRQ0HIANBIkcNBiABEJQBIAJBiAFqIAEQmQEgAigCiAENBSACKAKMAUUEQCAAQRU2AgAMDgsgAkGUAWooAgAgAkGQAWooAgAgAEEVNgIARQ0NELcBDA0LIAJBKGogARCaASACLQApIQMgAi0AKEEBcUUNAyADQdsARw0CIAEQlAEgAkEgaiABEJIBIAJBiAFqIQYgAigCICEFIAItACRBAXEhCSMAQTBrIgQkACAEQRhqIAUQmgFBASEDIAQtABkhCAJAAkAgBC0AGEEBcUUNAANAAkACQAJAAkAgCEEsRwRAIAhB3QBGDQQgCUH/AXEEQEEAIQkMAgtBByEDDAYLIAUQlAEgBEEQaiAFEJoBIAQtABEhCCAELQAQQQFxRQ0BCyAIQd0ARgRAQRMhAwwFCyAEQSBqIAUQbyAEKAIgIgdBFUYNASAELwAlIAQtACdBEHRyIQUgBCgCLCEKIAQoAighCSAELQAkIQggByEDDAQLQQQhAwwDCyAEQQhqIAUQmgEgBC0ACSEIIAQtAAhBAXENAQwCCwsgBkEVNgIADAELIAYgBTsABSAGIAo2AAwgBiAJNgAIIAYgCDoABCAGIAM2AgAgBkEHaiAFQRB2OgAACyAEQTBqJAAgAigCiAEiA0EVRw0BIAJBiAFqIAEQlgEgAigCiAEiAUEVRgRAIABBFTYCAAwNCyACQfAAaiACQZQBaigCACIDNgIAIAIgAikCjAEiCzcDaCAAQQxqIAM2AgAgACALNwIEIAAgATYCAAwMCyACQdgAaiABEJoBIAItAFkhAyACLQBYQQFxBEAgA0H7AEcNCSABEJQBIAJB0ABqIAEQkgEgAi0AVCEDIAJByABqIAIoAlAiBRCaASACLQBJIQQCQCACLQBIQQFxBEAgA0EBcSEHIAJB6ABqQQRyIQggAkGIAWpBBHIhCQNAAn8CQAJAAkAgBEH/AXEiBkEsRwRAIAZB/QBHBEAgBw0CQQkhBAwTCyADQYB+cQwECyAHBEBBECEEDBILIAUQlAEgAkFAayAFEJoBIAItAEEhBCACLQBAQQFxRQ0BCyAEQf8BcSIGQSJGDQFBE0EQIAZB/QBGGyEEDBALIANBgH5xIARB/wFxciEDQQQhBAwPCyACQThqIAUQmgEgAi0AOSEHAkAgAi0AOEEBcQRAIAdBIkYNAUEOIQQMEAsgByEDQQQhBAwPCyAFEJQBIAJBiAFqIAUQmQEgAigClAEhBiACKAKQASEHIAIoAowBIQQCQCACKAKIAUUEQCAERSAHRXINASAGELcBDAELIARBFUYNACACKAKYASEFIAchAwwPC0EAIQcgA0GAfnFBAXILIgNB/wFxRQRAIAJBiAFqIAEQlwEgAigCiAEiAUEVRw0DIABBFTYCAAwQCyACQYgBaiAFEJgBAkACQCACKAKIASIEQRVHBEAgAkGAAWogCUEIaigCACIBNgIAIAIgCSkCACILNwN4IAhBCGogATYCACAIIAs3AgAMAQsgAkHoAGogBRBvIAIoAmgiBEEVRg0BCyACKAJ0IQUgAigCcCEGIAItAGwhAyACLwBtIAItAG9BEHRyDA8LIAJBMGogBRCaASACLQAxIQQgAi0AMEEBcQ0ACwsgA0GAfnEgBEH/AXFyIQNBAiEEDAsLIAJB8ABqIAJBlAFqKAIAIgM2AgAgAiACKQKMASILNwNoIABBDGogAzYCACAAIAs3AgQgACABNgIADAwLIAAgAzoABCAAQQQ2AgAMCwsgAkHwAGogAkGUAWooAgAiATYCACACIAIpAowBIgs3A2ggAEEMaiABNgIAIAAgCzcCBCAAIAM2AgAMCgsgAEEONgIADAkLIAAgAzoABCAAQQQ2AgAMCAsgAikCjAEhCyAAIAJBlAFqKQIANwIIIAAgCzcCAAwHCyAAQQ42AgAMBgsgACADOgAEIABBBDYCAAwFCyAAQRU2AgAMBAsgAEELNgIADAMLIABBDjYCAAwCCyADQQh2CyIBOwAFIAAgBTYADCAAIAY2AAggACADOgAEIAAgBDYCACAAQQdqIAFBEHY6AAALIAJBoAFqJAALygECAn8BfiMAQSBrIgIkACACIAEQmgEgAi0AASEDAkACQAJAIAItAABBAXEEQCADQSJHDQEgARCUASACQQhqIAEQmQEgAigCCA0CIAJBFGooAgAhASACQRBqKAIAIQMgAigCDEUEQCAAIAMgARBxDAQLIAAgASACQRhqKAIAEHEgA0UNAyABELcBDAMLIAAgAzoABCAAQQQ2AgAMAgsgAEEONgIADAELIAIpAgwhBCAAIAJBFGopAgA3AgggACAENwIACyACQSBqJAALsysCEH8IfiMAQeAAayILJAAgCyACNgIMIAsgATYCCCALQRBqIRAgASEMQQAhASMAQfAAayIJJAACQAJAAkACQAJAAkACQAJAAkACQCACIAIiB0EDaiIGTQRAIAZBAnZBA2whBEEBIQ4gBkEETwRAIARBAE4iAkUNAiAEIAIQSiIORQ0DCyAJQQA2AkggCSAONgJEIAkgBDYCQCAHIAdBB2oiAksEQEHAxsAAQTNByMfAABDwAQALIAJBA3YiCK1CBn4iE0IgiKcNAyATpyIGBEBBACECIAQgBkkEQCAJQUBrQQAgBhARIAkoAkQhDiAJKAJIIQILIAIgDmohBCAGQQJPBH8gBEEAIAZBAWsiBBCaAiAOIAIgBGoiAmoFIAQLQQA6AAAgAkEBaiENCyAJIA02AkhBACEGQfDWwAAoAgAhBQJAAkACQAJAAkACQAJAAkAgB0EHcSIDDgYAAQIDBAEFC0EIIQMMBAtBASEPIAcNBAwMC0EKIQMMAgtBCyEDDAELQQwhAwtBACAHIANrIgEgASAHSxsiCkEgTw0BQQAhBAwHCyAMIAdBAWsiAWotAAAiA0E9Rg0HIAMgBWotAABB/wFHDQdBACEPDAcLIApBIGshEkEAIQECQANAAkAgASABQSBqIgRNBEAgBCAHTQ0BIAQgB0HMmMAAEOUBAAtBoJHAAEEcQbyYwAAQ5wEACyAGQRpqIA1LDQYgBSABIAxqIgItAAAiA2oxAAAiE0L/AVENCCAFIAJBAWotAAAiA2oxAAAiFEL/AVEEQCABQQFqIQEMCQsgBSACQQJqLQAAIgNqMQAAIhVC/wFRBEAgAUECaiEBDAkLIAUgAkEDai0AACIDajEAACIWQv8BUQRAIAFBA2ohAQwJCyAFIAJBBGotAAAiA2oxAAAiF0L/AVEEQCABQQRqIQEMCQsgBSACQQVqLQAAIgNqMQAAIhhC/wFRBEAgAUEFaiEBDAkLIAUgAkEGai0AACIDajEAACIZQv8BUQRAIAFBBmohAQwJCyAFIAJBB2otAAAiA2oxAAAiGkL/AVEEQCABQQdqIQEMCQsgBiAOaiIRIBRCNIYgE0I6hoQgFUIuhoQgFkIohoQgF0IihoQgGEIchoQgGUIWhoQiFCAaQhCGhCITQhiGQoCAgICA4D+DIBRCCIZCgICAgPAfg4QgE0IIiEKAgID4D4MgE0IYiEKAgPwHg4QgE0IoiEKA/gODIBNCOIiEhIQ3AAAgBSACQQhqLQAAIgNqMQAAIhNC/wFRDQEgBSACQQlqLQAAIgNqMQAAIhRC/wFRBEAgAUEJaiEBDAkLIAUgAkEKai0AACIDajEAACIVQv8BUQRAIAFBCmohAQwJCyAFIAJBC2otAAAiA2oxAAAiFkL/AVEEQCABQQtqIQEMCQsgBSACQQxqLQAAIgNqMQAAIhdC/wFRBEAgAUEMaiEBDAkLIAUgAkENai0AACIDajEAACIYQv8BUQRAIAFBDWohAQwJCyAFIAJBDmotAAAiA2oxAAAiGUL/AVEEQCABQQ5qIQEMCQsgBSACQQ9qLQAAIgNqMQAAIhpC/wFRBEAgAUEPaiEBDAkLIBFBBmogFEI0hiATQjqGhCAVQi6GhCAWQiiGhCAXQiKGhCAYQhyGhCAZQhaGhCIUIBpCEIaEIhNCGIZCgICAgIDgP4MgFEIIhkKAgICA8B+DhCATQgiIQoCAgPgPgyATQhiIQoCA/AeDhCATQiiIQoD+A4MgE0I4iISEhDcAAAJAIAUgAkEQai0AACIDajEAACITQv8BUgRAIAUgAkERai0AACIDajEAACIUQv8BUQRAIAFBEWohAQwLCyAFIAJBEmotAAAiA2oxAAAiFUL/AVEEQCABQRJqIQEMCwsgBSACQRNqLQAAIgNqMQAAIhZC/wFRBEAgAUETaiEBDAsLIAUgAkEUai0AACIDajEAACIXQv8BUQRAIAFBFGohAQwLCyAFIAJBFWotAAAiA2oxAAAiGEL/AVEEQCABQRVqIQEMCwsgBSACQRZqLQAAIgNqMQAAIhlC/wFRBEAgAUEWaiEBDAsLIAUgAkEXai0AACIDajEAACIaQv8BUg0BIAFBF2ohAQwKCyABQRBqIQEMCQsgEUEMaiAUQjSGIBNCOoaEIBVCLoaEIBZCKIaEIBdCIoaEIBhCHIaEIBlCFoaEIhQgGkIQhoQiE0IYhkKAgICAgOA/gyAUQgiGQoCAgIDwH4OEIBNCCIhCgICA+A+DIBNCGIhCgID8B4OEIBNCKIhCgP4DgyATQjiIhISENwAAAkAgBSACQRhqLQAAIgNqMQAAIhNC/wFSBEAgBSACQRlqLQAAIgNqMQAAIhRC/wFRBEAgAUEZaiEBDAsLIAUgAkEaai0AACIDajEAACIVQv8BUQRAIAFBGmohAQwLCyAFIAJBG2otAAAiA2oxAAAiFkL/AVEEQCABQRtqIQEMCwsgBSACQRxqLQAAIgNqMQAAIhdC/wFRBEAgAUEcaiEBDAsLIAUgAkEdai0AACIDajEAACIYQv8BUQRAIAFBHWohAQwLCyAFIAJBHmotAAAiA2oxAAAiGUL/AVEEQCABQR5qIQEMCwsgBSACQR9qLQAAIgNqMQAAIhpC/wFSDQEgAUEfaiEBDAoLIAFBGGohAQwJCyARQRJqIBRCNIYgE0I6hoQgFUIuhoQgFkIohoQgF0IihoQgGEIchoQgGUIWhoQiFCAaQhCGhCITQhiGQoCAgICA4D+DIBRCCIZCgICAgPAfg4QgE0IIiEKAgID4D4MgE0IYiEKAgPwHg4QgE0IoiEKA/gODIBNCOIiEhIQ3AAAgCEEETwRAIAhBBGshCCAGQRhqIQYgEiAEIgFJDQgMAQsLQdCRwABBIUHsmMAAEOcBAAsgAUEIaiEBDAYLQbSXwABBI0GsmMAAEPABAAsQ3QEACyAEIAIQ3AEAC0GInMAAQS5BuJzAABDwAQALIAZBGmogDUHcmMAAEOUBAAsCQAJAIApBCEkNACAEIApBCGsiEU8NAAJAAkACQAJAA0AgBEEIaiICIARJDQIgAiAHSw0BIAZBBmoiASAGSQ0DAkAgASABQQJqIgNNBEAgAyAGSQ0GIAMgDU0NASADIA1BvJnAABDlAQALQaCRwABBHEGsmcAAEOcBAAsgBSAEIAxqIgotAAAiA2oxAAAiE0L/AVEEQCAEIQEMCAsgBSAKQQFqLQAAIgNqMQAAIhRC/wFRBEAgBEEBaiEBDAgLIAUgCkECai0AACIDajEAACIVQv8BUQRAIARBAmohAQwICyAFIApBA2otAAAiA2oxAAAiFkL/AVEEQCAEQQNqIQEMCAsgBSAKQQRqLQAAIgNqMQAAIhdC/wFRBEAgBEEEaiEBDAgLIAUgCkEFai0AACIDajEAACIYQv8BUQRAIARBBWohAQwICyAFIApBBmotAAAiA2oxAAAiGUL/AVEEQCAEQQZqIQEMCAsgBSAKQQdqLQAAIgNqMQAAIhpC/wFRBEAgBEEHaiEBDAgLIAYgDmogFEI0hiATQjqGhCAVQi6GhCAWQiiGhCAXQiKGhCAYQhyGhCAZQhaGhCIUIBpCEIaEIhNCGIZCgICAgIDgP4MgFEIIhkKAgICA8B+DhCATQgiIQoCAgPgPgyATQhiIQoCA/AeDhCATQiiIQoD+A4MgE0I4iISEhDcAACAIBEAgCEEBayEIIAEhBiACIQQgAiARTw0HDAELC0HQkcAAQSFBzJnAABDnAQALIAIgB0GMmcAAEOUBAAtBoJHAAEEcQfyYwAAQ5wEAC0GgkcAAQRxBnJnAABDnAQALIAYgA0G8mcAAEOgBAAsgBiEBIAQhAgsgCEEBIAhBAUsbIQhBACACayEKAkACfwJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkADQCAIQQFrIghFBEAgAiAHSw0RIAIgB0cNEEEAIQNCACETQQAhCEEAIQdBACEGQQAhBEEAIQpBACEMQgAhFAwaCyACIAdLDREgAUEGaiIEIAFJDQ0gBCANSw0SIAIgB0YNEyAFIAIgDGoiBC0AACIDajEAACITQv8BUQRAIAIhAQwbCyAHIApqIgZBAkkNFCAFIARBAWotAAAiA2oxAAAiFEL/AVENASAGQQJNDQIgBSAEQQJqLQAAIgNqMQAAIhVC/wFRDQMgBkEDTQ0EIAUgBEEDai0AACIDajEAACIWQv8BUQ0FIAZBBE0NBiAFIARBBGotAAAiA2oxAAAiF0L/AVENByAGQQVNDQggBSAEQQVqLQAAIgNqMQAAIhhC/wFRDQkgBkEGTQ0KIAUgBEEGai0AACIDajEAACIZQv8BUQ0LIAZBB00NDCAFIARBB2otAAAiA2oxAAAiGkL/AVIEQCAKQQhrIQogASAOaiIEQQRqIBRCNIYgE0I6hoQgFUIuhoQgFkIohoQgF0IihoQgGEIchoQgGUIWhoQiFCAaQhCGhCITQhiGQoCAgICA4D+DIBRCCIZCgICAgPAfg4RCIIg9AAAgBCATQgiIQoCAgPgPgyATQhiIQoCA/AeDhCATQiiIQoD+A4MgE0I4iISEPgAAIAFBBmohASACIAJBCGoiAksNDwwBCwsgAkEHaiIBIAJPDRkMHAsgAkEBaiIBDRgMGwtBAkECQcicwAAQ4wEACyACQQJqIgEgAk8NFgwZC0EDQQNByJzAABDjAQALIAJBA2oiASACTw0UDBcLQQRBBEHInMAAEOMBAAsgAkEEaiIBIAJPDRIMFQtBBUEFQcicwAAQ4wEACyACQQVqIgEgAk8NEAwTC0EGQQZByJzAABDjAQALIAJBBmoiASACTw0ODBELQQdBB0HInMAAEOMBAAtBoJHAAEEcQeyZwAAQ5wEAC0GgkcAAQRxBjJrAABDnAQALIAcgDGohESACIAxqIQRCACETQQAhDEEAIQpBACEGQQAhBwNAIAdBAWoiCEUNBgJAAkACQCAELQAAIgNBPUcEQCAGQQBMDQIgAiAKaiIBIAJJDQFBACEPQT0hAwwPCwJAIAdBAnEEQCAGQQFqIgMgBkgNASAKIAcgBhshCiAIIQcgAyEGIARBAWoiBCARRw0FIAwhAwwEC0EAIQ8gAiACIAogByAGQQBKG2oiAU0EQEE9IQMMEAtBoJHAAEEcQayawAAQ5wEAC0GgkcAAQRxBvJrAABDnAQALQaCRwABBHEHMmsAAEOcBAAsgD0EKRg0IIAMgBWoxAAAiFEL/AVEEQCACIAIgB2oiAU0EQEEAIQ8MDgtBoJHAAEEcQeyawAAQ5wEACyAUIA9BAWoiD0E6bEE+ca2GIBOEIRMgAyEMIAghByAEQQFqIgQgEUcNAQsLQgAhFEEAIQxBACEIQQAhB0EAIQZBACEEQQAhCgJAAkACQAJAAkACQAJAIA8OCRAAAQIDAAQFBgALIwBBIGsiACQAIABBDGpBATYCACAAQRRqQQE2AgAgAEHQlcAANgIIIABBADYCACAAQSw2AhwgAEHQm8AANgIYIAAgAEEYajYCECAAQdibwAAQ4gEAC0IIIRRBASEIDAwLQhAhFEEBIQhBASEHDAsLQhghFEEBIQhBASEHQQEMCwtCICEUQQEhCEEBIQdBASEGQQEhBAwLC0IoIRRBASEIQQEhB0EBIQZBASEEQQEhCgwKC0IwIRRBASEIQQEhB0EBIQZBASEEQQEhCkEBIQwMCQsgAiAHQZyawAAQ5AEACyACIAdB3JnAABDkAQALIAQgDUH8mcAAEOUBAAtBAEEAQcicwAAQ4wEAC0EBQQFByJzAABDjAQALQaCRwABBHEG8kcAAEOcBAAtB0JHAAEEhQdyawAAQ5wEAC0EACyEGCwJAAkACQAJAIBMgFIZQBEAgCEUNAiABIA1JDQEgASECDAQLIAIgD2oiASACSQ0CIAEEQCABQQFrIQFBAiEPDAULQdCRwABBIUHom8AAEOcBAAsgASAOaiIIIBNCOIg8AAAgAUEBaiEDIAdFBEAgAyEBDAELIAMgASANIAEgDUsbIgJGDQIgCEEBaiATQjCIPAAAIAFBAmohAyAGRQRAIAMhAQwBCyACIANGDQIgCEECaiATQiiIPAAAIAFBA2ohBiAERQRAIAYhAQwBCyACIAZGDQIgCEEDaiATQiCIPAAAIAFBBGohBCAKRQRAIAQhAQwBCyACIARGDQIgCEEEaiATQhiIPAAAIAFBBWohBCAMRQRAIAQhAQwBCyACIARGDQIgCEEFaiATQhCIPAAAIAFBBmohAQsgCSgCQCECIBBBDGogCSgCSCABIAEgDUsbNgIAIBBBCGogDjYCACAQIAI2AgQgEEENNgIADAMLQaCRwABBHEHom8AAEOcBAAsgAiANQfibwAAQ4wEACyAJKAJABEAgDhC3AQsgCSABNgIsIAkgA0H/AXFBCHQgD3I2AiggCUEANgI4IAlCgICAgBA3AzAgCUFAayIEIAlBMGpBiJLAABD/ASMAQTBrIgEkAAJ/AkACQAJAIAlBKGoiAi0AAEEBaw4CAQIACyABIAIoAgQ2AgAgASACLQABOgAHIAFBFGpBAzYCACABQRxqQQI2AgAgAUEsakHSADYCACABQajGwAA2AhAgAUEANgIIIAFB0wA2AiQgASABQSBqNgIYIAEgATYCKCABIAFBB2o2AiAgBCABQQhqEIQCDAILIAFBFGpBATYCACABQRxqQQA2AgAgAUGQxsAANgIQIAFB8MDAADYCGCABQQA2AgggBCABQQhqEIQCDAELIAEgAigCBDYCACABIAItAAE6AAcgAUEUakEDNgIAIAFBHGpBAjYCACABQSxqQdIANgIAIAFBzMXAADYCECABQQA2AgggAUHTADYCJCABIAFBIGo2AhggASABNgIoIAEgAUEHajYCICAEIAFBCGoQhAILIAFBMGokAA0BIAlBEGogCUEgaikDACITNwMAIAkgCSkDGCIUNwMIIAkpAzAhFSAJKAI4IQEgEEEYaiATNwMAIBAgFDcDECAQIAE2AgwgECAVNwIEIBBBAzYCAAsgCUHwAGokAAwCC0GgksAAQTcgCUHoAGpB2JLAAEG0k8AAEPYBAAtBoJHAAEEcQcicwAAQ5wEACwJAIAsoAhBBDUYEQCAAIAspAhQ3AgQgAEEVNgIAIABBDGogC0EcaigCADYCAAwBCyALQSw2AkQgCyALQQhqNgJAIAtBATYCXCALQQE2AlQgC0G8nsAANgJQIAtBADYCSCALIAtBQGs2AlggC0EwaiIBIAtByABqIgIQ3gEgAkEEciABEN8BIAtBFDYCSCALKAIwBEAgCygCNBC3AQsgACALKQNINwIAIABBCGogC0HQAGopAwA3AgAgC0EQahA1CyALQeAAaiQAC4UDAgN/AX4jAEEgayICJAAgAiABEJoBIAItAAEhAwJAAkACQAJAAkACQAJAAkAgAi0AAEEBcQRAIANBIkcNASABEJQBIAJBCGogARCZASACKAIIDQIgAkEUaigCACEBIAJBEGooAgAhAyACKAIMRQRAAkACQCABQQJrDgQACQkBCQsgAy8AAEHv1gFGDQkMCAsgA0GXtcAAQQUQmQINByAAQRU2AgAgAEEBOgAEDAkLAkACQCACQRhqKAIAIgRBAmsOBAAFBQEFCyABLwAAQe/WAUYNBQwECyABQZe1wABBBRCZAg0DIABBFTYCACAAQQE6AAQMBQsgACADOgAEIABBBDYCAAwHCyAAQQ42AgAMBgsgAikCDCEFIAAgAkEUaikCADcCCCAAIAU3AgAMBQsgACABIARBmLbAAEECEG0MAQsgAEEVNgIAIABBADoABAsgA0UNAiAB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IABBATYCACABQTBqEDUMAQsgACABKQMQNwMAIABBGGogAUEoaikDADcDACAAQRBqIAFBIGopAwA3AwAgAEEIaiABQRhqKQMANwMAIBdFDQAgFhC3AQsgFBC3ASABQZABaiQADwtBDEEEENwBAAsgAUEUakEBNgIAIAFBHGpBADYCACABQaSpwAA2AhAgAUHMkcAANgIYIAFBADYCCCABQQhqQYiqwAAQ4gEACyABQRRqQQE2AgAgAUEcakEANgIAIAFBuKrAADYCECABQcyRwAA2AhggAUEANgIIIAFBCGpBwKrAABDiAQALQaCSwABBNyABQYgBakHYksAAQbSTwAAQ9gEAC8wJAQF/IwBBMGsiAiQAAn8CQAJAAkACQAJAAkACQAJAAkACQAJAAkACQCAAKAIAQQFrDgwBAgMEBQYHCAkKCwwACyACQSRqQQE2AgAgAkEsakEBNgIAIAJB6K/AADYCICACQQA2AhggAkEuNgIEIAIgAEEEajYCFCACIAI2AiggAiACQRRqNgIAIAEgAkEYahCEAgwMCyACQSRqQQE2AgAgAkEsakEBNgIAIAJBzK/AADYCICACQQA2AhggAkEvNgIEIAIgAEEEajYCFCACIAI2AiggAiACQRRqNgIAIAEgAkEYahCEAgwLCyACQSRqQQE2AgAgAkEsakEBNgIAIAJBrK/AADYCICACQQA2AhggAkEpNgIEIAIgAEEEajYCFCACIAI2AiggAiACQRRqNgIAIAEgAkEYahCEAgwKCyACQSRqQQE2AgAgAkEsakEBNgIAIAJBlK/AADYCICACQQA2AhggAkEpNgIEIAIgAEEEajYCFCACIAI2AiggAiACQRRqNgIAIAEgAkEYahCEAgwJCyACQQxqQTA2AgAgAkEkakECNgIAIAJBLGpBAjYCACACIABBCGo2AhAgAkHsrsAANgIgIAJBADYCGCACQTA2AgQgAiAAQRBqNgIUIAIgAjYCKCACIAJBFGo2AgggAiACQRBqNgIAIAEgAkEYahCEAgwICyACQSRqQQE2AgAgAkEsakEBNgIAIAJBwK7AADYCICACQQA2AhggAkEpNgIEIAIgAEEEajYCFCACIAI2AiggAiACQRRqNgIAIAEgAkEYahCEAgwHCyACQSRqQQE2AgAgAkEsakEBNgIAIAJBpK7AADYCICACQQA2AhggAkEpNgIEIAIgAEEEajYCFCACIAI2AiggAiACQRRqNgIAIAEgAkEYahCEAgwGCyACQSRqQQI2AgAgAkEsakEBNgIAIAJB7K3AADYCICACQQA2AhggAkEpNgIEIAIgAEEEajYCFCACIAI2AiggAiACQRRqNgIAIAEgAkEYahCEAgwFCyACQQxqQSk2AgAgAkEkakECNgIAIAJBLGpBAjYCACACIABBBGo2AhAgAkHQrcAANgIgIAJBADYCGCACQSk2AgQgAiAAQRBqNgIUIAIgAjYCKCACIAJBFGo2AgggAiACQRBqNgIAIAEgAkEYahCEAgwECyACQQxqQSk2AgAgAkEkakECNgIAIAJBLGpBAjYCACACIABBBGo2AhAgAkGorcAANgIgIAJBADYCGCACQSk2AgQgAiAAQRBqNgIUIAIgAjYCKCACIAJBFGo2AgggAiACQRBqNgIAIAEgAkEYahCEAgwDCyACQSRqQQE2AgAgAkEsakEBNgIAIAJBhK3AADYCICACQQA2AhggAkExNgIEIAIgAEEEajYCFCACIAI2AiggAiACQRRqNgIAIAEgAkEYahCEAgwCCyACQSRqQQE2AgAgAkEsakEBNgIAIAJB8KzAADYCICACQQA2AhggAkEyNgIEIAIgAEEEajYCFCACIAI2AiggAiACQRRqNgIAIAEgAkEYahCEAgwBCyACQSRqQQE2AgAgAkEsakEANgIAIAJB2KzAADYCICACQcyRwAA2AiggAkEANgIYIAEgAkEYahCEAgsgAkEwaiQAC0MBAn8gAEEIaigCACEBIABBBGooAgAhAkEMQQQQSiIARQRAQQxBBBDcAQALIAAgATYCCCAAIAE2AgQgACACNgIAIAALvwEBAn8jAEEgayICJAACQCABBEAgASgCACIDDQEgAkEUakEBNgIAIAJBHGpBADYCACACQbiqwAA2AhAgAkHMkcAANgIYIAJBADYCCCACQQhqQcCqwAAQ4gEACyACQRRqQQE2AgAgAkEcakEANgIAIAJBpKnAADYCECACQcyRwAA2AhggAkEANgIIIAJBCGpBiKrAABDiAQALIAAgAzYCBCAAIAEoAgg2AgggACABKAIENgIAIAEQtwEgAkEgaiQAC7kFAQF/IwBBEGsiAiQAAn8CQAJAAkACQAJAAkACQAJAAkACQAJAAkACQCAAKAIAQQFrDgwBAgMEBQYHCAkKCwwACyACIABBBGo2AgwgAUGEssAAQQ9BgrDAAEEGIAJBDGpBlLLAABCHAgwMCyACIABBBGo2AgwgAUHhscAAQRBBgrDAAEEGIAJBDGpB9LHAABCHAgwLCyACIABBBGo2AgwgAUHXscAAQQpB47DAAEEDIAJBDGpBlJXAABCHAgwKCyACIABBBGo2AgwgAUHKscAAQQ1B47DAAEEDIAJBDGpBlJXAABCHAgwJCyACIABBCGo2AgggAiAAQRBqNgIMIAFBmrHAAEEPQamxwABBCCACQQhqQbSxwABBxLHAAEEGIAJBDGpBtLHAABCIAgwICyACIABBBGo2AgwgAUGQscAAQQpB47DAAEEDIAJBDGpBlJXAABCHAgwHCyACIABBBGo2AgwgAUGFscAAQQtB47DAAEEDIAJBDGpBlJXAABCHAgwGCyACIABBBGo2AgwgAUH5sMAAQQhBgbHAAEEEIAJBDGpBlJXAABCHAgwFCyACIABBBGo2AgggAiAAQRBqNgIMIAFB5rDAAEEIQe6wwABBCyACQQhqQZSVwABB47DAAEEDIAJBDGpBlJXAABCIAgwECyACIABBBGo2AgggAiAAQRBqNgIMIAFBzLDAAEEMQdiwwABBCyACQQhqQZSVwABB47DAAEEDIAJBDGpBlJXAABCIAgwDCyACIABBBGo2AgwgAUG0sMAAQQhBgrDAAEEGIAJBDGpBvLDAABCHAgwCCyACIABBBGo2AgwgAUGYsMAAQQxBgrDAAEEGIAJBDGpBpLDAABCHAgwBCyACIABBBGo2AgwgAUHwr8AAQRJBgrDAAEEGIAJBDGpBiLDAABCHAgsgAkEQaiQACx8AIAAoAgAoAgAiAEEEaigCACAAQQhqKAIAIAEQjQILzwEBA38jAEEgayICJAACQAJAIAFBAWoiA0UNACAAKAIAIgFBAXQiBCADIAMgBEkbIgNBCCADQQhLGyIDQX9zQR92IQQCQCABBEAgAiAAQQRqKAIANgIQIAIgATYCFCACIAFBf3NBH3Y2AhgMAQsgAkEANgIYCyACIAMgBCACQRBqEEAgAigCBCEBIAIoAgBFBEAgACADNgIAIAAgATYCBAwCCyACQQhqKAIAIgBBgYCAgHhGDQEgAEUNACABIAAQ3AEACxDdAQALIAJBIGokAAvRAQECfyMAQSBrIgMkAAJAAkAgASACaiICIAFJDQAgACgCACIBQQF0IgQgAiACIARJGyICQQggAkEISxsiAkF/c0EfdiEEAkAgAQRAIAMgAEEEaigCADYCECADIAE2AhQgAyABQX9zQR92NgIYDAELIANBADYCGAsgAyACIAQgA0EQahBAIAMoAgQhASADKAIARQRAIAAgAjYCACAAIAE2AgQMAgsgA0EIaigCACIAQYGAgIB4Rg0BIABFDQAgASAAENwBAAsQ3QEACyADQSBqJAAL9wMBAX8jAEEwayICJAACfwJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQCAAKAIAQQFrDhQBAgMEBQYHCAkKCwwNDg8QERITFAALIAJBrrzAADYCKEEiDBQLIAJBlbzAADYCKEEZDBMLIAJB+bvAADYCKEEcDBILIAJB3rvAADYCKEEbDBELIAJBv7vAADYCKEEfDBALIAJBmbvAADYCKEEmDA8LIAJB8brAADYCKEEoDA4LIAJBurrAADYCKEE3DA0LIAJBk7rAADYCKEEnDAwLIAJB27nAADYCKEE4DAsLIAJBo7nAADYCKEE4DAoLIAJB9bjAADYCKEEuDAkLIAJB3bjAADYCKEEYDAgLIAJBzrjAADYCKEEPDAcLIAJBwrjAADYCKEEMDAYLIAJBp7jAADYCKEEbDAULIAJBjLjAADYCKEEbDAQLIAJBvbfAADYCKEHPAAwDCyACQYG3wAA2AihBPAwCCyACQci2wAA2AihBOQwBCyACIABBCGooAgA2AiggAEEMaigCAAshACACQRRqQQE2AgAgAkEcakEBNgIAIAJBzwA2AiQgAiAANgIsIAJBwLbAADYCECACQQA2AgggAiACQShqNgIgIAIgAkEgajYCGCABIAJBCGoQhAIgAkEwaiQACxAAIABBAToABCAAIAE2AgALFwAgAEEANgIIIAAgAjYCBCAAIAE2AgALKQEBfyAAKAIIQQFqIgEEQCAAIAE2AggPC0HQvcAAQRxBuL/AABDnAQALXwEDfyAAAn8gASgCCCIAIAEoAgQiAkkEQCABKAIAIQMDQEESIAAgA2otAABBCWsiBEEXS0EBIAR0QZOAgARxRXINAhogASAAQQFqIgA2AgggACACRw0ACwtBFQs2AgALwgIBBX8CQAJAAkAC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akHcADoAACAEQQFqDAcLIAEoAgAgBEYEQCABIAQQjwEgASgCCCEECyABKAIEIARqQdwAOgAAIAEgBEEBaiIENgIIIAEoAgAgBEYEQCABIAQQjwEgASgCCCEECyABKAIEIARqQSI6AAAgBEEBagwGCyABKAIAIARGBEAgASAEEI8BIAEoAgghBAsgASgCBCAEakHcADoAACABIARBAWoiBDYCCCABKAIAIARGBEAgASAEEI8BIAEoAgghBAsgASgCBCAEakHiADoAACAEQQFqDAULIAEoAgAgBEYEQCABIAQQjwEgASgCCCEECyABKAIEIARqQdwAOgAAIAEgBEEBaiIENgIIIAEoAgAgBEYEQCABIAQQjwEgASgCCCEECyABKAIEIARqQfQAOgAAIARBAWoMBAsgASgCACAERgRAIAEgBBCPASABKAIIIQQLIAEoAgQgBGpB3AA6AAAgASAEQQFqIgQ2AgggASgCACAERgRAIAEgBBCPASABKAIIIQQLIAEoAgQgBGpB7gA6AAAgBEEBagwDCyABKAIAIARGBEAgASAEEI8BIAEoAgghBAsgASgCBCAEakHcADoAACABIARBAWoiBDYCCCABKAIAIARGBEAgASAEEI8BIAEoAgghBAsgASgCBCAEakHmADoAACAEQQFqDAILIAEoAgAgBEYEQCABIAQQjwEgASgCCCEECyABKAIEIARqQdwAOgAAIAEgBEEBaiIENgIIIAEoAgAgBEYEQCABIAQQjwEgASgCCCEECyABKAIEIARqQfIAOgAAIARBAWoMAQsCfwJAAkACQCAFQSBPBEAgBUGAAUkNASAFQYAQSQ0CIAVBgIAETw0DIAYgBUE/cUGAAXI6AA4gBiAFQQx2QeABcjoADCAGIAVBBnZBP3FBgAFyOgANQQMMBAsgASgCACAERgRAIAEgBBCPASABKAIIIQQLIAEoAgQgBGpB3AA6AAAgASAEQQFqIgQ2AgggASgCACAERgRAIAEgBBCPASABKAIIIQQLIAEoAgQgBGpB9QA6AAAgASAEQQFqIgQ2AgggASgCACAERgRAIAEgBBCPASABKAIIIQQLIAEoAgQgBGpBMDoAACABIARBAWoiBDYCCCABKAIAIARGBEAgASAEEI8BIAEoAgghBAsgASgCBCAEakEwOgAAIAEgBEEBaiIENgIIIAVBD3EiA0EKSSEHIAEoAgAgBEYEQCABIAQQjwEgASgCCCEECyABKAIEIARqIAVB8AFxQQR2QTByOgAAIAEgBEEBaiIENgIIIAEoAgAgBEYEQCABIAQQjwEgASgCCCEECyABKAIEIARqIANBMHIgA0E3aiAHGzoAACAEQQFqDAQLIAEoAgAgBEYEQCABIAQQjwEgASgCCCEECyABKAIEIARqIAU6AAAgBEEBagwDCyAGIAVBP3FBgAFyOgANIAYgBUEGdkHAAXI6AAxBAgwBCyAGIAVBP3FBgAFyOgAPIAYgBUESdkHwAXI6AAwgBiAFQQZ2QT9xQYABcjoADiAGIAVBDHZBP3FBgAFyOgANQQQLIQUgBSABKAIAIARrSwRAIAEgBCAFEJABIAEoAgghBAsgASgCBCAEaiAGQQxqIAUQlwIaIAQgBWoLIgQ2AgggAiAIRw0ACwsgASgCACAERgRAIAEgBBCPASABKAIIIQQLIABBADYCACABIARBAWo2AgggASgCBCAEakEiOgAAIAZBEGokAAs/ACABKAIIIgIgASgCAEYEQCABIAIQjwEgASgCCCECCyAAQQA2AgAgASACQQFqNgIIIAEoAgQgAmpB3QA6AAALgAEBAn8gASgCCCICIAEoAgAiBEYEQCABIAIQjwEgASgCACEEIAEoAgghAgsgASACQQFqIgM2AgggAiABKAIEIgJqQf0AOgAAIAMgBEYEQCABIAQQjwEgASgCCCEDIAEoAgQhAgsgAEEANgIAIAEgA0EBajYCCCACIANqQf0AOgAACzABAX9BgAhBARBKIgFFBEBBgAhBARDcAQALIABBADYCCCAAIAE2AgQgAEGACDYCAAv4AQIEfwF+IwBBIGsiBCQAIARBF2pBADYAACAEQRBqQgA3AwAgBEIANwMIIAQgAkIKgqdBMHI6ABtBEyEDAkACQCACQgpaBEADQCADRQ0CIANBAWsiAyAEQQhqaiACQgqAIgdCCoKnQTByOgAAIAJC5ABUIAchAkUNAAsgA0EVTw0CC0EUIANrIgYgASgCACABKAIIIgVrSwRAIAEgBSAGEJABIAEoAgghBQsgASgCBCAFaiAEQQhqIANqIAYQlwIaIABBADYCACABIAUgBmo2AgggBEEgaiQADwtBgL7AAEEhQeDAwAAQ5wEACyADQRRB4MDAABDkAQALSQEBfyABKAIAIAEoAggiAmtBA00EQCABIAJBBBCQASABKAIIIQILIABBADYCACABIAJBBGo2AgggASgCBCACakHu6rHjBjYAAAsNACAAIAEgAiADEJ0BC1IBAX8gASgCCCICIAEoAgBGBEAgASACEI8BIAEoAgghAgsgACABNgIEIABBADYCACABIAJBAWo2AgggAEEIakEBOgAAIAEoAgQgAmpB2wA6AAALUgEBfyABKAIIIgIgASgCAEYEQCABIAIQjwEgASgCCCECCyAAIAE2AgQgAEEANgIAIAEgAkEBajYCCCAAQQhqQQE6AAAgASgCBCACakH7ADoAAAueAgICfwF+IwBBIGsiBSQAIAEoAggiBCABKAIARgRAIAEgBBCPASABKAIIIQQLIAEgBEEBajYCCCABKAIEIARqQfsAOgAAIAVBEGogASACIAMQnQECQCAFKAIQRQRAIAEoAggiBCABKAIARgRAIAEgBBCPASABKAIIIQQLIAEoAgQgBGpBOjoAACABIARBAWoiBDYCCCABKAIAIARGBEAgASAEEI8BIAEoAgghBAsgACABNgIEIABBADYCACABIARBAWo2AgggAEEIakEBOgAAIAEoAgQgBGpB+wA6AAAMAQsgBUEIaiAFQRxqKAIAIgE2AgAgBSAFKQIUIgY3AwAgAEEMaiABNgIAIAAgBjcCBCAAQQE2AgALIAVBIGokAAsWACAAKAIAIgAoAgAgACgCBCABEI0CCx0AIAEoAgBFBEAACyAAQZzXwAA2AgQgACABNgIAC1UBAn8gASgCACECIAFBADYCAAJAIAIEQCABKAIEIQNBCEEEEEoiAUUNASABIAM2AgQgASACNgIAIABBnNfAADYCBCAAIAE2AgAPCwALQQhBBBDcAQALwAQBA38jAEEwayICJAACfwJAAkACQAJAIAAoAgQiAw4DAAIDAQsjAEEQayIAJAAgAEHc2MAANgIIIABBDjYCBCAAQc3YwAA2AgAjAEEQayIBJAAgAUEIaiAAQQhqKAIANgIAIAEgACkCADcDACMAQRBrIgAkACAAIAEpAgA3AwggAEEIakGI18AAQQAgASgCCEEBEL4BAAsgAkEkakEBNgIAIAJBLGpBADYCACACQbTXwAA2AiAgAkGc18AANgIoIAJBADYCGEEBIAEgAkEYahCEAg0CGiADQQN0IQMgACgCACEAAkADQCACIAA2AhQgBARAIAJBATYCJCACQcDXwAA2AiAgAkEANgIsIAJBnNfAADYCKCACQQA2AhggASACQRhqEIQCDQILIAJBAjYCJCACQcjXwAA2AiAgAkEBNgIsIAJBADYCGCACQdQANgIEIAIgAjYCKCACIAJBFGo2AgAgASACQRhqEIQCDQEgAEEIaiEAIARBAWshBCADQQhrIgMNAAtBAAwDC0EBDAILIAJBJGpBAjYCACACQSxqQQE2AgAgAkHI18AANgIgIAJBADYCGCACQdUANgIEIAIgACgCADYCACACIAI2AiggASACQRhqEIQCDAELIAJBDGpB1QA2AgAgAkEkakEDNgIAIAJBLGpBAjYCACACQeDXwAA2AiAgAkEANgIYIAJB1QA2AgQgAiAAKAIAIgA2AgAgAiAAQQhqNgIIIAIgAjYCKCABIAJBGGoQhAILIAJBMGokAAsMAELr0N2RtuLCvEgLDQBCz8Kptu6ZpbSRfwsLAEHIgsEAKAIARQshAQF/AkAgAEEEaigCACIBRQ0AIAAoAgBFDQAgARC3AQsL0wIBAn8jAEEQayICJAAgACgCACEAAkACfwJAIAFBgAFPBEAgAkEANgIMIAFBgBBPDQEgAiABQT9xQYABcjoADSACIAFBBnZBwAFyOgAMQQIMAgsgACgCCCIDIAAoAgBGBEAgACADEBAgACgCCCEDCyAAIANBAWo2AgggACgCBCADaiABOgAADAILIAFBgIAETwRAIAIgAUE/cUGAAXI6AA8gAiABQQZ2QT9xQYABcjoADiACIAFBDHZBP3FBgAFyOgANIAIgAUESdkEHcUHwAXI6AAxBBAwBCyACIAFBP3FBgAFyOgAOIAIgAUEMdkHgAXI6AAwgAiABQQZ2QT9xQYABcjoADUEDCyEBIAEgACgCACAAKAIIIgNrSwRAIAAgAyABEBEgACgCCCEDCyAAKAIEIANqIAJBDGogARCXAhogACABIANqNgIICyACQRBqJABBAAtaAQF/IwBBIGsiAiQAIAIgACgCADYCBCACQRhqIAFBEGopAgA3AwAgAkEQaiABQQhqKQIANwMAIAIgASkCADcDCCACQQRqQezYwAAgAkEIahDsASACQSBqJAALkwMBBX8CQAJAAkACQCABQQlPBEBBEEEIEL8BIAFLDQEMAgsgABCyASEE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AEEBNgIARQ0BC0GA/8AAKAIAQf////8HcUUNABCtAQ0AQfT+wABBAToAAAtB8P7AAEEANgIAAkAgAkUNACACIAEoAgARBQAgAUEEaigCAEUNACABQQhqKAIAGiACELcBCyAAQSBqJAAPCyAAQRRqQQE2AgAgAEEcakEANgIAIABBwNrAADYCECAAQYTZwAA2AhggAEEANgIIIABBCGpB5NrAABDiAQALAAuLAgIDfwF+IwBBMGsiAiQAIAEoAgRFBEAgASgCDCEDIAJBEGoiBEEANgIAIAJCgICAgBA3AwggAiACQQhqNgIUIAJBKGogA0EQaikCADcDACACQSBqIANBCGopAgA3AwAgAiADKQIANwMYIAJBFGpB7NjAACACQRhqEOwBGiABQQhqIAQoAgA2AgAgASACKQMINwIACyABKQIAIQUgAUKAgICAEDcCACACQSBqIgMgAUEIaiIBKAIANgIAIAFBADYCACACIAU3AxhBDEEEEEoiAUUEQEEMQQQQ3AEACyABIAIpAxg3AgAgAUEIaiADKAIANgIAIABBlNvAADYCBCAAIAE2AgAgAkEwaiQAC6oBAQN/IwBBMGsiAiQAIAEoAgRFBEAgASgCDCEDIAJBEGoiBEEANgIAIAJCgICAgBA3AwggAiACQQhqNgIUIAJBKGogA0EQaikCADcDACACQSBqIANBCGopAgA3AwAgAiADKQIANwMYIAJBFGpB7NjAACACQRhqEOwBGiABQQhqIAQoAgA2AgAgASACKQMINwIACyAAQZTbwAA2AgQgACABNgIAIAJBMGokAAtFAQJ/IAEoAgQhAiABKAIAIQNBCEEEEEoiAUUEQEEIQQQQ3AEACyABIAI2AgQgASADNgIAIABBpNvAADYCBCAAIAE2AgALEwAgAEGk28AANgIEIAAgATYCAAuIAgECfyMAQSBrIgUkAEGA/8AAQYD/wAAoAgAiBkEBajYCAAJAAkAgBkEASA0AQciCwQBByILBACgCAEEBaiIGNgIAIAZBAksNACAFIAQ6ABggBSADNgIUIAUgAjYCECAFQdzbwAA2AgwgBUGE2cAANgIIQfD+wAAoAgAiAkEASA0AQfD+wAAgAkEBaiICNgIAQfD+wABB+P7AACgCAAR/IAUgACABKAIQEQEAIAUgBSkDADcDCEH4/sAAKAIAIAVBCGpB/P7A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AxshAiADIAEgAxshAQsgCkUNAiAAQQxqKAIAIQcCQCACQRBPBEAgASACEIACIQQMAQsgAkUEQEEAIQQMAQsgAkEDcSEFAkAgAkEBa0EDSQRAQQAhBCABIQMMAQsgAkF8cSEGQQAhBCABIQMDQCAEIAMsAABBv39KaiADLAABQb9/SmogAywAAkG/f0pqIAMsAANBv39KaiEEIANBBGohAyAGQQRrIgYNAAsLIAVFDQADQCAEIAMsAABBv39KaiEEIANBAWohAyAFQQFrIgUNAAsLIAQgB0kEQCAHIARrIgQhBgJAAkACQEEAIAAtACAiAyADQQNGG0EDcSIDQQFrDgIAAQILQQAhBiAEIQMMAQsgBEEBdiEDIARBAWpBAXYhBgsgA0EBaiEDIABBBGooAgAhBCAAKAIcIQUgACgCACEAAkADQCADQQFrIgNFDQEgACAFIAQoAhARAABFDQALQQEPC0EBIQMgBUGAgMQARg0CIAAgASACIAQoAgwRAgANAkEAIQMDQCADIAZGBEBBAA8LIANBAWohAyAAIAUgBCgCEBEAAEUNAAsgA0EBayAGSQ8LDAILIAAoAgAgASACIAAoAgQoAgwRAgAhAwsgAw8LIAAoAgAgASACIAAoAgQoAgwRAgALUgEBfyMAQSBrIgMkACADQQxqQQE2AgAgA0EUakEANgIAIANB+N7AADYCECADQQA2AgAgAyABNgIcIAMgADYCGCADIANBGGo2AgggAyACEOIBAAt5AQF/IwBBMGsiAyQAIAMgATYCBCADIAA2AgAgA0EUakECNgIAIANBHGpBAjYCACADQSxqQdIANgIAIANBgOfAADYCECADQQA2AgggA0HSADYCJCADIANBIGo2AhggAyADQQRqNgIoIAMgAzYCICADQQhqIAIQ4gEACyUAIAEgAC0AAEECdCIAQdT+wABqKAIAIABBwP7AAGooAgAQ5gELDAAgADUCACABEJICC74CAQN/IwBBgAFrIgQkAAJAAkACQAJAIAEoAhgiAkEQcUUEQCACQSBxDQEgADUCACABEJICIQAMBAsgACgCACEAQQAhAgNAIAIgBGpB/wBqQTBB1wAgAEEPcSIDQQpJGyADajoAACACQQFrIQIgAEEPSyAAQQR2IQANAAsgAkGAAWoiAEGBAU8NASABQfziwABBAiACIARqQYABakEA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aiIAIARJDQALCyAEIAIgA2siAkF8cSIDaiEAIANBAEoEQCABQf8BcUGBgoQIbCEDA0AgBCADNgIAIARBBGoiBCAASQ0ACwsgAkEDcSECCyACBEAgACACaiECA0AgACABOgAAIABBAWoiACACSQ0ACwsLC6l+BgBBgIDAAAvHE2F0dGVtcHQgdG8gYWRkIHdpdGggb3ZlcmZsb3dJYmNNc2djbG9zZV9jaGFubmVsY2hhbm5lbF9pZHNlbmRfcGFja2V0ZGF0YXRpbWVvdXR0cmFuc2ZlcnRvX2FkZHJlc3NhbW91bnRJYmNUaW1lb3V0YmxvY2t0aW1lc3RhbXBJYmNUaW1lb3V0QmxvY2tyZXZpc2lvbmhlaWdodENvaW5kZW5vbQAAAAYAAAAAAAAAAQAAAAcAAAAIAAAACQAAAAoAAAALAAAADAAAAAYAAAAAAAAAAQAAAA0AAAAOAAAADwAAABAAAAARAAAAEgAAABMAAAAUAAAABgAAAAAAAAABAAAAFQAAAHRyYW5zYWN0aW9uY29udHJhY3R0aW1lY2hhaW5faWRzZW5kZXJmdW5kc2FkZHJlc3NpbmRleAAAFgAAAAgAAAAEAAAAFwAAABgAAAAZAAAAGgAAABYAAAAIAAAABAAAABsAAAAYAAAAHAAAAB0AAABjYWxsZWQgYFJlc3VsdDo6dW53cmFwKClgIG9uIGFuIGBFcnJgIHZhbHVlAB4AAAAgAAAACAAAAB8AAAAvdXNyL2xvY2FsL2NhcmdvL3JlZ2lzdHJ5L3NyYy9naXRodWIuY29tLTFlY2M2Mjk5ZGI5ZWM4MjMvY29zbXdhc20tc3RkLTEuMy4zL3NyYy9leHBvcnRzLnJzALQBEABbAAAAlQAAAA0AAAC0ARAAWwAAAHcAAAANAAAAtAEQAFsAAADFAAAADQAAALQBEABbAAAA8gAAAA0AAABDb3Ntb3NNc2dnb3Z3YXNtaWJjc3RhcmdhdGV0eXBlX3VybHZhbHVlY3VzdG9tYmFua0dvdk1zZ3ZvdGVwcm9wb3NhbF9pZEJhbmtNc2didXJuc2VuZFdhc21Nc2djbGVhcl9hZG1pbmNvbnRyYWN0X2FkZHJ1cGRhdGVfYWRtaW5hZG1pbm1pZ3JhdGVuZXdfY29kZV9pZG1zZ2luc3RhbnRpYXRlY29kZV9pZGxhYmVsZXhlY3V0ZVZvdGVPcHRpb25ub193aXRoX3ZldG9hYnN0YWlubm95ZXNTdWJNc2dpZGdhc19saW1pdFJlcGx5T25uZXZlcnN1Y2Nlc3NlcnJvcmFsd2F5c29rRW1wdHlFdmVudHR5cGVhdHRyaWJ1dGVzQXR0cmlidXRla2V5UmVzcG9uc2VldmVudHNDb250cmFjdFZlcnNpb252ZXJzaW9uY29udHJhY3RfaW5mbwAAACAAAAAMAAAABAAAACEAAAAiAAAAIwAAAGEgRGlzcGxheSBpbXBsZW1lbnRhdGlvbiByZXR1cm5lZCBhbiBlcnJvciB1bmV4cGVjdGVkbHkABgAAAAAAAAABAAAAJAAAAC9ydXN0Yy9kNWE4MmJiZDI2ZTFhZDhiNzQwMWY2YTcxOGE5YzU3Yzk2OTA1NDgzL2xpYnJhcnkvYWxsb2Mvc3JjL3N0cmluZy5ycwAUBBAASwAAAOgJAAAJAAAAY2xvY2tfZXhhbXBsZTo6bXNnOjpFeGVjdXRlTXNnY2xvY2tfZXhhbXBsZTo6bXNnOjpJbnN0YW50aWF0ZU1zZ2N3Mjo6Q29udHJhY3RWZXJzaW9uY29zbXdhc21fc3RkOjp0eXBlczo6TWVzc2FnZUluZm9jbG9ja19leGFtcGxlOjpzdGF0ZTo6Q29uZmlnY2xvY2tfZXhhbXBsZTo6bXNnOjpTdWRvTXNnY29zbXdhc21fc3RkOjp0eXBlczo6RW52Y29zbXdhc21fc3RkOjpyZXN1bHRzOjpjb250cmFjdF9yZXN1bHQ6OkNvbnRyYWN0UmVzdWx0PGNvc213YXNtX3N0ZDo6cmVzdWx0czo6cmVzcG9uc2U6OlJlc3BvbnNlPmNvc213YXNtX3N0ZDo6cmVzdWx0czo6Y29udHJhY3RfcmVzdWx0OjpDb250cmFjdFJlc3VsdDxjb3Ntd2FzbV9zdGQ6OmJpbmFyeTo6QmluYXJ5PmNsb2NrX2V4YW1wbGU6Om1zZzo6UXVlcnlNc2cGAAAABAAAAAQAAAAlAAAAJgAAACcAAABtaXNzaW5nIGZpZWxkIGBgHAYQAA8AAAArBhAAAQAAAHVua25vd24gZmllbGQgYGAsIGV4cGVjdGVkIAA8BhAADwAAAEsGEAAMAAAAYCwgdGhlcmUgYXJlIG5vIGZpZWxkcwAAPAYQAA8AAABoBhAAFgAAAGR1cGxpY2F0ZSBmaWVsZCBgAAAAkAYQABEAAAArBhAAAQAAAHVua25vd24gdmFyaWFudCBgAAAAtAYQABEAAABLBhAADAAAAGludmFsaWQgVWludDY0ICcnIC0g2AYQABAAAADoBhAABAAAAGludmFsaWQgVWludDEyOCAnAAAA/AYQABEAAADoBhAABAAAAHVsbGNvbmZpZ3NyYy9jb250cmFjdC5ycykHEAAPAAAAIgAAAAUAAABjcmF0ZXMuaW86Y3ctaWJjLWV4YW1wbGUwLjEuMG1ldGhvZGludmFsaWQgSUJDIGNoYW5uZWwgdmVyc2lvbi4gR290ICgpLCBleHBlY3RlZCAoKQBrBxAAIgAAAI0HEAANAAAAmgcQAAEAAABvbmx5IHVub3JkZXJlZCBjaGFubmVscyBhcmUgc3VwcG9ydGVkAAAAtAcQACUAAAAcBhAAAAAAAGluY3JlbWVudAAAAOwHEAAJAAAAY2xvY2tfZW5kX2Jsb2NrAAAIEAAPAAAAZ2V0X2NvbmZpZwAAGAgQAAoAAABDb25maWd2YWwAAAAyCBAAAwAAAC9ydXN0Yy9kNWE4MmJiZDI2ZTFhZDhiNzQwMWY2YTcxOGE5YzU3Yzk2OTA1NDgzL2xpYnJhcnkvY29yZS9zcmMvaXRlci9hZGFwdGVycy9lbnVtZXJhdGUucnMAAAAAAGF0dGVtcHQgdG8gYWRkIHdpdGggb3ZlcmZsb3dACBAAWwAAADAAAAAJAAAAAAAAAGF0dGVtcHQgdG8gc3VidHJhY3Qgd2l0aCBvdmVyZmxvdwAAADMAAAAIAAAABAAAADQAAAA1AAAANgAAAAwAAAAEAAAANwAAADgAAAA5AAAAYSBEaXNwbGF5IGltcGxlbWVudGF0aW9uIHJldHVybmVkIGFuIGVycm9yIHVuZXhwZWN0ZWRseQAzAAAAAAAAAAEAAAAkAAAAL3J1c3RjL2Q1YTgyYmJkMjZlMWFkOGI3NDAxZjZhNzE4YTljNTdjOTY5MDU0ODMvbGlicmFyeS9hbGxvYy9zcmMvc3RyaW5nLnJzAGgJEABLAAAA6AkAAAkAAADMCBAAQdCTwAAL8SlhdHRlbXB0IHRvIG11bHRpcGx5IHdpdGggb3ZlcmZsb3djb3Ntd2FzbV9zdGQ6OnJlc3VsdHM6OnN5c3RlbV9yZXN1bHQ6OlN5c3RlbVJlc3VsdDxjb3Ntd2FzbV9zdGQ6OnJlc3VsdHM6OmNvbnRyYWN0X3Jlc3VsdDo6Q29udHJhY3RSZXN1bHQ8Y29zbXdhc21fc3RkOjpiaW5hcnk6OkJpbmFyeT4+AAAAMwAAAAQAAAAEAAAAOgAAADsAAAA8AAAAMwAAAAQAAAAEAAAAPQAAAGludGVybmFsIGVycm9yOiBlbnRlcmVkIHVucmVhY2hhYmxlIGNvZGU6IAAApAoQACoAAAAvcnVzdGMvZDVhODJiYmQyNmUxYWQ4Yjc0MDFmNmE3MThhOWM1N2M5NjkwNTQ4My9saWJyYXJ5L2NvcmUvc3JjL2l0ZXIvdHJhaXRzL2FjY3VtLnJzAAAA2AoQAFUAAACNAAAAAQAAAG1pc3NpbmcgZmllbGQgYGBACxAADwAAAE8LEAABAAAAZHVwbGljYXRlIGZpZWxkIGAAAABgCxAAEQAAAE8LEAABAAAAdW5rbm93biB2YXJpYW50IGBgLCBleHBlY3RlZCAAAACECxAAEQAAAJULEAAMAAAAZGVjb2RlZCBsZW5ndGggY2FsY3VsYXRpb24gb3ZlcmZsb3cvdXNyL2xvY2FsL2NhcmdvL3JlZ2lzdHJ5L3NyYy9naXRodWIuY29tLTFlY2M2Mjk5ZGI5ZWM4MjMvYmFzZTY0LTAuMTMuMS9zcmMvZGVjb2RlLnJz1wsQAFUAAABuAAAAIwAAANcLEABVAAAACgEAADcAAADXCxAAVQAAAAoBAAAkAAAA1wsQAFUAAAALAQAAKQAAANcLEABVAAAAKAEAABEAAADXCxAAVQAAADEBAAApAAAA1wsQAFUAAAAxAQAAFgAAANcLEABVAAAANQEAACkAAADXCxAAVQAAADUBAAAoAAAA1wsQAFUAAAA0AQAAGgAAANcLEABVAAAAOgEAABEAAADXCxAAVQAAAEgBAAAOAAAA1wsQAFUAAABLAQAAJwAAANcLEABVAAAASwEAABIAAADXCxAAVQAAAE4BAAAJAAAA1wsQAFUAAABfAQAAEwAAANcLEABVAAAAbQEAACkAAADXCxAAVQAAAH8BAAANAAAA1wsQAFUAAACJAQAAEQAAANcLEABVAAAAkQEAABUAAADXCxAAVQAAAJUBAAAxAAAASW1wb3NzaWJsZTogbXVzdCBvbmx5IGhhdmUgMCB0byA4IGlucHV0IGJ5dGVzIGluIGxhc3QgY2h1bmssIHdpdGggbm8gaW52YWxpZCBsZW5ndGhzfA0QAFQAAADXCxAAVQAAAKQBAAAOAAAA1wsQAFUAAACvAQAADQAAANcLEABVAAAAuAEAAAkAAABPdmVyZmxvdyB3aGVuIGNhbGN1bGF0aW5nIG91dHB1dCBidWZmZXIgbGVuZ3RoAADXCxAAVQAAAJoAAAAgAAAA1wsQAFUAAAAuAgAABQAAAC91c3IvbG9jYWwvY2FyZ28vcmVnaXN0cnkvc3JjL2dpdGh1Yi5jb20tMWVjYzYyOTlkYjllYzgyMy9iYXNlNjQtMC4xMy4xL3NyYy9lbmNvZGUucnNJbnZhbGlkIFVURjgAAAA+AAAAFAAAAAQAAAA/AAAAWA4QAFUAAAA0AAAABQAAAGludGVnZXIgb3ZlcmZsb3cgd2hlbiBjYWxjdWxhdGluZyBidWZmZXIgc2l6ZQAAAFgOEABVAAAALwAAABEAAAAzAAAACAAAAAQAAABAAAAAaW52YWxpZCBiYXNlNjQ6ICwPEAAQAAAAMwAAAAAAAAABAAAAQQAAAEIAAABCAAAAL3Vzci9sb2NhbC9jYXJnby9yZWdpc3RyeS9zcmMvZ2l0aHViLmNvbS0xZWNjNjI5OWRiOWVjODIzL2Nvc213YXNtLXN0ZC0xLjMuMy9zcmMvc2VjdGlvbnMucnNcDxAAXAAAABoAAAAQAAAAXA8QAFwAAAAaAAAABQAAAFwPEABcAAAAOQAAABgAAABDYW5ub3QgcmVhZCBzZWN0aW9uIGxlbmd0aAAA6A8QABoAAABcDxAAXAAAADcAAAAJAAAAVEw7RFI6IFZhbHVlIG11c3Qgbm90IGJlIGVtcHR5IGluIFN0b3JhZ2U6OnNldCBidXQgaW4gbW9zdCBjYXNlcyB5b3UgY2FuIHVzZSBTdG9yYWdlOjpyZW1vdmUgaW5zdGVhZC4gTG9uZyBzdG9yeTogR2V0dGluZyBlbXB0eSB2YWx1ZXMgZnJvbSBzdG9yYWdlIGlzIG5vdCB3ZWxsIHN1cHBvcnRlZCBhdCB0aGUgbW9tZW50LiBTb21lIG9mIG91ciBpbnRlcm5hbCBpbnRlcmZhY2VzIGNhbm5vdCBkaWZmZXJlbnRpYXRlIGJldHdlZW4gYSBub24tZXhpc3RlbnQga2V5IGFuZCBhbiBlbXB0eSB2YWx1ZS4gUmlnaHQgbm93LCB5b3UgY2Fubm90IHJlbHkgb24gdGhlIGJlaGF2aW91ciBvZiBlbXB0eSB2YWx1ZXMuIFRvIHByb3RlY3QgeW91IGZyb20gdHJvdWJsZSBsYXRlciBvbiwgd2Ugc3RvcCBoZXJlLiBTb3JyeSBmb3IgdGhlIGluY29udmVuaWVuY2UhIFdlIGhpZ2hseSB3ZWxjb21lIHlvdSB0byBjb250cmlidXRlIHRvIENvc21XYXNtLCBtYWtpbmcgdGhpcyBtb3JlIHNvbGlkIG9uZSB3YXkgb3IgdGhlIG90aGVyLhwQEAAIAgAAL3Vzci9sb2NhbC9jYXJnby9yZWdpc3RyeS9zcmMvZ2l0aHViLmNvbS0xZWNjNjI5OWRiOWVjODIzL2Nvc213YXNtLXN0ZC0xLjMuMy9zcmMvaW1wb3J0cy5ycwAsEhAAWwAAAGsAAAANAAAAMwAAAAQAAAAEAAAAQwAAAEQAAABFAAAARgAAAGlucHV0IHRvbyBsb25nIGZvciBhZGRyX3ZhbGlkYXRlYWRkcl92YWxpZGF0ZSBlcnJvcmVkOiAA1BIQABcAAABpbnB1dCB0b28gbG9uZyBmb3IgYWRkcl9jYW5vbmljYWxpemVhZGRyX2Nhbm9uaWNhbGl6ZSBlcnJvcmVkOiAAGBMQABsAAABhZGRyX2h1bWFuaXplIGVycm9yZWQ6IAA8ExAAFwAAAE1lc3NhZ2VUb29Mb25nIG11c3Qgbm90IGhhcHBlbi4gVGhpcyBpcyBhIGJ1ZyBpbiB0aGUgVk0uXBMQADgAAAAsEhAAWwAAAAgBAAASAAAALBIQAFsAAAAlAQAAEgAAAEludmFsaWRIYXNoRm9ybWF0IG11c3Qgbm90IGhhcHBlbi4gVGhpcyBpcyBhIGJ1ZyBpbiB0aGUgVk0uALwTEAA7AAAALBIQAFsAAAA/AQAAEgAAAEVycm9yIGNvZGUgMiB1bnVzZWQgc2luY2UgQ29zbVdhc20gMC4xNS4gVGhpcyBpcyBhIGJ1ZyBpbiB0aGUgVk0uAAAAEBQQAEEAAAAsEhAAWwAAAD4BAAASAAAALBIQAFsAAABfAQAAEgAAACwSEABbAAAAXgEAABIAAABSZWdpb24gcG9pbnRlciBpcyBudWxsAACMFBAAFgAAAC91c3IvbG9jYWwvY2FyZ28vcmVnaXN0cnkvc3JjL2dpdGh1Yi5jb20tMWVjYzYyOTlkYjllYzgyMy9jb3Ntd2FzbS1zdGQtMS4zLjMvc3JjL21lbW9yeS5ycwAArBQQAFoAAAA5AAAABQAAAFJlZ2lvbiBzdGFydHMgYXQgbnVsbCBwb2ludGVyAAAAGBUQAB0AAACsFBAAWgAAAD8AAAAFAAAAVW5rbm93biBlcnJvcjogAFAVEAAPAAAASW52YWxpZCByZWNvdmVyeSBwYXJhbWV0ZXIuIFN1cHBvcnRlZCB2YWx1ZXM6IDAgYW5kIDEuAABoFRAANgAAAEludmFsaWQgc2lnbmF0dXJlIGZvcm1hdKgVEAAYAAAASW52YWxpZCBoYXNoIGZvcm1hdADIFRAAEwAAAFVua25vd25FcnJlcnJvcl9jb2RlMwAAAAQAAAAEAAAARwAAAEludmFsaWRSZWNvdmVyeVBhcmFtSW52YWxpZFNpZ25hdHVyZUZvcm1hdEludmFsaWRIYXNoRm9ybWF0Q29udmVyc2lvbiBlcnJvcjogAAAAQxYQABIAAABEaXZpZGUgYnkgemVybzogYBYQABAAAABPdmVyZmxvdzogAAB4FhAACgAAAEVycm9yIHNlcmlhbGl6aW5nIHR5cGUgOiAAAACMFhAAFwAAAKMWEAACAAAARXJyb3IgcGFyc2luZyBpbnRvIHR5cGUguBYQABgAAACjFhAAAgAAACBub3QgZm91bmQAAMwIEAAAAAAA4BYQAAoAAABDYW5ub3QgZGVjb2RlIFVURjggYnl0ZXMgaW50byBzdHJpbmc6IAAA/BYQACYAAABJbnZhbGlkIGhleCBzdHJpbmc6ICwXEAAUAAAASW52YWxpZCBkYXRhIHNpemU6IGV4cGVjdGVkPSBhY3R1YWw9SBcQABwAAABkFxAACAAAAEludmFsaWQgQmFzZTY0IHN0cmluZzogAHwXEAAXAAAAR2VuZXJpYyBlcnJvcjogAJwXEAAPAAAAUmVjb3ZlciBwdWJrZXkgZXJyb3I6IAAAtBcQABYAAABWZXJpZmljYXRpb24gZXJyb3I6INQXEAAUAAAAQ29udmVyc2lvbk92ZXJmbG93c291cmNlMwAAAAQAAAAEAAAASAAAAERpdmlkZUJ5WmVybzMAAAAEAAAABAAAAEkAAABPdmVyZmxvdzMAAAAEAAAABAAAAEoAAABTZXJpYWxpemVFcnJzb3VyY2VfdHlwZW1zZ1BhcnNlRXJydGFyZ2V0X3R5cGVOb3RGb3VuZGtpbmRJbnZhbGlkVXRmOEludmFsaWRIZXhJbnZhbGlkRGF0YVNpemVleHBlY3RlZAAAADMAAAAEAAAABAAAAEsAAABhY3R1YWxJbnZhbGlkQmFzZTY0R2VuZXJpY0VyclJlY292ZXJQdWJrZXlFcnIAAAAzAAAABAAAAAQAAABMAAAAVmVyaWZpY2F0aW9uRXJyADMAAAAEAAAABAAAAE0AAABTaGxTaHJQb3dNdWxTdWJBZGRDYW5ub3QgIHdpdGggIGFuZCA2GRAABwAAAD0ZEAAGAAAAQxkQAAUAAABPdmVyZmxvd0Vycm9yb3BlcmF0aW9uAAAzAAAABAAAAAQAAAAqAAAAb3BlcmFuZDFvcGVyYW5kMkNvbnZlcnNpb25PdmVyZmxvd0Vycm9yADMAAAAEAAAABAAAAE4AAAB2YWx1ZUNhbm5vdCBkaXZpZGUgIGJ5IHplcm8AxRkQAA4AAADTGRAACAAAAERpdmlkZUJ5WmVyb0Vycm9yb3BlcmFuZGludmFsaWRfcmVxdWVzdGludmFsaWRfcmVzcG9uc2Vub19zdWNoX2NvbnRyYWN0bm9fc3VjaF9jb2RldW5rbm93bnVuc3VwcG9ydGVkX3JlcXVlc3QAAAAEGhAADwAAABMaEAAQAAAAIxoQABAAAAAzGhAADAAAAD8aEAAHAAAARhoQABMAAABjb2RlX2lkYWRkcmVycm9ycmVzcG9uc2VyZXF1ZXN0SW52YWxpZCBwdWJsaWMga2V5IGZvcm1hdKsaEAAZAAAAR2VuZXJpYyBlcnJvcgAAAMwaEAANAAAAQmF0Y2ggZXJyb3IA5BoQAAsAAABJbnZhbGlkUHVia2V5Rm9ybWF0QmF0Y2hFcnJvawAAABMbEAACAAAAlxoQAAUAAAAzGRAAMBkQAC0ZEAAqGRAAJxkQACQZEABAGxAAAAAAAEpTT04gaGFzIGEgY29tbWEgYWZ0ZXIgdGhlIGxhc3QgdmFsdWUgaW4gYW4gYXJyYXkgb3IgbWFwLkpTT04gaGFzIG5vbi13aGl0ZXNwYWNlIHRyYWlsaW5nIGNoYXJhY3RlcnMgYWZ0ZXIgdGhlIHZhbHVlLkZvdW5kIGEgbG9uZSBzdXJyb2dhdGUsIHdoaWNoIGNhbiBleGlzdCBpbiBKU09OIGJ1dCBjYW5ub3QgYmUgZW5jb2RlZCB0byBVVEYtOC5PYmplY3Qga2V5IGlzIG5vdCBhIHN0cmluZy5JbnZhbGlkIHVuaWNvZGUgY29kZSBwb2ludC5JbnZhbGlkIHR5cGVJbnZhbGlkIG51bWJlci5JbnZhbGlkIGVzY2FwZSBzZXF1ZW5jZS5FeHBlY3RlZCB0aGlzIGNoYXJhY3RlciB0byBzdGFydCBhIEpTT04gdmFsdWUuRXhwZWN0ZWQgdG8gcGFyc2UgZWl0aGVyIGEgYHRydWVgLCBgZmFsc2VgLCBvciBhIGBudWxsYC5FeHBlY3RlZCB0aGlzIGNoYXJhY3RlciB0byBiZSBlaXRoZXIgYSBgJywnYCBvciBhIGAnfSdgLkV4cGVjdGVkIGEgbG93IHN1cnJvZ2F0ZSAoREMwMOKAk0RGRkYpLkV4cGVjdGVkIHRoaXMgY2hhcmFjdGVyIHRvIGJlIGVpdGhlciBhIGAnLCdgIG9yYSBgJ10nYC5FeHBlY3RlZCBhIGhpZ2ggc3Vycm9nYXRlIChEODAw4oCTREJGRikuRXhwZWN0ZWQgdGhpcyBjaGFyYWN0ZXIgdG8gYmUgYSBgJzonYC5FT0Ygd2hpbGUgcGFyc2luZyBhIEpTT04gdmFsdWUuRU9GIHdoaWxlIHBhcnNpbmcgYSBzdHJpbmcuRU9GIHdoaWxlIHBhcnNpbmcgYW4gb2JqZWN0LkVPRiB3aGlsZSBwYXJzaW5nIGEgbGlzdC5Db250cm9sIGNoYXJhY3RlciBmb3VuZCBpbiBzdHJpbmcuL3Vzci9sb2NhbC9jYXJnby9yZWdpc3RyeS9zcmMvZ2l0aHViLmNvbS0xZWNjNjI5OWRiOWVjODIzL3NlcmRlLWpzb24td2FzbS0wLjUuMS9zcmMvZGUvdW5lc2NhcGUucnMAAFAeEABiAAAAJQAAABUAQdC9wAAL0QNhdHRlbXB0IHRvIGFkZCB3aXRoIG92ZXJmbG93UB4QAGIAAAAzAAAAKQAAAAAAAABhdHRlbXB0IHRvIHN1YnRyYWN0IHdpdGggb3ZlcmZsb3dOb24taGV4IEFTQ0lJIGNoYXJhY3RlciBmb3VuZAAAIR8QAB0AAABQHhAAYgAAAJkAAAAOAAAAL3Vzci9sb2NhbC9jYXJnby9yZWdpc3RyeS9zcmMvZ2l0aHViLmNvbS0xZWNjNjI5OWRiOWVjODIzL3NlcmRlLWpzb24td2FzbS0wLjUuMS9zcmMvZGUvbW9kLnJzAAAAWB8QAF0AAAAkAAAACQAAAFgfEABdAAAAfQAAACIAAABYHxAAXQAAAIEAAAAsAAAAQnVmZmVyIGlzIGZ1bGwAAOgfEAAOAAAAL3Vzci9sb2NhbC9jYXJnby9yZWdpc3RyeS9zcmMvZ2l0aHViLmNvbS0xZWNjNjI5OWRiOWVjODIzL3NlcmRlLWpzb24td2FzbS0wLjUuMS9zcmMvc2VyL21vZC5ycwAAACAQAF4AAADdAAAACQAAAGludGVybmFsIGVycm9yOiBlbnRlcmVkIHVucmVhY2hhYmxlIGNvZGU6IAAAcCAQACoAQbDBwAAL4CZhdHRlbXB0IHRvIGFkZCB3aXRoIG92ZXJmbG93L3Vzci9sb2NhbC9jYXJnby9yZWdpc3RyeS9zcmMvZ2l0aHViLmNvbS0xZWNjNjI5OWRiOWVjODIzL2Jhc2U2NC0wLjEzLjEvc3JjL2VuY29kZS5ycwAAAMwgEABVAAAAkgAAACcAAAB1c2l6ZSBvdmVyZmxvdyB3aGVuIGNhbGN1bGF0aW5nIGI2NCBsZW5ndGgAAMwgEABVAAAAlwAAABkAAADMIBAAVQAAALYAAAAgAAAAzCAQAFUAAAC3AAAAOgAAAMwgEABVAAAAtwAAACUAAADMIBAAVQAAAPwAAAAvAAAAzCAQAFUAAAD8AAAAHAAAAMwgEABVAAAA/QAAADYAAADMIBAAVQAAAP0AAAAhAAAAzCAQAFUAAAATAQAALgAAAMwgEABVAAAAEwEAAAkAAADMIBAAVQAAABQBAAAJAAAAzCAQAFUAAAALAQAALgAAAMwgEABVAAAACwEAAAkAAADMIBAAVQAAAA0BAAAPAAAAzCAQAFUAAAAMAQAACQAAAMwgEABVAAAADwEAAAkAAADMIBAAVQAAABEBAAAJAAAASW1wb3NzaWJsZSByZW1haW5kZXJwIhAAFAAAAMwgEABVAAAAKgEAABYAAADMIBAAVQAAADsBAAAJAAAASW52YWxpZCBsYXN0IHN5bWJvbCAsIG9mZnNldCAuAACsIhAAFAAAAMAiEAAJAAAAySIQAAEAAABFbmNvZGVkIHRleHQgY2Fubm90IGhhdmUgYSA2LWJpdCByZW1haW5kZXIuAOQiEAArAAAASW52YWxpZCBieXRlIAAAABgjEAANAAAAwCIQAAkAAADJIhAAAQAAAE92ZXJmbG93IHdoZW4gY2FsY3VsYXRpbmcgbnVtYmVyIG9mIGNodW5rcyBpbiBpbnB1dC91c3IvbG9jYWwvY2FyZ28vcmVnaXN0cnkvc3JjL2dpdGh1Yi5jb20tMWVjYzYyOTlkYjllYzgyMy9iYXNlNjQtMC4xMy4xL3NyYy9kZWNvZGUucnNzIxAAVQAAAMAAAAAFAAAAISIjJCUmJygpKissLTAxMjM0NTY3ODlAQUJDREVGR0hJSktMTU5QUVJTVFVWWFlaW2BhYmNkZWhpamtsbXBxckFCQ0RFRkdISUpLTE1OT1BRUlNUVVZXWFlaYWJjZGVmZ2hpamtsbW5vcHFyc3R1dnd4eXowMTIzNDU2Nzg5KywuL0FCQ0RFRkdISUpLTE1OT1BRUlNUVVZXWFlaYWJjZGVmZ2hpamtsbW5vcHFyc3R1dnd4eXowMTIzNDU2Nzg5Li8wMTIzNDU2Nzg5QUJDREVGR0hJSktMTU5PUFFSU1RVVldYWVphYmNkZWZnaGlqa2xtbm9wcXJzdHV2d3h5ekFCQ0RFRkdISUpLTE1OT1BRUlNUVVZXWFlaYWJjZGVmZ2hpamtsbW5vcHFyc3R1dnd4eXowMTIzNDU2Nzg5LV9BQkNERUZHSElKS0xNTk9QUVJTVFVWV1hZWmFiY2RlZmdoaWprbG1ub3BxcnN0dXZ3eHl6MDEyMzQ1Njc4OSsv////////////////////////////////////////////AAECAwQFBgcICQoLDP//DQ4PEBESExQVFv///////xcYGRobHB0eHyAhIiMkJf8mJygpKiss/y0uLzD/////MTIzNDU2//83ODk6Ozz//z0+P/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////8+P////zQ1Njc4OTo7PD3/////////AAECAwQFBgcICQoLDA0ODxAREhMUFRYXGBn///////8aGxwdHh8gISIjJCUmJygpKissLS4vMDEyM///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////AAE2Nzg5Ojs8PT4//////////wIDBAUGBwgJCgsMDQ4PEBESExQVFhcYGRob////////HB0eHyAhIiMkJSYnKCkqKywtLi8wMTIzNDX//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////wABAgMEBQYHCAkKC/////////8MDQ4PEBESExQVFhcYGRobHB0eHyAhIiMkJf///////yYnKCkqKywtLi8wMTIzNDU2Nzg5Ojs8PT4//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////z7//zQ1Njc4OTo7PD3/////////AAECAwQFBgcICQoLDA0ODxAREhMUFRYXGBn/////P/8aGxwdHh8gISIjJCUmJygpKissLS4vMDEyM///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////Pv///z80NTY3ODk6Ozw9/////////wABAgMEBQYHCAkKCwwNDg8QERITFBUWFxgZ////////GhscHR4fICEiIyQlJicoKSorLC0uLzAxMjP/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////GCUQANgkEACYJBAAWCQQABgkEADYIxAAWCoQAFgpEABYKBAAWCcQAFgmEABYJRAAVgAAAAgAAAAEAAAAVwAAAFgAAABWAAAACAAAAAQAAABZAAAAYG9uZSBvZiCtKxAABwAAACwgAAC8KxAAAgAAAKwrEAABAAAArCsQAAEAAABgIG9yIGAAAKwrEAABAAAA2CsQAAYAAACsKxAAAQAAAC91c3IvbG9jYWwvY2FyZ28vcmVnaXN0cnkvc3JjL2dpdGh1Yi5jb20tMWVjYzYyOTlkYjllYzgyMy9zZXJkZS0xLjAuMTg2L3NyYy9kZS9tb2QucnNleHBsaWNpdCBwYW5pYwD4KxAAVQAAAOoIAAASAAAAWwAAAAQAAAAEAAAAXAAAAF0AAABeAAAAY2FsbGVkIGBPcHRpb246OnVud3JhcCgpYCBvbiBhIGBOb25lYCB2YWx1ZW1lbW9yeSBhbGxvY2F0aW9uIG9mICBieXRlcyBmYWlsZWQKAACvLBAAFQAAAMQsEAAOAAAAbGlicmFyeS9zdGQvc3JjL2FsbG9jLnJz5CwQABgAAABVAQAACQAAAGNhbm5vdCBtb2RpZnkgdGhlIHBhbmljIGhvb2sgZnJvbSBhIHBhbmlja2luZyB0aHJlYWQM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", + "code_id": "1", + "code_info": { + "code_hash": "yEDfFQZ0Y/r68t1icFEjtQSnXZV0KrrHuCoJUs87vNo=", + "creator": "juno1hj5fveer5cjtn4wd6wstzugjfdxzl0xps73ftl", + "instantiate_config": { + "addresses": [], + "permission": "Everybody" + } + }, + "pinned": false + } + ], + "contracts": [ + { + "contract_address": "juno14hj2tavq8fpesdwxxcu44rty3hh90vhujrvcmstl4zr3txmfvw9skjuwg8", + "contract_code_history": [ + { + "code_id": "1", + "msg": {}, + "operation": "CONTRACT_CODE_HISTORY_OPERATION_TYPE_INIT", + "updated": { + "block_height": "4", + "tx_index": "0" + } + } + ], + "contract_info": { + "admin": "", + "code_id": "1", + "created": { + "block_height": "4", + "tx_index": "0" + }, + "creator": "juno1hj5fveer5cjtn4wd6wstzugjfdxzl0xps73ftl", + "extension": null, + "ibc_port_id": "", + "label": "test" + }, + "contract_state": [ + { + "key": "636F6E666967", + "value": "eyJ2YWwiOjF9" + }, + { + "key": "636F6E74726163745F696E666F", + "value": "eyJjb250cmFjdCI6ImNyYXRlcy5pbzpjdy1pYmMtZXhhbXBsZSIsInZlcnNpb24iOiIwLjEuMCJ9" + } + ] + } + ], + "params": { + "code_upload_access": { + "addresses": [], + "permission": "Everybody" + }, + "instantiate_default_permission": "Everybody" + }, + "sequences": [ + { + "id_key": "BGxhc3RDb2RlSWQ=", + "value": "2" + }, + { + "id_key": "BGxhc3RDb250cmFjdElk", + "value": "2" + } + ] + } + }, + "chain_id": "local-1", + "consensus_params": { + "block": { + "max_bytes": "22020096", + "max_gas": "100000000" + }, + "evidence": { + "max_age_duration": "172800000000000", + "max_age_num_blocks": "100000", + "max_bytes": "1048576" + }, + "validator": { + "pub_key_types": [ + "ed25519" + ] + }, + "version": { + "app": "0" + } + }, + "genesis_time": "2023-09-07T23:21:17.073977743Z", + "initial_height": "71", + "validators": [ + { + "address": "21D28714BEAA706095179C5BC4AE4B2B3C0D6988", + "name": "localjuno", + "power": "1", + "pub_key": { + "type": "tendermint/PubKeyEd25519", + "value": "9cSyCx910OX4PtUt+iYO6sF6TXi4OIDclvVEDxThXu8=" + } + } + ] +} \ No newline at end of file diff --git a/x/feepay/client/cli/query.go b/x/feepay/client/cli/query.go new file mode 100644 index 000000000..b31f78e63 --- /dev/null +++ b/x/feepay/client/cli/query.go @@ -0,0 +1,100 @@ +package cli + +import ( + "context" + "fmt" + + "github.com/spf13/cobra" + + "github.com/cosmos/cosmos-sdk/client" + "github.com/cosmos/cosmos-sdk/client/flags" + + "github.com/CosmosContracts/juno/v17/x/feepay/types" +) + +// NewQueryCmd returns the cli query commands for this module +func NewQueryCmd() *cobra.Command { + feepayQueryCmd := &cobra.Command{ + Use: types.ModuleName, + Short: fmt.Sprintf("Querying commands for the %s module", types.ModuleName), + DisableFlagParsing: true, + SuggestionsMinimumDistance: 2, + RunE: client.ValidateCmd, + } + + feepayQueryCmd.AddCommand( + NewQueryFeePayContract(), + NewQueryFeePayContracts(), + ) + + return feepayQueryCmd +} + +// Query all fee pay contracts +func NewQueryFeePayContract() *cobra.Command { + cmd := &cobra.Command{ + Use: "contract [address]", + Short: "Query a FeePay contract by address", + Args: cobra.ExactArgs(1), + RunE: func(cmd *cobra.Command, args []string) error { + clientCtx, err := client.GetClientQueryContext(cmd) + if err != nil { + return err + } + queryClient := types.NewQueryClient(clientCtx) + + address := args[0] + + req := &types.QueryFeePayContract{ + ContractAddress: address, + } + + res, err := queryClient.FeePayContract(context.Background(), req) + if err != nil { + return err + } + + return clientCtx.PrintProto(res) + }, + } + + flags.AddQueryFlagsToCmd(cmd) + + return cmd +} + +// Query all fee pay contracts +func NewQueryFeePayContracts() *cobra.Command { + cmd := &cobra.Command{ + Use: "contracts", + Short: "Query all FeePay contracts", + Args: cobra.NoArgs, + RunE: func(cmd *cobra.Command, _ []string) error { + clientCtx, err := client.GetClientQueryContext(cmd) + if err != nil { + return err + } + queryClient := types.NewQueryClient(clientCtx) + + pageReq, err := client.ReadPageRequest(cmd.Flags()) + if err != nil { + return err + } + + req := &types.QueryFeePayContracts{ + Pagination: pageReq, + } + + res, err := queryClient.FeePayContracts(context.Background(), req) + if err != nil { + return err + } + + return clientCtx.PrintProto(res) + }, + } + + flags.AddQueryFlagsToCmd(cmd) + flags.AddPaginationFlagsToCmd(cmd, "all-contracts") + return cmd +} diff --git a/x/feepay/client/cli/tx.go b/x/feepay/client/cli/tx.go index ee6a7e53d..3366f9e0d 100644 --- a/x/feepay/client/cli/tx.go +++ b/x/feepay/client/cli/tx.go @@ -50,6 +50,8 @@ func NewRegisterFeePayContract() *cobra.Command { wallet_limit := args[1] dec_limit, err := strconv.ParseUint(wallet_limit, 10, 64) + // todo bech32 validation + if err != nil { return err } diff --git a/x/feepay/keeper/grpc_query.go b/x/feepay/keeper/grpc_query.go new file mode 100644 index 000000000..baa9d182e --- /dev/null +++ b/x/feepay/keeper/grpc_query.go @@ -0,0 +1,52 @@ +package keeper + +import ( + "context" + + sdk "github.com/cosmos/cosmos-sdk/types" + + "github.com/CosmosContracts/juno/v17/x/feepay/types" + "github.com/cosmos/cosmos-sdk/types/query" +) + +var _ types.QueryServer = Querier{} + +// Querier defines a wrapper around the x/feepay keeper providing gRPC method +// handlers. +type Querier struct { + Keeper +} + +func NewQuerier(k Keeper) Querier { + return Querier{Keeper: k} +} + +// FeePayContract implements types.QueryServer. +func (q Querier) FeePayContract(ctx context.Context, req *types.QueryFeePayContract) (*types.QueryFeePayContractResponse, error) { + sdkCtx := sdk.UnwrapSDKContext(ctx) + + contract, err := q.Keeper.GetContract(sdkCtx, req.ContractAddress) + + return &types.QueryFeePayContractResponse{ + Contract: contract, + }, err +} + +// FeePayContracts implements types.QueryServer. +func (q Querier) FeePayContracts(ctx context.Context, req *types.QueryFeePayContracts) (*types.QueryFeePayContractsResponse, error) { + + sdkCtx := sdk.UnwrapSDKContext(ctx) + + contracts, err := q.Keeper.GetAllContracts(sdkCtx) + + if err != nil { + return nil, err + } + + return &types.QueryFeePayContractsResponse{ + Contracts: contracts, + Pagination: &query.PageResponse{ + Total: 3, + }, + }, nil +} diff --git a/x/feepay/keeper/keeper.go b/x/feepay/keeper/keeper.go index ef45186d6..e7c511158 100644 --- a/x/feepay/keeper/keeper.go +++ b/x/feepay/keeper/keeper.go @@ -16,6 +16,11 @@ import ( errorsmod "cosmossdk.io/errors" types "github.com/CosmosContracts/juno/v17/x/feepay/types" revtypes "github.com/CosmosContracts/juno/v17/x/feeshare/types" + bankkeeper "github.com/cosmos/cosmos-sdk/x/bank/keeper" +) + +const ( + StoreKeyContracts = "contracts" ) // Keeper of this module maintains collections of feeshares for contracts @@ -24,7 +29,7 @@ type Keeper struct { storeKey storetypes.StoreKey cdc codec.BinaryCodec - bankKeeper revtypes.BankKeeper + bankKeeper *bankkeeper.BaseKeeper wasmKeeper wasmkeeper.Keeper accountKeeper revtypes.AccountKeeper @@ -40,7 +45,7 @@ type Keeper struct { func NewKeeper( storeKey storetypes.StoreKey, cdc codec.BinaryCodec, - bk revtypes.BankKeeper, + bk *bankkeeper.BaseKeeper, wk wasmkeeper.Keeper, ak revtypes.AccountKeeper, feeCollector string, @@ -69,6 +74,8 @@ func (k Keeper) Logger(ctx sdk.Context) log.Logger { return ctx.Logger().With("module", fmt.Sprintf("x/%s", revtypes.ModuleName)) } +// === + // Check if a contract is associated with a FeePay contract func (k Keeper) IsValidContract(ctx sdk.Context, contractAddr string) error { store := prefix.NewStore(ctx.KVStore(k.storeKey), []byte("contracts")) @@ -82,19 +89,86 @@ func (k Keeper) IsValidContract(ctx sdk.Context, contractAddr string) error { } } +// Get a contract from KV store +func (k Keeper) GetContract(ctx sdk.Context, contractAddress string) (*types.FeePayContract, error) { + + // Return false because the contract was already registered + if err := k.IsValidContract(ctx, contractAddress); err != nil { + return nil, err + } + + store := prefix.NewStore(ctx.KVStore(k.storeKey), []byte(StoreKeyContracts)) + + key := []byte(contractAddress) + bz := store.Get(key) + + var fpc types.FeePayContract + if err := k.cdc.Unmarshal(bz, &fpc); err != nil { + return nil, err + } + + return &fpc, nil +} + +func (k Keeper) UpdateContractBalance(ctx sdk.Context, contractAddress string, newBalance uint64) error { + + // TODO: Do we need torecheck this? (remove if duplicate) + // Return false because the contract was already registered + if err := k.IsValidContract(ctx, contractAddress); err != nil { + return err + } + + store := prefix.NewStore(ctx.KVStore(k.storeKey), []byte(StoreKeyContracts)) + + key := []byte(contractAddress) + bz := store.Get(key) + + var fpc types.FeePayContract + if err := k.cdc.Unmarshal(bz, &fpc); err != nil { + return err + } + + fpc.Balance = newBalance + + store.Set(key, k.cdc.MustMarshal(&fpc)) + return nil +} + +// Get all registered fee pay contracts +func (k Keeper) GetAllContracts(ctx sdk.Context) ([]types.FeePayContract, error) { + store := prefix.NewStore(ctx.KVStore(k.storeKey), []byte(StoreKeyContracts)) + + var contracts []types.FeePayContract + iterator := sdk.KVStorePrefixIterator(store, nil) + + defer iterator.Close() + for ; iterator.Valid(); iterator.Next() { + var contract types.FeePayContract + k.cdc.MustUnmarshal(iterator.Value(), &contract) + contracts = append(contracts, contract) + } + + return contracts, nil +} + // Register the contract in the module store func (k Keeper) RegisterContract(ctx sdk.Context, fpc *types.FeePayContract) error { // Return false because the contract was already registered - if err := k.IsValidContract(ctx, fpc.ContractAddress); err != nil { - return err + if err := k.IsValidContract(ctx, fpc.ContractAddress); err == nil { + return errorsmod.Wrapf(errors.New("contract already registered"), "contract %s already registered", fpc.ContractAddress) } + ctx.Logger().Error("Registering contract", "Contract is not registered!") + // Register the new fee pay contract in the KV store + // TODO: change this to be the function GetContract() store := prefix.NewStore(ctx.KVStore(k.storeKey), []byte("contracts")) key := []byte(fpc.ContractAddress) bz := k.cdc.MustMarshal(fpc) + ctx.Logger().Error("Registering contract", "Key", key, "Value", bz) + store.Set(key, bz) return nil } @@ -102,6 +176,8 @@ func (k Keeper) RegisterContract(ctx sdk.Context, fpc *types.FeePayContract) err // Fund an existing fee pay contract func (k Keeper) FundContract(ctx sdk.Context, mfc *types.MsgFundFeePayContract) error { + ctx.Logger().Error("Funding contract", "Contract", mfc.ContractAddress) + // Return false because the contract was already registered if err := k.IsValidContract(ctx, mfc.ContractAddress); err != nil { return err @@ -115,29 +191,33 @@ func (k Keeper) FundContract(ctx sdk.Context, mfc *types.MsgFundFeePayContract) } } + ctx.Logger().Error("Funding contract", "Amount", transferCoin) + // Confirm the sender has enough funds to fund the contract addr, err := sdk.AccAddressFromBech32(mfc.SenderAddress) if err != nil { return err } - err = k.bankKeeper.SendCoinsFromAccountToModule(ctx, addr, types.ModuleName, sdk.NewCoins(transferCoin)) - if err != nil { + ctx.Logger().Error("Funding contract", "Address", addr) + + if err := k.bankKeeper.SendCoinsFromAccountToModule(ctx, addr, types.ModuleName, sdk.NewCoins(transferCoin)); err != nil { + ctx.Logger().Error("Funding contract", "Error", err) return err } - // Get existing fee pay contract from store - store := prefix.NewStore(ctx.KVStore(k.storeKey), []byte("contracts")) - key := []byte(mfc.ContractAddress) - bz := store.Get(key) + ctx.Logger().Error("Funding contract", "Sent Coins", true) - var fpc types.FeePayContract - k.cdc.MustUnmarshal(bz, &fpc) + // Get existing fee pay contract from store + fpc, err := k.GetContract(ctx, mfc.ContractAddress) + if err != nil { + return err + } // Increment the fpc balance fpc.Balance += transferCoin.Amount.Uint64() + k.UpdateContractBalance(ctx, mfc.ContractAddress, fpc.Balance) - // Update the balance in KV store, return success - store.Set(key, k.cdc.MustMarshal(&fpc)) + ctx.Logger().Error("Funded contract", "New Details", fpc) return nil } diff --git a/x/feepay/keeper/msg_server.go b/x/feepay/keeper/msg_server.go index 6e306eabd..424a0e50f 100644 --- a/x/feepay/keeper/msg_server.go +++ b/x/feepay/keeper/msg_server.go @@ -13,6 +13,7 @@ import ( var _ types.MsgServer = &Keeper{} +// Register a new fee pay contract. func (k Keeper) RegisterFeePayContract(goCtx context.Context, msg *types.MsgRegisterFeePayContract) (*types.MsgRegisterFeePayContractResponse, error) { ctx := sdk.UnwrapSDKContext(goCtx) return &types.MsgRegisterFeePayContractResponse{}, k.RegisterContract(ctx, msg.Contract) diff --git a/x/feepay/module.go b/x/feepay/module.go index 5c15b094e..e262188c1 100644 --- a/x/feepay/module.go +++ b/x/feepay/module.go @@ -96,7 +96,7 @@ func (AppModuleBasic) GetTxCmd() *cobra.Command { // GetQueryCmd returns the fees module's root query command. func (AppModuleBasic) GetQueryCmd() *cobra.Command { - return nil + return cli.NewQueryCmd() } // ___________________________________________________________________________ @@ -147,14 +147,7 @@ func (am AppModule) QuerierRoute() string { // module-specific GRPC queries. func (am AppModule) RegisterServices(cfg module.Configurator) { types.RegisterMsgServer(cfg.MsgServer(), am.keeper) - - // TODO: UNCOMMENT FOR QUERIES - // types.RegisterQueryServer(cfg.QueryServer(), keeper.NewQuerier(am.keeper)) - - // m := keeper.NewMigrator(am.keeper, am.legacySubspace) - // if err := cfg.RegisterMigration(types.ModuleName, 1, m.Migrate1to2); err != nil { - // panic(fmt.Sprintf("failed to migrate x/%s from version 1 to 2: %v", types.ModuleName, err)) - // } + types.RegisterQueryServer(cfg.QueryServer(), keeper.NewQuerier(am.keeper)) } // BeginBlock executes all ABCI BeginBlock logic respective to the fees module. diff --git a/x/feepay/types/codec.go b/x/feepay/types/codec.go index 5fee01649..76ae5d5b4 100644 --- a/x/feepay/types/codec.go +++ b/x/feepay/types/codec.go @@ -25,7 +25,7 @@ var ( const ( // Amino names registerFeePayContract = "juno/MsgRegisterFeePayContract" - FundFeePayContract = "juno/MsgFundFeePayContract" + fundFeePayContract = "juno/MsgFundFeePayContract" updateFeeShareParams = "juno/MsgFeePayUpdateParams" ) @@ -58,6 +58,6 @@ func RegisterInterfaces(registry codectypes.InterfaceRegistry) { // Amino JSON serialization and EIP-712 compatibility. func RegisterLegacyAminoCodec(cdc *codec.LegacyAmino) { cdc.RegisterConcrete(&MsgRegisterFeePayContract{}, registerFeePayContract, nil) - cdc.RegisterConcrete(&MsgFundFeePayContract{}, FundFeePayContract, nil) + cdc.RegisterConcrete(&MsgFundFeePayContract{}, fundFeePayContract, nil) cdc.RegisterConcrete(&MsgUpdateParams{}, updateFeeShareParams, nil) } diff --git a/x/feepay/types/query.pb.go b/x/feepay/types/query.pb.go index 9a008d27a..31dd3217b 100644 --- a/x/feepay/types/query.pb.go +++ b/x/feepay/types/query.pb.go @@ -4,12 +4,19 @@ package types import ( + context "context" fmt "fmt" - _ "github.com/cosmos/cosmos-sdk/types/query" + query "github.com/cosmos/cosmos-sdk/types/query" _ "github.com/cosmos/gogoproto/gogoproto" + grpc1 "github.com/cosmos/gogoproto/grpc" proto "github.com/cosmos/gogoproto/proto" _ "google.golang.org/genproto/googleapis/api/annotations" + grpc "google.golang.org/grpc" + codes "google.golang.org/grpc/codes" + status "google.golang.org/grpc/status" + io "io" math "math" + math_bits "math/bits" ) // Reference imports to suppress errors if they are not otherwise used. @@ -23,22 +30,1040 @@ var _ = math.Inf // proto package needs to be updated. const _ = proto.GoGoProtoPackageIsVersion3 // please upgrade the proto package +// QueryFeePayContract retrieves a single fee pay contract +type QueryFeePayContract struct { + // contract_address defines the address of the fee pay contract + ContractAddress string `protobuf:"bytes,1,opt,name=contract_address,json=contractAddress,proto3" json:"contract_address,omitempty"` +} + +func (m *QueryFeePayContract) Reset() { *m = QueryFeePayContract{} } +func (m *QueryFeePayContract) String() string { return proto.CompactTextString(m) } +func (*QueryFeePayContract) ProtoMessage() {} +func (*QueryFeePayContract) Descriptor() ([]byte, []int) { + return fileDescriptor_d6539df905bf35ca, []int{0} +} +func (m *QueryFeePayContract) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *QueryFeePayContract) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_QueryFeePayContract.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 *QueryFeePayContract) XXX_Merge(src proto.Message) { + xxx_messageInfo_QueryFeePayContract.Merge(m, src) +} +func (m *QueryFeePayContract) XXX_Size() int { + return m.Size() +} +func (m *QueryFeePayContract) XXX_DiscardUnknown() { + xxx_messageInfo_QueryFeePayContract.DiscardUnknown(m) +} + +var xxx_messageInfo_QueryFeePayContract proto.InternalMessageInfo + +func (m *QueryFeePayContract) GetContractAddress() string { + if m != nil { + return m.ContractAddress + } + return "" +} + +// QueryFeePayContractResponse defines the response for retrieving a single fee pay contract +type QueryFeePayContractResponse struct { + // contract defines the fee pay contract + Contract *FeePayContract `protobuf:"bytes,1,opt,name=contract,proto3" json:"contract,omitempty"` +} + +func (m *QueryFeePayContractResponse) Reset() { *m = QueryFeePayContractResponse{} } +func (m *QueryFeePayContractResponse) String() string { return proto.CompactTextString(m) } +func (*QueryFeePayContractResponse) ProtoMessage() {} +func (*QueryFeePayContractResponse) Descriptor() ([]byte, []int) { + return fileDescriptor_d6539df905bf35ca, []int{1} +} +func (m *QueryFeePayContractResponse) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *QueryFeePayContractResponse) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_QueryFeePayContractResponse.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 *QueryFeePayContractResponse) XXX_Merge(src proto.Message) { + xxx_messageInfo_QueryFeePayContractResponse.Merge(m, src) +} +func (m *QueryFeePayContractResponse) XXX_Size() int { + return m.Size() +} +func (m *QueryFeePayContractResponse) XXX_DiscardUnknown() { + xxx_messageInfo_QueryFeePayContractResponse.DiscardUnknown(m) +} + +var xxx_messageInfo_QueryFeePayContractResponse proto.InternalMessageInfo + +func (m *QueryFeePayContractResponse) GetContract() *FeePayContract { + if m != nil { + return m.Contract + } + return nil +} + +// Message for querying a list of fee pay contracts +type QueryFeePayContracts struct { + // Pagination defines an optional pagination for the request. + Pagination *query.PageRequest `protobuf:"bytes,1,opt,name=pagination,proto3" json:"pagination,omitempty"` +} + +func (m *QueryFeePayContracts) Reset() { *m = QueryFeePayContracts{} } +func (m *QueryFeePayContracts) String() string { return proto.CompactTextString(m) } +func (*QueryFeePayContracts) ProtoMessage() {} +func (*QueryFeePayContracts) Descriptor() ([]byte, []int) { + return fileDescriptor_d6539df905bf35ca, []int{2} +} +func (m *QueryFeePayContracts) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *QueryFeePayContracts) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_QueryFeePayContracts.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 *QueryFeePayContracts) XXX_Merge(src proto.Message) { + xxx_messageInfo_QueryFeePayContracts.Merge(m, src) +} +func (m *QueryFeePayContracts) XXX_Size() int { + return m.Size() +} +func (m *QueryFeePayContracts) XXX_DiscardUnknown() { + xxx_messageInfo_QueryFeePayContracts.DiscardUnknown(m) +} + +var xxx_messageInfo_QueryFeePayContracts proto.InternalMessageInfo + +func (m *QueryFeePayContracts) GetPagination() *query.PageRequest { + if m != nil { + return m.Pagination + } + return nil +} + +// The response for querying all fee pay contracts +type QueryFeePayContractsResponse struct { + // A slice of all the stored fee pay contracts + Contracts []FeePayContract `protobuf:"bytes,1,rep,name=contracts,proto3" json:"contracts"` + // pagination defines the pagination in the response. + Pagination *query.PageResponse `protobuf:"bytes,2,opt,name=pagination,proto3" json:"pagination,omitempty"` +} + +func (m *QueryFeePayContractsResponse) Reset() { *m = QueryFeePayContractsResponse{} } +func (m *QueryFeePayContractsResponse) String() string { return proto.CompactTextString(m) } +func (*QueryFeePayContractsResponse) ProtoMessage() {} +func (*QueryFeePayContractsResponse) Descriptor() ([]byte, []int) { + return fileDescriptor_d6539df905bf35ca, []int{3} +} +func (m *QueryFeePayContractsResponse) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *QueryFeePayContractsResponse) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_QueryFeePayContractsResponse.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 *QueryFeePayContractsResponse) XXX_Merge(src proto.Message) { + xxx_messageInfo_QueryFeePayContractsResponse.Merge(m, src) +} +func (m *QueryFeePayContractsResponse) XXX_Size() int { + return m.Size() +} +func (m *QueryFeePayContractsResponse) XXX_DiscardUnknown() { + xxx_messageInfo_QueryFeePayContractsResponse.DiscardUnknown(m) +} + +var xxx_messageInfo_QueryFeePayContractsResponse proto.InternalMessageInfo + +func (m *QueryFeePayContractsResponse) GetContracts() []FeePayContract { + if m != nil { + return m.Contracts + } + return nil +} + +func (m *QueryFeePayContractsResponse) GetPagination() *query.PageResponse { + if m != nil { + return m.Pagination + } + return nil +} + +func init() { + proto.RegisterType((*QueryFeePayContract)(nil), "juno.feepay.v1.QueryFeePayContract") + proto.RegisterType((*QueryFeePayContractResponse)(nil), "juno.feepay.v1.QueryFeePayContractResponse") + proto.RegisterType((*QueryFeePayContracts)(nil), "juno.feepay.v1.QueryFeePayContracts") + proto.RegisterType((*QueryFeePayContractsResponse)(nil), "juno.feepay.v1.QueryFeePayContractsResponse") +} + func init() { proto.RegisterFile("juno/feepay/v1/query.proto", fileDescriptor_d6539df905bf35ca) } var fileDescriptor_d6539df905bf35ca = []byte{ - // 210 bytes of a gzipped FileDescriptorProto - 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x5c, 0x8e, 0x31, 0x4e, 0xc4, 0x30, - 0x10, 0x45, 0x93, 0x86, 0x82, 0x82, 0x02, 0x51, 0x05, 0xe4, 0x03, 0x50, 0x78, 0x64, 0x71, 0x03, - 0xb6, 0xe1, 0x0c, 0x74, 0xe3, 0x68, 0x30, 0x46, 0xac, 0xc7, 0xc4, 0x93, 0x88, 0xdc, 0x82, 0x63, - 0x51, 0xa6, 0xa4, 0x44, 0xc9, 0x45, 0x56, 0xb1, 0x93, 0x26, 0xdd, 0x97, 0xde, 0xcc, 0xfb, 0xff, - 0xba, 0xf9, 0xe8, 0x03, 0xc3, 0x1b, 0x51, 0xc4, 0x11, 0x06, 0x03, 0x5f, 0x3d, 0x75, 0xa3, 0x8e, - 0x1d, 0x0b, 0xdf, 0xde, 0xac, 0x4c, 0x17, 0xa6, 0x07, 0xd3, 0x3c, 0xb6, 0x9c, 0xce, 0x9c, 0xc0, - 0x62, 0xa2, 0x72, 0x08, 0x83, 0xb1, 0x24, 0x68, 0x20, 0xa2, 0xf3, 0x01, 0xc5, 0x73, 0x28, 0xbf, - 0xcd, 0xc3, 0xc1, 0xeb, 0x28, 0x50, 0xf2, 0x69, 0xa3, 0xf7, 0x07, 0xba, 0x75, 0x14, 0x78, 0xe7, - 0xd8, 0x71, 0x8e, 0xb0, 0xa6, 0x5d, 0xe8, 0x98, 0xdd, 0x27, 0x01, 0x46, 0x0f, 0x18, 0x02, 0x4b, - 0x6e, 0xdb, 0x84, 0xcf, 0x2f, 0xbf, 0xb3, 0xaa, 0xa7, 0x59, 0xd5, 0xff, 0xb3, 0xaa, 0x7f, 0x16, - 0x55, 0x4d, 0x8b, 0xaa, 0xfe, 0x16, 0x55, 0xbd, 0x6a, 0xe7, 0xe5, 0xbd, 0xb7, 0xba, 0xe5, 0x33, - 0x9c, 0xf2, 0xfe, 0x13, 0x07, 0xe9, 0xb0, 0x95, 0x04, 0x79, 0xc5, 0xf7, 0xbe, 0x43, 0xc6, 0x48, - 0xc9, 0x5e, 0x65, 0xe1, 0xd3, 0x25, 0x00, 0x00, 0xff, 0xff, 0x82, 0xb6, 0xd6, 0xb1, 0x19, 0x01, - 0x00, 0x00, + // 452 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x8c, 0x93, 0xcf, 0x6b, 0x14, 0x31, + 0x14, 0xc7, 0x37, 0xeb, 0x0f, 0x6c, 0x84, 0x56, 0x62, 0x91, 0x32, 0x2d, 0x51, 0x46, 0x51, 0x6b, + 0x25, 0x61, 0xea, 0xcd, 0x93, 0x6e, 0xa1, 0x7a, 0xac, 0x73, 0xd3, 0x83, 0x92, 0x9d, 0x3e, 0xe3, + 0x88, 0x4d, 0xa6, 0x93, 0xcc, 0xe2, 0x20, 0x5e, 0x04, 0xef, 0x82, 0xf8, 0x37, 0x78, 0xf0, 0x1f, + 0xe9, 0xb1, 0xe0, 0xc5, 0x93, 0xc8, 0xae, 0x7f, 0x48, 0x99, 0x64, 0x66, 0xda, 0x0e, 0x03, 0xbb, + 0xb7, 0x47, 0xde, 0x7b, 0xdf, 0xf7, 0xc9, 0xf7, 0x25, 0x38, 0x78, 0x5f, 0x28, 0xcd, 0xdf, 0x02, + 0x64, 0xa2, 0xe4, 0x93, 0x88, 0x1f, 0x16, 0x90, 0x97, 0x2c, 0xcb, 0xb5, 0xd5, 0x64, 0xb9, 0xca, + 0x31, 0x9f, 0x63, 0x93, 0x28, 0x78, 0x90, 0x68, 0x73, 0xa0, 0x0d, 0x1f, 0x0b, 0x03, 0xbe, 0x90, + 0x4f, 0xa2, 0x31, 0x58, 0x11, 0xf1, 0x4c, 0xc8, 0x54, 0x09, 0x9b, 0x6a, 0xe5, 0x7b, 0x83, 0x8d, + 0x8e, 0xae, 0x04, 0x05, 0x26, 0x35, 0x75, 0x76, 0xbd, 0x93, 0xad, 0x67, 0xf8, 0xe4, 0xaa, 0xd4, + 0x52, 0xbb, 0x90, 0x57, 0x51, 0x23, 0x28, 0xb5, 0x96, 0x1f, 0x80, 0x8b, 0x2c, 0xe5, 0x42, 0x29, + 0x6d, 0xdd, 0xb4, 0x5a, 0x30, 0x7c, 0x82, 0xaf, 0xbf, 0xa8, 0x80, 0x76, 0x01, 0xf6, 0x44, 0xb9, + 0xa3, 0x95, 0xcd, 0x45, 0x62, 0xc9, 0x26, 0xbe, 0x96, 0xd4, 0xf1, 0x1b, 0xb1, 0xbf, 0x9f, 0x83, + 0x31, 0x6b, 0xe8, 0x16, 0xba, 0xbf, 0x14, 0xaf, 0x34, 0xe7, 0x4f, 0xfd, 0x71, 0xf8, 0x12, 0xaf, + 0xf7, 0x28, 0xc4, 0x60, 0x32, 0xad, 0x0c, 0x90, 0xc7, 0xf8, 0x4a, 0xd3, 0xe1, 0x14, 0xae, 0x6e, + 0x53, 0x76, 0xde, 0x1e, 0xd6, 0xe9, 0x6c, 0xeb, 0xc3, 0xd7, 0x78, 0xb5, 0x47, 0xda, 0x90, 0x5d, + 0x8c, 0x4f, 0x7d, 0xab, 0x55, 0xef, 0x32, 0x6f, 0x32, 0xab, 0x4c, 0x66, 0x7e, 0x1b, 0xb5, 0xc9, + 0x6c, 0x4f, 0x48, 0x88, 0xe1, 0xb0, 0x00, 0x63, 0xe3, 0x33, 0x9d, 0xe1, 0x2f, 0x84, 0x37, 0xfa, + 0x06, 0xb4, 0xf0, 0x23, 0xbc, 0xd4, 0xc0, 0x54, 0xf7, 0xbf, 0x30, 0x9f, 0x7e, 0x74, 0xf1, 0xe8, + 0xef, 0xcd, 0x41, 0x7c, 0xda, 0x46, 0x9e, 0x9d, 0x83, 0x1d, 0x3a, 0xd8, 0x7b, 0x73, 0x61, 0x3d, + 0xc0, 0x59, 0xda, 0xed, 0x9f, 0x43, 0x7c, 0xc9, 0xd1, 0x92, 0x1f, 0x08, 0x2f, 0x77, 0x16, 0x76, + 0xbb, 0x8b, 0xd5, 0x73, 0xaf, 0x60, 0x6b, 0x81, 0xa2, 0x66, 0x74, 0x18, 0x7d, 0xf9, 0xfd, 0xff, + 0xfb, 0x70, 0x8b, 0x6c, 0xf2, 0xde, 0x37, 0xc7, 0x3f, 0x75, 0x1f, 0xc8, 0x67, 0xf2, 0x15, 0xe1, + 0x95, 0xee, 0xae, 0xee, 0x2c, 0x30, 0xd3, 0x04, 0x0f, 0x17, 0xa9, 0x6a, 0xd1, 0xa8, 0x43, 0x5b, + 0x23, 0x37, 0xfa, 0xd1, 0x46, 0xcf, 0x8f, 0xa6, 0x14, 0x1d, 0x4f, 0x29, 0xfa, 0x37, 0xa5, 0xe8, + 0xdb, 0x8c, 0x0e, 0x8e, 0x67, 0x74, 0xf0, 0x67, 0x46, 0x07, 0xaf, 0x98, 0x4c, 0xed, 0xbb, 0x62, + 0xcc, 0x12, 0x7d, 0xc0, 0x77, 0xdc, 0x0a, 0x5a, 0x75, 0xaf, 0xf5, 0xb1, 0x51, 0xb3, 0x65, 0x06, + 0x66, 0x7c, 0xd9, 0xfd, 0x92, 0x47, 0x27, 0x01, 0x00, 0x00, 0xff, 0xff, 0x9a, 0x34, 0x0f, 0x08, + 0xee, 0x03, 0x00, 0x00, +} + +// Reference imports to suppress errors if they are not otherwise used. +var _ context.Context +var _ grpc.ClientConn + +// This is a compile-time assertion to ensure that this generated file +// is compatible with the grpc package it is being compiled against. +const _ = grpc.SupportPackageIsVersion4 + +// QueryClient is the client API for Query service. +// +// For semantics around ctx use and closing/ending streaming RPCs, please refer to https://godoc.org/google.golang.org/grpc#ClientConn.NewStream. +type QueryClient interface { + // FeePayContract queries a single fee pay contract by address + FeePayContract(ctx context.Context, in *QueryFeePayContract, opts ...grpc.CallOption) (*QueryFeePayContractResponse, error) + // Retrieve all fee pay contracts + FeePayContracts(ctx context.Context, in *QueryFeePayContracts, opts ...grpc.CallOption) (*QueryFeePayContractsResponse, error) +} + +type queryClient struct { + cc grpc1.ClientConn +} + +func NewQueryClient(cc grpc1.ClientConn) QueryClient { + return &queryClient{cc} +} + +func (c *queryClient) FeePayContract(ctx context.Context, in *QueryFeePayContract, opts ...grpc.CallOption) (*QueryFeePayContractResponse, error) { + out := new(QueryFeePayContractResponse) + err := c.cc.Invoke(ctx, "/juno.feepay.v1.Query/FeePayContract", in, out, opts...) + if err != nil { + return nil, err + } + return out, nil } + +func (c *queryClient) FeePayContracts(ctx context.Context, in *QueryFeePayContracts, opts ...grpc.CallOption) (*QueryFeePayContractsResponse, error) { + out := new(QueryFeePayContractsResponse) + err := c.cc.Invoke(ctx, "/juno.feepay.v1.Query/FeePayContracts", in, out, opts...) + if err != nil { + return nil, err + } + return out, nil +} + +// QueryServer is the server API for Query service. +type QueryServer interface { + // FeePayContract queries a single fee pay contract by address + FeePayContract(context.Context, *QueryFeePayContract) (*QueryFeePayContractResponse, error) + // Retrieve all fee pay contracts + FeePayContracts(context.Context, *QueryFeePayContracts) (*QueryFeePayContractsResponse, error) +} + +// UnimplementedQueryServer can be embedded to have forward compatible implementations. +type UnimplementedQueryServer struct { +} + +func (*UnimplementedQueryServer) FeePayContract(ctx context.Context, req *QueryFeePayContract) (*QueryFeePayContractResponse, error) { + return nil, status.Errorf(codes.Unimplemented, "method FeePayContract not implemented") +} +func (*UnimplementedQueryServer) FeePayContracts(ctx context.Context, req *QueryFeePayContracts) (*QueryFeePayContractsResponse, error) { + return nil, status.Errorf(codes.Unimplemented, "method FeePayContracts not implemented") +} + +func RegisterQueryServer(s grpc1.Server, srv QueryServer) { + s.RegisterService(&_Query_serviceDesc, srv) +} + +func _Query_FeePayContract_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(QueryFeePayContract) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(QueryServer).FeePayContract(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: "/juno.feepay.v1.Query/FeePayContract", + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(QueryServer).FeePayContract(ctx, req.(*QueryFeePayContract)) + } + return interceptor(ctx, in, info, handler) +} + +func _Query_FeePayContracts_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(QueryFeePayContracts) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(QueryServer).FeePayContracts(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: "/juno.feepay.v1.Query/FeePayContracts", + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(QueryServer).FeePayContracts(ctx, req.(*QueryFeePayContracts)) + } + return interceptor(ctx, in, info, handler) +} + +var _Query_serviceDesc = grpc.ServiceDesc{ + ServiceName: "juno.feepay.v1.Query", + HandlerType: (*QueryServer)(nil), + Methods: []grpc.MethodDesc{ + { + MethodName: "FeePayContract", + Handler: _Query_FeePayContract_Handler, + }, + { + MethodName: "FeePayContracts", + Handler: _Query_FeePayContracts_Handler, + }, + }, + Streams: []grpc.StreamDesc{}, + Metadata: "juno/feepay/v1/query.proto", +} + +func (m *QueryFeePayContract) 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 *QueryFeePayContract) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *QueryFeePayContract) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + if len(m.ContractAddress) > 0 { + i -= len(m.ContractAddress) + copy(dAtA[i:], m.ContractAddress) + i = encodeVarintQuery(dAtA, i, uint64(len(m.ContractAddress))) + i-- + dAtA[i] = 0xa + } + return len(dAtA) - i, nil +} + +func (m *QueryFeePayContractResponse) 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 *QueryFeePayContractResponse) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *QueryFeePayContractResponse) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + if m.Contract != nil { + { + size, err := m.Contract.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 *QueryFeePayContracts) 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 *QueryFeePayContracts) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *QueryFeePayContracts) 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] = 0xa + } + return len(dAtA) - i, nil +} + +func (m *QueryFeePayContractsResponse) 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 *QueryFeePayContractsResponse) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *QueryFeePayContractsResponse) 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.Contracts) > 0 { + for iNdEx := len(m.Contracts) - 1; iNdEx >= 0; iNdEx-- { + { + size, err := m.Contracts[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 encodeVarintQuery(dAtA []byte, offset int, v uint64) int { + offset -= sovQuery(v) + base := offset + for v >= 1<<7 { + dAtA[offset] = uint8(v&0x7f | 0x80) + v >>= 7 + offset++ + } + dAtA[offset] = uint8(v) + return base +} +func (m *QueryFeePayContract) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + l = len(m.ContractAddress) + if l > 0 { + n += 1 + l + sovQuery(uint64(l)) + } + return n +} + +func (m *QueryFeePayContractResponse) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + if m.Contract != nil { + l = m.Contract.Size() + n += 1 + l + sovQuery(uint64(l)) + } + return n +} + +func (m *QueryFeePayContracts) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + if m.Pagination != nil { + l = m.Pagination.Size() + n += 1 + l + sovQuery(uint64(l)) + } + return n +} + +func (m *QueryFeePayContractsResponse) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + if len(m.Contracts) > 0 { + for _, e := range m.Contracts { + 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 sovQuery(x uint64) (n int) { + return (math_bits.Len64(x|1) + 6) / 7 +} +func sozQuery(x uint64) (n int) { + return sovQuery(uint64((x << 1) ^ uint64((int64(x) >> 63)))) +} +func (m *QueryFeePayContract) 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: QueryFeePayContract: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: QueryFeePayContract: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field ContractAddress", 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.ContractAddress = 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 *QueryFeePayContractResponse) 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: QueryFeePayContractResponse: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: QueryFeePayContractResponse: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Contract", 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.Contract == nil { + m.Contract = &FeePayContract{} + } + if err := m.Contract.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 *QueryFeePayContracts) 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: QueryFeePayContracts: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: QueryFeePayContracts: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + 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 *QueryFeePayContractsResponse) 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: QueryFeePayContractsResponse: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: QueryFeePayContractsResponse: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Contracts", 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.Contracts = append(m.Contracts, FeePayContract{}) + if err := m.Contracts[len(m.Contracts)-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 skipQuery(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, ErrIntOverflowQuery + } + 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, ErrIntOverflowQuery + } + 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, ErrIntOverflowQuery + } + 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, ErrInvalidLengthQuery + } + iNdEx += length + case 3: + depth++ + case 4: + if depth == 0 { + return 0, ErrUnexpectedEndOfGroupQuery + } + depth-- + case 5: + iNdEx += 4 + default: + return 0, fmt.Errorf("proto: illegal wireType %d", wireType) + } + if iNdEx < 0 { + return 0, ErrInvalidLengthQuery + } + if depth == 0 { + return iNdEx, nil + } + } + return 0, io.ErrUnexpectedEOF +} + +var ( + ErrInvalidLengthQuery = fmt.Errorf("proto: negative length found during unmarshaling") + ErrIntOverflowQuery = fmt.Errorf("proto: integer overflow") + ErrUnexpectedEndOfGroupQuery = fmt.Errorf("proto: unexpected end of group") +) diff --git a/x/feepay/types/query.pb.gw.go b/x/feepay/types/query.pb.gw.go new file mode 100644 index 000000000..2c457fbeb --- /dev/null +++ b/x/feepay/types/query.pb.gw.go @@ -0,0 +1,272 @@ +// Code generated by protoc-gen-grpc-gateway. DO NOT EDIT. +// source: juno/feepay/v1/query.proto + +/* +Package types is a reverse proxy. + +It translates gRPC into RESTful JSON APIs. +*/ +package types + +import ( + "context" + "io" + "net/http" + + "github.com/golang/protobuf/descriptor" + "github.com/golang/protobuf/proto" + "github.com/grpc-ecosystem/grpc-gateway/runtime" + "github.com/grpc-ecosystem/grpc-gateway/utilities" + "google.golang.org/grpc" + "google.golang.org/grpc/codes" + "google.golang.org/grpc/grpclog" + "google.golang.org/grpc/metadata" + "google.golang.org/grpc/status" +) + +// Suppress "imported and not used" errors +var _ codes.Code +var _ io.Reader +var _ status.Status +var _ = runtime.String +var _ = utilities.NewDoubleArray +var _ = descriptor.ForMessage +var _ = metadata.Join + +func request_Query_FeePayContract_0(ctx context.Context, marshaler runtime.Marshaler, client QueryClient, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) { + var protoReq QueryFeePayContract + var metadata runtime.ServerMetadata + + var ( + val string + ok bool + err error + _ = err + ) + + val, ok = pathParams["contract_address"] + if !ok { + return nil, metadata, status.Errorf(codes.InvalidArgument, "missing parameter %s", "contract_address") + } + + protoReq.ContractAddress, err = runtime.String(val) + + if err != nil { + return nil, metadata, status.Errorf(codes.InvalidArgument, "type mismatch, parameter: %s, error: %v", "contract_address", err) + } + + msg, err := client.FeePayContract(ctx, &protoReq, grpc.Header(&metadata.HeaderMD), grpc.Trailer(&metadata.TrailerMD)) + return msg, metadata, err + +} + +func local_request_Query_FeePayContract_0(ctx context.Context, marshaler runtime.Marshaler, server QueryServer, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) { + var protoReq QueryFeePayContract + var metadata runtime.ServerMetadata + + var ( + val string + ok bool + err error + _ = err + ) + + val, ok = pathParams["contract_address"] + if !ok { + return nil, metadata, status.Errorf(codes.InvalidArgument, "missing parameter %s", "contract_address") + } + + protoReq.ContractAddress, err = runtime.String(val) + + if err != nil { + return nil, metadata, status.Errorf(codes.InvalidArgument, "type mismatch, parameter: %s, error: %v", "contract_address", err) + } + + msg, err := server.FeePayContract(ctx, &protoReq) + return msg, metadata, err + +} + +var ( + filter_Query_FeePayContracts_0 = &utilities.DoubleArray{Encoding: map[string]int{}, Base: []int(nil), Check: []int(nil)} +) + +func request_Query_FeePayContracts_0(ctx context.Context, marshaler runtime.Marshaler, client QueryClient, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) { + var protoReq QueryFeePayContracts + 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_FeePayContracts_0); err != nil { + return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err) + } + + msg, err := client.FeePayContracts(ctx, &protoReq, grpc.Header(&metadata.HeaderMD), grpc.Trailer(&metadata.TrailerMD)) + return msg, metadata, err + +} + +func local_request_Query_FeePayContracts_0(ctx context.Context, marshaler runtime.Marshaler, server QueryServer, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) { + var protoReq QueryFeePayContracts + 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_FeePayContracts_0); err != nil { + return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err) + } + + msg, err := server.FeePayContracts(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. +// Note that using this registration option will cause many gRPC library features to stop working. Consider using RegisterQueryHandlerFromEndpoint instead. +func RegisterQueryHandlerServer(ctx context.Context, mux *runtime.ServeMux, server QueryServer) error { + + mux.Handle("GET", pattern_Query_FeePayContract_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_FeePayContract_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_FeePayContract_0(ctx, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...) + + }) + + mux.Handle("GET", pattern_Query_FeePayContracts_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_FeePayContracts_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_FeePayContracts_0(ctx, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...) + + }) + + return nil +} + +// RegisterQueryHandlerFromEndpoint is same as RegisterQueryHandler but +// automatically dials to "endpoint" and closes the connection when "ctx" gets done. +func RegisterQueryHandlerFromEndpoint(ctx context.Context, mux *runtime.ServeMux, endpoint string, opts []grpc.DialOption) (err error) { + conn, err := grpc.Dial(endpoint, opts...) + if err != nil { + return err + } + defer func() { + if err != nil { + if cerr := conn.Close(); cerr != nil { + grpclog.Infof("Failed to close conn to %s: %v", endpoint, cerr) + } + return + } + go func() { + <-ctx.Done() + if cerr := conn.Close(); cerr != nil { + grpclog.Infof("Failed to close conn to %s: %v", endpoint, cerr) + } + }() + }() + + return RegisterQueryHandler(ctx, mux, conn) +} + +// RegisterQueryHandler registers the http handlers for service Query to "mux". +// The handlers forward requests to the grpc endpoint over "conn". +func RegisterQueryHandler(ctx context.Context, mux *runtime.ServeMux, conn *grpc.ClientConn) error { + return RegisterQueryHandlerClient(ctx, mux, NewQueryClient(conn)) +} + +// RegisterQueryHandlerClient registers the http handlers for service Query +// to "mux". The handlers forward requests to the grpc endpoint over the given implementation of "QueryClient". +// Note: the gRPC framework executes interceptors within the gRPC handler. If the passed in "QueryClient" +// doesn't go through the normal gRPC flow (creating a gRPC client etc.) then it will be up to the passed in +// "QueryClient" to call the correct interceptors. +func RegisterQueryHandlerClient(ctx context.Context, mux *runtime.ServeMux, client QueryClient) error { + + mux.Handle("GET", pattern_Query_FeePayContract_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_FeePayContract_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_FeePayContract_0(ctx, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...) + + }) + + mux.Handle("GET", pattern_Query_FeePayContracts_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_FeePayContracts_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_FeePayContracts_0(ctx, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...) + + }) + + return nil +} + +var ( + pattern_Query_FeePayContract_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2, 2, 1, 1, 0, 4, 1, 5, 3}, []string{"juno", "feepay", "v1", "contract_address"}, "", runtime.AssumeColonVerbOpt(false))) + + pattern_Query_FeePayContracts_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2, 2, 1}, []string{"juno", "feepay", "v1"}, "", runtime.AssumeColonVerbOpt(false))) +) + +var ( + forward_Query_FeePayContract_0 = runtime.ForwardResponseMessage + + forward_Query_FeePayContracts_0 = runtime.ForwardResponseMessage +) From 5a943164fa1c922fd68d2fdc144dc3fa7f591970 Mon Sep 17 00:00:00 2001 From: Joel Smith Date: Fri, 8 Sep 2023 13:48:17 -0500 Subject: [PATCH 21/79] Implement Contract Query Pagination --- x/feepay/keeper/grpc_query.go | 10 ++-------- x/feepay/keeper/keeper.go | 35 ++++++++++++++++++++++++++--------- 2 files changed, 28 insertions(+), 17 deletions(-) diff --git a/x/feepay/keeper/grpc_query.go b/x/feepay/keeper/grpc_query.go index baa9d182e..ae4a1ff27 100644 --- a/x/feepay/keeper/grpc_query.go +++ b/x/feepay/keeper/grpc_query.go @@ -6,7 +6,6 @@ import ( sdk "github.com/cosmos/cosmos-sdk/types" "github.com/CosmosContracts/juno/v17/x/feepay/types" - "github.com/cosmos/cosmos-sdk/types/query" ) var _ types.QueryServer = Querier{} @@ -37,16 +36,11 @@ func (q Querier) FeePayContracts(ctx context.Context, req *types.QueryFeePayCont sdkCtx := sdk.UnwrapSDKContext(ctx) - contracts, err := q.Keeper.GetAllContracts(sdkCtx) + res, err := q.Keeper.GetAllContracts(sdkCtx, req) if err != nil { return nil, err } - return &types.QueryFeePayContractsResponse{ - Contracts: contracts, - Pagination: &query.PageResponse{ - Total: 3, - }, - }, nil + return res, nil } diff --git a/x/feepay/keeper/keeper.go b/x/feepay/keeper/keeper.go index e7c511158..072310dd1 100644 --- a/x/feepay/keeper/keeper.go +++ b/x/feepay/keeper/keeper.go @@ -17,6 +17,8 @@ import ( types "github.com/CosmosContracts/juno/v17/x/feepay/types" revtypes "github.com/CosmosContracts/juno/v17/x/feeshare/types" bankkeeper "github.com/cosmos/cosmos-sdk/x/bank/keeper" + + "github.com/cosmos/cosmos-sdk/types/query" ) const ( @@ -135,20 +137,35 @@ func (k Keeper) UpdateContractBalance(ctx sdk.Context, contractAddress string, n } // Get all registered fee pay contracts -func (k Keeper) GetAllContracts(ctx sdk.Context) ([]types.FeePayContract, error) { +func (k Keeper) GetAllContracts(ctx sdk.Context, req *types.QueryFeePayContracts) (*types.QueryFeePayContractsResponse, error) { + store := prefix.NewStore(ctx.KVStore(k.storeKey), []byte(StoreKeyContracts)) - var contracts []types.FeePayContract - iterator := sdk.KVStorePrefixIterator(store, nil) + results, pageRes, err := query.GenericFilteredPaginate( + k.cdc, + store, + req.Pagination, + func(key []byte, value *types.FeePayContract) (*types.FeePayContract, error) { + return value, nil + }, + func() *types.FeePayContract { + return &types.FeePayContract{} + }, + ) + + if err != nil { + return nil, err + } - defer iterator.Close() - for ; iterator.Valid(); iterator.Next() { - var contract types.FeePayContract - k.cdc.MustUnmarshal(iterator.Value(), &contract) - contracts = append(contracts, contract) + var contracts []types.FeePayContract + for _, contract := range results { + contracts = append(contracts, *contract) } - return contracts, nil + return &types.QueryFeePayContractsResponse{ + Contracts: contracts, + Pagination: pageRes, + }, nil } // Register the contract in the module store From c89e7aaec2720732acb59bdd883da3ec8ba98101 Mon Sep 17 00:00:00 2001 From: Joel Smith Date: Fri, 8 Sep 2023 15:01:08 -0500 Subject: [PATCH 22/79] Code cleanup, Register fee pay errors --- x/feepay/ante/dedcuct_fee.go | 4 +- x/feepay/keeper/keeper.go | 94 +++++++++++++++++------------------- x/feepay/types/errors.go | 12 +++++ 3 files changed, 57 insertions(+), 53 deletions(-) create mode 100644 x/feepay/types/errors.go diff --git a/x/feepay/ante/dedcuct_fee.go b/x/feepay/ante/dedcuct_fee.go index 7b82a841f..4d1fe5cad 100644 --- a/x/feepay/ante/dedcuct_fee.go +++ b/x/feepay/ante/dedcuct_fee.go @@ -154,8 +154,8 @@ func (dfd DeductFeeDecorator) handleZeroFees(ctx sdk.Context, deductFeesFromAcc cw := msg.(*wasmtypes.MsgExecuteContract) // We need to check if it is a valid contract. Utilize the FeePay Keeper for validation - if err := dfd.feepayKeeper.IsValidContract(ctx, cw.GetContract()); err != nil { - return sdkerrors.ErrInvalidRequest.Wrapf("contract %s is not registered for fee pay", cw.GetContract()) + if !dfd.feepayKeeper.IsRegisteredContract(ctx, cw.GetContract()) { + return feepaytypes.ErrContractNotRegistered } // Get the fee price in the chain denom diff --git a/x/feepay/keeper/keeper.go b/x/feepay/keeper/keeper.go index 072310dd1..0ba046d0c 100644 --- a/x/feepay/keeper/keeper.go +++ b/x/feepay/keeper/keeper.go @@ -1,7 +1,6 @@ package keeper import ( - "errors" "fmt" wasmkeeper "github.com/CosmWasm/wasmd/x/wasm/keeper" @@ -13,7 +12,6 @@ import ( storetypes "github.com/cosmos/cosmos-sdk/store/types" sdk "github.com/cosmos/cosmos-sdk/types" - errorsmod "cosmossdk.io/errors" types "github.com/CosmosContracts/juno/v17/x/feepay/types" revtypes "github.com/CosmosContracts/juno/v17/x/feeshare/types" bankkeeper "github.com/cosmos/cosmos-sdk/x/bank/keeper" @@ -22,7 +20,8 @@ import ( ) const ( - StoreKeyContracts = "contracts" + StoreKeyContracts = "contracts" + StoreKeyContractUses = "contract-uses" ) // Keeper of this module maintains collections of feeshares for contracts @@ -76,27 +75,20 @@ func (k Keeper) Logger(ctx sdk.Context) log.Logger { return ctx.Logger().With("module", fmt.Sprintf("x/%s", revtypes.ModuleName)) } -// === +// === TODO: MOVE BELOW FUNCTIONS TO NEW FILE === -// Check if a contract is associated with a FeePay contract -func (k Keeper) IsValidContract(ctx sdk.Context, contractAddr string) error { - store := prefix.NewStore(ctx.KVStore(k.storeKey), []byte("contracts")) - - hasData := store.Has([]byte(contractAddr)) - - if hasData { - return nil - } else { - return errorsmod.Wrapf(errors.New("invalid contract address"), "contract %s not registered", contractAddr) - } +// Check if a contract is registered as a fee pay contract +func (k Keeper) IsRegisteredContract(ctx sdk.Context, contractAddr string) bool { + store := prefix.NewStore(ctx.KVStore(k.storeKey), []byte(StoreKeyContracts)) + return store.Has([]byte(contractAddr)) } // Get a contract from KV store func (k Keeper) GetContract(ctx sdk.Context, contractAddress string) (*types.FeePayContract, error) { - // Return false because the contract was already registered - if err := k.IsValidContract(ctx, contractAddress); err != nil { - return nil, err + // Return nil, contract not registered + if !k.IsRegisteredContract(ctx, contractAddress) { + return nil, types.ErrContractNotRegistered } store := prefix.NewStore(ctx.KVStore(k.storeKey), []byte(StoreKeyContracts)) @@ -112,35 +104,12 @@ func (k Keeper) GetContract(ctx sdk.Context, contractAddress string) (*types.Fee return &fpc, nil } -func (k Keeper) UpdateContractBalance(ctx sdk.Context, contractAddress string, newBalance uint64) error { - - // TODO: Do we need torecheck this? (remove if duplicate) - // Return false because the contract was already registered - if err := k.IsValidContract(ctx, contractAddress); err != nil { - return err - } - - store := prefix.NewStore(ctx.KVStore(k.storeKey), []byte(StoreKeyContracts)) - - key := []byte(contractAddress) - bz := store.Get(key) - - var fpc types.FeePayContract - if err := k.cdc.Unmarshal(bz, &fpc); err != nil { - return err - } - - fpc.Balance = newBalance - - store.Set(key, k.cdc.MustMarshal(&fpc)) - return nil -} - // Get all registered fee pay contracts func (k Keeper) GetAllContracts(ctx sdk.Context, req *types.QueryFeePayContracts) (*types.QueryFeePayContractsResponse, error) { store := prefix.NewStore(ctx.KVStore(k.storeKey), []byte(StoreKeyContracts)) + // Filter and paginate all contracts results, pageRes, err := query.GenericFilteredPaginate( k.cdc, store, @@ -157,6 +126,7 @@ func (k Keeper) GetAllContracts(ctx sdk.Context, req *types.QueryFeePayContracts return nil, err } + // Dereference pointer array of contracts var contracts []types.FeePayContract for _, contract := range results { contracts = append(contracts, *contract) @@ -172,14 +142,11 @@ func (k Keeper) GetAllContracts(ctx sdk.Context, req *types.QueryFeePayContracts func (k Keeper) RegisterContract(ctx sdk.Context, fpc *types.FeePayContract) error { // Return false because the contract was already registered - if err := k.IsValidContract(ctx, fpc.ContractAddress); err == nil { - return errorsmod.Wrapf(errors.New("contract already registered"), "contract %s already registered", fpc.ContractAddress) + if k.IsRegisteredContract(ctx, fpc.ContractAddress) { + return types.ErrContractAlreadyRegistered } - ctx.Logger().Error("Registering contract", "Contract is not registered!") - // Register the new fee pay contract in the KV store - // TODO: change this to be the function GetContract() store := prefix.NewStore(ctx.KVStore(k.storeKey), []byte("contracts")) key := []byte(fpc.ContractAddress) bz := k.cdc.MustMarshal(fpc) @@ -190,14 +157,39 @@ func (k Keeper) RegisterContract(ctx sdk.Context, fpc *types.FeePayContract) err return nil } +// Update the contract balance in the KV store +func (k Keeper) UpdateContractBalance(ctx sdk.Context, contractAddress string, newBalance uint64) error { + + // Skip if the contract is not registered + if !k.IsRegisteredContract(ctx, contractAddress) { + return types.ErrContractNotRegistered + } + + // Get the existing contract in KV store + store := prefix.NewStore(ctx.KVStore(k.storeKey), []byte(StoreKeyContracts)) + + key := []byte(contractAddress) + bz := store.Get(key) + + var fpc types.FeePayContract + if err := k.cdc.Unmarshal(bz, &fpc); err != nil { + return err + } + + // Set new balance and save to KV store + fpc.Balance = newBalance + + store.Set(key, k.cdc.MustMarshal(&fpc)) + return nil +} + // Fund an existing fee pay contract func (k Keeper) FundContract(ctx sdk.Context, mfc *types.MsgFundFeePayContract) error { - ctx.Logger().Error("Funding contract", "Contract", mfc.ContractAddress) - // Return false because the contract was already registered - if err := k.IsValidContract(ctx, mfc.ContractAddress); err != nil { - return err + // Check if the contract is registered + if !k.IsRegisteredContract(ctx, mfc.ContractAddress) { + return types.ErrContractNotRegistered } // Only transfer the bond denom diff --git a/x/feepay/types/errors.go b/x/feepay/types/errors.go new file mode 100644 index 000000000..cbd807279 --- /dev/null +++ b/x/feepay/types/errors.go @@ -0,0 +1,12 @@ +package types + +import ( + errorsmod "cosmossdk.io/errors" +) + +var ( + ErrContractNotRegistered = errorsmod.Register(ModuleName, 1, "contract not registered") + ErrContractAlreadyRegistered = errorsmod.Register(ModuleName, 2, "contract already registered") + ErrContractRegisterNotAdmin = errorsmod.Register(ModuleName, 3, "this address is not the contract admin, cannot register") + ErrContractNotEnoughFunds = errorsmod.Register(ModuleName, 4, "contract does not have enough funds") +) From 8090a8efaf8e599ef8ac67974f573b8fe61bcd7a Mon Sep 17 00:00:00 2001 From: Joel Smith Date: Fri, 8 Sep 2023 16:28:00 -0500 Subject: [PATCH 23/79] Implement wallet limits, Update ante to deduct contract balance --- proto/juno/feepay/v1/feepay.proto | 8 +- proto/juno/feepay/v1/query.proto | 19 ++ x/feepay/ante/dedcuct_fee.go | 30 +- x/feepay/client/cli/query.go | 38 ++- x/feepay/client/cli/tx.go | 2 +- x/feepay/keeper/grpc_query.go | 12 + x/feepay/keeper/keeper.go | 96 +++++- x/feepay/types/errors.go | 1 + x/feepay/types/feepay.pb.go | 105 +++++-- x/feepay/types/query.pb.go | 483 ++++++++++++++++++++++++++++-- x/feepay/types/query.pb.gw.go | 123 ++++++++ 11 files changed, 853 insertions(+), 64 deletions(-) diff --git a/proto/juno/feepay/v1/feepay.proto b/proto/juno/feepay/v1/feepay.proto index fe5c2b786..f94929ba4 100644 --- a/proto/juno/feepay/v1/feepay.proto +++ b/proto/juno/feepay/v1/feepay.proto @@ -11,14 +11,16 @@ message FeePayContract { // The ledger balance of the contract. uint64 balance = 2; // The number of times a wallet may interact with the contract. - uint64 limit = 3; + uint64 wallet_limit = 3; } // This object is used to store the number of times a wallet has // interacted with a contract. message FeePayWalletUsage { + // The contract address. + string contract_address = 1; // The wallet address. - string wallet_address = 1; + string wallet_address = 2; // The number of uses corresponding to a wallet. - uint64 uses = 2; + uint64 uses = 3; } diff --git a/proto/juno/feepay/v1/query.proto b/proto/juno/feepay/v1/query.proto index 4d060fd29..4fcc71918 100644 --- a/proto/juno/feepay/v1/query.proto +++ b/proto/juno/feepay/v1/query.proto @@ -20,6 +20,11 @@ service Query { rpc FeePayContracts(QueryFeePayContracts) returns (QueryFeePayContractsResponse) { option (google.api.http).get = "/juno/feepay/v1/feepay"; } + + // Retrieve the number of uses on a fee pay contract by wallet + rpc FeePayContractUses(QueryFeePayContractUses) returns (QueryFeePayContractUsesResponse) { + option (google.api.http).get = "/juno/feepay/v1/feepay/{contract_address}/uses/{wallet_address}"; + } } // QueryFeePayContract retrieves a single fee pay contract @@ -47,3 +52,17 @@ message QueryFeePayContractsResponse { // pagination defines the pagination in the response. cosmos.base.query.v1beta1.PageResponse pagination = 2; } + +// Message for querying the number of uses on a fee pay contract by wallet +message QueryFeePayContractUses { + // The contract address. + string contract_address = 1; + // The wallet address. + string wallet_address = 2; +} + +// The response for querying the number of uses on a fee pay contract by wallet +message QueryFeePayContractUsesResponse { + // The number of uses on the fee pay contract by wallet + uint64 uses = 1; +} diff --git a/x/feepay/ante/dedcuct_fee.go b/x/feepay/ante/dedcuct_fee.go index 4d1fe5cad..5658fba16 100644 --- a/x/feepay/ante/dedcuct_fee.go +++ b/x/feepay/ante/dedcuct_fee.go @@ -178,6 +178,16 @@ func (dfd DeductFeeDecorator) handleZeroFees(ctx sdk.Context, deductFeesFromAcc ctx.Logger().Error("HandleZeroFees", "RequiredFee", requiredFee) + // Check if wallet exceeded usage limit on contract + if dfd.feepayKeeper.HasWalletExceededUsageLimit(ctx, cw.GetContract(), deductFeesFromAcc.GetAddress().String()) { + return feepaytypes.ErrWalletExceededUsageLimit + } + + // Check if the contract has enough funds to cover the fee + if !dfd.feepayKeeper.CanContractCoverFee(ctx, cw.GetContract(), requiredFee.Uint64()) { + return feepaytypes.ErrContractNotEnoughFunds + } + // Create an array of coins, storing the required fee payment := sdk.NewCoins(sdk.NewCoin(feePrice.Denom, requiredFee)) @@ -185,13 +195,29 @@ func (dfd DeductFeeDecorator) handleZeroFees(ctx sdk.Context, deductFeesFromAcc // Cover the fees of the transaction, send from FeePay Module to FeeCollector Module err := dfd.bankKeeper.SendCoinsFromModuleToModule(ctx, feepaytypes.ModuleName, types.FeeCollectorName, payment) - - // Throw transfer errors if err != nil { ctx.Logger().Error("HandleZeroFees", "Error transfering funds from module to module", err) return sdkerrors.ErrInsufficientFunds.Wrapf("error transfering funds from module to module: %s", err) } + // Deduct the fees from the contract + feepayContract, err := dfd.feepayKeeper.GetContract(ctx, cw.GetContract()) + if err != nil { + return err + } + + dfd.feepayKeeper.UpdateContractBalance(ctx, cw.GetContract(), feepayContract.Balance-requiredFee.Uint64()) + + // Increment wallet usage + uses, err := dfd.feepayKeeper.GetContractUses(ctx, cw.GetContract(), deductFeesFromAcc.GetAddress().String()) + if err != nil { + return err + } + + if err := dfd.feepayKeeper.SetContractUses(ctx, cw.GetContract(), deductFeesFromAcc.GetAddress().String(), uses+1); err != nil { + return err + } + ctx.Logger().Error("HandleZeroFees", "Ending", true) return nil } diff --git a/x/feepay/client/cli/query.go b/x/feepay/client/cli/query.go index b31f78e63..170e88b40 100644 --- a/x/feepay/client/cli/query.go +++ b/x/feepay/client/cli/query.go @@ -25,6 +25,7 @@ func NewQueryCmd() *cobra.Command { feepayQueryCmd.AddCommand( NewQueryFeePayContract(), NewQueryFeePayContracts(), + NewQueryFeePayContractUsage(), ) return feepayQueryCmd @@ -33,7 +34,7 @@ func NewQueryCmd() *cobra.Command { // Query all fee pay contracts func NewQueryFeePayContract() *cobra.Command { cmd := &cobra.Command{ - Use: "contract [address]", + Use: "contract [contract_address]", Short: "Query a FeePay contract by address", Args: cobra.ExactArgs(1), RunE: func(cmd *cobra.Command, args []string) error { @@ -98,3 +99,38 @@ func NewQueryFeePayContracts() *cobra.Command { flags.AddPaginationFlagsToCmd(cmd, "all-contracts") return cmd } + +// Query fee pay contract usage +func NewQueryFeePayContractUsage() *cobra.Command { + cmd := &cobra.Command{ + Use: "uses [contract_address] [wallet_address]", + Short: "Query wallet usage on FeePay contract", + Args: cobra.ExactArgs(2), + RunE: func(cmd *cobra.Command, args []string) error { + clientCtx, err := client.GetClientQueryContext(cmd) + if err != nil { + return err + } + queryClient := types.NewQueryClient(clientCtx) + + contractAddress := args[0] + walletAddress := args[1] + + req := &types.QueryFeePayContractUses{ + ContractAddress: contractAddress, + WalletAddress: walletAddress, + } + + res, err := queryClient.FeePayContractUses(context.Background(), req) + if err != nil { + return err + } + + return clientCtx.PrintProto(res) + }, + } + + flags.AddQueryFlagsToCmd(cmd) + + return cmd +} diff --git a/x/feepay/client/cli/tx.go b/x/feepay/client/cli/tx.go index 3366f9e0d..dac67cd3f 100644 --- a/x/feepay/client/cli/tx.go +++ b/x/feepay/client/cli/tx.go @@ -59,7 +59,7 @@ func NewRegisterFeePayContract() *cobra.Command { fpc := &types.FeePayContract{ ContractAddress: contract_address, Balance: uint64(0), - Limit: dec_limit, + WalletLimit: dec_limit, } msg := &types.MsgRegisterFeePayContract{ diff --git a/x/feepay/keeper/grpc_query.go b/x/feepay/keeper/grpc_query.go index ae4a1ff27..4c231d7f2 100644 --- a/x/feepay/keeper/grpc_query.go +++ b/x/feepay/keeper/grpc_query.go @@ -44,3 +44,15 @@ func (q Querier) FeePayContracts(ctx context.Context, req *types.QueryFeePayCont return res, nil } + +// FeePayContractUses implements types.QueryServer. +func (q Querier) FeePayContractUses(ctx context.Context, req *types.QueryFeePayContractUses) (*types.QueryFeePayContractUsesResponse, error) { + + sdkCtx := sdk.UnwrapSDKContext(ctx) + + uses, err := q.Keeper.GetContractUses(sdkCtx, req.ContractAddress, req.WalletAddress) + + return &types.QueryFeePayContractUsesResponse{ + Uses: uses, + }, err +} diff --git a/x/feepay/keeper/keeper.go b/x/feepay/keeper/keeper.go index 0ba046d0c..4573cd249 100644 --- a/x/feepay/keeper/keeper.go +++ b/x/feepay/keeper/keeper.go @@ -147,7 +147,7 @@ func (k Keeper) RegisterContract(ctx sdk.Context, fpc *types.FeePayContract) err } // Register the new fee pay contract in the KV store - store := prefix.NewStore(ctx.KVStore(k.storeKey), []byte("contracts")) + store := prefix.NewStore(ctx.KVStore(k.storeKey), []byte(StoreKeyContracts)) key := []byte(fpc.ContractAddress) bz := k.cdc.MustMarshal(fpc) @@ -230,3 +230,97 @@ func (k Keeper) FundContract(ctx sdk.Context, mfc *types.MsgFundFeePayContract) ctx.Logger().Error("Funded contract", "New Details", fpc) return nil } + +// Get the funds associated with a contract +func (k Keeper) GetContractFunds(ctx sdk.Context, contractAddress string) (uint64, error) { + contract, err := k.GetContract(ctx, contractAddress) + + if err != nil { + return 0, err + } + + return contract.Balance, nil +} + +// Check if a contract can cover the fees of a transaction +func (k Keeper) CanContractCoverFee(ctx sdk.Context, contractAddress string, fee uint64) bool { + + funds, err := k.GetContractFunds(ctx, contractAddress) + + // Check if contract exists in KV store + if err != nil { + return false + } + + // Check for enough funds + if funds < fee { + return false + } + + return true +} + +// Get the number of times a wallet has interacted with a fee pay contract (err only if contract not registered) +func (k Keeper) GetContractUses(ctx sdk.Context, contractAddress string, walletAddress string) (uint64, error) { + + if !k.IsRegisteredContract(ctx, contractAddress) { + return 0, types.ErrContractNotRegistered + } + + // Get usage from store + store := prefix.NewStore(ctx.KVStore(k.storeKey), []byte(StoreKeyContractUses)) + key := []byte(contractAddress + "-" + walletAddress) + bz := store.Get(key) + + var walletUsage types.FeePayWalletUsage + if err := k.cdc.Unmarshal(bz, &walletUsage); err != nil { + return 0, err + } + + return walletUsage.Uses, nil +} + +// Set the number of times a wallet has interacted with a fee pay contract +func (k Keeper) SetContractUses(ctx sdk.Context, contractAddress string, walletAddress string, uses uint64) error { + + if !k.IsRegisteredContract(ctx, contractAddress) { + return types.ErrContractNotRegistered + } + + // Get store for updating usage + store := prefix.NewStore(ctx.KVStore(k.storeKey), []byte(StoreKeyContractUses)) + key := []byte(contractAddress + "-" + walletAddress) + bz, err := k.cdc.Marshal(&types.FeePayWalletUsage{ + ContractAddress: contractAddress, + WalletAddress: walletAddress, + Uses: uses, + }) + + if err != nil { + return err + } + + store.Set(key, bz) + return nil +} + +// Check if a wallet exceeded usage limit (defaults to true if contract not registered) +func (k Keeper) HasWalletExceededUsageLimit(ctx sdk.Context, contractAddress string, walletAddress string) bool { + + contract, err := k.GetContract(ctx, contractAddress) + + // Check if contract exists in KV store + if err != nil { + return true + } + + // Get account uses + uses, err := k.GetContractUses(ctx, contractAddress, walletAddress) + + if err != nil { + return true + } + + // Return if the wallet has used the contract too many times + return uses >= contract.WalletLimit +} diff --git a/x/feepay/types/errors.go b/x/feepay/types/errors.go index cbd807279..224080911 100644 --- a/x/feepay/types/errors.go +++ b/x/feepay/types/errors.go @@ -9,4 +9,5 @@ var ( ErrContractAlreadyRegistered = errorsmod.Register(ModuleName, 2, "contract already registered") ErrContractRegisterNotAdmin = errorsmod.Register(ModuleName, 3, "this address is not the contract admin, cannot register") ErrContractNotEnoughFunds = errorsmod.Register(ModuleName, 4, "contract does not have enough funds") + ErrWalletExceededUsageLimit = errorsmod.Register(ModuleName, 5, "wallet exceeded usage limit") ) diff --git a/x/feepay/types/feepay.pb.go b/x/feepay/types/feepay.pb.go index 8a939e991..aa6546520 100644 --- a/x/feepay/types/feepay.pb.go +++ b/x/feepay/types/feepay.pb.go @@ -30,7 +30,7 @@ type FeePayContract struct { // The ledger balance of the contract. Balance uint64 `protobuf:"varint,2,opt,name=balance,proto3" json:"balance,omitempty"` // The number of times a wallet may interact with the contract. - Limit uint64 `protobuf:"varint,3,opt,name=limit,proto3" json:"limit,omitempty"` + WalletLimit uint64 `protobuf:"varint,3,opt,name=wallet_limit,json=walletLimit,proto3" json:"wallet_limit,omitempty"` } func (m *FeePayContract) Reset() { *m = FeePayContract{} } @@ -80,9 +80,9 @@ func (m *FeePayContract) GetBalance() uint64 { return 0 } -func (m *FeePayContract) GetLimit() uint64 { +func (m *FeePayContract) GetWalletLimit() uint64 { if m != nil { - return m.Limit + return m.WalletLimit } return 0 } @@ -90,10 +90,12 @@ func (m *FeePayContract) GetLimit() uint64 { // This object is used to store the number of times a wallet has // interacted with a contract. type FeePayWalletUsage struct { + // The contract address. + ContractAddress string `protobuf:"bytes,1,opt,name=contract_address,json=contractAddress,proto3" json:"contract_address,omitempty"` // The wallet address. - WalletAddress string `protobuf:"bytes,1,opt,name=wallet_address,json=walletAddress,proto3" json:"wallet_address,omitempty"` + WalletAddress string `protobuf:"bytes,2,opt,name=wallet_address,json=walletAddress,proto3" json:"wallet_address,omitempty"` // The number of uses corresponding to a wallet. - Uses uint64 `protobuf:"varint,2,opt,name=uses,proto3" json:"uses,omitempty"` + Uses uint64 `protobuf:"varint,3,opt,name=uses,proto3" json:"uses,omitempty"` } func (m *FeePayWalletUsage) Reset() { *m = FeePayWalletUsage{} } @@ -129,6 +131,13 @@ func (m *FeePayWalletUsage) XXX_DiscardUnknown() { var xxx_messageInfo_FeePayWalletUsage proto.InternalMessageInfo +func (m *FeePayWalletUsage) GetContractAddress() string { + if m != nil { + return m.ContractAddress + } + return "" +} + func (m *FeePayWalletUsage) GetWalletAddress() string { if m != nil { return m.WalletAddress @@ -151,23 +160,24 @@ func init() { func init() { proto.RegisterFile("juno/feepay/v1/feepay.proto", fileDescriptor_14ea6771eacbfed1) } var fileDescriptor_14ea6771eacbfed1 = []byte{ - // 245 bytes of a gzipped FileDescriptorProto + // 257 bytes of a gzipped FileDescriptorProto 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xe2, 0x92, 0xce, 0x2a, 0xcd, 0xcb, 0xd7, 0x4f, 0x4b, 0x4d, 0x2d, 0x48, 0xac, 0xd4, 0x2f, 0x33, 0x84, 0xb2, 0xf4, 0x0a, 0x8a, 0xf2, - 0x4b, 0xf2, 0x85, 0xf8, 0x40, 0x92, 0x7a, 0x50, 0xa1, 0x32, 0x43, 0xa5, 0x6c, 0x2e, 0x3e, 0xb7, + 0x4b, 0xf2, 0x85, 0xf8, 0x40, 0x92, 0x7a, 0x50, 0xa1, 0x32, 0x43, 0xa5, 0x0a, 0x2e, 0x3e, 0xb7, 0xd4, 0xd4, 0x80, 0xc4, 0x4a, 0xe7, 0xfc, 0xbc, 0x92, 0xa2, 0xc4, 0xe4, 0x12, 0x21, 0x4d, 0x2e, 0x81, 0x64, 0x28, 0x3b, 0x3e, 0x31, 0x25, 0xa5, 0x28, 0xb5, 0xb8, 0x58, 0x82, 0x51, 0x81, 0x51, 0x83, 0x33, 0x88, 0x1f, 0x26, 0xee, 0x08, 0x11, 0x16, 0x92, 0xe0, 0x62, 0x4f, 0x4a, 0xcc, 0x49, - 0xcc, 0x4b, 0x4e, 0x95, 0x60, 0x52, 0x60, 0xd4, 0x60, 0x09, 0x82, 0x71, 0x85, 0x44, 0xb8, 0x58, - 0x73, 0x32, 0x73, 0x33, 0x4b, 0x24, 0x98, 0xc1, 0xe2, 0x10, 0x8e, 0x92, 0x1f, 0x97, 0x20, 0xc4, - 0xb2, 0xf0, 0xc4, 0x9c, 0x9c, 0xd4, 0x92, 0xd0, 0xe2, 0xc4, 0xf4, 0x54, 0x21, 0x55, 0x2e, 0xbe, - 0x72, 0x30, 0x17, 0xcd, 0x36, 0x5e, 0x88, 0x28, 0xcc, 0x2e, 0x21, 0x2e, 0x96, 0xd2, 0xe2, 0xd4, - 0x62, 0xa8, 0x45, 0x60, 0xb6, 0x93, 0xc7, 0x89, 0x47, 0x72, 0x8c, 0x17, 0x1e, 0xc9, 0x31, 0x3e, - 0x78, 0x24, 0xc7, 0x38, 0xe1, 0xb1, 0x1c, 0xc3, 0x85, 0xc7, 0x72, 0x0c, 0x37, 0x1e, 0xcb, 0x31, - 0x44, 0xe9, 0xa5, 0x67, 0x96, 0x64, 0x94, 0x26, 0xe9, 0x25, 0xe7, 0xe7, 0xea, 0x3b, 0xe7, 0x17, - 0xe7, 0xe6, 0x17, 0xc3, 0xfc, 0x57, 0xac, 0x0f, 0x0e, 0x9e, 0x0a, 0x58, 0x00, 0x95, 0x54, 0x16, - 0xa4, 0x16, 0x27, 0xb1, 0x81, 0x43, 0xc7, 0x18, 0x10, 0x00, 0x00, 0xff, 0xff, 0x88, 0xdb, 0x97, - 0xc5, 0x3c, 0x01, 0x00, 0x00, + 0xcc, 0x4b, 0x4e, 0x95, 0x60, 0x52, 0x60, 0xd4, 0x60, 0x09, 0x82, 0x71, 0x85, 0x14, 0xb9, 0x78, + 0xca, 0x13, 0x73, 0x72, 0x52, 0x4b, 0xe2, 0x73, 0x32, 0x73, 0x33, 0x4b, 0x24, 0x98, 0xc1, 0xd2, + 0xdc, 0x10, 0x31, 0x1f, 0x90, 0x90, 0x52, 0x25, 0x97, 0x20, 0xc4, 0xe6, 0x70, 0xb0, 0x60, 0x68, + 0x71, 0x62, 0x7a, 0x2a, 0x29, 0x96, 0xab, 0x72, 0xf1, 0x41, 0xad, 0x80, 0x29, 0x64, 0x02, 0x2b, + 0xe4, 0x85, 0x88, 0xc2, 0x94, 0x09, 0x71, 0xb1, 0x94, 0x16, 0xa7, 0x16, 0x43, 0x5d, 0x00, 0x66, + 0x3b, 0x79, 0x9c, 0x78, 0x24, 0xc7, 0x78, 0xe1, 0x91, 0x1c, 0xe3, 0x83, 0x47, 0x72, 0x8c, 0x13, + 0x1e, 0xcb, 0x31, 0x5c, 0x78, 0x2c, 0xc7, 0x70, 0xe3, 0xb1, 0x1c, 0x43, 0x94, 0x5e, 0x7a, 0x66, + 0x49, 0x46, 0x69, 0x92, 0x5e, 0x72, 0x7e, 0xae, 0xbe, 0x73, 0x7e, 0x71, 0x6e, 0x7e, 0x31, 0x2c, + 0x5c, 0x8a, 0xf5, 0xc1, 0xc1, 0x5a, 0x01, 0x0b, 0xd8, 0x92, 0xca, 0x82, 0xd4, 0xe2, 0x24, 0x36, + 0x70, 0xa8, 0x1a, 0x03, 0x02, 0x00, 0x00, 0xff, 0xff, 0xe9, 0x06, 0xb9, 0x8c, 0x74, 0x01, 0x00, + 0x00, } func (m *FeePayContract) Marshal() (dAtA []byte, err error) { @@ -190,8 +200,8 @@ func (m *FeePayContract) MarshalToSizedBuffer(dAtA []byte) (int, error) { _ = i var l int _ = l - if m.Limit != 0 { - i = encodeVarintFeepay(dAtA, i, uint64(m.Limit)) + if m.WalletLimit != 0 { + i = encodeVarintFeepay(dAtA, i, uint64(m.WalletLimit)) i-- dAtA[i] = 0x18 } @@ -233,13 +243,20 @@ func (m *FeePayWalletUsage) MarshalToSizedBuffer(dAtA []byte) (int, error) { if m.Uses != 0 { i = encodeVarintFeepay(dAtA, i, uint64(m.Uses)) i-- - dAtA[i] = 0x10 + dAtA[i] = 0x18 } if len(m.WalletAddress) > 0 { i -= len(m.WalletAddress) copy(dAtA[i:], m.WalletAddress) i = encodeVarintFeepay(dAtA, i, uint64(len(m.WalletAddress))) i-- + dAtA[i] = 0x12 + } + if len(m.ContractAddress) > 0 { + i -= len(m.ContractAddress) + copy(dAtA[i:], m.ContractAddress) + i = encodeVarintFeepay(dAtA, i, uint64(len(m.ContractAddress))) + i-- dAtA[i] = 0xa } return len(dAtA) - i, nil @@ -269,8 +286,8 @@ func (m *FeePayContract) Size() (n int) { if m.Balance != 0 { n += 1 + sovFeepay(uint64(m.Balance)) } - if m.Limit != 0 { - n += 1 + sovFeepay(uint64(m.Limit)) + if m.WalletLimit != 0 { + n += 1 + sovFeepay(uint64(m.WalletLimit)) } return n } @@ -281,6 +298,10 @@ func (m *FeePayWalletUsage) Size() (n int) { } var l int _ = l + l = len(m.ContractAddress) + if l > 0 { + n += 1 + l + sovFeepay(uint64(l)) + } l = len(m.WalletAddress) if l > 0 { n += 1 + l + sovFeepay(uint64(l)) @@ -379,9 +400,9 @@ func (m *FeePayContract) Unmarshal(dAtA []byte) error { } case 3: if wireType != 0 { - return fmt.Errorf("proto: wrong wireType = %d for field Limit", wireType) + return fmt.Errorf("proto: wrong wireType = %d for field WalletLimit", wireType) } - m.Limit = 0 + m.WalletLimit = 0 for shift := uint(0); ; shift += 7 { if shift >= 64 { return ErrIntOverflowFeepay @@ -391,7 +412,7 @@ func (m *FeePayContract) Unmarshal(dAtA []byte) error { } b := dAtA[iNdEx] iNdEx++ - m.Limit |= uint64(b&0x7F) << shift + m.WalletLimit |= uint64(b&0x7F) << shift if b < 0x80 { break } @@ -447,6 +468,38 @@ func (m *FeePayWalletUsage) Unmarshal(dAtA []byte) error { } switch fieldNum { case 1: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field ContractAddress", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowFeepay + } + 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 ErrInvalidLengthFeepay + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthFeepay + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.ContractAddress = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + case 2: if wireType != 2 { return fmt.Errorf("proto: wrong wireType = %d for field WalletAddress", wireType) } @@ -478,7 +531,7 @@ func (m *FeePayWalletUsage) Unmarshal(dAtA []byte) error { } m.WalletAddress = string(dAtA[iNdEx:postIndex]) iNdEx = postIndex - case 2: + case 3: if wireType != 0 { return fmt.Errorf("proto: wrong wireType = %d for field Uses", wireType) } diff --git a/x/feepay/types/query.pb.go b/x/feepay/types/query.pb.go index 31dd3217b..b7fdf0992 100644 --- a/x/feepay/types/query.pb.go +++ b/x/feepay/types/query.pb.go @@ -223,46 +223,154 @@ func (m *QueryFeePayContractsResponse) GetPagination() *query.PageResponse { return nil } +// Message for querying the number of uses on a fee pay contract by wallet +type QueryFeePayContractUses struct { + // The contract address. + ContractAddress string `protobuf:"bytes,1,opt,name=contract_address,json=contractAddress,proto3" json:"contract_address,omitempty"` + // The wallet address. + WalletAddress string `protobuf:"bytes,2,opt,name=wallet_address,json=walletAddress,proto3" json:"wallet_address,omitempty"` +} + +func (m *QueryFeePayContractUses) Reset() { *m = QueryFeePayContractUses{} } +func (m *QueryFeePayContractUses) String() string { return proto.CompactTextString(m) } +func (*QueryFeePayContractUses) ProtoMessage() {} +func (*QueryFeePayContractUses) Descriptor() ([]byte, []int) { + return fileDescriptor_d6539df905bf35ca, []int{4} +} +func (m *QueryFeePayContractUses) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *QueryFeePayContractUses) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_QueryFeePayContractUses.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 *QueryFeePayContractUses) XXX_Merge(src proto.Message) { + xxx_messageInfo_QueryFeePayContractUses.Merge(m, src) +} +func (m *QueryFeePayContractUses) XXX_Size() int { + return m.Size() +} +func (m *QueryFeePayContractUses) XXX_DiscardUnknown() { + xxx_messageInfo_QueryFeePayContractUses.DiscardUnknown(m) +} + +var xxx_messageInfo_QueryFeePayContractUses proto.InternalMessageInfo + +func (m *QueryFeePayContractUses) GetContractAddress() string { + if m != nil { + return m.ContractAddress + } + return "" +} + +func (m *QueryFeePayContractUses) GetWalletAddress() string { + if m != nil { + return m.WalletAddress + } + return "" +} + +// The response for querying the number of uses on a fee pay contract by wallet +type QueryFeePayContractUsesResponse struct { + // The number of uses on the fee pay contract by wallet + Uses uint64 `protobuf:"varint,1,opt,name=uses,proto3" json:"uses,omitempty"` +} + +func (m *QueryFeePayContractUsesResponse) Reset() { *m = QueryFeePayContractUsesResponse{} } +func (m *QueryFeePayContractUsesResponse) String() string { return proto.CompactTextString(m) } +func (*QueryFeePayContractUsesResponse) ProtoMessage() {} +func (*QueryFeePayContractUsesResponse) Descriptor() ([]byte, []int) { + return fileDescriptor_d6539df905bf35ca, []int{5} +} +func (m *QueryFeePayContractUsesResponse) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *QueryFeePayContractUsesResponse) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_QueryFeePayContractUsesResponse.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 *QueryFeePayContractUsesResponse) XXX_Merge(src proto.Message) { + xxx_messageInfo_QueryFeePayContractUsesResponse.Merge(m, src) +} +func (m *QueryFeePayContractUsesResponse) XXX_Size() int { + return m.Size() +} +func (m *QueryFeePayContractUsesResponse) XXX_DiscardUnknown() { + xxx_messageInfo_QueryFeePayContractUsesResponse.DiscardUnknown(m) +} + +var xxx_messageInfo_QueryFeePayContractUsesResponse proto.InternalMessageInfo + +func (m *QueryFeePayContractUsesResponse) GetUses() uint64 { + if m != nil { + return m.Uses + } + return 0 +} + func init() { proto.RegisterType((*QueryFeePayContract)(nil), "juno.feepay.v1.QueryFeePayContract") proto.RegisterType((*QueryFeePayContractResponse)(nil), "juno.feepay.v1.QueryFeePayContractResponse") proto.RegisterType((*QueryFeePayContracts)(nil), "juno.feepay.v1.QueryFeePayContracts") proto.RegisterType((*QueryFeePayContractsResponse)(nil), "juno.feepay.v1.QueryFeePayContractsResponse") + proto.RegisterType((*QueryFeePayContractUses)(nil), "juno.feepay.v1.QueryFeePayContractUses") + proto.RegisterType((*QueryFeePayContractUsesResponse)(nil), "juno.feepay.v1.QueryFeePayContractUsesResponse") } func init() { proto.RegisterFile("juno/feepay/v1/query.proto", fileDescriptor_d6539df905bf35ca) } var fileDescriptor_d6539df905bf35ca = []byte{ - // 452 bytes of a gzipped FileDescriptorProto - 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x8c, 0x93, 0xcf, 0x6b, 0x14, 0x31, - 0x14, 0xc7, 0x37, 0xeb, 0x0f, 0x6c, 0x84, 0x56, 0x62, 0x91, 0x32, 0x2d, 0x51, 0x46, 0x51, 0x6b, - 0x25, 0x61, 0xea, 0xcd, 0x93, 0x6e, 0xa1, 0x7a, 0xac, 0x73, 0xd3, 0x83, 0x92, 0x9d, 0x3e, 0xe3, - 0x88, 0x4d, 0xa6, 0x93, 0xcc, 0xe2, 0x20, 0x5e, 0x04, 0xef, 0x82, 0xf8, 0x37, 0x78, 0xf0, 0x1f, - 0xe9, 0xb1, 0xe0, 0xc5, 0x93, 0xc8, 0xae, 0x7f, 0x48, 0x99, 0x64, 0x66, 0xda, 0x0e, 0x03, 0xbb, - 0xb7, 0x47, 0xde, 0x7b, 0xdf, 0xf7, 0xc9, 0xf7, 0x25, 0x38, 0x78, 0x5f, 0x28, 0xcd, 0xdf, 0x02, - 0x64, 0xa2, 0xe4, 0x93, 0x88, 0x1f, 0x16, 0x90, 0x97, 0x2c, 0xcb, 0xb5, 0xd5, 0x64, 0xb9, 0xca, - 0x31, 0x9f, 0x63, 0x93, 0x28, 0x78, 0x90, 0x68, 0x73, 0xa0, 0x0d, 0x1f, 0x0b, 0x03, 0xbe, 0x90, - 0x4f, 0xa2, 0x31, 0x58, 0x11, 0xf1, 0x4c, 0xc8, 0x54, 0x09, 0x9b, 0x6a, 0xe5, 0x7b, 0x83, 0x8d, - 0x8e, 0xae, 0x04, 0x05, 0x26, 0x35, 0x75, 0x76, 0xbd, 0x93, 0xad, 0x67, 0xf8, 0xe4, 0xaa, 0xd4, - 0x52, 0xbb, 0x90, 0x57, 0x51, 0x23, 0x28, 0xb5, 0x96, 0x1f, 0x80, 0x8b, 0x2c, 0xe5, 0x42, 0x29, - 0x6d, 0xdd, 0xb4, 0x5a, 0x30, 0x7c, 0x82, 0xaf, 0xbf, 0xa8, 0x80, 0x76, 0x01, 0xf6, 0x44, 0xb9, - 0xa3, 0x95, 0xcd, 0x45, 0x62, 0xc9, 0x26, 0xbe, 0x96, 0xd4, 0xf1, 0x1b, 0xb1, 0xbf, 0x9f, 0x83, - 0x31, 0x6b, 0xe8, 0x16, 0xba, 0xbf, 0x14, 0xaf, 0x34, 0xe7, 0x4f, 0xfd, 0x71, 0xf8, 0x12, 0xaf, - 0xf7, 0x28, 0xc4, 0x60, 0x32, 0xad, 0x0c, 0x90, 0xc7, 0xf8, 0x4a, 0xd3, 0xe1, 0x14, 0xae, 0x6e, - 0x53, 0x76, 0xde, 0x1e, 0xd6, 0xe9, 0x6c, 0xeb, 0xc3, 0xd7, 0x78, 0xb5, 0x47, 0xda, 0x90, 0x5d, - 0x8c, 0x4f, 0x7d, 0xab, 0x55, 0xef, 0x32, 0x6f, 0x32, 0xab, 0x4c, 0x66, 0x7e, 0x1b, 0xb5, 0xc9, - 0x6c, 0x4f, 0x48, 0x88, 0xe1, 0xb0, 0x00, 0x63, 0xe3, 0x33, 0x9d, 0xe1, 0x2f, 0x84, 0x37, 0xfa, - 0x06, 0xb4, 0xf0, 0x23, 0xbc, 0xd4, 0xc0, 0x54, 0xf7, 0xbf, 0x30, 0x9f, 0x7e, 0x74, 0xf1, 0xe8, - 0xef, 0xcd, 0x41, 0x7c, 0xda, 0x46, 0x9e, 0x9d, 0x83, 0x1d, 0x3a, 0xd8, 0x7b, 0x73, 0x61, 0x3d, - 0xc0, 0x59, 0xda, 0xed, 0x9f, 0x43, 0x7c, 0xc9, 0xd1, 0x92, 0x1f, 0x08, 0x2f, 0x77, 0x16, 0x76, - 0xbb, 0x8b, 0xd5, 0x73, 0xaf, 0x60, 0x6b, 0x81, 0xa2, 0x66, 0x74, 0x18, 0x7d, 0xf9, 0xfd, 0xff, - 0xfb, 0x70, 0x8b, 0x6c, 0xf2, 0xde, 0x37, 0xc7, 0x3f, 0x75, 0x1f, 0xc8, 0x67, 0xf2, 0x15, 0xe1, - 0x95, 0xee, 0xae, 0xee, 0x2c, 0x30, 0xd3, 0x04, 0x0f, 0x17, 0xa9, 0x6a, 0xd1, 0xa8, 0x43, 0x5b, - 0x23, 0x37, 0xfa, 0xd1, 0x46, 0xcf, 0x8f, 0xa6, 0x14, 0x1d, 0x4f, 0x29, 0xfa, 0x37, 0xa5, 0xe8, - 0xdb, 0x8c, 0x0e, 0x8e, 0x67, 0x74, 0xf0, 0x67, 0x46, 0x07, 0xaf, 0x98, 0x4c, 0xed, 0xbb, 0x62, - 0xcc, 0x12, 0x7d, 0xc0, 0x77, 0xdc, 0x0a, 0x5a, 0x75, 0xaf, 0xf5, 0xb1, 0x51, 0xb3, 0x65, 0x06, - 0x66, 0x7c, 0xd9, 0xfd, 0x92, 0x47, 0x27, 0x01, 0x00, 0x00, 0xff, 0xff, 0x9a, 0x34, 0x0f, 0x08, - 0xee, 0x03, 0x00, 0x00, + // 533 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x94, 0x94, 0xcf, 0x6e, 0xd3, 0x40, + 0x10, 0xc6, 0xe3, 0x36, 0x20, 0x3a, 0x88, 0x14, 0x2d, 0x15, 0x54, 0x6e, 0xe5, 0x22, 0xf3, 0xa7, + 0x94, 0xa2, 0x5d, 0xb9, 0x88, 0x0b, 0x17, 0x68, 0x2a, 0xb5, 0x1c, 0x8b, 0x25, 0x0e, 0x70, 0x00, + 0x6d, 0xd2, 0xc1, 0x18, 0x52, 0xaf, 0x9b, 0x5d, 0x07, 0xa2, 0xaa, 0x17, 0x24, 0xee, 0x48, 0x88, + 0xa7, 0xe0, 0x01, 0x78, 0x85, 0x1e, 0x2b, 0x71, 0xe1, 0x84, 0x20, 0xe1, 0x41, 0x90, 0x77, 0x6d, + 0x87, 0x58, 0x46, 0x35, 0xb7, 0xd5, 0xce, 0x37, 0xf3, 0xfd, 0xf2, 0xcd, 0xc6, 0x60, 0xbf, 0x4e, + 0x22, 0xc1, 0x5e, 0x22, 0xc6, 0x7c, 0xc8, 0x06, 0x1e, 0x3b, 0x48, 0xb0, 0x3f, 0xa4, 0x71, 0x5f, + 0x28, 0x41, 0x5a, 0x69, 0x8d, 0x9a, 0x1a, 0x1d, 0x78, 0xf6, 0xed, 0xae, 0x90, 0xfb, 0x42, 0xb2, + 0x0e, 0x97, 0x68, 0x84, 0x6c, 0xe0, 0x75, 0x50, 0x71, 0x8f, 0xc5, 0x3c, 0x08, 0x23, 0xae, 0x42, + 0x11, 0x99, 0x5e, 0x7b, 0xb9, 0x34, 0x37, 0xc0, 0x08, 0x65, 0x28, 0xb3, 0xea, 0x52, 0xa9, 0x9a, + 0x79, 0x98, 0xe2, 0x42, 0x20, 0x02, 0xa1, 0x8f, 0x2c, 0x3d, 0xe5, 0x03, 0x03, 0x21, 0x82, 0x1e, + 0x32, 0x1e, 0x87, 0x8c, 0x47, 0x91, 0x50, 0xda, 0x2d, 0x1b, 0xe8, 0x3e, 0x84, 0x4b, 0x8f, 0x53, + 0xa0, 0x6d, 0xc4, 0x5d, 0x3e, 0xdc, 0x12, 0x91, 0xea, 0xf3, 0xae, 0x22, 0x6b, 0x70, 0xb1, 0x9b, + 0x9d, 0x5f, 0xf0, 0xbd, 0xbd, 0x3e, 0x4a, 0xb9, 0x68, 0x5d, 0xb5, 0x6e, 0xcd, 0xf9, 0xf3, 0xf9, + 0xfd, 0xa6, 0xb9, 0x76, 0x9f, 0xc2, 0x52, 0xc5, 0x04, 0x1f, 0x65, 0x2c, 0x22, 0x89, 0xe4, 0x3e, + 0x9c, 0xcb, 0x3b, 0xf4, 0x84, 0xf3, 0x1b, 0x0e, 0x9d, 0x8e, 0x87, 0x96, 0x3a, 0x0b, 0xbd, 0xfb, + 0x1c, 0x16, 0x2a, 0x46, 0x4b, 0xb2, 0x0d, 0x30, 0xc9, 0x2d, 0x9b, 0x7a, 0x93, 0x9a, 0x90, 0x69, + 0x1a, 0x32, 0x35, 0xdb, 0xc8, 0x42, 0xa6, 0xbb, 0x3c, 0x40, 0x1f, 0x0f, 0x12, 0x94, 0xca, 0xff, + 0xab, 0xd3, 0xfd, 0x62, 0xc1, 0x72, 0x95, 0x41, 0x01, 0xdf, 0x86, 0xb9, 0x1c, 0x26, 0xfd, 0xfd, + 0xb3, 0xa7, 0xd3, 0xb7, 0x9b, 0xc7, 0x3f, 0x56, 0x1a, 0xfe, 0xa4, 0x8d, 0xec, 0x4c, 0xc1, 0xce, + 0x68, 0xd8, 0xd5, 0x53, 0x61, 0x0d, 0xc0, 0x14, 0xed, 0x1b, 0xb8, 0x52, 0x01, 0xfb, 0x44, 0xa2, + 0xfc, 0x8f, 0x75, 0x91, 0x1b, 0xd0, 0x7a, 0xcb, 0x7b, 0x3d, 0x9c, 0x08, 0x67, 0xb4, 0xf0, 0x82, + 0xb9, 0xcd, 0xb7, 0x7a, 0x0f, 0x56, 0xfe, 0x61, 0x56, 0x84, 0x43, 0xa0, 0x99, 0x48, 0x34, 0x46, + 0x4d, 0x5f, 0x9f, 0x37, 0x7e, 0xcd, 0xc2, 0x19, 0xdd, 0x47, 0x3e, 0x5b, 0xd0, 0x2a, 0x3d, 0xaa, + 0x6b, 0xe5, 0xe8, 0x2a, 0x1c, 0xec, 0xf5, 0x1a, 0xa2, 0x1c, 0xc1, 0xf5, 0xde, 0x7f, 0xfb, 0xfd, + 0x69, 0x66, 0x9d, 0xac, 0xb1, 0xca, 0xff, 0x05, 0x3b, 0x2c, 0xa7, 0x72, 0x44, 0x3e, 0x58, 0x30, + 0x5f, 0x7e, 0x4f, 0xd7, 0x6b, 0x78, 0x4a, 0xfb, 0x4e, 0x1d, 0x55, 0x81, 0xe6, 0x68, 0xb4, 0x45, + 0x72, 0xb9, 0x1a, 0x8d, 0x7c, 0xb5, 0x80, 0x54, 0x6c, 0x72, 0xb5, 0x86, 0x49, 0x2a, 0xb4, 0x59, + 0x4d, 0x61, 0x01, 0xb4, 0xa3, 0x81, 0x36, 0xc9, 0x83, 0xda, 0x59, 0xb1, 0x74, 0xa5, 0xec, 0x70, + 0xfa, 0xb9, 0x1c, 0xb5, 0x1f, 0x1d, 0x8f, 0x1c, 0xeb, 0x64, 0xe4, 0x58, 0x3f, 0x47, 0x8e, 0xf5, + 0x71, 0xec, 0x34, 0x4e, 0xc6, 0x4e, 0xe3, 0xfb, 0xd8, 0x69, 0x3c, 0xa3, 0x41, 0xa8, 0x5e, 0x25, + 0x1d, 0xda, 0x15, 0xfb, 0x6c, 0x4b, 0x3f, 0xf0, 0x22, 0x17, 0x63, 0xfa, 0x2e, 0x37, 0x53, 0xc3, + 0x18, 0x65, 0xe7, 0xac, 0xfe, 0x06, 0xdd, 0xfd, 0x13, 0x00, 0x00, 0xff, 0xff, 0xc5, 0x59, 0x69, + 0xb7, 0x4c, 0x05, 0x00, 0x00, } // Reference imports to suppress errors if they are not otherwise used. @@ -281,6 +389,8 @@ type QueryClient interface { FeePayContract(ctx context.Context, in *QueryFeePayContract, opts ...grpc.CallOption) (*QueryFeePayContractResponse, error) // Retrieve all fee pay contracts FeePayContracts(ctx context.Context, in *QueryFeePayContracts, opts ...grpc.CallOption) (*QueryFeePayContractsResponse, error) + // Retrieve the number of uses on a fee pay contract by wallet + FeePayContractUses(ctx context.Context, in *QueryFeePayContractUses, opts ...grpc.CallOption) (*QueryFeePayContractUsesResponse, error) } type queryClient struct { @@ -309,12 +419,23 @@ func (c *queryClient) FeePayContracts(ctx context.Context, in *QueryFeePayContra return out, nil } +func (c *queryClient) FeePayContractUses(ctx context.Context, in *QueryFeePayContractUses, opts ...grpc.CallOption) (*QueryFeePayContractUsesResponse, error) { + out := new(QueryFeePayContractUsesResponse) + err := c.cc.Invoke(ctx, "/juno.feepay.v1.Query/FeePayContractUses", in, out, opts...) + if err != nil { + return nil, err + } + return out, nil +} + // QueryServer is the server API for Query service. type QueryServer interface { // FeePayContract queries a single fee pay contract by address FeePayContract(context.Context, *QueryFeePayContract) (*QueryFeePayContractResponse, error) // Retrieve all fee pay contracts FeePayContracts(context.Context, *QueryFeePayContracts) (*QueryFeePayContractsResponse, error) + // Retrieve the number of uses on a fee pay contract by wallet + FeePayContractUses(context.Context, *QueryFeePayContractUses) (*QueryFeePayContractUsesResponse, error) } // UnimplementedQueryServer can be embedded to have forward compatible implementations. @@ -327,6 +448,9 @@ func (*UnimplementedQueryServer) FeePayContract(ctx context.Context, req *QueryF func (*UnimplementedQueryServer) FeePayContracts(ctx context.Context, req *QueryFeePayContracts) (*QueryFeePayContractsResponse, error) { return nil, status.Errorf(codes.Unimplemented, "method FeePayContracts not implemented") } +func (*UnimplementedQueryServer) FeePayContractUses(ctx context.Context, req *QueryFeePayContractUses) (*QueryFeePayContractUsesResponse, error) { + return nil, status.Errorf(codes.Unimplemented, "method FeePayContractUses not implemented") +} func RegisterQueryServer(s grpc1.Server, srv QueryServer) { s.RegisterService(&_Query_serviceDesc, srv) @@ -368,6 +492,24 @@ func _Query_FeePayContracts_Handler(srv interface{}, ctx context.Context, dec fu return interceptor(ctx, in, info, handler) } +func _Query_FeePayContractUses_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(QueryFeePayContractUses) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(QueryServer).FeePayContractUses(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: "/juno.feepay.v1.Query/FeePayContractUses", + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(QueryServer).FeePayContractUses(ctx, req.(*QueryFeePayContractUses)) + } + return interceptor(ctx, in, info, handler) +} + var _Query_serviceDesc = grpc.ServiceDesc{ ServiceName: "juno.feepay.v1.Query", HandlerType: (*QueryServer)(nil), @@ -380,6 +522,10 @@ var _Query_serviceDesc = grpc.ServiceDesc{ MethodName: "FeePayContracts", Handler: _Query_FeePayContracts_Handler, }, + { + MethodName: "FeePayContractUses", + Handler: _Query_FeePayContractUses_Handler, + }, }, Streams: []grpc.StreamDesc{}, Metadata: "juno/feepay/v1/query.proto", @@ -534,6 +680,71 @@ func (m *QueryFeePayContractsResponse) MarshalToSizedBuffer(dAtA []byte) (int, e return len(dAtA) - i, nil } +func (m *QueryFeePayContractUses) 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 *QueryFeePayContractUses) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *QueryFeePayContractUses) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + if len(m.WalletAddress) > 0 { + i -= len(m.WalletAddress) + copy(dAtA[i:], m.WalletAddress) + i = encodeVarintQuery(dAtA, i, uint64(len(m.WalletAddress))) + 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))) + i-- + dAtA[i] = 0xa + } + return len(dAtA) - i, nil +} + +func (m *QueryFeePayContractUsesResponse) 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 *QueryFeePayContractUsesResponse) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *QueryFeePayContractUsesResponse) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + if m.Uses != 0 { + i = encodeVarintQuery(dAtA, i, uint64(m.Uses)) + i-- + dAtA[i] = 0x8 + } + return len(dAtA) - i, nil +} + func encodeVarintQuery(dAtA []byte, offset int, v uint64) int { offset -= sovQuery(v) base := offset @@ -603,6 +814,35 @@ func (m *QueryFeePayContractsResponse) Size() (n int) { return n } +func (m *QueryFeePayContractUses) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + l = len(m.ContractAddress) + if l > 0 { + n += 1 + l + sovQuery(uint64(l)) + } + l = len(m.WalletAddress) + if l > 0 { + n += 1 + l + sovQuery(uint64(l)) + } + return n +} + +func (m *QueryFeePayContractUsesResponse) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + if m.Uses != 0 { + n += 1 + sovQuery(uint64(m.Uses)) + } + return n +} + func sovQuery(x uint64) (n int) { return (math_bits.Len64(x|1) + 6) / 7 } @@ -983,6 +1223,189 @@ func (m *QueryFeePayContractsResponse) Unmarshal(dAtA []byte) error { } return nil } +func (m *QueryFeePayContractUses) 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: QueryFeePayContractUses: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: QueryFeePayContractUses: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field ContractAddress", 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.ContractAddress = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + case 2: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field WalletAddress", 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.WalletAddress = 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 *QueryFeePayContractUsesResponse) 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: QueryFeePayContractUsesResponse: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: QueryFeePayContractUsesResponse: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field Uses", wireType) + } + m.Uses = 0 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowQuery + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + m.Uses |= uint64(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 skipQuery(dAtA []byte) (n int, err error) { l := len(dAtA) iNdEx := 0 diff --git a/x/feepay/types/query.pb.gw.go b/x/feepay/types/query.pb.gw.go index 2c457fbeb..0331d636a 100644 --- a/x/feepay/types/query.pb.gw.go +++ b/x/feepay/types/query.pb.gw.go @@ -123,6 +123,82 @@ func local_request_Query_FeePayContracts_0(ctx context.Context, marshaler runtim } +func request_Query_FeePayContractUses_0(ctx context.Context, marshaler runtime.Marshaler, client QueryClient, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) { + var protoReq QueryFeePayContractUses + var metadata runtime.ServerMetadata + + var ( + val string + ok bool + err error + _ = err + ) + + val, ok = pathParams["contract_address"] + if !ok { + return nil, metadata, status.Errorf(codes.InvalidArgument, "missing parameter %s", "contract_address") + } + + protoReq.ContractAddress, err = runtime.String(val) + + if err != nil { + return nil, metadata, status.Errorf(codes.InvalidArgument, "type mismatch, parameter: %s, error: %v", "contract_address", err) + } + + val, ok = pathParams["wallet_address"] + if !ok { + return nil, metadata, status.Errorf(codes.InvalidArgument, "missing parameter %s", "wallet_address") + } + + protoReq.WalletAddress, err = runtime.String(val) + + if err != nil { + return nil, metadata, status.Errorf(codes.InvalidArgument, "type mismatch, parameter: %s, error: %v", "wallet_address", err) + } + + msg, err := client.FeePayContractUses(ctx, &protoReq, grpc.Header(&metadata.HeaderMD), grpc.Trailer(&metadata.TrailerMD)) + return msg, metadata, err + +} + +func local_request_Query_FeePayContractUses_0(ctx context.Context, marshaler runtime.Marshaler, server QueryServer, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) { + var protoReq QueryFeePayContractUses + var metadata runtime.ServerMetadata + + var ( + val string + ok bool + err error + _ = err + ) + + val, ok = pathParams["contract_address"] + if !ok { + return nil, metadata, status.Errorf(codes.InvalidArgument, "missing parameter %s", "contract_address") + } + + protoReq.ContractAddress, err = runtime.String(val) + + if err != nil { + return nil, metadata, status.Errorf(codes.InvalidArgument, "type mismatch, parameter: %s, error: %v", "contract_address", err) + } + + val, ok = pathParams["wallet_address"] + if !ok { + return nil, metadata, status.Errorf(codes.InvalidArgument, "missing parameter %s", "wallet_address") + } + + protoReq.WalletAddress, err = runtime.String(val) + + if err != nil { + return nil, metadata, status.Errorf(codes.InvalidArgument, "type mismatch, parameter: %s, error: %v", "wallet_address", err) + } + + msg, err := server.FeePayContractUses(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. @@ -175,6 +251,29 @@ func RegisterQueryHandlerServer(ctx context.Context, mux *runtime.ServeMux, serv }) + mux.Handle("GET", pattern_Query_FeePayContractUses_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_FeePayContractUses_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_FeePayContractUses_0(ctx, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...) + + }) + return nil } @@ -256,6 +355,26 @@ func RegisterQueryHandlerClient(ctx context.Context, mux *runtime.ServeMux, clie }) + mux.Handle("GET", pattern_Query_FeePayContractUses_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_FeePayContractUses_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_FeePayContractUses_0(ctx, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...) + + }) + return nil } @@ -263,10 +382,14 @@ var ( pattern_Query_FeePayContract_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2, 2, 1, 1, 0, 4, 1, 5, 3}, []string{"juno", "feepay", "v1", "contract_address"}, "", runtime.AssumeColonVerbOpt(false))) pattern_Query_FeePayContracts_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2, 2, 1}, []string{"juno", "feepay", "v1"}, "", runtime.AssumeColonVerbOpt(false))) + + pattern_Query_FeePayContractUses_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2, 2, 1, 1, 0, 4, 1, 5, 3, 2, 4, 1, 0, 4, 1, 5, 5}, []string{"juno", "feepay", "v1", "contract_address", "uses", "wallet_address"}, "", runtime.AssumeColonVerbOpt(false))) ) var ( forward_Query_FeePayContract_0 = runtime.ForwardResponseMessage forward_Query_FeePayContracts_0 = runtime.ForwardResponseMessage + + forward_Query_FeePayContractUses_0 = runtime.ForwardResponseMessage ) From 81d0e01b2826483e2bb2820dffe529c629f2f341 Mon Sep 17 00:00:00 2001 From: Joel Smith Date: Mon, 11 Sep 2023 20:28:32 -0500 Subject: [PATCH 24/79] Query if wallet is eligible, Add admin checks on contract registration --- proto/juno/feepay/v1/query.proto | 23 +- scripts/feepay.sh | 2 +- x/feepay/client/cli/query.go | 36 ++ x/feepay/keeper/grpc_query.go | 13 + x/feepay/keeper/keeper.go | 61 +++- x/feepay/keeper/msg_server.go | 2 +- x/feepay/types/errors.go | 2 + x/feepay/types/query.pb.go | 551 +++++++++++++++++++++++++++++-- x/feepay/types/query.pb.gw.go | 123 +++++++ 9 files changed, 758 insertions(+), 55 deletions(-) diff --git a/proto/juno/feepay/v1/query.proto b/proto/juno/feepay/v1/query.proto index 4fcc71918..32b7ffc50 100644 --- a/proto/juno/feepay/v1/query.proto +++ b/proto/juno/feepay/v1/query.proto @@ -25,6 +25,11 @@ service Query { rpc FeePayContractUses(QueryFeePayContractUses) returns (QueryFeePayContractUsesResponse) { option (google.api.http).get = "/juno/feepay/v1/feepay/{contract_address}/uses/{wallet_address}"; } + + // Query if sender is eligible for fee pay contract interaction + rpc FeePayWalletIsEligible(QueryFeePayWalletIsEligible) returns (QueryFeePayWalletIsEligibleResponse) { + option (google.api.http).get = "/juno/feepay/v1/feepay/{contract_address}/eligible/{wallet_address}"; + } } // QueryFeePayContract retrieves a single fee pay contract @@ -55,7 +60,7 @@ message QueryFeePayContractsResponse { // Message for querying the number of uses on a fee pay contract by wallet message QueryFeePayContractUses { - // The contract address. + // The contract address. string contract_address = 1; // The wallet address. string wallet_address = 2; @@ -66,3 +71,19 @@ message QueryFeePayContractUsesResponse { // The number of uses on the fee pay contract by wallet uint64 uses = 1; } + +// Message for querying if a wallet is eligible for fee pay contract interactions +message QueryFeePayWalletIsEligible { + // The contract address. + string contract_address = 1; + // The wallet address. + string wallet_address = 2; +} + +// The response for querying if a wallet is eligible for fee pay contract interactions +message QueryFeePayWalletIsEligibleResponse { + // The eligibility of the wallet for fee pay contract interactions + bool eligible = 1; + // The reason (if any) for the wallet being ineligible for fee pay contract interactions + string reason = 2; +} \ No newline at end of file diff --git a/scripts/feepay.sh b/scripts/feepay.sh index f01b6c293..951bfd360 100644 --- a/scripts/feepay.sh +++ b/scripts/feepay.sh @@ -38,7 +38,7 @@ sleep 3 # sleep 3 # Fund the contract -junod tx feepay fund juno14hj2tavq8fpesdwxxcu44rty3hh90vhujrvcmstl4zr3txmfvw9skjuwg8 100ujuno --gas=200000 --fees=5000ujuno --home /home/joel/.juno1 --chain-id local-1 --keyring-backend=test -y --from juno1 +junod tx feepay fund juno14hj2tavq8fpesdwxxcu44rty3hh90vhujrvcmstl4zr3txmfvw9skjuwg8 1000000ujuno --gas=200000 --fees=5000ujuno --home /home/joel/.juno1 --chain-id local-1 --keyring-backend=test -y --from juno1 sleep 3 diff --git a/x/feepay/client/cli/query.go b/x/feepay/client/cli/query.go index 170e88b40..71f659610 100644 --- a/x/feepay/client/cli/query.go +++ b/x/feepay/client/cli/query.go @@ -26,6 +26,7 @@ func NewQueryCmd() *cobra.Command { NewQueryFeePayContract(), NewQueryFeePayContracts(), NewQueryFeePayContractUsage(), + NewQueryWalletIsEligible(), ) return feepayQueryCmd @@ -134,3 +135,38 @@ func NewQueryFeePayContractUsage() *cobra.Command { return cmd } + +// Query if a wallet is eligible +func NewQueryWalletIsEligible() *cobra.Command { + cmd := &cobra.Command{ + Use: "eligible [contract_address] [wallet_address]", + Short: "Query if a wallet is eligible to interact with a FeePay contract", + Args: cobra.ExactArgs(2), + RunE: func(cmd *cobra.Command, args []string) error { + clientCtx, err := client.GetClientQueryContext(cmd) + if err != nil { + return err + } + queryClient := types.NewQueryClient(clientCtx) + + contractAddress := args[0] + walletAddress := args[1] + + req := &types.QueryFeePayWalletIsEligible{ + ContractAddress: contractAddress, + WalletAddress: walletAddress, + } + + res, err := queryClient.FeePayWalletIsEligible(context.Background(), req) + if err != nil { + return err + } + + return clientCtx.PrintProto(res) + }, + } + + flags.AddQueryFlagsToCmd(cmd) + + return cmd +} diff --git a/x/feepay/keeper/grpc_query.go b/x/feepay/keeper/grpc_query.go index 4c231d7f2..be6f81c55 100644 --- a/x/feepay/keeper/grpc_query.go +++ b/x/feepay/keeper/grpc_query.go @@ -56,3 +56,16 @@ func (q Querier) FeePayContractUses(ctx context.Context, req *types.QueryFeePayC Uses: uses, }, err } + +// FeePayContractEligible implements types.QueryServer. +func (q Querier) FeePayWalletIsEligible(ctx context.Context, req *types.QueryFeePayWalletIsEligible) (*types.QueryFeePayWalletIsEligibleResponse, error) { + + sdkCtx := sdk.UnwrapSDKContext(ctx) + + eligible, reason := q.Keeper.IsWalletEligible(sdkCtx, req.ContractAddress, req.WalletAddress) + + return &types.QueryFeePayWalletIsEligibleResponse{ + Eligible: eligible, + Reason: reason, + }, nil +} diff --git a/x/feepay/keeper/keeper.go b/x/feepay/keeper/keeper.go index 4573cd249..46f42a02f 100644 --- a/x/feepay/keeper/keeper.go +++ b/x/feepay/keeper/keeper.go @@ -139,19 +139,34 @@ func (k Keeper) GetAllContracts(ctx sdk.Context, req *types.QueryFeePayContracts } // Register the contract in the module store -func (k Keeper) RegisterContract(ctx sdk.Context, fpc *types.FeePayContract) error { +func (k Keeper) RegisterContract(ctx sdk.Context, rfp *types.MsgRegisterFeePayContract) error { // Return false because the contract was already registered - if k.IsRegisteredContract(ctx, fpc.ContractAddress) { + if k.IsRegisteredContract(ctx, rfp.Contract.ContractAddress) { return types.ErrContractAlreadyRegistered } + // Check if sender is the owner of the cw contract + contractAddr, err := sdk.AccAddressFromBech32(rfp.Contract.ContractAddress) + if err != nil { + return err + } + + // Get the contract owner + contractInfo := k.wasmKeeper.GetContractInfo(ctx, contractAddr) + + // Check if the sender is first the admin & then the creator (if no admin exists) + adminExists := len(contractInfo.Admin) > 0 + if adminExists && contractInfo.Admin != rfp.SenderAddress { + return types.ErrContractNotAdmin + } else if !adminExists && contractInfo.Creator != rfp.SenderAddress { + return types.ErrContractNotCreator + } + // Register the new fee pay contract in the KV store store := prefix.NewStore(ctx.KVStore(k.storeKey), []byte(StoreKeyContracts)) - key := []byte(fpc.ContractAddress) - bz := k.cdc.MustMarshal(fpc) - - ctx.Logger().Error("Registering contract", "Key", key, "Value", bz) + key := []byte(rfp.Contract.ContractAddress) + bz := k.cdc.MustMarshal(rfp.Contract) store.Set(key, bz) return nil @@ -185,8 +200,6 @@ func (k Keeper) UpdateContractBalance(ctx sdk.Context, contractAddress string, n // Fund an existing fee pay contract func (k Keeper) FundContract(ctx sdk.Context, mfc *types.MsgFundFeePayContract) error { - ctx.Logger().Error("Funding contract", "Contract", mfc.ContractAddress) - // Check if the contract is registered if !k.IsRegisteredContract(ctx, mfc.ContractAddress) { return types.ErrContractNotRegistered @@ -200,23 +213,16 @@ func (k Keeper) FundContract(ctx sdk.Context, mfc *types.MsgFundFeePayContract) } } - ctx.Logger().Error("Funding contract", "Amount", transferCoin) - // Confirm the sender has enough funds to fund the contract addr, err := sdk.AccAddressFromBech32(mfc.SenderAddress) if err != nil { return err } - ctx.Logger().Error("Funding contract", "Address", addr) - if err := k.bankKeeper.SendCoinsFromAccountToModule(ctx, addr, types.ModuleName, sdk.NewCoins(transferCoin)); err != nil { - ctx.Logger().Error("Funding contract", "Error", err) return err } - ctx.Logger().Error("Funding contract", "Sent Coins", true) - // Get existing fee pay contract from store fpc, err := k.GetContract(ctx, mfc.ContractAddress) if err != nil { @@ -226,8 +232,6 @@ func (k Keeper) FundContract(ctx sdk.Context, mfc *types.MsgFundFeePayContract) // Increment the fpc balance fpc.Balance += transferCoin.Amount.Uint64() k.UpdateContractBalance(ctx, mfc.ContractAddress, fpc.Balance) - - ctx.Logger().Error("Funded contract", "New Details", fpc) return nil } @@ -324,3 +328,26 @@ func (k Keeper) HasWalletExceededUsageLimit(ctx sdk.Context, contractAddress str // Return if the wallet has used the contract too many times return uses >= contract.WalletLimit } + +// Check if a wallet is eligible to interact with a contract +func (k Keeper) IsWalletEligible(ctx sdk.Context, contractAddress string, walletAddress string) (bool, string) { + + // Check if contract is registered + if !k.IsRegisteredContract(ctx, contractAddress) { + return false, types.ErrContractNotRegistered.Error() + } + + // Check if wallet has exceeded usage limit + if k.HasWalletExceededUsageLimit(ctx, contractAddress, walletAddress) { + return false, types.ErrWalletExceededUsageLimit.Error() + } + + // Check if contract has enough funds + funds, err := k.GetContractFunds(ctx, contractAddress) + + if err != nil || funds <= 0 { + return false, types.ErrContractNotEnoughFunds.Error() + } + + return true, "" +} diff --git a/x/feepay/keeper/msg_server.go b/x/feepay/keeper/msg_server.go index 424a0e50f..21ce2a4f5 100644 --- a/x/feepay/keeper/msg_server.go +++ b/x/feepay/keeper/msg_server.go @@ -16,7 +16,7 @@ var _ types.MsgServer = &Keeper{} // Register a new fee pay contract. func (k Keeper) RegisterFeePayContract(goCtx context.Context, msg *types.MsgRegisterFeePayContract) (*types.MsgRegisterFeePayContractResponse, error) { ctx := sdk.UnwrapSDKContext(goCtx) - return &types.MsgRegisterFeePayContractResponse{}, k.RegisterContract(ctx, msg.Contract) + return &types.MsgRegisterFeePayContractResponse{}, k.RegisterContract(ctx, msg) } // FundFeePayContract funds a contract with the given amount of tokens. diff --git a/x/feepay/types/errors.go b/x/feepay/types/errors.go index 224080911..ff29f83f8 100644 --- a/x/feepay/types/errors.go +++ b/x/feepay/types/errors.go @@ -10,4 +10,6 @@ var ( ErrContractRegisterNotAdmin = errorsmod.Register(ModuleName, 3, "this address is not the contract admin, cannot register") ErrContractNotEnoughFunds = errorsmod.Register(ModuleName, 4, "contract does not have enough funds") ErrWalletExceededUsageLimit = errorsmod.Register(ModuleName, 5, "wallet exceeded usage limit") + ErrContractNotAdmin = errorsmod.Register(ModuleName, 6, "sender is not the contract admin") + ErrContractNotCreator = errorsmod.Register(ModuleName, 7, "sender is not the contract creator") ) diff --git a/x/feepay/types/query.pb.go b/x/feepay/types/query.pb.go index b7fdf0992..60b79e515 100644 --- a/x/feepay/types/query.pb.go +++ b/x/feepay/types/query.pb.go @@ -324,6 +324,116 @@ func (m *QueryFeePayContractUsesResponse) GetUses() uint64 { return 0 } +// Message for querying if a wallet is eligible for fee pay contract interactions +type QueryFeePayWalletIsEligible struct { + // The contract address. + ContractAddress string `protobuf:"bytes,1,opt,name=contract_address,json=contractAddress,proto3" json:"contract_address,omitempty"` + // The wallet address. + WalletAddress string `protobuf:"bytes,2,opt,name=wallet_address,json=walletAddress,proto3" json:"wallet_address,omitempty"` +} + +func (m *QueryFeePayWalletIsEligible) Reset() { *m = QueryFeePayWalletIsEligible{} } +func (m *QueryFeePayWalletIsEligible) String() string { return proto.CompactTextString(m) } +func (*QueryFeePayWalletIsEligible) ProtoMessage() {} +func (*QueryFeePayWalletIsEligible) Descriptor() ([]byte, []int) { + return fileDescriptor_d6539df905bf35ca, []int{6} +} +func (m *QueryFeePayWalletIsEligible) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *QueryFeePayWalletIsEligible) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_QueryFeePayWalletIsEligible.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 *QueryFeePayWalletIsEligible) XXX_Merge(src proto.Message) { + xxx_messageInfo_QueryFeePayWalletIsEligible.Merge(m, src) +} +func (m *QueryFeePayWalletIsEligible) XXX_Size() int { + return m.Size() +} +func (m *QueryFeePayWalletIsEligible) XXX_DiscardUnknown() { + xxx_messageInfo_QueryFeePayWalletIsEligible.DiscardUnknown(m) +} + +var xxx_messageInfo_QueryFeePayWalletIsEligible proto.InternalMessageInfo + +func (m *QueryFeePayWalletIsEligible) GetContractAddress() string { + if m != nil { + return m.ContractAddress + } + return "" +} + +func (m *QueryFeePayWalletIsEligible) GetWalletAddress() string { + if m != nil { + return m.WalletAddress + } + return "" +} + +// The response for querying if a wallet is eligible for fee pay contract interactions +type QueryFeePayWalletIsEligibleResponse struct { + // The eligibility of the wallet for fee pay contract interactions + Eligible bool `protobuf:"varint,1,opt,name=eligible,proto3" json:"eligible,omitempty"` + // The reason (if any) for the wallet being ineligible for fee pay contract interactions + Reason string `protobuf:"bytes,2,opt,name=reason,proto3" json:"reason,omitempty"` +} + +func (m *QueryFeePayWalletIsEligibleResponse) Reset() { *m = QueryFeePayWalletIsEligibleResponse{} } +func (m *QueryFeePayWalletIsEligibleResponse) String() string { return proto.CompactTextString(m) } +func (*QueryFeePayWalletIsEligibleResponse) ProtoMessage() {} +func (*QueryFeePayWalletIsEligibleResponse) Descriptor() ([]byte, []int) { + return fileDescriptor_d6539df905bf35ca, []int{7} +} +func (m *QueryFeePayWalletIsEligibleResponse) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *QueryFeePayWalletIsEligibleResponse) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_QueryFeePayWalletIsEligibleResponse.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 *QueryFeePayWalletIsEligibleResponse) XXX_Merge(src proto.Message) { + xxx_messageInfo_QueryFeePayWalletIsEligibleResponse.Merge(m, src) +} +func (m *QueryFeePayWalletIsEligibleResponse) XXX_Size() int { + return m.Size() +} +func (m *QueryFeePayWalletIsEligibleResponse) XXX_DiscardUnknown() { + xxx_messageInfo_QueryFeePayWalletIsEligibleResponse.DiscardUnknown(m) +} + +var xxx_messageInfo_QueryFeePayWalletIsEligibleResponse proto.InternalMessageInfo + +func (m *QueryFeePayWalletIsEligibleResponse) GetEligible() bool { + if m != nil { + return m.Eligible + } + return false +} + +func (m *QueryFeePayWalletIsEligibleResponse) GetReason() string { + if m != nil { + return m.Reason + } + return "" +} + func init() { proto.RegisterType((*QueryFeePayContract)(nil), "juno.feepay.v1.QueryFeePayContract") proto.RegisterType((*QueryFeePayContractResponse)(nil), "juno.feepay.v1.QueryFeePayContractResponse") @@ -331,46 +441,53 @@ func init() { proto.RegisterType((*QueryFeePayContractsResponse)(nil), "juno.feepay.v1.QueryFeePayContractsResponse") proto.RegisterType((*QueryFeePayContractUses)(nil), "juno.feepay.v1.QueryFeePayContractUses") proto.RegisterType((*QueryFeePayContractUsesResponse)(nil), "juno.feepay.v1.QueryFeePayContractUsesResponse") + proto.RegisterType((*QueryFeePayWalletIsEligible)(nil), "juno.feepay.v1.QueryFeePayWalletIsEligible") + proto.RegisterType((*QueryFeePayWalletIsEligibleResponse)(nil), "juno.feepay.v1.QueryFeePayWalletIsEligibleResponse") } func init() { proto.RegisterFile("juno/feepay/v1/query.proto", fileDescriptor_d6539df905bf35ca) } var fileDescriptor_d6539df905bf35ca = []byte{ - // 533 bytes of a gzipped FileDescriptorProto - 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x94, 0x94, 0xcf, 0x6e, 0xd3, 0x40, - 0x10, 0xc6, 0xe3, 0x36, 0x20, 0x3a, 0x88, 0x14, 0x2d, 0x15, 0x54, 0x6e, 0xe5, 0x22, 0xf3, 0xa7, - 0x94, 0xa2, 0x5d, 0xb9, 0x88, 0x0b, 0x17, 0x68, 0x2a, 0xb5, 0x1c, 0x8b, 0x25, 0x0e, 0x70, 0x00, - 0x6d, 0xd2, 0xc1, 0x18, 0x52, 0xaf, 0x9b, 0x5d, 0x07, 0xa2, 0xaa, 0x17, 0x24, 0xee, 0x48, 0x88, - 0xa7, 0xe0, 0x01, 0x78, 0x85, 0x1e, 0x2b, 0x71, 0xe1, 0x84, 0x20, 0xe1, 0x41, 0x90, 0x77, 0x6d, - 0x87, 0x58, 0x46, 0x35, 0xb7, 0xd5, 0xce, 0x37, 0xf3, 0xfd, 0xf2, 0xcd, 0xc6, 0x60, 0xbf, 0x4e, - 0x22, 0xc1, 0x5e, 0x22, 0xc6, 0x7c, 0xc8, 0x06, 0x1e, 0x3b, 0x48, 0xb0, 0x3f, 0xa4, 0x71, 0x5f, - 0x28, 0x41, 0x5a, 0x69, 0x8d, 0x9a, 0x1a, 0x1d, 0x78, 0xf6, 0xed, 0xae, 0x90, 0xfb, 0x42, 0xb2, - 0x0e, 0x97, 0x68, 0x84, 0x6c, 0xe0, 0x75, 0x50, 0x71, 0x8f, 0xc5, 0x3c, 0x08, 0x23, 0xae, 0x42, - 0x11, 0x99, 0x5e, 0x7b, 0xb9, 0x34, 0x37, 0xc0, 0x08, 0x65, 0x28, 0xb3, 0xea, 0x52, 0xa9, 0x9a, - 0x79, 0x98, 0xe2, 0x42, 0x20, 0x02, 0xa1, 0x8f, 0x2c, 0x3d, 0xe5, 0x03, 0x03, 0x21, 0x82, 0x1e, - 0x32, 0x1e, 0x87, 0x8c, 0x47, 0x91, 0x50, 0xda, 0x2d, 0x1b, 0xe8, 0x3e, 0x84, 0x4b, 0x8f, 0x53, - 0xa0, 0x6d, 0xc4, 0x5d, 0x3e, 0xdc, 0x12, 0x91, 0xea, 0xf3, 0xae, 0x22, 0x6b, 0x70, 0xb1, 0x9b, - 0x9d, 0x5f, 0xf0, 0xbd, 0xbd, 0x3e, 0x4a, 0xb9, 0x68, 0x5d, 0xb5, 0x6e, 0xcd, 0xf9, 0xf3, 0xf9, - 0xfd, 0xa6, 0xb9, 0x76, 0x9f, 0xc2, 0x52, 0xc5, 0x04, 0x1f, 0x65, 0x2c, 0x22, 0x89, 0xe4, 0x3e, - 0x9c, 0xcb, 0x3b, 0xf4, 0x84, 0xf3, 0x1b, 0x0e, 0x9d, 0x8e, 0x87, 0x96, 0x3a, 0x0b, 0xbd, 0xfb, - 0x1c, 0x16, 0x2a, 0x46, 0x4b, 0xb2, 0x0d, 0x30, 0xc9, 0x2d, 0x9b, 0x7a, 0x93, 0x9a, 0x90, 0x69, - 0x1a, 0x32, 0x35, 0xdb, 0xc8, 0x42, 0xa6, 0xbb, 0x3c, 0x40, 0x1f, 0x0f, 0x12, 0x94, 0xca, 0xff, - 0xab, 0xd3, 0xfd, 0x62, 0xc1, 0x72, 0x95, 0x41, 0x01, 0xdf, 0x86, 0xb9, 0x1c, 0x26, 0xfd, 0xfd, - 0xb3, 0xa7, 0xd3, 0xb7, 0x9b, 0xc7, 0x3f, 0x56, 0x1a, 0xfe, 0xa4, 0x8d, 0xec, 0x4c, 0xc1, 0xce, - 0x68, 0xd8, 0xd5, 0x53, 0x61, 0x0d, 0xc0, 0x14, 0xed, 0x1b, 0xb8, 0x52, 0x01, 0xfb, 0x44, 0xa2, - 0xfc, 0x8f, 0x75, 0x91, 0x1b, 0xd0, 0x7a, 0xcb, 0x7b, 0x3d, 0x9c, 0x08, 0x67, 0xb4, 0xf0, 0x82, - 0xb9, 0xcd, 0xb7, 0x7a, 0x0f, 0x56, 0xfe, 0x61, 0x56, 0x84, 0x43, 0xa0, 0x99, 0x48, 0x34, 0x46, - 0x4d, 0x5f, 0x9f, 0x37, 0x7e, 0xcd, 0xc2, 0x19, 0xdd, 0x47, 0x3e, 0x5b, 0xd0, 0x2a, 0x3d, 0xaa, - 0x6b, 0xe5, 0xe8, 0x2a, 0x1c, 0xec, 0xf5, 0x1a, 0xa2, 0x1c, 0xc1, 0xf5, 0xde, 0x7f, 0xfb, 0xfd, - 0x69, 0x66, 0x9d, 0xac, 0xb1, 0xca, 0xff, 0x05, 0x3b, 0x2c, 0xa7, 0x72, 0x44, 0x3e, 0x58, 0x30, - 0x5f, 0x7e, 0x4f, 0xd7, 0x6b, 0x78, 0x4a, 0xfb, 0x4e, 0x1d, 0x55, 0x81, 0xe6, 0x68, 0xb4, 0x45, - 0x72, 0xb9, 0x1a, 0x8d, 0x7c, 0xb5, 0x80, 0x54, 0x6c, 0x72, 0xb5, 0x86, 0x49, 0x2a, 0xb4, 0x59, - 0x4d, 0x61, 0x01, 0xb4, 0xa3, 0x81, 0x36, 0xc9, 0x83, 0xda, 0x59, 0xb1, 0x74, 0xa5, 0xec, 0x70, - 0xfa, 0xb9, 0x1c, 0xb5, 0x1f, 0x1d, 0x8f, 0x1c, 0xeb, 0x64, 0xe4, 0x58, 0x3f, 0x47, 0x8e, 0xf5, - 0x71, 0xec, 0x34, 0x4e, 0xc6, 0x4e, 0xe3, 0xfb, 0xd8, 0x69, 0x3c, 0xa3, 0x41, 0xa8, 0x5e, 0x25, - 0x1d, 0xda, 0x15, 0xfb, 0x6c, 0x4b, 0x3f, 0xf0, 0x22, 0x17, 0x63, 0xfa, 0x2e, 0x37, 0x53, 0xc3, - 0x18, 0x65, 0xe7, 0xac, 0xfe, 0x06, 0xdd, 0xfd, 0x13, 0x00, 0x00, 0xff, 0xff, 0xc5, 0x59, 0x69, - 0xb7, 0x4c, 0x05, 0x00, 0x00, + // 615 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xb4, 0x55, 0xc1, 0x6e, 0xd3, 0x40, + 0x10, 0x8d, 0x4b, 0x5b, 0x25, 0x83, 0x48, 0xd1, 0x52, 0x85, 0xca, 0xad, 0x5c, 0xe4, 0x02, 0xa5, + 0x14, 0x79, 0x95, 0x56, 0x5c, 0xb8, 0x40, 0x13, 0xb5, 0x05, 0x71, 0x29, 0x96, 0x10, 0x2a, 0x07, + 0xd0, 0x26, 0x1d, 0x8c, 0x21, 0xf5, 0xba, 0x59, 0x27, 0x10, 0x55, 0xbd, 0x20, 0x71, 0x47, 0x42, + 0x7c, 0x45, 0x3f, 0x80, 0x4f, 0xa0, 0xc7, 0x4a, 0x5c, 0x38, 0x21, 0x94, 0xf0, 0x21, 0xc8, 0xbb, + 0xb6, 0x43, 0x8c, 0xdb, 0xba, 0x07, 0x6e, 0xeb, 0x9d, 0x37, 0xf3, 0xde, 0xbc, 0x99, 0x4d, 0x40, + 0x7f, 0xd3, 0xf1, 0x38, 0x7d, 0x85, 0xe8, 0xb3, 0x1e, 0xed, 0x56, 0xe9, 0x5e, 0x07, 0xdb, 0x3d, + 0xcb, 0x6f, 0xf3, 0x80, 0x93, 0x72, 0x18, 0xb3, 0x54, 0xcc, 0xea, 0x56, 0xf5, 0xdb, 0x4d, 0x2e, + 0x76, 0xb9, 0xa0, 0x0d, 0x26, 0x50, 0x01, 0x69, 0xb7, 0xda, 0xc0, 0x80, 0x55, 0xa9, 0xcf, 0x1c, + 0xd7, 0x63, 0x81, 0xcb, 0x3d, 0x95, 0xab, 0xcf, 0xa5, 0xea, 0x3a, 0xe8, 0xa1, 0x70, 0x45, 0x14, + 0x9d, 0x4d, 0x45, 0x23, 0x0e, 0x15, 0x9c, 0x76, 0xb8, 0xc3, 0xe5, 0x91, 0x86, 0xa7, 0xb8, 0xa0, + 0xc3, 0xb9, 0xd3, 0x42, 0xca, 0x7c, 0x97, 0x32, 0xcf, 0xe3, 0x81, 0x64, 0x8b, 0x0a, 0x9a, 0x0f, + 0xe0, 0xca, 0x93, 0x50, 0xd0, 0x06, 0xe2, 0x16, 0xeb, 0xd5, 0xb9, 0x17, 0xb4, 0x59, 0x33, 0x20, + 0x4b, 0x70, 0xb9, 0x19, 0x9d, 0x5f, 0xb2, 0x9d, 0x9d, 0x36, 0x0a, 0x31, 0xa3, 0x5d, 0xd3, 0x6e, + 0x95, 0xec, 0xa9, 0xf8, 0x7e, 0x4d, 0x5d, 0x9b, 0xdb, 0x30, 0x9b, 0x51, 0xc1, 0x46, 0xe1, 0x73, + 0x4f, 0x20, 0xb9, 0x07, 0xc5, 0x38, 0x43, 0x56, 0xb8, 0xb8, 0x62, 0x58, 0xa3, 0xf6, 0x58, 0xa9, + 0xcc, 0x04, 0x6f, 0xbe, 0x80, 0xe9, 0x8c, 0xd2, 0x82, 0x6c, 0x00, 0x0c, 0x7d, 0x8b, 0xaa, 0xde, + 0xb4, 0x94, 0xc9, 0x56, 0x68, 0xb2, 0xa5, 0xa6, 0x11, 0x99, 0x6c, 0x6d, 0x31, 0x07, 0x6d, 0xdc, + 0xeb, 0xa0, 0x08, 0xec, 0xbf, 0x32, 0xcd, 0x43, 0x0d, 0xe6, 0xb2, 0x08, 0x12, 0xf1, 0x35, 0x28, + 0xc5, 0x62, 0xc2, 0xfe, 0x2f, 0x9c, 0xad, 0xbe, 0x36, 0x7e, 0xf4, 0x73, 0xbe, 0x60, 0x0f, 0xd3, + 0xc8, 0xe6, 0x88, 0xd8, 0x31, 0x29, 0x76, 0xf1, 0x4c, 0xb1, 0x4a, 0xc0, 0x88, 0xda, 0xb7, 0x70, + 0x35, 0x43, 0xec, 0x53, 0x81, 0xe2, 0x1c, 0xe3, 0x22, 0x37, 0xa0, 0xfc, 0x8e, 0xb5, 0x5a, 0x38, + 0x04, 0x8e, 0x49, 0xe0, 0x25, 0x75, 0x1b, 0x4f, 0xf5, 0x2e, 0xcc, 0x9f, 0x40, 0x96, 0x98, 0x43, + 0x60, 0xbc, 0x23, 0x50, 0x11, 0x8d, 0xdb, 0xf2, 0x6c, 0xf2, 0x91, 0x65, 0x78, 0x26, 0x4b, 0x3e, + 0x12, 0xeb, 0x2d, 0xd7, 0x71, 0x1b, 0x2d, 0xfc, 0x0f, 0x3a, 0xb7, 0x61, 0xe1, 0x14, 0xc2, 0x44, + 0xab, 0x0e, 0x45, 0x8c, 0xee, 0x24, 0x61, 0xd1, 0x4e, 0xbe, 0x49, 0x05, 0x26, 0xdb, 0xc8, 0x44, + 0x34, 0x9c, 0x92, 0x1d, 0x7d, 0xad, 0x1c, 0x4e, 0xc0, 0x84, 0xac, 0x4d, 0xbe, 0x68, 0x50, 0x4e, + 0x3d, 0x90, 0x85, 0xf4, 0x1a, 0x64, 0xb8, 0xa5, 0x2f, 0xe7, 0x00, 0xc5, 0x12, 0xcd, 0xea, 0x87, + 0xef, 0xbf, 0x3f, 0x8f, 0x2d, 0x93, 0x25, 0x9a, 0xf9, 0xc6, 0xe9, 0x7e, 0xda, 0xb9, 0x03, 0xf2, + 0x51, 0x83, 0xa9, 0xf4, 0xdb, 0xb8, 0x9e, 0x83, 0x53, 0xe8, 0x77, 0xf2, 0xa0, 0x12, 0x69, 0x86, + 0x94, 0x36, 0x43, 0x2a, 0xd9, 0xd2, 0xc8, 0x57, 0x0d, 0x48, 0xc6, 0x56, 0x2e, 0xe6, 0x20, 0x09, + 0x81, 0x3a, 0xcd, 0x09, 0x4c, 0x04, 0x6d, 0x4a, 0x41, 0x6b, 0xe4, 0x7e, 0x6e, 0xaf, 0x68, 0xb8, + 0x9e, 0x74, 0x7f, 0x74, 0xa5, 0x0e, 0xc8, 0x37, 0x0d, 0x2a, 0x27, 0xec, 0xea, 0x69, 0xc3, 0x4b, + 0x83, 0xf5, 0xd5, 0x73, 0x80, 0x93, 0x2e, 0x1e, 0xcb, 0x2e, 0xd6, 0x49, 0x3d, 0x7f, 0x17, 0xf1, + 0xd2, 0xfe, 0xd3, 0x49, 0xed, 0xe1, 0x51, 0xdf, 0xd0, 0x8e, 0xfb, 0x86, 0xf6, 0xab, 0x6f, 0x68, + 0x9f, 0x06, 0x46, 0xe1, 0x78, 0x60, 0x14, 0x7e, 0x0c, 0x8c, 0xc2, 0x73, 0xcb, 0x71, 0x83, 0xd7, + 0x9d, 0x86, 0xd5, 0xe4, 0xbb, 0xb4, 0x2e, 0x7f, 0x76, 0x92, 0x09, 0x2b, 0xe2, 0xf7, 0x31, 0x61, + 0xd0, 0xf3, 0x51, 0x34, 0x26, 0xe5, 0x3f, 0xc3, 0xea, 0x9f, 0x00, 0x00, 0x00, 0xff, 0xff, 0x7c, + 0x30, 0x61, 0xab, 0xe2, 0x06, 0x00, 0x00, } // Reference imports to suppress errors if they are not otherwise used. @@ -391,6 +508,8 @@ type QueryClient interface { FeePayContracts(ctx context.Context, in *QueryFeePayContracts, opts ...grpc.CallOption) (*QueryFeePayContractsResponse, error) // Retrieve the number of uses on a fee pay contract by wallet FeePayContractUses(ctx context.Context, in *QueryFeePayContractUses, opts ...grpc.CallOption) (*QueryFeePayContractUsesResponse, error) + // Query if sender is eligible for fee pay contract interaction + FeePayWalletIsEligible(ctx context.Context, in *QueryFeePayWalletIsEligible, opts ...grpc.CallOption) (*QueryFeePayWalletIsEligibleResponse, error) } type queryClient struct { @@ -428,6 +547,15 @@ func (c *queryClient) FeePayContractUses(ctx context.Context, in *QueryFeePayCon return out, nil } +func (c *queryClient) FeePayWalletIsEligible(ctx context.Context, in *QueryFeePayWalletIsEligible, opts ...grpc.CallOption) (*QueryFeePayWalletIsEligibleResponse, error) { + out := new(QueryFeePayWalletIsEligibleResponse) + err := c.cc.Invoke(ctx, "/juno.feepay.v1.Query/FeePayWalletIsEligible", in, out, opts...) + if err != nil { + return nil, err + } + return out, nil +} + // QueryServer is the server API for Query service. type QueryServer interface { // FeePayContract queries a single fee pay contract by address @@ -436,6 +564,8 @@ type QueryServer interface { FeePayContracts(context.Context, *QueryFeePayContracts) (*QueryFeePayContractsResponse, error) // Retrieve the number of uses on a fee pay contract by wallet FeePayContractUses(context.Context, *QueryFeePayContractUses) (*QueryFeePayContractUsesResponse, error) + // Query if sender is eligible for fee pay contract interaction + FeePayWalletIsEligible(context.Context, *QueryFeePayWalletIsEligible) (*QueryFeePayWalletIsEligibleResponse, error) } // UnimplementedQueryServer can be embedded to have forward compatible implementations. @@ -451,6 +581,9 @@ func (*UnimplementedQueryServer) FeePayContracts(ctx context.Context, req *Query func (*UnimplementedQueryServer) FeePayContractUses(ctx context.Context, req *QueryFeePayContractUses) (*QueryFeePayContractUsesResponse, error) { return nil, status.Errorf(codes.Unimplemented, "method FeePayContractUses not implemented") } +func (*UnimplementedQueryServer) FeePayWalletIsEligible(ctx context.Context, req *QueryFeePayWalletIsEligible) (*QueryFeePayWalletIsEligibleResponse, error) { + return nil, status.Errorf(codes.Unimplemented, "method FeePayWalletIsEligible not implemented") +} func RegisterQueryServer(s grpc1.Server, srv QueryServer) { s.RegisterService(&_Query_serviceDesc, srv) @@ -510,6 +643,24 @@ func _Query_FeePayContractUses_Handler(srv interface{}, ctx context.Context, dec return interceptor(ctx, in, info, handler) } +func _Query_FeePayWalletIsEligible_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(QueryFeePayWalletIsEligible) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(QueryServer).FeePayWalletIsEligible(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: "/juno.feepay.v1.Query/FeePayWalletIsEligible", + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(QueryServer).FeePayWalletIsEligible(ctx, req.(*QueryFeePayWalletIsEligible)) + } + return interceptor(ctx, in, info, handler) +} + var _Query_serviceDesc = grpc.ServiceDesc{ ServiceName: "juno.feepay.v1.Query", HandlerType: (*QueryServer)(nil), @@ -526,6 +677,10 @@ var _Query_serviceDesc = grpc.ServiceDesc{ MethodName: "FeePayContractUses", Handler: _Query_FeePayContractUses_Handler, }, + { + MethodName: "FeePayWalletIsEligible", + Handler: _Query_FeePayWalletIsEligible_Handler, + }, }, Streams: []grpc.StreamDesc{}, Metadata: "juno/feepay/v1/query.proto", @@ -745,6 +900,83 @@ func (m *QueryFeePayContractUsesResponse) MarshalToSizedBuffer(dAtA []byte) (int return len(dAtA) - i, nil } +func (m *QueryFeePayWalletIsEligible) 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 *QueryFeePayWalletIsEligible) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *QueryFeePayWalletIsEligible) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + if len(m.WalletAddress) > 0 { + i -= len(m.WalletAddress) + copy(dAtA[i:], m.WalletAddress) + i = encodeVarintQuery(dAtA, i, uint64(len(m.WalletAddress))) + 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))) + i-- + dAtA[i] = 0xa + } + return len(dAtA) - i, nil +} + +func (m *QueryFeePayWalletIsEligibleResponse) 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 *QueryFeePayWalletIsEligibleResponse) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *QueryFeePayWalletIsEligibleResponse) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + if len(m.Reason) > 0 { + i -= len(m.Reason) + copy(dAtA[i:], m.Reason) + i = encodeVarintQuery(dAtA, i, uint64(len(m.Reason))) + i-- + dAtA[i] = 0x12 + } + if m.Eligible { + i-- + if m.Eligible { + dAtA[i] = 1 + } else { + dAtA[i] = 0 + } + i-- + dAtA[i] = 0x8 + } + return len(dAtA) - i, nil +} + func encodeVarintQuery(dAtA []byte, offset int, v uint64) int { offset -= sovQuery(v) base := offset @@ -843,6 +1075,39 @@ func (m *QueryFeePayContractUsesResponse) Size() (n int) { return n } +func (m *QueryFeePayWalletIsEligible) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + l = len(m.ContractAddress) + if l > 0 { + n += 1 + l + sovQuery(uint64(l)) + } + l = len(m.WalletAddress) + if l > 0 { + n += 1 + l + sovQuery(uint64(l)) + } + return n +} + +func (m *QueryFeePayWalletIsEligibleResponse) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + if m.Eligible { + n += 2 + } + l = len(m.Reason) + if l > 0 { + n += 1 + l + sovQuery(uint64(l)) + } + return n +} + func sovQuery(x uint64) (n int) { return (math_bits.Len64(x|1) + 6) / 7 } @@ -1406,6 +1671,222 @@ func (m *QueryFeePayContractUsesResponse) Unmarshal(dAtA []byte) error { } return nil } +func (m *QueryFeePayWalletIsEligible) 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: QueryFeePayWalletIsEligible: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: QueryFeePayWalletIsEligible: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field ContractAddress", 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.ContractAddress = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + case 2: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field WalletAddress", 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.WalletAddress = 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 *QueryFeePayWalletIsEligibleResponse) 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: QueryFeePayWalletIsEligibleResponse: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: QueryFeePayWalletIsEligibleResponse: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field Eligible", wireType) + } + var v int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowQuery + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + v |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + m.Eligible = bool(v != 0) + case 2: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Reason", 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.Reason = 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 skipQuery(dAtA []byte) (n int, err error) { l := len(dAtA) iNdEx := 0 diff --git a/x/feepay/types/query.pb.gw.go b/x/feepay/types/query.pb.gw.go index 0331d636a..dd1b8703e 100644 --- a/x/feepay/types/query.pb.gw.go +++ b/x/feepay/types/query.pb.gw.go @@ -199,6 +199,82 @@ func local_request_Query_FeePayContractUses_0(ctx context.Context, marshaler run } +func request_Query_FeePayWalletIsEligible_0(ctx context.Context, marshaler runtime.Marshaler, client QueryClient, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) { + var protoReq QueryFeePayWalletIsEligible + var metadata runtime.ServerMetadata + + var ( + val string + ok bool + err error + _ = err + ) + + val, ok = pathParams["contract_address"] + if !ok { + return nil, metadata, status.Errorf(codes.InvalidArgument, "missing parameter %s", "contract_address") + } + + protoReq.ContractAddress, err = runtime.String(val) + + if err != nil { + return nil, metadata, status.Errorf(codes.InvalidArgument, "type mismatch, parameter: %s, error: %v", "contract_address", err) + } + + val, ok = pathParams["wallet_address"] + if !ok { + return nil, metadata, status.Errorf(codes.InvalidArgument, "missing parameter %s", "wallet_address") + } + + protoReq.WalletAddress, err = runtime.String(val) + + if err != nil { + return nil, metadata, status.Errorf(codes.InvalidArgument, "type mismatch, parameter: %s, error: %v", "wallet_address", err) + } + + msg, err := client.FeePayWalletIsEligible(ctx, &protoReq, grpc.Header(&metadata.HeaderMD), grpc.Trailer(&metadata.TrailerMD)) + return msg, metadata, err + +} + +func local_request_Query_FeePayWalletIsEligible_0(ctx context.Context, marshaler runtime.Marshaler, server QueryServer, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) { + var protoReq QueryFeePayWalletIsEligible + var metadata runtime.ServerMetadata + + var ( + val string + ok bool + err error + _ = err + ) + + val, ok = pathParams["contract_address"] + if !ok { + return nil, metadata, status.Errorf(codes.InvalidArgument, "missing parameter %s", "contract_address") + } + + protoReq.ContractAddress, err = runtime.String(val) + + if err != nil { + return nil, metadata, status.Errorf(codes.InvalidArgument, "type mismatch, parameter: %s, error: %v", "contract_address", err) + } + + val, ok = pathParams["wallet_address"] + if !ok { + return nil, metadata, status.Errorf(codes.InvalidArgument, "missing parameter %s", "wallet_address") + } + + protoReq.WalletAddress, err = runtime.String(val) + + if err != nil { + return nil, metadata, status.Errorf(codes.InvalidArgument, "type mismatch, parameter: %s, error: %v", "wallet_address", err) + } + + msg, err := server.FeePayWalletIsEligible(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. @@ -274,6 +350,29 @@ func RegisterQueryHandlerServer(ctx context.Context, mux *runtime.ServeMux, serv }) + mux.Handle("GET", pattern_Query_FeePayWalletIsEligible_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_FeePayWalletIsEligible_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_FeePayWalletIsEligible_0(ctx, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...) + + }) + return nil } @@ -375,6 +474,26 @@ func RegisterQueryHandlerClient(ctx context.Context, mux *runtime.ServeMux, clie }) + mux.Handle("GET", pattern_Query_FeePayWalletIsEligible_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_FeePayWalletIsEligible_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_FeePayWalletIsEligible_0(ctx, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...) + + }) + return nil } @@ -384,6 +503,8 @@ var ( pattern_Query_FeePayContracts_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2, 2, 1}, []string{"juno", "feepay", "v1"}, "", runtime.AssumeColonVerbOpt(false))) pattern_Query_FeePayContractUses_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2, 2, 1, 1, 0, 4, 1, 5, 3, 2, 4, 1, 0, 4, 1, 5, 5}, []string{"juno", "feepay", "v1", "contract_address", "uses", "wallet_address"}, "", runtime.AssumeColonVerbOpt(false))) + + pattern_Query_FeePayWalletIsEligible_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2, 2, 1, 1, 0, 4, 1, 5, 3, 2, 4, 1, 0, 4, 1, 5, 5}, []string{"juno", "feepay", "v1", "contract_address", "eligible", "wallet_address"}, "", runtime.AssumeColonVerbOpt(false))) ) var ( @@ -392,4 +513,6 @@ var ( forward_Query_FeePayContracts_0 = runtime.ForwardResponseMessage forward_Query_FeePayContractUses_0 = runtime.ForwardResponseMessage + + forward_Query_FeePayWalletIsEligible_0 = runtime.ForwardResponseMessage ) From 3e852615d8187fd3cd27d6d327f87b29f945d105 Mon Sep 17 00:00:00 2001 From: Joel Smith Date: Mon, 11 Sep 2023 21:18:54 -0500 Subject: [PATCH 25/79] Improve ante error messages --- x/feepay/ante/dedcuct_fee.go | 26 +++++++++++--------------- 1 file changed, 11 insertions(+), 15 deletions(-) diff --git a/x/feepay/ante/dedcuct_fee.go b/x/feepay/ante/dedcuct_fee.go index 5658fba16..8c95e60ab 100644 --- a/x/feepay/ante/dedcuct_fee.go +++ b/x/feepay/ante/dedcuct_fee.go @@ -148,8 +148,6 @@ func (dfd DeductFeeDecorator) checkDeductFee(ctx sdk.Context, sdkTx sdk.Tx, fee // Handle zero fee transactions for fee prepay module func (dfd DeductFeeDecorator) handleZeroFees(ctx sdk.Context, deductFeesFromAcc types.AccountI, tx sdk.Tx, fee sdk.Coins) error { - ctx.Logger().Error("HandleZeroFees", "Starting", true) - msg := tx.GetMsgs()[0] cw := msg.(*wasmtypes.MsgExecuteContract) @@ -178,14 +176,20 @@ func (dfd DeductFeeDecorator) handleZeroFees(ctx sdk.Context, deductFeesFromAcc ctx.Logger().Error("HandleZeroFees", "RequiredFee", requiredFee) + // Get the fee pay contract + feepayContract, err := dfd.feepayKeeper.GetContract(ctx, cw.GetContract()) + if err != nil { + return err + } + // Check if wallet exceeded usage limit on contract if dfd.feepayKeeper.HasWalletExceededUsageLimit(ctx, cw.GetContract(), deductFeesFromAcc.GetAddress().String()) { - return feepaytypes.ErrWalletExceededUsageLimit + return errorsmod.Wrapf(feepaytypes.ErrWalletExceededUsageLimit, "wallet has exceeded usage limit (%d)", feepayContract.WalletLimit) } // Check if the contract has enough funds to cover the fee if !dfd.feepayKeeper.CanContractCoverFee(ctx, cw.GetContract(), requiredFee.Uint64()) { - return feepaytypes.ErrContractNotEnoughFunds + return errorsmod.Wrapf(feepaytypes.ErrContractNotEnoughFunds, "contract has insufficient funds; expected: %d, got: %d", requiredFee.Uint64(), feepayContract.Balance) } // Create an array of coins, storing the required fee @@ -194,18 +198,12 @@ func (dfd DeductFeeDecorator) handleZeroFees(ctx sdk.Context, deductFeesFromAcc ctx.Logger().Error("HandleZeroFees", "Payment", payment) // Cover the fees of the transaction, send from FeePay Module to FeeCollector Module - err := dfd.bankKeeper.SendCoinsFromModuleToModule(ctx, feepaytypes.ModuleName, types.FeeCollectorName, payment) + err = dfd.bankKeeper.SendCoinsFromModuleToModule(ctx, feepaytypes.ModuleName, types.FeeCollectorName, payment) if err != nil { - ctx.Logger().Error("HandleZeroFees", "Error transfering funds from module to module", err) - return sdkerrors.ErrInsufficientFunds.Wrapf("error transfering funds from module to module: %s", err) - } - - // Deduct the fees from the contract - feepayContract, err := dfd.feepayKeeper.GetContract(ctx, cw.GetContract()) - if err != nil { - return err + return errorsmod.Wrapf(sdkerrors.ErrInsufficientFunds, "error transfering funds from FeePay to FeeCollector; %s", err) } + // Deduct the fee from the contract balance dfd.feepayKeeper.UpdateContractBalance(ctx, cw.GetContract(), feepayContract.Balance-requiredFee.Uint64()) // Increment wallet usage @@ -217,8 +215,6 @@ func (dfd DeductFeeDecorator) handleZeroFees(ctx sdk.Context, deductFeesFromAcc if err := dfd.feepayKeeper.SetContractUses(ctx, cw.GetContract(), deductFeesFromAcc.GetAddress().String(), uses+1); err != nil { return err } - - ctx.Logger().Error("HandleZeroFees", "Ending", true) return nil } From ab97eec51485b4ddb13586b8da257d6e7da97d8a Mon Sep 17 00:00:00 2001 From: Joel Smith Date: Wed, 13 Sep 2023 19:16:20 -0500 Subject: [PATCH 26/79] Add Tx for Unregistering Contract (WIP) --- app/keepers/keepers.go | 1 - proto/juno/feepay/v1/tx.proto | 20 ++ x/feepay/client/cli/tx.go | 35 +++ x/feepay/keeper/keeper.go | 93 ++++++- x/feepay/keeper/msg_server.go | 5 + x/feepay/types/codec.go | 9 +- x/feepay/types/msg.go | 30 ++- x/feepay/types/tx.pb.go | 475 ++++++++++++++++++++++++++++++---- x/feepay/types/tx.pb.gw.go | 83 ++++++ 9 files changed, 688 insertions(+), 63 deletions(-) diff --git a/app/keepers/keepers.go b/app/keepers/keepers.go index e32e51373..2d19446b6 100644 --- a/app/keepers/keepers.go +++ b/app/keepers/keepers.go @@ -550,7 +550,6 @@ func NewAppKeepers( &appKeepers.BankKeeper, appKeepers.WasmKeeper, appKeepers.AccountKeeper, - authtypes.FeeCollectorName, bondDenom, govModAddress, ) diff --git a/proto/juno/feepay/v1/tx.proto b/proto/juno/feepay/v1/tx.proto index fae3f66df..12141f61d 100644 --- a/proto/juno/feepay/v1/tx.proto +++ b/proto/juno/feepay/v1/tx.proto @@ -20,6 +20,12 @@ service Msg { option (google.api.http).post = "/juno/feepay/v1/tx/registerFeePayContract"; }; + // UnregisterFeeShare unregisters a contract for receiving transaction fees + rpc UnregisterFeePayContract(MsgUnregisterFeePayContract) + returns (MsgUnregisterFeePayContractResponse) { + option (google.api.http).post = "/juno/feepay/v1/tx/unregisterFeePayContract"; + }; + // Fund a fee pay contract rpc FundFeePayContract(MsgFundFeePayContract) returns (MsgFundFeePayContractResponse) { @@ -44,6 +50,20 @@ message MsgRegisterFeePayContract { // The response message for registering a fee pay contract. message MsgRegisterFeePayContractResponse {} +// The message to unregister a fee pay contract. +message MsgUnregisterFeePayContract { + option (gogoproto.equal) = false; + + // The wallet address of the sender. + string sender_address = 1; + + // The fee pay contract address. + string contract_address = 2; +} + +// The response message for unregistering a fee pay contract. +message MsgUnregisterFeePayContractResponse {} + // The message to fund a fee pay contract message MsgFundFeePayContract { option (gogoproto.equal) = false; diff --git a/x/feepay/client/cli/tx.go b/x/feepay/client/cli/tx.go index dac67cd3f..cf4a5a92b 100644 --- a/x/feepay/client/cli/tx.go +++ b/x/feepay/client/cli/tx.go @@ -26,6 +26,7 @@ func NewTxCmd() *cobra.Command { txCmd.AddCommand( NewRegisterFeePayContract(), + NewUnregisterFeePayContract(), NewFundFeePayContract(), ) return txCmd @@ -79,6 +80,40 @@ func NewRegisterFeePayContract() *cobra.Command { return cmd } +// NewUnregisterFeePayContract returns a CLI command handler for +// unregistering a fee pay contract. +func NewUnregisterFeePayContract() *cobra.Command { + cmd := &cobra.Command{ + Use: "unregister [contract_bech32]", + Short: "Unregister a contract for fee pay.", + Long: "Unregister a contract for fee pay. All remaining funds will return to the contract creator.", + Args: cobra.ExactArgs(1), + RunE: func(cmd *cobra.Command, args []string) error { + cliCtx, err := client.GetClientTxContext(cmd) + if err != nil { + return err + } + + deployer_address := cliCtx.GetFromAddress() + contract_address := args[0] + + msg := &types.MsgUnregisterFeePayContract{ + SenderAddress: deployer_address.String(), + ContractAddress: contract_address, + } + + if err := msg.ValidateBasic(); err != nil { + return err + } + + return tx.GenerateOrBroadcastTxCLI(cliCtx, cmd.Flags(), msg) + }, + } + + flags.AddTxFlagsToCmd(cmd) + return cmd +} + // NewRegisterFeeShare returns a CLI command handler for // funding a fee pay contract. func NewFundFeePayContract() *cobra.Command { diff --git a/x/feepay/keeper/keeper.go b/x/feepay/keeper/keeper.go index 46f42a02f..0eb01a375 100644 --- a/x/feepay/keeper/keeper.go +++ b/x/feepay/keeper/keeper.go @@ -34,8 +34,7 @@ type Keeper struct { wasmKeeper wasmkeeper.Keeper accountKeeper revtypes.AccountKeeper - feeCollectorName string - bondDenom string + bondDenom string // the address capable of executing a MsgUpdateParams message. Typically, this // should be the x/gov module account. @@ -49,19 +48,17 @@ func NewKeeper( bk *bankkeeper.BaseKeeper, wk wasmkeeper.Keeper, ak revtypes.AccountKeeper, - feeCollector string, bondDenom string, authority string, ) Keeper { return Keeper{ - storeKey: storeKey, - cdc: cdc, - bankKeeper: bk, - wasmKeeper: wk, - accountKeeper: ak, - feeCollectorName: feeCollector, - bondDenom: bondDenom, - authority: authority, + storeKey: storeKey, + cdc: cdc, + bankKeeper: bk, + wasmKeeper: wk, + accountKeeper: ak, + bondDenom: bondDenom, + authority: authority, } } @@ -172,6 +169,80 @@ func (k Keeper) RegisterContract(ctx sdk.Context, rfp *types.MsgRegisterFeePayCo return nil } +// Unregister contract (loop through usage store & remove all usage entries for contract) +func (k Keeper) UnregisterContract(ctx sdk.Context, rfp *types.MsgUnregisterFeePayContract) error { + + // Return false because the contract was already registered + if !k.IsRegisteredContract(ctx, rfp.ContractAddress) { + return types.ErrContractNotRegistered + } + + ctx.Logger().Error("*", "Registered", true) + + // Get fee pay contract + contract, err := k.GetContract(ctx, rfp.ContractAddress) + if err != nil { + return err + } + + ctx.Logger().Error("*", "Got contract obj", contract) + + // Get contract address + contractAddr, err := sdk.AccAddressFromBech32(rfp.ContractAddress) + if err != nil { + return err + } + + ctx.Logger().Error("*", "Got address", contractAddr) + + // Get the contract info + contractInfo := k.wasmKeeper.GetContractInfo(ctx, contractAddr) + + ctx.Logger().Error("*", "Got contract info", contractInfo) + + // Check if sender is the contract owner + if contractInfo.Creator != rfp.SenderAddress { + return types.ErrContractNotCreator + } + + // Remove contract from KV store + store := prefix.NewStore(ctx.KVStore(k.storeKey), []byte(StoreKeyContracts)) + store.Delete([]byte(rfp.ContractAddress)) + + ctx.Logger().Error("*", "Deleted contract", true) + + // Remove all usage entries for contract + store = prefix.NewStore(ctx.KVStore(k.storeKey), []byte(StoreKeyContractUses)) + iterator := sdk.KVStorePrefixIterator(store, []byte(rfp.ContractAddress)) + + for ; iterator.Valid(); iterator.Next() { + store.Delete(iterator.Key()) + } + + ctx.Logger().Error("*", "Deleted contract usages", true) + + // Transfer funds back to contract owner + coins := sdk.NewCoins(sdk.NewCoin(k.bondDenom, sdk.NewIntFromUint64(contract.Balance))) + + // Find admin or creator + var refundAddr string + if len(contractInfo.Admin) > 0 { + refundAddr = contractInfo.Admin + } else { + refundAddr = contractInfo.Creator + } + + ctx.Logger().Error("*", "Sent coins", coins) + ctx.Logger().Error("*", "Refund to", refundAddr) + + // TODO: FIX THE FOLLOWING LINE FROM CRASHING THE TX + if err := k.bankKeeper.SendCoinsFromModuleToAccount(ctx, types.ModuleName, sdk.AccAddress(refundAddr), coins); err != nil { + return err + } + + return nil +} + // Update the contract balance in the KV store func (k Keeper) UpdateContractBalance(ctx sdk.Context, contractAddress string, newBalance uint64) error { diff --git a/x/feepay/keeper/msg_server.go b/x/feepay/keeper/msg_server.go index 21ce2a4f5..ab2c130b5 100644 --- a/x/feepay/keeper/msg_server.go +++ b/x/feepay/keeper/msg_server.go @@ -19,6 +19,11 @@ func (k Keeper) RegisterFeePayContract(goCtx context.Context, msg *types.MsgRegi return &types.MsgRegisterFeePayContractResponse{}, k.RegisterContract(ctx, msg) } +func (k Keeper) UnregisterFeePayContract(goCtx context.Context, msg *types.MsgUnregisterFeePayContract) (*types.MsgUnregisterFeePayContractResponse, error) { + ctx := sdk.UnwrapSDKContext(goCtx) + return &types.MsgUnregisterFeePayContractResponse{}, k.UnregisterContract(ctx, msg) +} + // FundFeePayContract funds a contract with the given amount of tokens. func (k Keeper) FundFeePayContract(goCtx context.Context, msg *types.MsgFundFeePayContract) (*types.MsgFundFeePayContractResponse, error) { ctx := sdk.UnwrapSDKContext(goCtx) diff --git a/x/feepay/types/codec.go b/x/feepay/types/codec.go index 76ae5d5b4..99140ac8f 100644 --- a/x/feepay/types/codec.go +++ b/x/feepay/types/codec.go @@ -24,9 +24,10 @@ var ( const ( // Amino names - registerFeePayContract = "juno/MsgRegisterFeePayContract" - fundFeePayContract = "juno/MsgFundFeePayContract" - updateFeeShareParams = "juno/MsgFeePayUpdateParams" + registerFeePayContract = "juno/MsgRegisterFeePayContract" + unregisterFeePayContract = "juno/MsgUnregisterFeePayContract" + fundFeePayContract = "juno/MsgFundFeePayContract" + updateFeeShareParams = "juno/MsgFeePayUpdateParams" ) // NOTE: This is required for the GetSignBytes function @@ -46,6 +47,7 @@ func RegisterInterfaces(registry codectypes.InterfaceRegistry) { registry.RegisterImplementations( (*sdk.Msg)(nil), &MsgRegisterFeePayContract{}, + &MsgUnregisterFeePayContract{}, &MsgFundFeePayContract{}, &MsgUpdateParams{}, ) @@ -58,6 +60,7 @@ func RegisterInterfaces(registry codectypes.InterfaceRegistry) { // Amino JSON serialization and EIP-712 compatibility. func RegisterLegacyAminoCodec(cdc *codec.LegacyAmino) { cdc.RegisterConcrete(&MsgRegisterFeePayContract{}, registerFeePayContract, nil) + cdc.RegisterConcrete(&MsgUnregisterFeePayContract{}, unregisterFeePayContract, nil) cdc.RegisterConcrete(&MsgFundFeePayContract{}, fundFeePayContract, nil) cdc.RegisterConcrete(&MsgUpdateParams{}, updateFeeShareParams, nil) } diff --git a/x/feepay/types/msg.go b/x/feepay/types/msg.go index 16c7a6400..db43ec860 100644 --- a/x/feepay/types/msg.go +++ b/x/feepay/types/msg.go @@ -6,14 +6,16 @@ import ( var ( _ sdk.Msg = &MsgRegisterFeePayContract{} + _ sdk.Msg = &MsgUnregisterFeePayContract{} _ sdk.Msg = &MsgFundFeePayContract{} _ sdk.Msg = &MsgUpdateParams{} ) const ( - TypeMsgRegisterFeePayContract = "register_feepay_contract" - TypeMsgFundFeePayContract = "fund_feepay_contract" - TypeMsgUpdateParams = "msg_update_params" + TypeMsgRegisterFeePayContract = "register_feepay_contract" + TypeMsgUnregisterFeePayContract = "unregister_feepay_contract" + TypeMsgFundFeePayContract = "fund_feepay_contract" + TypeMsgUpdateParams = "msg_update_params" ) // Route returns the name of the module @@ -38,6 +40,28 @@ func (msg MsgRegisterFeePayContract) GetSigners() []sdk.AccAddress { return []sdk.AccAddress{from} } +// Route returns the name of the module +func (msg MsgUnregisterFeePayContract) Route() string { return RouterKey } + +// Type returns the the action +func (msg MsgUnregisterFeePayContract) Type() string { return TypeMsgUnregisterFeePayContract } + +// ValidateBasic runs stateless checks on the message +func (msg MsgUnregisterFeePayContract) ValidateBasic() error { + return nil +} + +// GetSignBytes encodes the message for signing +func (msg *MsgUnregisterFeePayContract) GetSignBytes() []byte { + return sdk.MustSortJSON(AminoCdc.MustMarshalJSON(msg)) +} + +// GetSigners defines whose signature is required +func (msg MsgUnregisterFeePayContract) GetSigners() []sdk.AccAddress { + from, _ := sdk.AccAddressFromBech32(msg.SenderAddress) + return []sdk.AccAddress{from} +} + // Route returns the name of the module func (msg MsgFundFeePayContract) Route() string { return RouterKey } diff --git a/x/feepay/types/tx.pb.go b/x/feepay/types/tx.pb.go index 033834489..88a72b323 100644 --- a/x/feepay/types/tx.pb.go +++ b/x/feepay/types/tx.pb.go @@ -126,6 +126,98 @@ func (m *MsgRegisterFeePayContractResponse) XXX_DiscardUnknown() { var xxx_messageInfo_MsgRegisterFeePayContractResponse proto.InternalMessageInfo +// The message to unregister a fee pay contract. +type MsgUnregisterFeePayContract struct { + // The wallet address of the sender. + SenderAddress string `protobuf:"bytes,1,opt,name=sender_address,json=senderAddress,proto3" json:"sender_address,omitempty"` + // The fee pay contract address. + ContractAddress string `protobuf:"bytes,2,opt,name=contract_address,json=contractAddress,proto3" json:"contract_address,omitempty"` +} + +func (m *MsgUnregisterFeePayContract) Reset() { *m = MsgUnregisterFeePayContract{} } +func (m *MsgUnregisterFeePayContract) String() string { return proto.CompactTextString(m) } +func (*MsgUnregisterFeePayContract) ProtoMessage() {} +func (*MsgUnregisterFeePayContract) Descriptor() ([]byte, []int) { + return fileDescriptor_d739bd30c8846fd5, []int{2} +} +func (m *MsgUnregisterFeePayContract) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *MsgUnregisterFeePayContract) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_MsgUnregisterFeePayContract.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 *MsgUnregisterFeePayContract) XXX_Merge(src proto.Message) { + xxx_messageInfo_MsgUnregisterFeePayContract.Merge(m, src) +} +func (m *MsgUnregisterFeePayContract) XXX_Size() int { + return m.Size() +} +func (m *MsgUnregisterFeePayContract) XXX_DiscardUnknown() { + xxx_messageInfo_MsgUnregisterFeePayContract.DiscardUnknown(m) +} + +var xxx_messageInfo_MsgUnregisterFeePayContract proto.InternalMessageInfo + +func (m *MsgUnregisterFeePayContract) GetSenderAddress() string { + if m != nil { + return m.SenderAddress + } + return "" +} + +func (m *MsgUnregisterFeePayContract) GetContractAddress() string { + if m != nil { + return m.ContractAddress + } + return "" +} + +// The response message for unregistering a fee pay contract. +type MsgUnregisterFeePayContractResponse struct { +} + +func (m *MsgUnregisterFeePayContractResponse) Reset() { *m = MsgUnregisterFeePayContractResponse{} } +func (m *MsgUnregisterFeePayContractResponse) String() string { return proto.CompactTextString(m) } +func (*MsgUnregisterFeePayContractResponse) ProtoMessage() {} +func (*MsgUnregisterFeePayContractResponse) Descriptor() ([]byte, []int) { + return fileDescriptor_d739bd30c8846fd5, []int{3} +} +func (m *MsgUnregisterFeePayContractResponse) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *MsgUnregisterFeePayContractResponse) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_MsgUnregisterFeePayContractResponse.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 *MsgUnregisterFeePayContractResponse) XXX_Merge(src proto.Message) { + xxx_messageInfo_MsgUnregisterFeePayContractResponse.Merge(m, src) +} +func (m *MsgUnregisterFeePayContractResponse) XXX_Size() int { + return m.Size() +} +func (m *MsgUnregisterFeePayContractResponse) XXX_DiscardUnknown() { + xxx_messageInfo_MsgUnregisterFeePayContractResponse.DiscardUnknown(m) +} + +var xxx_messageInfo_MsgUnregisterFeePayContractResponse proto.InternalMessageInfo + // The message to fund a fee pay contract type MsgFundFeePayContract struct { // The wallet address of the sender. @@ -140,7 +232,7 @@ func (m *MsgFundFeePayContract) Reset() { *m = MsgFundFeePayContract{} } func (m *MsgFundFeePayContract) String() string { return proto.CompactTextString(m) } func (*MsgFundFeePayContract) ProtoMessage() {} func (*MsgFundFeePayContract) Descriptor() ([]byte, []int) { - return fileDescriptor_d739bd30c8846fd5, []int{2} + return fileDescriptor_d739bd30c8846fd5, []int{4} } func (m *MsgFundFeePayContract) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -198,7 +290,7 @@ func (m *MsgFundFeePayContractResponse) Reset() { *m = MsgFundFeePayCont func (m *MsgFundFeePayContractResponse) String() string { return proto.CompactTextString(m) } func (*MsgFundFeePayContractResponse) ProtoMessage() {} func (*MsgFundFeePayContractResponse) Descriptor() ([]byte, []int) { - return fileDescriptor_d739bd30c8846fd5, []int{3} + return fileDescriptor_d739bd30c8846fd5, []int{5} } func (m *MsgFundFeePayContractResponse) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -243,7 +335,7 @@ func (m *MsgUpdateParams) Reset() { *m = MsgUpdateParams{} } func (m *MsgUpdateParams) String() string { return proto.CompactTextString(m) } func (*MsgUpdateParams) ProtoMessage() {} func (*MsgUpdateParams) Descriptor() ([]byte, []int) { - return fileDescriptor_d739bd30c8846fd5, []int{4} + return fileDescriptor_d739bd30c8846fd5, []int{6} } func (m *MsgUpdateParams) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -297,7 +389,7 @@ func (m *MsgUpdateParamsResponse) Reset() { *m = MsgUpdateParamsResponse func (m *MsgUpdateParamsResponse) String() string { return proto.CompactTextString(m) } func (*MsgUpdateParamsResponse) ProtoMessage() {} func (*MsgUpdateParamsResponse) Descriptor() ([]byte, []int) { - return fileDescriptor_d739bd30c8846fd5, []int{5} + return fileDescriptor_d739bd30c8846fd5, []int{7} } func (m *MsgUpdateParamsResponse) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -329,6 +421,8 @@ var xxx_messageInfo_MsgUpdateParamsResponse proto.InternalMessageInfo func init() { proto.RegisterType((*MsgRegisterFeePayContract)(nil), "juno.feepay.v1.MsgRegisterFeePayContract") proto.RegisterType((*MsgRegisterFeePayContractResponse)(nil), "juno.feepay.v1.MsgRegisterFeePayContractResponse") + proto.RegisterType((*MsgUnregisterFeePayContract)(nil), "juno.feepay.v1.MsgUnregisterFeePayContract") + proto.RegisterType((*MsgUnregisterFeePayContractResponse)(nil), "juno.feepay.v1.MsgUnregisterFeePayContractResponse") proto.RegisterType((*MsgFundFeePayContract)(nil), "juno.feepay.v1.MsgFundFeePayContract") proto.RegisterType((*MsgFundFeePayContractResponse)(nil), "juno.feepay.v1.MsgFundFeePayContractResponse") proto.RegisterType((*MsgUpdateParams)(nil), "juno.feepay.v1.MsgUpdateParams") @@ -338,47 +432,50 @@ func init() { func init() { proto.RegisterFile("juno/feepay/v1/tx.proto", fileDescriptor_d739bd30c8846fd5) } var fileDescriptor_d739bd30c8846fd5 = []byte{ - // 628 bytes of a gzipped FileDescriptorProto - 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x9c, 0x94, 0x4d, 0x4f, 0x13, 0x41, - 0x18, 0xc7, 0x3b, 0x94, 0x10, 0x19, 0x10, 0x74, 0x83, 0xd0, 0x56, 0xdd, 0xe2, 0x1a, 0x42, 0xc1, - 0x74, 0x27, 0x8b, 0xc6, 0x03, 0x37, 0x4b, 0x42, 0xbc, 0x34, 0x21, 0x6b, 0x4c, 0x8c, 0x17, 0x32, - 0xdd, 0x1d, 0x86, 0x55, 0x76, 0x66, 0xb3, 0x33, 0x25, 0xec, 0x95, 0x78, 0xd7, 0xc4, 0x93, 0x9e, - 0xbc, 0xf9, 0x72, 0xe2, 0xe0, 0x87, 0xe0, 0x48, 0xf4, 0xe2, 0x49, 0x0d, 0x35, 0xa9, 0xf1, 0x53, - 0x98, 0xdd, 0x9d, 0x2d, 0xb4, 0xdd, 0x46, 0xe2, 0xa5, 0x2f, 0xcf, 0xff, 0xbf, 0xcf, 0xf3, 0x7b, - 0x5e, 0x5a, 0xb8, 0xf0, 0xac, 0xcd, 0x38, 0xda, 0x21, 0x24, 0xc0, 0x11, 0xda, 0xb7, 0x90, 0x3c, - 0x30, 0x83, 0x90, 0x4b, 0xae, 0xcd, 0xc4, 0x82, 0x99, 0x0a, 0xe6, 0xbe, 0x55, 0x99, 0xa3, 0x9c, - 0xf2, 0x44, 0x42, 0xf1, 0xa7, 0xd4, 0x55, 0xb9, 0x41, 0x39, 0xa7, 0x7b, 0x04, 0xe1, 0xc0, 0x43, - 0x98, 0x31, 0x2e, 0xb1, 0xf4, 0x38, 0x13, 0x4a, 0xbd, 0x8a, 0x7d, 0x8f, 0x71, 0x94, 0xbc, 0xaa, - 0xd0, 0x82, 0xc3, 0x85, 0xcf, 0x05, 0xf2, 0x05, 0x8d, 0xcb, 0xf9, 0x82, 0x2a, 0x41, 0x57, 0x42, - 0x0b, 0x0b, 0x82, 0xf6, 0xad, 0x16, 0x91, 0xd8, 0x42, 0x0e, 0xf7, 0x98, 0xd2, 0xcb, 0xa9, 0xbe, - 0x9d, 0x22, 0xa4, 0x5f, 0x32, 0x88, 0x81, 0x1e, 0x28, 0x61, 0x44, 0x78, 0x99, 0x7a, 0x7d, 0x40, - 0x55, 0x2d, 0x25, 0xa2, 0xf1, 0x02, 0xc0, 0x72, 0x53, 0x50, 0x9b, 0x50, 0x4f, 0x48, 0x12, 0x6e, - 0x12, 0xb2, 0x85, 0xa3, 0x0d, 0xce, 0x64, 0x88, 0x1d, 0xa9, 0x2d, 0xc1, 0x19, 0x41, 0x98, 0x4b, - 0xc2, 0x6d, 0xec, 0xba, 0x21, 0x11, 0xa2, 0x04, 0x16, 0x41, 0x6d, 0xd2, 0xbe, 0x9c, 0x46, 0x1f, - 0xa4, 0x41, 0x6d, 0x1d, 0x5e, 0x72, 0xd4, 0x23, 0xa5, 0xb1, 0x45, 0x50, 0x9b, 0x5a, 0xd3, 0xcd, - 0xfe, 0xe9, 0x99, 0xfd, 0x89, 0xed, 0x9e, 0x7f, 0x7d, 0xfc, 0xf7, 0xbb, 0x6a, 0xc1, 0xb8, 0x0d, - 0x6f, 0x8d, 0xa4, 0xb0, 0x89, 0x08, 0x38, 0x13, 0xc4, 0xf8, 0x03, 0xe0, 0xb5, 0xa6, 0xa0, 0x9b, - 0x6d, 0xe6, 0xfe, 0x1f, 0xe7, 0x0a, 0xbc, 0x92, 0xd5, 0xed, 0x19, 0xc7, 0x12, 0xe3, 0x6c, 0x16, - 0xcf, 0xac, 0x11, 0x9c, 0xc0, 0x3e, 0x6f, 0x33, 0x59, 0x2a, 0x2e, 0x16, 0x6b, 0x53, 0x6b, 0x65, - 0x53, 0x4d, 0x3c, 0x5e, 0x8f, 0xa9, 0xd6, 0x63, 0x6e, 0x70, 0x8f, 0x35, 0x36, 0x8f, 0xbf, 0x57, - 0x0b, 0x9f, 0x7e, 0x54, 0x6b, 0xd4, 0x93, 0xbb, 0xed, 0x96, 0xe9, 0x70, 0x5f, 0xad, 0x47, 0xbd, - 0xd5, 0x85, 0xfb, 0x1c, 0xc9, 0x28, 0x20, 0x22, 0x79, 0x40, 0xbc, 0xed, 0x1e, 0xad, 0x4e, 0xef, - 0x11, 0x8a, 0x9d, 0x68, 0x3b, 0x5e, 0xb0, 0xf8, 0xd0, 0x3d, 0x5a, 0x05, 0xb6, 0x2a, 0xa8, 0x26, - 0x52, 0x85, 0x37, 0x73, 0x7b, 0xed, 0x4d, 0xe3, 0x25, 0x80, 0xb3, 0x4d, 0x41, 0x1f, 0x07, 0x2e, - 0x96, 0x64, 0x0b, 0x87, 0xd8, 0x17, 0xda, 0x7d, 0x38, 0x89, 0xdb, 0x72, 0x97, 0x87, 0x9e, 0x8c, - 0xd2, 0x11, 0x34, 0x4a, 0x5f, 0x3e, 0xd7, 0xe7, 0x14, 0xbb, 0x6a, 0xee, 0x91, 0x0c, 0x3d, 0x46, - 0xed, 0x33, 0xab, 0x76, 0x0f, 0x4e, 0x04, 0x49, 0x06, 0xb5, 0xbe, 0xf9, 0xc1, 0xf5, 0xa5, 0xf9, - 0x1b, 0xe3, 0x71, 0xab, 0xb6, 0xf2, 0xae, 0xcf, 0x1c, 0x76, 0x8f, 0x56, 0xcf, 0xb2, 0x18, 0x65, - 0xb8, 0x30, 0x00, 0x94, 0xc1, 0xae, 0xbd, 0x2f, 0xc2, 0x62, 0x53, 0x50, 0xed, 0x23, 0x80, 0xf3, - 0x23, 0x6e, 0x6d, 0x65, 0xb0, 0xe6, 0xc8, 0x83, 0xa8, 0x58, 0x17, 0xb6, 0xf6, 0xa6, 0x65, 0x1d, - 0x7e, 0xfd, 0xf5, 0x7a, 0xec, 0x8e, 0xb1, 0x82, 0x86, 0x7e, 0xef, 0x28, 0xcc, 0x07, 0x7a, 0x03, - 0xa0, 0x96, 0x77, 0x6b, 0x39, 0xc5, 0x87, 0x6d, 0x95, 0xfa, 0x85, 0x6c, 0x3d, 0xbe, 0x7a, 0xc2, - 0xb7, 0x6c, 0x2c, 0xe5, 0xf0, 0xed, 0x0c, 0x43, 0x3c, 0x81, 0xd3, 0x7d, 0x8b, 0xaf, 0xe6, 0x54, - 0x3b, 0x6f, 0xa8, 0x2c, 0xff, 0xc3, 0x90, 0x81, 0x34, 0x1e, 0x1e, 0x9f, 0xea, 0xe0, 0xe4, 0x54, - 0x07, 0x3f, 0x4f, 0x75, 0xf0, 0xaa, 0xa3, 0x17, 0x4e, 0x3a, 0x7a, 0xe1, 0x5b, 0x47, 0x2f, 0x3c, - 0x35, 0xcf, 0xdd, 0xf7, 0x46, 0x72, 0x50, 0x19, 0x8e, 0x48, 0xa1, 0x0f, 0x32, 0xec, 0xe4, 0xd6, - 0x5b, 0x13, 0xc9, 0x3f, 0xcc, 0xdd, 0xbf, 0x01, 0x00, 0x00, 0xff, 0xff, 0x93, 0x1a, 0x53, 0xb8, - 0x62, 0x05, 0x00, 0x00, + // 675 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xb4, 0x94, 0x4f, 0x4f, 0xd4, 0x40, + 0x18, 0xc6, 0x77, 0x80, 0x10, 0x19, 0x10, 0xb4, 0x41, 0xd8, 0x5d, 0xb4, 0x8b, 0x25, 0x84, 0x05, + 0xb2, 0x9d, 0x2c, 0x18, 0x0f, 0xdc, 0x5c, 0x12, 0xe2, 0x65, 0x13, 0x52, 0x63, 0x62, 0xbc, 0x90, + 0xd9, 0xdd, 0x61, 0xa8, 0xd2, 0x99, 0xa6, 0x33, 0x25, 0xf4, 0x4a, 0xbc, 0x6b, 0xe2, 0x49, 0x4f, + 0x1e, 0xd5, 0x13, 0x26, 0x7e, 0x08, 0x8e, 0x44, 0x2f, 0x26, 0x26, 0x6a, 0xc0, 0x04, 0xe3, 0xa7, + 0x30, 0x6d, 0xa7, 0x05, 0x76, 0x5b, 0xc5, 0x18, 0x2f, 0xfb, 0x67, 0x9e, 0xa7, 0xf3, 0xfe, 0xde, + 0x37, 0xcf, 0x5b, 0x38, 0xf9, 0xc8, 0x67, 0x1c, 0x6d, 0x12, 0xe2, 0xe2, 0x00, 0xed, 0xd4, 0x91, + 0xdc, 0x35, 0x5d, 0x8f, 0x4b, 0xae, 0x8d, 0x86, 0x82, 0x19, 0x0b, 0xe6, 0x4e, 0xbd, 0x3c, 0x4e, + 0x39, 0xe5, 0x91, 0x84, 0xc2, 0x5f, 0xb1, 0xab, 0x7c, 0x9d, 0x72, 0x4e, 0xb7, 0x09, 0xc2, 0xae, + 0x8d, 0x30, 0x63, 0x5c, 0x62, 0x69, 0x73, 0x26, 0x94, 0x7a, 0x15, 0x3b, 0x36, 0xe3, 0x28, 0xfa, + 0x54, 0x47, 0x93, 0x6d, 0x2e, 0x1c, 0x2e, 0x90, 0x23, 0x68, 0x58, 0xce, 0x11, 0x54, 0x09, 0xba, + 0x12, 0x5a, 0x58, 0x10, 0xb4, 0x53, 0x6f, 0x11, 0x89, 0xeb, 0xa8, 0xcd, 0x6d, 0xa6, 0xf4, 0x52, + 0xac, 0x6f, 0xc4, 0x08, 0xf1, 0x9f, 0x04, 0xa2, 0xab, 0x07, 0x4a, 0x18, 0x11, 0x76, 0xa2, 0x4e, + 0x75, 0xa9, 0xaa, 0xa5, 0x48, 0x34, 0x9e, 0x00, 0x58, 0x6a, 0x0a, 0x6a, 0x11, 0x6a, 0x0b, 0x49, + 0xbc, 0x35, 0x42, 0xd6, 0x71, 0xb0, 0xca, 0x99, 0xf4, 0x70, 0x5b, 0x6a, 0xb3, 0x70, 0x54, 0x10, + 0xd6, 0x21, 0xde, 0x06, 0xee, 0x74, 0x3c, 0x22, 0x44, 0x11, 0x4c, 0x83, 0xea, 0x90, 0x75, 0x39, + 0x3e, 0xbd, 0x13, 0x1f, 0x6a, 0x2b, 0xf0, 0x52, 0x5b, 0x3d, 0x52, 0xec, 0x9b, 0x06, 0xd5, 0xe1, + 0x25, 0xdd, 0x3c, 0x3f, 0x3d, 0xf3, 0xfc, 0xc5, 0x56, 0xea, 0x5f, 0x19, 0xf8, 0xf1, 0xaa, 0x52, + 0x30, 0x66, 0xe0, 0xcd, 0x5c, 0x0a, 0x8b, 0x08, 0x97, 0x33, 0x41, 0x0c, 0x1f, 0x4e, 0x35, 0x05, + 0xbd, 0xcf, 0xbc, 0x7f, 0x82, 0x9d, 0x87, 0x57, 0x92, 0xe2, 0xa9, 0xb1, 0x2f, 0x32, 0x8e, 0x25, + 0xe7, 0xca, 0xaa, 0xd8, 0x66, 0xe1, 0xcc, 0x6f, 0xca, 0xa6, 0x74, 0x3f, 0x01, 0xbc, 0xd6, 0x14, + 0x74, 0xcd, 0x67, 0x9d, 0xff, 0x0d, 0xa6, 0x05, 0x70, 0x10, 0x3b, 0xdc, 0x67, 0xb2, 0xd8, 0x3f, + 0xdd, 0x5f, 0x1d, 0x5e, 0x2a, 0x99, 0x2a, 0x0f, 0x61, 0x78, 0x4c, 0x15, 0x1e, 0x73, 0x95, 0xdb, + 0xac, 0xb1, 0x76, 0xf0, 0xa5, 0x52, 0x78, 0xfb, 0xb5, 0x52, 0xa5, 0xb6, 0xdc, 0xf2, 0x5b, 0x66, + 0x9b, 0x3b, 0x2a, 0x3c, 0xea, 0xab, 0x26, 0x3a, 0x8f, 0x91, 0x0c, 0x5c, 0x22, 0xa2, 0x07, 0xc4, + 0xcb, 0x93, 0xfd, 0x85, 0x91, 0x6d, 0x42, 0x71, 0x3b, 0xd8, 0x08, 0xe3, 0x27, 0x5e, 0x9f, 0xec, + 0x2f, 0x00, 0x4b, 0x15, 0x54, 0x33, 0xa9, 0xc0, 0x1b, 0x99, 0xbd, 0xa6, 0xd3, 0x78, 0x0a, 0xe0, + 0x58, 0x38, 0x35, 0xb7, 0x83, 0x25, 0x59, 0xc7, 0x1e, 0x76, 0x84, 0x76, 0x1b, 0x0e, 0x61, 0x5f, + 0x6e, 0x71, 0xcf, 0x96, 0x41, 0x3c, 0x82, 0x46, 0xf1, 0xc3, 0xfb, 0xda, 0xb8, 0x62, 0x57, 0xcd, + 0xdd, 0x93, 0x9e, 0xcd, 0xa8, 0x75, 0x6a, 0xd5, 0x6e, 0xc1, 0x41, 0x37, 0xba, 0x41, 0x85, 0x6b, + 0xa2, 0x3b, 0x5c, 0xf1, 0xfd, 0x8d, 0x81, 0xb0, 0x55, 0x4b, 0x79, 0x57, 0x46, 0xf7, 0x4e, 0xf6, + 0x17, 0x4e, 0x6f, 0x31, 0x4a, 0x70, 0xb2, 0x0b, 0x28, 0x81, 0x5d, 0xfa, 0x3c, 0x00, 0xfb, 0x9b, + 0x82, 0x6a, 0x6f, 0x00, 0x9c, 0xc8, 0xd9, 0x84, 0xf9, 0xee, 0x9a, 0xb9, 0x71, 0x2d, 0xd7, 0x2f, + 0x6c, 0x4d, 0xa7, 0x55, 0xdf, 0xfb, 0xf8, 0xfd, 0x79, 0xdf, 0xa2, 0x31, 0x8f, 0x7a, 0xde, 0x46, + 0x28, 0x27, 0xed, 0xef, 0x00, 0x2c, 0xe6, 0xae, 0xc2, 0x62, 0x06, 0x42, 0x9e, 0xb9, 0xbc, 0xfc, + 0x17, 0xe6, 0x94, 0x78, 0x39, 0x22, 0xae, 0x19, 0x8b, 0x19, 0xc4, 0x7e, 0x1e, 0xd6, 0x0b, 0x00, + 0xb5, 0xac, 0xfd, 0xc8, 0x00, 0xe8, 0xb5, 0x95, 0x6b, 0x17, 0xb2, 0xa5, 0x84, 0xb5, 0x88, 0x70, + 0xce, 0x98, 0xcd, 0x20, 0xdc, 0xec, 0x85, 0x78, 0x00, 0x47, 0xce, 0x85, 0xb5, 0x92, 0x35, 0x95, + 0x33, 0x86, 0xf2, 0xdc, 0x1f, 0x0c, 0x09, 0x48, 0xe3, 0xee, 0xc1, 0x91, 0x0e, 0x0e, 0x8f, 0x74, + 0xf0, 0xed, 0x48, 0x07, 0xcf, 0x8e, 0xf5, 0xc2, 0xe1, 0xb1, 0x5e, 0xf8, 0x74, 0xac, 0x17, 0x1e, + 0x9a, 0x67, 0x76, 0x72, 0x35, 0x5a, 0x82, 0x04, 0x47, 0xc4, 0xd0, 0xbb, 0x09, 0x76, 0xb4, 0x9f, + 0xad, 0xc1, 0xe8, 0x9d, 0xbd, 0xfc, 0x2b, 0x00, 0x00, 0xff, 0xff, 0xa4, 0x06, 0xeb, 0xcd, 0xb4, + 0x06, 0x00, 0x00, } // Reference imports to suppress errors if they are not otherwise used. @@ -395,6 +492,8 @@ const _ = grpc.SupportPackageIsVersion4 type MsgClient interface { // RegisterFeeShare registers a new contract for receiving transaction fees RegisterFeePayContract(ctx context.Context, in *MsgRegisterFeePayContract, opts ...grpc.CallOption) (*MsgRegisterFeePayContractResponse, error) + // UnregisterFeeShare unregisters a contract for receiving transaction fees + UnregisterFeePayContract(ctx context.Context, in *MsgUnregisterFeePayContract, opts ...grpc.CallOption) (*MsgUnregisterFeePayContractResponse, error) // Fund a fee pay contract FundFeePayContract(ctx context.Context, in *MsgFundFeePayContract, opts ...grpc.CallOption) (*MsgFundFeePayContractResponse, error) // Update the params of the module through gov v1 type. @@ -418,6 +517,15 @@ func (c *msgClient) RegisterFeePayContract(ctx context.Context, in *MsgRegisterF return out, nil } +func (c *msgClient) UnregisterFeePayContract(ctx context.Context, in *MsgUnregisterFeePayContract, opts ...grpc.CallOption) (*MsgUnregisterFeePayContractResponse, error) { + out := new(MsgUnregisterFeePayContractResponse) + err := c.cc.Invoke(ctx, "/juno.feepay.v1.Msg/UnregisterFeePayContract", in, out, opts...) + if err != nil { + return nil, err + } + return out, nil +} + func (c *msgClient) FundFeePayContract(ctx context.Context, in *MsgFundFeePayContract, opts ...grpc.CallOption) (*MsgFundFeePayContractResponse, error) { out := new(MsgFundFeePayContractResponse) err := c.cc.Invoke(ctx, "/juno.feepay.v1.Msg/FundFeePayContract", in, out, opts...) @@ -440,6 +548,8 @@ func (c *msgClient) UpdateParams(ctx context.Context, in *MsgUpdateParams, opts type MsgServer interface { // RegisterFeeShare registers a new contract for receiving transaction fees RegisterFeePayContract(context.Context, *MsgRegisterFeePayContract) (*MsgRegisterFeePayContractResponse, error) + // UnregisterFeeShare unregisters a contract for receiving transaction fees + UnregisterFeePayContract(context.Context, *MsgUnregisterFeePayContract) (*MsgUnregisterFeePayContractResponse, error) // Fund a fee pay contract FundFeePayContract(context.Context, *MsgFundFeePayContract) (*MsgFundFeePayContractResponse, error) // Update the params of the module through gov v1 type. @@ -453,6 +563,9 @@ type UnimplementedMsgServer struct { func (*UnimplementedMsgServer) RegisterFeePayContract(ctx context.Context, req *MsgRegisterFeePayContract) (*MsgRegisterFeePayContractResponse, error) { return nil, status.Errorf(codes.Unimplemented, "method RegisterFeePayContract not implemented") } +func (*UnimplementedMsgServer) UnregisterFeePayContract(ctx context.Context, req *MsgUnregisterFeePayContract) (*MsgUnregisterFeePayContractResponse, error) { + return nil, status.Errorf(codes.Unimplemented, "method UnregisterFeePayContract not implemented") +} func (*UnimplementedMsgServer) FundFeePayContract(ctx context.Context, req *MsgFundFeePayContract) (*MsgFundFeePayContractResponse, error) { return nil, status.Errorf(codes.Unimplemented, "method FundFeePayContract not implemented") } @@ -482,6 +595,24 @@ func _Msg_RegisterFeePayContract_Handler(srv interface{}, ctx context.Context, d return interceptor(ctx, in, info, handler) } +func _Msg_UnregisterFeePayContract_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(MsgUnregisterFeePayContract) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(MsgServer).UnregisterFeePayContract(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: "/juno.feepay.v1.Msg/UnregisterFeePayContract", + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(MsgServer).UnregisterFeePayContract(ctx, req.(*MsgUnregisterFeePayContract)) + } + return interceptor(ctx, in, info, handler) +} + func _Msg_FundFeePayContract_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { in := new(MsgFundFeePayContract) if err := dec(in); err != nil { @@ -526,6 +657,10 @@ var _Msg_serviceDesc = grpc.ServiceDesc{ MethodName: "RegisterFeePayContract", Handler: _Msg_RegisterFeePayContract_Handler, }, + { + MethodName: "UnregisterFeePayContract", + Handler: _Msg_UnregisterFeePayContract_Handler, + }, { MethodName: "FundFeePayContract", Handler: _Msg_FundFeePayContract_Handler, @@ -604,6 +739,66 @@ func (m *MsgRegisterFeePayContractResponse) MarshalToSizedBuffer(dAtA []byte) (i return len(dAtA) - i, nil } +func (m *MsgUnregisterFeePayContract) 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 *MsgUnregisterFeePayContract) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *MsgUnregisterFeePayContract) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + if len(m.ContractAddress) > 0 { + i -= len(m.ContractAddress) + copy(dAtA[i:], m.ContractAddress) + i = encodeVarintTx(dAtA, i, uint64(len(m.ContractAddress))) + i-- + dAtA[i] = 0x12 + } + if len(m.SenderAddress) > 0 { + i -= len(m.SenderAddress) + copy(dAtA[i:], m.SenderAddress) + i = encodeVarintTx(dAtA, i, uint64(len(m.SenderAddress))) + i-- + dAtA[i] = 0xa + } + return len(dAtA) - i, nil +} + +func (m *MsgUnregisterFeePayContractResponse) 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 *MsgUnregisterFeePayContractResponse) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *MsgUnregisterFeePayContractResponse) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + return len(dAtA) - i, nil +} + func (m *MsgFundFeePayContract) Marshal() (dAtA []byte, err error) { size := m.Size() dAtA = make([]byte, size) @@ -778,6 +973,32 @@ func (m *MsgRegisterFeePayContractResponse) Size() (n int) { return n } +func (m *MsgUnregisterFeePayContract) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + l = len(m.SenderAddress) + if l > 0 { + n += 1 + l + sovTx(uint64(l)) + } + l = len(m.ContractAddress) + if l > 0 { + n += 1 + l + sovTx(uint64(l)) + } + return n +} + +func (m *MsgUnregisterFeePayContractResponse) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + return n +} + func (m *MsgFundFeePayContract) Size() (n int) { if m == nil { return 0 @@ -1008,6 +1229,170 @@ func (m *MsgRegisterFeePayContractResponse) Unmarshal(dAtA []byte) error { } return nil } +func (m *MsgUnregisterFeePayContract) 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: MsgUnregisterFeePayContract: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: MsgUnregisterFeePayContract: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field SenderAddress", 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.SenderAddress = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + case 2: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field ContractAddress", 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.ContractAddress = string(dAtA[iNdEx:postIndex]) + 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 *MsgUnregisterFeePayContractResponse) 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: MsgUnregisterFeePayContractResponse: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: MsgUnregisterFeePayContractResponse: 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 *MsgFundFeePayContract) Unmarshal(dAtA []byte) error { l := len(dAtA) iNdEx := 0 diff --git a/x/feepay/types/tx.pb.gw.go b/x/feepay/types/tx.pb.gw.go index 6a1b0e548..bdd51e724 100644 --- a/x/feepay/types/tx.pb.gw.go +++ b/x/feepay/types/tx.pb.gw.go @@ -69,6 +69,42 @@ func local_request_Msg_RegisterFeePayContract_0(ctx context.Context, marshaler r } +var ( + filter_Msg_UnregisterFeePayContract_0 = &utilities.DoubleArray{Encoding: map[string]int{}, Base: []int(nil), Check: []int(nil)} +) + +func request_Msg_UnregisterFeePayContract_0(ctx context.Context, marshaler runtime.Marshaler, client MsgClient, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) { + var protoReq MsgUnregisterFeePayContract + 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_Msg_UnregisterFeePayContract_0); err != nil { + return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err) + } + + msg, err := client.UnregisterFeePayContract(ctx, &protoReq, grpc.Header(&metadata.HeaderMD), grpc.Trailer(&metadata.TrailerMD)) + return msg, metadata, err + +} + +func local_request_Msg_UnregisterFeePayContract_0(ctx context.Context, marshaler runtime.Marshaler, server MsgServer, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) { + var protoReq MsgUnregisterFeePayContract + 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_Msg_UnregisterFeePayContract_0); err != nil { + return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err) + } + + msg, err := server.UnregisterFeePayContract(ctx, &protoReq) + return msg, metadata, err + +} + var ( filter_Msg_FundFeePayContract_0 = &utilities.DoubleArray{Encoding: map[string]int{}, Base: []int(nil), Check: []int(nil)} ) @@ -134,6 +170,29 @@ func RegisterMsgHandlerServer(ctx context.Context, mux *runtime.ServeMux, server }) + mux.Handle("POST", pattern_Msg_UnregisterFeePayContract_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_Msg_UnregisterFeePayContract_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_Msg_UnregisterFeePayContract_0(ctx, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...) + + }) + mux.Handle("POST", pattern_Msg_FundFeePayContract_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) { ctx, cancel := context.WithCancel(req.Context()) defer cancel() @@ -218,6 +277,26 @@ func RegisterMsgHandlerClient(ctx context.Context, mux *runtime.ServeMux, client }) + mux.Handle("POST", pattern_Msg_UnregisterFeePayContract_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_Msg_UnregisterFeePayContract_0(rctx, inboundMarshaler, client, req, pathParams) + ctx = runtime.NewServerMetadataContext(ctx, md) + if err != nil { + runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) + return + } + + forward_Msg_UnregisterFeePayContract_0(ctx, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...) + + }) + mux.Handle("POST", pattern_Msg_FundFeePayContract_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) { ctx, cancel := context.WithCancel(req.Context()) defer cancel() @@ -244,11 +323,15 @@ func RegisterMsgHandlerClient(ctx context.Context, mux *runtime.ServeMux, client var ( pattern_Msg_RegisterFeePayContract_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2, 2, 3, 2, 4}, []string{"juno", "feepay", "v1", "tx", "registerFeePayContract"}, "", runtime.AssumeColonVerbOpt(false))) + pattern_Msg_UnregisterFeePayContract_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2, 2, 3, 2, 4}, []string{"juno", "feepay", "v1", "tx", "unregisterFeePayContract"}, "", runtime.AssumeColonVerbOpt(false))) + pattern_Msg_FundFeePayContract_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2, 2, 3, 2, 4}, []string{"juno", "feepay", "v1", "tx", "fundFeePayContract"}, "", runtime.AssumeColonVerbOpt(false))) ) var ( forward_Msg_RegisterFeePayContract_0 = runtime.ForwardResponseMessage + forward_Msg_UnregisterFeePayContract_0 = runtime.ForwardResponseMessage + forward_Msg_FundFeePayContract_0 = runtime.ForwardResponseMessage ) From bd89c046f782c626199558c7fa6956cc9074dab7 Mon Sep 17 00:00:00 2001 From: Joel Smith Date: Thu, 14 Sep 2023 09:26:52 -0500 Subject: [PATCH 27/79] Fix refund account address --- x/feepay/client/cli/tx.go | 6 +++--- x/feepay/keeper/keeper.go | 24 +++++------------------- 2 files changed, 8 insertions(+), 22 deletions(-) diff --git a/x/feepay/client/cli/tx.go b/x/feepay/client/cli/tx.go index cf4a5a92b..a18c3696d 100644 --- a/x/feepay/client/cli/tx.go +++ b/x/feepay/client/cli/tx.go @@ -86,7 +86,7 @@ func NewUnregisterFeePayContract() *cobra.Command { cmd := &cobra.Command{ Use: "unregister [contract_bech32]", Short: "Unregister a contract for fee pay.", - Long: "Unregister a contract for fee pay. All remaining funds will return to the contract creator.", + Long: "Unregister a contract for fee pay. All remaining funds will return to the contract admin or the creator (as a fallback).", Args: cobra.ExactArgs(1), RunE: func(cmd *cobra.Command, args []string) error { cliCtx, err := client.GetClientTxContext(cmd) @@ -94,11 +94,11 @@ func NewUnregisterFeePayContract() *cobra.Command { return err } - deployer_address := cliCtx.GetFromAddress() + sender_address := cliCtx.GetFromAddress() contract_address := args[0] msg := &types.MsgUnregisterFeePayContract{ - SenderAddress: deployer_address.String(), + SenderAddress: sender_address.String(), ContractAddress: contract_address, } diff --git a/x/feepay/keeper/keeper.go b/x/feepay/keeper/keeper.go index 0eb01a375..5dce51dbc 100644 --- a/x/feepay/keeper/keeper.go +++ b/x/feepay/keeper/keeper.go @@ -3,6 +3,7 @@ package keeper import ( "fmt" + "cosmossdk.io/math" wasmkeeper "github.com/CosmWasm/wasmd/x/wasm/keeper" "github.com/cometbft/cometbft/libs/log" @@ -177,29 +178,21 @@ func (k Keeper) UnregisterContract(ctx sdk.Context, rfp *types.MsgUnregisterFeeP return types.ErrContractNotRegistered } - ctx.Logger().Error("*", "Registered", true) - // Get fee pay contract contract, err := k.GetContract(ctx, rfp.ContractAddress) if err != nil { return err } - ctx.Logger().Error("*", "Got contract obj", contract) - // Get contract address contractAddr, err := sdk.AccAddressFromBech32(rfp.ContractAddress) if err != nil { return err } - ctx.Logger().Error("*", "Got address", contractAddr) - // Get the contract info contractInfo := k.wasmKeeper.GetContractInfo(ctx, contractAddr) - ctx.Logger().Error("*", "Got contract info", contractInfo) - // Check if sender is the contract owner if contractInfo.Creator != rfp.SenderAddress { return types.ErrContractNotCreator @@ -209,8 +202,6 @@ func (k Keeper) UnregisterContract(ctx sdk.Context, rfp *types.MsgUnregisterFeeP store := prefix.NewStore(ctx.KVStore(k.storeKey), []byte(StoreKeyContracts)) store.Delete([]byte(rfp.ContractAddress)) - ctx.Logger().Error("*", "Deleted contract", true) - // Remove all usage entries for contract store = prefix.NewStore(ctx.KVStore(k.storeKey), []byte(StoreKeyContractUses)) iterator := sdk.KVStorePrefixIterator(store, []byte(rfp.ContractAddress)) @@ -219,24 +210,19 @@ func (k Keeper) UnregisterContract(ctx sdk.Context, rfp *types.MsgUnregisterFeeP store.Delete(iterator.Key()) } - ctx.Logger().Error("*", "Deleted contract usages", true) - // Transfer funds back to contract owner - coins := sdk.NewCoins(sdk.NewCoin(k.bondDenom, sdk.NewIntFromUint64(contract.Balance))) + coins := sdk.NewCoins(sdk.NewCoin(k.bondDenom, math.NewIntFromUint64(contract.Balance))) // Find admin or creator var refundAddr string - if len(contractInfo.Admin) > 0 { + if contractInfo.Admin != "" { refundAddr = contractInfo.Admin } else { refundAddr = contractInfo.Creator } - ctx.Logger().Error("*", "Sent coins", coins) - ctx.Logger().Error("*", "Refund to", refundAddr) - - // TODO: FIX THE FOLLOWING LINE FROM CRASHING THE TX - if err := k.bankKeeper.SendCoinsFromModuleToAccount(ctx, types.ModuleName, sdk.AccAddress(refundAddr), coins); err != nil { + // Send coins from the FeePay module to the refund address + if err := k.bankKeeper.SendCoinsFromModuleToAccount(ctx, types.ModuleName, sdk.MustAccAddressFromBech32(refundAddr), coins); err != nil { return err } From 0c75d4a1eb7cadbf02256e19cfacdb085d869482 Mon Sep 17 00:00:00 2001 From: Joel Smith Date: Thu, 14 Sep 2023 19:01:06 -0500 Subject: [PATCH 28/79] Add Tx Msg Validation --- x/feepay/client/cli/tx.go | 2 -- x/feepay/types/errors.go | 2 ++ x/feepay/types/msg.go | 34 ++++++++++++++++++++++++++++++++++ 3 files changed, 36 insertions(+), 2 deletions(-) diff --git a/x/feepay/client/cli/tx.go b/x/feepay/client/cli/tx.go index a18c3696d..4f7b217a0 100644 --- a/x/feepay/client/cli/tx.go +++ b/x/feepay/client/cli/tx.go @@ -51,8 +51,6 @@ func NewRegisterFeePayContract() *cobra.Command { wallet_limit := args[1] dec_limit, err := strconv.ParseUint(wallet_limit, 10, 64) - // todo bech32 validation - if err != nil { return err } diff --git a/x/feepay/types/errors.go b/x/feepay/types/errors.go index ff29f83f8..dd3fe0a96 100644 --- a/x/feepay/types/errors.go +++ b/x/feepay/types/errors.go @@ -12,4 +12,6 @@ var ( ErrWalletExceededUsageLimit = errorsmod.Register(ModuleName, 5, "wallet exceeded usage limit") ErrContractNotAdmin = errorsmod.Register(ModuleName, 6, "sender is not the contract admin") ErrContractNotCreator = errorsmod.Register(ModuleName, 7, "sender is not the contract creator") + ErrInvalidWalletLimit = errorsmod.Register(ModuleName, 8, "invalid wallet limit; must be between 0 and 1,000,000") + ErrInvalidJunoFundAmount = errorsmod.Register(ModuleName, 9, "fee pay contracts only accept juno funds") ) diff --git a/x/feepay/types/msg.go b/x/feepay/types/msg.go index db43ec860..4114970d5 100644 --- a/x/feepay/types/msg.go +++ b/x/feepay/types/msg.go @@ -26,6 +26,18 @@ func (msg MsgRegisterFeePayContract) Type() string { return TypeMsgRegisterFeePa // ValidateBasic runs stateless checks on the message func (msg MsgRegisterFeePayContract) ValidateBasic() error { + if _, err := sdk.AccAddressFromBech32(msg.SenderAddress); err != nil { + return err + } + + if _, err := sdk.AccAddressFromBech32(msg.Contract.ContractAddress); err != nil { + return err + } + + if msg.Contract.WalletLimit < 0 || msg.Contract.WalletLimit > 1_000_000 { + return ErrInvalidWalletLimit + } + return nil } @@ -48,6 +60,15 @@ func (msg MsgUnregisterFeePayContract) Type() string { return TypeMsgUnregisterF // ValidateBasic runs stateless checks on the message func (msg MsgUnregisterFeePayContract) ValidateBasic() error { + + if _, err := sdk.AccAddressFromBech32(msg.SenderAddress); err != nil { + return err + } + + if _, err := sdk.AccAddressFromBech32(msg.ContractAddress); err != nil { + return err + } + return nil } @@ -70,6 +91,19 @@ func (msg MsgFundFeePayContract) Type() string { return TypeMsgFundFeePayContrac // ValidateBasic runs stateless checks on the message func (msg MsgFundFeePayContract) ValidateBasic() error { + + if _, err := sdk.AccAddressFromBech32(msg.SenderAddress); err != nil { + return err + } + + if _, err := sdk.AccAddressFromBech32(msg.ContractAddress); err != nil { + return err + } + + if len(msg.Amount) != 1 { + return ErrInvalidJunoFundAmount + } + return nil } From 6487f2b9c515f491519807ec312b5d320aff9a56 Mon Sep 17 00:00:00 2001 From: Joel Smith Date: Fri, 15 Sep 2023 15:52:14 -0500 Subject: [PATCH 29/79] Add bech32 validation to queries --- x/feepay/keeper/keeper.go | 23 +++++++++++++++++++++++ x/feepay/types/errors.go | 1 + 2 files changed, 24 insertions(+) diff --git a/x/feepay/keeper/keeper.go b/x/feepay/keeper/keeper.go index 5dce51dbc..acc438374 100644 --- a/x/feepay/keeper/keeper.go +++ b/x/feepay/keeper/keeper.go @@ -84,6 +84,11 @@ func (k Keeper) IsRegisteredContract(ctx sdk.Context, contractAddr string) bool // Get a contract from KV store func (k Keeper) GetContract(ctx sdk.Context, contractAddress string) (*types.FeePayContract, error) { + // Check if address is valid + if _, err := sdk.AccAddressFromBech32(contractAddress); err != nil { + return nil, types.ErrInvalidAddress + } + // Return nil, contract not registered if !k.IsRegisteredContract(ctx, contractAddress) { return nil, types.ErrContractNotRegistered @@ -324,6 +329,15 @@ func (k Keeper) CanContractCoverFee(ctx sdk.Context, contractAddress string, fee // Get the number of times a wallet has interacted with a fee pay contract (err only if contract not registered) func (k Keeper) GetContractUses(ctx sdk.Context, contractAddress string, walletAddress string) (uint64, error) { + // Check if wallet & contract address are valid + if _, err := sdk.AccAddressFromBech32(contractAddress); err != nil { + return 0, types.ErrInvalidAddress.GRPCStatus().Err() + } + + if _, err := sdk.AccAddressFromBech32(walletAddress); err != nil { + return 0, types.ErrInvalidAddress + } + if !k.IsRegisteredContract(ctx, contractAddress) { return 0, types.ErrContractNotRegistered } @@ -389,6 +403,15 @@ func (k Keeper) HasWalletExceededUsageLimit(ctx sdk.Context, contractAddress str // Check if a wallet is eligible to interact with a contract func (k Keeper) IsWalletEligible(ctx sdk.Context, contractAddress string, walletAddress string) (bool, string) { + // Check if wallet & contract address are valid + if _, err := sdk.AccAddressFromBech32(contractAddress); err != nil { + return false, types.ErrInvalidAddress.Error() + } + + if _, err := sdk.AccAddressFromBech32(walletAddress); err != nil { + return false, types.ErrInvalidAddress.Error() + } + // Check if contract is registered if !k.IsRegisteredContract(ctx, contractAddress) { return false, types.ErrContractNotRegistered.Error() diff --git a/x/feepay/types/errors.go b/x/feepay/types/errors.go index dd3fe0a96..8f52e058f 100644 --- a/x/feepay/types/errors.go +++ b/x/feepay/types/errors.go @@ -14,4 +14,5 @@ var ( ErrContractNotCreator = errorsmod.Register(ModuleName, 7, "sender is not the contract creator") ErrInvalidWalletLimit = errorsmod.Register(ModuleName, 8, "invalid wallet limit; must be between 0 and 1,000,000") ErrInvalidJunoFundAmount = errorsmod.Register(ModuleName, 9, "fee pay contracts only accept juno funds") + ErrInvalidAddress = errorsmod.Register(ModuleName, 10, "invalid bech32 address") ) From bd893995b608944e359bceed3a75aa6181e35d3f Mon Sep 17 00:00:00 2001 From: Joel Smith Date: Fri, 15 Sep 2023 15:56:18 -0500 Subject: [PATCH 30/79] Update wallet limit bounds --- x/feepay/types/msg.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/x/feepay/types/msg.go b/x/feepay/types/msg.go index 4114970d5..666226284 100644 --- a/x/feepay/types/msg.go +++ b/x/feepay/types/msg.go @@ -34,7 +34,7 @@ func (msg MsgRegisterFeePayContract) ValidateBasic() error { return err } - if msg.Contract.WalletLimit < 0 || msg.Contract.WalletLimit > 1_000_000 { + if msg.Contract.WalletLimit < 1 || msg.Contract.WalletLimit > 1_000_000 { return ErrInvalidWalletLimit } From 9de66404d4b88770e6b63ee0801467089c5fb1c0 Mon Sep 17 00:00:00 2001 From: Joel Smith Date: Tue, 19 Sep 2023 16:19:40 -0500 Subject: [PATCH 31/79] Refactor queries, txs, & keeper --- app/modules.go | 4 +- proto/juno/feepay/v1/query.proto | 6 +- proto/juno/feepay/v1/tx.proto | 4 +- .../ante/{dedcuct_fee.go => deduct_fee.go} | 42 +- x/feepay/client/cli/query.go | 2 +- x/feepay/client/cli/tx.go | 6 +- x/feepay/genesis.go | 2 +- x/feepay/keeper/feepay.go | 290 ++++++++++++++ x/feepay/keeper/grpc_query.go | 47 ++- x/feepay/keeper/keeper.go | 373 +----------------- x/feepay/keeper/msg_server.go | 12 +- x/feepay/keeper/params.go | 2 +- x/feepay/module.go | 17 +- x/feepay/types/errors.go | 1 + x/feepay/types/msg.go | 4 +- x/feepay/types/query.pb.go | 176 +++------ x/feepay/types/tx.pb.go | 112 +++--- 17 files changed, 498 insertions(+), 602 deletions(-) rename x/feepay/ante/{dedcuct_fee.go => deduct_fee.go} (88%) create mode 100644 x/feepay/keeper/feepay.go diff --git a/app/modules.go b/app/modules.go index d9ed90cf3..bee9b2268 100644 --- a/app/modules.go +++ b/app/modules.go @@ -150,7 +150,7 @@ func appModules( ibcfee.NewAppModule(app.AppKeepers.IBCFeeKeeper), tokenfactory.NewAppModule(app.AppKeepers.TokenFactoryKeeper, app.AppKeepers.AccountKeeper, app.AppKeepers.BankKeeper, app.GetSubspace(tokenfactorytypes.ModuleName)), globalfee.NewAppModule(appCodec, app.AppKeepers.GlobalFeeKeeper, bondDenom), - feepay.NewAppModule(app.AppKeepers.FeePayKeeper, app.AppKeepers.AccountKeeper, app.GetSubspace(feepaytypes.ModuleName)), + feepay.NewAppModule(app.AppKeepers.FeePayKeeper, app.AppKeepers.AccountKeeper), feeshare.NewAppModule(app.AppKeepers.FeeShareKeeper, app.AppKeepers.AccountKeeper, app.GetSubspace(feesharetypes.ModuleName)), wasm.NewAppModule(appCodec, &app.AppKeepers.WasmKeeper, app.AppKeepers.StakingKeeper, app.AppKeepers.AccountKeeper, app.AppKeepers.BankKeeper, app.MsgServiceRouter(), app.GetSubspace(wasmtypes.ModuleName)), ica.NewAppModule(&app.AppKeepers.ICAControllerKeeper, &app.AppKeepers.ICAHostKeeper), @@ -191,7 +191,7 @@ func simulationModules( wasm.NewAppModule(appCodec, &app.AppKeepers.WasmKeeper, app.AppKeepers.StakingKeeper, app.AppKeepers.AccountKeeper, app.AppKeepers.BankKeeper, app.MsgServiceRouter(), app.GetSubspace(wasmtypes.ModuleName)), ibc.NewAppModule(app.AppKeepers.IBCKeeper), transfer.NewAppModule(app.AppKeepers.TransferKeeper), - feepay.NewAppModule(app.AppKeepers.FeePayKeeper, app.AppKeepers.AccountKeeper, app.GetSubspace(feepaytypes.ModuleName)), + feepay.NewAppModule(app.AppKeepers.FeePayKeeper, app.AppKeepers.AccountKeeper), feeshare.NewAppModule(app.AppKeepers.FeeShareKeeper, app.AppKeepers.AccountKeeper, app.GetSubspace(feesharetypes.ModuleName)), ibcfee.NewAppModule(app.AppKeepers.IBCFeeKeeper), } diff --git a/proto/juno/feepay/v1/query.proto b/proto/juno/feepay/v1/query.proto index 32b7ffc50..296952be7 100644 --- a/proto/juno/feepay/v1/query.proto +++ b/proto/juno/feepay/v1/query.proto @@ -41,7 +41,7 @@ message QueryFeePayContract { // QueryFeePayContractResponse defines the response for retrieving a single fee pay contract message QueryFeePayContractResponse { // contract defines the fee pay contract - FeePayContract contract = 1; + FeePayContract fee_pay_contract = 1; } // Message for querying a list of fee pay contracts @@ -53,7 +53,7 @@ message QueryFeePayContracts { // The response for querying all fee pay contracts message QueryFeePayContractsResponse { // A slice of all the stored fee pay contracts - repeated FeePayContract contracts = 1 [ (gogoproto.nullable) = false ]; + repeated FeePayContract fee_pay_contracts = 1 [ (gogoproto.nullable) = false ]; // pagination defines the pagination in the response. cosmos.base.query.v1beta1.PageResponse pagination = 2; } @@ -84,6 +84,4 @@ message QueryFeePayWalletIsEligible { message QueryFeePayWalletIsEligibleResponse { // The eligibility of the wallet for fee pay contract interactions bool eligible = 1; - // The reason (if any) for the wallet being ineligible for fee pay contract interactions - string reason = 2; } \ No newline at end of file diff --git a/proto/juno/feepay/v1/tx.proto b/proto/juno/feepay/v1/tx.proto index 12141f61d..dbde95622 100644 --- a/proto/juno/feepay/v1/tx.proto +++ b/proto/juno/feepay/v1/tx.proto @@ -44,7 +44,7 @@ message MsgRegisterFeePayContract { string sender_address = 1; // The fee pay contract to register. - FeePayContract contract = 2; + FeePayContract fee_pay_contract = 2; } // The response message for registering a fee pay contract. @@ -95,7 +95,7 @@ message MsgUpdateParams { // authority is the address that controls the module (defaults to x/gov unless overwritten). string authority = 1 [(cosmos_proto.scalar) = "cosmos.AddressString"]; - // params defines the x/feeshare parameters to update. + // params defines the x/feepay parameters to update. // // NOTE: All parameters must be supplied. Params params = 2 [(gogoproto.nullable) = false]; diff --git a/x/feepay/ante/dedcuct_fee.go b/x/feepay/ante/deduct_fee.go similarity index 88% rename from x/feepay/ante/dedcuct_fee.go rename to x/feepay/ante/deduct_fee.go index 8c95e60ab..9d9483b4d 100644 --- a/x/feepay/ante/dedcuct_fee.go +++ b/x/feepay/ante/deduct_fee.go @@ -36,6 +36,7 @@ type DeductFeeDecorator struct { // type TxFeeChecker func(ctx sdk.Context, tx sdk.Tx) (sdk.Coins, int64, error) txFeeChecker ante.TxFeeChecker + // TODO: test this. bondDenom string } @@ -58,7 +59,6 @@ func NewDeductFeeDecorator(fpk feepaykeeper.Keeper, gfk globalfeekeeper.Keeper, func (dfd DeductFeeDecorator) AnteHandle(ctx sdk.Context, tx sdk.Tx, simulate bool, next sdk.AnteHandler) (sdk.Context, error) { feeTx, ok := tx.(sdk.FeeTx) if !ok { - // return ctx, errorsmod.Wrap(sdkerrors.ErrTxDecode, "Tx must be a FeeTx") return ctx, errorsmod.Wrap(sdkerrors.ErrTxDecode, "Tx must be a FeeTx") } @@ -151,9 +151,10 @@ func (dfd DeductFeeDecorator) handleZeroFees(ctx sdk.Context, deductFeesFromAcc msg := tx.GetMsgs()[0] cw := msg.(*wasmtypes.MsgExecuteContract) - // We need to check if it is a valid contract. Utilize the FeePay Keeper for validation - if !dfd.feepayKeeper.IsRegisteredContract(ctx, cw.GetContract()) { - return feepaytypes.ErrContractNotRegistered + // Get the fee pay contract + feepayContract, err := dfd.feepayKeeper.GetContract(ctx, cw.GetContract()) + if err != nil { + return errorsmod.Wrapf(err, "error getting contract %s", cw.GetContract()) } // Get the fee price in the chain denom @@ -176,19 +177,14 @@ func (dfd DeductFeeDecorator) handleZeroFees(ctx sdk.Context, deductFeesFromAcc ctx.Logger().Error("HandleZeroFees", "RequiredFee", requiredFee) - // Get the fee pay contract - feepayContract, err := dfd.feepayKeeper.GetContract(ctx, cw.GetContract()) - if err != nil { - return err - } - // Check if wallet exceeded usage limit on contract - if dfd.feepayKeeper.HasWalletExceededUsageLimit(ctx, cw.GetContract(), deductFeesFromAcc.GetAddress().String()) { + accBech32 := deductFeesFromAcc.GetAddress().String() + if dfd.feepayKeeper.HasWalletExceededUsageLimit(ctx, feepayContract, accBech32) { return errorsmod.Wrapf(feepaytypes.ErrWalletExceededUsageLimit, "wallet has exceeded usage limit (%d)", feepayContract.WalletLimit) } // Check if the contract has enough funds to cover the fee - if !dfd.feepayKeeper.CanContractCoverFee(ctx, cw.GetContract(), requiredFee.Uint64()) { + if !dfd.feepayKeeper.CanContractCoverFee(ctx, feepayContract, requiredFee.Uint64()) { return errorsmod.Wrapf(feepaytypes.ErrContractNotEnoughFunds, "contract has insufficient funds; expected: %d, got: %d", requiredFee.Uint64(), feepayContract.Balance) } @@ -198,23 +194,16 @@ func (dfd DeductFeeDecorator) handleZeroFees(ctx sdk.Context, deductFeesFromAcc ctx.Logger().Error("HandleZeroFees", "Payment", payment) // Cover the fees of the transaction, send from FeePay Module to FeeCollector Module - err = dfd.bankKeeper.SendCoinsFromModuleToModule(ctx, feepaytypes.ModuleName, types.FeeCollectorName, payment) - if err != nil { + if err := dfd.bankKeeper.SendCoinsFromModuleToModule(ctx, feepaytypes.ModuleName, types.FeeCollectorName, payment); err != nil { return errorsmod.Wrapf(sdkerrors.ErrInsufficientFunds, "error transfering funds from FeePay to FeeCollector; %s", err) } // Deduct the fee from the contract balance - dfd.feepayKeeper.UpdateContractBalance(ctx, cw.GetContract(), feepayContract.Balance-requiredFee.Uint64()) + dfd.feepayKeeper.SetContractBalance(ctx, feepayContract, feepayContract.Balance-requiredFee.Uint64()) // Increment wallet usage - uses, err := dfd.feepayKeeper.GetContractUses(ctx, cw.GetContract(), deductFeesFromAcc.GetAddress().String()) - if err != nil { - return err - } + dfd.feepayKeeper.IncrementContractUses(ctx, feepayContract, accBech32, 1) - if err := dfd.feepayKeeper.SetContractUses(ctx, cw.GetContract(), deductFeesFromAcc.GetAddress().String(), uses+1); err != nil { - return err - } return nil } @@ -224,7 +213,6 @@ func DeductFees(bankKeeper types.BankKeeper, ctx sdk.Context, acc types.AccountI return errorsmod.Wrapf(sdkerrors.ErrInsufficientFee, "invalid fee amount: %s", fees) } - // TODO: if 0 fees are sent, then the module account needs to pay it. (prepay module) ELSE have the standard user err := bankKeeper.SendCoinsFromAccountToModule(ctx, acc.GetAddress(), types.FeeCollectorName, fees) if err != nil { return errorsmod.Wrapf(sdkerrors.ErrInsufficientFunds, err.Error()) @@ -234,6 +222,7 @@ func DeductFees(bankKeeper types.BankKeeper, ctx sdk.Context, acc types.AccountI } // from the SDK pulled out +// TODO: modify this in part with globalfee for bypasses with ibc, force set 0? need an override in the event of DOS attacks func checkTxFeeWithValidatorMinGasPrices(ctx sdk.Context, tx sdk.Tx) (sdk.Coins, int64, error) { feeTx, ok := tx.(sdk.FeeTx) if !ok { @@ -246,6 +235,7 @@ func checkTxFeeWithValidatorMinGasPrices(ctx sdk.Context, tx sdk.Tx) (sdk.Coins, // Ensure that the provided fees meet a minimum threshold for the validator, // if this is a CheckTx. This is only for local mempool purposes, and thus // is only ran on check tx. + // TODO: see if we can remove, since we do call this twice. if ctx.IsCheckTx() && !isValidFeePayTransaction(ctx, tx, feeTx.GetFee()) { minGasPrices := ctx.MinGasPrices() if !minGasPrices.IsZero() { @@ -292,15 +282,11 @@ func getTxPriority(fee sdk.Coins, gas int64) int64 { // Check if a transaction should be processed as a FeePay transaction. // A valid FeePay transaction has no fee, and only 1 message for executing a contract. func isValidFeePayTransaction(ctx sdk.Context, tx sdk.Tx, fee sdk.Coins) bool { - - ctx.Logger().Error("FeePayAnte", "IsZero", fee.IsZero(), "Msgs", len(tx.GetMsgs())) + // TODO: Future allow for multiple msgs. // Check if fee is zero, and tx has only 1 message for executing a contract if fee.IsZero() && len(tx.GetMsgs()) == 1 { _, ok := (tx.GetMsgs()[0]).(*wasmtypes.MsgExecuteContract) - - ctx.Logger().Error("FeePayAnte", "IsCWExecuteContract", ok) - return ok } diff --git a/x/feepay/client/cli/query.go b/x/feepay/client/cli/query.go index 71f659610..65b731e76 100644 --- a/x/feepay/client/cli/query.go +++ b/x/feepay/client/cli/query.go @@ -139,7 +139,7 @@ func NewQueryFeePayContractUsage() *cobra.Command { // Query if a wallet is eligible func NewQueryWalletIsEligible() *cobra.Command { cmd := &cobra.Command{ - Use: "eligible [contract_address] [wallet_address]", + Use: "is-eligible [contract_address] [wallet_address]", Short: "Query if a wallet is eligible to interact with a FeePay contract", Args: cobra.ExactArgs(2), RunE: func(cmd *cobra.Command, args []string) error { diff --git a/x/feepay/client/cli/tx.go b/x/feepay/client/cli/tx.go index 4f7b217a0..2461fffd8 100644 --- a/x/feepay/client/cli/tx.go +++ b/x/feepay/client/cli/tx.go @@ -28,6 +28,7 @@ func NewTxCmd() *cobra.Command { NewRegisterFeePayContract(), NewUnregisterFeePayContract(), NewFundFeePayContract(), + // TODO: update wallet limit for usage. (0 = disabled) ) return txCmd } @@ -38,7 +39,6 @@ func NewRegisterFeePayContract() *cobra.Command { cmd := &cobra.Command{ Use: "register [contract_bech32] [wallet_limit]", Short: "Register a contract for fee pay. Only the contract admin can register a contract.", - Long: "Register a contract for fee pay. Only the contract admin can register a contract.", Args: cobra.ExactArgs(2), RunE: func(cmd *cobra.Command, args []string) error { cliCtx, err := client.GetClientTxContext(cmd) @@ -62,8 +62,8 @@ func NewRegisterFeePayContract() *cobra.Command { } msg := &types.MsgRegisterFeePayContract{ - SenderAddress: deployer_address.String(), - Contract: fpc, + SenderAddress: deployer_address.String(), + FeePayContract: fpc, } if err := msg.ValidateBasic(); err != nil { diff --git a/x/feepay/genesis.go b/x/feepay/genesis.go index afe5520cc..47cee6245 100644 --- a/x/feepay/genesis.go +++ b/x/feepay/genesis.go @@ -13,7 +13,7 @@ func InitGenesis( k keeper.Keeper, data types.GenesisState, ) { - + // TODO: impl, just remember that ParamsKey is going to be nil? } // ExportGenesis export module state diff --git a/x/feepay/keeper/feepay.go b/x/feepay/keeper/feepay.go new file mode 100644 index 000000000..bfc7f5f0d --- /dev/null +++ b/x/feepay/keeper/feepay.go @@ -0,0 +1,290 @@ +package keeper + +import ( + "cosmossdk.io/math" + wasmtypes "github.com/CosmWasm/wasmd/x/wasm/types" + "github.com/CosmosContracts/juno/v17/x/feepay/types" + "github.com/cosmos/cosmos-sdk/store/prefix" + sdk "github.com/cosmos/cosmos-sdk/types" + "github.com/cosmos/cosmos-sdk/types/query" +) + +// Check if a contract is registered as a fee pay contract +func (k Keeper) IsContractRegistered(ctx sdk.Context, contractAddr string) bool { + store := prefix.NewStore(ctx.KVStore(k.storeKey), []byte(StoreKeyContracts)) + return store.Has([]byte(contractAddr)) +} + +// Get a contract from KV store +func (k Keeper) GetContract(ctx sdk.Context, contractAddress string) (*types.FeePayContract, error) { + + // Return nil, contract not registered + if !k.IsContractRegistered(ctx, contractAddress) { + return nil, types.ErrContractNotRegistered + } + + store := prefix.NewStore(ctx.KVStore(k.storeKey), []byte(StoreKeyContracts)) + + key := []byte(contractAddress) + bz := store.Get(key) + + var fpc types.FeePayContract + if err := k.cdc.Unmarshal(bz, &fpc); err != nil { + return nil, err + } + + return &fpc, nil +} + +// Get all registered fee pay contracts +func (k Keeper) GetAllContracts(ctx sdk.Context, pag *query.PageRequest) (*types.QueryFeePayContractsResponse, error) { + + store := prefix.NewStore(ctx.KVStore(k.storeKey), []byte(StoreKeyContracts)) + + // Filter and paginate all contracts + results, pageRes, err := query.GenericFilteredPaginate( + k.cdc, + store, + pag, + func(key []byte, value *types.FeePayContract) (*types.FeePayContract, error) { + return value, nil + }, + func() *types.FeePayContract { + return &types.FeePayContract{} + }, + ) + + if err != nil { + return nil, err + } + + // Dereference pointer array of contracts + var contracts []types.FeePayContract + for _, contract := range results { + contracts = append(contracts, *contract) + } + + return &types.QueryFeePayContractsResponse{ + FeePayContracts: contracts, + Pagination: pageRes, + }, nil +} + +// Register the contract in the module store +func (k Keeper) RegisterContract(ctx sdk.Context, rfp *types.MsgRegisterFeePayContract) error { + + // Return false because the contract was already registered + if k.IsContractRegistered(ctx, rfp.FeePayContract.ContractAddress) { + return types.ErrContractAlreadyRegistered + } + + // Check if sender is the owner of the cw contract + contractAddr, err := sdk.AccAddressFromBech32(rfp.FeePayContract.ContractAddress) + if err != nil { + return err + } + + if ok := k.wasmKeeper.HasContractInfo(ctx, contractAddr); !ok { + return types.ErrInvalidCWContract + } + + // Get the contract owner + contractInfo := k.wasmKeeper.GetContractInfo(ctx, contractAddr) + + // Check if sender is contract manager + if ok, err := k.IsContractManager(rfp.SenderAddress, contractInfo); !ok { + return err + } + + // Register the new fee pay contract in the KV store + store := prefix.NewStore(ctx.KVStore(k.storeKey), []byte(StoreKeyContracts)) + key := []byte(rfp.FeePayContract.ContractAddress) + bz := k.cdc.MustMarshal(rfp.FeePayContract) + + store.Set(key, bz) + return nil +} + +// Unregister contract (loop through usage store & remove all usage entries for contract) +func (k Keeper) UnregisterContract(ctx sdk.Context, rfp *types.MsgUnregisterFeePayContract) error { + + // Get fee pay contract + contract, err := k.GetContract(ctx, rfp.ContractAddress) + if err != nil { + return err + } + + // Get contract address + contractAddr, err := sdk.AccAddressFromBech32(rfp.ContractAddress) + if err != nil { + return err + } + + // Ensure CW contract is valid + if ok := k.wasmKeeper.HasContractInfo(ctx, contractAddr); !ok { + return types.ErrInvalidCWContract + } + + // Get the contract info + contractInfo := k.wasmKeeper.GetContractInfo(ctx, contractAddr) + + // Check if sender is the contract manager + if ok, err := k.IsContractManager(rfp.SenderAddress, contractInfo); !ok { + return err + } + + // Remove contract from KV store + store := prefix.NewStore(ctx.KVStore(k.storeKey), []byte(StoreKeyContracts)) + store.Delete([]byte(rfp.ContractAddress)) + + // Remove all usage entries for contract + store = prefix.NewStore(ctx.KVStore(k.storeKey), []byte(StoreKeyContractUses)) + iterator := sdk.KVStorePrefixIterator(store, []byte(rfp.ContractAddress)) + + for ; iterator.Valid(); iterator.Next() { + store.Delete(iterator.Key()) + } + + // Transfer funds back to contract owner + coins := sdk.NewCoins(sdk.NewCoin(k.bondDenom, math.NewIntFromUint64(contract.Balance))) + + // Default refund address to admin, fallback to creator + var refundAddr string + if contractInfo.Admin != "" { + refundAddr = contractInfo.Admin + } else { + refundAddr = contractInfo.Creator + } + + // Send coins from the FeePay module to the refund address + if err := k.bankKeeper.SendCoinsFromModuleToAccount(ctx, types.ModuleName, sdk.MustAccAddressFromBech32(refundAddr), coins); err != nil { + return err + } + + return nil +} + +// Set the contract balance in the KV store +func (k Keeper) SetContractBalance(ctx sdk.Context, fpc *types.FeePayContract, newBalance uint64) { + + // Get the existing contract in KV store + store := prefix.NewStore(ctx.KVStore(k.storeKey), []byte(StoreKeyContracts)) + + // Set new balance and save to KV store + fpc.Balance = newBalance + store.Set([]byte(fpc.ContractAddress), k.cdc.MustMarshal(fpc)) +} + +// Fund an existing fee pay contract +func (k Keeper) FundContract(ctx sdk.Context, fpc *types.FeePayContract, senderAddr sdk.AccAddress, coins sdk.Coins) error { + + // Only transfer the bond denom + var transferCoin sdk.Coin + for _, c := range coins { + if c.Denom == k.bondDenom { + transferCoin = c + } + } + + // Transfer from sender to module + if err := k.bankKeeper.SendCoinsFromAccountToModule(ctx, senderAddr, types.ModuleName, sdk.NewCoins(transferCoin)); err != nil { + return err + } + + // Increment the fpc balance + k.SetContractBalance(ctx, fpc, fpc.Balance+transferCoin.Amount.Uint64()) + return nil +} + +// Check if a fee pay contract has a balance greater than or equal to the fee +func (k Keeper) CanContractCoverFee(ctx sdk.Context, fpc *types.FeePayContract, fee uint64) bool { + return fpc.Balance >= fee +} + +// Get the number of times a wallet has interacted with a fee pay contract (err only if contract not registered) +func (k Keeper) GetContractUses(ctx sdk.Context, fpc *types.FeePayContract, walletAddress string) (uint64, error) { + + // Get usage from store + store := prefix.NewStore(ctx.KVStore(k.storeKey), []byte(StoreKeyContractUses)) + key := []byte(fpc.ContractAddress + "-" + walletAddress) + bz := store.Get(key) + + var walletUsage types.FeePayWalletUsage + if err := k.cdc.Unmarshal(bz, &walletUsage); err != nil { + return 0, err + } + + return walletUsage.Uses, nil +} + +// Set the number of times a wallet has interacted with a fee pay contract +func (k Keeper) IncrementContractUses(ctx sdk.Context, fpc *types.FeePayContract, walletAddress string, increment uint64) error { + + uses, err := k.GetContractUses(ctx, fpc, walletAddress) + if err != nil { + return err + } + + // Get store, key, & value for setting usage + store := prefix.NewStore(ctx.KVStore(k.storeKey), []byte(StoreKeyContractUses)) + key := []byte(fpc.ContractAddress + "-" + walletAddress) + bz, err := k.cdc.Marshal(&types.FeePayWalletUsage{ + ContractAddress: fpc.ContractAddress, + WalletAddress: walletAddress, + Uses: uses + increment, + }) + + if err != nil { + return err + } + + store.Set(key, bz) + return nil +} + +// Check if a wallet exceeded usage limit (defaults to true if contract not registered) +func (k Keeper) HasWalletExceededUsageLimit(ctx sdk.Context, fpc *types.FeePayContract, walletAddress string) bool { + + // Get account uses + uses, err := k.GetContractUses(ctx, fpc, walletAddress) + if err != nil { + return true + } + + // Return if the wallet has used the contract too many times + return uses >= fpc.WalletLimit +} + +// Check if a wallet is eligible to interact with a contract +func (k Keeper) IsWalletEligible(ctx sdk.Context, fpc *types.FeePayContract, walletAddress string) (bool, error) { + + // Check if wallet has exceeded usage limit + if k.HasWalletExceededUsageLimit(ctx, fpc, walletAddress) { + return false, types.ErrWalletExceededUsageLimit + } + + // Check if contract has enough funds + if fpc.Balance == 0 { + return true, types.ErrContractNotEnoughFunds + } + + return true, nil +} + +// Check if the sender is the designated contract manager for the FeePay contract. If +// an admin is present, they are considered the manager. If there is no admin, the +// contract creator is considered the manager. +func (k Keeper) IsContractManager(senderAddress string, contractInfo *wasmtypes.ContractInfo) (bool, error) { + // Flags for admin existence & sender being admin/creator + adminExists := len(contractInfo.Admin) > 0 + isSenderAdmin := contractInfo.Admin == senderAddress + isSenderCreator := contractInfo.Creator == senderAddress + + if adminExists && !isSenderAdmin { + return false, types.ErrContractNotAdmin + } else if !adminExists && !isSenderCreator { + return false, types.ErrContractNotCreator + } + + return true, nil +} diff --git a/x/feepay/keeper/grpc_query.go b/x/feepay/keeper/grpc_query.go index be6f81c55..13b60a18b 100644 --- a/x/feepay/keeper/grpc_query.go +++ b/x/feepay/keeper/grpc_query.go @@ -22,12 +22,17 @@ func NewQuerier(k Keeper) Querier { // FeePayContract implements types.QueryServer. func (q Querier) FeePayContract(ctx context.Context, req *types.QueryFeePayContract) (*types.QueryFeePayContractResponse, error) { + // Check if contract address are valid + if _, err := sdk.AccAddressFromBech32(req.ContractAddress); err != nil { + return nil, types.ErrInvalidAddress + } + sdkCtx := sdk.UnwrapSDKContext(ctx) contract, err := q.Keeper.GetContract(sdkCtx, req.ContractAddress) return &types.QueryFeePayContractResponse{ - Contract: contract, + FeePayContract: contract, }, err } @@ -36,7 +41,7 @@ func (q Querier) FeePayContracts(ctx context.Context, req *types.QueryFeePayCont sdkCtx := sdk.UnwrapSDKContext(ctx) - res, err := q.Keeper.GetAllContracts(sdkCtx, req) + res, err := q.Keeper.GetAllContracts(sdkCtx, req.Pagination) if err != nil { return nil, err @@ -47,10 +52,24 @@ func (q Querier) FeePayContracts(ctx context.Context, req *types.QueryFeePayCont // FeePayContractUses implements types.QueryServer. func (q Querier) FeePayContractUses(ctx context.Context, req *types.QueryFeePayContractUses) (*types.QueryFeePayContractUsesResponse, error) { + // Check if wallet & contract address are valid + if _, err := sdk.AccAddressFromBech32(req.ContractAddress); err != nil { + return nil, types.ErrInvalidAddress + } + + if _, err := sdk.AccAddressFromBech32(req.WalletAddress); err != nil { + return nil, types.ErrInvalidAddress + } sdkCtx := sdk.UnwrapSDKContext(ctx) - uses, err := q.Keeper.GetContractUses(sdkCtx, req.ContractAddress, req.WalletAddress) + // Get contract from KV store + fpc, err := q.Keeper.GetContract(sdkCtx, req.ContractAddress) + if err != nil { + return nil, err + } + + uses, err := q.Keeper.GetContractUses(sdkCtx, fpc, req.WalletAddress) return &types.QueryFeePayContractUsesResponse{ Uses: uses, @@ -59,13 +78,27 @@ func (q Querier) FeePayContractUses(ctx context.Context, req *types.QueryFeePayC // FeePayContractEligible implements types.QueryServer. func (q Querier) FeePayWalletIsEligible(ctx context.Context, req *types.QueryFeePayWalletIsEligible) (*types.QueryFeePayWalletIsEligibleResponse, error) { + // Check if wallet & contract address are valid + if _, err := sdk.AccAddressFromBech32(req.ContractAddress); err != nil { + return nil, types.ErrInvalidAddress + } + + if _, err := sdk.AccAddressFromBech32(req.WalletAddress); err != nil { + return nil, types.ErrInvalidAddress + } sdkCtx := sdk.UnwrapSDKContext(ctx) - eligible, reason := q.Keeper.IsWalletEligible(sdkCtx, req.ContractAddress, req.WalletAddress) + // Get fee pay contract + fpc, err := q.Keeper.GetContract(sdkCtx, req.ContractAddress) + if err != nil { + return nil, err + } + + // Return if wallet is eligible + isEligible, err := q.Keeper.IsWalletEligible(sdkCtx, fpc, req.WalletAddress) return &types.QueryFeePayWalletIsEligibleResponse{ - Eligible: eligible, - Reason: reason, - }, nil + Eligible: isEligible, + }, err } diff --git a/x/feepay/keeper/keeper.go b/x/feepay/keeper/keeper.go index acc438374..912307110 100644 --- a/x/feepay/keeper/keeper.go +++ b/x/feepay/keeper/keeper.go @@ -3,21 +3,17 @@ package keeper import ( "fmt" - "cosmossdk.io/math" wasmkeeper "github.com/CosmWasm/wasmd/x/wasm/keeper" "github.com/cometbft/cometbft/libs/log" "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" - types "github.com/CosmosContracts/juno/v17/x/feepay/types" - revtypes "github.com/CosmosContracts/juno/v17/x/feeshare/types" + feepaytypes "github.com/CosmosContracts/juno/v17/x/feepay/types" + feesharetypes "github.com/CosmosContracts/juno/v17/x/feeshare/types" bankkeeper "github.com/cosmos/cosmos-sdk/x/bank/keeper" - - "github.com/cosmos/cosmos-sdk/types/query" ) const ( @@ -33,7 +29,7 @@ type Keeper struct { bankKeeper *bankkeeper.BaseKeeper wasmKeeper wasmkeeper.Keeper - accountKeeper revtypes.AccountKeeper + accountKeeper feesharetypes.AccountKeeper bondDenom string @@ -48,7 +44,7 @@ func NewKeeper( cdc codec.BinaryCodec, bk *bankkeeper.BaseKeeper, wk wasmkeeper.Keeper, - ak revtypes.AccountKeeper, + ak feesharetypes.AccountKeeper, bondDenom string, authority string, ) Keeper { @@ -70,364 +66,5 @@ func (k Keeper) GetAuthority() string { // Logger returns a module-specific logger. func (k Keeper) Logger(ctx sdk.Context) log.Logger { - return ctx.Logger().With("module", fmt.Sprintf("x/%s", revtypes.ModuleName)) -} - -// === TODO: MOVE BELOW FUNCTIONS TO NEW FILE === - -// Check if a contract is registered as a fee pay contract -func (k Keeper) IsRegisteredContract(ctx sdk.Context, contractAddr string) bool { - store := prefix.NewStore(ctx.KVStore(k.storeKey), []byte(StoreKeyContracts)) - return store.Has([]byte(contractAddr)) -} - -// Get a contract from KV store -func (k Keeper) GetContract(ctx sdk.Context, contractAddress string) (*types.FeePayContract, error) { - - // Check if address is valid - if _, err := sdk.AccAddressFromBech32(contractAddress); err != nil { - return nil, types.ErrInvalidAddress - } - - // Return nil, contract not registered - if !k.IsRegisteredContract(ctx, contractAddress) { - return nil, types.ErrContractNotRegistered - } - - store := prefix.NewStore(ctx.KVStore(k.storeKey), []byte(StoreKeyContracts)) - - key := []byte(contractAddress) - bz := store.Get(key) - - var fpc types.FeePayContract - if err := k.cdc.Unmarshal(bz, &fpc); err != nil { - return nil, err - } - - return &fpc, nil -} - -// Get all registered fee pay contracts -func (k Keeper) GetAllContracts(ctx sdk.Context, req *types.QueryFeePayContracts) (*types.QueryFeePayContractsResponse, error) { - - store := prefix.NewStore(ctx.KVStore(k.storeKey), []byte(StoreKeyContracts)) - - // Filter and paginate all contracts - results, pageRes, err := query.GenericFilteredPaginate( - k.cdc, - store, - req.Pagination, - func(key []byte, value *types.FeePayContract) (*types.FeePayContract, error) { - return value, nil - }, - func() *types.FeePayContract { - return &types.FeePayContract{} - }, - ) - - if err != nil { - return nil, err - } - - // Dereference pointer array of contracts - var contracts []types.FeePayContract - for _, contract := range results { - contracts = append(contracts, *contract) - } - - return &types.QueryFeePayContractsResponse{ - Contracts: contracts, - Pagination: pageRes, - }, nil -} - -// Register the contract in the module store -func (k Keeper) RegisterContract(ctx sdk.Context, rfp *types.MsgRegisterFeePayContract) error { - - // Return false because the contract was already registered - if k.IsRegisteredContract(ctx, rfp.Contract.ContractAddress) { - return types.ErrContractAlreadyRegistered - } - - // Check if sender is the owner of the cw contract - contractAddr, err := sdk.AccAddressFromBech32(rfp.Contract.ContractAddress) - if err != nil { - return err - } - - // Get the contract owner - contractInfo := k.wasmKeeper.GetContractInfo(ctx, contractAddr) - - // Check if the sender is first the admin & then the creator (if no admin exists) - adminExists := len(contractInfo.Admin) > 0 - if adminExists && contractInfo.Admin != rfp.SenderAddress { - return types.ErrContractNotAdmin - } else if !adminExists && contractInfo.Creator != rfp.SenderAddress { - return types.ErrContractNotCreator - } - - // Register the new fee pay contract in the KV store - store := prefix.NewStore(ctx.KVStore(k.storeKey), []byte(StoreKeyContracts)) - key := []byte(rfp.Contract.ContractAddress) - bz := k.cdc.MustMarshal(rfp.Contract) - - store.Set(key, bz) - return nil -} - -// Unregister contract (loop through usage store & remove all usage entries for contract) -func (k Keeper) UnregisterContract(ctx sdk.Context, rfp *types.MsgUnregisterFeePayContract) error { - - // Return false because the contract was already registered - if !k.IsRegisteredContract(ctx, rfp.ContractAddress) { - return types.ErrContractNotRegistered - } - - // Get fee pay contract - contract, err := k.GetContract(ctx, rfp.ContractAddress) - if err != nil { - return err - } - - // Get contract address - contractAddr, err := sdk.AccAddressFromBech32(rfp.ContractAddress) - if err != nil { - return err - } - - // Get the contract info - contractInfo := k.wasmKeeper.GetContractInfo(ctx, contractAddr) - - // Check if sender is the contract owner - if contractInfo.Creator != rfp.SenderAddress { - return types.ErrContractNotCreator - } - - // Remove contract from KV store - store := prefix.NewStore(ctx.KVStore(k.storeKey), []byte(StoreKeyContracts)) - store.Delete([]byte(rfp.ContractAddress)) - - // Remove all usage entries for contract - store = prefix.NewStore(ctx.KVStore(k.storeKey), []byte(StoreKeyContractUses)) - iterator := sdk.KVStorePrefixIterator(store, []byte(rfp.ContractAddress)) - - for ; iterator.Valid(); iterator.Next() { - store.Delete(iterator.Key()) - } - - // Transfer funds back to contract owner - coins := sdk.NewCoins(sdk.NewCoin(k.bondDenom, math.NewIntFromUint64(contract.Balance))) - - // Find admin or creator - var refundAddr string - if contractInfo.Admin != "" { - refundAddr = contractInfo.Admin - } else { - refundAddr = contractInfo.Creator - } - - // Send coins from the FeePay module to the refund address - if err := k.bankKeeper.SendCoinsFromModuleToAccount(ctx, types.ModuleName, sdk.MustAccAddressFromBech32(refundAddr), coins); err != nil { - return err - } - - return nil -} - -// Update the contract balance in the KV store -func (k Keeper) UpdateContractBalance(ctx sdk.Context, contractAddress string, newBalance uint64) error { - - // Skip if the contract is not registered - if !k.IsRegisteredContract(ctx, contractAddress) { - return types.ErrContractNotRegistered - } - - // Get the existing contract in KV store - store := prefix.NewStore(ctx.KVStore(k.storeKey), []byte(StoreKeyContracts)) - - key := []byte(contractAddress) - bz := store.Get(key) - - var fpc types.FeePayContract - if err := k.cdc.Unmarshal(bz, &fpc); err != nil { - return err - } - - // Set new balance and save to KV store - fpc.Balance = newBalance - - store.Set(key, k.cdc.MustMarshal(&fpc)) - return nil -} - -// Fund an existing fee pay contract -func (k Keeper) FundContract(ctx sdk.Context, mfc *types.MsgFundFeePayContract) error { - // Check if the contract is registered - if !k.IsRegisteredContract(ctx, mfc.ContractAddress) { - return types.ErrContractNotRegistered - } - - // Only transfer the bond denom - var transferCoin sdk.Coin - for _, c := range mfc.Amount { - if c.Denom == k.bondDenom { - transferCoin = c - } - } - - // Confirm the sender has enough funds to fund the contract - addr, err := sdk.AccAddressFromBech32(mfc.SenderAddress) - if err != nil { - return err - } - - if err := k.bankKeeper.SendCoinsFromAccountToModule(ctx, addr, types.ModuleName, sdk.NewCoins(transferCoin)); err != nil { - return err - } - - // Get existing fee pay contract from store - fpc, err := k.GetContract(ctx, mfc.ContractAddress) - if err != nil { - return err - } - - // Increment the fpc balance - fpc.Balance += transferCoin.Amount.Uint64() - k.UpdateContractBalance(ctx, mfc.ContractAddress, fpc.Balance) - return nil -} - -// Get the funds associated with a contract -func (k Keeper) GetContractFunds(ctx sdk.Context, contractAddress string) (uint64, error) { - contract, err := k.GetContract(ctx, contractAddress) - - if err != nil { - return 0, err - } - - return contract.Balance, nil -} - -// Check if a contract can cover the fees of a transaction -func (k Keeper) CanContractCoverFee(ctx sdk.Context, contractAddress string, fee uint64) bool { - - funds, err := k.GetContractFunds(ctx, contractAddress) - - // Check if contract exists in KV store - if err != nil { - return false - } - - // Check for enough funds - if funds < fee { - return false - } - - return true -} - -// Get the number of times a wallet has interacted with a fee pay contract (err only if contract not registered) -func (k Keeper) GetContractUses(ctx sdk.Context, contractAddress string, walletAddress string) (uint64, error) { - - // Check if wallet & contract address are valid - if _, err := sdk.AccAddressFromBech32(contractAddress); err != nil { - return 0, types.ErrInvalidAddress.GRPCStatus().Err() - } - - if _, err := sdk.AccAddressFromBech32(walletAddress); err != nil { - return 0, types.ErrInvalidAddress - } - - if !k.IsRegisteredContract(ctx, contractAddress) { - return 0, types.ErrContractNotRegistered - } - - // Get usage from store - store := prefix.NewStore(ctx.KVStore(k.storeKey), []byte(StoreKeyContractUses)) - key := []byte(contractAddress + "-" + walletAddress) - bz := store.Get(key) - - var walletUsage types.FeePayWalletUsage - if err := k.cdc.Unmarshal(bz, &walletUsage); err != nil { - return 0, err - } - - return walletUsage.Uses, nil -} - -// Set the number of times a wallet has interacted with a fee pay contract -func (k Keeper) SetContractUses(ctx sdk.Context, contractAddress string, walletAddress string, uses uint64) error { - - if !k.IsRegisteredContract(ctx, contractAddress) { - return types.ErrContractNotRegistered - } - - // Get store for updating usage - store := prefix.NewStore(ctx.KVStore(k.storeKey), []byte(StoreKeyContractUses)) - key := []byte(contractAddress + "-" + walletAddress) - bz, err := k.cdc.Marshal(&types.FeePayWalletUsage{ - ContractAddress: contractAddress, - WalletAddress: walletAddress, - Uses: uses, - }) - - if err != nil { - return err - } - - store.Set(key, bz) - return nil -} - -// Check if a wallet exceeded usage limit (defaults to true if contract not registered) -func (k Keeper) HasWalletExceededUsageLimit(ctx sdk.Context, contractAddress string, walletAddress string) bool { - - contract, err := k.GetContract(ctx, contractAddress) - - // Check if contract exists in KV store - if err != nil { - return true - } - - // Get account uses - uses, err := k.GetContractUses(ctx, contractAddress, walletAddress) - - if err != nil { - return true - } - - // Return if the wallet has used the contract too many times - return uses >= contract.WalletLimit -} - -// Check if a wallet is eligible to interact with a contract -func (k Keeper) IsWalletEligible(ctx sdk.Context, contractAddress string, walletAddress string) (bool, string) { - - // Check if wallet & contract address are valid - if _, err := sdk.AccAddressFromBech32(contractAddress); err != nil { - return false, types.ErrInvalidAddress.Error() - } - - if _, err := sdk.AccAddressFromBech32(walletAddress); err != nil { - return false, types.ErrInvalidAddress.Error() - } - - // Check if contract is registered - if !k.IsRegisteredContract(ctx, contractAddress) { - return false, types.ErrContractNotRegistered.Error() - } - - // Check if wallet has exceeded usage limit - if k.HasWalletExceededUsageLimit(ctx, contractAddress, walletAddress) { - return false, types.ErrWalletExceededUsageLimit.Error() - } - - // Check if contract has enough funds - funds, err := k.GetContractFunds(ctx, contractAddress) - - if err != nil || funds <= 0 { - return false, types.ErrContractNotEnoughFunds.Error() - } - - return true, "" + return ctx.Logger().With("module", fmt.Sprintf("x/%s", feepaytypes.ModuleName)) } diff --git a/x/feepay/keeper/msg_server.go b/x/feepay/keeper/msg_server.go index ab2c130b5..ed5955a85 100644 --- a/x/feepay/keeper/msg_server.go +++ b/x/feepay/keeper/msg_server.go @@ -27,7 +27,17 @@ func (k Keeper) UnregisterFeePayContract(goCtx context.Context, msg *types.MsgUn // FundFeePayContract funds a contract with the given amount of tokens. func (k Keeper) FundFeePayContract(goCtx context.Context, msg *types.MsgFundFeePayContract) (*types.MsgFundFeePayContractResponse, error) { ctx := sdk.UnwrapSDKContext(goCtx) - return &types.MsgFundFeePayContractResponse{}, k.FundContract(ctx, msg) + + // Get the contract + contract, err := k.GetContract(ctx, msg.ContractAddress) + if err != nil { + return nil, err + } + + // Sender address (already validated in msg.go) + senderAddr := sdk.MustAccAddressFromBech32(msg.SenderAddress) + + return &types.MsgFundFeePayContractResponse{}, k.FundContract(ctx, contract, senderAddr, msg.Amount) } func (k Keeper) UpdateParams(goCtx context.Context, req *types.MsgUpdateParams) (*types.MsgUpdateParamsResponse, error) { diff --git a/x/feepay/keeper/params.go b/x/feepay/keeper/params.go index d0cce8e4e..91fe928d4 100644 --- a/x/feepay/keeper/params.go +++ b/x/feepay/keeper/params.go @@ -8,6 +8,7 @@ import ( // GetParams returns the total set of fees parameters. func (k Keeper) GetParams(ctx sdk.Context) (p types.Params) { + // set to nil? add a ParamsKey which is a 0x00 value. Maybe a bool for enable and disable (set in .proto file genesis.proto (kill switch)) // store := ctx.KVStore(k.storeKey) // bz := store.Get(types.ParamsKey) // if bz == nil { @@ -27,6 +28,5 @@ func (k Keeper) SetParams(ctx sdk.Context, p types.Params) error { // store := ctx.KVStore(k.storeKey) // bz := k.cdc.MustMarshal(&p) // store.Set(types.ParamsKey, bz) - return nil } diff --git a/x/feepay/module.go b/x/feepay/module.go index e262188c1..2e80f8630 100644 --- a/x/feepay/module.go +++ b/x/feepay/module.go @@ -1,6 +1,7 @@ package feepay import ( + "context" "encoding/json" "fmt" @@ -21,7 +22,6 @@ import ( "github.com/CosmosContracts/juno/v17/x/feepay/client/cli" "github.com/CosmosContracts/juno/v17/x/feepay/keeper" "github.com/CosmosContracts/juno/v17/x/feepay/types" - "github.com/CosmosContracts/juno/v17/x/mint/exported" ) // type check to ensure the interface is properly implemented @@ -32,7 +32,7 @@ var ( ) // ConsensusVersion defines the current x/feepay module consensus version. -const ConsensusVersion = 2 +const ConsensusVersion = 1 // AppModuleBasic type for the fees module type AppModuleBasic struct{} @@ -82,11 +82,9 @@ func (AppModuleBasic) RegisterRESTRoutes(_ client.Context, _ *mux.Router) {} // RegisterGRPCGatewayRoutes registers the gRPC Gateway routes for the fees // module. func (b AppModuleBasic) RegisterGRPCGatewayRoutes(c client.Context, serveMux *runtime.ServeMux) { - - // TODO: UNCOMMENT FOR QUERIES - // if err := types.RegisterQueryHandlerClient(context.Background(), serveMux, types.NewQueryClient(c)); err != nil { - // panic(err) - // } + if err := types.RegisterQueryHandlerClient(context.Background(), serveMux, types.NewQueryClient(c)); err != nil { + panic(err) + } } // GetTxCmd returns the root tx command for the fees module. @@ -106,22 +104,17 @@ type AppModule struct { AppModuleBasic keeper keeper.Keeper ak authkeeper.AccountKeeper - - // legacySubspace is used solely for migration of x/params managed parameters - legacySubspace exported.Subspace } // NewAppModule creates a new AppModule Object func NewAppModule( k keeper.Keeper, ak authkeeper.AccountKeeper, - ss exported.Subspace, ) AppModule { return AppModule{ AppModuleBasic: AppModuleBasic{}, keeper: k, ak: ak, - legacySubspace: ss, } } diff --git a/x/feepay/types/errors.go b/x/feepay/types/errors.go index 8f52e058f..f29218251 100644 --- a/x/feepay/types/errors.go +++ b/x/feepay/types/errors.go @@ -15,4 +15,5 @@ var ( ErrInvalidWalletLimit = errorsmod.Register(ModuleName, 8, "invalid wallet limit; must be between 0 and 1,000,000") ErrInvalidJunoFundAmount = errorsmod.Register(ModuleName, 9, "fee pay contracts only accept juno funds") ErrInvalidAddress = errorsmod.Register(ModuleName, 10, "invalid bech32 address") + ErrInvalidCWContract = errorsmod.Register(ModuleName, 11, "invalid CosmWasm contract") ) diff --git a/x/feepay/types/msg.go b/x/feepay/types/msg.go index 666226284..12e445196 100644 --- a/x/feepay/types/msg.go +++ b/x/feepay/types/msg.go @@ -30,11 +30,11 @@ func (msg MsgRegisterFeePayContract) ValidateBasic() error { return err } - if _, err := sdk.AccAddressFromBech32(msg.Contract.ContractAddress); err != nil { + if _, err := sdk.AccAddressFromBech32(msg.FeePayContract.ContractAddress); err != nil { return err } - if msg.Contract.WalletLimit < 1 || msg.Contract.WalletLimit > 1_000_000 { + if msg.FeePayContract.WalletLimit > 1_000_000 { return ErrInvalidWalletLimit } diff --git a/x/feepay/types/query.pb.go b/x/feepay/types/query.pb.go index 60b79e515..0c1e049e5 100644 --- a/x/feepay/types/query.pb.go +++ b/x/feepay/types/query.pb.go @@ -79,7 +79,7 @@ func (m *QueryFeePayContract) GetContractAddress() string { // QueryFeePayContractResponse defines the response for retrieving a single fee pay contract type QueryFeePayContractResponse struct { // contract defines the fee pay contract - Contract *FeePayContract `protobuf:"bytes,1,opt,name=contract,proto3" json:"contract,omitempty"` + FeePayContract *FeePayContract `protobuf:"bytes,1,opt,name=fee_pay_contract,json=feePayContract,proto3" json:"fee_pay_contract,omitempty"` } func (m *QueryFeePayContractResponse) Reset() { *m = QueryFeePayContractResponse{} } @@ -115,9 +115,9 @@ func (m *QueryFeePayContractResponse) XXX_DiscardUnknown() { var xxx_messageInfo_QueryFeePayContractResponse proto.InternalMessageInfo -func (m *QueryFeePayContractResponse) GetContract() *FeePayContract { +func (m *QueryFeePayContractResponse) GetFeePayContract() *FeePayContract { if m != nil { - return m.Contract + return m.FeePayContract } return nil } @@ -171,7 +171,7 @@ func (m *QueryFeePayContracts) GetPagination() *query.PageRequest { // The response for querying all fee pay contracts type QueryFeePayContractsResponse struct { // A slice of all the stored fee pay contracts - Contracts []FeePayContract `protobuf:"bytes,1,rep,name=contracts,proto3" json:"contracts"` + FeePayContracts []FeePayContract `protobuf:"bytes,1,rep,name=fee_pay_contracts,json=feePayContracts,proto3" json:"fee_pay_contracts"` // pagination defines the pagination in the response. Pagination *query.PageResponse `protobuf:"bytes,2,opt,name=pagination,proto3" json:"pagination,omitempty"` } @@ -209,9 +209,9 @@ func (m *QueryFeePayContractsResponse) XXX_DiscardUnknown() { var xxx_messageInfo_QueryFeePayContractsResponse proto.InternalMessageInfo -func (m *QueryFeePayContractsResponse) GetContracts() []FeePayContract { +func (m *QueryFeePayContractsResponse) GetFeePayContracts() []FeePayContract { if m != nil { - return m.Contracts + return m.FeePayContracts } return nil } @@ -383,8 +383,6 @@ func (m *QueryFeePayWalletIsEligible) GetWalletAddress() string { type QueryFeePayWalletIsEligibleResponse struct { // The eligibility of the wallet for fee pay contract interactions Eligible bool `protobuf:"varint,1,opt,name=eligible,proto3" json:"eligible,omitempty"` - // The reason (if any) for the wallet being ineligible for fee pay contract interactions - Reason string `protobuf:"bytes,2,opt,name=reason,proto3" json:"reason,omitempty"` } func (m *QueryFeePayWalletIsEligibleResponse) Reset() { *m = QueryFeePayWalletIsEligibleResponse{} } @@ -427,13 +425,6 @@ func (m *QueryFeePayWalletIsEligibleResponse) GetEligible() bool { return false } -func (m *QueryFeePayWalletIsEligibleResponse) GetReason() string { - if m != nil { - return m.Reason - } - return "" -} - func init() { proto.RegisterType((*QueryFeePayContract)(nil), "juno.feepay.v1.QueryFeePayContract") proto.RegisterType((*QueryFeePayContractResponse)(nil), "juno.feepay.v1.QueryFeePayContractResponse") @@ -448,46 +439,46 @@ func init() { func init() { proto.RegisterFile("juno/feepay/v1/query.proto", fileDescriptor_d6539df905bf35ca) } var fileDescriptor_d6539df905bf35ca = []byte{ - // 615 bytes of a gzipped FileDescriptorProto - 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xb4, 0x55, 0xc1, 0x6e, 0xd3, 0x40, - 0x10, 0x8d, 0x4b, 0x5b, 0x25, 0x83, 0x48, 0xd1, 0x52, 0x85, 0xca, 0xad, 0x5c, 0xe4, 0x02, 0xa5, - 0x14, 0x79, 0x95, 0x56, 0x5c, 0xb8, 0x40, 0x13, 0xb5, 0x05, 0x71, 0x29, 0x96, 0x10, 0x2a, 0x07, - 0xd0, 0x26, 0x1d, 0x8c, 0x21, 0xf5, 0xba, 0x59, 0x27, 0x10, 0x55, 0xbd, 0x20, 0x71, 0x47, 0x42, - 0x7c, 0x45, 0x3f, 0x80, 0x4f, 0xa0, 0xc7, 0x4a, 0x5c, 0x38, 0x21, 0x94, 0xf0, 0x21, 0xc8, 0xbb, - 0xb6, 0x43, 0x8c, 0xdb, 0xba, 0x07, 0x6e, 0xeb, 0x9d, 0x37, 0xf3, 0xde, 0xbc, 0x99, 0x4d, 0x40, - 0x7f, 0xd3, 0xf1, 0x38, 0x7d, 0x85, 0xe8, 0xb3, 0x1e, 0xed, 0x56, 0xe9, 0x5e, 0x07, 0xdb, 0x3d, - 0xcb, 0x6f, 0xf3, 0x80, 0x93, 0x72, 0x18, 0xb3, 0x54, 0xcc, 0xea, 0x56, 0xf5, 0xdb, 0x4d, 0x2e, - 0x76, 0xb9, 0xa0, 0x0d, 0x26, 0x50, 0x01, 0x69, 0xb7, 0xda, 0xc0, 0x80, 0x55, 0xa9, 0xcf, 0x1c, - 0xd7, 0x63, 0x81, 0xcb, 0x3d, 0x95, 0xab, 0xcf, 0xa5, 0xea, 0x3a, 0xe8, 0xa1, 0x70, 0x45, 0x14, - 0x9d, 0x4d, 0x45, 0x23, 0x0e, 0x15, 0x9c, 0x76, 0xb8, 0xc3, 0xe5, 0x91, 0x86, 0xa7, 0xb8, 0xa0, - 0xc3, 0xb9, 0xd3, 0x42, 0xca, 0x7c, 0x97, 0x32, 0xcf, 0xe3, 0x81, 0x64, 0x8b, 0x0a, 0x9a, 0x0f, - 0xe0, 0xca, 0x93, 0x50, 0xd0, 0x06, 0xe2, 0x16, 0xeb, 0xd5, 0xb9, 0x17, 0xb4, 0x59, 0x33, 0x20, - 0x4b, 0x70, 0xb9, 0x19, 0x9d, 0x5f, 0xb2, 0x9d, 0x9d, 0x36, 0x0a, 0x31, 0xa3, 0x5d, 0xd3, 0x6e, - 0x95, 0xec, 0xa9, 0xf8, 0x7e, 0x4d, 0x5d, 0x9b, 0xdb, 0x30, 0x9b, 0x51, 0xc1, 0x46, 0xe1, 0x73, - 0x4f, 0x20, 0xb9, 0x07, 0xc5, 0x38, 0x43, 0x56, 0xb8, 0xb8, 0x62, 0x58, 0xa3, 0xf6, 0x58, 0xa9, - 0xcc, 0x04, 0x6f, 0xbe, 0x80, 0xe9, 0x8c, 0xd2, 0x82, 0x6c, 0x00, 0x0c, 0x7d, 0x8b, 0xaa, 0xde, - 0xb4, 0x94, 0xc9, 0x56, 0x68, 0xb2, 0xa5, 0xa6, 0x11, 0x99, 0x6c, 0x6d, 0x31, 0x07, 0x6d, 0xdc, - 0xeb, 0xa0, 0x08, 0xec, 0xbf, 0x32, 0xcd, 0x43, 0x0d, 0xe6, 0xb2, 0x08, 0x12, 0xf1, 0x35, 0x28, - 0xc5, 0x62, 0xc2, 0xfe, 0x2f, 0x9c, 0xad, 0xbe, 0x36, 0x7e, 0xf4, 0x73, 0xbe, 0x60, 0x0f, 0xd3, - 0xc8, 0xe6, 0x88, 0xd8, 0x31, 0x29, 0x76, 0xf1, 0x4c, 0xb1, 0x4a, 0xc0, 0x88, 0xda, 0xb7, 0x70, - 0x35, 0x43, 0xec, 0x53, 0x81, 0xe2, 0x1c, 0xe3, 0x22, 0x37, 0xa0, 0xfc, 0x8e, 0xb5, 0x5a, 0x38, - 0x04, 0x8e, 0x49, 0xe0, 0x25, 0x75, 0x1b, 0x4f, 0xf5, 0x2e, 0xcc, 0x9f, 0x40, 0x96, 0x98, 0x43, - 0x60, 0xbc, 0x23, 0x50, 0x11, 0x8d, 0xdb, 0xf2, 0x6c, 0xf2, 0x91, 0x65, 0x78, 0x26, 0x4b, 0x3e, - 0x12, 0xeb, 0x2d, 0xd7, 0x71, 0x1b, 0x2d, 0xfc, 0x0f, 0x3a, 0xb7, 0x61, 0xe1, 0x14, 0xc2, 0x44, - 0xab, 0x0e, 0x45, 0x8c, 0xee, 0x24, 0x61, 0xd1, 0x4e, 0xbe, 0x49, 0x05, 0x26, 0xdb, 0xc8, 0x44, - 0x34, 0x9c, 0x92, 0x1d, 0x7d, 0xad, 0x1c, 0x4e, 0xc0, 0x84, 0xac, 0x4d, 0xbe, 0x68, 0x50, 0x4e, - 0x3d, 0x90, 0x85, 0xf4, 0x1a, 0x64, 0xb8, 0xa5, 0x2f, 0xe7, 0x00, 0xc5, 0x12, 0xcd, 0xea, 0x87, - 0xef, 0xbf, 0x3f, 0x8f, 0x2d, 0x93, 0x25, 0x9a, 0xf9, 0xc6, 0xe9, 0x7e, 0xda, 0xb9, 0x03, 0xf2, - 0x51, 0x83, 0xa9, 0xf4, 0xdb, 0xb8, 0x9e, 0x83, 0x53, 0xe8, 0x77, 0xf2, 0xa0, 0x12, 0x69, 0x86, - 0x94, 0x36, 0x43, 0x2a, 0xd9, 0xd2, 0xc8, 0x57, 0x0d, 0x48, 0xc6, 0x56, 0x2e, 0xe6, 0x20, 0x09, - 0x81, 0x3a, 0xcd, 0x09, 0x4c, 0x04, 0x6d, 0x4a, 0x41, 0x6b, 0xe4, 0x7e, 0x6e, 0xaf, 0x68, 0xb8, - 0x9e, 0x74, 0x7f, 0x74, 0xa5, 0x0e, 0xc8, 0x37, 0x0d, 0x2a, 0x27, 0xec, 0xea, 0x69, 0xc3, 0x4b, - 0x83, 0xf5, 0xd5, 0x73, 0x80, 0x93, 0x2e, 0x1e, 0xcb, 0x2e, 0xd6, 0x49, 0x3d, 0x7f, 0x17, 0xf1, - 0xd2, 0xfe, 0xd3, 0x49, 0xed, 0xe1, 0x51, 0xdf, 0xd0, 0x8e, 0xfb, 0x86, 0xf6, 0xab, 0x6f, 0x68, - 0x9f, 0x06, 0x46, 0xe1, 0x78, 0x60, 0x14, 0x7e, 0x0c, 0x8c, 0xc2, 0x73, 0xcb, 0x71, 0x83, 0xd7, - 0x9d, 0x86, 0xd5, 0xe4, 0xbb, 0xb4, 0x2e, 0x7f, 0x76, 0x92, 0x09, 0x2b, 0xe2, 0xf7, 0x31, 0x61, - 0xd0, 0xf3, 0x51, 0x34, 0x26, 0xe5, 0x3f, 0xc3, 0xea, 0x9f, 0x00, 0x00, 0x00, 0xff, 0xff, 0x7c, - 0x30, 0x61, 0xab, 0xe2, 0x06, 0x00, 0x00, + // 613 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xb4, 0x55, 0x4f, 0x6f, 0xd3, 0x30, + 0x1c, 0x6d, 0x4a, 0x87, 0x86, 0x11, 0xed, 0x30, 0xd3, 0x98, 0xb2, 0x29, 0x43, 0x19, 0x30, 0xc6, + 0x90, 0xad, 0x6e, 0xe2, 0x0c, 0x5d, 0xb5, 0x3f, 0x88, 0x4b, 0x89, 0x84, 0x90, 0x38, 0x50, 0xb9, + 0xdd, 0xaf, 0x21, 0xd0, 0xc5, 0x59, 0x9d, 0x16, 0xaa, 0x69, 0x17, 0x24, 0xee, 0x48, 0x88, 0x4f, + 0xc1, 0x07, 0x40, 0x7c, 0x02, 0x76, 0x9c, 0xc4, 0x85, 0x13, 0x42, 0x2d, 0x1f, 0x04, 0xc5, 0x4e, + 0x32, 0x12, 0xb2, 0x2d, 0x3b, 0x70, 0x73, 0xec, 0xe7, 0xf7, 0xde, 0xef, 0xfd, 0x7e, 0x6e, 0x91, + 0xfe, 0xaa, 0xef, 0x72, 0xda, 0x01, 0xf0, 0xd8, 0x90, 0x0e, 0xaa, 0x74, 0xaf, 0x0f, 0xbd, 0x21, + 0xf1, 0x7a, 0xdc, 0xe7, 0xb8, 0x1c, 0x9c, 0x11, 0x75, 0x46, 0x06, 0x55, 0xfd, 0x6e, 0x9b, 0x8b, + 0x5d, 0x2e, 0x68, 0x8b, 0x09, 0x50, 0x40, 0x3a, 0xa8, 0xb6, 0xc0, 0x67, 0x55, 0xea, 0x31, 0xdb, + 0x71, 0x99, 0xef, 0x70, 0x57, 0xdd, 0xd5, 0xe7, 0x53, 0xbc, 0x36, 0xb8, 0x20, 0x1c, 0x11, 0x9e, + 0xce, 0xa5, 0x4e, 0x43, 0x0d, 0x75, 0x38, 0x6d, 0x73, 0x9b, 0xcb, 0x25, 0x0d, 0x56, 0x11, 0xa1, + 0xcd, 0xb9, 0xdd, 0x05, 0xca, 0x3c, 0x87, 0x32, 0xd7, 0xe5, 0xbe, 0x54, 0x0b, 0x09, 0xcd, 0x87, + 0xe8, 0xda, 0x93, 0xc0, 0xd0, 0x26, 0x40, 0x83, 0x0d, 0xeb, 0xdc, 0xf5, 0x7b, 0xac, 0xed, 0xe3, + 0x65, 0x34, 0xd5, 0x0e, 0xd7, 0x4d, 0xb6, 0xb3, 0xd3, 0x03, 0x21, 0x66, 0xb5, 0x1b, 0xda, 0x9d, + 0x4b, 0x56, 0x25, 0xda, 0xaf, 0xa9, 0x6d, 0xd3, 0x46, 0x73, 0x19, 0x0c, 0x16, 0x08, 0x8f, 0xbb, + 0x02, 0xf0, 0x36, 0x9a, 0xea, 0x00, 0x34, 0x3d, 0x36, 0x6c, 0x46, 0x37, 0x25, 0xd3, 0xe5, 0x55, + 0x83, 0x24, 0x63, 0x22, 0x29, 0x86, 0x72, 0x27, 0xf1, 0x6d, 0xbe, 0x40, 0xd3, 0x19, 0x42, 0x02, + 0x6f, 0x22, 0x74, 0x9c, 0x62, 0xc8, 0x7d, 0x9b, 0xa8, 0xc8, 0x49, 0x10, 0x39, 0x51, 0xbd, 0x09, + 0x23, 0x27, 0x0d, 0x66, 0x83, 0x05, 0x7b, 0x7d, 0x10, 0xbe, 0xf5, 0xd7, 0x4d, 0xf3, 0xab, 0x86, + 0xe6, 0xb3, 0x04, 0xe2, 0x52, 0x1a, 0xe8, 0x6a, 0xba, 0x94, 0x20, 0x95, 0x0b, 0x67, 0xd7, 0xb2, + 0x5e, 0x3a, 0xfc, 0xb9, 0x50, 0xb0, 0x2a, 0x9d, 0x94, 0xf5, 0xad, 0x84, 0xf5, 0xa2, 0xb4, 0xbe, + 0x74, 0xa6, 0x75, 0x65, 0x27, 0xe1, 0xfd, 0x35, 0xba, 0x9e, 0x61, 0xfd, 0xa9, 0x00, 0x71, 0x8e, + 0x56, 0xe2, 0x5b, 0xa8, 0xfc, 0x86, 0x75, 0xbb, 0x70, 0x0c, 0x2c, 0x4a, 0xe0, 0x15, 0xb5, 0x1b, + 0x75, 0xfc, 0x3e, 0x5a, 0x38, 0x41, 0x2c, 0x8e, 0x0a, 0xa3, 0x52, 0x5f, 0x80, 0x12, 0x2a, 0x59, + 0x72, 0x6d, 0xf2, 0xc4, 0xa0, 0x3c, 0x93, 0x94, 0x8f, 0xc4, 0x46, 0xd7, 0xb1, 0x9d, 0x56, 0x17, + 0xfe, 0x83, 0xcf, 0x1a, 0x5a, 0x3c, 0x45, 0x30, 0xf6, 0xaa, 0xa3, 0x49, 0x08, 0xf7, 0xa4, 0xe0, + 0xa4, 0x15, 0x7f, 0xaf, 0x7e, 0x9e, 0x40, 0x13, 0x92, 0x03, 0x7f, 0xd2, 0x50, 0x39, 0xf5, 0x48, + 0x16, 0xd3, 0x4d, 0xcf, 0x48, 0x45, 0x5f, 0xc9, 0x01, 0x8a, 0xac, 0x98, 0xd5, 0x77, 0xdf, 0x7f, + 0x7f, 0x2c, 0xae, 0xe0, 0x65, 0x9a, 0xf9, 0xce, 0xe9, 0x7e, 0x3a, 0xa1, 0x03, 0xfc, 0x5e, 0x43, + 0x95, 0xf4, 0x8b, 0xb8, 0x99, 0x43, 0x53, 0xe8, 0xf7, 0xf2, 0xa0, 0x62, 0x6b, 0x86, 0xb4, 0x36, + 0x8b, 0x67, 0xb2, 0xad, 0xe1, 0x2f, 0x1a, 0xc2, 0x19, 0xd3, 0xb7, 0x94, 0x43, 0x24, 0x00, 0xea, + 0x34, 0x27, 0x30, 0x36, 0xb4, 0x25, 0x0d, 0xd5, 0xf0, 0x83, 0xdc, 0x59, 0xd1, 0x60, 0x0c, 0xe9, + 0x7e, 0x72, 0x74, 0x0e, 0xf0, 0x37, 0x0d, 0xcd, 0x9c, 0x30, 0x93, 0xa7, 0x35, 0x2f, 0x0d, 0xd6, + 0xd7, 0xce, 0x01, 0x8e, 0xab, 0x78, 0x2c, 0xab, 0xd8, 0xc0, 0xf5, 0xfc, 0x55, 0x44, 0xc3, 0xf9, + 0x4f, 0x25, 0xeb, 0xdb, 0x87, 0x23, 0x43, 0x3b, 0x1a, 0x19, 0xda, 0xaf, 0x91, 0xa1, 0x7d, 0x18, + 0x1b, 0x85, 0xa3, 0xb1, 0x51, 0xf8, 0x31, 0x36, 0x0a, 0xcf, 0x89, 0xed, 0xf8, 0x2f, 0xfb, 0x2d, + 0xd2, 0xe6, 0xbb, 0xb4, 0x2e, 0x7f, 0x5e, 0xe2, 0x0e, 0x2b, 0xe1, 0xb7, 0x91, 0xa0, 0x3f, 0xf4, + 0x40, 0xb4, 0x2e, 0xca, 0x7f, 0x87, 0xb5, 0x3f, 0x01, 0x00, 0x00, 0xff, 0xff, 0xc4, 0xa3, 0x66, + 0xda, 0xe6, 0x06, 0x00, 0x00, } // Reference imports to suppress errors if they are not otherwise used. @@ -736,9 +727,9 @@ func (m *QueryFeePayContractResponse) MarshalToSizedBuffer(dAtA []byte) (int, er _ = i var l int _ = l - if m.Contract != nil { + if m.FeePayContract != nil { { - size, err := m.Contract.MarshalToSizedBuffer(dAtA[:i]) + size, err := m.FeePayContract.MarshalToSizedBuffer(dAtA[:i]) if err != nil { return 0, err } @@ -818,10 +809,10 @@ func (m *QueryFeePayContractsResponse) MarshalToSizedBuffer(dAtA []byte) (int, e i-- dAtA[i] = 0x12 } - if len(m.Contracts) > 0 { - for iNdEx := len(m.Contracts) - 1; iNdEx >= 0; iNdEx-- { + if len(m.FeePayContracts) > 0 { + for iNdEx := len(m.FeePayContracts) - 1; iNdEx >= 0; iNdEx-- { { - size, err := m.Contracts[iNdEx].MarshalToSizedBuffer(dAtA[:i]) + size, err := m.FeePayContracts[iNdEx].MarshalToSizedBuffer(dAtA[:i]) if err != nil { return 0, err } @@ -957,13 +948,6 @@ func (m *QueryFeePayWalletIsEligibleResponse) MarshalToSizedBuffer(dAtA []byte) _ = i var l int _ = l - if len(m.Reason) > 0 { - i -= len(m.Reason) - copy(dAtA[i:], m.Reason) - i = encodeVarintQuery(dAtA, i, uint64(len(m.Reason))) - i-- - dAtA[i] = 0x12 - } if m.Eligible { i-- if m.Eligible { @@ -1007,8 +991,8 @@ func (m *QueryFeePayContractResponse) Size() (n int) { } var l int _ = l - if m.Contract != nil { - l = m.Contract.Size() + if m.FeePayContract != nil { + l = m.FeePayContract.Size() n += 1 + l + sovQuery(uint64(l)) } return n @@ -1033,8 +1017,8 @@ func (m *QueryFeePayContractsResponse) Size() (n int) { } var l int _ = l - if len(m.Contracts) > 0 { - for _, e := range m.Contracts { + if len(m.FeePayContracts) > 0 { + for _, e := range m.FeePayContracts { l = e.Size() n += 1 + l + sovQuery(uint64(l)) } @@ -1101,10 +1085,6 @@ func (m *QueryFeePayWalletIsEligibleResponse) Size() (n int) { if m.Eligible { n += 2 } - l = len(m.Reason) - if l > 0 { - n += 1 + l + sovQuery(uint64(l)) - } return n } @@ -1227,7 +1207,7 @@ func (m *QueryFeePayContractResponse) Unmarshal(dAtA []byte) error { switch fieldNum { case 1: if wireType != 2 { - return fmt.Errorf("proto: wrong wireType = %d for field Contract", wireType) + return fmt.Errorf("proto: wrong wireType = %d for field FeePayContract", wireType) } var msglen int for shift := uint(0); ; shift += 7 { @@ -1254,10 +1234,10 @@ func (m *QueryFeePayContractResponse) Unmarshal(dAtA []byte) error { if postIndex > l { return io.ErrUnexpectedEOF } - if m.Contract == nil { - m.Contract = &FeePayContract{} + if m.FeePayContract == nil { + m.FeePayContract = &FeePayContract{} } - if err := m.Contract.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + if err := m.FeePayContract.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { return err } iNdEx = postIndex @@ -1399,7 +1379,7 @@ func (m *QueryFeePayContractsResponse) Unmarshal(dAtA []byte) error { switch fieldNum { case 1: if wireType != 2 { - return fmt.Errorf("proto: wrong wireType = %d for field Contracts", wireType) + return fmt.Errorf("proto: wrong wireType = %d for field FeePayContracts", wireType) } var msglen int for shift := uint(0); ; shift += 7 { @@ -1426,8 +1406,8 @@ func (m *QueryFeePayContractsResponse) Unmarshal(dAtA []byte) error { if postIndex > l { return io.ErrUnexpectedEOF } - m.Contracts = append(m.Contracts, FeePayContract{}) - if err := m.Contracts[len(m.Contracts)-1].Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + m.FeePayContracts = append(m.FeePayContracts, FeePayContract{}) + if err := m.FeePayContracts[len(m.FeePayContracts)-1].Unmarshal(dAtA[iNdEx:postIndex]); err != nil { return err } iNdEx = postIndex @@ -1834,38 +1814,6 @@ func (m *QueryFeePayWalletIsEligibleResponse) Unmarshal(dAtA []byte) error { } } m.Eligible = bool(v != 0) - case 2: - if wireType != 2 { - return fmt.Errorf("proto: wrong wireType = %d for field Reason", 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.Reason = string(dAtA[iNdEx:postIndex]) - iNdEx = postIndex default: iNdEx = preIndex skippy, err := skipQuery(dAtA[iNdEx:]) diff --git a/x/feepay/types/tx.pb.go b/x/feepay/types/tx.pb.go index 88a72b323..eea9eabf5 100644 --- a/x/feepay/types/tx.pb.go +++ b/x/feepay/types/tx.pb.go @@ -39,7 +39,7 @@ type MsgRegisterFeePayContract struct { // The wallet address of the sender. SenderAddress string `protobuf:"bytes,1,opt,name=sender_address,json=senderAddress,proto3" json:"sender_address,omitempty"` // The fee pay contract to register. - Contract *FeePayContract `protobuf:"bytes,2,opt,name=contract,proto3" json:"contract,omitempty"` + FeePayContract *FeePayContract `protobuf:"bytes,2,opt,name=fee_pay_contract,json=feePayContract,proto3" json:"fee_pay_contract,omitempty"` } func (m *MsgRegisterFeePayContract) Reset() { *m = MsgRegisterFeePayContract{} } @@ -82,9 +82,9 @@ func (m *MsgRegisterFeePayContract) GetSenderAddress() string { return "" } -func (m *MsgRegisterFeePayContract) GetContract() *FeePayContract { +func (m *MsgRegisterFeePayContract) GetFeePayContract() *FeePayContract { if m != nil { - return m.Contract + return m.FeePayContract } return nil } @@ -325,7 +325,7 @@ var xxx_messageInfo_MsgFundFeePayContractResponse proto.InternalMessageInfo type MsgUpdateParams struct { // authority is the address that controls the module (defaults to x/gov unless overwritten). Authority string `protobuf:"bytes,1,opt,name=authority,proto3" json:"authority,omitempty"` - // params defines the x/feeshare parameters to update. + // params defines the x/feepay parameters to update. // // NOTE: All parameters must be supplied. Params Params `protobuf:"bytes,2,opt,name=params,proto3" json:"params"` @@ -432,50 +432,50 @@ func init() { func init() { proto.RegisterFile("juno/feepay/v1/tx.proto", fileDescriptor_d739bd30c8846fd5) } var fileDescriptor_d739bd30c8846fd5 = []byte{ - // 675 bytes of a gzipped FileDescriptorProto - 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xb4, 0x94, 0x4f, 0x4f, 0xd4, 0x40, - 0x18, 0xc6, 0x77, 0x80, 0x10, 0x19, 0x10, 0xb4, 0x41, 0xd8, 0x5d, 0xb4, 0x8b, 0x25, 0x84, 0x05, - 0xb2, 0x9d, 0x2c, 0x18, 0x0f, 0xdc, 0x5c, 0x12, 0xe2, 0x65, 0x13, 0x52, 0x63, 0x62, 0xbc, 0x90, - 0xd9, 0xdd, 0x61, 0xa8, 0xd2, 0x99, 0xa6, 0x33, 0x25, 0xf4, 0x4a, 0xbc, 0x6b, 0xe2, 0x49, 0x4f, - 0x1e, 0xd5, 0x13, 0x26, 0x7e, 0x08, 0x8e, 0x44, 0x2f, 0x26, 0x26, 0x6a, 0xc0, 0x04, 0xe3, 0xa7, - 0x30, 0x6d, 0xa7, 0x05, 0x76, 0x5b, 0xc5, 0x18, 0x2f, 0xfb, 0x67, 0x9e, 0xa7, 0xf3, 0xfe, 0xde, - 0x37, 0xcf, 0x5b, 0x38, 0xf9, 0xc8, 0x67, 0x1c, 0x6d, 0x12, 0xe2, 0xe2, 0x00, 0xed, 0xd4, 0x91, - 0xdc, 0x35, 0x5d, 0x8f, 0x4b, 0xae, 0x8d, 0x86, 0x82, 0x19, 0x0b, 0xe6, 0x4e, 0xbd, 0x3c, 0x4e, - 0x39, 0xe5, 0x91, 0x84, 0xc2, 0x5f, 0xb1, 0xab, 0x7c, 0x9d, 0x72, 0x4e, 0xb7, 0x09, 0xc2, 0xae, - 0x8d, 0x30, 0x63, 0x5c, 0x62, 0x69, 0x73, 0x26, 0x94, 0x7a, 0x15, 0x3b, 0x36, 0xe3, 0x28, 0xfa, - 0x54, 0x47, 0x93, 0x6d, 0x2e, 0x1c, 0x2e, 0x90, 0x23, 0x68, 0x58, 0xce, 0x11, 0x54, 0x09, 0xba, - 0x12, 0x5a, 0x58, 0x10, 0xb4, 0x53, 0x6f, 0x11, 0x89, 0xeb, 0xa8, 0xcd, 0x6d, 0xa6, 0xf4, 0x52, - 0xac, 0x6f, 0xc4, 0x08, 0xf1, 0x9f, 0x04, 0xa2, 0xab, 0x07, 0x4a, 0x18, 0x11, 0x76, 0xa2, 0x4e, - 0x75, 0xa9, 0xaa, 0xa5, 0x48, 0x34, 0x9e, 0x00, 0x58, 0x6a, 0x0a, 0x6a, 0x11, 0x6a, 0x0b, 0x49, - 0xbc, 0x35, 0x42, 0xd6, 0x71, 0xb0, 0xca, 0x99, 0xf4, 0x70, 0x5b, 0x6a, 0xb3, 0x70, 0x54, 0x10, - 0xd6, 0x21, 0xde, 0x06, 0xee, 0x74, 0x3c, 0x22, 0x44, 0x11, 0x4c, 0x83, 0xea, 0x90, 0x75, 0x39, - 0x3e, 0xbd, 0x13, 0x1f, 0x6a, 0x2b, 0xf0, 0x52, 0x5b, 0x3d, 0x52, 0xec, 0x9b, 0x06, 0xd5, 0xe1, - 0x25, 0xdd, 0x3c, 0x3f, 0x3d, 0xf3, 0xfc, 0xc5, 0x56, 0xea, 0x5f, 0x19, 0xf8, 0xf1, 0xaa, 0x52, - 0x30, 0x66, 0xe0, 0xcd, 0x5c, 0x0a, 0x8b, 0x08, 0x97, 0x33, 0x41, 0x0c, 0x1f, 0x4e, 0x35, 0x05, - 0xbd, 0xcf, 0xbc, 0x7f, 0x82, 0x9d, 0x87, 0x57, 0x92, 0xe2, 0xa9, 0xb1, 0x2f, 0x32, 0x8e, 0x25, - 0xe7, 0xca, 0xaa, 0xd8, 0x66, 0xe1, 0xcc, 0x6f, 0xca, 0xa6, 0x74, 0x3f, 0x01, 0xbc, 0xd6, 0x14, - 0x74, 0xcd, 0x67, 0x9d, 0xff, 0x0d, 0xa6, 0x05, 0x70, 0x10, 0x3b, 0xdc, 0x67, 0xb2, 0xd8, 0x3f, - 0xdd, 0x5f, 0x1d, 0x5e, 0x2a, 0x99, 0x2a, 0x0f, 0x61, 0x78, 0x4c, 0x15, 0x1e, 0x73, 0x95, 0xdb, - 0xac, 0xb1, 0x76, 0xf0, 0xa5, 0x52, 0x78, 0xfb, 0xb5, 0x52, 0xa5, 0xb6, 0xdc, 0xf2, 0x5b, 0x66, - 0x9b, 0x3b, 0x2a, 0x3c, 0xea, 0xab, 0x26, 0x3a, 0x8f, 0x91, 0x0c, 0x5c, 0x22, 0xa2, 0x07, 0xc4, - 0xcb, 0x93, 0xfd, 0x85, 0x91, 0x6d, 0x42, 0x71, 0x3b, 0xd8, 0x08, 0xe3, 0x27, 0x5e, 0x9f, 0xec, - 0x2f, 0x00, 0x4b, 0x15, 0x54, 0x33, 0xa9, 0xc0, 0x1b, 0x99, 0xbd, 0xa6, 0xd3, 0x78, 0x0a, 0xe0, - 0x58, 0x38, 0x35, 0xb7, 0x83, 0x25, 0x59, 0xc7, 0x1e, 0x76, 0x84, 0x76, 0x1b, 0x0e, 0x61, 0x5f, - 0x6e, 0x71, 0xcf, 0x96, 0x41, 0x3c, 0x82, 0x46, 0xf1, 0xc3, 0xfb, 0xda, 0xb8, 0x62, 0x57, 0xcd, - 0xdd, 0x93, 0x9e, 0xcd, 0xa8, 0x75, 0x6a, 0xd5, 0x6e, 0xc1, 0x41, 0x37, 0xba, 0x41, 0x85, 0x6b, - 0xa2, 0x3b, 0x5c, 0xf1, 0xfd, 0x8d, 0x81, 0xb0, 0x55, 0x4b, 0x79, 0x57, 0x46, 0xf7, 0x4e, 0xf6, - 0x17, 0x4e, 0x6f, 0x31, 0x4a, 0x70, 0xb2, 0x0b, 0x28, 0x81, 0x5d, 0xfa, 0x3c, 0x00, 0xfb, 0x9b, - 0x82, 0x6a, 0x6f, 0x00, 0x9c, 0xc8, 0xd9, 0x84, 0xf9, 0xee, 0x9a, 0xb9, 0x71, 0x2d, 0xd7, 0x2f, - 0x6c, 0x4d, 0xa7, 0x55, 0xdf, 0xfb, 0xf8, 0xfd, 0x79, 0xdf, 0xa2, 0x31, 0x8f, 0x7a, 0xde, 0x46, - 0x28, 0x27, 0xed, 0xef, 0x00, 0x2c, 0xe6, 0xae, 0xc2, 0x62, 0x06, 0x42, 0x9e, 0xb9, 0xbc, 0xfc, - 0x17, 0xe6, 0x94, 0x78, 0x39, 0x22, 0xae, 0x19, 0x8b, 0x19, 0xc4, 0x7e, 0x1e, 0xd6, 0x0b, 0x00, - 0xb5, 0xac, 0xfd, 0xc8, 0x00, 0xe8, 0xb5, 0x95, 0x6b, 0x17, 0xb2, 0xa5, 0x84, 0xb5, 0x88, 0x70, - 0xce, 0x98, 0xcd, 0x20, 0xdc, 0xec, 0x85, 0x78, 0x00, 0x47, 0xce, 0x85, 0xb5, 0x92, 0x35, 0x95, - 0x33, 0x86, 0xf2, 0xdc, 0x1f, 0x0c, 0x09, 0x48, 0xe3, 0xee, 0xc1, 0x91, 0x0e, 0x0e, 0x8f, 0x74, - 0xf0, 0xed, 0x48, 0x07, 0xcf, 0x8e, 0xf5, 0xc2, 0xe1, 0xb1, 0x5e, 0xf8, 0x74, 0xac, 0x17, 0x1e, - 0x9a, 0x67, 0x76, 0x72, 0x35, 0x5a, 0x82, 0x04, 0x47, 0xc4, 0xd0, 0xbb, 0x09, 0x76, 0xb4, 0x9f, - 0xad, 0xc1, 0xe8, 0x9d, 0xbd, 0xfc, 0x2b, 0x00, 0x00, 0xff, 0xff, 0xa4, 0x06, 0xeb, 0xcd, 0xb4, - 0x06, 0x00, 0x00, + // 686 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xb4, 0x94, 0x41, 0x4f, 0x13, 0x4f, + 0x18, 0xc6, 0x3b, 0x40, 0x48, 0x18, 0xf8, 0x17, 0xfe, 0x1b, 0x84, 0xb6, 0xe8, 0x16, 0x97, 0x10, + 0x0a, 0xa4, 0x3b, 0x29, 0x18, 0x0f, 0xdc, 0x2c, 0x09, 0xe1, 0xd2, 0x84, 0xac, 0x31, 0x31, 0x5e, + 0x9a, 0x69, 0x3b, 0x1d, 0x56, 0xd9, 0x99, 0xcd, 0xce, 0x2c, 0xa1, 0x57, 0xbe, 0x80, 0x46, 0x4f, + 0x7a, 0xf2, 0xa8, 0x9e, 0x30, 0xf1, 0x43, 0x70, 0x24, 0x7a, 0x31, 0x31, 0x51, 0x03, 0x26, 0x18, + 0x3f, 0x85, 0xd9, 0xdd, 0xd9, 0x42, 0xdb, 0x5d, 0xc5, 0x18, 0x2f, 0x6d, 0x77, 0x9e, 0x67, 0xf7, + 0xfd, 0xbd, 0x6f, 0x9f, 0x77, 0xe1, 0xec, 0x43, 0x9f, 0x71, 0xd4, 0x26, 0xc4, 0xc5, 0x1d, 0xb4, + 0x5f, 0x41, 0xf2, 0xc0, 0x74, 0x3d, 0x2e, 0xb9, 0x96, 0x0d, 0x04, 0x33, 0x12, 0xcc, 0xfd, 0x4a, + 0x61, 0x9a, 0x72, 0xca, 0x43, 0x09, 0x05, 0xbf, 0x22, 0x57, 0xe1, 0x3a, 0xe5, 0x9c, 0xee, 0x11, + 0x84, 0x5d, 0x1b, 0x61, 0xc6, 0xb8, 0xc4, 0xd2, 0xe6, 0x4c, 0x28, 0xf5, 0x7f, 0xec, 0xd8, 0x8c, + 0xa3, 0xf0, 0x53, 0x1d, 0xcd, 0x36, 0xb9, 0x70, 0xb8, 0x40, 0x8e, 0xa0, 0x41, 0x39, 0x47, 0x50, + 0x25, 0xe8, 0x4a, 0x68, 0x60, 0x41, 0xd0, 0x7e, 0xa5, 0x41, 0x24, 0xae, 0xa0, 0x26, 0xb7, 0x99, + 0xd2, 0xf3, 0x91, 0x5e, 0x8f, 0x10, 0xa2, 0x8b, 0x18, 0xa2, 0xaf, 0x07, 0x4a, 0x18, 0x11, 0x76, + 0xac, 0xce, 0xf5, 0xa9, 0xaa, 0xa5, 0x50, 0x34, 0x9e, 0x02, 0x98, 0xaf, 0x09, 0x6a, 0x11, 0x6a, + 0x0b, 0x49, 0xbc, 0x2d, 0x42, 0x76, 0x70, 0x67, 0x93, 0x33, 0xe9, 0xe1, 0xa6, 0xd4, 0x16, 0x61, + 0x56, 0x10, 0xd6, 0x22, 0x5e, 0x1d, 0xb7, 0x5a, 0x1e, 0x11, 0x22, 0x07, 0xe6, 0x41, 0x69, 0xcc, + 0xfa, 0x2f, 0x3a, 0xbd, 0x13, 0x1d, 0x6a, 0xdb, 0x70, 0xaa, 0x4d, 0x48, 0xdd, 0xc5, 0x9d, 0x7a, + 0x53, 0xdd, 0x9a, 0x1b, 0x9a, 0x07, 0xa5, 0xf1, 0x35, 0xdd, 0xec, 0x9d, 0xa2, 0xd9, 0x5b, 0xc0, + 0xca, 0xb6, 0x7b, 0xae, 0x37, 0x46, 0xbe, 0xbf, 0x2c, 0x66, 0x8c, 0x05, 0x78, 0x33, 0x95, 0xc9, + 0x22, 0xc2, 0xe5, 0x4c, 0x10, 0xc3, 0x87, 0x73, 0x35, 0x41, 0xef, 0x31, 0xef, 0xaf, 0xd0, 0x97, + 0xe1, 0x54, 0x8c, 0xdc, 0x35, 0x0e, 0x85, 0xc6, 0xc9, 0xf8, 0x5c, 0x59, 0x15, 0xdb, 0x22, 0x5c, + 0xf8, 0x45, 0xd9, 0x2e, 0xdd, 0x0f, 0x00, 0xaf, 0xd5, 0x04, 0xdd, 0xf2, 0x59, 0xeb, 0x5f, 0x83, + 0x69, 0x1d, 0x38, 0x8a, 0x1d, 0xee, 0x33, 0x99, 0x1b, 0x9e, 0x1f, 0x2e, 0x8d, 0xaf, 0xe5, 0x4d, + 0x95, 0x8e, 0x20, 0x4a, 0xa6, 0x8a, 0x92, 0xb9, 0xc9, 0x6d, 0x56, 0xdd, 0x3a, 0xfe, 0x5c, 0xcc, + 0xbc, 0xf9, 0x52, 0x2c, 0x51, 0x5b, 0xee, 0xfa, 0x0d, 0xb3, 0xc9, 0x1d, 0x15, 0x25, 0xf5, 0x55, + 0x16, 0xad, 0x47, 0x48, 0x76, 0x5c, 0x22, 0xc2, 0x1b, 0xc4, 0x8b, 0xf3, 0xa3, 0x95, 0x89, 0x3d, + 0x42, 0x71, 0x33, 0xf8, 0x6f, 0x6d, 0x26, 0x5e, 0x9d, 0x1f, 0xad, 0x00, 0x4b, 0x15, 0x54, 0x33, + 0x29, 0xc2, 0x1b, 0x89, 0xbd, 0x76, 0xa7, 0xf1, 0x18, 0xc0, 0xc9, 0x60, 0x6a, 0x6e, 0x0b, 0x4b, + 0xb2, 0x83, 0x3d, 0xec, 0x08, 0xed, 0x36, 0x1c, 0xc3, 0xbe, 0xdc, 0xe5, 0x9e, 0x2d, 0x3b, 0xd1, + 0x08, 0xaa, 0xb9, 0xf7, 0xef, 0xca, 0xd3, 0x8a, 0x5d, 0x35, 0x77, 0x57, 0x7a, 0x36, 0xa3, 0xd6, + 0x85, 0x55, 0xbb, 0x05, 0x47, 0xdd, 0xf0, 0x09, 0x2a, 0x62, 0x33, 0xfd, 0x11, 0x8b, 0x9e, 0x5f, + 0x1d, 0x09, 0x5a, 0xb5, 0x94, 0x77, 0x23, 0x7b, 0x78, 0x7e, 0xb4, 0x72, 0xf1, 0x14, 0x23, 0x0f, + 0x67, 0xfb, 0x80, 0x62, 0xd8, 0xb5, 0x4f, 0x23, 0x70, 0xb8, 0x26, 0xa8, 0xf6, 0x1a, 0xc0, 0x99, + 0x94, 0xbd, 0x58, 0xee, 0xaf, 0x99, 0x1a, 0xd7, 0x42, 0xe5, 0xca, 0xd6, 0xee, 0xb4, 0x2a, 0x87, + 0x1f, 0xbe, 0x3d, 0x1b, 0x5a, 0x35, 0x96, 0xd1, 0xc0, 0xbb, 0x09, 0xa5, 0xa4, 0xfd, 0x2d, 0x80, + 0xb9, 0xd4, 0x55, 0x58, 0x4d, 0x40, 0x48, 0x33, 0x17, 0xd6, 0xff, 0xc0, 0xdc, 0x25, 0x5e, 0x0f, + 0x89, 0xcb, 0xc6, 0x6a, 0x02, 0xb1, 0x9f, 0x86, 0xf5, 0x1c, 0x40, 0x2d, 0x69, 0x3f, 0x12, 0x00, + 0x06, 0x6d, 0x85, 0xf2, 0x95, 0x6c, 0x5d, 0xc2, 0x72, 0x48, 0xb8, 0x64, 0x2c, 0x26, 0x10, 0xb6, + 0x07, 0x21, 0xee, 0xc3, 0x89, 0x9e, 0xb0, 0x16, 0x93, 0xa6, 0x72, 0xc9, 0x50, 0x58, 0xfa, 0x8d, + 0x21, 0x06, 0xa9, 0x6e, 0x1f, 0x9f, 0xea, 0xe0, 0xe4, 0x54, 0x07, 0x5f, 0x4f, 0x75, 0xf0, 0xe4, + 0x4c, 0xcf, 0x9c, 0x9c, 0xe9, 0x99, 0x8f, 0x67, 0x7a, 0xe6, 0x81, 0x79, 0x69, 0x27, 0x37, 0xc3, + 0x25, 0x88, 0x71, 0x44, 0x04, 0x7d, 0x10, 0x63, 0x87, 0xfb, 0xd9, 0x18, 0x0d, 0xdf, 0xe0, 0xeb, + 0x3f, 0x03, 0x00, 0x00, 0xff, 0xff, 0xe0, 0x18, 0x62, 0x74, 0xc2, 0x06, 0x00, 0x00, } // Reference imports to suppress errors if they are not otherwise used. @@ -694,9 +694,9 @@ func (m *MsgRegisterFeePayContract) MarshalToSizedBuffer(dAtA []byte) (int, erro _ = i var l int _ = l - if m.Contract != nil { + if m.FeePayContract != nil { { - size, err := m.Contract.MarshalToSizedBuffer(dAtA[:i]) + size, err := m.FeePayContract.MarshalToSizedBuffer(dAtA[:i]) if err != nil { return 0, err } @@ -957,8 +957,8 @@ func (m *MsgRegisterFeePayContract) Size() (n int) { if l > 0 { n += 1 + l + sovTx(uint64(l)) } - if m.Contract != nil { - l = m.Contract.Size() + if m.FeePayContract != nil { + l = m.FeePayContract.Size() n += 1 + l + sovTx(uint64(l)) } return n @@ -1124,7 +1124,7 @@ func (m *MsgRegisterFeePayContract) Unmarshal(dAtA []byte) error { iNdEx = postIndex case 2: if wireType != 2 { - return fmt.Errorf("proto: wrong wireType = %d for field Contract", wireType) + return fmt.Errorf("proto: wrong wireType = %d for field FeePayContract", wireType) } var msglen int for shift := uint(0); ; shift += 7 { @@ -1151,10 +1151,10 @@ func (m *MsgRegisterFeePayContract) Unmarshal(dAtA []byte) error { if postIndex > l { return io.ErrUnexpectedEOF } - if m.Contract == nil { - m.Contract = &FeePayContract{} + if m.FeePayContract == nil { + m.FeePayContract = &FeePayContract{} } - if err := m.Contract.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + if err := m.FeePayContract.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { return err } iNdEx = postIndex From 8b543dcee85aa1629794e64b3901c3f12b3ab65e Mon Sep 17 00:00:00 2001 From: Joel Smith Date: Tue, 19 Sep 2023 17:06:40 -0500 Subject: [PATCH 32/79] Add Tx for Updating Wallet Limit --- proto/juno/feepay/v1/tx.proto | 23 ++ scripts/feepay.sh | 8 + x/feepay/client/cli/tx.go | 43 ++- x/feepay/keeper/feepay.go | 28 ++ x/feepay/keeper/msg_server.go | 14 + x/feepay/types/msg.go | 48 +++- x/feepay/types/tx.pb.go | 520 +++++++++++++++++++++++++++++++--- x/feepay/types/tx.pb.gw.go | 83 ++++++ 8 files changed, 715 insertions(+), 52 deletions(-) diff --git a/proto/juno/feepay/v1/tx.proto b/proto/juno/feepay/v1/tx.proto index dbde95622..f3833ca00 100644 --- a/proto/juno/feepay/v1/tx.proto +++ b/proto/juno/feepay/v1/tx.proto @@ -31,6 +31,12 @@ service Msg { returns (MsgFundFeePayContractResponse) { option (google.api.http).post = "/juno/feepay/v1/tx/fundFeePayContract"; }; + + // Update a fee pay contract wallet limit + rpc UpdateFeePayContractWalletLimit(MsgUpdateFeePayContractWalletLimit) + returns (MsgUpdateFeePayContractWalletLimitResponse) { + option (google.api.http).post = "/juno/feepay/v1/tx/updateFeePayContractWalletLimit"; + }; // Update the params of the module through gov v1 type. rpc UpdateParams(MsgUpdateParams) returns (MsgUpdateParamsResponse); @@ -86,6 +92,23 @@ message MsgFundFeePayContract { // The response message for funding a fee pay contract. message MsgFundFeePayContractResponse {} +// The message to update a fee pay contract wallet limit. +message MsgUpdateFeePayContractWalletLimit { + option (gogoproto.equal) = false; + + // The wallet address of the sender. + string sender_address = 1; + + // The fee pay contract to fund. + string contract_address = 2; + + // The new wallet limit. + uint64 wallet_limit = 3; +} + +// The response message for updating a fee pay contract wallet limit. +message MsgUpdateFeePayContractWalletLimitResponse {} + // MsgUpdateParams is the Msg/UpdateParams request type. // // Since: cosmos-sdk 0.47 diff --git a/scripts/feepay.sh b/scripts/feepay.sh index 951bfd360..54c39c8d1 100644 --- a/scripts/feepay.sh +++ b/scripts/feepay.sh @@ -43,3 +43,11 @@ junod tx feepay fund juno14hj2tavq8fpesdwxxcu44rty3hh90vhujrvcmstl4zr3txmfvw9skj sleep 3 junod q feepay contract juno14hj2tavq8fpesdwxxcu44rty3hh90vhujrvcmstl4zr3txmfvw9skjuwg8 --home /home/joel/.juno1 --chain-id local-1 + +sleep 3 + +junod tx feepay update-wallet-limit juno14hj2tavq8fpesdwxxcu44rty3hh90vhujrvcmstl4zr3txmfvw9skjuwg8 5 --gas=200000 --fees=5000ujuno --home /home/joel/.juno1 --chain-id local-1 --keyring-backend=test --from juno1 -y + +sleep 3 + +junod q feepay contract juno14hj2tavq8fpesdwxxcu44rty3hh90vhujrvcmstl4zr3txmfvw9skjuwg8 --home /home/joel/.juno1 --chain-id local-1 diff --git a/x/feepay/client/cli/tx.go b/x/feepay/client/cli/tx.go index 2461fffd8..8e92a198f 100644 --- a/x/feepay/client/cli/tx.go +++ b/x/feepay/client/cli/tx.go @@ -28,7 +28,7 @@ func NewTxCmd() *cobra.Command { NewRegisterFeePayContract(), NewUnregisterFeePayContract(), NewFundFeePayContract(), - // TODO: update wallet limit for usage. (0 = disabled) + NewUpdateFeePayContractWalletLimit(), ) return txCmd } @@ -150,3 +150,44 @@ func NewFundFeePayContract() *cobra.Command { flags.AddTxFlagsToCmd(cmd) return cmd } + +// NewUpdateFeePayContractWalletLimit returns a CLI command handler for +// updating the wallet limit of a fee pay contract. +func NewUpdateFeePayContractWalletLimit() *cobra.Command { + cmd := &cobra.Command{ + Use: "update-wallet-limit [contract_bech32] [wallet_limit]", + Short: "Update the wallet limit of a fee pay contract.", + Long: "Update the wallet limit of a fee pay contract.", + Args: cobra.ExactArgs(2), + RunE: func(cmd *cobra.Command, args []string) error { + cliCtx, err := client.GetClientTxContext(cmd) + if err != nil { + return err + } + + sender_address := cliCtx.GetFromAddress() + contract_address := args[0] + wallet_limit := args[1] + dec_limit, err := strconv.ParseUint(wallet_limit, 10, 64) + + if err != nil { + return err + } + + msg := &types.MsgUpdateFeePayContractWalletLimit{ + SenderAddress: sender_address.String(), + ContractAddress: contract_address, + WalletLimit: dec_limit, + } + + if err := msg.ValidateBasic(); err != nil { + return err + } + + return tx.GenerateOrBroadcastTxCLI(cliCtx, cmd.Flags(), msg) + }, + } + + flags.AddTxFlagsToCmd(cmd) + return cmd +} diff --git a/x/feepay/keeper/feepay.go b/x/feepay/keeper/feepay.go index bfc7f5f0d..09e6b31d6 100644 --- a/x/feepay/keeper/feepay.go +++ b/x/feepay/keeper/feepay.go @@ -255,6 +255,34 @@ func (k Keeper) HasWalletExceededUsageLimit(ctx sdk.Context, fpc *types.FeePayCo return uses >= fpc.WalletLimit } +// Update the wallet limit of an existing fee pay contract +func (k Keeper) UpdateContractWalletLimit(ctx sdk.Context, fpc *types.FeePayContract, senderAddress string, walletLimit uint64) error { + + // Check if a cw contract + contractAddr, err := sdk.AccAddressFromBech32(fpc.ContractAddress) + if err != nil { + return err + } + + if ok := k.wasmKeeper.HasContractInfo(ctx, contractAddr); !ok { + return types.ErrInvalidCWContract + } + + // Get the contract info & ensure sender is the manager + contractInfo := k.wasmKeeper.GetContractInfo(ctx, contractAddr) + + if ok, err := k.IsContractManager(senderAddress, contractInfo); !ok { + return err + } + + // Update the store with the new limit + store := prefix.NewStore(ctx.KVStore(k.storeKey), []byte(StoreKeyContracts)) + fpc.WalletLimit = walletLimit + store.Set([]byte(fpc.ContractAddress), k.cdc.MustMarshal(fpc)) + + return nil +} + // Check if a wallet is eligible to interact with a contract func (k Keeper) IsWalletEligible(ctx sdk.Context, fpc *types.FeePayContract, walletAddress string) (bool, error) { diff --git a/x/feepay/keeper/msg_server.go b/x/feepay/keeper/msg_server.go index ed5955a85..e4d6f9814 100644 --- a/x/feepay/keeper/msg_server.go +++ b/x/feepay/keeper/msg_server.go @@ -40,6 +40,20 @@ func (k Keeper) FundFeePayContract(goCtx context.Context, msg *types.MsgFundFeeP return &types.MsgFundFeePayContractResponse{}, k.FundContract(ctx, contract, senderAddr, msg.Amount) } +// Update the wallet limit of a fee pay contract. +func (k Keeper) UpdateFeePayContractWalletLimit(goCtx context.Context, msg *types.MsgUpdateFeePayContractWalletLimit) (*types.MsgUpdateFeePayContractWalletLimitResponse, error) { + ctx := sdk.UnwrapSDKContext(goCtx) + + // Get the contract + contract, err := k.GetContract(ctx, msg.ContractAddress) + if err != nil { + return nil, err + } + + return &types.MsgUpdateFeePayContractWalletLimitResponse{}, k.UpdateContractWalletLimit(ctx, contract, msg.SenderAddress, msg.WalletLimit) +} + +// UpdateParams updates the parameters of the module. func (k Keeper) UpdateParams(goCtx context.Context, req *types.MsgUpdateParams) (*types.MsgUpdateParamsResponse, error) { if k.authority != req.Authority { return nil, errorsmod.Wrapf(govtypes.ErrInvalidSigner, "invalid authority; expected %s, got %s", k.authority, req.Authority) diff --git a/x/feepay/types/msg.go b/x/feepay/types/msg.go index 12e445196..36a60b054 100644 --- a/x/feepay/types/msg.go +++ b/x/feepay/types/msg.go @@ -8,14 +8,16 @@ var ( _ sdk.Msg = &MsgRegisterFeePayContract{} _ sdk.Msg = &MsgUnregisterFeePayContract{} _ sdk.Msg = &MsgFundFeePayContract{} + _ sdk.Msg = &MsgUpdateFeePayContractWalletLimit{} _ sdk.Msg = &MsgUpdateParams{} ) const ( - TypeMsgRegisterFeePayContract = "register_feepay_contract" - TypeMsgUnregisterFeePayContract = "unregister_feepay_contract" - TypeMsgFundFeePayContract = "fund_feepay_contract" - TypeMsgUpdateParams = "msg_update_params" + TypeMsgRegisterFeePayContract = "register_feepay_contract" + TypeMsgUnregisterFeePayContract = "unregister_feepay_contract" + TypeMsgFundFeePayContract = "fund_feepay_contract" + TypeMsgUpdateFeePayContractWalletLimit = "update_feepay_contract_wallet_limit" + TypeMsgUpdateParams = "msg_update_params" ) // Route returns the name of the module @@ -118,6 +120,43 @@ func (msg MsgFundFeePayContract) GetSigners() []sdk.AccAddress { return []sdk.AccAddress{from} } +// Route returns the name of the module +func (msg MsgUpdateFeePayContractWalletLimit) Route() string { return RouterKey } + +// Type returns the the action +func (msg MsgUpdateFeePayContractWalletLimit) Type() string { + return TypeMsgUpdateFeePayContractWalletLimit +} + +// ValidateBasic runs stateless checks on the message +func (msg MsgUpdateFeePayContractWalletLimit) ValidateBasic() error { + + if _, err := sdk.AccAddressFromBech32(msg.SenderAddress); err != nil { + return err + } + + if _, err := sdk.AccAddressFromBech32(msg.ContractAddress); err != nil { + return err + } + + if msg.WalletLimit > 1_000_000 { + return ErrInvalidWalletLimit + } + + return nil +} + +// GetSignBytes encodes the message for signing +func (msg *MsgUpdateFeePayContractWalletLimit) GetSignBytes() []byte { + return sdk.MustSortJSON(AminoCdc.MustMarshalJSON(msg)) +} + +// GetSigners defines whose signature is required +func (msg MsgUpdateFeePayContractWalletLimit) GetSigners() []sdk.AccAddress { + from, _ := sdk.AccAddressFromBech32(msg.SenderAddress) + return []sdk.AccAddress{from} +} + // Route returns the name of the module func (msg MsgUpdateParams) Route() string { return RouterKey } @@ -126,7 +165,6 @@ func (msg MsgUpdateParams) Type() string { return TypeMsgUpdateParams } // ValidateBasic does a sanity check on the provided data. func (m *MsgUpdateParams) ValidateBasic() error { - // TODO: LATER return nil } diff --git a/x/feepay/types/tx.pb.go b/x/feepay/types/tx.pb.go index eea9eabf5..55faee6c0 100644 --- a/x/feepay/types/tx.pb.go +++ b/x/feepay/types/tx.pb.go @@ -319,6 +319,111 @@ func (m *MsgFundFeePayContractResponse) XXX_DiscardUnknown() { var xxx_messageInfo_MsgFundFeePayContractResponse proto.InternalMessageInfo +// The message to update a fee pay contract wallet limit. +type MsgUpdateFeePayContractWalletLimit struct { + // The wallet address of the sender. + SenderAddress string `protobuf:"bytes,1,opt,name=sender_address,json=senderAddress,proto3" json:"sender_address,omitempty"` + // The fee pay contract to fund. + ContractAddress string `protobuf:"bytes,2,opt,name=contract_address,json=contractAddress,proto3" json:"contract_address,omitempty"` + // The new wallet limit. + WalletLimit uint64 `protobuf:"varint,3,opt,name=wallet_limit,json=walletLimit,proto3" json:"wallet_limit,omitempty"` +} + +func (m *MsgUpdateFeePayContractWalletLimit) Reset() { *m = MsgUpdateFeePayContractWalletLimit{} } +func (m *MsgUpdateFeePayContractWalletLimit) String() string { return proto.CompactTextString(m) } +func (*MsgUpdateFeePayContractWalletLimit) ProtoMessage() {} +func (*MsgUpdateFeePayContractWalletLimit) Descriptor() ([]byte, []int) { + return fileDescriptor_d739bd30c8846fd5, []int{6} +} +func (m *MsgUpdateFeePayContractWalletLimit) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *MsgUpdateFeePayContractWalletLimit) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_MsgUpdateFeePayContractWalletLimit.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 *MsgUpdateFeePayContractWalletLimit) XXX_Merge(src proto.Message) { + xxx_messageInfo_MsgUpdateFeePayContractWalletLimit.Merge(m, src) +} +func (m *MsgUpdateFeePayContractWalletLimit) XXX_Size() int { + return m.Size() +} +func (m *MsgUpdateFeePayContractWalletLimit) XXX_DiscardUnknown() { + xxx_messageInfo_MsgUpdateFeePayContractWalletLimit.DiscardUnknown(m) +} + +var xxx_messageInfo_MsgUpdateFeePayContractWalletLimit proto.InternalMessageInfo + +func (m *MsgUpdateFeePayContractWalletLimit) GetSenderAddress() string { + if m != nil { + return m.SenderAddress + } + return "" +} + +func (m *MsgUpdateFeePayContractWalletLimit) GetContractAddress() string { + if m != nil { + return m.ContractAddress + } + return "" +} + +func (m *MsgUpdateFeePayContractWalletLimit) GetWalletLimit() uint64 { + if m != nil { + return m.WalletLimit + } + return 0 +} + +// The response message for updating a fee pay contract wallet limit. +type MsgUpdateFeePayContractWalletLimitResponse struct { +} + +func (m *MsgUpdateFeePayContractWalletLimitResponse) Reset() { + *m = MsgUpdateFeePayContractWalletLimitResponse{} +} +func (m *MsgUpdateFeePayContractWalletLimitResponse) String() string { + return proto.CompactTextString(m) +} +func (*MsgUpdateFeePayContractWalletLimitResponse) ProtoMessage() {} +func (*MsgUpdateFeePayContractWalletLimitResponse) Descriptor() ([]byte, []int) { + return fileDescriptor_d739bd30c8846fd5, []int{7} +} +func (m *MsgUpdateFeePayContractWalletLimitResponse) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *MsgUpdateFeePayContractWalletLimitResponse) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_MsgUpdateFeePayContractWalletLimitResponse.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 *MsgUpdateFeePayContractWalletLimitResponse) XXX_Merge(src proto.Message) { + xxx_messageInfo_MsgUpdateFeePayContractWalletLimitResponse.Merge(m, src) +} +func (m *MsgUpdateFeePayContractWalletLimitResponse) XXX_Size() int { + return m.Size() +} +func (m *MsgUpdateFeePayContractWalletLimitResponse) XXX_DiscardUnknown() { + xxx_messageInfo_MsgUpdateFeePayContractWalletLimitResponse.DiscardUnknown(m) +} + +var xxx_messageInfo_MsgUpdateFeePayContractWalletLimitResponse proto.InternalMessageInfo + // MsgUpdateParams is the Msg/UpdateParams request type. // // Since: cosmos-sdk 0.47 @@ -335,7 +440,7 @@ func (m *MsgUpdateParams) Reset() { *m = MsgUpdateParams{} } func (m *MsgUpdateParams) String() string { return proto.CompactTextString(m) } func (*MsgUpdateParams) ProtoMessage() {} func (*MsgUpdateParams) Descriptor() ([]byte, []int) { - return fileDescriptor_d739bd30c8846fd5, []int{6} + return fileDescriptor_d739bd30c8846fd5, []int{8} } func (m *MsgUpdateParams) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -389,7 +494,7 @@ func (m *MsgUpdateParamsResponse) Reset() { *m = MsgUpdateParamsResponse func (m *MsgUpdateParamsResponse) String() string { return proto.CompactTextString(m) } func (*MsgUpdateParamsResponse) ProtoMessage() {} func (*MsgUpdateParamsResponse) Descriptor() ([]byte, []int) { - return fileDescriptor_d739bd30c8846fd5, []int{7} + return fileDescriptor_d739bd30c8846fd5, []int{9} } func (m *MsgUpdateParamsResponse) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -425,6 +530,8 @@ func init() { proto.RegisterType((*MsgUnregisterFeePayContractResponse)(nil), "juno.feepay.v1.MsgUnregisterFeePayContractResponse") proto.RegisterType((*MsgFundFeePayContract)(nil), "juno.feepay.v1.MsgFundFeePayContract") proto.RegisterType((*MsgFundFeePayContractResponse)(nil), "juno.feepay.v1.MsgFundFeePayContractResponse") + proto.RegisterType((*MsgUpdateFeePayContractWalletLimit)(nil), "juno.feepay.v1.MsgUpdateFeePayContractWalletLimit") + proto.RegisterType((*MsgUpdateFeePayContractWalletLimitResponse)(nil), "juno.feepay.v1.MsgUpdateFeePayContractWalletLimitResponse") proto.RegisterType((*MsgUpdateParams)(nil), "juno.feepay.v1.MsgUpdateParams") proto.RegisterType((*MsgUpdateParamsResponse)(nil), "juno.feepay.v1.MsgUpdateParamsResponse") } @@ -432,50 +539,56 @@ func init() { func init() { proto.RegisterFile("juno/feepay/v1/tx.proto", fileDescriptor_d739bd30c8846fd5) } var fileDescriptor_d739bd30c8846fd5 = []byte{ - // 686 bytes of a gzipped FileDescriptorProto - 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xb4, 0x94, 0x41, 0x4f, 0x13, 0x4f, - 0x18, 0xc6, 0x3b, 0x40, 0x48, 0x18, 0xf8, 0x17, 0xfe, 0x1b, 0x84, 0xb6, 0xe8, 0x16, 0x97, 0x10, - 0x0a, 0xa4, 0x3b, 0x29, 0x18, 0x0f, 0xdc, 0x2c, 0x09, 0xe1, 0xd2, 0x84, 0xac, 0x31, 0x31, 0x5e, - 0x9a, 0x69, 0x3b, 0x1d, 0x56, 0xd9, 0x99, 0xcd, 0xce, 0x2c, 0xa1, 0x57, 0xbe, 0x80, 0x46, 0x4f, - 0x7a, 0xf2, 0xa8, 0x9e, 0x30, 0xf1, 0x43, 0x70, 0x24, 0x7a, 0x31, 0x31, 0x51, 0x03, 0x26, 0x18, - 0x3f, 0x85, 0xd9, 0xdd, 0xd9, 0x42, 0xdb, 0x5d, 0xc5, 0x18, 0x2f, 0x6d, 0x77, 0x9e, 0x67, 0xf7, - 0xfd, 0xbd, 0x6f, 0x9f, 0x77, 0xe1, 0xec, 0x43, 0x9f, 0x71, 0xd4, 0x26, 0xc4, 0xc5, 0x1d, 0xb4, - 0x5f, 0x41, 0xf2, 0xc0, 0x74, 0x3d, 0x2e, 0xb9, 0x96, 0x0d, 0x04, 0x33, 0x12, 0xcc, 0xfd, 0x4a, - 0x61, 0x9a, 0x72, 0xca, 0x43, 0x09, 0x05, 0xbf, 0x22, 0x57, 0xe1, 0x3a, 0xe5, 0x9c, 0xee, 0x11, - 0x84, 0x5d, 0x1b, 0x61, 0xc6, 0xb8, 0xc4, 0xd2, 0xe6, 0x4c, 0x28, 0xf5, 0x7f, 0xec, 0xd8, 0x8c, - 0xa3, 0xf0, 0x53, 0x1d, 0xcd, 0x36, 0xb9, 0x70, 0xb8, 0x40, 0x8e, 0xa0, 0x41, 0x39, 0x47, 0x50, - 0x25, 0xe8, 0x4a, 0x68, 0x60, 0x41, 0xd0, 0x7e, 0xa5, 0x41, 0x24, 0xae, 0xa0, 0x26, 0xb7, 0x99, - 0xd2, 0xf3, 0x91, 0x5e, 0x8f, 0x10, 0xa2, 0x8b, 0x18, 0xa2, 0xaf, 0x07, 0x4a, 0x18, 0x11, 0x76, - 0xac, 0xce, 0xf5, 0xa9, 0xaa, 0xa5, 0x50, 0x34, 0x9e, 0x02, 0x98, 0xaf, 0x09, 0x6a, 0x11, 0x6a, - 0x0b, 0x49, 0xbc, 0x2d, 0x42, 0x76, 0x70, 0x67, 0x93, 0x33, 0xe9, 0xe1, 0xa6, 0xd4, 0x16, 0x61, - 0x56, 0x10, 0xd6, 0x22, 0x5e, 0x1d, 0xb7, 0x5a, 0x1e, 0x11, 0x22, 0x07, 0xe6, 0x41, 0x69, 0xcc, - 0xfa, 0x2f, 0x3a, 0xbd, 0x13, 0x1d, 0x6a, 0xdb, 0x70, 0xaa, 0x4d, 0x48, 0xdd, 0xc5, 0x9d, 0x7a, - 0x53, 0xdd, 0x9a, 0x1b, 0x9a, 0x07, 0xa5, 0xf1, 0x35, 0xdd, 0xec, 0x9d, 0xa2, 0xd9, 0x5b, 0xc0, - 0xca, 0xb6, 0x7b, 0xae, 0x37, 0x46, 0xbe, 0xbf, 0x2c, 0x66, 0x8c, 0x05, 0x78, 0x33, 0x95, 0xc9, - 0x22, 0xc2, 0xe5, 0x4c, 0x10, 0xc3, 0x87, 0x73, 0x35, 0x41, 0xef, 0x31, 0xef, 0xaf, 0xd0, 0x97, - 0xe1, 0x54, 0x8c, 0xdc, 0x35, 0x0e, 0x85, 0xc6, 0xc9, 0xf8, 0x5c, 0x59, 0x15, 0xdb, 0x22, 0x5c, - 0xf8, 0x45, 0xd9, 0x2e, 0xdd, 0x0f, 0x00, 0xaf, 0xd5, 0x04, 0xdd, 0xf2, 0x59, 0xeb, 0x5f, 0x83, - 0x69, 0x1d, 0x38, 0x8a, 0x1d, 0xee, 0x33, 0x99, 0x1b, 0x9e, 0x1f, 0x2e, 0x8d, 0xaf, 0xe5, 0x4d, - 0x95, 0x8e, 0x20, 0x4a, 0xa6, 0x8a, 0x92, 0xb9, 0xc9, 0x6d, 0x56, 0xdd, 0x3a, 0xfe, 0x5c, 0xcc, - 0xbc, 0xf9, 0x52, 0x2c, 0x51, 0x5b, 0xee, 0xfa, 0x0d, 0xb3, 0xc9, 0x1d, 0x15, 0x25, 0xf5, 0x55, - 0x16, 0xad, 0x47, 0x48, 0x76, 0x5c, 0x22, 0xc2, 0x1b, 0xc4, 0x8b, 0xf3, 0xa3, 0x95, 0x89, 0x3d, - 0x42, 0x71, 0x33, 0xf8, 0x6f, 0x6d, 0x26, 0x5e, 0x9d, 0x1f, 0xad, 0x00, 0x4b, 0x15, 0x54, 0x33, - 0x29, 0xc2, 0x1b, 0x89, 0xbd, 0x76, 0xa7, 0xf1, 0x18, 0xc0, 0xc9, 0x60, 0x6a, 0x6e, 0x0b, 0x4b, - 0xb2, 0x83, 0x3d, 0xec, 0x08, 0xed, 0x36, 0x1c, 0xc3, 0xbe, 0xdc, 0xe5, 0x9e, 0x2d, 0x3b, 0xd1, - 0x08, 0xaa, 0xb9, 0xf7, 0xef, 0xca, 0xd3, 0x8a, 0x5d, 0x35, 0x77, 0x57, 0x7a, 0x36, 0xa3, 0xd6, - 0x85, 0x55, 0xbb, 0x05, 0x47, 0xdd, 0xf0, 0x09, 0x2a, 0x62, 0x33, 0xfd, 0x11, 0x8b, 0x9e, 0x5f, - 0x1d, 0x09, 0x5a, 0xb5, 0x94, 0x77, 0x23, 0x7b, 0x78, 0x7e, 0xb4, 0x72, 0xf1, 0x14, 0x23, 0x0f, - 0x67, 0xfb, 0x80, 0x62, 0xd8, 0xb5, 0x4f, 0x23, 0x70, 0xb8, 0x26, 0xa8, 0xf6, 0x1a, 0xc0, 0x99, - 0x94, 0xbd, 0x58, 0xee, 0xaf, 0x99, 0x1a, 0xd7, 0x42, 0xe5, 0xca, 0xd6, 0xee, 0xb4, 0x2a, 0x87, - 0x1f, 0xbe, 0x3d, 0x1b, 0x5a, 0x35, 0x96, 0xd1, 0xc0, 0xbb, 0x09, 0xa5, 0xa4, 0xfd, 0x2d, 0x80, - 0xb9, 0xd4, 0x55, 0x58, 0x4d, 0x40, 0x48, 0x33, 0x17, 0xd6, 0xff, 0xc0, 0xdc, 0x25, 0x5e, 0x0f, - 0x89, 0xcb, 0xc6, 0x6a, 0x02, 0xb1, 0x9f, 0x86, 0xf5, 0x1c, 0x40, 0x2d, 0x69, 0x3f, 0x12, 0x00, - 0x06, 0x6d, 0x85, 0xf2, 0x95, 0x6c, 0x5d, 0xc2, 0x72, 0x48, 0xb8, 0x64, 0x2c, 0x26, 0x10, 0xb6, - 0x07, 0x21, 0xee, 0xc3, 0x89, 0x9e, 0xb0, 0x16, 0x93, 0xa6, 0x72, 0xc9, 0x50, 0x58, 0xfa, 0x8d, - 0x21, 0x06, 0xa9, 0x6e, 0x1f, 0x9f, 0xea, 0xe0, 0xe4, 0x54, 0x07, 0x5f, 0x4f, 0x75, 0xf0, 0xe4, - 0x4c, 0xcf, 0x9c, 0x9c, 0xe9, 0x99, 0x8f, 0x67, 0x7a, 0xe6, 0x81, 0x79, 0x69, 0x27, 0x37, 0xc3, - 0x25, 0x88, 0x71, 0x44, 0x04, 0x7d, 0x10, 0x63, 0x87, 0xfb, 0xd9, 0x18, 0x0d, 0xdf, 0xe0, 0xeb, - 0x3f, 0x03, 0x00, 0x00, 0xff, 0xff, 0xe0, 0x18, 0x62, 0x74, 0xc2, 0x06, 0x00, 0x00, + // 769 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xb4, 0x95, 0x4f, 0x4f, 0x1b, 0x47, + 0x18, 0xc6, 0x3d, 0x18, 0x59, 0x62, 0xa0, 0x86, 0xae, 0x28, 0xd8, 0xa6, 0x5d, 0x9b, 0x45, 0x08, + 0x63, 0xea, 0x5d, 0xd9, 0xa0, 0x1e, 0x7c, 0xab, 0x91, 0x10, 0x87, 0x5a, 0x42, 0x5b, 0x55, 0xad, + 0x7a, 0xb1, 0xc6, 0xf6, 0x78, 0xd9, 0xd6, 0x3b, 0xb3, 0xda, 0x19, 0x03, 0xbe, 0xf2, 0x05, 0x5a, + 0xb5, 0xa7, 0xf6, 0x92, 0x1c, 0xf3, 0xe7, 0x42, 0xa4, 0x7c, 0x08, 0x2e, 0x91, 0x50, 0x72, 0xc9, + 0x29, 0x89, 0x20, 0x12, 0x51, 0x3e, 0x45, 0xb4, 0xbb, 0xb3, 0x4b, 0x6c, 0x76, 0x31, 0x28, 0xe2, + 0x62, 0x7b, 0xe6, 0x79, 0x66, 0xde, 0xdf, 0xfb, 0xce, 0xbc, 0x63, 0xb8, 0xf8, 0x47, 0x9f, 0x50, + 0xad, 0x8b, 0xb1, 0x8d, 0x06, 0xda, 0x41, 0x45, 0xe3, 0x47, 0xaa, 0xed, 0x50, 0x4e, 0xa5, 0xb4, + 0x2b, 0xa8, 0xbe, 0xa0, 0x1e, 0x54, 0x72, 0xf3, 0x06, 0x35, 0xa8, 0x27, 0x69, 0xee, 0x2f, 0xdf, + 0x95, 0xfb, 0xd6, 0xa0, 0xd4, 0xe8, 0x61, 0x0d, 0xd9, 0xa6, 0x86, 0x08, 0xa1, 0x1c, 0x71, 0x93, + 0x12, 0x26, 0xd4, 0xaf, 0x91, 0x65, 0x12, 0xaa, 0x79, 0x9f, 0x62, 0x6a, 0xb1, 0x4d, 0x99, 0x45, + 0x99, 0x66, 0x31, 0xc3, 0x0d, 0x67, 0x31, 0x43, 0x08, 0xb2, 0x10, 0x5a, 0x88, 0x61, 0xed, 0xa0, + 0xd2, 0xc2, 0x1c, 0x55, 0xb4, 0x36, 0x35, 0x89, 0xd0, 0xb3, 0xbe, 0xde, 0xf4, 0x11, 0xfc, 0x41, + 0x00, 0x31, 0x92, 0x83, 0x81, 0x09, 0x66, 0x66, 0xa0, 0x2e, 0x8d, 0xa8, 0x22, 0x25, 0x4f, 0x54, + 0xfe, 0x01, 0x30, 0xdb, 0x60, 0x86, 0x8e, 0x0d, 0x93, 0x71, 0xec, 0xec, 0x60, 0xbc, 0x87, 0x06, + 0xdb, 0x94, 0x70, 0x07, 0xb5, 0xb9, 0xb4, 0x0a, 0xd3, 0x0c, 0x93, 0x0e, 0x76, 0x9a, 0xa8, 0xd3, + 0x71, 0x30, 0x63, 0x19, 0x50, 0x00, 0xc5, 0x29, 0xfd, 0x2b, 0x7f, 0xf6, 0x47, 0x7f, 0x52, 0xda, + 0x85, 0x73, 0x5d, 0x8c, 0x9b, 0x36, 0x1a, 0x34, 0xdb, 0x62, 0x69, 0x66, 0xa2, 0x00, 0x8a, 0xd3, + 0x55, 0x59, 0x1d, 0xae, 0xa2, 0x3a, 0x1c, 0x40, 0x4f, 0x77, 0x87, 0xc6, 0xb5, 0xc9, 0x0f, 0x0f, + 0xf3, 0x09, 0x65, 0x05, 0x2e, 0xc7, 0x32, 0xe9, 0x98, 0xd9, 0x94, 0x30, 0xac, 0xf4, 0xe1, 0x52, + 0x83, 0x19, 0xbf, 0x10, 0xe7, 0x8b, 0xd0, 0xd7, 0xe1, 0x5c, 0x80, 0x1c, 0x1a, 0x27, 0x3c, 0xe3, + 0x6c, 0x30, 0x2f, 0xac, 0x82, 0x6d, 0x15, 0xae, 0xdc, 0x10, 0x36, 0xa4, 0xfb, 0x08, 0xe0, 0x37, + 0x0d, 0x66, 0xec, 0xf4, 0x49, 0xe7, 0xbe, 0xc1, 0xa4, 0x01, 0x4c, 0x21, 0x8b, 0xf6, 0x09, 0xcf, + 0x24, 0x0b, 0xc9, 0xe2, 0x74, 0x35, 0xab, 0x8a, 0xdb, 0xe1, 0x5e, 0x25, 0x55, 0x5c, 0x25, 0x75, + 0x9b, 0x9a, 0xa4, 0xbe, 0x73, 0xfa, 0x26, 0x9f, 0x78, 0xf2, 0x36, 0x5f, 0x34, 0x4c, 0xbe, 0xdf, + 0x6f, 0xa9, 0x6d, 0x6a, 0x89, 0xab, 0x24, 0xbe, 0xca, 0xac, 0xf3, 0xa7, 0xc6, 0x07, 0x36, 0x66, + 0xde, 0x02, 0xf6, 0xff, 0xe5, 0x49, 0x69, 0xa6, 0x87, 0x0d, 0xd4, 0x76, 0xcf, 0xd6, 0x24, 0xec, + 0xd1, 0xe5, 0x49, 0x09, 0xe8, 0x22, 0xa0, 0xa8, 0x49, 0x1e, 0x7e, 0x17, 0x99, 0x6b, 0x58, 0x8d, + 0x07, 0x00, 0x2a, 0x6e, 0xd5, 0xec, 0x0e, 0xe2, 0x78, 0xd8, 0xf3, 0x2b, 0xea, 0xf5, 0x30, 0xff, + 0xc9, 0xb4, 0xcc, 0xfb, 0x28, 0xcd, 0x32, 0x9c, 0x39, 0xf4, 0x02, 0x34, 0x7b, 0x6e, 0x84, 0x4c, + 0xb2, 0x00, 0x8a, 0x93, 0xfa, 0xf4, 0xe1, 0x55, 0x50, 0x91, 0xc2, 0xf7, 0xb0, 0x34, 0x1e, 0x30, + 0xcc, 0xe7, 0x2f, 0x00, 0x67, 0x43, 0xfb, 0x1e, 0x72, 0x90, 0xc5, 0xa4, 0x1f, 0xe0, 0x14, 0xea, + 0xf3, 0x7d, 0xea, 0x98, 0x7c, 0xe0, 0x73, 0xd7, 0x33, 0x2f, 0x9f, 0x97, 0xe7, 0xc5, 0x59, 0x08, + 0xa2, 0x9f, 0xb9, 0x63, 0x12, 0x43, 0xbf, 0xb2, 0x4a, 0x5b, 0x30, 0x65, 0x7b, 0x3b, 0x88, 0x96, + 0x59, 0x18, 0x6d, 0x19, 0x7f, 0xff, 0xfa, 0xa4, 0x7b, 0x74, 0xba, 0xf0, 0xd6, 0xd2, 0xc7, 0x97, + 0x27, 0xa5, 0xab, 0x5d, 0x94, 0x2c, 0x5c, 0x1c, 0x01, 0x0a, 0x60, 0xab, 0x4f, 0x53, 0x30, 0xd9, + 0x60, 0x86, 0xf4, 0x18, 0xc0, 0x85, 0x98, 0x3e, 0x5f, 0x1f, 0x8d, 0x19, 0xdb, 0x7e, 0xb9, 0xca, + 0xad, 0xad, 0x61, 0xb5, 0x2a, 0xc7, 0xaf, 0xde, 0xff, 0x3b, 0xb1, 0xa1, 0xac, 0x6b, 0xd7, 0xde, + 0x5a, 0x2d, 0xa6, 0x7b, 0x9f, 0x01, 0x98, 0x89, 0x6d, 0xed, 0x8d, 0x08, 0x84, 0x38, 0x73, 0x6e, + 0xf3, 0x0e, 0xe6, 0x90, 0x78, 0xd3, 0x23, 0x2e, 0x2b, 0x1b, 0x11, 0xc4, 0xfd, 0x38, 0xac, 0xff, + 0x00, 0x94, 0xa2, 0xfa, 0x3d, 0x02, 0xe0, 0xba, 0x2d, 0x57, 0xbe, 0x95, 0x2d, 0x24, 0x2c, 0x7b, + 0x84, 0x6b, 0xca, 0x6a, 0x04, 0x61, 0xf7, 0x3a, 0xc4, 0x0b, 0x00, 0xf3, 0xe3, 0xba, 0xaf, 0x1a, + 0x55, 0xa9, 0x9b, 0xd7, 0xe4, 0x6a, 0x77, 0x5f, 0x13, 0xa6, 0x50, 0xf3, 0x52, 0xd8, 0x52, 0xaa, + 0x51, 0x45, 0x1e, 0xc3, 0xfa, 0x1b, 0x9c, 0x19, 0x6a, 0xbe, 0x7c, 0x2c, 0x87, 0x6f, 0xc8, 0xad, + 0x8d, 0x31, 0x04, 0x54, 0xf5, 0xdd, 0xd3, 0x73, 0x19, 0x9c, 0x9d, 0xcb, 0xe0, 0xdd, 0xb9, 0x0c, + 0xfe, 0xbe, 0x90, 0x13, 0x67, 0x17, 0x72, 0xe2, 0xf5, 0x85, 0x9c, 0xf8, 0x5d, 0xfd, 0xec, 0xcd, + 0xdc, 0xf6, 0x9a, 0x3a, 0x20, 0x63, 0x7e, 0x06, 0x47, 0x41, 0x0e, 0xde, 0xfb, 0xd9, 0x4a, 0x79, + 0xff, 0xb0, 0x9b, 0x9f, 0x02, 0x00, 0x00, 0xff, 0xff, 0x2c, 0x2b, 0xd3, 0x5b, 0x62, 0x08, 0x00, + 0x00, } // Reference imports to suppress errors if they are not otherwise used. @@ -496,6 +609,8 @@ type MsgClient interface { UnregisterFeePayContract(ctx context.Context, in *MsgUnregisterFeePayContract, opts ...grpc.CallOption) (*MsgUnregisterFeePayContractResponse, error) // Fund a fee pay contract FundFeePayContract(ctx context.Context, in *MsgFundFeePayContract, opts ...grpc.CallOption) (*MsgFundFeePayContractResponse, error) + // Update a fee pay contract wallet limit + UpdateFeePayContractWalletLimit(ctx context.Context, in *MsgUpdateFeePayContractWalletLimit, opts ...grpc.CallOption) (*MsgUpdateFeePayContractWalletLimitResponse, error) // Update the params of the module through gov v1 type. UpdateParams(ctx context.Context, in *MsgUpdateParams, opts ...grpc.CallOption) (*MsgUpdateParamsResponse, error) } @@ -535,6 +650,15 @@ func (c *msgClient) FundFeePayContract(ctx context.Context, in *MsgFundFeePayCon return out, nil } +func (c *msgClient) UpdateFeePayContractWalletLimit(ctx context.Context, in *MsgUpdateFeePayContractWalletLimit, opts ...grpc.CallOption) (*MsgUpdateFeePayContractWalletLimitResponse, error) { + out := new(MsgUpdateFeePayContractWalletLimitResponse) + err := c.cc.Invoke(ctx, "/juno.feepay.v1.Msg/UpdateFeePayContractWalletLimit", in, out, opts...) + if err != nil { + return nil, err + } + return out, nil +} + func (c *msgClient) UpdateParams(ctx context.Context, in *MsgUpdateParams, opts ...grpc.CallOption) (*MsgUpdateParamsResponse, error) { out := new(MsgUpdateParamsResponse) err := c.cc.Invoke(ctx, "/juno.feepay.v1.Msg/UpdateParams", in, out, opts...) @@ -552,6 +676,8 @@ type MsgServer interface { UnregisterFeePayContract(context.Context, *MsgUnregisterFeePayContract) (*MsgUnregisterFeePayContractResponse, error) // Fund a fee pay contract FundFeePayContract(context.Context, *MsgFundFeePayContract) (*MsgFundFeePayContractResponse, error) + // Update a fee pay contract wallet limit + UpdateFeePayContractWalletLimit(context.Context, *MsgUpdateFeePayContractWalletLimit) (*MsgUpdateFeePayContractWalletLimitResponse, error) // Update the params of the module through gov v1 type. UpdateParams(context.Context, *MsgUpdateParams) (*MsgUpdateParamsResponse, error) } @@ -569,6 +695,9 @@ func (*UnimplementedMsgServer) UnregisterFeePayContract(ctx context.Context, req func (*UnimplementedMsgServer) FundFeePayContract(ctx context.Context, req *MsgFundFeePayContract) (*MsgFundFeePayContractResponse, error) { return nil, status.Errorf(codes.Unimplemented, "method FundFeePayContract not implemented") } +func (*UnimplementedMsgServer) UpdateFeePayContractWalletLimit(ctx context.Context, req *MsgUpdateFeePayContractWalletLimit) (*MsgUpdateFeePayContractWalletLimitResponse, error) { + return nil, status.Errorf(codes.Unimplemented, "method UpdateFeePayContractWalletLimit not implemented") +} func (*UnimplementedMsgServer) UpdateParams(ctx context.Context, req *MsgUpdateParams) (*MsgUpdateParamsResponse, error) { return nil, status.Errorf(codes.Unimplemented, "method UpdateParams not implemented") } @@ -631,6 +760,24 @@ func _Msg_FundFeePayContract_Handler(srv interface{}, ctx context.Context, dec f return interceptor(ctx, in, info, handler) } +func _Msg_UpdateFeePayContractWalletLimit_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(MsgUpdateFeePayContractWalletLimit) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(MsgServer).UpdateFeePayContractWalletLimit(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: "/juno.feepay.v1.Msg/UpdateFeePayContractWalletLimit", + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(MsgServer).UpdateFeePayContractWalletLimit(ctx, req.(*MsgUpdateFeePayContractWalletLimit)) + } + return interceptor(ctx, in, info, handler) +} + func _Msg_UpdateParams_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { in := new(MsgUpdateParams) if err := dec(in); err != nil { @@ -665,6 +812,10 @@ var _Msg_serviceDesc = grpc.ServiceDesc{ MethodName: "FundFeePayContract", Handler: _Msg_FundFeePayContract_Handler, }, + { + MethodName: "UpdateFeePayContractWalletLimit", + Handler: _Msg_UpdateFeePayContractWalletLimit_Handler, + }, { MethodName: "UpdateParams", Handler: _Msg_UpdateParams_Handler, @@ -873,6 +1024,71 @@ func (m *MsgFundFeePayContractResponse) MarshalToSizedBuffer(dAtA []byte) (int, return len(dAtA) - i, nil } +func (m *MsgUpdateFeePayContractWalletLimit) 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 *MsgUpdateFeePayContractWalletLimit) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *MsgUpdateFeePayContractWalletLimit) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + if m.WalletLimit != 0 { + i = encodeVarintTx(dAtA, i, uint64(m.WalletLimit)) + i-- + dAtA[i] = 0x18 + } + if len(m.ContractAddress) > 0 { + i -= len(m.ContractAddress) + copy(dAtA[i:], m.ContractAddress) + i = encodeVarintTx(dAtA, i, uint64(len(m.ContractAddress))) + i-- + dAtA[i] = 0x12 + } + if len(m.SenderAddress) > 0 { + i -= len(m.SenderAddress) + copy(dAtA[i:], m.SenderAddress) + i = encodeVarintTx(dAtA, i, uint64(len(m.SenderAddress))) + i-- + dAtA[i] = 0xa + } + return len(dAtA) - i, nil +} + +func (m *MsgUpdateFeePayContractWalletLimitResponse) 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 *MsgUpdateFeePayContractWalletLimitResponse) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *MsgUpdateFeePayContractWalletLimitResponse) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + return len(dAtA) - i, nil +} + func (m *MsgUpdateParams) Marshal() (dAtA []byte, err error) { size := m.Size() dAtA = make([]byte, size) @@ -1031,6 +1247,35 @@ func (m *MsgFundFeePayContractResponse) Size() (n int) { return n } +func (m *MsgUpdateFeePayContractWalletLimit) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + l = len(m.SenderAddress) + if l > 0 { + n += 1 + l + sovTx(uint64(l)) + } + l = len(m.ContractAddress) + if l > 0 { + n += 1 + l + sovTx(uint64(l)) + } + if m.WalletLimit != 0 { + n += 1 + sovTx(uint64(m.WalletLimit)) + } + return n +} + +func (m *MsgUpdateFeePayContractWalletLimitResponse) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + return n +} + func (m *MsgUpdateParams) Size() (n int) { if m == nil { return 0 @@ -1591,6 +1836,189 @@ func (m *MsgFundFeePayContractResponse) Unmarshal(dAtA []byte) error { } return nil } +func (m *MsgUpdateFeePayContractWalletLimit) 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: MsgUpdateFeePayContractWalletLimit: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: MsgUpdateFeePayContractWalletLimit: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field SenderAddress", 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.SenderAddress = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + case 2: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field ContractAddress", 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.ContractAddress = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + case 3: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field WalletLimit", wireType) + } + m.WalletLimit = 0 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowTx + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + m.WalletLimit |= uint64(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 *MsgUpdateFeePayContractWalletLimitResponse) 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: MsgUpdateFeePayContractWalletLimitResponse: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: MsgUpdateFeePayContractWalletLimitResponse: 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 *MsgUpdateParams) Unmarshal(dAtA []byte) error { l := len(dAtA) iNdEx := 0 diff --git a/x/feepay/types/tx.pb.gw.go b/x/feepay/types/tx.pb.gw.go index bdd51e724..2eef89984 100644 --- a/x/feepay/types/tx.pb.gw.go +++ b/x/feepay/types/tx.pb.gw.go @@ -141,6 +141,42 @@ func local_request_Msg_FundFeePayContract_0(ctx context.Context, marshaler runti } +var ( + filter_Msg_UpdateFeePayContractWalletLimit_0 = &utilities.DoubleArray{Encoding: map[string]int{}, Base: []int(nil), Check: []int(nil)} +) + +func request_Msg_UpdateFeePayContractWalletLimit_0(ctx context.Context, marshaler runtime.Marshaler, client MsgClient, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) { + var protoReq MsgUpdateFeePayContractWalletLimit + 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_Msg_UpdateFeePayContractWalletLimit_0); err != nil { + return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err) + } + + msg, err := client.UpdateFeePayContractWalletLimit(ctx, &protoReq, grpc.Header(&metadata.HeaderMD), grpc.Trailer(&metadata.TrailerMD)) + return msg, metadata, err + +} + +func local_request_Msg_UpdateFeePayContractWalletLimit_0(ctx context.Context, marshaler runtime.Marshaler, server MsgServer, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) { + var protoReq MsgUpdateFeePayContractWalletLimit + 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_Msg_UpdateFeePayContractWalletLimit_0); err != nil { + return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err) + } + + msg, err := server.UpdateFeePayContractWalletLimit(ctx, &protoReq) + return msg, metadata, err + +} + // RegisterMsgHandlerServer registers the http handlers for service Msg to "mux". // UnaryRPC :call MsgServer directly. // StreamingRPC :currently unsupported pending https://github.com/grpc/grpc-go/issues/906. @@ -216,6 +252,29 @@ func RegisterMsgHandlerServer(ctx context.Context, mux *runtime.ServeMux, server }) + mux.Handle("POST", pattern_Msg_UpdateFeePayContractWalletLimit_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_Msg_UpdateFeePayContractWalletLimit_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_Msg_UpdateFeePayContractWalletLimit_0(ctx, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...) + + }) + return nil } @@ -317,6 +376,26 @@ func RegisterMsgHandlerClient(ctx context.Context, mux *runtime.ServeMux, client }) + mux.Handle("POST", pattern_Msg_UpdateFeePayContractWalletLimit_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_Msg_UpdateFeePayContractWalletLimit_0(rctx, inboundMarshaler, client, req, pathParams) + ctx = runtime.NewServerMetadataContext(ctx, md) + if err != nil { + runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) + return + } + + forward_Msg_UpdateFeePayContractWalletLimit_0(ctx, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...) + + }) + return nil } @@ -326,6 +405,8 @@ var ( pattern_Msg_UnregisterFeePayContract_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2, 2, 3, 2, 4}, []string{"juno", "feepay", "v1", "tx", "unregisterFeePayContract"}, "", runtime.AssumeColonVerbOpt(false))) pattern_Msg_FundFeePayContract_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2, 2, 3, 2, 4}, []string{"juno", "feepay", "v1", "tx", "fundFeePayContract"}, "", runtime.AssumeColonVerbOpt(false))) + + pattern_Msg_UpdateFeePayContractWalletLimit_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2, 2, 3, 2, 4}, []string{"juno", "feepay", "v1", "tx", "updateFeePayContractWalletLimit"}, "", runtime.AssumeColonVerbOpt(false))) ) var ( @@ -334,4 +415,6 @@ var ( forward_Msg_UnregisterFeePayContract_0 = runtime.ForwardResponseMessage forward_Msg_FundFeePayContract_0 = runtime.ForwardResponseMessage + + forward_Msg_UpdateFeePayContractWalletLimit_0 = runtime.ForwardResponseMessage ) From bcbe59354f93cf53f73278fc289ab109419e3154 Mon Sep 17 00:00:00 2001 From: Joel Smith Date: Wed, 20 Sep 2023 20:25:40 -0500 Subject: [PATCH 33/79] Add Params & Genesis Integration --- proto/juno/feepay/v1/genesis.proto | 19 +- proto/juno/feepay/v1/query.proto | 14 + x/feepay/client/cli/query.go | 31 +++ x/feepay/genesis.go | 17 +- x/feepay/keeper/feepay.go | 51 ++-- x/feepay/keeper/grpc_query.go | 12 +- x/feepay/keeper/keeper.go | 6 +- x/feepay/keeper/params.go | 27 +- x/feepay/module.go | 1 - x/feepay/types/constants.go | 8 + x/feepay/types/genesis.go | 9 +- x/feepay/types/genesis.pb.go | 61 ++++- x/feepay/types/query.pb.go | 415 ++++++++++++++++++++++++++--- x/feepay/types/query.pb.gw.go | 65 +++++ 14 files changed, 632 insertions(+), 104 deletions(-) diff --git a/proto/juno/feepay/v1/genesis.proto b/proto/juno/feepay/v1/genesis.proto index 064e8ba44..cc0a961ff 100644 --- a/proto/juno/feepay/v1/genesis.proto +++ b/proto/juno/feepay/v1/genesis.proto @@ -7,25 +7,14 @@ option go_package = "github.com/CosmosContracts/juno/x/feepay/types"; // GenesisState defines the module's genesis state. message GenesisState { - // params are the feeshare module parameters + // params are the feepay module parameters Params params = 1 [ (gogoproto.nullable) = false ]; repeated FeePayContract fee_contract = 2 [ (gogoproto.nullable) = false ]; } -// Params defines the feeshare module params +// Params defines the feepay module params message Params { - // // enable_feeshare defines a parameter to enable the feeshare module - // bool enable_fee_share = 1; - // // developer_shares defines the proportion of the transaction fees to be - // // distributed to the registered contract owner - // string developer_shares = 2 [ - // (gogoproto.customtype) = "github.com/cosmos/cosmos-sdk/types.Dec", - // (gogoproto.nullable) = false - // ]; - // // allowed_denoms defines the list of denoms that are allowed to be paid to - // // the contract withdraw addresses. If said denom is not in the list, the fees - // // will ONLY be sent to the community pool. - // // If this list is empty, all denoms are allowed. - // repeated string allowed_denoms = 3; + // enable_feepay defines a parameter to enable the feepay module + bool enable_feepay = 1; } diff --git a/proto/juno/feepay/v1/query.proto b/proto/juno/feepay/v1/query.proto index 296952be7..1aac276b9 100644 --- a/proto/juno/feepay/v1/query.proto +++ b/proto/juno/feepay/v1/query.proto @@ -30,6 +30,11 @@ service Query { rpc FeePayWalletIsEligible(QueryFeePayWalletIsEligible) returns (QueryFeePayWalletIsEligibleResponse) { option (google.api.http).get = "/juno/feepay/v1/feepay/{contract_address}/eligible/{wallet_address}"; } + + // Params retrieves the FeePay module params + rpc Params(QueryParamsRequest) returns (QueryParamsResponse) { + option (google.api.http).get = "/juno/feepay/v1/params"; + } } // QueryFeePayContract retrieves a single fee pay contract @@ -84,4 +89,13 @@ message QueryFeePayWalletIsEligible { message QueryFeePayWalletIsEligibleResponse { // The eligibility of the wallet for fee pay contract interactions bool eligible = 1; +} + +// QueryParamsRequest is the request type for the Query/Params RPC method. +message QueryParamsRequest {} + +// QueryParamsResponse is the response type for the Query/Params RPC method. +message QueryParamsResponse { + // params is the returned Feepay parameter + Params params = 1 [ (gogoproto.nullable) = false ]; } \ No newline at end of file diff --git a/x/feepay/client/cli/query.go b/x/feepay/client/cli/query.go index 65b731e76..420ca2b44 100644 --- a/x/feepay/client/cli/query.go +++ b/x/feepay/client/cli/query.go @@ -27,6 +27,7 @@ func NewQueryCmd() *cobra.Command { NewQueryFeePayContracts(), NewQueryFeePayContractUsage(), NewQueryWalletIsEligible(), + GetCmdQueryParams(), ) return feepayQueryCmd @@ -170,3 +171,33 @@ func NewQueryWalletIsEligible() *cobra.Command { return cmd } + +// GetCmdQueryParams implements a command to return the current FeePay +// parameters. +func GetCmdQueryParams() *cobra.Command { + cmd := &cobra.Command{ + Use: "params", + Short: "Query the current feepay module parameters", + Args: cobra.NoArgs, + RunE: func(cmd *cobra.Command, _ []string) error { + clientCtx, err := client.GetClientQueryContext(cmd) + if err != nil { + return err + } + queryClient := types.NewQueryClient(clientCtx) + + params := &types.QueryParamsRequest{} + + res, err := queryClient.Params(context.Background(), params) + if err != nil { + return err + } + + return clientCtx.PrintProto(&res.Params) + }, + } + + flags.AddQueryFlagsToCmd(cmd) + + return cmd +} diff --git a/x/feepay/genesis.go b/x/feepay/genesis.go index 47cee6245..9aa37ab0b 100644 --- a/x/feepay/genesis.go +++ b/x/feepay/genesis.go @@ -13,10 +13,23 @@ func InitGenesis( k keeper.Keeper, data types.GenesisState, ) { - // TODO: impl, just remember that ParamsKey is going to be nil? + if err := k.SetParams(ctx, data.Params); err != nil { + panic(err) + } + + for _, feepay := range data.FeeContract { + // TODO: future, add all wallet interactions for exports? + k.SetFeePayContract(ctx, feepay) + } } // ExportGenesis export module state func ExportGenesis(ctx sdk.Context, k keeper.Keeper) *types.GenesisState { - return &types.GenesisState{} + params := k.GetParams(ctx) + contract := k.GetAllContracts(ctx) + + return &types.GenesisState{ + Params: params, + FeeContract: contract, + } } diff --git a/x/feepay/keeper/feepay.go b/x/feepay/keeper/feepay.go index 09e6b31d6..17e1be272 100644 --- a/x/feepay/keeper/feepay.go +++ b/x/feepay/keeper/feepay.go @@ -11,7 +11,7 @@ import ( // Check if a contract is registered as a fee pay contract func (k Keeper) IsContractRegistered(ctx sdk.Context, contractAddr string) bool { - store := prefix.NewStore(ctx.KVStore(k.storeKey), []byte(StoreKeyContracts)) + store := prefix.NewStore(ctx.KVStore(k.storeKey), StoreKeyContracts) return store.Has([]byte(contractAddr)) } @@ -23,7 +23,7 @@ func (k Keeper) GetContract(ctx sdk.Context, contractAddress string) (*types.Fee return nil, types.ErrContractNotRegistered } - store := prefix.NewStore(ctx.KVStore(k.storeKey), []byte(StoreKeyContracts)) + store := prefix.NewStore(ctx.KVStore(k.storeKey), StoreKeyContracts) key := []byte(contractAddress) bz := store.Get(key) @@ -37,9 +37,9 @@ func (k Keeper) GetContract(ctx sdk.Context, contractAddress string) (*types.Fee } // Get all registered fee pay contracts -func (k Keeper) GetAllContracts(ctx sdk.Context, pag *query.PageRequest) (*types.QueryFeePayContractsResponse, error) { +func (k Keeper) GetContracts(ctx sdk.Context, pag *query.PageRequest) (*types.QueryFeePayContractsResponse, error) { - store := prefix.NewStore(ctx.KVStore(k.storeKey), []byte(StoreKeyContracts)) + store := prefix.NewStore(ctx.KVStore(k.storeKey), StoreKeyContracts) // Filter and paginate all contracts results, pageRes, err := query.GenericFilteredPaginate( @@ -70,6 +70,24 @@ func (k Keeper) GetAllContracts(ctx sdk.Context, pag *query.PageRequest) (*types }, nil } +// GetAllContracts returns all the registered FeePay contracts. +func (k Keeper) GetAllContracts(ctx sdk.Context) []types.FeePayContract { + contracts := []types.FeePayContract{} + + store := ctx.KVStore(k.storeKey) + iterator := sdk.KVStorePrefixIterator(store, StoreKeyContracts) + defer iterator.Close() + + for ; iterator.Valid(); iterator.Next() { + var c types.FeePayContract + k.cdc.MustUnmarshal(iterator.Value(), &c) + + contracts = append(contracts, c) + } + + return contracts +} + // Register the contract in the module store func (k Keeper) RegisterContract(ctx sdk.Context, rfp *types.MsgRegisterFeePayContract) error { @@ -96,13 +114,16 @@ func (k Keeper) RegisterContract(ctx sdk.Context, rfp *types.MsgRegisterFeePayCo return err } - // Register the new fee pay contract in the KV store - store := prefix.NewStore(ctx.KVStore(k.storeKey), []byte(StoreKeyContracts)) - key := []byte(rfp.FeePayContract.ContractAddress) - bz := k.cdc.MustMarshal(rfp.FeePayContract) + k.SetFeePayContract(ctx, *rfp.FeePayContract) + return nil +} +// Set a contract in the KV Store +func (k Keeper) SetFeePayContract(ctx sdk.Context, feepay types.FeePayContract) { + store := prefix.NewStore(ctx.KVStore(k.storeKey), StoreKeyContracts) + key := []byte(feepay.ContractAddress) + bz := k.cdc.MustMarshal(&feepay) store.Set(key, bz) - return nil } // Unregister contract (loop through usage store & remove all usage entries for contract) @@ -134,11 +155,11 @@ func (k Keeper) UnregisterContract(ctx sdk.Context, rfp *types.MsgUnregisterFeeP } // Remove contract from KV store - store := prefix.NewStore(ctx.KVStore(k.storeKey), []byte(StoreKeyContracts)) + store := prefix.NewStore(ctx.KVStore(k.storeKey), StoreKeyContracts) store.Delete([]byte(rfp.ContractAddress)) // Remove all usage entries for contract - store = prefix.NewStore(ctx.KVStore(k.storeKey), []byte(StoreKeyContractUses)) + store = prefix.NewStore(ctx.KVStore(k.storeKey), StoreKeyContractUses) iterator := sdk.KVStorePrefixIterator(store, []byte(rfp.ContractAddress)) for ; iterator.Valid(); iterator.Next() { @@ -168,7 +189,7 @@ func (k Keeper) UnregisterContract(ctx sdk.Context, rfp *types.MsgUnregisterFeeP func (k Keeper) SetContractBalance(ctx sdk.Context, fpc *types.FeePayContract, newBalance uint64) { // Get the existing contract in KV store - store := prefix.NewStore(ctx.KVStore(k.storeKey), []byte(StoreKeyContracts)) + store := prefix.NewStore(ctx.KVStore(k.storeKey), StoreKeyContracts) // Set new balance and save to KV store fpc.Balance = newBalance @@ -205,7 +226,7 @@ func (k Keeper) CanContractCoverFee(ctx sdk.Context, fpc *types.FeePayContract, func (k Keeper) GetContractUses(ctx sdk.Context, fpc *types.FeePayContract, walletAddress string) (uint64, error) { // Get usage from store - store := prefix.NewStore(ctx.KVStore(k.storeKey), []byte(StoreKeyContractUses)) + store := prefix.NewStore(ctx.KVStore(k.storeKey), StoreKeyContractUses) key := []byte(fpc.ContractAddress + "-" + walletAddress) bz := store.Get(key) @@ -226,7 +247,7 @@ func (k Keeper) IncrementContractUses(ctx sdk.Context, fpc *types.FeePayContract } // Get store, key, & value for setting usage - store := prefix.NewStore(ctx.KVStore(k.storeKey), []byte(StoreKeyContractUses)) + store := prefix.NewStore(ctx.KVStore(k.storeKey), StoreKeyContractUses) key := []byte(fpc.ContractAddress + "-" + walletAddress) bz, err := k.cdc.Marshal(&types.FeePayWalletUsage{ ContractAddress: fpc.ContractAddress, @@ -276,7 +297,7 @@ func (k Keeper) UpdateContractWalletLimit(ctx sdk.Context, fpc *types.FeePayCont } // Update the store with the new limit - store := prefix.NewStore(ctx.KVStore(k.storeKey), []byte(StoreKeyContracts)) + store := prefix.NewStore(ctx.KVStore(k.storeKey), StoreKeyContracts) fpc.WalletLimit = walletLimit store.Set([]byte(fpc.ContractAddress), k.cdc.MustMarshal(fpc)) diff --git a/x/feepay/keeper/grpc_query.go b/x/feepay/keeper/grpc_query.go index 13b60a18b..af94021e6 100644 --- a/x/feepay/keeper/grpc_query.go +++ b/x/feepay/keeper/grpc_query.go @@ -41,7 +41,7 @@ func (q Querier) FeePayContracts(ctx context.Context, req *types.QueryFeePayCont sdkCtx := sdk.UnwrapSDKContext(ctx) - res, err := q.Keeper.GetAllContracts(sdkCtx, req.Pagination) + res, err := q.Keeper.GetContracts(sdkCtx, req.Pagination) if err != nil { return nil, err @@ -102,3 +102,13 @@ func (q Querier) FeePayWalletIsEligible(ctx context.Context, req *types.QueryFee Eligible: isEligible, }, err } + +// Params returns the feepay module params +func (q Querier) Params( + c context.Context, + _ *types.QueryParamsRequest, +) (*types.QueryParamsResponse, error) { + ctx := sdk.UnwrapSDKContext(c) + params := q.GetParams(ctx) + return &types.QueryParamsResponse{Params: params}, nil +} diff --git a/x/feepay/keeper/keeper.go b/x/feepay/keeper/keeper.go index 912307110..25d08518d 100644 --- a/x/feepay/keeper/keeper.go +++ b/x/feepay/keeper/keeper.go @@ -16,9 +16,9 @@ import ( bankkeeper "github.com/cosmos/cosmos-sdk/x/bank/keeper" ) -const ( - StoreKeyContracts = "contracts" - StoreKeyContractUses = "contract-uses" +var ( + StoreKeyContracts = []byte("contracts") + StoreKeyContractUses = []byte("contract-uses") ) // Keeper of this module maintains collections of feeshares for contracts diff --git a/x/feepay/keeper/params.go b/x/feepay/keeper/params.go index 91fe928d4..235d759af 100644 --- a/x/feepay/keeper/params.go +++ b/x/feepay/keeper/params.go @@ -6,27 +6,22 @@ import ( "github.com/CosmosContracts/juno/v17/x/feepay/types" ) -// GetParams returns the total set of fees parameters. +// Get the parameters for the fee pay module. func (k Keeper) GetParams(ctx sdk.Context) (p types.Params) { - // set to nil? add a ParamsKey which is a 0x00 value. Maybe a bool for enable and disable (set in .proto file genesis.proto (kill switch)) - // store := ctx.KVStore(k.storeKey) - // bz := store.Get(types.ParamsKey) - // if bz == nil { - // return p - // } + store := ctx.KVStore(k.storeKey) + bz := store.Get(types.ParamsKey) + if bz == nil { + return p + } - // k.cdc.MustUnmarshal(bz, &p) + k.cdc.MustUnmarshal(bz, &p) return p } -// SetParams sets the fees parameters to the param space. +// Set the params for the fee pay module. func (k Keeper) SetParams(ctx sdk.Context, p types.Params) error { - // if err := p.Validate(); err != nil { - // return err - // } - - // store := ctx.KVStore(k.storeKey) - // bz := k.cdc.MustMarshal(&p) - // store.Set(types.ParamsKey, bz) + store := ctx.KVStore(k.storeKey) + bz := k.cdc.MustMarshal(&p) + store.Set(types.ParamsKey, bz) return nil } diff --git a/x/feepay/module.go b/x/feepay/module.go index 2e80f8630..4b9c51fc5 100644 --- a/x/feepay/module.go +++ b/x/feepay/module.go @@ -157,7 +157,6 @@ func (am AppModule) EndBlock(_ sdk.Context, _ abci.RequestEndBlock) []abci.Valid // no validator updates. func (am AppModule) InitGenesis(ctx sdk.Context, cdc codec.JSONCodec, data json.RawMessage) []abci.ValidatorUpdate { var genesisState types.GenesisState - cdc.MustUnmarshalJSON(data, &genesisState) InitGenesis(ctx, am.keeper, genesisState) return []abci.ValidatorUpdate{} diff --git a/x/feepay/types/constants.go b/x/feepay/types/constants.go index 40fc2dc13..86a05b49a 100644 --- a/x/feepay/types/constants.go +++ b/x/feepay/types/constants.go @@ -1,5 +1,9 @@ package types +const ( + prefixParamsKey = iota + 1 +) + const ( // module name ModuleName = "feepay" @@ -10,3 +14,7 @@ const ( // RouterKey to be used for message routing RouterKey = ModuleName ) + +var ( + ParamsKey = []byte{prefixParamsKey} +) diff --git a/x/feepay/types/genesis.go b/x/feepay/types/genesis.go index 2e539e9b3..23c9e7d80 100644 --- a/x/feepay/types/genesis.go +++ b/x/feepay/types/genesis.go @@ -8,10 +8,15 @@ func NewGenesisState(params Params, feecontract []FeePayContract) GenesisState { } } -// DefaultGenesisState sets default evm genesis state with empty accounts and +// DefaultGenesisState sets default genesis state with empty accounts and // default params and chain config values. func DefaultGenesisState() *GenesisState { - return &GenesisState{} + return &GenesisState{ + Params: Params{ + EnableFeepay: true, + }, + FeeContract: []FeePayContract{}, + } } // Validate performs basic genesis state validation returning an error upon any diff --git a/x/feepay/types/genesis.pb.go b/x/feepay/types/genesis.pb.go index 3caef7ab9..ab99c7416 100644 --- a/x/feepay/types/genesis.pb.go +++ b/x/feepay/types/genesis.pb.go @@ -25,7 +25,7 @@ const _ = proto.GoGoProtoPackageIsVersion3 // please upgrade the proto package // GenesisState defines the module's genesis state. type GenesisState struct { - // params are the feeshare module parameters + // params are the feepay module parameters Params Params `protobuf:"bytes,1,opt,name=params,proto3" json:"params"` FeeContract []FeePayContract `protobuf:"bytes,2,rep,name=fee_contract,json=feeContract,proto3" json:"fee_contract"` } @@ -77,8 +77,10 @@ func (m *GenesisState) GetFeeContract() []FeePayContract { return nil } -// Params defines the feeshare module params +// Params defines the feepay module params type Params struct { + // enable_feepay defines a parameter to enable the feepay module + EnableFeepay bool `protobuf:"varint,1,opt,name=enable_feepay,json=enableFeepay,proto3" json:"enable_feepay,omitempty"` } func (m *Params) Reset() { *m = Params{} } @@ -114,6 +116,13 @@ func (m *Params) XXX_DiscardUnknown() { var xxx_messageInfo_Params proto.InternalMessageInfo +func (m *Params) GetEnableFeepay() bool { + if m != nil { + return m.EnableFeepay + } + return false +} + func init() { proto.RegisterType((*GenesisState)(nil), "juno.feepay.v1.GenesisState") proto.RegisterType((*Params)(nil), "juno.feepay.v1.Params") @@ -122,7 +131,7 @@ func init() { func init() { proto.RegisterFile("juno/feepay/v1/genesis.proto", fileDescriptor_ac1bd21601b5f553) } var fileDescriptor_ac1bd21601b5f553 = []byte{ - // 246 bytes of a gzipped FileDescriptorProto + // 271 bytes of a gzipped FileDescriptorProto 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xe2, 0x92, 0xc9, 0x2a, 0xcd, 0xcb, 0xd7, 0x4f, 0x4b, 0x4d, 0x2d, 0x48, 0xac, 0xd4, 0x2f, 0x33, 0xd4, 0x4f, 0x4f, 0xcd, 0x4b, 0x2d, 0xce, 0x2c, 0xd6, 0x2b, 0x28, 0xca, 0x2f, 0xc9, 0x17, 0xe2, 0x03, 0xc9, 0xea, 0x41, 0x64, 0xf5, @@ -133,12 +142,13 @@ var fileDescriptor_ac1bd21601b5f553 = []byte{ 0x7b, 0xf2, 0x0c, 0x41, 0x50, 0xb5, 0x42, 0xee, 0x5c, 0x3c, 0x69, 0xa9, 0xa9, 0xf1, 0xc9, 0xf9, 0x79, 0x25, 0x45, 0x89, 0xc9, 0x25, 0x12, 0x4c, 0x0a, 0xcc, 0x1a, 0xdc, 0x46, 0x72, 0xe8, 0x7a, 0xdd, 0x52, 0x53, 0x03, 0x12, 0x2b, 0x9d, 0xa1, 0xaa, 0xa0, 0x66, 0x70, 0xa7, 0xa5, 0xa6, 0xc2, - 0x84, 0x94, 0x38, 0xb8, 0xd8, 0xa0, 0x16, 0x78, 0x9c, 0x78, 0x24, 0xc7, 0x78, 0xe1, 0x91, 0x1c, - 0xe3, 0x83, 0x47, 0x72, 0x8c, 0x13, 0x1e, 0xcb, 0x31, 0x5c, 0x78, 0x2c, 0xc7, 0x70, 0xe3, 0xb1, - 0x1c, 0x43, 0x94, 0x5e, 0x7a, 0x66, 0x49, 0x46, 0x69, 0x92, 0x5e, 0x72, 0x7e, 0xae, 0xbe, 0x73, - 0x7e, 0x71, 0x6e, 0x7e, 0x31, 0x4c, 0x7b, 0xb1, 0x3e, 0x38, 0x04, 0x2a, 0x60, 0x61, 0x50, 0x52, - 0x59, 0x90, 0x5a, 0x9c, 0xc4, 0x06, 0xf6, 0xaa, 0x31, 0x20, 0x00, 0x00, 0xff, 0xff, 0xc2, 0xf7, - 0x70, 0x02, 0x4d, 0x01, 0x00, 0x00, + 0x84, 0x94, 0x74, 0xb9, 0xd8, 0x20, 0x16, 0x08, 0x29, 0x73, 0xf1, 0xa6, 0xe6, 0x25, 0x26, 0xe5, + 0xa4, 0xc6, 0x43, 0xf4, 0x83, 0xdd, 0xc3, 0x11, 0xc4, 0x03, 0x11, 0x74, 0x03, 0x8b, 0x39, 0x79, + 0x9c, 0x78, 0x24, 0xc7, 0x78, 0xe1, 0x91, 0x1c, 0xe3, 0x83, 0x47, 0x72, 0x8c, 0x13, 0x1e, 0xcb, + 0x31, 0x5c, 0x78, 0x2c, 0xc7, 0x70, 0xe3, 0xb1, 0x1c, 0x43, 0x94, 0x5e, 0x7a, 0x66, 0x49, 0x46, + 0x69, 0x92, 0x5e, 0x72, 0x7e, 0xae, 0xbe, 0x73, 0x7e, 0x71, 0x6e, 0x7e, 0x31, 0xcc, 0x8e, 0x62, + 0x7d, 0x70, 0x30, 0x55, 0xc0, 0x02, 0xaa, 0xa4, 0xb2, 0x20, 0xb5, 0x38, 0x89, 0x0d, 0x1c, 0x1e, + 0xc6, 0x80, 0x00, 0x00, 0x00, 0xff, 0xff, 0x35, 0xf0, 0xde, 0xa1, 0x72, 0x01, 0x00, 0x00, } func (m *GenesisState) Marshal() (dAtA []byte, err error) { @@ -208,6 +218,16 @@ func (m *Params) MarshalToSizedBuffer(dAtA []byte) (int, error) { _ = i var l int _ = l + if m.EnableFeepay { + i-- + if m.EnableFeepay { + dAtA[i] = 1 + } else { + dAtA[i] = 0 + } + i-- + dAtA[i] = 0x8 + } return len(dAtA) - i, nil } @@ -245,6 +265,9 @@ func (m *Params) Size() (n int) { } var l int _ = l + if m.EnableFeepay { + n += 2 + } return n } @@ -400,6 +423,26 @@ func (m *Params) Unmarshal(dAtA []byte) error { return fmt.Errorf("proto: Params: illegal tag %d (wire type %d)", fieldNum, wire) } switch fieldNum { + case 1: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field EnableFeepay", wireType) + } + var v int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowGenesis + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + v |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + m.EnableFeepay = bool(v != 0) default: iNdEx = preIndex skippy, err := skipGenesis(dAtA[iNdEx:]) diff --git a/x/feepay/types/query.pb.go b/x/feepay/types/query.pb.go index 0c1e049e5..88edc0843 100644 --- a/x/feepay/types/query.pb.go +++ b/x/feepay/types/query.pb.go @@ -425,6 +425,89 @@ func (m *QueryFeePayWalletIsEligibleResponse) GetEligible() bool { return false } +// QueryParamsRequest is the request type for the Query/Params RPC method. +type QueryParamsRequest struct { +} + +func (m *QueryParamsRequest) Reset() { *m = QueryParamsRequest{} } +func (m *QueryParamsRequest) String() string { return proto.CompactTextString(m) } +func (*QueryParamsRequest) ProtoMessage() {} +func (*QueryParamsRequest) Descriptor() ([]byte, []int) { + return fileDescriptor_d6539df905bf35ca, []int{8} +} +func (m *QueryParamsRequest) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *QueryParamsRequest) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_QueryParamsRequest.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 *QueryParamsRequest) XXX_Merge(src proto.Message) { + xxx_messageInfo_QueryParamsRequest.Merge(m, src) +} +func (m *QueryParamsRequest) XXX_Size() int { + return m.Size() +} +func (m *QueryParamsRequest) XXX_DiscardUnknown() { + xxx_messageInfo_QueryParamsRequest.DiscardUnknown(m) +} + +var xxx_messageInfo_QueryParamsRequest proto.InternalMessageInfo + +// QueryParamsResponse is the response type for the Query/Params RPC method. +type QueryParamsResponse struct { + // params is the returned Feepay parameter + Params Params `protobuf:"bytes,1,opt,name=params,proto3" json:"params"` +} + +func (m *QueryParamsResponse) Reset() { *m = QueryParamsResponse{} } +func (m *QueryParamsResponse) String() string { return proto.CompactTextString(m) } +func (*QueryParamsResponse) ProtoMessage() {} +func (*QueryParamsResponse) Descriptor() ([]byte, []int) { + return fileDescriptor_d6539df905bf35ca, []int{9} +} +func (m *QueryParamsResponse) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *QueryParamsResponse) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_QueryParamsResponse.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 *QueryParamsResponse) XXX_Merge(src proto.Message) { + xxx_messageInfo_QueryParamsResponse.Merge(m, src) +} +func (m *QueryParamsResponse) XXX_Size() int { + return m.Size() +} +func (m *QueryParamsResponse) XXX_DiscardUnknown() { + xxx_messageInfo_QueryParamsResponse.DiscardUnknown(m) +} + +var xxx_messageInfo_QueryParamsResponse proto.InternalMessageInfo + +func (m *QueryParamsResponse) GetParams() Params { + if m != nil { + return m.Params + } + return Params{} +} + func init() { proto.RegisterType((*QueryFeePayContract)(nil), "juno.feepay.v1.QueryFeePayContract") proto.RegisterType((*QueryFeePayContractResponse)(nil), "juno.feepay.v1.QueryFeePayContractResponse") @@ -434,51 +517,56 @@ func init() { proto.RegisterType((*QueryFeePayContractUsesResponse)(nil), "juno.feepay.v1.QueryFeePayContractUsesResponse") proto.RegisterType((*QueryFeePayWalletIsEligible)(nil), "juno.feepay.v1.QueryFeePayWalletIsEligible") proto.RegisterType((*QueryFeePayWalletIsEligibleResponse)(nil), "juno.feepay.v1.QueryFeePayWalletIsEligibleResponse") + proto.RegisterType((*QueryParamsRequest)(nil), "juno.feepay.v1.QueryParamsRequest") + proto.RegisterType((*QueryParamsResponse)(nil), "juno.feepay.v1.QueryParamsResponse") } func init() { proto.RegisterFile("juno/feepay/v1/query.proto", fileDescriptor_d6539df905bf35ca) } var fileDescriptor_d6539df905bf35ca = []byte{ - // 613 bytes of a gzipped FileDescriptorProto - 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xb4, 0x55, 0x4f, 0x6f, 0xd3, 0x30, - 0x1c, 0x6d, 0x4a, 0x87, 0x86, 0x11, 0xed, 0x30, 0xd3, 0x98, 0xb2, 0x29, 0x43, 0x19, 0x30, 0xc6, - 0x90, 0xad, 0x6e, 0xe2, 0x0c, 0x5d, 0xb5, 0x3f, 0x88, 0x4b, 0x89, 0x84, 0x90, 0x38, 0x50, 0xb9, - 0xdd, 0xaf, 0x21, 0xd0, 0xc5, 0x59, 0x9d, 0x16, 0xaa, 0x69, 0x17, 0x24, 0xee, 0x48, 0x88, 0x4f, - 0xc1, 0x07, 0x40, 0x7c, 0x02, 0x76, 0x9c, 0xc4, 0x85, 0x13, 0x42, 0x2d, 0x1f, 0x04, 0xc5, 0x4e, - 0x32, 0x12, 0xb2, 0x2d, 0x3b, 0x70, 0x73, 0xec, 0xe7, 0xf7, 0xde, 0xef, 0xfd, 0x7e, 0x6e, 0x91, - 0xfe, 0xaa, 0xef, 0x72, 0xda, 0x01, 0xf0, 0xd8, 0x90, 0x0e, 0xaa, 0x74, 0xaf, 0x0f, 0xbd, 0x21, - 0xf1, 0x7a, 0xdc, 0xe7, 0xb8, 0x1c, 0x9c, 0x11, 0x75, 0x46, 0x06, 0x55, 0xfd, 0x6e, 0x9b, 0x8b, - 0x5d, 0x2e, 0x68, 0x8b, 0x09, 0x50, 0x40, 0x3a, 0xa8, 0xb6, 0xc0, 0x67, 0x55, 0xea, 0x31, 0xdb, - 0x71, 0x99, 0xef, 0x70, 0x57, 0xdd, 0xd5, 0xe7, 0x53, 0xbc, 0x36, 0xb8, 0x20, 0x1c, 0x11, 0x9e, - 0xce, 0xa5, 0x4e, 0x43, 0x0d, 0x75, 0x38, 0x6d, 0x73, 0x9b, 0xcb, 0x25, 0x0d, 0x56, 0x11, 0xa1, - 0xcd, 0xb9, 0xdd, 0x05, 0xca, 0x3c, 0x87, 0x32, 0xd7, 0xe5, 0xbe, 0x54, 0x0b, 0x09, 0xcd, 0x87, - 0xe8, 0xda, 0x93, 0xc0, 0xd0, 0x26, 0x40, 0x83, 0x0d, 0xeb, 0xdc, 0xf5, 0x7b, 0xac, 0xed, 0xe3, - 0x65, 0x34, 0xd5, 0x0e, 0xd7, 0x4d, 0xb6, 0xb3, 0xd3, 0x03, 0x21, 0x66, 0xb5, 0x1b, 0xda, 0x9d, - 0x4b, 0x56, 0x25, 0xda, 0xaf, 0xa9, 0x6d, 0xd3, 0x46, 0x73, 0x19, 0x0c, 0x16, 0x08, 0x8f, 0xbb, - 0x02, 0xf0, 0x36, 0x9a, 0xea, 0x00, 0x34, 0x3d, 0x36, 0x6c, 0x46, 0x37, 0x25, 0xd3, 0xe5, 0x55, - 0x83, 0x24, 0x63, 0x22, 0x29, 0x86, 0x72, 0x27, 0xf1, 0x6d, 0xbe, 0x40, 0xd3, 0x19, 0x42, 0x02, - 0x6f, 0x22, 0x74, 0x9c, 0x62, 0xc8, 0x7d, 0x9b, 0xa8, 0xc8, 0x49, 0x10, 0x39, 0x51, 0xbd, 0x09, - 0x23, 0x27, 0x0d, 0x66, 0x83, 0x05, 0x7b, 0x7d, 0x10, 0xbe, 0xf5, 0xd7, 0x4d, 0xf3, 0xab, 0x86, - 0xe6, 0xb3, 0x04, 0xe2, 0x52, 0x1a, 0xe8, 0x6a, 0xba, 0x94, 0x20, 0x95, 0x0b, 0x67, 0xd7, 0xb2, - 0x5e, 0x3a, 0xfc, 0xb9, 0x50, 0xb0, 0x2a, 0x9d, 0x94, 0xf5, 0xad, 0x84, 0xf5, 0xa2, 0xb4, 0xbe, - 0x74, 0xa6, 0x75, 0x65, 0x27, 0xe1, 0xfd, 0x35, 0xba, 0x9e, 0x61, 0xfd, 0xa9, 0x00, 0x71, 0x8e, - 0x56, 0xe2, 0x5b, 0xa8, 0xfc, 0x86, 0x75, 0xbb, 0x70, 0x0c, 0x2c, 0x4a, 0xe0, 0x15, 0xb5, 0x1b, - 0x75, 0xfc, 0x3e, 0x5a, 0x38, 0x41, 0x2c, 0x8e, 0x0a, 0xa3, 0x52, 0x5f, 0x80, 0x12, 0x2a, 0x59, - 0x72, 0x6d, 0xf2, 0xc4, 0xa0, 0x3c, 0x93, 0x94, 0x8f, 0xc4, 0x46, 0xd7, 0xb1, 0x9d, 0x56, 0x17, - 0xfe, 0x83, 0xcf, 0x1a, 0x5a, 0x3c, 0x45, 0x30, 0xf6, 0xaa, 0xa3, 0x49, 0x08, 0xf7, 0xa4, 0xe0, - 0xa4, 0x15, 0x7f, 0xaf, 0x7e, 0x9e, 0x40, 0x13, 0x92, 0x03, 0x7f, 0xd2, 0x50, 0x39, 0xf5, 0x48, - 0x16, 0xd3, 0x4d, 0xcf, 0x48, 0x45, 0x5f, 0xc9, 0x01, 0x8a, 0xac, 0x98, 0xd5, 0x77, 0xdf, 0x7f, - 0x7f, 0x2c, 0xae, 0xe0, 0x65, 0x9a, 0xf9, 0xce, 0xe9, 0x7e, 0x3a, 0xa1, 0x03, 0xfc, 0x5e, 0x43, - 0x95, 0xf4, 0x8b, 0xb8, 0x99, 0x43, 0x53, 0xe8, 0xf7, 0xf2, 0xa0, 0x62, 0x6b, 0x86, 0xb4, 0x36, - 0x8b, 0x67, 0xb2, 0xad, 0xe1, 0x2f, 0x1a, 0xc2, 0x19, 0xd3, 0xb7, 0x94, 0x43, 0x24, 0x00, 0xea, - 0x34, 0x27, 0x30, 0x36, 0xb4, 0x25, 0x0d, 0xd5, 0xf0, 0x83, 0xdc, 0x59, 0xd1, 0x60, 0x0c, 0xe9, - 0x7e, 0x72, 0x74, 0x0e, 0xf0, 0x37, 0x0d, 0xcd, 0x9c, 0x30, 0x93, 0xa7, 0x35, 0x2f, 0x0d, 0xd6, - 0xd7, 0xce, 0x01, 0x8e, 0xab, 0x78, 0x2c, 0xab, 0xd8, 0xc0, 0xf5, 0xfc, 0x55, 0x44, 0xc3, 0xf9, - 0x4f, 0x25, 0xeb, 0xdb, 0x87, 0x23, 0x43, 0x3b, 0x1a, 0x19, 0xda, 0xaf, 0x91, 0xa1, 0x7d, 0x18, - 0x1b, 0x85, 0xa3, 0xb1, 0x51, 0xf8, 0x31, 0x36, 0x0a, 0xcf, 0x89, 0xed, 0xf8, 0x2f, 0xfb, 0x2d, - 0xd2, 0xe6, 0xbb, 0xb4, 0x2e, 0x7f, 0x5e, 0xe2, 0x0e, 0x2b, 0xe1, 0xb7, 0x91, 0xa0, 0x3f, 0xf4, - 0x40, 0xb4, 0x2e, 0xca, 0x7f, 0x87, 0xb5, 0x3f, 0x01, 0x00, 0x00, 0xff, 0xff, 0xc4, 0xa3, 0x66, - 0xda, 0xe6, 0x06, 0x00, 0x00, + // 666 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xb4, 0x55, 0x4d, 0x6f, 0xd3, 0x40, + 0x10, 0x8d, 0x4b, 0x89, 0xca, 0x22, 0xd2, 0xb2, 0x54, 0xa5, 0x72, 0x2b, 0x17, 0xb9, 0x40, 0x29, + 0x45, 0x5e, 0xa5, 0x85, 0x33, 0xb4, 0x55, 0x3f, 0x50, 0x2f, 0xc1, 0x12, 0x42, 0xe2, 0x40, 0xb5, + 0x49, 0x27, 0xc6, 0x90, 0x78, 0x9d, 0xac, 0x13, 0x88, 0xaa, 0x5e, 0x90, 0xb8, 0x23, 0x21, 0xae, + 0xfc, 0x0d, 0xc4, 0x2f, 0xa0, 0xc7, 0x4a, 0x5c, 0x38, 0x21, 0x94, 0xf0, 0x43, 0x90, 0x77, 0xd7, + 0x2e, 0x36, 0x6e, 0xe2, 0x1e, 0xb8, 0x6d, 0x66, 0xdf, 0xbe, 0x79, 0x33, 0xf3, 0xc6, 0x41, 0xfa, + 0xab, 0x8e, 0xc7, 0x48, 0x1d, 0xc0, 0xa7, 0x3d, 0xd2, 0x2d, 0x93, 0x56, 0x07, 0xda, 0x3d, 0xcb, + 0x6f, 0xb3, 0x80, 0xe1, 0x52, 0x78, 0x67, 0xc9, 0x3b, 0xab, 0x5b, 0xd6, 0xef, 0xd6, 0x18, 0x6f, + 0x32, 0x4e, 0xaa, 0x94, 0x83, 0x04, 0x92, 0x6e, 0xb9, 0x0a, 0x01, 0x2d, 0x13, 0x9f, 0x3a, 0xae, + 0x47, 0x03, 0x97, 0x79, 0xf2, 0xad, 0x3e, 0x9f, 0xe2, 0x75, 0xc0, 0x03, 0xee, 0x72, 0x75, 0x3b, + 0x97, 0xba, 0x55, 0x39, 0xe4, 0xe5, 0xb4, 0xc3, 0x1c, 0x26, 0x8e, 0x24, 0x3c, 0x45, 0x84, 0x0e, + 0x63, 0x4e, 0x03, 0x08, 0xf5, 0x5d, 0x42, 0x3d, 0x8f, 0x05, 0x22, 0x9b, 0x22, 0x34, 0x1f, 0xa1, + 0x6b, 0x4f, 0x42, 0x41, 0xdb, 0x00, 0x15, 0xda, 0xdb, 0x64, 0x5e, 0xd0, 0xa6, 0xb5, 0x00, 0x2f, + 0xa3, 0xa9, 0x9a, 0x3a, 0xef, 0xd3, 0x83, 0x83, 0x36, 0x70, 0x3e, 0xab, 0xdd, 0xd0, 0xee, 0x5c, + 0xb2, 0x27, 0xa3, 0xf8, 0xba, 0x0c, 0x9b, 0x0e, 0x9a, 0xcb, 0x60, 0xb0, 0x81, 0xfb, 0xcc, 0xe3, + 0x80, 0x77, 0xd1, 0x54, 0x1d, 0x60, 0xdf, 0xa7, 0xbd, 0xfd, 0xe8, 0xa5, 0x60, 0xba, 0xbc, 0x6a, + 0x58, 0xc9, 0x36, 0x59, 0x29, 0x86, 0x52, 0x3d, 0xf1, 0xdb, 0x7c, 0x81, 0xa6, 0x33, 0x12, 0x71, + 0xbc, 0x8d, 0xd0, 0x69, 0x17, 0x15, 0xf7, 0x6d, 0x4b, 0xb6, 0xdc, 0x0a, 0x5b, 0x6e, 0xc9, 0xd9, + 0xa8, 0x96, 0x5b, 0x15, 0xea, 0x80, 0x0d, 0xad, 0x0e, 0xf0, 0xc0, 0xfe, 0xeb, 0xa5, 0xf9, 0x55, + 0x43, 0xf3, 0x59, 0x09, 0xe2, 0x52, 0x2a, 0xe8, 0x6a, 0xba, 0x94, 0xb0, 0x2b, 0x17, 0x46, 0xd7, + 0xb2, 0x31, 0x7e, 0xfc, 0x73, 0xa1, 0x60, 0x4f, 0xd6, 0x53, 0xd2, 0x77, 0x12, 0xd2, 0xc7, 0x84, + 0xf4, 0xa5, 0x91, 0xd2, 0xa5, 0x9c, 0x84, 0xf6, 0xd7, 0xe8, 0x7a, 0x86, 0xf4, 0xa7, 0x1c, 0xf8, + 0x39, 0x46, 0x89, 0x6f, 0xa1, 0xd2, 0x1b, 0xda, 0x68, 0xc0, 0x29, 0x70, 0x4c, 0x00, 0xaf, 0xc8, + 0x68, 0x34, 0xf1, 0x07, 0x68, 0xe1, 0x8c, 0x64, 0x71, 0xab, 0x30, 0x1a, 0xef, 0x70, 0x90, 0x89, + 0xc6, 0x6d, 0x71, 0x36, 0x59, 0xc2, 0x28, 0xcf, 0x04, 0xe5, 0x63, 0xbe, 0xd5, 0x70, 0x1d, 0xb7, + 0xda, 0x80, 0xff, 0xa0, 0x73, 0x1d, 0x2d, 0x0e, 0x49, 0x18, 0x6b, 0xd5, 0xd1, 0x04, 0xa8, 0x98, + 0x48, 0x38, 0x61, 0xc7, 0xbf, 0xcd, 0x69, 0x84, 0x05, 0x45, 0x85, 0xb6, 0x69, 0x93, 0x2b, 0xd7, + 0x98, 0x7b, 0x6a, 0x69, 0xa2, 0xa8, 0x22, 0xba, 0x8f, 0x8a, 0xbe, 0x88, 0x28, 0x13, 0xce, 0xa4, + 0x4d, 0x21, 0xf1, 0xca, 0x0c, 0x0a, 0xbb, 0xfa, 0xb9, 0x88, 0x2e, 0x0a, 0x36, 0xfc, 0x49, 0x43, + 0xa5, 0xd4, 0x1e, 0x2e, 0xa6, 0x29, 0x32, 0x1a, 0xaf, 0xaf, 0xe4, 0x00, 0x45, 0x22, 0xcd, 0xf2, + 0xbb, 0xef, 0xbf, 0x3f, 0x8e, 0xad, 0xe0, 0x65, 0x92, 0xf9, 0x29, 0x21, 0x87, 0xe9, 0x21, 0x1c, + 0xe1, 0xf7, 0x1a, 0x9a, 0x4c, 0x2f, 0xdd, 0xcd, 0x1c, 0x39, 0xb9, 0x7e, 0x2f, 0x0f, 0x2a, 0x96, + 0x66, 0x08, 0x69, 0xb3, 0x78, 0x26, 0x5b, 0x1a, 0xfe, 0xa2, 0x21, 0x9c, 0x61, 0xf0, 0xa5, 0x1c, + 0x49, 0x42, 0xa0, 0x4e, 0x72, 0x02, 0x63, 0x41, 0x3b, 0x42, 0xd0, 0x3a, 0x7e, 0x98, 0xbb, 0x57, + 0x24, 0x74, 0x3a, 0x39, 0x4c, 0xba, 0xf3, 0x08, 0x7f, 0xd3, 0xd0, 0xcc, 0x19, 0xb6, 0x1f, 0x36, + 0xbc, 0x34, 0x58, 0x5f, 0x3b, 0x07, 0x38, 0xae, 0x62, 0x4f, 0x54, 0xb1, 0x85, 0x37, 0xf3, 0x57, + 0x11, 0xf9, 0xff, 0xdf, 0x4a, 0x5a, 0xa8, 0x28, 0x5d, 0x8c, 0xcd, 0x4c, 0x2d, 0x89, 0x45, 0xd1, + 0x17, 0x87, 0x62, 0x46, 0x8d, 0x5d, 0x2e, 0xc8, 0xc6, 0xee, 0x71, 0xdf, 0xd0, 0x4e, 0xfa, 0x86, + 0xf6, 0xab, 0x6f, 0x68, 0x1f, 0x06, 0x46, 0xe1, 0x64, 0x60, 0x14, 0x7e, 0x0c, 0x8c, 0xc2, 0x73, + 0xcb, 0x71, 0x83, 0x97, 0x9d, 0xaa, 0x55, 0x63, 0x4d, 0xb2, 0x29, 0x3e, 0x9a, 0xb1, 0xa9, 0x24, + 0xd7, 0xdb, 0x88, 0x2d, 0xe8, 0xf9, 0xc0, 0xab, 0x45, 0xf1, 0x9f, 0xb7, 0xf6, 0x27, 0x00, 0x00, + 0xff, 0xff, 0x97, 0xc0, 0x24, 0x4b, 0xbc, 0x07, 0x00, 0x00, } // Reference imports to suppress errors if they are not otherwise used. @@ -501,6 +589,8 @@ type QueryClient interface { FeePayContractUses(ctx context.Context, in *QueryFeePayContractUses, opts ...grpc.CallOption) (*QueryFeePayContractUsesResponse, error) // Query if sender is eligible for fee pay contract interaction FeePayWalletIsEligible(ctx context.Context, in *QueryFeePayWalletIsEligible, opts ...grpc.CallOption) (*QueryFeePayWalletIsEligibleResponse, error) + // Params retrieves the FeePay module params + Params(ctx context.Context, in *QueryParamsRequest, opts ...grpc.CallOption) (*QueryParamsResponse, error) } type queryClient struct { @@ -547,6 +637,15 @@ func (c *queryClient) FeePayWalletIsEligible(ctx context.Context, in *QueryFeePa return out, nil } +func (c *queryClient) Params(ctx context.Context, in *QueryParamsRequest, opts ...grpc.CallOption) (*QueryParamsResponse, error) { + out := new(QueryParamsResponse) + err := c.cc.Invoke(ctx, "/juno.feepay.v1.Query/Params", in, out, opts...) + if err != nil { + return nil, err + } + return out, nil +} + // QueryServer is the server API for Query service. type QueryServer interface { // FeePayContract queries a single fee pay contract by address @@ -557,6 +656,8 @@ type QueryServer interface { FeePayContractUses(context.Context, *QueryFeePayContractUses) (*QueryFeePayContractUsesResponse, error) // Query if sender is eligible for fee pay contract interaction FeePayWalletIsEligible(context.Context, *QueryFeePayWalletIsEligible) (*QueryFeePayWalletIsEligibleResponse, error) + // Params retrieves the FeePay module params + Params(context.Context, *QueryParamsRequest) (*QueryParamsResponse, error) } // UnimplementedQueryServer can be embedded to have forward compatible implementations. @@ -575,6 +676,9 @@ func (*UnimplementedQueryServer) FeePayContractUses(ctx context.Context, req *Qu func (*UnimplementedQueryServer) FeePayWalletIsEligible(ctx context.Context, req *QueryFeePayWalletIsEligible) (*QueryFeePayWalletIsEligibleResponse, error) { return nil, status.Errorf(codes.Unimplemented, "method FeePayWalletIsEligible not implemented") } +func (*UnimplementedQueryServer) Params(ctx context.Context, req *QueryParamsRequest) (*QueryParamsResponse, error) { + return nil, status.Errorf(codes.Unimplemented, "method Params not implemented") +} func RegisterQueryServer(s grpc1.Server, srv QueryServer) { s.RegisterService(&_Query_serviceDesc, srv) @@ -652,6 +756,24 @@ func _Query_FeePayWalletIsEligible_Handler(srv interface{}, ctx context.Context, return interceptor(ctx, in, info, handler) } +func _Query_Params_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(QueryParamsRequest) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(QueryServer).Params(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: "/juno.feepay.v1.Query/Params", + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(QueryServer).Params(ctx, req.(*QueryParamsRequest)) + } + return interceptor(ctx, in, info, handler) +} + var _Query_serviceDesc = grpc.ServiceDesc{ ServiceName: "juno.feepay.v1.Query", HandlerType: (*QueryServer)(nil), @@ -672,6 +794,10 @@ var _Query_serviceDesc = grpc.ServiceDesc{ MethodName: "FeePayWalletIsEligible", Handler: _Query_FeePayWalletIsEligible_Handler, }, + { + MethodName: "Params", + Handler: _Query_Params_Handler, + }, }, Streams: []grpc.StreamDesc{}, Metadata: "juno/feepay/v1/query.proto", @@ -961,6 +1087,62 @@ func (m *QueryFeePayWalletIsEligibleResponse) MarshalToSizedBuffer(dAtA []byte) return len(dAtA) - i, nil } +func (m *QueryParamsRequest) 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 *QueryParamsRequest) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *QueryParamsRequest) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + return len(dAtA) - i, nil +} + +func (m *QueryParamsResponse) 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 *QueryParamsResponse) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *QueryParamsResponse) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + { + size, err := m.Params.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 encodeVarintQuery(dAtA []byte, offset int, v uint64) int { offset -= sovQuery(v) base := offset @@ -1088,6 +1270,26 @@ func (m *QueryFeePayWalletIsEligibleResponse) Size() (n int) { return n } +func (m *QueryParamsRequest) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + return n +} + +func (m *QueryParamsResponse) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + l = m.Params.Size() + n += 1 + l + sovQuery(uint64(l)) + return n +} + func sovQuery(x uint64) (n int) { return (math_bits.Len64(x|1) + 6) / 7 } @@ -1835,6 +2037,139 @@ func (m *QueryFeePayWalletIsEligibleResponse) Unmarshal(dAtA []byte) error { } return nil } +func (m *QueryParamsRequest) 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: QueryParamsRequest: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: QueryParamsRequest: 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 *QueryParamsResponse) 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: QueryParamsResponse: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: QueryParamsResponse: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Params", 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 err := m.Params.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 skipQuery(dAtA []byte) (n int, err error) { l := len(dAtA) iNdEx := 0 diff --git a/x/feepay/types/query.pb.gw.go b/x/feepay/types/query.pb.gw.go index dd1b8703e..91c1f358e 100644 --- a/x/feepay/types/query.pb.gw.go +++ b/x/feepay/types/query.pb.gw.go @@ -275,6 +275,24 @@ func local_request_Query_FeePayWalletIsEligible_0(ctx context.Context, marshaler } +func request_Query_Params_0(ctx context.Context, marshaler runtime.Marshaler, client QueryClient, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) { + var protoReq QueryParamsRequest + var metadata runtime.ServerMetadata + + msg, err := client.Params(ctx, &protoReq, grpc.Header(&metadata.HeaderMD), grpc.Trailer(&metadata.TrailerMD)) + return msg, metadata, err + +} + +func local_request_Query_Params_0(ctx context.Context, marshaler runtime.Marshaler, server QueryServer, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) { + var protoReq QueryParamsRequest + var metadata runtime.ServerMetadata + + msg, err := server.Params(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. @@ -373,6 +391,29 @@ func RegisterQueryHandlerServer(ctx context.Context, mux *runtime.ServeMux, serv }) + mux.Handle("GET", pattern_Query_Params_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_Params_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_Params_0(ctx, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...) + + }) + return nil } @@ -494,6 +535,26 @@ func RegisterQueryHandlerClient(ctx context.Context, mux *runtime.ServeMux, clie }) + mux.Handle("GET", pattern_Query_Params_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_Params_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_Params_0(ctx, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...) + + }) + return nil } @@ -505,6 +566,8 @@ var ( pattern_Query_FeePayContractUses_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2, 2, 1, 1, 0, 4, 1, 5, 3, 2, 4, 1, 0, 4, 1, 5, 5}, []string{"juno", "feepay", "v1", "contract_address", "uses", "wallet_address"}, "", runtime.AssumeColonVerbOpt(false))) pattern_Query_FeePayWalletIsEligible_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2, 2, 1, 1, 0, 4, 1, 5, 3, 2, 4, 1, 0, 4, 1, 5, 5}, []string{"juno", "feepay", "v1", "contract_address", "eligible", "wallet_address"}, "", runtime.AssumeColonVerbOpt(false))) + + pattern_Query_Params_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2, 2, 3}, []string{"juno", "feepay", "v1", "params"}, "", runtime.AssumeColonVerbOpt(false))) ) var ( @@ -515,4 +578,6 @@ var ( forward_Query_FeePayContractUses_0 = runtime.ForwardResponseMessage forward_Query_FeePayWalletIsEligible_0 = runtime.ForwardResponseMessage + + forward_Query_Params_0 = runtime.ForwardResponseMessage ) From 5272da5439414c7739e397f3ba10e087da16344e Mon Sep 17 00:00:00 2001 From: Joel Smith Date: Thu, 21 Sep 2023 00:12:07 -0500 Subject: [PATCH 34/79] Prevent FeePay Tx in Ante when Disabled --- x/feepay/ante/deduct_fee.go | 6 ++++++ x/feepay/types/errors.go | 1 + 2 files changed, 7 insertions(+) diff --git a/x/feepay/ante/deduct_fee.go b/x/feepay/ante/deduct_fee.go index 9d9483b4d..810e56d98 100644 --- a/x/feepay/ante/deduct_fee.go +++ b/x/feepay/ante/deduct_fee.go @@ -148,6 +148,12 @@ func (dfd DeductFeeDecorator) checkDeductFee(ctx sdk.Context, sdkTx sdk.Tx, fee // Handle zero fee transactions for fee prepay module func (dfd DeductFeeDecorator) handleZeroFees(ctx sdk.Context, deductFeesFromAcc types.AccountI, tx sdk.Tx, fee sdk.Coins) error { + + // Prevent FeePay Tx from occuring when module is disabled + if !dfd.feepayKeeper.GetParams(ctx).EnableFeepay { + return feepaytypes.ErrFeePayDisabled + } + msg := tx.GetMsgs()[0] cw := msg.(*wasmtypes.MsgExecuteContract) diff --git a/x/feepay/types/errors.go b/x/feepay/types/errors.go index f29218251..87b0baa5b 100644 --- a/x/feepay/types/errors.go +++ b/x/feepay/types/errors.go @@ -16,4 +16,5 @@ var ( ErrInvalidJunoFundAmount = errorsmod.Register(ModuleName, 9, "fee pay contracts only accept juno funds") ErrInvalidAddress = errorsmod.Register(ModuleName, 10, "invalid bech32 address") ErrInvalidCWContract = errorsmod.Register(ModuleName, 11, "invalid CosmWasm contract") + ErrFeePayDisabled = errorsmod.Register(ModuleName, 12, "the FeePay module is disabled") ) From c08709f7d8bea64bcaaea698c02d4cd7077377e3 Mon Sep 17 00:00:00 2001 From: Reece Williams Date: Tue, 3 Oct 2023 18:37:36 -0500 Subject: [PATCH 35/79] add base test Co-authored-by: Joel Smith --- x/feepay/genesis_test.go | 3 + x/feepay/keeper/keeper_test.go | 117 +++++ x/feepay/keeper/msg_server_test.go | 432 ++++++++++++++++++ x/feepay/keeper/{grpc_query.go => querier.go} | 0 x/feepay/keeper/querier_test.go | 5 + x/feepay/keeper/testdata/clock_example.wasm | Bin 0 -> 141386 bytes 6 files changed, 557 insertions(+) create mode 100644 x/feepay/genesis_test.go create mode 100644 x/feepay/keeper/keeper_test.go create mode 100644 x/feepay/keeper/msg_server_test.go rename x/feepay/keeper/{grpc_query.go => querier.go} (100%) create mode 100644 x/feepay/keeper/querier_test.go create mode 100644 x/feepay/keeper/testdata/clock_example.wasm diff --git a/x/feepay/genesis_test.go b/x/feepay/genesis_test.go new file mode 100644 index 000000000..23d709624 --- /dev/null +++ b/x/feepay/genesis_test.go @@ -0,0 +1,3 @@ +package feepay_test + +// x/feeshare diff --git a/x/feepay/keeper/keeper_test.go b/x/feepay/keeper/keeper_test.go new file mode 100644 index 000000000..13c22c9a4 --- /dev/null +++ b/x/feepay/keeper/keeper_test.go @@ -0,0 +1,117 @@ +package keeper_test + +import ( + "crypto/sha256" + "testing" + "time" + + wasmkeeper "github.com/CosmWasm/wasmd/x/wasm/keeper" + wasmtypes "github.com/CosmWasm/wasmd/x/wasm/types" + bankkeeper "github.com/cosmos/cosmos-sdk/x/bank/keeper" + "github.com/stretchr/testify/suite" + + _ "embed" + + tmproto "github.com/cometbft/cometbft/proto/tendermint/types" + + "github.com/cosmos/cosmos-sdk/baseapp" + sdk "github.com/cosmos/cosmos-sdk/types" + minttypes "github.com/cosmos/cosmos-sdk/x/mint/types" + + "github.com/CosmosContracts/juno/v17/app" + "github.com/CosmosContracts/juno/v17/x/feepay/keeper" + "github.com/CosmosContracts/juno/v17/x/feepay/types" + "github.com/cosmos/cosmos-sdk/testutil/testdata" +) + +type IntegrationTestSuite struct { + suite.Suite + + ctx sdk.Context + app *app.App + bankKeeper bankkeeper.Keeper + queryClient types.QueryClient + msgServer types.MsgServer + wasmMsgServer wasmtypes.MsgServer +} + +func (s *IntegrationTestSuite) SetupTest() { + isCheckTx := false + s.app = app.Setup(s.T()) + + s.ctx = s.app.BaseApp.NewContext(isCheckTx, tmproto.Header{ + ChainID: "testing", + Height: 9, + Time: time.Now().UTC(), + }) + + queryHelper := baseapp.NewQueryServerTestHelper(s.ctx, s.app.InterfaceRegistry()) + types.RegisterQueryServer(queryHelper, keeper.NewQuerier(s.app.AppKeepers.FeePayKeeper)) + + s.queryClient = types.NewQueryClient(queryHelper) + s.bankKeeper = s.app.AppKeepers.BankKeeper + // s.accountKeeper = s.app.AppKeepers.AccountKeeper + s.msgServer = s.app.AppKeepers.FeePayKeeper + s.wasmMsgServer = wasmkeeper.NewMsgServerImpl(&s.app.AppKeepers.WasmKeeper) +} + +func (s *IntegrationTestSuite) FundAccount(ctx sdk.Context, addr sdk.AccAddress, amounts sdk.Coins) error { + if err := s.bankKeeper.MintCoins(ctx, minttypes.ModuleName, amounts); err != nil { + return err + } + + return s.bankKeeper.SendCoinsFromModuleToAccount(ctx, minttypes.ModuleName, addr, amounts) +} + +func TestKeeperTestSuite(t *testing.T) { + suite.Run(t, new(IntegrationTestSuite)) +} + +//go:embed testdata/clock_example.wasm +var wasmContract []byte + +func (s *IntegrationTestSuite) StoreCode() { + _, _, sender := testdata.KeyTestPubAddr() + msg := wasmtypes.MsgStoreCodeFixture(func(m *wasmtypes.MsgStoreCode) { + m.WASMByteCode = wasmContract + m.Sender = sender.String() + }) + rsp, err := s.app.MsgServiceRouter().Handler(msg)(s.ctx, msg) + s.Require().NoError(err) + var result wasmtypes.MsgStoreCodeResponse + s.Require().NoError(s.app.AppCodec().Unmarshal(rsp.Data, &result)) + s.Require().Equal(uint64(1), result.CodeID) + expHash := sha256.Sum256(wasmContract) + s.Require().Equal(expHash[:], result.Checksum) + // and + info := s.app.AppKeepers.WasmKeeper.GetCodeInfo(s.ctx, 1) + s.Require().NotNil(info) + s.Require().Equal(expHash[:], info.CodeHash) + s.Require().Equal(sender.String(), info.Creator) + s.Require().Equal(wasmtypes.DefaultParams().InstantiateDefaultPermission.With(sender), info.InstantiateConfig) +} + +func (s *IntegrationTestSuite) InstantiateContract(sender string, admin string) string { + msgStoreCode := wasmtypes.MsgStoreCodeFixture(func(m *wasmtypes.MsgStoreCode) { + m.WASMByteCode = wasmContract + m.Sender = sender + }) + _, err := s.app.MsgServiceRouter().Handler(msgStoreCode)(s.ctx, msgStoreCode) + s.Require().NoError(err) + + msgInstantiate := wasmtypes.MsgInstantiateContractFixture(func(m *wasmtypes.MsgInstantiateContract) { + m.Sender = sender + m.Admin = admin + m.Msg = []byte(`{}`) + }) + resp, err := s.app.MsgServiceRouter().Handler(msgInstantiate)(s.ctx, msgInstantiate) + s.Require().NoError(err) + var result wasmtypes.MsgInstantiateContractResponse + s.Require().NoError(s.app.AppCodec().Unmarshal(resp.Data, &result)) + contractInfo := s.app.AppKeepers.WasmKeeper.GetContractInfo(s.ctx, sdk.MustAccAddressFromBech32(result.Address)) + s.Require().Equal(contractInfo.CodeID, uint64(1)) + s.Require().Equal(contractInfo.Admin, admin) + s.Require().Equal(contractInfo.Creator, sender) + + return result.Address +} diff --git a/x/feepay/keeper/msg_server_test.go b/x/feepay/keeper/msg_server_test.go new file mode 100644 index 000000000..767ec7dfa --- /dev/null +++ b/x/feepay/keeper/msg_server_test.go @@ -0,0 +1,432 @@ +package keeper_test + +import ( + _ "embed" + + "github.com/cosmos/cosmos-sdk/testutil/testdata" + sdk "github.com/cosmos/cosmos-sdk/types" + + // govtypes "github.com/cosmos/cosmos-sdk/x/gov/types" + "github.com/CosmosContracts/juno/v17/x/feepay/types" +) + +func (s *IntegrationTestSuite) TestRegisterFeePayContract() { + _, _, sender := testdata.KeyTestPubAddr() + _, _, admin := testdata.KeyTestPubAddr() + _ = s.FundAccount(s.ctx, sender, sdk.NewCoins(sdk.NewCoin("stake", sdk.NewInt(1_000_000)))) + _ = s.FundAccount(s.ctx, admin, sdk.NewCoins(sdk.NewCoin("stake", sdk.NewInt(1_000_000)))) + + noAdminContractAddress := s.InstantiateContract(sender.String(), "") + withAdminContractAddress := s.InstantiateContract(sender.String(), admin.String()) + tContract := s.InstantiateContract(sender.String(), admin.String()) + + for _, tc := range []struct { + desc string + contractAddress string + deployerAddress string + shouldErr bool + }{ + { + desc: "Success - Creator", + contractAddress: noAdminContractAddress, + deployerAddress: sender.String(), + shouldErr: false, + }, + { + desc: "Success - Admin", + contractAddress: withAdminContractAddress, + deployerAddress: admin.String(), + shouldErr: false, + }, + { + desc: "Error - contract already registered", + contractAddress: withAdminContractAddress, + deployerAddress: admin.String(), + shouldErr: true, + }, + { + desc: "Error - Invalid deployer", + contractAddress: tContract, + deployerAddress: "Invalid", + shouldErr: true, + }, + { + desc: "Error - Invalid contract", + contractAddress: "Invalid", + deployerAddress: admin.String(), + shouldErr: true, + }, + } { + tc := tc + + s.Run(tc.desc, func() { + + // TODO: test setting balances & wallet limit work in another test with the querier. + err := s.app.AppKeepers.FeePayKeeper.RegisterContract(s.ctx, &types.MsgRegisterFeePayContract{ + SenderAddress: tc.deployerAddress, + FeePayContract: &types.FeePayContract{ + ContractAddress: tc.contractAddress, + WalletLimit: 1, + }, + }) + + if tc.shouldErr { + s.Require().Error(err) + } else { + s.Require().NoError(err) + } + }) + } +} + +func (s *IntegrationTestSuite) TestUnRegisterFeePayContract() { + _, _, sender := testdata.KeyTestPubAddr() + _, _, admin := testdata.KeyTestPubAddr() + _ = s.FundAccount(s.ctx, sender, sdk.NewCoins(sdk.NewCoin("stake", sdk.NewInt(1_000_000)))) + _ = s.FundAccount(s.ctx, admin, sdk.NewCoins(sdk.NewCoin("stake", sdk.NewInt(1_000_000)))) + + contract := s.InstantiateContract(sender.String(), "") + + err := s.app.AppKeepers.FeePayKeeper.RegisterContract(s.ctx, &types.MsgRegisterFeePayContract{ + SenderAddress: sender.String(), + FeePayContract: &types.FeePayContract{ + ContractAddress: contract, + WalletLimit: 1, + }, + }) + s.Require().NoError(err) + + for _, tc := range []struct { + desc string + contractAddress string + deployerAddress string + shouldErr bool + }{ + { + desc: "Fail - invalid address", + contractAddress: contract, + deployerAddress: "Invalid", + shouldErr: true, + }, + // TODO: non creator, non admin, etc + { + desc: "Success - unregister", + contractAddress: contract, + deployerAddress: sender.String(), + shouldErr: false, + }, + } { + tc := tc + + s.Run(tc.desc, func() { + err := s.app.AppKeepers.FeePayKeeper.UnregisterContract(s.ctx, &types.MsgUnregisterFeePayContract{ + SenderAddress: tc.deployerAddress, + ContractAddress: tc.contractAddress, + }) + + if tc.shouldErr { + s.Require().Error(err) + } else { + s.Require().NoError(err) + } + }) + } +} + +// TODO: FundFeePayContract, UpdateFeePayContractWalletLimit +// UpdateParams? (Prob better to do in e2e) +// querier test +// genesis_test +// E2E test with interchaintest (both end of week) also handle the ante test. Fees etc. + +// --- + +// OLD Examples from feeshare +// func (s *IntegrationTestSuite) TestRegisterFeeShare() { +// _, _, sender := testdata.KeyTestPubAddr() +// _ = s.FundAccount(s.ctx, sender, sdk.NewCoins(sdk.NewCoin("stake", sdk.NewInt(1_000_000)))) + +// gov := s.accountKeeper.GetModuleAddress(govtypes.ModuleName).String() +// govContract := s.InstantiateContract(sender.String(), gov) + +// contractAddress := s.InstantiateContract(sender.String(), "") +// contractAddress2 := s.InstantiateContract(contractAddress, contractAddress) + +// DAODAO := s.InstantiateContract(sender.String(), "") +// subContract := s.InstantiateContract(DAODAO, DAODAO) + +// _, _, withdrawer := testdata.KeyTestPubAddr() + +// for _, tc := range []struct { +// desc string +// msg *types.MsgRegisterFeeShare +// resp *types.MsgRegisterFeeShareResponse +// shouldErr bool +// }{ +// { +// desc: "Invalid contract address", +// msg: &types.MsgRegisterFeeShare{ +// ContractAddress: "Invalid", +// DeployerAddress: sender.String(), +// WithdrawerAddress: withdrawer.String(), +// }, +// resp: &types.MsgRegisterFeeShareResponse{}, +// shouldErr: true, +// }, +// { +// desc: "Invalid deployer address", +// msg: &types.MsgRegisterFeeShare{ +// ContractAddress: contractAddress, +// DeployerAddress: "Invalid", +// WithdrawerAddress: withdrawer.String(), +// }, +// resp: &types.MsgRegisterFeeShareResponse{}, +// shouldErr: true, +// }, +// { +// desc: "Invalid withdrawer address", +// msg: &types.MsgRegisterFeeShare{ +// ContractAddress: contractAddress, +// DeployerAddress: sender.String(), +// WithdrawerAddress: "Invalid", +// }, +// resp: &types.MsgRegisterFeeShareResponse{}, +// shouldErr: true, +// }, +// { +// desc: "Success", +// msg: &types.MsgRegisterFeeShare{ +// ContractAddress: contractAddress, +// DeployerAddress: sender.String(), +// WithdrawerAddress: withdrawer.String(), +// }, +// resp: &types.MsgRegisterFeeShareResponse{}, +// shouldErr: false, +// }, +// { +// desc: "Invalid withdraw address for factory contract", +// msg: &types.MsgRegisterFeeShare{ +// ContractAddress: contractAddress2, +// DeployerAddress: sender.String(), +// WithdrawerAddress: sender.String(), +// }, +// resp: &types.MsgRegisterFeeShareResponse{}, +// shouldErr: true, +// }, +// { +// desc: "Success register factory contract to itself", +// msg: &types.MsgRegisterFeeShare{ +// ContractAddress: contractAddress2, +// DeployerAddress: sender.String(), +// WithdrawerAddress: contractAddress2, +// }, +// resp: &types.MsgRegisterFeeShareResponse{}, +// shouldErr: false, +// }, +// { +// desc: "Invalid register gov contract withdraw address", +// msg: &types.MsgRegisterFeeShare{ +// ContractAddress: govContract, +// DeployerAddress: sender.String(), +// WithdrawerAddress: sender.String(), +// }, +// resp: &types.MsgRegisterFeeShareResponse{}, +// shouldErr: true, +// }, +// { +// desc: "Success register gov contract withdraw address to self", +// msg: &types.MsgRegisterFeeShare{ +// ContractAddress: govContract, +// DeployerAddress: sender.String(), +// WithdrawerAddress: govContract, +// }, +// resp: &types.MsgRegisterFeeShareResponse{}, +// shouldErr: false, +// }, +// { +// desc: "Success register contract from DAODAO contract as admin", +// msg: &types.MsgRegisterFeeShare{ +// ContractAddress: subContract, +// DeployerAddress: DAODAO, +// WithdrawerAddress: DAODAO, +// }, +// resp: &types.MsgRegisterFeeShareResponse{}, +// shouldErr: false, +// }, +// } { +// tc := tc +// s.Run(tc.desc, func() { +// goCtx := sdk.WrapSDKContext(s.ctx) +// if !tc.shouldErr { +// resp, err := s.feeShareMsgServer.RegisterFeeShare(goCtx, tc.msg) +// s.Require().NoError(err) +// s.Require().Equal(resp, tc.resp) +// } else { +// resp, err := s.feeShareMsgServer.RegisterFeeShare(goCtx, tc.msg) +// s.Require().Error(err) +// s.Require().Nil(resp) +// } +// }) +// } +// } + +// func (s *IntegrationTestSuite) TestUpdateFeeShare() { +// _, _, sender := testdata.KeyTestPubAddr() +// _ = s.FundAccount(s.ctx, sender, sdk.NewCoins(sdk.NewCoin("stake", sdk.NewInt(1_000_000)))) + +// contractAddress := s.InstantiateContract(sender.String(), "") +// _, _, withdrawer := testdata.KeyTestPubAddr() + +// contractAddressNoRegisFeeShare := s.InstantiateContract(sender.String(), "") +// s.Require().NotEqual(contractAddress, contractAddressNoRegisFeeShare) + +// // RegsisFeeShare +// goCtx := sdk.WrapSDKContext(s.ctx) +// msg := &types.MsgRegisterFeeShare{ +// ContractAddress: contractAddress, +// DeployerAddress: sender.String(), +// WithdrawerAddress: withdrawer.String(), +// } +// _, err := s.feeShareMsgServer.RegisterFeeShare(goCtx, msg) +// s.Require().NoError(err) +// _, _, newWithdrawer := testdata.KeyTestPubAddr() +// s.Require().NotEqual(withdrawer, newWithdrawer) + +// for _, tc := range []struct { +// desc string +// msg *types.MsgUpdateFeeShare +// resp *types.MsgCancelFeeShareResponse +// shouldErr bool +// }{ +// { +// desc: "Invalid - contract not regis", +// msg: &types.MsgUpdateFeeShare{ +// ContractAddress: contractAddressNoRegisFeeShare, +// DeployerAddress: sender.String(), +// WithdrawerAddress: newWithdrawer.String(), +// }, +// resp: nil, +// shouldErr: true, +// }, +// { +// desc: "Invalid - Invalid DeployerAddress", +// msg: &types.MsgUpdateFeeShare{ +// ContractAddress: contractAddress, +// DeployerAddress: "Invalid", +// WithdrawerAddress: newWithdrawer.String(), +// }, +// resp: nil, +// shouldErr: true, +// }, +// { +// desc: "Invalid - Invalid WithdrawerAddress", +// msg: &types.MsgUpdateFeeShare{ +// ContractAddress: contractAddress, +// DeployerAddress: sender.String(), +// WithdrawerAddress: "Invalid", +// }, +// resp: nil, +// shouldErr: true, +// }, +// { +// desc: "Invalid - Invalid WithdrawerAddress not change", +// msg: &types.MsgUpdateFeeShare{ +// ContractAddress: contractAddress, +// DeployerAddress: sender.String(), +// WithdrawerAddress: withdrawer.String(), +// }, +// resp: nil, +// shouldErr: true, +// }, +// { +// desc: "Success", +// msg: &types.MsgUpdateFeeShare{ +// ContractAddress: contractAddress, +// DeployerAddress: sender.String(), +// WithdrawerAddress: newWithdrawer.String(), +// }, +// resp: &types.MsgCancelFeeShareResponse{}, +// shouldErr: false, +// }, +// } { +// tc := tc +// s.Run(tc.desc, func() { +// goCtx := sdk.WrapSDKContext(s.ctx) +// if !tc.shouldErr { +// _, err := s.feeShareMsgServer.UpdateFeeShare(goCtx, tc.msg) +// s.Require().NoError(err) +// } else { +// resp, err := s.feeShareMsgServer.UpdateFeeShare(goCtx, tc.msg) +// s.Require().Error(err) +// s.Require().Nil(resp) +// } +// }) +// } +// } + +// func (s *IntegrationTestSuite) TestCancelFeeShare() { +// _, _, sender := testdata.KeyTestPubAddr() +// _ = s.FundAccount(s.ctx, sender, sdk.NewCoins(sdk.NewCoin("stake", sdk.NewInt(1_000_000)))) + +// contractAddress := s.InstantiateContract(sender.String(), "") +// _, _, withdrawer := testdata.KeyTestPubAddr() + +// // RegsisFeeShare +// goCtx := sdk.WrapSDKContext(s.ctx) +// msg := &types.MsgRegisterFeeShare{ +// ContractAddress: contractAddress, +// DeployerAddress: sender.String(), +// WithdrawerAddress: withdrawer.String(), +// } +// _, err := s.feeShareMsgServer.RegisterFeeShare(goCtx, msg) +// s.Require().NoError(err) + +// for _, tc := range []struct { +// desc string +// msg *types.MsgCancelFeeShare +// resp *types.MsgCancelFeeShareResponse +// shouldErr bool +// }{ +// { +// desc: "Invalid - contract Address", +// msg: &types.MsgCancelFeeShare{ +// ContractAddress: "Invalid", +// DeployerAddress: sender.String(), +// }, +// resp: nil, +// shouldErr: true, +// }, +// { +// desc: "Invalid - deployer Address", +// msg: &types.MsgCancelFeeShare{ +// ContractAddress: contractAddress, +// DeployerAddress: "Invalid", +// }, +// resp: nil, +// shouldErr: true, +// }, +// { +// desc: "Success", +// msg: &types.MsgCancelFeeShare{ +// ContractAddress: contractAddress, +// DeployerAddress: sender.String(), +// }, +// resp: &types.MsgCancelFeeShareResponse{}, +// shouldErr: false, +// }, +// } { +// tc := tc +// s.Run(tc.desc, func() { +// goCtx := sdk.WrapSDKContext(s.ctx) +// if !tc.shouldErr { +// resp, err := s.feeShareMsgServer.CancelFeeShare(goCtx, tc.msg) +// s.Require().NoError(err) +// s.Require().Equal(resp, tc.resp) +// } else { +// resp, err := s.feeShareMsgServer.CancelFeeShare(goCtx, tc.msg) +// s.Require().Error(err) +// s.Require().Equal(resp, tc.resp) +// } +// }) +// } +// } diff --git a/x/feepay/keeper/grpc_query.go b/x/feepay/keeper/querier.go similarity index 100% rename from x/feepay/keeper/grpc_query.go rename to x/feepay/keeper/querier.go diff --git a/x/feepay/keeper/querier_test.go b/x/feepay/keeper/querier_test.go new file mode 100644 index 000000000..2a7322b20 --- /dev/null +++ b/x/feepay/keeper/querier_test.go @@ -0,0 +1,5 @@ +package keeper_test + +// pagination test from x/feeshare/grpc_query_test.go + +// params we can do in e2e. diff --git a/x/feepay/keeper/testdata/clock_example.wasm b/x/feepay/keeper/testdata/clock_example.wasm new file mode 100644 index 0000000000000000000000000000000000000000..e2d99f71c55b2204fd7e9867e1e45447f107e987 GIT binary patch literal 141386 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 literal 0 HcmV?d00001 From ba4862a67cc8813b24b8287b6d164863f99d4dc6 Mon Sep 17 00:00:00 2001 From: Joel Smith Date: Wed, 4 Oct 2023 21:53:23 -0500 Subject: [PATCH 36/79] Add Tests for Msg Server --- x/feepay/ante/deduct_fee.go | 8 - x/feepay/keeper/feepay.go | 9 +- x/feepay/keeper/msg_server.go | 12 +- x/feepay/keeper/msg_server_test.go | 542 ++++++++++++----------------- 4 files changed, 249 insertions(+), 322 deletions(-) diff --git a/x/feepay/ante/deduct_fee.go b/x/feepay/ante/deduct_fee.go index 810e56d98..5faae248e 100644 --- a/x/feepay/ante/deduct_fee.go +++ b/x/feepay/ante/deduct_fee.go @@ -171,18 +171,12 @@ func (dfd DeductFeeDecorator) handleZeroFees(ctx sdk.Context, deductFeesFromAcc } } - ctx.Logger().Error("HandleZeroFees", "FeePrice", feePrice) - // Get the tx gas feeTx := tx.(sdk.FeeTx) gas := sdkmath.LegacyNewDec(int64(feeTx.GetGas())) - ctx.Logger().Error("HandleZeroFees", "Gas", gas) - requiredFee := feePrice.Amount.Mul(gas).Ceil().RoundInt() - ctx.Logger().Error("HandleZeroFees", "RequiredFee", requiredFee) - // Check if wallet exceeded usage limit on contract accBech32 := deductFeesFromAcc.GetAddress().String() if dfd.feepayKeeper.HasWalletExceededUsageLimit(ctx, feepayContract, accBech32) { @@ -197,8 +191,6 @@ func (dfd DeductFeeDecorator) handleZeroFees(ctx sdk.Context, deductFeesFromAcc // Create an array of coins, storing the required fee payment := sdk.NewCoins(sdk.NewCoin(feePrice.Denom, requiredFee)) - ctx.Logger().Error("HandleZeroFees", "Payment", payment) - // Cover the fees of the transaction, send from FeePay Module to FeeCollector Module if err := dfd.bankKeeper.SendCoinsFromModuleToModule(ctx, feepaytypes.ModuleName, types.FeeCollectorName, payment); err != nil { return errorsmod.Wrapf(sdkerrors.ErrInsufficientFunds, "error transfering funds from FeePay to FeeCollector; %s", err) diff --git a/x/feepay/keeper/feepay.go b/x/feepay/keeper/feepay.go index 17e1be272..8e09bf984 100644 --- a/x/feepay/keeper/feepay.go +++ b/x/feepay/keeper/feepay.go @@ -166,7 +166,7 @@ func (k Keeper) UnregisterContract(ctx sdk.Context, rfp *types.MsgUnregisterFeeP store.Delete(iterator.Key()) } - // Transfer funds back to contract owner + // Calculate coins to refund coins := sdk.NewCoins(sdk.NewCoin(k.bondDenom, math.NewIntFromUint64(contract.Balance))) // Default refund address to admin, fallback to creator @@ -207,8 +207,13 @@ func (k Keeper) FundContract(ctx sdk.Context, fpc *types.FeePayContract, senderA } } + // Ensure the transfer coin was set + if transferCoin == (sdk.Coin{}) { + return types.ErrInvalidJunoFundAmount.Wrapf("contract must be funded with '%s'", k.bondDenom) + } + // Transfer from sender to module - if err := k.bankKeeper.SendCoinsFromAccountToModule(ctx, senderAddr, types.ModuleName, sdk.NewCoins(transferCoin)); err != nil { + if err := k.bankKeeper.SendCoinsFromAccountToModule(ctx, senderAddr, types.ModuleName, coins); err != nil { return err } diff --git a/x/feepay/keeper/msg_server.go b/x/feepay/keeper/msg_server.go index e4d6f9814..511523fb0 100644 --- a/x/feepay/keeper/msg_server.go +++ b/x/feepay/keeper/msg_server.go @@ -34,8 +34,12 @@ func (k Keeper) FundFeePayContract(goCtx context.Context, msg *types.MsgFundFeeP return nil, err } - // Sender address (already validated in msg.go) - senderAddr := sdk.MustAccAddressFromBech32(msg.SenderAddress) + // Validate sender address + senderAddr, err := sdk.AccAddressFromBech32(msg.SenderAddress) + + if err != nil { + return nil, errorsmod.Wrapf(types.ErrInvalidAddress, "invalid sender address: %s", msg.SenderAddress) + } return &types.MsgFundFeePayContractResponse{}, k.FundContract(ctx, contract, senderAddr, msg.Amount) } @@ -50,6 +54,10 @@ func (k Keeper) UpdateFeePayContractWalletLimit(goCtx context.Context, msg *type return nil, err } + if msg.WalletLimit > 1_000_000 { + return nil, errorsmod.Wrapf(types.ErrInvalidWalletLimit, "invalid wallet limit: %d", msg.WalletLimit) + } + return &types.MsgUpdateFeePayContractWalletLimitResponse{}, k.UpdateContractWalletLimit(ctx, contract, msg.SenderAddress, msg.WalletLimit) } diff --git a/x/feepay/keeper/msg_server_test.go b/x/feepay/keeper/msg_server_test.go index 767ec7dfa..298e9d93e 100644 --- a/x/feepay/keeper/msg_server_test.go +++ b/x/feepay/keeper/msg_server_test.go @@ -23,47 +23,51 @@ func (s *IntegrationTestSuite) TestRegisterFeePayContract() { for _, tc := range []struct { desc string contractAddress string - deployerAddress string + senderAddress string shouldErr bool }{ { desc: "Success - Creator", contractAddress: noAdminContractAddress, - deployerAddress: sender.String(), + senderAddress: sender.String(), shouldErr: false, }, + { + desc: "Fail - Already Registered Contract", + contractAddress: noAdminContractAddress, + senderAddress: sender.String(), + shouldErr: true, + }, { desc: "Success - Admin", contractAddress: withAdminContractAddress, - deployerAddress: admin.String(), + senderAddress: admin.String(), shouldErr: false, }, { - desc: "Error - contract already registered", + desc: "Error - Contract Already Registered", contractAddress: withAdminContractAddress, - deployerAddress: admin.String(), + senderAddress: admin.String(), shouldErr: true, }, { - desc: "Error - Invalid deployer", + desc: "Error - Invalid Sender", contractAddress: tContract, - deployerAddress: "Invalid", + senderAddress: "Invalid", shouldErr: true, }, { - desc: "Error - Invalid contract", + desc: "Error - Invalid Contract", contractAddress: "Invalid", - deployerAddress: admin.String(), + senderAddress: admin.String(), shouldErr: true, }, } { tc := tc s.Run(tc.desc, func() { - - // TODO: test setting balances & wallet limit work in another test with the querier. - err := s.app.AppKeepers.FeePayKeeper.RegisterContract(s.ctx, &types.MsgRegisterFeePayContract{ - SenderAddress: tc.deployerAddress, + _, err := s.app.AppKeepers.FeePayKeeper.RegisterFeePayContract(s.ctx, &types.MsgRegisterFeePayContract{ + SenderAddress: tc.senderAddress, FeePayContract: &types.FeePayContract{ ContractAddress: tc.contractAddress, WalletLimit: 1, @@ -79,48 +83,81 @@ func (s *IntegrationTestSuite) TestRegisterFeePayContract() { } } -func (s *IntegrationTestSuite) TestUnRegisterFeePayContract() { +func (s *IntegrationTestSuite) TestUnregisterFeePayContract() { _, _, sender := testdata.KeyTestPubAddr() _, _, admin := testdata.KeyTestPubAddr() _ = s.FundAccount(s.ctx, sender, sdk.NewCoins(sdk.NewCoin("stake", sdk.NewInt(1_000_000)))) _ = s.FundAccount(s.ctx, admin, sdk.NewCoins(sdk.NewCoin("stake", sdk.NewInt(1_000_000)))) - contract := s.InstantiateContract(sender.String(), "") + creatorContract := s.InstantiateContract(sender.String(), "") + adminContract := s.InstantiateContract(sender.String(), admin.String()) - err := s.app.AppKeepers.FeePayKeeper.RegisterContract(s.ctx, &types.MsgRegisterFeePayContract{ + _, err := s.app.AppKeepers.FeePayKeeper.RegisterFeePayContract(s.ctx, &types.MsgRegisterFeePayContract{ SenderAddress: sender.String(), FeePayContract: &types.FeePayContract{ - ContractAddress: contract, + ContractAddress: creatorContract, WalletLimit: 1, }, }) s.Require().NoError(err) + _, err = s.app.AppKeepers.FeePayKeeper.RegisterFeePayContract(s.ctx, &types.MsgRegisterFeePayContract{ + SenderAddress: admin.String(), + FeePayContract: &types.FeePayContract{ + ContractAddress: adminContract, + WalletLimit: 0, + }, + }) + s.Require().NoError(err) + for _, tc := range []struct { desc string contractAddress string - deployerAddress string + senderAddress string shouldErr bool }{ { - desc: "Fail - invalid address", - contractAddress: contract, - deployerAddress: "Invalid", + desc: "Fail - Invalid Contract Address", + contractAddress: "Invalid", + senderAddress: sender.String(), shouldErr: true, }, - // TODO: non creator, non admin, etc { - desc: "Success - unregister", - contractAddress: contract, - deployerAddress: sender.String(), + desc: "Fail - Invalid Sender Address", + contractAddress: creatorContract, + senderAddress: "Invalid", + shouldErr: true, + }, + { + desc: "Success - Unregister Creator Contract as Creator", + contractAddress: creatorContract, + senderAddress: sender.String(), shouldErr: false, }, + { + desc: "Fail - Unregister Admin Contract As Creator", + contractAddress: adminContract, + senderAddress: sender.String(), + shouldErr: true, + }, + { + desc: "Success - Unregister Admin Contract As Admin", + contractAddress: adminContract, + senderAddress: admin.String(), + shouldErr: false, + }, + { + desc: "Fail - Already Unregistered", + contractAddress: creatorContract, + senderAddress: sender.String(), + shouldErr: true, + }, } { tc := tc s.Run(tc.desc, func() { - err := s.app.AppKeepers.FeePayKeeper.UnregisterContract(s.ctx, &types.MsgUnregisterFeePayContract{ - SenderAddress: tc.deployerAddress, + _, err := s.app.AppKeepers.FeePayKeeper.UnregisterFeePayContract(s.ctx, &types.MsgUnregisterFeePayContract{ + SenderAddress: tc.senderAddress, ContractAddress: tc.contractAddress, }) @@ -133,300 +170,185 @@ func (s *IntegrationTestSuite) TestUnRegisterFeePayContract() { } } -// TODO: FundFeePayContract, UpdateFeePayContractWalletLimit -// UpdateParams? (Prob better to do in e2e) -// querier test -// genesis_test -// E2E test with interchaintest (both end of week) also handle the ante test. Fees etc. - -// --- - -// OLD Examples from feeshare -// func (s *IntegrationTestSuite) TestRegisterFeeShare() { -// _, _, sender := testdata.KeyTestPubAddr() -// _ = s.FundAccount(s.ctx, sender, sdk.NewCoins(sdk.NewCoin("stake", sdk.NewInt(1_000_000)))) +func (s *IntegrationTestSuite) TestFundFeePayContract() { + _, _, sender := testdata.KeyTestPubAddr() + _, _, admin := testdata.KeyTestPubAddr() + _ = s.FundAccount(s.ctx, sender, sdk.NewCoins(sdk.NewCoin("stake", sdk.NewInt(1_000_000)))) + _ = s.FundAccount(s.ctx, sender, sdk.NewCoins(sdk.NewCoin("ujuno", sdk.NewInt(100_000_000)))) + _ = s.FundAccount(s.ctx, admin, sdk.NewCoins(sdk.NewCoin("stake", sdk.NewInt(1_000_000)))) -// gov := s.accountKeeper.GetModuleAddress(govtypes.ModuleName).String() -// govContract := s.InstantiateContract(sender.String(), gov) + contract := s.InstantiateContract(sender.String(), "") -// contractAddress := s.InstantiateContract(sender.String(), "") -// contractAddress2 := s.InstantiateContract(contractAddress, contractAddress) + err := s.app.AppKeepers.FeePayKeeper.RegisterContract(s.ctx, &types.MsgRegisterFeePayContract{ + SenderAddress: sender.String(), + FeePayContract: &types.FeePayContract{ + ContractAddress: contract, + WalletLimit: 1, + }, + }) + s.Require().NoError(err) -// DAODAO := s.InstantiateContract(sender.String(), "") -// subContract := s.InstantiateContract(DAODAO, DAODAO) + for _, tc := range []struct { + desc string + contractAddress string + senderAddress string + amount sdk.Coins + shouldErr bool + }{ + { + desc: "Fail - Invalid Contract Address", + contractAddress: "Invalid", + senderAddress: sender.String(), + amount: sdk.NewCoins(sdk.NewCoin("ujuno", sdk.NewInt(1_000_000))), + shouldErr: true, + }, + { + desc: "Fail - Invalid Sender Address", + contractAddress: contract, + senderAddress: "Invalid", + amount: sdk.NewCoins(sdk.NewCoin("ujuno", sdk.NewInt(1_000_000))), + shouldErr: true, + }, + { + desc: "Fail - Invalid Funds", + contractAddress: contract, + senderAddress: sender.String(), + amount: sdk.NewCoins(sdk.NewCoin("invalid-denom", sdk.NewInt(1_000_000))), + shouldErr: true, + }, + { + desc: "Fail - Wallet Not Enough Funds", + contractAddress: contract, + senderAddress: sender.String(), + amount: sdk.NewCoins(sdk.NewCoin("ujuno", sdk.NewInt(100_000_000_000))), + shouldErr: true, + }, + { + desc: "Success - Contract Funded", + contractAddress: contract, + senderAddress: sender.String(), + amount: sdk.NewCoins(sdk.NewCoin("ujuno", sdk.NewInt(1_000_000))), + shouldErr: false, + }, + } { + tc := tc -// _, _, withdrawer := testdata.KeyTestPubAddr() + s.Run(tc.desc, func() { -// for _, tc := range []struct { -// desc string -// msg *types.MsgRegisterFeeShare -// resp *types.MsgRegisterFeeShareResponse -// shouldErr bool -// }{ -// { -// desc: "Invalid contract address", -// msg: &types.MsgRegisterFeeShare{ -// ContractAddress: "Invalid", -// DeployerAddress: sender.String(), -// WithdrawerAddress: withdrawer.String(), -// }, -// resp: &types.MsgRegisterFeeShareResponse{}, -// shouldErr: true, -// }, -// { -// desc: "Invalid deployer address", -// msg: &types.MsgRegisterFeeShare{ -// ContractAddress: contractAddress, -// DeployerAddress: "Invalid", -// WithdrawerAddress: withdrawer.String(), -// }, -// resp: &types.MsgRegisterFeeShareResponse{}, -// shouldErr: true, -// }, -// { -// desc: "Invalid withdrawer address", -// msg: &types.MsgRegisterFeeShare{ -// ContractAddress: contractAddress, -// DeployerAddress: sender.String(), -// WithdrawerAddress: "Invalid", -// }, -// resp: &types.MsgRegisterFeeShareResponse{}, -// shouldErr: true, -// }, -// { -// desc: "Success", -// msg: &types.MsgRegisterFeeShare{ -// ContractAddress: contractAddress, -// DeployerAddress: sender.String(), -// WithdrawerAddress: withdrawer.String(), -// }, -// resp: &types.MsgRegisterFeeShareResponse{}, -// shouldErr: false, -// }, -// { -// desc: "Invalid withdraw address for factory contract", -// msg: &types.MsgRegisterFeeShare{ -// ContractAddress: contractAddress2, -// DeployerAddress: sender.String(), -// WithdrawerAddress: sender.String(), -// }, -// resp: &types.MsgRegisterFeeShareResponse{}, -// shouldErr: true, -// }, -// { -// desc: "Success register factory contract to itself", -// msg: &types.MsgRegisterFeeShare{ -// ContractAddress: contractAddress2, -// DeployerAddress: sender.String(), -// WithdrawerAddress: contractAddress2, -// }, -// resp: &types.MsgRegisterFeeShareResponse{}, -// shouldErr: false, -// }, -// { -// desc: "Invalid register gov contract withdraw address", -// msg: &types.MsgRegisterFeeShare{ -// ContractAddress: govContract, -// DeployerAddress: sender.String(), -// WithdrawerAddress: sender.String(), -// }, -// resp: &types.MsgRegisterFeeShareResponse{}, -// shouldErr: true, -// }, -// { -// desc: "Success register gov contract withdraw address to self", -// msg: &types.MsgRegisterFeeShare{ -// ContractAddress: govContract, -// DeployerAddress: sender.String(), -// WithdrawerAddress: govContract, -// }, -// resp: &types.MsgRegisterFeeShareResponse{}, -// shouldErr: false, -// }, -// { -// desc: "Success register contract from DAODAO contract as admin", -// msg: &types.MsgRegisterFeeShare{ -// ContractAddress: subContract, -// DeployerAddress: DAODAO, -// WithdrawerAddress: DAODAO, -// }, -// resp: &types.MsgRegisterFeeShareResponse{}, -// shouldErr: false, -// }, -// } { -// tc := tc -// s.Run(tc.desc, func() { -// goCtx := sdk.WrapSDKContext(s.ctx) -// if !tc.shouldErr { -// resp, err := s.feeShareMsgServer.RegisterFeeShare(goCtx, tc.msg) -// s.Require().NoError(err) -// s.Require().Equal(resp, tc.resp) -// } else { -// resp, err := s.feeShareMsgServer.RegisterFeeShare(goCtx, tc.msg) -// s.Require().Error(err) -// s.Require().Nil(resp) -// } -// }) -// } -// } + _, err := s.app.AppKeepers.FeePayKeeper.FundFeePayContract(s.ctx, &types.MsgFundFeePayContract{ + SenderAddress: tc.senderAddress, + ContractAddress: tc.contractAddress, + Amount: tc.amount, + }) -// func (s *IntegrationTestSuite) TestUpdateFeeShare() { -// _, _, sender := testdata.KeyTestPubAddr() -// _ = s.FundAccount(s.ctx, sender, sdk.NewCoins(sdk.NewCoin("stake", sdk.NewInt(1_000_000)))) + if tc.shouldErr { + s.Require().Error(err) + } else { + s.Require().NoError(err) + } + }) + } +} -// contractAddress := s.InstantiateContract(sender.String(), "") -// _, _, withdrawer := testdata.KeyTestPubAddr() +func (s *IntegrationTestSuite) TestUpdateFeePayContractWalletLimit() { + _, _, sender := testdata.KeyTestPubAddr() + _, _, admin := testdata.KeyTestPubAddr() + _ = s.FundAccount(s.ctx, sender, sdk.NewCoins(sdk.NewCoin("stake", sdk.NewInt(1_000_000)))) + _ = s.FundAccount(s.ctx, admin, sdk.NewCoins(sdk.NewCoin("stake", sdk.NewInt(1_000_000)))) -// contractAddressNoRegisFeeShare := s.InstantiateContract(sender.String(), "") -// s.Require().NotEqual(contractAddress, contractAddressNoRegisFeeShare) + creatorContract := s.InstantiateContract(sender.String(), "") + adminContract := s.InstantiateContract(sender.String(), admin.String()) -// // RegsisFeeShare -// goCtx := sdk.WrapSDKContext(s.ctx) -// msg := &types.MsgRegisterFeeShare{ -// ContractAddress: contractAddress, -// DeployerAddress: sender.String(), -// WithdrawerAddress: withdrawer.String(), -// } -// _, err := s.feeShareMsgServer.RegisterFeeShare(goCtx, msg) -// s.Require().NoError(err) -// _, _, newWithdrawer := testdata.KeyTestPubAddr() -// s.Require().NotEqual(withdrawer, newWithdrawer) + _, err := s.app.AppKeepers.FeePayKeeper.RegisterFeePayContract(s.ctx, &types.MsgRegisterFeePayContract{ + SenderAddress: sender.String(), + FeePayContract: &types.FeePayContract{ + ContractAddress: creatorContract, + WalletLimit: 1, + }, + }) + s.Require().NoError(err) -// for _, tc := range []struct { -// desc string -// msg *types.MsgUpdateFeeShare -// resp *types.MsgCancelFeeShareResponse -// shouldErr bool -// }{ -// { -// desc: "Invalid - contract not regis", -// msg: &types.MsgUpdateFeeShare{ -// ContractAddress: contractAddressNoRegisFeeShare, -// DeployerAddress: sender.String(), -// WithdrawerAddress: newWithdrawer.String(), -// }, -// resp: nil, -// shouldErr: true, -// }, -// { -// desc: "Invalid - Invalid DeployerAddress", -// msg: &types.MsgUpdateFeeShare{ -// ContractAddress: contractAddress, -// DeployerAddress: "Invalid", -// WithdrawerAddress: newWithdrawer.String(), -// }, -// resp: nil, -// shouldErr: true, -// }, -// { -// desc: "Invalid - Invalid WithdrawerAddress", -// msg: &types.MsgUpdateFeeShare{ -// ContractAddress: contractAddress, -// DeployerAddress: sender.String(), -// WithdrawerAddress: "Invalid", -// }, -// resp: nil, -// shouldErr: true, -// }, -// { -// desc: "Invalid - Invalid WithdrawerAddress not change", -// msg: &types.MsgUpdateFeeShare{ -// ContractAddress: contractAddress, -// DeployerAddress: sender.String(), -// WithdrawerAddress: withdrawer.String(), -// }, -// resp: nil, -// shouldErr: true, -// }, -// { -// desc: "Success", -// msg: &types.MsgUpdateFeeShare{ -// ContractAddress: contractAddress, -// DeployerAddress: sender.String(), -// WithdrawerAddress: newWithdrawer.String(), -// }, -// resp: &types.MsgCancelFeeShareResponse{}, -// shouldErr: false, -// }, -// } { -// tc := tc -// s.Run(tc.desc, func() { -// goCtx := sdk.WrapSDKContext(s.ctx) -// if !tc.shouldErr { -// _, err := s.feeShareMsgServer.UpdateFeeShare(goCtx, tc.msg) -// s.Require().NoError(err) -// } else { -// resp, err := s.feeShareMsgServer.UpdateFeeShare(goCtx, tc.msg) -// s.Require().Error(err) -// s.Require().Nil(resp) -// } -// }) -// } -// } + _, err = s.app.AppKeepers.FeePayKeeper.RegisterFeePayContract(s.ctx, &types.MsgRegisterFeePayContract{ + SenderAddress: admin.String(), + FeePayContract: &types.FeePayContract{ + ContractAddress: adminContract, + WalletLimit: 0, + }, + }) + s.Require().NoError(err) -// func (s *IntegrationTestSuite) TestCancelFeeShare() { -// _, _, sender := testdata.KeyTestPubAddr() -// _ = s.FundAccount(s.ctx, sender, sdk.NewCoins(sdk.NewCoin("stake", sdk.NewInt(1_000_000)))) + for _, tc := range []struct { + desc string + contractAddress string + senderAddress string + walletLimit uint64 + shouldErr bool + }{ + { + desc: "Success - Update Admin Contract As Admin", + contractAddress: adminContract, + senderAddress: admin.String(), + walletLimit: 10, + shouldErr: false, + }, + { + desc: "Fail - Update Admin Contract As Creator", + contractAddress: adminContract, + senderAddress: sender.String(), + walletLimit: 150, + shouldErr: true, + }, + { + desc: "Success - Update Admin Contract As Admin (lower bounds)", + contractAddress: adminContract, + senderAddress: admin.String(), + walletLimit: 0, + shouldErr: false, + }, + { + desc: "Success - Update Admin Contract As Admin (upper bounds)", + contractAddress: adminContract, + senderAddress: admin.String(), + walletLimit: 1_000_000, + shouldErr: false, + }, + { + desc: "Fail - Update Admin Contract As Admin (out of bounds)", + contractAddress: adminContract, + senderAddress: admin.String(), + walletLimit: 1_000_001, + shouldErr: true, + }, + { + desc: "Fail - Update Creator Contract As Non Creator", + contractAddress: creatorContract, + senderAddress: admin.String(), + walletLimit: 1, + shouldErr: true, + }, + { + desc: "Success - Update Creator Contract As Creator", + contractAddress: creatorContract, + senderAddress: sender.String(), + walletLimit: 21, + shouldErr: false, + }, + } { + tc := tc -// contractAddress := s.InstantiateContract(sender.String(), "") -// _, _, withdrawer := testdata.KeyTestPubAddr() + s.Run(tc.desc, func() { -// // RegsisFeeShare -// goCtx := sdk.WrapSDKContext(s.ctx) -// msg := &types.MsgRegisterFeeShare{ -// ContractAddress: contractAddress, -// DeployerAddress: sender.String(), -// WithdrawerAddress: withdrawer.String(), -// } -// _, err := s.feeShareMsgServer.RegisterFeeShare(goCtx, msg) -// s.Require().NoError(err) + _, err := s.app.AppKeepers.FeePayKeeper.UpdateFeePayContractWalletLimit(s.ctx, &types.MsgUpdateFeePayContractWalletLimit{ + SenderAddress: tc.senderAddress, + ContractAddress: tc.contractAddress, + WalletLimit: tc.walletLimit, + }) -// for _, tc := range []struct { -// desc string -// msg *types.MsgCancelFeeShare -// resp *types.MsgCancelFeeShareResponse -// shouldErr bool -// }{ -// { -// desc: "Invalid - contract Address", -// msg: &types.MsgCancelFeeShare{ -// ContractAddress: "Invalid", -// DeployerAddress: sender.String(), -// }, -// resp: nil, -// shouldErr: true, -// }, -// { -// desc: "Invalid - deployer Address", -// msg: &types.MsgCancelFeeShare{ -// ContractAddress: contractAddress, -// DeployerAddress: "Invalid", -// }, -// resp: nil, -// shouldErr: true, -// }, -// { -// desc: "Success", -// msg: &types.MsgCancelFeeShare{ -// ContractAddress: contractAddress, -// DeployerAddress: sender.String(), -// }, -// resp: &types.MsgCancelFeeShareResponse{}, -// shouldErr: false, -// }, -// } { -// tc := tc -// s.Run(tc.desc, func() { -// goCtx := sdk.WrapSDKContext(s.ctx) -// if !tc.shouldErr { -// resp, err := s.feeShareMsgServer.CancelFeeShare(goCtx, tc.msg) -// s.Require().NoError(err) -// s.Require().Equal(resp, tc.resp) -// } else { -// resp, err := s.feeShareMsgServer.CancelFeeShare(goCtx, tc.msg) -// s.Require().Error(err) -// s.Require().Equal(resp, tc.resp) -// } -// }) -// } -// } + if tc.shouldErr { + s.Require().Error(err) + } else { + s.Require().NoError(err) + } + }) + } +} From cbf3252c9c542203e687651efff7d182fce3c145 Mon Sep 17 00:00:00 2001 From: Joel Smith Date: Thu, 5 Oct 2023 20:50:13 -0500 Subject: [PATCH 37/79] Add Query Tests --- x/feepay/keeper/keeper_test.go | 1 - x/feepay/keeper/querier_test.go | 225 +++++++++++++++++++++++++++++++- 2 files changed, 223 insertions(+), 3 deletions(-) diff --git a/x/feepay/keeper/keeper_test.go b/x/feepay/keeper/keeper_test.go index 13c22c9a4..3ed66f538 100644 --- a/x/feepay/keeper/keeper_test.go +++ b/x/feepay/keeper/keeper_test.go @@ -50,7 +50,6 @@ func (s *IntegrationTestSuite) SetupTest() { s.queryClient = types.NewQueryClient(queryHelper) s.bankKeeper = s.app.AppKeepers.BankKeeper - // s.accountKeeper = s.app.AppKeepers.AccountKeeper s.msgServer = s.app.AppKeepers.FeePayKeeper s.wasmMsgServer = wasmkeeper.NewMsgServerImpl(&s.app.AppKeepers.WasmKeeper) } diff --git a/x/feepay/keeper/querier_test.go b/x/feepay/keeper/querier_test.go index 2a7322b20..7ee0e9854 100644 --- a/x/feepay/keeper/querier_test.go +++ b/x/feepay/keeper/querier_test.go @@ -1,5 +1,226 @@ package keeper_test -// pagination test from x/feeshare/grpc_query_test.go +import ( + "github.com/cosmos/cosmos-sdk/testutil/testdata" + sdk "github.com/cosmos/cosmos-sdk/types" + "github.com/cosmos/cosmos-sdk/types/query" -// params we can do in e2e. + //"github.com/cosmos/cosmos-sdk/types/query" + + //"github.com/CosmosContracts/juno/v17/testutil/nullify" + "github.com/CosmosContracts/juno/v17/testutil/nullify" + "github.com/CosmosContracts/juno/v17/x/feepay/types" +) + +func (s *IntegrationTestSuite) TestQueryContract() { + // Get & fund creator + _, _, sender := testdata.KeyTestPubAddr() + _ = s.FundAccount(s.ctx, sender, sdk.NewCoins(sdk.NewCoin("stake", sdk.NewInt(1_000_000)))) + + // Instantiate the contractAddr + contractAddr := s.InstantiateContract(sender.String(), "") + + // Register the fee pay contract + _, err := s.app.AppKeepers.FeePayKeeper.RegisterFeePayContract(s.ctx, &types.MsgRegisterFeePayContract{ + SenderAddress: sender.String(), + FeePayContract: &types.FeePayContract{ + ContractAddress: contractAddr, + WalletLimit: 1, + }, + }) + s.Require().NoError(err) + + s.Run("QueryContract", func() { + // Query for the contract + res, err := s.queryClient.FeePayContract(s.ctx, &types.QueryFeePayContract{ + ContractAddress: contractAddr, + }) + + // Ensure no error and response exists + s.Require().NoError(err) + s.Require().NotNil(res) + }) +} + +func (s *IntegrationTestSuite) TestQueryContracts() { + // Get & fund creator + _, _, sender := testdata.KeyTestPubAddr() + _ = s.FundAccount(s.ctx, sender, sdk.NewCoins(sdk.NewCoin("stake", sdk.NewInt(1_000_000)))) + + // Instantiate & register multiple fee pay contracts + var contractAddressList []string + var feePayContracts []types.FeePayContract + for index := 0; index < 5; index++ { + // Instantiate the contractAddr + contractAddr := s.InstantiateContract(sender.String(), "") + + // Register the fee pay contract + _, err := s.app.AppKeepers.FeePayKeeper.RegisterFeePayContract(s.ctx, &types.MsgRegisterFeePayContract{ + SenderAddress: sender.String(), + FeePayContract: &types.FeePayContract{ + ContractAddress: contractAddr, + WalletLimit: 1, + }, + }) + s.Require().NoError(err) + + // Query for the contract + res, err := s.queryClient.FeePayContract(s.ctx, &types.QueryFeePayContract{ + ContractAddress: contractAddr, + }) + + // Ensure no error and response exists + s.Require().NoError(err) + s.Require().NotNil(res) + + // Append to lists + contractAddressList = append(contractAddressList, contractAddr) + feePayContracts = append(feePayContracts, *res.FeePayContract) + } + + request := func(next []byte, offset, limit uint64, total bool) *types.QueryFeePayContracts { + return &types.QueryFeePayContracts{ + Pagination: &query.PageRequest{ + Key: next, + Offset: offset, + Limit: limit, + CountTotal: total, + }, + } + } + + s.Run("ByOffset", func() { + step := 2 + goCtx := sdk.WrapSDKContext(s.ctx) + for i := 0; i < len(contractAddressList); i += step { + resp, err := s.queryClient.FeePayContracts(goCtx, request(nil, uint64(i), uint64(step), false)) + s.Require().NoError(err) + s.Require().LessOrEqual(len(resp.FeePayContracts), step) + s.Require().Subset(nullify.Fill(feePayContracts), nullify.Fill(resp.FeePayContracts)) + } + }) + + s.Run("ByKey", func() { + step := 2 + var next []byte + goCtx := sdk.WrapSDKContext(s.ctx) + for i := 0; i < len(contractAddressList); i += step { + resp, err := s.queryClient.FeePayContracts(goCtx, request(next, 0, uint64(step), false)) + s.Require().NoError(err) + s.Require().LessOrEqual(len(resp.FeePayContracts), step) + s.Require().Subset(nullify.Fill(feePayContracts), nullify.Fill(resp.FeePayContracts)) + next = resp.Pagination.NextKey + } + }) + + s.Run("Total", func() { + goCtx := sdk.WrapSDKContext(s.ctx) + resp, err := s.queryClient.FeePayContracts(goCtx, request(nil, 0, 0, true)) + s.Require().NoError(err) + s.Require().Equal(len(contractAddressList), int(resp.Pagination.Total)) + s.Require().ElementsMatch(nullify.Fill(feePayContracts), nullify.Fill(resp.FeePayContracts)) + }) +} + +func (s *IntegrationTestSuite) TestQueryEligibility() { + // Get & fund creator + _, _, sender := testdata.KeyTestPubAddr() + _ = s.FundAccount(s.ctx, sender, sdk.NewCoins(sdk.NewCoin("stake", sdk.NewInt(1_000_000)))) + _ = s.FundAccount(s.ctx, sender, sdk.NewCoins(sdk.NewCoin("ujuno", sdk.NewInt(100_000_000)))) + + // Instantiate the contractAddr + contractAddr := s.InstantiateContract(sender.String(), "") + + // Register the fee pay contract + _, err := s.app.AppKeepers.FeePayKeeper.RegisterFeePayContract(s.ctx, &types.MsgRegisterFeePayContract{ + SenderAddress: sender.String(), + FeePayContract: &types.FeePayContract{ + ContractAddress: contractAddr, + WalletLimit: 1, + }, + }) + s.Require().NoError(err) + + s.Run("QueryEligibilityNoFunds", func() { + // Query for the contract + res, err := s.queryClient.FeePayWalletIsEligible(s.ctx, &types.QueryFeePayWalletIsEligible{ + ContractAddress: contractAddr, + WalletAddress: sender.String(), + }) + + // Should error, contract should have no funds + s.Require().Error(err) + s.Require().Nil(res) + }) + + // Add funds + _, err = s.app.AppKeepers.FeePayKeeper.FundFeePayContract(s.ctx, &types.MsgFundFeePayContract{ + SenderAddress: sender.String(), + ContractAddress: contractAddr, + Amount: sdk.NewCoins(sdk.NewCoin("ujuno", sdk.NewInt(1_000_000))), + }) + + s.Run("QueryEligibilityWithFunds", func() { + // Query for the contract + res, err := s.queryClient.FeePayWalletIsEligible(s.ctx, &types.QueryFeePayWalletIsEligible{ + ContractAddress: contractAddr, + WalletAddress: sender.String(), + }) + + // Should error, contract should have no funds + s.Require().NoError(err) + s.Require().NotNil(res) + s.Require().True(res.Eligible) + }) + + // Update usage limit to 0 + _, err = s.app.AppKeepers.FeePayKeeper.UpdateFeePayContractWalletLimit(s.ctx, &types.MsgUpdateFeePayContractWalletLimit{ + SenderAddress: sender.String(), + ContractAddress: contractAddr, + WalletLimit: 0, + }) + + s.Run("QueryEligibilityWithLimit", func() { + // Query for the contract + res, err := s.queryClient.FeePayWalletIsEligible(s.ctx, &types.QueryFeePayWalletIsEligible{ + ContractAddress: contractAddr, + WalletAddress: sender.String(), + }) + + // Should error, wallet exceeded limit of 0 + s.Require().Error(err) + s.Require().Nil(res) + }) +} + +func (s *IntegrationTestSuite) TestQueryUses() { + // Get & fund creator + _, _, sender := testdata.KeyTestPubAddr() + _ = s.FundAccount(s.ctx, sender, sdk.NewCoins(sdk.NewCoin("stake", sdk.NewInt(1_000_000)))) + + // Instantiate the contractAddr + contractAddr := s.InstantiateContract(sender.String(), "") + + // Register the fee pay contract + _, err := s.app.AppKeepers.FeePayKeeper.RegisterFeePayContract(s.ctx, &types.MsgRegisterFeePayContract{ + SenderAddress: sender.String(), + FeePayContract: &types.FeePayContract{ + ContractAddress: contractAddr, + WalletLimit: 1, + }, + }) + s.Require().NoError(err) + + s.Run("QueryUses", func() { + // Query for the contract + res, err := s.queryClient.FeePayContractUses(s.ctx, &types.QueryFeePayContractUses{ + ContractAddress: contractAddr, + WalletAddress: sender.String(), + }) + + // Ensure no error and response is false, contract should have no funds + s.Require().NoError(err) + s.Require().NotNil(res) + s.Require().Equal(uint64(0), res.Uses) + }) +} From 0b8bae7e59ed445449b83ec4a188fe6833a085c2 Mon Sep 17 00:00:00 2001 From: Joel Smith Date: Thu, 5 Oct 2023 21:34:09 -0500 Subject: [PATCH 38/79] Cleanup Query Response Validation --- x/feepay/keeper/querier_test.go | 16 ++++++++++++---- 1 file changed, 12 insertions(+), 4 deletions(-) diff --git a/x/feepay/keeper/querier_test.go b/x/feepay/keeper/querier_test.go index 7ee0e9854..57fdf78c6 100644 --- a/x/feepay/keeper/querier_test.go +++ b/x/feepay/keeper/querier_test.go @@ -38,7 +38,12 @@ func (s *IntegrationTestSuite) TestQueryContract() { // Ensure no error and response exists s.Require().NoError(err) - s.Require().NotNil(res) + s.Require().Equal(res, &types.QueryFeePayContractResponse{ + FeePayContract: &types.FeePayContract{ + ContractAddress: contractAddr, + WalletLimit: 1, + }, + }) }) } @@ -71,7 +76,12 @@ func (s *IntegrationTestSuite) TestQueryContracts() { // Ensure no error and response exists s.Require().NoError(err) - s.Require().NotNil(res) + s.Require().Equal(res, &types.QueryFeePayContractResponse{ + FeePayContract: &types.FeePayContract{ + ContractAddress: contractAddr, + WalletLimit: 1, + }, + }) // Append to lists contractAddressList = append(contractAddressList, contractAddr) @@ -169,7 +179,6 @@ func (s *IntegrationTestSuite) TestQueryEligibility() { // Should error, contract should have no funds s.Require().NoError(err) - s.Require().NotNil(res) s.Require().True(res.Eligible) }) @@ -220,7 +229,6 @@ func (s *IntegrationTestSuite) TestQueryUses() { // Ensure no error and response is false, contract should have no funds s.Require().NoError(err) - s.Require().NotNil(res) s.Require().Equal(uint64(0), res.Uses) }) } From d890568b7a45db43d02ac727603c67ddacb7a951 Mon Sep 17 00:00:00 2001 From: Joel Smith Date: Fri, 6 Oct 2023 15:34:02 -0500 Subject: [PATCH 39/79] Add Genesis Tests --- x/feepay/genesis_test.go | 82 +++++++++++++++++++++++++++++++++++++++- 1 file changed, 81 insertions(+), 1 deletion(-) diff --git a/x/feepay/genesis_test.go b/x/feepay/genesis_test.go index 23d709624..e5b799050 100644 --- a/x/feepay/genesis_test.go +++ b/x/feepay/genesis_test.go @@ -1,3 +1,83 @@ package feepay_test -// x/feeshare +import ( + "fmt" + "testing" + + "github.com/stretchr/testify/suite" + + tmproto "github.com/cometbft/cometbft/proto/tendermint/types" + + sdk "github.com/cosmos/cosmos-sdk/types" + + "github.com/CosmosContracts/juno/v17/app" + "github.com/CosmosContracts/juno/v17/x/feepay" + "github.com/CosmosContracts/juno/v17/x/feepay/types" +) + +type GenesisTestSuite struct { + suite.Suite + + ctx sdk.Context + + app *app.App + genesis types.GenesisState +} + +func TestGenesisTestSuite(t *testing.T) { + suite.Run(t, new(GenesisTestSuite)) +} + +func (suite *GenesisTestSuite) SetupTest() { + app := app.Setup(suite.T()) + ctx := app.BaseApp.NewContext(false, tmproto.Header{ + ChainID: "testing", + }) + + suite.app = app + suite.ctx = ctx + + suite.genesis = *types.DefaultGenesisState() +} + +func (suite *GenesisTestSuite) TestFeeShareInitGenesis() { + testCases := []struct { + name string + genesis types.GenesisState + expPanic bool + }{ + { + "Default Genesis - FeePay Enabled", + suite.genesis, + false, + }, + { + "Custom Genesis - FeePay Disabled", + types.GenesisState{ + Params: types.Params{ + EnableFeepay: false, + }, + }, + false, + }, + } + + for _, tc := range testCases { + suite.Run(fmt.Sprintf("Case %s", tc.name), func() { + suite.SetupTest() // reset + + if tc.expPanic { + suite.Require().Panics(func() { + feepay.InitGenesis(suite.ctx, suite.app.AppKeepers.FeePayKeeper, tc.genesis) + }) + } else { + suite.Require().NotPanics(func() { + feepay.InitGenesis(suite.ctx, suite.app.AppKeepers.FeePayKeeper, tc.genesis) + }) + + params := suite.app.AppKeepers.FeePayKeeper.GetParams(suite.ctx) + suite.Require().Equal(tc.genesis.Params, params) + } + }) + } +} From e9d448736b6fcbd6db20b459b2f82e777d55757d Mon Sep 17 00:00:00 2001 From: Joel Smith Date: Mon, 9 Oct 2023 11:34:30 -0500 Subject: [PATCH 40/79] Add genesis state validation --- proto/juno/feepay/v1/genesis.proto | 3 +- x/feepay/genesis.go | 8 ++--- x/feepay/genesis_test.go | 25 +++++--------- x/feepay/types/genesis.go | 21 +++++++++--- x/feepay/types/genesis.pb.go | 54 ++++++++++++++++-------------- 5 files changed, 59 insertions(+), 52 deletions(-) diff --git a/proto/juno/feepay/v1/genesis.proto b/proto/juno/feepay/v1/genesis.proto index cc0a961ff..1d24071d8 100644 --- a/proto/juno/feepay/v1/genesis.proto +++ b/proto/juno/feepay/v1/genesis.proto @@ -10,7 +10,8 @@ message GenesisState { // params are the feepay module parameters Params params = 1 [ (gogoproto.nullable) = false ]; - repeated FeePayContract fee_contract = 2 [ (gogoproto.nullable) = false ]; + // fee_pay_contracts are the feepay module contracts + repeated FeePayContract fee_pay_contracts = 2 [ (gogoproto.nullable) = false ]; } // Params defines the feepay module params diff --git a/x/feepay/genesis.go b/x/feepay/genesis.go index 9aa37ab0b..496b540af 100644 --- a/x/feepay/genesis.go +++ b/x/feepay/genesis.go @@ -17,7 +17,7 @@ func InitGenesis( panic(err) } - for _, feepay := range data.FeeContract { + for _, feepay := range data.FeePayContracts { // TODO: future, add all wallet interactions for exports? k.SetFeePayContract(ctx, feepay) } @@ -26,10 +26,10 @@ func InitGenesis( // ExportGenesis export module state func ExportGenesis(ctx sdk.Context, k keeper.Keeper) *types.GenesisState { params := k.GetParams(ctx) - contract := k.GetAllContracts(ctx) + contracts := k.GetAllContracts(ctx) return &types.GenesisState{ - Params: params, - FeeContract: contract, + Params: params, + FeePayContracts: contracts, } } diff --git a/x/feepay/genesis_test.go b/x/feepay/genesis_test.go index e5b799050..27bab51e1 100644 --- a/x/feepay/genesis_test.go +++ b/x/feepay/genesis_test.go @@ -42,14 +42,12 @@ func (suite *GenesisTestSuite) SetupTest() { func (suite *GenesisTestSuite) TestFeeShareInitGenesis() { testCases := []struct { - name string - genesis types.GenesisState - expPanic bool + name string + genesis types.GenesisState }{ { "Default Genesis - FeePay Enabled", suite.genesis, - false, }, { "Custom Genesis - FeePay Disabled", @@ -58,7 +56,6 @@ func (suite *GenesisTestSuite) TestFeeShareInitGenesis() { EnableFeepay: false, }, }, - false, }, } @@ -66,18 +63,12 @@ func (suite *GenesisTestSuite) TestFeeShareInitGenesis() { suite.Run(fmt.Sprintf("Case %s", tc.name), func() { suite.SetupTest() // reset - if tc.expPanic { - suite.Require().Panics(func() { - feepay.InitGenesis(suite.ctx, suite.app.AppKeepers.FeePayKeeper, tc.genesis) - }) - } else { - suite.Require().NotPanics(func() { - feepay.InitGenesis(suite.ctx, suite.app.AppKeepers.FeePayKeeper, tc.genesis) - }) - - params := suite.app.AppKeepers.FeePayKeeper.GetParams(suite.ctx) - suite.Require().Equal(tc.genesis.Params, params) - } + suite.Require().NotPanics(func() { + feepay.InitGenesis(suite.ctx, suite.app.AppKeepers.FeePayKeeper, tc.genesis) + }) + + params := suite.app.AppKeepers.FeePayKeeper.GetParams(suite.ctx) + suite.Require().Equal(tc.genesis.Params, params) }) } } diff --git a/x/feepay/types/genesis.go b/x/feepay/types/genesis.go index 23c9e7d80..5501776a1 100644 --- a/x/feepay/types/genesis.go +++ b/x/feepay/types/genesis.go @@ -1,10 +1,12 @@ package types +import sdk "github.com/cosmos/cosmos-sdk/types" + // NewGenesisState creates a new genesis state. -func NewGenesisState(params Params, feecontract []FeePayContract) GenesisState { +func NewGenesisState(params Params, feePayContracts []FeePayContract) GenesisState { return GenesisState{ - Params: params, - FeeContract: feecontract, + Params: params, + FeePayContracts: feePayContracts, } } @@ -15,12 +17,23 @@ func DefaultGenesisState() *GenesisState { Params: Params{ EnableFeepay: true, }, - FeeContract: []FeePayContract{}, + FeePayContracts: []FeePayContract{}, } } // Validate performs basic genesis state validation returning an error upon any // failure. func (gs GenesisState) Validate() error { + // Loop through all fee pay contracts and validate they + // have a valid bech32 address + for _, contract := range gs.FeePayContracts { + + _, err := sdk.AccAddressFromBech32(contract.ContractAddress) + + if err != nil { + return err + } + } + return nil } diff --git a/x/feepay/types/genesis.pb.go b/x/feepay/types/genesis.pb.go index ab99c7416..b09b51576 100644 --- a/x/feepay/types/genesis.pb.go +++ b/x/feepay/types/genesis.pb.go @@ -26,8 +26,9 @@ const _ = proto.GoGoProtoPackageIsVersion3 // please upgrade the proto package // GenesisState defines the module's genesis state. type GenesisState struct { // params are the feepay module parameters - Params Params `protobuf:"bytes,1,opt,name=params,proto3" json:"params"` - FeeContract []FeePayContract `protobuf:"bytes,2,rep,name=fee_contract,json=feeContract,proto3" json:"fee_contract"` + Params Params `protobuf:"bytes,1,opt,name=params,proto3" json:"params"` + // fee_pay_contracts are the feepay module contracts + FeePayContracts []FeePayContract `protobuf:"bytes,2,rep,name=fee_pay_contracts,json=feePayContracts,proto3" json:"fee_pay_contracts"` } func (m *GenesisState) Reset() { *m = GenesisState{} } @@ -70,9 +71,9 @@ func (m *GenesisState) GetParams() Params { return Params{} } -func (m *GenesisState) GetFeeContract() []FeePayContract { +func (m *GenesisState) GetFeePayContracts() []FeePayContract { if m != nil { - return m.FeeContract + return m.FeePayContracts } return nil } @@ -131,24 +132,25 @@ func init() { func init() { proto.RegisterFile("juno/feepay/v1/genesis.proto", fileDescriptor_ac1bd21601b5f553) } var fileDescriptor_ac1bd21601b5f553 = []byte{ - // 271 bytes of a gzipped FileDescriptorProto + // 274 bytes of a gzipped FileDescriptorProto 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xe2, 0x92, 0xc9, 0x2a, 0xcd, 0xcb, 0xd7, 0x4f, 0x4b, 0x4d, 0x2d, 0x48, 0xac, 0xd4, 0x2f, 0x33, 0xd4, 0x4f, 0x4f, 0xcd, 0x4b, 0x2d, 0xce, 0x2c, 0xd6, 0x2b, 0x28, 0xca, 0x2f, 0xc9, 0x17, 0xe2, 0x03, 0xc9, 0xea, 0x41, 0x64, 0xf5, 0xca, 0x0c, 0xa5, 0xa4, 0xd1, 0x54, 0x43, 0x65, 0xc0, 0x8a, 0xa5, 0x44, 0xd2, 0xf3, 0xd3, 0xf3, - 0xc1, 0x4c, 0x7d, 0x10, 0x0b, 0x22, 0xaa, 0xd4, 0xcb, 0xc8, 0xc5, 0xe3, 0x0e, 0x31, 0x34, 0xb8, - 0x24, 0xb1, 0x24, 0x55, 0xc8, 0x84, 0x8b, 0xad, 0x20, 0xb1, 0x28, 0x31, 0xb7, 0x58, 0x82, 0x51, - 0x81, 0x51, 0x83, 0xdb, 0x48, 0x4c, 0x0f, 0xd5, 0x12, 0xbd, 0x00, 0xb0, 0xac, 0x13, 0xcb, 0x89, - 0x7b, 0xf2, 0x0c, 0x41, 0x50, 0xb5, 0x42, 0xee, 0x5c, 0x3c, 0x69, 0xa9, 0xa9, 0xf1, 0xc9, 0xf9, - 0x79, 0x25, 0x45, 0x89, 0xc9, 0x25, 0x12, 0x4c, 0x0a, 0xcc, 0x1a, 0xdc, 0x46, 0x72, 0xe8, 0x7a, - 0xdd, 0x52, 0x53, 0x03, 0x12, 0x2b, 0x9d, 0xa1, 0xaa, 0xa0, 0x66, 0x70, 0xa7, 0xa5, 0xa6, 0xc2, - 0x84, 0x94, 0x74, 0xb9, 0xd8, 0x20, 0x16, 0x08, 0x29, 0x73, 0xf1, 0xa6, 0xe6, 0x25, 0x26, 0xe5, - 0xa4, 0xc6, 0x43, 0xf4, 0x83, 0xdd, 0xc3, 0x11, 0xc4, 0x03, 0x11, 0x74, 0x03, 0x8b, 0x39, 0x79, - 0x9c, 0x78, 0x24, 0xc7, 0x78, 0xe1, 0x91, 0x1c, 0xe3, 0x83, 0x47, 0x72, 0x8c, 0x13, 0x1e, 0xcb, - 0x31, 0x5c, 0x78, 0x2c, 0xc7, 0x70, 0xe3, 0xb1, 0x1c, 0x43, 0x94, 0x5e, 0x7a, 0x66, 0x49, 0x46, - 0x69, 0x92, 0x5e, 0x72, 0x7e, 0xae, 0xbe, 0x73, 0x7e, 0x71, 0x6e, 0x7e, 0x31, 0xcc, 0x8e, 0x62, - 0x7d, 0x70, 0x30, 0x55, 0xc0, 0x02, 0xaa, 0xa4, 0xb2, 0x20, 0xb5, 0x38, 0x89, 0x0d, 0x1c, 0x1e, - 0xc6, 0x80, 0x00, 0x00, 0x00, 0xff, 0xff, 0x35, 0xf0, 0xde, 0xa1, 0x72, 0x01, 0x00, 0x00, + 0xc1, 0x4c, 0x7d, 0x10, 0x0b, 0x22, 0xaa, 0x34, 0x8d, 0x91, 0x8b, 0xc7, 0x1d, 0x62, 0x68, 0x70, + 0x49, 0x62, 0x49, 0xaa, 0x90, 0x09, 0x17, 0x5b, 0x41, 0x62, 0x51, 0x62, 0x6e, 0xb1, 0x04, 0xa3, + 0x02, 0xa3, 0x06, 0xb7, 0x91, 0x98, 0x1e, 0xaa, 0x25, 0x7a, 0x01, 0x60, 0x59, 0x27, 0x96, 0x13, + 0xf7, 0xe4, 0x19, 0x82, 0xa0, 0x6a, 0x85, 0x02, 0xb8, 0x04, 0xd3, 0x52, 0x53, 0xe3, 0x0b, 0x12, + 0x2b, 0xe3, 0x93, 0xf3, 0xf3, 0x4a, 0x8a, 0x12, 0x93, 0x4b, 0x8a, 0x25, 0x98, 0x14, 0x98, 0x35, + 0xb8, 0x8d, 0xe4, 0xd0, 0x0d, 0x70, 0x4b, 0x4d, 0x0d, 0x48, 0xac, 0x74, 0x86, 0x2a, 0x83, 0x1a, + 0xc4, 0x9f, 0x86, 0x22, 0x5a, 0xac, 0xa4, 0xcb, 0xc5, 0x06, 0xb1, 0x49, 0x48, 0x99, 0x8b, 0x37, + 0x35, 0x2f, 0x31, 0x29, 0x27, 0x35, 0x1e, 0x62, 0x06, 0xd8, 0x61, 0x1c, 0x41, 0x3c, 0x10, 0x41, + 0x37, 0xb0, 0x98, 0x93, 0xc7, 0x89, 0x47, 0x72, 0x8c, 0x17, 0x1e, 0xc9, 0x31, 0x3e, 0x78, 0x24, + 0xc7, 0x38, 0xe1, 0xb1, 0x1c, 0xc3, 0x85, 0xc7, 0x72, 0x0c, 0x37, 0x1e, 0xcb, 0x31, 0x44, 0xe9, + 0xa5, 0x67, 0x96, 0x64, 0x94, 0x26, 0xe9, 0x25, 0xe7, 0xe7, 0xea, 0x3b, 0xe7, 0x17, 0xe7, 0xe6, + 0x17, 0xc3, 0x2d, 0xd1, 0x07, 0x87, 0x57, 0x05, 0x2c, 0xc4, 0x4a, 0x2a, 0x0b, 0x52, 0x8b, 0x93, + 0xd8, 0xc0, 0x01, 0x63, 0x0c, 0x08, 0x00, 0x00, 0xff, 0xff, 0xde, 0x9d, 0xea, 0xfc, 0x7b, 0x01, + 0x00, 0x00, } func (m *GenesisState) Marshal() (dAtA []byte, err error) { @@ -171,10 +173,10 @@ func (m *GenesisState) MarshalToSizedBuffer(dAtA []byte) (int, error) { _ = i var l int _ = l - if len(m.FeeContract) > 0 { - for iNdEx := len(m.FeeContract) - 1; iNdEx >= 0; iNdEx-- { + if len(m.FeePayContracts) > 0 { + for iNdEx := len(m.FeePayContracts) - 1; iNdEx >= 0; iNdEx-- { { - size, err := m.FeeContract[iNdEx].MarshalToSizedBuffer(dAtA[:i]) + size, err := m.FeePayContracts[iNdEx].MarshalToSizedBuffer(dAtA[:i]) if err != nil { return 0, err } @@ -250,8 +252,8 @@ func (m *GenesisState) Size() (n int) { _ = l l = m.Params.Size() n += 1 + l + sovGenesis(uint64(l)) - if len(m.FeeContract) > 0 { - for _, e := range m.FeeContract { + if len(m.FeePayContracts) > 0 { + for _, e := range m.FeePayContracts { l = e.Size() n += 1 + l + sovGenesis(uint64(l)) } @@ -341,7 +343,7 @@ func (m *GenesisState) Unmarshal(dAtA []byte) error { iNdEx = postIndex case 2: if wireType != 2 { - return fmt.Errorf("proto: wrong wireType = %d for field FeeContract", wireType) + return fmt.Errorf("proto: wrong wireType = %d for field FeePayContracts", wireType) } var msglen int for shift := uint(0); ; shift += 7 { @@ -368,8 +370,8 @@ func (m *GenesisState) Unmarshal(dAtA []byte) error { if postIndex > l { return io.ErrUnexpectedEOF } - m.FeeContract = append(m.FeeContract, FeePayContract{}) - if err := m.FeeContract[len(m.FeeContract)-1].Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + m.FeePayContracts = append(m.FeePayContracts, FeePayContract{}) + if err := m.FeePayContracts[len(m.FeePayContracts)-1].Unmarshal(dAtA[iNdEx:postIndex]); err != nil { return err } iNdEx = postIndex From 808d6be19635db2b4e202454c4f434255e2bb22c Mon Sep 17 00:00:00 2001 From: Joel Smith Date: Mon, 9 Oct 2023 12:51:59 -0500 Subject: [PATCH 41/79] Add Contract Registration Helper --- x/feepay/keeper/keeper_test.go | 12 +++++++ x/feepay/keeper/msg_server_test.go | 50 ++++-------------------------- x/feepay/keeper/querier_test.go | 44 +++++--------------------- 3 files changed, 26 insertions(+), 80 deletions(-) diff --git a/x/feepay/keeper/keeper_test.go b/x/feepay/keeper/keeper_test.go index 3ed66f538..b28027744 100644 --- a/x/feepay/keeper/keeper_test.go +++ b/x/feepay/keeper/keeper_test.go @@ -114,3 +114,15 @@ func (s *IntegrationTestSuite) InstantiateContract(sender string, admin string) return result.Address } + +// Helper method for quickly registering a fee pay contract +func (s *IntegrationTestSuite) registerFeePayContract(senderAddress string, contractAddress string, walletLimit uint64) { + _, err := s.app.AppKeepers.FeePayKeeper.RegisterFeePayContract(s.ctx, &types.MsgRegisterFeePayContract{ + SenderAddress: senderAddress, + FeePayContract: &types.FeePayContract{ + ContractAddress: contractAddress, + WalletLimit: walletLimit, + }, + }) + s.Require().NoError(err) +} diff --git a/x/feepay/keeper/msg_server_test.go b/x/feepay/keeper/msg_server_test.go index 298e9d93e..98f4d28c4 100644 --- a/x/feepay/keeper/msg_server_test.go +++ b/x/feepay/keeper/msg_server_test.go @@ -92,23 +92,8 @@ func (s *IntegrationTestSuite) TestUnregisterFeePayContract() { creatorContract := s.InstantiateContract(sender.String(), "") adminContract := s.InstantiateContract(sender.String(), admin.String()) - _, err := s.app.AppKeepers.FeePayKeeper.RegisterFeePayContract(s.ctx, &types.MsgRegisterFeePayContract{ - SenderAddress: sender.String(), - FeePayContract: &types.FeePayContract{ - ContractAddress: creatorContract, - WalletLimit: 1, - }, - }) - s.Require().NoError(err) - - _, err = s.app.AppKeepers.FeePayKeeper.RegisterFeePayContract(s.ctx, &types.MsgRegisterFeePayContract{ - SenderAddress: admin.String(), - FeePayContract: &types.FeePayContract{ - ContractAddress: adminContract, - WalletLimit: 0, - }, - }) - s.Require().NoError(err) + s.registerFeePayContract(sender.String(), creatorContract, 1) + s.registerFeePayContract(admin.String(), adminContract, 0) for _, tc := range []struct { desc string @@ -173,20 +158,12 @@ func (s *IntegrationTestSuite) TestUnregisterFeePayContract() { func (s *IntegrationTestSuite) TestFundFeePayContract() { _, _, sender := testdata.KeyTestPubAddr() _, _, admin := testdata.KeyTestPubAddr() - _ = s.FundAccount(s.ctx, sender, sdk.NewCoins(sdk.NewCoin("stake", sdk.NewInt(1_000_000)))) - _ = s.FundAccount(s.ctx, sender, sdk.NewCoins(sdk.NewCoin("ujuno", sdk.NewInt(100_000_000)))) + _ = s.FundAccount(s.ctx, sender, sdk.NewCoins(sdk.NewCoin("stake", sdk.NewInt(1_000_000)), sdk.NewCoin("ujuno", sdk.NewInt(100_000_000)))) _ = s.FundAccount(s.ctx, admin, sdk.NewCoins(sdk.NewCoin("stake", sdk.NewInt(1_000_000)))) contract := s.InstantiateContract(sender.String(), "") - err := s.app.AppKeepers.FeePayKeeper.RegisterContract(s.ctx, &types.MsgRegisterFeePayContract{ - SenderAddress: sender.String(), - FeePayContract: &types.FeePayContract{ - ContractAddress: contract, - WalletLimit: 1, - }, - }) - s.Require().NoError(err) + s.registerFeePayContract(sender.String(), contract, 1) for _, tc := range []struct { desc string @@ -259,23 +236,8 @@ func (s *IntegrationTestSuite) TestUpdateFeePayContractWalletLimit() { creatorContract := s.InstantiateContract(sender.String(), "") adminContract := s.InstantiateContract(sender.String(), admin.String()) - _, err := s.app.AppKeepers.FeePayKeeper.RegisterFeePayContract(s.ctx, &types.MsgRegisterFeePayContract{ - SenderAddress: sender.String(), - FeePayContract: &types.FeePayContract{ - ContractAddress: creatorContract, - WalletLimit: 1, - }, - }) - s.Require().NoError(err) - - _, err = s.app.AppKeepers.FeePayKeeper.RegisterFeePayContract(s.ctx, &types.MsgRegisterFeePayContract{ - SenderAddress: admin.String(), - FeePayContract: &types.FeePayContract{ - ContractAddress: adminContract, - WalletLimit: 0, - }, - }) - s.Require().NoError(err) + s.registerFeePayContract(sender.String(), creatorContract, 1) + s.registerFeePayContract(admin.String(), adminContract, 0) for _, tc := range []struct { desc string diff --git a/x/feepay/keeper/querier_test.go b/x/feepay/keeper/querier_test.go index 57fdf78c6..f8f7e5a08 100644 --- a/x/feepay/keeper/querier_test.go +++ b/x/feepay/keeper/querier_test.go @@ -20,15 +20,7 @@ func (s *IntegrationTestSuite) TestQueryContract() { // Instantiate the contractAddr contractAddr := s.InstantiateContract(sender.String(), "") - // Register the fee pay contract - _, err := s.app.AppKeepers.FeePayKeeper.RegisterFeePayContract(s.ctx, &types.MsgRegisterFeePayContract{ - SenderAddress: sender.String(), - FeePayContract: &types.FeePayContract{ - ContractAddress: contractAddr, - WalletLimit: 1, - }, - }) - s.Require().NoError(err) + s.registerFeePayContract(sender.String(), contractAddr, 1) s.Run("QueryContract", func() { // Query for the contract @@ -60,14 +52,7 @@ func (s *IntegrationTestSuite) TestQueryContracts() { contractAddr := s.InstantiateContract(sender.String(), "") // Register the fee pay contract - _, err := s.app.AppKeepers.FeePayKeeper.RegisterFeePayContract(s.ctx, &types.MsgRegisterFeePayContract{ - SenderAddress: sender.String(), - FeePayContract: &types.FeePayContract{ - ContractAddress: contractAddr, - WalletLimit: 1, - }, - }) - s.Require().NoError(err) + s.registerFeePayContract(sender.String(), contractAddr, 1) // Query for the contract res, err := s.queryClient.FeePayContract(s.ctx, &types.QueryFeePayContract{ @@ -135,21 +120,13 @@ func (s *IntegrationTestSuite) TestQueryContracts() { func (s *IntegrationTestSuite) TestQueryEligibility() { // Get & fund creator _, _, sender := testdata.KeyTestPubAddr() - _ = s.FundAccount(s.ctx, sender, sdk.NewCoins(sdk.NewCoin("stake", sdk.NewInt(1_000_000)))) - _ = s.FundAccount(s.ctx, sender, sdk.NewCoins(sdk.NewCoin("ujuno", sdk.NewInt(100_000_000)))) + _ = s.FundAccount(s.ctx, sender, sdk.NewCoins(sdk.NewCoin("stake", sdk.NewInt(1_000_000)), sdk.NewCoin("ujuno", sdk.NewInt(100_000_000)))) // Instantiate the contractAddr contractAddr := s.InstantiateContract(sender.String(), "") // Register the fee pay contract - _, err := s.app.AppKeepers.FeePayKeeper.RegisterFeePayContract(s.ctx, &types.MsgRegisterFeePayContract{ - SenderAddress: sender.String(), - FeePayContract: &types.FeePayContract{ - ContractAddress: contractAddr, - WalletLimit: 1, - }, - }) - s.Require().NoError(err) + s.registerFeePayContract(sender.String(), contractAddr, 1) s.Run("QueryEligibilityNoFunds", func() { // Query for the contract @@ -164,11 +141,12 @@ func (s *IntegrationTestSuite) TestQueryEligibility() { }) // Add funds - _, err = s.app.AppKeepers.FeePayKeeper.FundFeePayContract(s.ctx, &types.MsgFundFeePayContract{ + _, err := s.app.AppKeepers.FeePayKeeper.FundFeePayContract(s.ctx, &types.MsgFundFeePayContract{ SenderAddress: sender.String(), ContractAddress: contractAddr, Amount: sdk.NewCoins(sdk.NewCoin("ujuno", sdk.NewInt(1_000_000))), }) + s.Require().NoError(err) s.Run("QueryEligibilityWithFunds", func() { // Query for the contract @@ -188,6 +166,7 @@ func (s *IntegrationTestSuite) TestQueryEligibility() { ContractAddress: contractAddr, WalletLimit: 0, }) + s.Require().NoError(err) s.Run("QueryEligibilityWithLimit", func() { // Query for the contract @@ -211,14 +190,7 @@ func (s *IntegrationTestSuite) TestQueryUses() { contractAddr := s.InstantiateContract(sender.String(), "") // Register the fee pay contract - _, err := s.app.AppKeepers.FeePayKeeper.RegisterFeePayContract(s.ctx, &types.MsgRegisterFeePayContract{ - SenderAddress: sender.String(), - FeePayContract: &types.FeePayContract{ - ContractAddress: contractAddr, - WalletLimit: 1, - }, - }) - s.Require().NoError(err) + s.registerFeePayContract(sender.String(), contractAddr, 1) s.Run("QueryUses", func() { // Query for the contract From ab03d6ce12eeebb624a2380c6dad7fbac0db152b Mon Sep 17 00:00:00 2001 From: Reece Williams Date: Mon, 9 Oct 2023 13:02:11 -0500 Subject: [PATCH 42/79] update ictest to latest v7 + PR 810 backport --- interchaintest/contract_unity_submit_test.go | 3 +- interchaintest/go.mod | 99 +++---- interchaintest/go.sum | 246 ++++++++++-------- interchaintest/ibc_transfer_test.go | 5 +- interchaintest/module_drip_test.go | 7 +- interchaintest/module_feeshare_test.go | 4 +- interchaintest/module_ibchooks_test.go | 3 +- interchaintest/module_pfm_test.go | 5 +- ...pob_test.go => module_pob_test.go.archive} | 3 + interchaintest/module_tokenfactory_test.go | 6 +- 10 files changed, 213 insertions(+), 168 deletions(-) rename interchaintest/{module_pob_test.go => module_pob_test.go.archive} (83%) diff --git a/interchaintest/contract_unity_submit_test.go b/interchaintest/contract_unity_submit_test.go index c5416f1dc..882242fa8 100644 --- a/interchaintest/contract_unity_submit_test.go +++ b/interchaintest/contract_unity_submit_test.go @@ -4,6 +4,7 @@ import ( "fmt" "testing" + "cosmossdk.io/math" wasmtypes "github.com/CosmWasm/wasmd/x/wasm/types" "github.com/strangelove-ventures/interchaintest/v7" "github.com/strangelove-ventures/interchaintest/v7/chain/cosmos" @@ -41,7 +42,7 @@ func TestJunoUnityContractGovSubmit(t *testing.T) { t.Log("testing Unity contractAddr", contractAddr) // send 2JUNO funds to the contract from user - juno.SendFunds(ctx, user.KeyName(), ibc.WalletAmount{Address: contractAddr, Denom: nativeDenom, Amount: 2000000}) + juno.SendFunds(ctx, user.KeyName(), ibc.WalletAmount{Address: contractAddr, Denom: nativeDenom, Amount: math.NewInt(2000000)}) height, err := juno.Height(ctx) require.NoError(t, err, "error fetching height") diff --git a/interchaintest/go.mod b/interchaintest/go.mod index a3820e9be..4cb1820b1 100644 --- a/interchaintest/go.mod +++ b/interchaintest/go.mod @@ -18,14 +18,16 @@ replace ( require ( github.com/CosmWasm/wasmd v0.41.0 github.com/CosmosContracts/juno/v17 v17.0.0-00010101000000-000000000000 - github.com/cosmos/cosmos-sdk v0.47.4 + github.com/cosmos/cosmos-sdk v0.47.5 github.com/cosmos/gogoproto v1.4.10 - github.com/cosmos/ibc-go/v7 v7.2.0 - github.com/docker/docker v24.0.4+incompatible - github.com/skip-mev/pob/tests/integration v0.1.0 - github.com/strangelove-ventures/interchaintest/v7 v7.0.0-20230721183422-fb937bb0e165 + github.com/cosmos/ibc-go/v7 v7.3.0 + github.com/docker/docker v24.0.5+incompatible + // github.com/skip-mev/pob/tests/integration v0.1.0 // TODO: does not return a math.Int + // origin/reece/juno-pr810 + // go get github.com/strangelove-ventures/interchaintest/v7@4e98e35e363e84ffea18c1e74c2ebb2b51bf97ff + github.com/strangelove-ventures/interchaintest/v7 v7.0.0-20231009173908-4e98e35e363e github.com/stretchr/testify v1.8.4 - go.uber.org/zap v1.24.0 + go.uber.org/zap v1.25.0 ) @@ -37,10 +39,10 @@ require ( cloud.google.com/go/storage v1.30.1 // indirect cosmossdk.io/api v0.3.1 // indirect cosmossdk.io/core v0.6.1 // indirect - cosmossdk.io/depinject v1.0.0-alpha.3 // indirect + cosmossdk.io/depinject v1.0.0-alpha.4 // indirect cosmossdk.io/errors v1.0.0 // indirect - cosmossdk.io/log v1.1.1-0.20230704160919-88f2c830b0ca // indirect - cosmossdk.io/math v1.0.1 // indirect + cosmossdk.io/log v1.2.1 // indirect + cosmossdk.io/math v1.1.2 cosmossdk.io/tools/rosetta v0.2.1 // indirect filippo.io/edwards25519 v1.0.0 // indirect github.com/99designs/go-keychain v0.0.0-20191008050251-8e49817e8af4 // indirect @@ -55,7 +57,7 @@ require ( github.com/Microsoft/go-winio v0.6.0 // indirect github.com/StirlingMarketingGroup/go-namecase v1.0.0 // indirect github.com/armon/go-metrics v0.4.1 // indirect - github.com/avast/retry-go/v4 v4.3.4 // indirect + github.com/avast/retry-go/v4 v4.5.0 // indirect github.com/aws/aws-sdk-go v1.44.203 // indirect github.com/benbjohnson/clock v1.3.0 // indirect github.com/beorn7/perks v1.0.1 // indirect @@ -67,6 +69,9 @@ require ( github.com/cespare/xxhash v1.1.0 // indirect github.com/cespare/xxhash/v2 v2.2.0 // indirect github.com/chzyer/readline v1.5.1 // indirect + github.com/cockroachdb/errors v1.10.0 // indirect + github.com/cockroachdb/logtags v0.0.0-20230118201751-21c54148d20b // indirect + github.com/cockroachdb/redact v1.1.5 // indirect github.com/coinbase/rosetta-sdk-go/types v1.0.0 // indirect github.com/cometbft/cometbft v0.37.2 // indirect github.com/cometbft/cometbft-db v0.8.0 // indirect @@ -76,17 +81,18 @@ require ( github.com/cosmos/go-bip39 v1.0.0 // indirect github.com/cosmos/gogogateway v1.2.0 // indirect github.com/cosmos/iavl v0.20.0 // indirect + github.com/cosmos/ibc-go/modules/capability v1.0.0-rc1 // indirect github.com/cosmos/ics23/go v0.10.0 // indirect - github.com/cosmos/ledger-cosmos-go v0.12.2 // indirect + github.com/cosmos/ledger-cosmos-go v0.13.0 // indirect github.com/cosmos/rosetta-sdk-go v0.10.0 // indirect github.com/creachadair/taskgroup v0.4.2 // indirect github.com/danieljoos/wincred v1.1.2 // indirect github.com/davecgh/go-spew v1.1.1 // indirect github.com/deckarep/golang-set v1.8.0 // indirect github.com/decred/base58 v1.0.4 // indirect - github.com/decred/dcrd/crypto/blake256 v1.0.0 // indirect + github.com/decred/dcrd/crypto/blake256 v1.0.1 // indirect github.com/decred/dcrd/dcrec/secp256k1/v2 v2.0.1 // indirect - github.com/decred/dcrd/dcrec/secp256k1/v4 v4.1.0 // indirect + github.com/decred/dcrd/dcrec/secp256k1/v4 v4.2.0 // indirect github.com/desertbit/timer v0.0.0-20180107155436-c41aec40b27f // indirect github.com/dgraph-io/badger/v2 v2.2007.4 // indirect github.com/dgraph-io/ristretto v0.1.1 // indirect @@ -99,10 +105,10 @@ require ( github.com/ethereum/go-ethereum v1.11.6 // indirect github.com/felixge/httpsnoop v1.0.2 // indirect github.com/fsnotify/fsnotify v1.6.0 // indirect + github.com/getsentry/sentry-go v0.23.0 // indirect github.com/go-kit/kit v0.12.0 // indirect github.com/go-kit/log v0.2.1 // indirect github.com/go-logfmt/logfmt v0.6.0 // indirect - github.com/go-playground/locales v0.14.0 // indirect github.com/go-stack/stack v1.8.1 // indirect github.com/godbus/dbus v0.0.0-20190726142602-4481cbc300e2 // indirect github.com/gogo/googleapis v1.4.1 // indirect @@ -122,7 +128,7 @@ require ( github.com/gorilla/handlers v1.5.1 // indirect github.com/gorilla/mux v1.8.0 // indirect github.com/gorilla/websocket v1.5.0 // indirect - github.com/grpc-ecosystem/go-grpc-middleware v1.3.0 // indirect + github.com/grpc-ecosystem/go-grpc-middleware v1.4.0 // indirect github.com/grpc-ecosystem/grpc-gateway v1.16.0 // indirect github.com/gsterjov/go-libsecret v0.0.0-20161001094733-a6f4afe4910c // indirect github.com/gtank/merlin v0.1.1 // indirect @@ -140,22 +146,22 @@ require ( github.com/icza/dyno v0.0.0-20220812133438-f0b6f8a18845 // indirect github.com/improbable-eng/grpc-web v0.15.0 // indirect github.com/inconshreveable/mousetrap v1.1.0 // indirect - github.com/ipfs/go-cid v0.2.0 // indirect + github.com/ipfs/go-cid v0.4.1 // indirect github.com/jmespath/go-jmespath v0.4.0 // indirect github.com/jmhodges/levigo v1.0.0 // indirect github.com/kballard/go-shellquote v0.0.0-20180428030007-95032a82bc51 // indirect - github.com/klauspost/compress v1.16.3 // indirect - github.com/klauspost/cpuid/v2 v2.2.3 // indirect + github.com/klauspost/compress v1.16.7 // indirect + github.com/klauspost/cpuid/v2 v2.2.4 // indirect + github.com/kr/pretty v0.3.1 // indirect + github.com/kr/text v0.2.0 // indirect github.com/lib/pq v1.10.7 // indirect github.com/libp2p/go-buffer-pool v0.1.0 // indirect - github.com/libp2p/go-libp2p v0.22.0 // indirect - github.com/libp2p/go-openssl v0.1.0 // indirect - github.com/linxGnu/grocksdb v1.7.16 // indirect + github.com/libp2p/go-libp2p v0.27.8 // indirect + github.com/linxGnu/grocksdb v1.8.0 // indirect github.com/magiconair/properties v1.8.7 // indirect github.com/manifoldco/promptui v0.9.0 // indirect github.com/mattn/go-colorable v0.1.13 // indirect github.com/mattn/go-isatty v0.0.19 // indirect - github.com/mattn/go-pointer v0.0.1 // indirect github.com/matttproud/golang_protobuf_extensions v1.0.4 // indirect github.com/mimoo/StrobeGo v0.0.0-20220103164710-9a04d6ca976b // indirect github.com/minio/highwayhash v1.0.2 // indirect @@ -166,33 +172,33 @@ require ( github.com/mitchellh/mapstructure v1.5.0 // indirect github.com/mr-tron/base58 v1.2.0 // indirect github.com/mtibben/percent v0.2.1 // indirect - github.com/multiformats/go-base32 v0.0.4 // indirect - github.com/multiformats/go-base36 v0.1.0 // indirect - github.com/multiformats/go-multiaddr v0.6.0 // indirect - github.com/multiformats/go-multibase v0.1.1 // indirect - github.com/multiformats/go-multicodec v0.5.0 // indirect + github.com/multiformats/go-base32 v0.1.0 // indirect + github.com/multiformats/go-base36 v0.2.0 // indirect + github.com/multiformats/go-multiaddr v0.9.0 // indirect + github.com/multiformats/go-multibase v0.2.0 // indirect + github.com/multiformats/go-multicodec v0.8.1 // indirect github.com/multiformats/go-multihash v0.2.1 // indirect - github.com/multiformats/go-varint v0.0.6 // indirect + github.com/multiformats/go-varint v0.0.7 // indirect github.com/opencontainers/go-digest v1.0.0 // indirect github.com/opencontainers/image-spec v1.1.0-rc2 // indirect + github.com/opencontainers/runc v1.1.5 // indirect github.com/pelletier/go-toml v1.9.5 // indirect github.com/pelletier/go-toml/v2 v2.0.9 // indirect - github.com/petermattis/goid v0.0.0-20230317030725-371a4b8eda08 // indirect + github.com/petermattis/goid v0.0.0-20230518223814-80aa455d8761 // indirect github.com/pierrec/xxHash v0.1.5 // indirect github.com/pkg/errors v0.9.1 // indirect github.com/pmezard/go-difflib v1.0.0 // indirect github.com/prometheus/client_golang v1.16.0 // indirect - github.com/prometheus/client_model v0.3.0 // indirect - github.com/prometheus/common v0.42.0 // indirect - github.com/prometheus/procfs v0.10.1 // indirect + github.com/prometheus/client_model v0.4.0 // indirect + github.com/prometheus/common v0.44.0 // indirect + github.com/prometheus/procfs v0.11.0 // indirect github.com/rakyll/statik v0.1.7 // indirect github.com/rcrowley/go-metrics v0.0.0-20201227073835-cf1acfcdf475 // indirect github.com/remyoudompheng/bigfft v0.0.0-20230129092748-24d4a6f8daec // indirect + github.com/rogpeppe/go-internal v1.11.0 // indirect github.com/rs/cors v1.8.3 // indirect - github.com/rs/zerolog v1.29.1 // indirect + github.com/rs/zerolog v1.30.0 // indirect github.com/sasha-s/go-deadlock v0.3.1 // indirect - github.com/skip-mev/pob v1.0.4 // indirect - github.com/spacemonkeygo/spacelog v0.0.0-20180420211403-2296661a0572 // indirect github.com/spaolacci/murmur3 v1.1.0 // indirect github.com/spf13/afero v1.9.5 // indirect github.com/spf13/cast v1.5.1 // indirect @@ -211,18 +217,17 @@ require ( github.com/zondax/ledger-go v0.14.1 // indirect go.etcd.io/bbolt v1.3.7 // indirect go.opencensus.io v0.24.0 // indirect - go.uber.org/atomic v1.10.0 // indirect go.uber.org/multierr v1.11.0 // indirect - golang.org/x/crypto v0.11.0 // indirect - golang.org/x/exp v0.0.0-20230515195305-f3d0a9c9a5cc // indirect + golang.org/x/crypto v0.12.0 // indirect + golang.org/x/exp v0.0.0-20230711153332-06a737ee72cb // indirect golang.org/x/mod v0.12.0 // indirect - golang.org/x/net v0.12.0 // indirect + golang.org/x/net v0.14.0 // indirect golang.org/x/oauth2 v0.8.0 // indirect golang.org/x/sync v0.3.0 // indirect - golang.org/x/sys v0.10.0 // indirect - golang.org/x/term v0.10.0 // indirect - golang.org/x/text v0.11.0 // indirect - golang.org/x/tools v0.11.0 // indirect + golang.org/x/sys v0.11.0 // indirect + golang.org/x/term v0.11.0 // indirect + golang.org/x/text v0.12.0 // indirect + golang.org/x/tools v0.12.0 // indirect golang.org/x/xerrors v0.0.0-20220907171357-04be3eba64a2 // indirect google.golang.org/api v0.126.0 // indirect google.golang.org/appengine v1.6.7 // indirect @@ -239,14 +244,14 @@ require ( lukechampine.com/uint128 v1.2.0 // indirect modernc.org/cc/v3 v3.40.0 // indirect modernc.org/ccgo/v3 v3.16.13 // indirect - modernc.org/libc v1.22.5 // indirect + modernc.org/libc v1.24.1 // indirect modernc.org/mathutil v1.5.0 // indirect - modernc.org/memory v1.5.0 // indirect + modernc.org/memory v1.6.0 // indirect modernc.org/opt v0.1.3 // indirect - modernc.org/sqlite v1.24.0 // indirect + modernc.org/sqlite v1.25.0 // indirect modernc.org/strutil v1.1.3 // indirect modernc.org/token v1.0.1 // indirect nhooyr.io/websocket v1.8.7 // indirect - pgregory.net/rapid v0.5.5 // indirect + pgregory.net/rapid v1.0.0 // indirect sigs.k8s.io/yaml v1.3.0 // indirect ) diff --git a/interchaintest/go.sum b/interchaintest/go.sum index d75160f07..4358a3f2d 100644 --- a/interchaintest/go.sum +++ b/interchaintest/go.sum @@ -191,14 +191,14 @@ cosmossdk.io/api v0.3.1 h1:NNiOclKRR0AOlO4KIqeaG6PS6kswOMhHD0ir0SscNXE= cosmossdk.io/api v0.3.1/go.mod h1:DfHfMkiNA2Uhy8fj0JJlOCYOBp4eWUUJ1te5zBGNyIw= cosmossdk.io/core v0.6.1 h1:OBy7TI2W+/gyn2z40vVvruK3di+cAluinA6cybFbE7s= cosmossdk.io/core v0.6.1/go.mod h1:g3MMBCBXtxbDWBURDVnJE7XML4BG5qENhs0gzkcpuFA= -cosmossdk.io/depinject v1.0.0-alpha.3 h1:6evFIgj//Y3w09bqOUOzEpFj5tsxBqdc5CfkO7z+zfw= -cosmossdk.io/depinject v1.0.0-alpha.3/go.mod h1:eRbcdQ7MRpIPEM5YUJh8k97nxHpYbc3sMUnEtt8HPWU= +cosmossdk.io/depinject v1.0.0-alpha.4 h1:PLNp8ZYAMPTUKyG9IK2hsbciDWqna2z1Wsl98okJopc= +cosmossdk.io/depinject v1.0.0-alpha.4/go.mod h1:HeDk7IkR5ckZ3lMGs/o91AVUc7E596vMaOmslGFM3yU= cosmossdk.io/errors v1.0.0 h1:nxF07lmlBbB8NKQhtJ+sJm6ef5uV1XkvPXG2bUntb04= cosmossdk.io/errors v1.0.0/go.mod h1:+hJZLuhdDE0pYN8HkOrVNwrIOYvUGnn6+4fjnJs/oV0= -cosmossdk.io/log v1.1.1-0.20230704160919-88f2c830b0ca h1:msenprh2BLLRwNT7zN56TbBHOGk/7ARQckXHxXyvjoQ= -cosmossdk.io/log v1.1.1-0.20230704160919-88f2c830b0ca/go.mod h1:PkIAKXZvaxrTRc++z53XMRvFk8AcGGWYHcMIPzVYX9c= -cosmossdk.io/math v1.0.1 h1:Qx3ifyOPaMLNH/89WeZFH268yCvU4xEcnPLu3sJqPPg= -cosmossdk.io/math v1.0.1/go.mod h1:Ygz4wBHrgc7g0N+8+MrnTfS9LLn9aaTGa9hKopuym5k= +cosmossdk.io/log v1.2.1 h1:Xc1GgTCicniwmMiKwDxUjO4eLhPxoVdI9vtMW8Ti/uk= +cosmossdk.io/log v1.2.1/go.mod h1:GNSCc/6+DhFIj1aLn/j7Id7PaO8DzNylUZoOYBL9+I4= +cosmossdk.io/math v1.1.2 h1:ORZetZCTyWkI5GlZ6CZS28fMHi83ZYf+A2vVnHNzZBM= +cosmossdk.io/math v1.1.2/go.mod h1:l2Gnda87F0su8a/7FEKJfFdJrM0JZRXQaohlgJeyQh0= cosmossdk.io/tools/rosetta v0.2.1 h1:ddOMatOH+pbxWbrGJKRAawdBkPYLfKXutK9IETnjYxw= cosmossdk.io/tools/rosetta v0.2.1/go.mod h1:Pqdc1FdvkNV3LcNIkYWt2RQY6IP1ge6YWZk8MhhO9Hw= dmitri.shuralyov.com/gpu/mtl v0.0.0-20190408044501-666a987793e9/go.mod h1:H6x//7gZCb22OMCxBHrMx7a5I7Hp++hsVxbQ4BYO7hU= @@ -243,7 +243,6 @@ github.com/VividCortex/gohistogram v1.0.0 h1:6+hBz+qvs0JOrrNhhmR7lFxo5sINxBCGXrd github.com/VividCortex/gohistogram v1.0.0/go.mod h1:Pf5mBqqDxYaXu3hDrrU+w6nw50o/4+TcAqDqk/vUH7g= github.com/adlio/schema v1.3.3 h1:oBJn8I02PyTB466pZO1UZEn1TV5XLlifBSyMrmHl/1I= github.com/afex/hystrix-go v0.0.0-20180502004556-fa1af6a1f4f5/go.mod h1:SkGFH1ia65gfNATL8TAiHDNxPzPdmEL5uirI2Uyuz6c= -github.com/alecthomas/participle/v2 v2.0.0-alpha7 h1:cK4vjj0VSgb3lN1nuKA5F7dw+1s1pWBe5bx7nNCnN+c= github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc= github.com/alecthomas/template v0.0.0-20190718012654-fb15b899a751/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc= github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0= @@ -259,14 +258,15 @@ github.com/armon/go-metrics v0.4.1 h1:hR91U9KYmb6bLBYLQjyM+3j+rcd/UhE+G78SFnF8gJ github.com/armon/go-metrics v0.4.1/go.mod h1:E6amYzXo6aW1tqzoZGT755KkbgrJsSdpwZ+3JqfkOG4= github.com/armon/go-radix v0.0.0-20180808171621-7fddfc383310/go.mod h1:ufUuZ+zHj4x4TnLV4JWEpy2hxWSpsRywHrMgIH9cCH8= github.com/aryann/difflib v0.0.0-20170710044230-e206f873d14a/go.mod h1:DAHtR1m6lCRdSC2Tm3DSWRPvIPr6xNKyeHdqDQSQT+A= -github.com/avast/retry-go/v4 v4.3.4 h1:pHLkL7jvCvP317I8Ge+Km2Yhntv3SdkJm7uekkqbKhM= -github.com/avast/retry-go/v4 v4.3.4/go.mod h1:rv+Nla6Vk3/ilU0H51VHddWHiwimzX66yZ0JT6T+UvE= +github.com/avast/retry-go/v4 v4.5.0 h1:QoRAZZ90cj5oni2Lsgl2GW8mNTnUCnmpx/iKpwVisHg= +github.com/avast/retry-go/v4 v4.5.0/go.mod h1:7hLEXp0oku2Nir2xBAsg0PTphp9z71bN5Aq1fboC3+I= github.com/aws/aws-lambda-go v1.13.3/go.mod h1:4UKl9IzQMoD+QF79YdCuzCwp8VbmG4VAQwij/eHl5CU= github.com/aws/aws-sdk-go v1.27.0/go.mod h1:KmX6BPdI08NWTb3/sm4ZGu5ShLoqVDhKgpiN924inxo= github.com/aws/aws-sdk-go v1.44.122/go.mod h1:y4AeaBuwd2Lk+GepC1E9v0qOiTws0MIWAX4oIKwKHZo= github.com/aws/aws-sdk-go v1.44.203 h1:pcsP805b9acL3wUqa4JR2vg1k2wnItkDYNvfmcy6F+U= github.com/aws/aws-sdk-go v1.44.203/go.mod h1:aVsgQcEevwlmQ7qHE9I3h+dtQgpqhFB+i8Phjh7fkwI= github.com/aws/aws-sdk-go-v2 v0.18.0/go.mod h1:JWVYvqSMppoMJC0x5wdwiImzgXTI9FuZwxzkQq9wy+g= +github.com/benbjohnson/clock v1.1.0/go.mod h1:J11/hYXuz8f4ySSvYwY0FKfm+ezbsZBKZxNJlLklBHA= github.com/benbjohnson/clock v1.3.0 h1:ip6w0uFQkncKQ979AypyG0ER7mqUSBdKLOgAle/AT8A= github.com/benbjohnson/clock v1.3.0/go.mod h1:J11/hYXuz8f4ySSvYwY0FKfm+ezbsZBKZxNJlLklBHA= github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q= @@ -297,6 +297,7 @@ github.com/cespare/xxhash v1.1.0/go.mod h1:XrSqR1VqqWfGrhpAt58auRo0WTKS1nRRg3ghf github.com/cespare/xxhash/v2 v2.1.1/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= github.com/cespare/xxhash/v2 v2.2.0 h1:DC2CZ1Ep5Y4k3ZQ899DldepgrayRUGE6BBZ/cd9Cj44= github.com/cespare/xxhash/v2 v2.2.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= +github.com/checkpoint-restore/go-criu/v5 v5.3.0/go.mod h1:E/eQpaFtUKGOOSEBZgmKAcn+zUUwWxqcaKZlF54wK8E= github.com/cheggaaa/pb v1.0.27/go.mod h1:pQciLPpbU0oxA0h+VJYYLxO+XeDQb5pZijXscXHm81s= github.com/chzyer/logex v1.1.10/go.mod h1:+Ywpsq7O8HXn0nuIou7OrIPyXbp3wmkHB+jjWRnGsAI= github.com/chzyer/logex v1.2.1 h1:XHDu3E6q+gdHgsdTPH6ImJMIp436vR6MPtH8gP05QzM= @@ -307,6 +308,7 @@ github.com/chzyer/readline v1.5.1/go.mod h1:Eh+b79XXUwfKfcPLepksvw2tcLE/Ct21YObk github.com/chzyer/test v0.0.0-20180213035817-a1ea475d72b1/go.mod h1:Q3SI9o4m/ZMnBNeIyt5eFwwo7qiLfzFZmjNmxjkiQlU= github.com/chzyer/test v1.0.0 h1:p3BQDXSxOhOG0P9z6/hGnII4LGiEPOYBhs8asl/fC04= github.com/chzyer/test v1.0.0/go.mod h1:2JlltgoNkt4TW/z9V/IzDdFaMTM2JPIi26O1pF38GC8= +github.com/cilium/ebpf v0.7.0/go.mod h1:/oI2+1shJiTGAMgl6/RgJr36Eo1jzrRcAWbcXO2usCA= github.com/circonus-labs/circonus-gometrics v2.3.1+incompatible/go.mod h1:nmEj6Dob7S7YxXgwXpfOuvO54S+tGdZdw9fuRZt25Ag= github.com/circonus-labs/circonusllhist v0.1.3/go.mod h1:kMXHVDlOchFAehlya5ePtbp5jckzBHf4XRpQvBOLI+I= github.com/clbanning/x2j v0.0.0-20191024224557-825249438eec/go.mod h1:jMjuTZXRI4dUb/I5gc9Hdhagfvm9+RyrPryS/auMzxE= @@ -323,8 +325,13 @@ github.com/cncf/xds/go v0.0.0-20210922020428-25de7278fc84/go.mod h1:eXthEFrGJvWH github.com/cncf/xds/go v0.0.0-20211001041855-01bcc9b48dfe/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs= github.com/cncf/xds/go v0.0.0-20211011173535-cb28da3451f1/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs= github.com/cockroachdb/apd/v2 v2.0.2 h1:weh8u7Cneje73dDh+2tEVLUvyBc89iwepWCD8b8034E= -github.com/cockroachdb/apd/v3 v3.1.0 h1:MK3Ow7LH0W8zkd5GMKA1PvS9qG3bWFI95WaVNfyZJ/w= github.com/cockroachdb/datadriven v0.0.0-20190809214429-80d97fb3cbaa/go.mod h1:zn76sxSg3SzpJ0PPJaLDCu+Bu0Lg3sKTORVIj19EIF8= +github.com/cockroachdb/errors v1.10.0 h1:lfxS8zZz1+OjtV4MtNWgboi/W5tyLEB6VQZBXN+0VUU= +github.com/cockroachdb/errors v1.10.0/go.mod h1:lknhIsEVQ9Ss/qKDBQS/UqFSvPQjOwNq2qyKAxtHRqE= +github.com/cockroachdb/logtags v0.0.0-20230118201751-21c54148d20b h1:r6VH0faHjZeQy818SGhaone5OnYfxFR/+AzdY3sf5aE= +github.com/cockroachdb/logtags v0.0.0-20230118201751-21c54148d20b/go.mod h1:Vz9DsVWQQhf3vs21MhPMZpMGSht7O/2vFW2xusFUVOs= +github.com/cockroachdb/redact v1.1.5 h1:u1PMllDkdFfPWaNGMyLD1+so+aq3uUItthCFqzwPJ30= +github.com/cockroachdb/redact v1.1.5/go.mod h1:BVNblN9mBWFyMyqK1k3AAiSxhvhfK2oOZZ2lK+dpvRg= github.com/codahale/hdrhistogram v0.0.0-20161010025455-3a0bb77429bd/go.mod h1:sE/e/2PUdi/liOCUjSTXgM1o87ZssimdTWN964YiIeI= github.com/coinbase/rosetta-sdk-go/types v1.0.0 h1:jpVIwLcPoOeCR6o1tU+Xv7r5bMONNbHU7MuEHboiFuA= github.com/coinbase/rosetta-sdk-go/types v1.0.0/go.mod h1:eq7W2TMRH22GTW0N0beDnN931DW0/WOI1R2sdHNHG4c= @@ -334,19 +341,21 @@ github.com/cometbft/cometbft-db v0.8.0 h1:vUMDaH3ApkX8m0KZvOFFy9b5DZHBAjsnEuo9AK github.com/cometbft/cometbft-db v0.8.0/go.mod h1:6ASCP4pfhmrCBpfk01/9E1SI29nD3HfVHrY4PG8x5c0= github.com/confio/ics23/go v0.9.0 h1:cWs+wdbS2KRPZezoaaj+qBleXgUk5WOQFMP3CQFGTr4= github.com/confio/ics23/go v0.9.0/go.mod h1:4LPZ2NYqnYIVRklaozjNR1FScgDJ2s5Xrp+e/mYVRak= +github.com/containerd/console v1.0.3/go.mod h1:7LqA/THxQ86k76b8c/EMSiaJ3h1eZkMkXar0TQ1gf3U= github.com/containerd/continuity v0.3.0 h1:nisirsYROK15TAMVukJOUyGJjz4BNQJBVsNvAXZJ/eg= github.com/coreos/etcd v3.3.10+incompatible/go.mod h1:uF7uidLiAD3TWHmW31ZFd/JWoc32PjwdhPthX9715RE= github.com/coreos/go-etcd v2.0.0+incompatible/go.mod h1:Jez6KQU2B/sWsbdaef3ED8NzMklzPG4d5KIOhIy30Tk= github.com/coreos/go-semver v0.2.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3EedlOD2RNk= github.com/coreos/go-systemd v0.0.0-20180511133405-39ca1b05acc7/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4= +github.com/coreos/go-systemd/v22 v22.3.2/go.mod h1:Y58oyj3AT4RCenI/lSvhwexgC+NSVTIJ3seZv2GcEnc= github.com/coreos/go-systemd/v22 v22.5.0/go.mod h1:Y58oyj3AT4RCenI/lSvhwexgC+NSVTIJ3seZv2GcEnc= github.com/coreos/pkg v0.0.0-20160727233714-3ac0863d7acf/go.mod h1:E3G3o1h8I7cfcXa63jLwjI0eiQQMgzzUDFVpN/nH/eA= github.com/cosmos/btcutil v1.0.5 h1:t+ZFcX77LpKtDBhjucvnOH8C2l2ioGsBNEQ3jef8xFk= github.com/cosmos/btcutil v1.0.5/go.mod h1:IyB7iuqZMJlthe2tkIFL33xPyzbFYP0XVdS8P5lUPis= github.com/cosmos/cosmos-proto v1.0.0-beta.3 h1:VitvZ1lPORTVxkmF2fAp3IiA61xVwArQYKXTdEcpW6o= github.com/cosmos/cosmos-proto v1.0.0-beta.3/go.mod h1:t8IASdLaAq+bbHbjq4p960BvcTqtwuAxid3b/2rOD6I= -github.com/cosmos/cosmos-sdk v0.47.4 h1:FVUpEprm58nMmBX4xkRdMDaIG5Nr4yy92HZAfGAw9bg= -github.com/cosmos/cosmos-sdk v0.47.4/go.mod h1:R5n+uM7vguVPFap4pgkdvQCT1nVo/OtPwrlAU40rvok= +github.com/cosmos/cosmos-sdk v0.47.5 h1:n1+WjP/VM/gAEOx3TqU2/Ny734rj/MX1kpUnn7zVJP8= +github.com/cosmos/cosmos-sdk v0.47.5/go.mod h1:EHwCeN9IXonsjKcjpS12MqeStdZvIdxt3VYXhus3G3c= github.com/cosmos/go-bip39 v0.0.0-20180819234021-555e2067c45d/go.mod h1:tSxLoYXyBmiFeKpvmq4dzayMdCjCnu8uqmCysIGBT2Y= github.com/cosmos/go-bip39 v1.0.0 h1:pcomnQdrdH22njcAatO0yWojsUnCO3y2tNoV1cb6hHY= github.com/cosmos/go-bip39 v1.0.0/go.mod h1:RNJv0H/pOIVgxw6KS7QeX2a0Uo0aKUlfhZ4xuwvCdJw= @@ -357,12 +366,14 @@ github.com/cosmos/gogoproto v1.4.10 h1:QH/yT8X+c0F4ZDacDv3z+xE3WU1P1Z3wQoLMBRJoK github.com/cosmos/gogoproto v1.4.10/go.mod h1:3aAZzeRWpAwr+SS/LLkICX2/kDFyaYVzckBDzygIxek= github.com/cosmos/iavl v0.20.0 h1:fTVznVlepH0KK8NyKq8w+U7c2L6jofa27aFX6YGlm38= github.com/cosmos/iavl v0.20.0/go.mod h1:WO7FyvaZJoH65+HFOsDir7xU9FWk2w9cHXNW1XHcl7A= -github.com/cosmos/ibc-go/v7 v7.2.0 h1:dx0DLUl7rxdyZ8NiT6UsrbzKOJx/w7s+BOaewFRH6cg= -github.com/cosmos/ibc-go/v7 v7.2.0/go.mod h1:OOcjKIRku/j1Xs1RgKK0yvKRrJ5iFuZYMetR1n3yMlc= +github.com/cosmos/ibc-go/modules/capability v1.0.0-rc1 h1:BvSKnPFKxL+TTSLxGKwJN4x0ndCZj0yfXhSvmsQztSA= +github.com/cosmos/ibc-go/modules/capability v1.0.0-rc1/go.mod h1:A+CxAQdn2j6ihDTbClpEEBdHthWgAUAcHbRAQPY8sl4= +github.com/cosmos/ibc-go/v7 v7.3.0 h1:QtGeVMi/3JeLWuvEuC60sBHpAF40Oenx/y+bP8+wRRw= +github.com/cosmos/ibc-go/v7 v7.3.0/go.mod h1:mUmaHFXpXrEdcxfdXyau+utZf14pGKVUiXwYftRZZfQ= github.com/cosmos/ics23/go v0.10.0 h1:iXqLLgp2Lp+EdpIuwXTYIQU+AiHj9mOC2X9ab++bZDM= github.com/cosmos/ics23/go v0.10.0/go.mod h1:ZfJSmng/TBNTBkFemHHHj5YY7VAU/MBU980F4VU1NG0= -github.com/cosmos/ledger-cosmos-go v0.12.2 h1:/XYaBlE2BJxtvpkHiBm97gFGSGmYGKunKyF3nNqAXZA= -github.com/cosmos/ledger-cosmos-go v0.12.2/go.mod h1:ZcqYgnfNJ6lAXe4HPtWgarNEY+B74i+2/8MhZw4ziiI= +github.com/cosmos/ledger-cosmos-go v0.13.0 h1:ex0CvCxToSR7j5WjrghPu2Bu9sSXKikjnVvUryNnx4s= +github.com/cosmos/ledger-cosmos-go v0.13.0/go.mod h1:ZcqYgnfNJ6lAXe4HPtWgarNEY+B74i+2/8MhZw4ziiI= github.com/cosmos/rosetta-sdk-go v0.10.0 h1:E5RhTruuoA7KTIXUcMicL76cffyeoyvNybzUGSKFTcM= github.com/cosmos/rosetta-sdk-go v0.10.0/go.mod h1:SImAZkb96YbwvoRkzSMQB6noNJXFgWl/ENIznEoYQI4= github.com/cpuguy83/go-md2man v1.0.10/go.mod h1:SmD6nW6nTyfqj6ABTjUi3V3JVMnlJmwcJI5acqYI6dE= @@ -371,8 +382,8 @@ github.com/cpuguy83/go-md2man/v2 v2.0.2/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46t github.com/creachadair/taskgroup v0.4.2 h1:jsBLdAJE42asreGss2xZGZ8fJra7WtwnHWeJFxv2Li8= github.com/creachadair/taskgroup v0.4.2/go.mod h1:qiXUOSrbwAY3u0JPGTzObbE3yf9hcXHDKBZ2ZjpCbgM= github.com/creack/pty v1.1.7/go.mod h1:lj5s0c3V2DBrqTV7llrYr5NG6My20zk30Fl46Y7DoTY= -github.com/cucumber/common/gherkin/go/v22 v22.0.0 h1:4K8NqptbvdOrjL9DEea6HFjSpbdT9+Q5kgLpmmsHYl0= -github.com/cucumber/common/messages/go/v17 v17.1.1 h1:RNqopvIFyLWnKv0LfATh34SWBhXeoFTJnSrgm9cT/Ts= +github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E= +github.com/cyphar/filepath-securejoin v0.2.3/go.mod h1:aPGpWjXOXUn2NCNjFvBE6aRxGGx79pTxQpKOJNYHHl4= github.com/danieljoos/wincred v1.1.2 h1:QLdCxFs1/Yl4zduvBdcHB8goaYk9RARS2SgLLRuAyr0= github.com/danieljoos/wincred v1.1.2/go.mod h1:GijpziifJoIBfYh+S7BbkdUTU4LfM+QnGqR5Vl2tAx0= github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= @@ -385,12 +396,13 @@ github.com/decred/base58 v1.0.4 h1:QJC6B0E0rXOPA8U/kw2rP+qiRJsUaE2Er+pYb3siUeA= github.com/decred/base58 v1.0.4/go.mod h1:jJswKPEdvpFpvf7dsDvFZyLT22xZ9lWqEByX38oGd9E= github.com/decred/dcrd/chaincfg/chainhash v1.0.2 h1:rt5Vlq/jM3ZawwiacWjPa+smINyLRN07EO0cNBV6DGU= github.com/decred/dcrd/chaincfg/chainhash v1.0.2/go.mod h1:BpbrGgrPTr3YJYRN3Bm+D9NuaFd+zGyNeIKgrhCXK60= -github.com/decred/dcrd/crypto/blake256 v1.0.0 h1:/8DMNYp9SGi5f0w7uCm6d6M4OU2rGFK09Y2A4Xv7EE0= github.com/decred/dcrd/crypto/blake256 v1.0.0/go.mod h1:sQl2p6Y26YV+ZOcSTP6thNdn47hh8kt6rqSlvmrXFAc= +github.com/decred/dcrd/crypto/blake256 v1.0.1 h1:7PltbUIQB7u/FfZ39+DGa/ShuMyJ5ilcvdfma9wOH6Y= +github.com/decred/dcrd/crypto/blake256 v1.0.1/go.mod h1:2OfgNZ5wDpcsFmHmCK5gZTPcCXqlm2ArzUIkw9czNJo= github.com/decred/dcrd/dcrec/secp256k1/v2 v2.0.1 h1:18HurQ6DfHeNvwIjvOmrgr44bPdtVaQAe/WWwHg9goM= github.com/decred/dcrd/dcrec/secp256k1/v2 v2.0.1/go.mod h1:XmyzkaXBy7ZvHdrTAlXAjpog8qKSAWa3ze7yqzWmgmc= -github.com/decred/dcrd/dcrec/secp256k1/v4 v4.1.0 h1:HbphB4TFFXpv7MNrT52FGrrgVXF1owhMVTHFZIlnvd4= -github.com/decred/dcrd/dcrec/secp256k1/v4 v4.1.0/go.mod h1:DZGJHZMqrU4JJqFAWUS2UO1+lbSKsdiOoYi9Zzey7Fc= +github.com/decred/dcrd/dcrec/secp256k1/v4 v4.2.0 h1:8UrgZ3GkP4i/CLijOJx79Yu+etlyjdBU4sfcs2WYQMs= +github.com/decred/dcrd/dcrec/secp256k1/v4 v4.2.0/go.mod h1:v57UDF4pDQJcEfFUCRop3lJL149eHGSe9Jvczhzjo/0= github.com/desertbit/timer v0.0.0-20180107155436-c41aec40b27f h1:U5y3Y5UE0w7amNe7Z5G/twsBW0KEalRQXZzf8ufSh9I= github.com/desertbit/timer v0.0.0-20180107155436-c41aec40b27f/go.mod h1:xH/i4TFMt8koVQZ6WFms69WAsDWr2XsYL3Hkl7jkoLE= github.com/dgraph-io/badger/v2 v2.2007.4 h1:TRWBQg8UrlUhaFdco01nO2uXwzKS7zd+HVdwV/GHc4o= @@ -404,10 +416,11 @@ github.com/dgryski/go-farm v0.0.0-20200201041132-a6ae2369ad13 h1:fAjc9m62+UWV/WA github.com/dgryski/go-farm v0.0.0-20200201041132-a6ae2369ad13/go.mod h1:SqUrOPUnsFjfmXRMNPybcSiG0BgUW2AuFH8PAnS2iTw= github.com/docker/distribution v2.8.2+incompatible h1:T3de5rq0dB1j30rp0sA2rER+m322EBzniBPB6ZIzuh8= github.com/docker/distribution v2.8.2+incompatible/go.mod h1:J2gT2udsDAN96Uj4KfcMRqY0/ypR+oyYUYmja8H+y+w= -github.com/docker/docker v24.0.4+incompatible h1:s/LVDftw9hjblvqIeTiGYXBCD95nOEEl7qRsRrIOuQI= -github.com/docker/docker v24.0.4+incompatible/go.mod h1:eEKB0N0r5NX/I1kEveEz05bcu8tLC/8azJZsviup8Sk= +github.com/docker/docker v24.0.5+incompatible h1:WmgcE4fxyI6EEXxBRxsHnZXrO1pQ3smi0k/jho4HLeY= +github.com/docker/docker v24.0.5+incompatible/go.mod h1:eEKB0N0r5NX/I1kEveEz05bcu8tLC/8azJZsviup8Sk= github.com/docker/go-connections v0.4.0 h1:El9xVISelRB7BuFusrZozjnkIM5YnzCViNKohAFqRJQ= github.com/docker/go-connections v0.4.0/go.mod h1:Gbd7IOopHjR8Iph03tsViu4nIes5XhDvyHbTtUxmeec= +github.com/docker/go-units v0.4.0/go.mod h1:fgPhTUdO+D/Jk86RDLlptpiXQzgHJF7gydDDbaIK4Dk= github.com/docker/go-units v0.5.0 h1:69rxXcBk27SvSaaxTtLh/8llcHD8vYHT7WSdRZ/jvr4= github.com/docker/go-units v0.5.0/go.mod h1:fgPhTUdO+D/Jk86RDLlptpiXQzgHJF7gydDDbaIK4Dk= github.com/dustin/go-humanize v0.0.0-20171111073723-bb3d318650d4/go.mod h1:HtrtbFcZ19U5GC7JDqmcUSB87Iq5E25KnS6fMYU6eOk= @@ -440,17 +453,21 @@ github.com/felixge/httpsnoop v1.0.2/go.mod h1:m8KPJKqk1gH5J9DgRY2ASl2lWCfGKXixSw github.com/fortytw2/leaktest v1.3.0 h1:u8491cBMTQ8ft8aeV+adlcytMZylmA5nnwwkRZjI8vw= github.com/franela/goblin v0.0.0-20200105215937-c9ffbefa60db/go.mod h1:7dvUGVsVBjqR7JHJk0brhHOZYGmfBYOrK0ZhYMEtBr4= github.com/franela/goreq v0.0.0-20171204163338-bcd34c9993f8/go.mod h1:ZhphrRTfi2rbfLwlschooIH4+wKKDR4Pdxhh+TRoA20= +github.com/frankban/quicktest v1.11.3/go.mod h1:wRf/ReqHper53s+kmmSZizM8NamnL3IM0I9ntUbOk+k= github.com/frankban/quicktest v1.14.4 h1:g2rn0vABPOOXmZUj+vbmUp0lPoXEMuhTpIluN0XL9UY= github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo= github.com/fsnotify/fsnotify v1.4.9/go.mod h1:znqG4EE+3YCdAaPaxE2ZRY/06pZUdp0tY4IgpuI1SZQ= github.com/fsnotify/fsnotify v1.5.4/go.mod h1:OVB6XrOHzAwXMpEM7uPOzcehqUV2UqJxmVXmkdnm1bU= github.com/fsnotify/fsnotify v1.6.0 h1:n+5WquG0fcWoWp6xPWfHdbskMCQaFnG6PfBrh1Ky4HY= github.com/fsnotify/fsnotify v1.6.0/go.mod h1:sl3t1tCWJFWoRz9R8WJCbQihKKwmorjAbSClcnxKAGw= +github.com/getsentry/sentry-go v0.23.0 h1:dn+QRCeJv4pPt9OjVXiMcGIBIefaTJPw/h0bZWO05nE= +github.com/getsentry/sentry-go v0.23.0/go.mod h1:lc76E2QywIyW8WuBnwl8Lc4bkmQH4+w1gwTf25trprY= github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04= github.com/gin-contrib/sse v0.1.0 h1:Y/yl/+YNO8GZSjAhjMsSuLt29uWRFHdHYUb5lYOV9qE= github.com/gin-contrib/sse v0.1.0/go.mod h1:RHrZQHXnP2xjPF+u1gW/2HnVO7nvIa9PG3Gm+fLHvGI= -github.com/gin-gonic/gin v1.6.3 h1:ahKqKTFpO5KTPHxWZjEdPScmYaGtLo8Y4DMHoEsnp14= github.com/gin-gonic/gin v1.6.3/go.mod h1:75u5sXoLsGZoRN5Sgbi1eraJ4GU3++wFwWzhwvtwp4M= +github.com/gin-gonic/gin v1.8.1 h1:4+fr/el88TOO3ewCmQr8cx/CtZ/umlIRIs5M4NTNjf8= +github.com/go-errors/errors v1.4.2 h1:J6MZopCL4uSllY1OfXM374weqZFFItUbrImctkmUxIA= github.com/go-gl/glfw v0.0.0-20190409004039-e6da0acd62b1/go.mod h1:vR7hzQXu2zJy9AVAgeJqvqgH9Q5CA+iKCZ2gyEVpxRU= github.com/go-gl/glfw/v3.3/glfw v0.0.0-20191125211704-12ad95a8df72/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8= github.com/go-gl/glfw/v3.3/glfw v0.0.0-20200222043503-6f7a984d4dc4/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8= @@ -459,6 +476,7 @@ github.com/go-kit/kit v0.9.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2 github.com/go-kit/kit v0.10.0/go.mod h1:xUsJbQ/Fp4kEt7AFgCuvyX4a71u8h9jB8tj/ORgOZ7o= github.com/go-kit/kit v0.12.0 h1:e4o3o3IsBfAKQh5Qbbiqyfu97Ku7jrO/JbohvztANh4= github.com/go-kit/kit v0.12.0/go.mod h1:lHd+EkCZPIwYItmGDDRdhinkzX2A1sj+M9biaEaizzs= +github.com/go-kit/log v0.1.0/go.mod h1:zbhenjAZHb184qTLMA9ZjW7ThYL0H2mk7Q6pNt4vbaY= github.com/go-kit/log v0.2.1 h1:MRVx0/zhvdseW+Gza6N9rVzU/IVzaeE1SFI4raAhmBU= github.com/go-kit/log v0.2.1/go.mod h1:NwTd00d/i8cPZ3xOwwiv2PO5MOcx78fFErGNcVmBjv0= github.com/go-logfmt/logfmt v0.3.0/go.mod h1:Qt1PoO58o5twSAckw1HlFXLmHsOX5/0LbT9GBnD5lWE= @@ -470,11 +488,10 @@ github.com/go-ole/go-ole v1.2.6 h1:/Fpf6oFPoeFik9ty7siob0G6Ke8QvQEuVcuChpwXzpY= github.com/go-playground/assert/v2 v2.0.1/go.mod h1:VDjEfimB/XKnb+ZQfWdccd7VUvScMdVu0Titje2rxJ4= github.com/go-playground/locales v0.13.0/go.mod h1:taPMhCMXrRLJO55olJkUXHZBHCxTMfnGwq/HNwmWNS8= github.com/go-playground/locales v0.14.0 h1:u50s323jtVGugKlcYeyzC0etD1HifMjqmJqb8WugfUU= -github.com/go-playground/locales v0.14.0/go.mod h1:sawfccIbzZTqEDETgFXqTho0QybSa7l++s0DH+LDiLs= github.com/go-playground/universal-translator v0.17.0/go.mod h1:UkSxE5sNxxRwHyU+Scu5vgOQjsIJAF8j9muTVoKLVtA= github.com/go-playground/universal-translator v0.18.0 h1:82dyy6p4OuJq4/CByFNOn/jYrnRPArHwAcmLoJZxyho= -github.com/go-playground/validator/v10 v10.2.0 h1:KgJ0snyC2R9VXYN2rneOtQcw5aHQB1Vv0sFl1UcHBOY= github.com/go-playground/validator/v10 v10.2.0/go.mod h1:uOYAAleCW8F/7oMFd6aG0GOhaH6EGOAJShg8Id5JGkI= +github.com/go-playground/validator/v10 v10.11.1 h1:prmOlTVv+YjZjmRmNSF3VmspqJIxJWXmqUsHwfTRRkQ= github.com/go-sql-driver/mysql v1.4.0/go.mod h1:zAC/RDZ24gD3HViQzih4MyKcchzm+sOG5ZlKdlhCg5w= github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY= github.com/go-stack/stack v1.8.1 h1:ntEHSVwIt7PNXNpgPmVfMrNhLtgjlmnZha2kOpuRiDw= @@ -486,10 +503,11 @@ github.com/gobwas/pool v0.2.0 h1:QEmUOlnSjWtnpRGHF3SauEiOsy82Cup83Vf2LcMlnc8= github.com/gobwas/pool v0.2.0/go.mod h1:q8bcK0KcYlCgd9e7WYLm9LpyS+YeLd8JVDW6WezmKEw= github.com/gobwas/ws v1.0.2 h1:CoAavW/wd/kulfZmSIBt6p24n4j7tHgNVCjsfHVNUbo= github.com/gobwas/ws v1.0.2/go.mod h1:szmBTxLgaFppYjEmNtny/v3w89xOydFnnZMcgRRu/EM= +github.com/goccy/go-json v0.9.11 h1:/pAaQDLHEoCq/5FFmSKBswWmK6H0e8g4159Kc/X/nqk= github.com/godbus/dbus v0.0.0-20190726142602-4481cbc300e2 h1:ZpnhV/YsD2/4cESfV5+Hoeu/iUR3ruzNvZ+yQfO03a0= github.com/godbus/dbus v0.0.0-20190726142602-4481cbc300e2/go.mod h1:bBOAhwG1umN6/6ZUMtDFBMQR8jRg9O75tm9K00oMsK4= github.com/godbus/dbus/v5 v5.0.4/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA= -github.com/gofrs/uuid v4.3.0+incompatible h1:CaSVZxm5B+7o45rtab4jC2G37WGYX1zQfuU2i6DSvnc= +github.com/godbus/dbus/v5 v5.0.6/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA= github.com/gogo/googleapis v1.1.0/go.mod h1:gf4bu3Q80BeJ6H1S1vYPm8/ELATdvryBaNFGgqEef3s= github.com/gogo/googleapis v1.4.1-0.20201022092350-68b0159b7869/go.mod h1:5YRNX2z1oM5gXdAkurHa942MDgEJyk02w4OecKY87+c= github.com/gogo/googleapis v1.4.1 h1:1Yx4Myt7BxzvUr5ldGSbwYiZG6t9wGBZ+8/fX3Wvtq0= @@ -585,7 +603,7 @@ github.com/google/pprof v0.0.0-20210407192527-94a9f03dee38/go.mod h1:kpwsk12EmLe github.com/google/pprof v0.0.0-20210601050228-01bbb1931b22/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= github.com/google/pprof v0.0.0-20210609004039-a478d1d731e9/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= github.com/google/pprof v0.0.0-20210720184732-4bb14d4b1be1/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= -github.com/google/pprof v0.0.0-20221118152302-e6195bd50e26 h1:Xim43kblpZXfIBQsbuBVKCudVG457BR2GZFIz3uw3hQ= +github.com/google/pprof v0.0.0-20230405160723-4a4c7d95572b h1:Qcx5LM0fSiks9uCyFZwDBUasd3lxd1RM0GYpL+Li5o4= github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI= github.com/google/s2a-go v0.1.4 h1:1kZ/sQM3srePvKs3tXAvQzo66XfcReoqFpIpIccE7Oc= github.com/google/s2a-go v0.1.4/go.mod h1:Ej+mSEMGRnqRzjc7VtF+jdBwYG5fuJfiZ8ELkjEwM0A= @@ -625,8 +643,8 @@ github.com/gorilla/websocket v1.5.0 h1:PPwGk2jz7EePpoHN/+ClbZu8SPxiqlu12wZP/3sWm github.com/gorilla/websocket v1.5.0/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE= github.com/grpc-ecosystem/go-grpc-middleware v1.0.1-0.20190118093823-f849b5445de4/go.mod h1:FiyG127CGDf3tlThmgyCl78X/SZQqEOJBCDaAfeWzPs= github.com/grpc-ecosystem/go-grpc-middleware v1.2.2/go.mod h1:EaizFBKfUKtMIF5iaDEhniwNedqGo9FuLFzppDr3uwI= -github.com/grpc-ecosystem/go-grpc-middleware v1.3.0 h1:+9834+KizmvFV7pXQGSXQTsaWhq2GjuNUt0aUU0YBYw= -github.com/grpc-ecosystem/go-grpc-middleware v1.3.0/go.mod h1:z0ButlSOZa5vEBq9m2m2hlwIgKw+rp3sdCBRoJY+30Y= +github.com/grpc-ecosystem/go-grpc-middleware v1.4.0 h1:UH//fgunKIs4JdUbpDl1VZCDaL56wXCB/5+wF6uHfaI= +github.com/grpc-ecosystem/go-grpc-middleware v1.4.0/go.mod h1:g5qyo/la0ALbONm6Vbp88Yd8NsDy6rZz+RcrMPxvld8= github.com/grpc-ecosystem/go-grpc-prometheus v1.2.0/go.mod h1:8NvIoxWQoOIhqOTXgfV/d3M/q6VIi02HzZEHgUlZvzk= github.com/grpc-ecosystem/grpc-gateway v1.9.5/go.mod h1:vNeuVxBJEsws4ogUvrchl83t/GYV9WGTSLVdBhOQFDY= github.com/grpc-ecosystem/grpc-gateway v1.16.0 h1:gmcG1KaJ57LophUzW0Hy8NmPhnMZb4M0+kPpLofRdBo= @@ -695,8 +713,8 @@ github.com/inconshreveable/mousetrap v1.0.0/go.mod h1:PxqpIevigyE2G7u3NXJIT2ANyt github.com/inconshreveable/mousetrap v1.1.0 h1:wN+x4NVGpMsO7ErUn/mUI3vEoE6Jt13X2s0bqwp9tc8= github.com/inconshreveable/mousetrap v1.1.0/go.mod h1:vpF70FUmC8bwa3OWnCshd2FqLfsEA9PFc4w1p2J65bw= github.com/influxdata/influxdb1-client v0.0.0-20191209144304-8bf82d3c094d/go.mod h1:qj24IKcXYK6Iy9ceXlo3Tc+vtHo9lIhSX5JddghvEPo= -github.com/ipfs/go-cid v0.2.0 h1:01JTiihFq9en9Vz0lc0VDWvZe/uBonGpzo4THP0vcQ0= -github.com/ipfs/go-cid v0.2.0/go.mod h1:P+HXFDF4CVhaVayiEb4wkAy7zBHxBwsJyt0Y5U6MLro= +github.com/ipfs/go-cid v0.4.1 h1:A/T3qGvxi4kpKWWcPC/PgbvDA2bjVLO7n4UeVwnbs/s= +github.com/ipfs/go-cid v0.4.1/go.mod h1:uQHwDeX4c6CtyrFwdqyhpNcxVewur1M7l7fNU7LKwZk= github.com/jhump/protoreflect v1.15.1 h1:HUMERORf3I3ZdX05WaQ6MIpd/NJ434hTp5YiKgfCL6c= github.com/jmespath/go-jmespath v0.0.0-20180206201540-c2b33e8439af/go.mod h1:Nht3zPeWKUH0NzdCt2Blrr5ys8VGpn0CEB0cQHVjt7k= github.com/jmespath/go-jmespath v0.4.0 h1:BEgLn5cpjn8UN1mAw4NjwDrS35OdebyEtFe+9YPoQUg= @@ -726,35 +744,36 @@ github.com/klauspost/compress v1.10.3/go.mod h1:aoV0uJVorq1K+umq18yTdKaF57EivdYs github.com/klauspost/compress v1.11.7/go.mod h1:aoV0uJVorq1K+umq18yTdKaF57EivdYsUV+/s2qKfXs= github.com/klauspost/compress v1.12.3/go.mod h1:8dP1Hq4DHOhN9w426knH3Rhby4rFm6D8eO+e+Dq5Gzg= github.com/klauspost/compress v1.15.11/go.mod h1:QPwzmACJjUTFsnSHH934V6woptycfrDDJnH7hvFVbGM= -github.com/klauspost/compress v1.16.3 h1:XuJt9zzcnaz6a16/OU53ZjWp/v7/42WcR5t2a0PcNQY= -github.com/klauspost/compress v1.16.3/go.mod h1:ntbaceVETuRiXiv4DpjP66DpAtAGkEQskQzEyD//IeE= +github.com/klauspost/compress v1.16.7 h1:2mk3MPGNzKyxErAw8YaohYh69+pa4sIQSC0fPGCFR9I= +github.com/klauspost/compress v1.16.7/go.mod h1:ntbaceVETuRiXiv4DpjP66DpAtAGkEQskQzEyD//IeE= github.com/klauspost/cpuid/v2 v2.0.4/go.mod h1:FInQzS24/EEf25PyTYn52gqo7WaD8xa0213Md/qVLRg= github.com/klauspost/cpuid/v2 v2.0.9/go.mod h1:FInQzS24/EEf25PyTYn52gqo7WaD8xa0213Md/qVLRg= -github.com/klauspost/cpuid/v2 v2.2.3 h1:sxCkb+qR91z4vsqw4vGGZlDgPz3G7gjaLyK3V8y70BU= -github.com/klauspost/cpuid/v2 v2.2.3/go.mod h1:RVVoqg1df56z8g3pUjL/3lE5UfnlrJX8tyFgg4nqhuY= +github.com/klauspost/cpuid/v2 v2.2.4 h1:acbojRNwl3o09bUq+yDCtZFc1aiwaAAxtcn8YkZXnvk= +github.com/klauspost/cpuid/v2 v2.2.4/go.mod h1:RVVoqg1df56z8g3pUjL/3lE5UfnlrJX8tyFgg4nqhuY= github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= github.com/konsorten/go-windows-terminal-sequences v1.0.3/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= github.com/kr/fs v0.1.0/go.mod h1:FFnZGqtBN9Gxj7eW1uZ42v5BccTP0vu6NEaFoC2HwRg= github.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515/go.mod h1:+0opPa2QZZtGFBFZlji/RkVcI2GknAs/DXo4wKdlNEc= github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= +github.com/kr/pretty v0.2.1/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI= github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE= +github.com/kr/pretty v0.3.1/go.mod h1:hoEshYVHaxMs3cyo3Yncou5ZscifuDolrwPKZanG3xk= github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= +github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE= github.com/leodido/go-urn v1.2.0/go.mod h1:+8+nEpDfqqsY+g338gtMEUOtuK+4dEMhiQEgxpxOKII= github.com/leodido/go-urn v1.2.1 h1:BqpAaACuzVSgi/VLzGZIobT2z4v53pjosyNd9Yv6n/w= github.com/lib/pq v1.10.7 h1:p7ZhMD+KsSRozJr34udlUrhboJwWAgCg34+/ZZNvZZw= github.com/lib/pq v1.10.7/go.mod h1:AlVN5x4E4T544tWzH6hKfbfQvm3HdbOxrmggDNAPY9o= github.com/libp2p/go-buffer-pool v0.1.0 h1:oK4mSFcQz7cTQIfqbe4MIj9gLW+mnanjyFtc6cdF0Y8= github.com/libp2p/go-buffer-pool v0.1.0/go.mod h1:N+vh8gMqimBzdKkSMVuydVDq+UV5QTWy5HSiZacSbPg= -github.com/libp2p/go-libp2p v0.22.0 h1:2Tce0kHOp5zASFKJbNzRElvh0iZwdtG5uZheNW8chIw= -github.com/libp2p/go-libp2p v0.22.0/go.mod h1:UDolmweypBSjQb2f7xutPnwZ/fxioLbMBxSjRksxxU4= -github.com/libp2p/go-openssl v0.1.0 h1:LBkKEcUv6vtZIQLVTegAil8jbNpJErQ9AnT+bWV+Ooo= -github.com/libp2p/go-openssl v0.1.0/go.mod h1:OiOxwPpL3n4xlenjx2h7AwSGaFSC/KZvf6gNdOBQMtc= +github.com/libp2p/go-libp2p v0.27.8 h1:IX5x/4yKwyPQeVS2AXHZ3J4YATM9oHBGH1gBc23jBAI= +github.com/libp2p/go-libp2p v0.27.8/go.mod h1:eCFFtd0s5i/EVKR7+5Ki8bM7qwkNW3TPTTSSW9sz8NE= github.com/lightstep/lightstep-tracer-common/golang/gogo v0.0.0-20190605223551-bc2310a04743/go.mod h1:qklhhLq1aX+mtWk9cPHPzaBjWImj5ULL6C7HFJtXQMM= github.com/lightstep/lightstep-tracer-go v0.18.1/go.mod h1:jlF1pusYV4pidLvZ+XD0UBX0ZE6WURAspgAczcDHrL4= -github.com/linxGnu/grocksdb v1.7.16 h1:Q2co1xrpdkr5Hx3Fp+f+f7fRGhQFQhvi/+226dtLmA8= -github.com/linxGnu/grocksdb v1.7.16/go.mod h1:JkS7pl5qWpGpuVb3bPqTz8nC12X3YtPZT+Xq7+QfQo4= +github.com/linxGnu/grocksdb v1.8.0 h1:H4L/LhP7GOMf1j17oQAElHgVlbEje2h14A8Tz9cM2BE= +github.com/linxGnu/grocksdb v1.8.0/go.mod h1:09CeBborffXhXdNpEcOeZrLKEnRtrZFEpFdPNI9Zjjg= github.com/lyft/protoc-gen-validate v0.0.13/go.mod h1:XbGvPuh87YZc5TdIa2/I4pLk0QoUACkjt2znoq26NVQ= github.com/magiconair/properties v1.8.0/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czPbwD3XqdrwzmxQ= github.com/magiconair/properties v1.8.7 h1:IeQXZAiQcpL9mgcAe1Nu6cX9LLw6ExEHKjN0VQdvPDY= @@ -772,8 +791,6 @@ github.com/mattn/go-isatty v0.0.14/go.mod h1:7GGIvUiUoEMVVmxf/4nioHXj79iQHKdU27k github.com/mattn/go-isatty v0.0.16/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM= github.com/mattn/go-isatty v0.0.19 h1:JITubQf0MOLdlGRuRq+jtsDlekdYPia9ZFsB8h/APPA= github.com/mattn/go-isatty v0.0.19/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y= -github.com/mattn/go-pointer v0.0.1 h1:n+XhsuGeVO6MEAp7xyEukFINEa+Quek5psIR/ylA6o0= -github.com/mattn/go-pointer v0.0.1/go.mod h1:2zXcozF6qYGgmsG+SeTZz3oAbFLdD3OWqnUbNvJZAlc= github.com/mattn/go-runewidth v0.0.2/go.mod h1:LwmH8dsx7+W8Uxz3IHJYH5QSwggIsqBzpuz5H//U1FU= github.com/mattn/go-runewidth v0.0.4/go.mod h1:LwmH8dsx7+W8Uxz3IHJYH5QSwggIsqBzpuz5H//U1FU= github.com/mattn/go-sqlite3 v1.14.16 h1:yOQRA0RpS5PFz/oikGwBEqvAWhWg5ufRz4ETLjwpU1Y= @@ -803,6 +820,7 @@ github.com/mitchellh/mapstructure v0.0.0-20160808181253-ca63d7c062ee/go.mod h1:F github.com/mitchellh/mapstructure v1.1.2/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y= github.com/mitchellh/mapstructure v1.5.0 h1:jeMsZIYE/09sWLaz43PL7Gy6RuMjD2eJVyuac5Z2hdY= github.com/mitchellh/mapstructure v1.5.0/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo= +github.com/moby/sys/mountinfo v0.5.0/go.mod h1:3bMD3Rg+zkqx8MRYPi7Pyb0Ie97QEBmdxbhnCLlSvSU= github.com/moby/term v0.0.0-20220808134915-39b0c02b01ae h1:O4SWKdcHVCvYqyDV+9CJA1fcDN2L11Bule0iFy3YlAI= github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd h1:TRLaZ9cD/w8PVh93nsPXa1VrQ6jlwL5oN8l14QlcNfg= @@ -813,22 +831,23 @@ github.com/modern-go/reflect2 v1.0.2 h1:xBagoLtFs94CBntxluKeaWgTMpvLxC4ur3nMaC9G github.com/morikuni/aec v1.0.0 h1:nP9CBfwrvYnBRgY6qfDQkygYDmYwOilePFkwzv4dU8A= github.com/mr-tron/base58 v1.2.0 h1:T/HDJBh4ZCPbU39/+c3rRvE0uKBQlU27+QI8LJ4t64o= github.com/mr-tron/base58 v1.2.0/go.mod h1:BinMc/sQntlIE1frQmRFPUoPA1Zkr8VRgBdjWI2mNwc= +github.com/mrunalp/fileutils v0.5.0/go.mod h1:M1WthSahJixYnrXQl/DFQuteStB1weuxD2QJNHXfbSQ= github.com/mtibben/percent v0.2.1 h1:5gssi8Nqo8QU/r2pynCm+hBQHpkB/uNK7BJCFogWdzs= github.com/mtibben/percent v0.2.1/go.mod h1:KG9uO+SZkUp+VkRHsCdYQV3XSZrrSpR3O9ibNBTZrns= -github.com/multiformats/go-base32 v0.0.4 h1:+qMh4a2f37b4xTNs6mqitDinryCI+tfO2dRVMN9mjSE= -github.com/multiformats/go-base32 v0.0.4/go.mod h1:jNLFzjPZtp3aIARHbJRZIaPuspdH0J6q39uUM5pnABM= -github.com/multiformats/go-base36 v0.1.0 h1:JR6TyF7JjGd3m6FbLU2cOxhC0Li8z8dLNGQ89tUg4F4= -github.com/multiformats/go-base36 v0.1.0/go.mod h1:kFGE83c6s80PklsHO9sRn2NCoffoRdUUOENyW/Vv6sM= -github.com/multiformats/go-multiaddr v0.6.0 h1:qMnoOPj2s8xxPU5kZ57Cqdr0hHhARz7mFsPMIiYNqzg= -github.com/multiformats/go-multiaddr v0.6.0/go.mod h1:F4IpaKZuPP360tOMn2Tpyu0At8w23aRyVqeK0DbFeGM= -github.com/multiformats/go-multibase v0.1.1 h1:3ASCDsuLX8+j4kx58qnJ4YFq/JWTJpCyDW27ztsVTOI= -github.com/multiformats/go-multibase v0.1.1/go.mod h1:ZEjHE+IsUrgp5mhlEAYjMtZwK1k4haNkcaPg9aoe1a8= -github.com/multiformats/go-multicodec v0.5.0 h1:EgU6cBe/D7WRwQb1KmnBvU7lrcFGMggZVTPtOW9dDHs= -github.com/multiformats/go-multicodec v0.5.0/go.mod h1:DiY2HFaEp5EhEXb/iYzVAunmyX/aSFMxq2KMKfWEues= +github.com/multiformats/go-base32 v0.1.0 h1:pVx9xoSPqEIQG8o+UbAe7DNi51oej1NtK+aGkbLYxPE= +github.com/multiformats/go-base32 v0.1.0/go.mod h1:Kj3tFY6zNr+ABYMqeUNeGvkIC/UYgtWibDcT0rExnbI= +github.com/multiformats/go-base36 v0.2.0 h1:lFsAbNOGeKtuKozrtBsAkSVhv1p9D0/qedU9rQyccr0= +github.com/multiformats/go-base36 v0.2.0/go.mod h1:qvnKE++v+2MWCfePClUEjE78Z7P2a1UV0xHgWc0hkp4= +github.com/multiformats/go-multiaddr v0.9.0 h1:3h4V1LHIk5w4hJHekMKWALPXErDfz/sggzwC/NcqbDQ= +github.com/multiformats/go-multiaddr v0.9.0/go.mod h1:mI67Lb1EeTOYb8GQfL/7wpIZwc46ElrvzhYnoJOmTT0= +github.com/multiformats/go-multibase v0.2.0 h1:isdYCVLvksgWlMW9OZRYJEa9pZETFivncJHmHnnd87g= +github.com/multiformats/go-multibase v0.2.0/go.mod h1:bFBZX4lKCA/2lyOFSAoKH5SS6oPyjtnzK/XTFDPkNuk= +github.com/multiformats/go-multicodec v0.8.1 h1:ycepHwavHafh3grIbR1jIXnKCsFm0fqsfEOsJ8NtKE8= +github.com/multiformats/go-multicodec v0.8.1/go.mod h1:L3QTQvMIaVBkXOXXtVmYE+LI16i14xuaojr/H7Ai54k= github.com/multiformats/go-multihash v0.2.1 h1:aem8ZT0VA2nCHHk7bPJ1BjUbHNciqZC/d16Vve9l108= github.com/multiformats/go-multihash v0.2.1/go.mod h1:WxoMcYG85AZVQUyRyo9s4wULvW5qrI9vb2Lt6evduFc= -github.com/multiformats/go-varint v0.0.6 h1:gk85QWKxh3TazbLxED/NlDVv8+q+ReFJk7Y2W/KhfNY= -github.com/multiformats/go-varint v0.0.6/go.mod h1:3Ls8CIEsrijN6+B7PbrXRPxHRPuXSrVKRY101jdMZYE= +github.com/multiformats/go-varint v0.0.7 h1:sWSGR+f/eu5ABZA2ZpYKBILXTTs9JWpdEM/nEGOHFS8= +github.com/multiformats/go-varint v0.0.7/go.mod h1:r8PUYw/fD/SjBCiKOoDlGF6QawOELpZAu9eioSos/OU= github.com/mwitkow/go-conntrack v0.0.0-20161129095857-cc309e4a2223/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U= github.com/mwitkow/go-conntrack v0.0.0-20190716064945-2f068394615f h1:KUppIJq7/+SVif2QVs3tOP0zanoHgBEVAwHxUSIzRqU= github.com/mwitkow/go-conntrack v0.0.0-20190716064945-2f068394615f/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U= @@ -859,13 +878,16 @@ github.com/onsi/gomega v1.7.1/go.mod h1:XdKZgCCFLUoM/7CFJVPcG8C1xQ1AJ0vpAezJrB7J github.com/onsi/gomega v1.10.1/go.mod h1:iN09h71vgCQne3DLsj+A5owkum+a2tYe+TOCB1ybHNo= github.com/onsi/gomega v1.17.0/go.mod h1:HnhC7FXeEQY45zxNK3PPoIUhzk/80Xly9PcubAlGdZY= github.com/onsi/gomega v1.19.0/go.mod h1:LY+I3pBVzYsTBU1AnDwOSxaYi9WoWiqgwooUqq9yPro= -github.com/onsi/gomega v1.20.0 h1:8W0cWlwFkflGPLltQvLRB7ZVD5HuP6ng320w2IS245Q= +github.com/onsi/gomega v1.27.4 h1:Z2AnStgsdSayCMDiCU42qIz+HLqEPcgiOCXjAU/w+8E= github.com/op/go-logging v0.0.0-20160315200505-970db520ece7/go.mod h1:HzydrMdWErDVzsI23lYNej1Htcns9BCg93Dk0bBINWk= github.com/opencontainers/go-digest v1.0.0 h1:apOUWs51W5PlhuyGyz9FCeeBIOUDA/6nW8Oi/yOhh5U= github.com/opencontainers/go-digest v1.0.0/go.mod h1:0JzlMkj0TRzQZfJkVvzbP0HBR3IKzErnv2BNG4W4MAM= github.com/opencontainers/image-spec v1.1.0-rc2 h1:2zx/Stx4Wc5pIPDvIxHXvXtQFW/7XWJGmnM7r3wg034= github.com/opencontainers/image-spec v1.1.0-rc2/go.mod h1:3OVijpioIKYWTqjiG0zfF6wvoJ4fAXGbjdZuI2NgsRQ= github.com/opencontainers/runc v1.1.5 h1:L44KXEpKmfWDcS02aeGm8QNTFXTo2D+8MYGDIJ/GDEs= +github.com/opencontainers/runc v1.1.5/go.mod h1:1J5XiS+vdZ3wCyZybsuxXZWGrgSr8fFJHLXuG2PsnNg= +github.com/opencontainers/runtime-spec v1.0.3-0.20210326190908-1c3f411f0417/go.mod h1:jwyrGlmzljRJv/Fgzds9SsS/C5hL+LL3ko9hs6T5lQ0= +github.com/opencontainers/selinux v1.10.0/go.mod h1:2i0OySw99QjzBBQByd1Gr9gSjvuho1lHsJxIJ3gGbJI= github.com/opentracing-contrib/go-observer v0.0.0-20170622124052-a52f23424492/go.mod h1:Ngi6UdF0k5OKD5t5wlmGhe/EDKPoUM3BXZSSfIuJbis= github.com/opentracing/basictracer-go v1.0.0/go.mod h1:QfBfYuafItcjQuMwinw9GhYKwFXS9KnPs5lxoYwgW74= github.com/opentracing/opentracing-go v1.0.2/go.mod h1:UkNAQd3GIcIGf0SeVgPpRdFStlNbqXla1AfSYxPUl2o= @@ -887,12 +909,14 @@ github.com/pelletier/go-toml/v2 v2.0.9 h1:uH2qQXheeefCCkuBBSLi7jCiSmj3VRh2+Goq2N github.com/pelletier/go-toml/v2 v2.0.9/go.mod h1:tJU2Z3ZkXwnxa4DPO899bsyIoywizdUvyaeZurnPPDc= github.com/performancecopilot/speed v3.0.0+incompatible/go.mod h1:/CLtqpZ5gBg1M9iaPbIdPPGyKcA8hKdoy6hAWba7Yac= github.com/petermattis/goid v0.0.0-20180202154549-b0b1615b78e5/go.mod h1:jvVRKCrJTQWu0XVbaOlby/2lO20uSCHEMzzplHXte1o= -github.com/petermattis/goid v0.0.0-20230317030725-371a4b8eda08 h1:hDSdbBuw3Lefr6R18ax0tZ2BJeNB3NehB3trOwYBsdU= -github.com/petermattis/goid v0.0.0-20230317030725-371a4b8eda08/go.mod h1:pxMtw7cyUw6B2bRH0ZBANSPg+AoSud1I1iyJHI69jH4= +github.com/petermattis/goid v0.0.0-20230518223814-80aa455d8761 h1:W04oB3d0J01W5jgYRGKsV8LCM6g9EkCvPkZcmFuy0OE= +github.com/petermattis/goid v0.0.0-20230518223814-80aa455d8761/go.mod h1:pxMtw7cyUw6B2bRH0ZBANSPg+AoSud1I1iyJHI69jH4= github.com/pierrec/lz4 v1.0.2-0.20190131084431-473cd7ce01a1/go.mod h1:3/3N9NVKO0jef7pBehbT1qWhCMrIgbYNnFAZCqQ5LRc= github.com/pierrec/lz4 v2.0.5+incompatible/go.mod h1:pdkljMzZIN41W+lC3N2tnIh5sFi+IEE17M5jbnwPHcY= github.com/pierrec/xxHash v0.1.5 h1:n/jBpwTHiER4xYvK3/CdPVnLDPchj8eTJFFLUb4QHBo= github.com/pierrec/xxHash v0.1.5/go.mod h1:w2waW5Zoa/Wc4Yqe0wgrIYAGKqRMf7czn2HNKXmuL+I= +github.com/pingcap/errors v0.11.4 h1:lFuQV/oaUMGcD2tqt+01ROSmJs75VG1ToEOkZIZ4nE4= +github.com/pkg/diff v0.0.0-20210226163009-20ebb0f2a09e/go.mod h1:pJLUxLENpZxwdsKMEsNbx1VGcRFpLqf3715MtcvvzbA= github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4= @@ -916,30 +940,29 @@ github.com/prometheus/client_model v0.0.0-20190129233127-fd36f4220a90/go.mod h1: github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= github.com/prometheus/client_model v0.1.0/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= github.com/prometheus/client_model v0.2.0/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= -github.com/prometheus/client_model v0.3.0 h1:UBgGFHqYdG/TPFD1B1ogZywDqEkwp3fBMvqdiQ7Xew4= -github.com/prometheus/client_model v0.3.0/go.mod h1:LDGWKZIo7rky3hgvBe+caln+Dr3dPggB5dvjtD7w9+w= +github.com/prometheus/client_model v0.4.0 h1:5lQXD3cAg1OXBf4Wq03gTrXHeaV0TQvGfUooCfx1yqY= +github.com/prometheus/client_model v0.4.0/go.mod h1:oMQmHW1/JoDwqLtg57MGgP/Fb1CJEYF2imWWhWtMkYU= github.com/prometheus/common v0.2.0/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4= github.com/prometheus/common v0.4.1/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4= github.com/prometheus/common v0.7.0/go.mod h1:DjGbpBbp5NYNiECxcL/VnbXCCaQpKd3tt26CguLLsqA= github.com/prometheus/common v0.9.1/go.mod h1:yhUN8i9wzaXS3w1O07YhxHEBxD+W35wd8bs7vj7HSQ4= github.com/prometheus/common v0.10.0/go.mod h1:Tlit/dnDKsSWFlCLTWaA1cyBgKHSMdTB80sz/V91rCo= github.com/prometheus/common v0.15.0/go.mod h1:U+gB1OBLb1lF3O42bTCL+FK18tX9Oar16Clt/msog/s= -github.com/prometheus/common v0.42.0 h1:EKsfXEYo4JpWMHH5cg+KOUWeuJSov1Id8zGR8eeI1YM= -github.com/prometheus/common v0.42.0/go.mod h1:xBwqVerjNdUDjgODMpudtOMwlOwf2SaTr1yjz4b7Zbc= +github.com/prometheus/common v0.44.0 h1:+5BrQJwiBB9xsMygAB3TNvpQKOwlkc25LbISbrdOOfY= +github.com/prometheus/common v0.44.0/go.mod h1:ofAIvZbQ1e/nugmZGz4/qCb9Ap1VoSTIO7x0VV9VvuY= github.com/prometheus/procfs v0.0.0-20181005140218-185b4288413d/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk= github.com/prometheus/procfs v0.0.0-20190117184657-bf6a532e95b1/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk= github.com/prometheus/procfs v0.0.2/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA= github.com/prometheus/procfs v0.0.8/go.mod h1:7Qr8sr6344vo1JqZ6HhLceV9o3AJ1Ff+GxbHq6oeK9A= github.com/prometheus/procfs v0.1.3/go.mod h1:lV6e/gmhEcM9IjHGsFOCxxuZ+z1YqCvr4OA4YeYWdaU= github.com/prometheus/procfs v0.3.0/go.mod h1:lV6e/gmhEcM9IjHGsFOCxxuZ+z1YqCvr4OA4YeYWdaU= -github.com/prometheus/procfs v0.10.1 h1:kYK1Va/YMlutzCGazswoHKo//tZVlFpKYh+PymziUAg= -github.com/prometheus/procfs v0.10.1/go.mod h1:nwNm2aOCAYw8uTR/9bWRREkZFxAUcWzPHWJq+XBB/FM= +github.com/prometheus/procfs v0.11.0 h1:5EAgkfkMl659uZPbe9AS2N68a7Cc1TJbPEuGzFuRbyk= +github.com/prometheus/procfs v0.11.0/go.mod h1:nwNm2aOCAYw8uTR/9bWRREkZFxAUcWzPHWJq+XBB/FM= github.com/rakyll/statik v0.1.7 h1:OF3QCZUuyPxuGEP7B4ypUa7sB/iHtqOTDYZXGM8KOdQ= github.com/rakyll/statik v0.1.7/go.mod h1:AlZONWzMtEnMs7W4e/1LURLiI49pIMmp6V9Unghqrcc= github.com/rcrowley/go-metrics v0.0.0-20181016184325-3113b8401b8a/go.mod h1:bCqnVzQkZxMG4s8nGwiZ5l3QUCyqpo9Y+/ZMZ9VjZe4= github.com/rcrowley/go-metrics v0.0.0-20201227073835-cf1acfcdf475 h1:N/ElC8H3+5XpJzTSTfLsJV/mx9Q9g7kxmchpfZyxgzM= github.com/rcrowley/go-metrics v0.0.0-20201227073835-cf1acfcdf475/go.mod h1:bCqnVzQkZxMG4s8nGwiZ5l3QUCyqpo9Y+/ZMZ9VjZe4= -github.com/regen-network/gocuke v0.6.2 h1:pHviZ0kKAq2U2hN2q3smKNxct6hS0mGByFMHGnWA97M= github.com/regen-network/protobuf v1.3.3-alpha.regen.1 h1:OHEc+q5iIAXpqiqFKeLpu5NwTIkVXUs48vFMwzqpqY4= github.com/regen-network/protobuf v1.3.3-alpha.regen.1/go.mod h1:2DjTFR1HhMQhiWC5sZ4OhQ3+NtdbZ6oBDKQwq5Ou+FI= github.com/remyoudompheng/bigfft v0.0.0-20200410134404-eec4a21b6bb0/go.mod h1:qqbHyh8v60DhA7CoWK5oRCqLrMHRGoxYCSS9EjAz6Eo= @@ -948,13 +971,15 @@ github.com/remyoudompheng/bigfft v0.0.0-20230129092748-24d4a6f8daec/go.mod h1:qq github.com/rogpeppe/fastuuid v0.0.0-20150106093220-6724a57986af/go.mod h1:XWv6SoW27p1b0cqNHllgS5HIMJraePCO15w5zCzIWYg= github.com/rogpeppe/fastuuid v1.2.0/go.mod h1:jVj6XXZzXRy/MSR5jhDC/2q6DgLz+nrA6LYCDYWNEvQ= github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4= -github.com/rogpeppe/go-internal v1.9.0 h1:73kH8U+JUqXU8lRuOHeVHaa/SZPifC7BkcraZVejAe8= +github.com/rogpeppe/go-internal v1.9.0/go.mod h1:WtVeX8xhTBvf0smdhujwtBcq4Qrzq/fJaraNFVN+nFs= +github.com/rogpeppe/go-internal v1.11.0 h1:cWPaGQEPrBb5/AsnsZesgZZ9yb1OQ+GOISoDNXVBh4M= +github.com/rogpeppe/go-internal v1.11.0/go.mod h1:ddIwULY96R17DhadqLgMfk9H9tvdUzkipdSkR5nkCZA= github.com/rs/cors v1.7.0/go.mod h1:gFx+x8UowdsKA9AchylcLynDq+nNFfI8FkUZdN/jGCU= github.com/rs/cors v1.8.3 h1:O+qNyWn7Z+F9M0ILBHgMVPuB1xTOucVd5gtaYyXBpRo= github.com/rs/cors v1.8.3/go.mod h1:XyqrcTp5zjWr1wsJ8PIRZssZ8b/WMcMf71DJnit4EMU= -github.com/rs/xid v1.4.0/go.mod h1:trrq9SKmegXys3aeAKXMUTdJsYXVwGY3RLcfgqegfbg= -github.com/rs/zerolog v1.29.1 h1:cO+d60CHkknCbvzEWxP0S9K6KqyTjrCNUy1LdQLCGPc= -github.com/rs/zerolog v1.29.1/go.mod h1:Le6ESbR7hc+DP6Lt1THiV8CQSdkkNrd3R0XbEgp3ZBU= +github.com/rs/xid v1.5.0/go.mod h1:trrq9SKmegXys3aeAKXMUTdJsYXVwGY3RLcfgqegfbg= +github.com/rs/zerolog v1.30.0 h1:SymVODrcRsaRaSInD9yQtKbtWqwsfoPcRff/oRXLj4c= +github.com/rs/zerolog v1.30.0/go.mod h1:/tk+P47gFdPXq4QYjvCmT5/Gsug2nagsFWBWhAiSi1w= github.com/russross/blackfriday v1.5.2/go.mod h1:JO/DiYxRf+HjHt06OyowR9PTA263kcR/rfWxYHBV53g= github.com/russross/blackfriday/v2 v2.0.1/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= @@ -963,23 +988,19 @@ github.com/samuel/go-zookeeper v0.0.0-20190923202752-2cc03de413da/go.mod h1:gi+0 github.com/sasha-s/go-deadlock v0.3.1 h1:sqv7fDNShgjcaxkO0JNcOAlr8B9+cV5Ey/OB71efZx0= github.com/sasha-s/go-deadlock v0.3.1/go.mod h1:F73l+cr82YSh10GxyRI6qZiCgK64VaZjwesgfQ1/iLM= github.com/sean-/seed v0.0.0-20170313163322-e2103e2c3529/go.mod h1:DxrIzT+xaE7yg65j358z/aeFdxmN0P9QXhEzd20vsDc= +github.com/seccomp/libseccomp-golang v0.9.2-0.20220502022130-f33da4d89646/go.mod h1:JA8cRccbGaA1s33RQf7Y1+q9gHmZX1yB/z9WDN1C6fg= github.com/shirou/gopsutil v3.21.4-0.20210419000835-c7a38de76ee5+incompatible h1:Bn1aCHHRnjv4Bl16T8rcaFjYSrGrIZvpiGO6P3Q4GpU= github.com/shurcooL/sanitized_anchor_name v1.0.0/go.mod h1:1NzhyTcUVG4SuEtjjoZeVRXNmyL/1OwPU0+IJeTBvfc= github.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo= github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE= github.com/sirupsen/logrus v1.6.0/go.mod h1:7uNnSEd1DgxDLC74fIahvMZmmYsHGZGEOFrfsX/uA88= github.com/sirupsen/logrus v1.7.0/go.mod h1:yWOB1SBYBC5VeMP7gHvWumXLIWorT60ONWic61uBYv0= +github.com/sirupsen/logrus v1.8.1/go.mod h1:yWOB1SBYBC5VeMP7gHvWumXLIWorT60ONWic61uBYv0= github.com/sirupsen/logrus v1.9.0 h1:trlNQbNUG3OdDrDil03MCb1H2o9nJ1x4/5LYw7byDE0= -github.com/skip-mev/pob v1.0.4 h1:Degz+Pdm9pCom16bbLawZhXi6PbYPiiJe6cGjBE5g30= -github.com/skip-mev/pob v1.0.4/go.mod h1:tpZivmkiDgCO6O79qBnK4eJQjuJeR9yUzc1jPlGaE1s= -github.com/skip-mev/pob/tests/integration v0.1.0 h1:Rag5gcOxMyqOQIY1/C9ZQ1PMRkO01DUkZSKfVs3l7lQ= -github.com/skip-mev/pob/tests/integration v0.1.0/go.mod h1:BJtVD+0ic4YPLw1ljSnMlB2VI2KlFJVDW61P2p6+888= github.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d/go.mod h1:OnSkiWE9lh6wB0YB77sQom3nweQdgAjqCqsofrRNTgc= github.com/smartystreets/goconvey v1.6.4/go.mod h1:syvi0/a8iFYH4r/RixwvyeAJjdLS9QV7WQ/tjFTllLA= github.com/soheilhy/cmux v0.1.4/go.mod h1:IM3LyeVVIOuxMH7sFAkER9+bJ4dT7Ms6E4xg4kGIyLM= github.com/sony/gobreaker v0.4.1/go.mod h1:ZKptC7FHNvhBz7dN2LGjPVBz2sZJmc0/PkyDJOjmxWY= -github.com/spacemonkeygo/spacelog v0.0.0-20180420211403-2296661a0572 h1:RC6RW7j+1+HkWaX/Yh71Ee5ZHaHYt7ZP4sQgUrm6cDU= -github.com/spacemonkeygo/spacelog v0.0.0-20180420211403-2296661a0572/go.mod h1:w0SWMsp6j9O/dk4/ZpIhL+3CkG8ofA2vuv7k+ltqUMc= github.com/spaolacci/murmur3 v0.0.0-20180118202830-f09979ecbc72/go.mod h1:JwIasOWyU6f++ZhiEuf87xNszmSA2myDM2Kzu9HwQUA= github.com/spaolacci/murmur3 v1.1.0 h1:7c1g84S4BPRrfL5Xrdp6fOJ206sU9y293DDHaoy0bLI= github.com/spaolacci/murmur3 v1.1.0/go.mod h1:JwIasOWyU6f++ZhiEuf87xNszmSA2myDM2Kzu9HwQUA= @@ -1003,8 +1024,8 @@ github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An github.com/spf13/viper v1.3.2/go.mod h1:ZiWeW+zYFKm7srdB9IoDzzZXaJaI5eL9QjNiN/DMA2s= github.com/spf13/viper v1.16.0 h1:rGGH0XDZhdUOryiDWjmIvUSWpbNqisK8Wk0Vyefw8hc= github.com/spf13/viper v1.16.0/go.mod h1:yg78JgCJcbrQOvV9YLXgkLaZqUidkY9K+Dd1FofRzQg= -github.com/strangelove-ventures/interchaintest/v7 v7.0.0-20230721183422-fb937bb0e165 h1:uVCHoklBlbAy77RT6iQBaK7oo8rTn5uI0hrRn1LL5Sw= -github.com/strangelove-ventures/interchaintest/v7 v7.0.0-20230721183422-fb937bb0e165/go.mod h1:WUglvTs5dOXiI7z+VRiVibkFcd2pvTfoDEcXnjYONrw= +github.com/strangelove-ventures/interchaintest/v7 v7.0.0-20231009173908-4e98e35e363e h1:65cHpS7aKw3q/VjsNTgXuXvONpRSOs7YSOaNtuL7COE= +github.com/strangelove-ventures/interchaintest/v7 v7.0.0-20231009173908-4e98e35e363e/go.mod h1:8oeA4y0gCxEK8tgp+/oaHC4+iZXaAS2Sx+rd84hWzMQ= github.com/streadway/amqp v0.0.0-20190404075320-75d898a42a94/go.mod h1:AZpEONHx3DKn8O/DFsRAY58/XVQiIPMTMB1SddzLXVw= github.com/streadway/amqp v0.0.0-20190827072141-edfb9018d271/go.mod h1:AZpEONHx3DKn8O/DFsRAY58/XVQiIPMTMB1SddzLXVw= github.com/streadway/handy v0.0.0-20190108123426-d5acb3125c2a/go.mod h1:qNTQ5P5JnDBl6z3cMAg/SywNDC5ABu5ApDIw6lUbRmI= @@ -1024,11 +1045,11 @@ github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/ github.com/stretchr/testify v1.7.2/go.mod h1:R6va5+xMeoiuVRoj+gSkQ7d3FALtqAAGI1FQKckRals= github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU= github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4= -github.com/stretchr/testify v1.8.2/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4= github.com/stretchr/testify v1.8.4 h1:CcVxjf3Q8PM0mHUKJCdn+eZZtm5yQwehR5yeSVQQcUk= github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo= github.com/subosito/gotenv v1.4.2 h1:X1TuBLAMDFbaTAChgCBLu3DU3UPyELpnF2jjJ2cz/S8= github.com/subosito/gotenv v1.4.2/go.mod h1:ayKnFf/c6rvx/2iiLrJUk1e6plDbT3edrFNGqEflhK0= +github.com/syndtr/gocapability v0.0.0-20200815063812-42c35b437635/go.mod h1:hkRG7XYTFWNJGYcbNJQlaLq0fg1yr4J4t/NcTQtrfww= github.com/syndtr/goleveldb v1.0.1-0.20220721030215-126854af5e6d h1:vfofYNRScrDdvS342BElfbETmL1Aiz3i2t0zfRj16Hs= github.com/syndtr/goleveldb v1.0.1-0.20220721030215-126854af5e6d/go.mod h1:RRCYJbIwD5jmqPI9XoAFR0OcDxqUctll6zUj/+B4S48= github.com/tendermint/go-amino v0.16.0 h1:GyhmgQKvqF82e2oZeuMSp9JTN0N09emoSZlb2lyGa2E= @@ -1053,6 +1074,8 @@ github.com/ulikunitz/xz v0.5.11 h1:kpFauv27b6ynzBNT/Xy+1k+fK4WswhN/6PN5WhFAGw8= github.com/ulikunitz/xz v0.5.11/go.mod h1:nbz6k7qbPmH4IRqmfOplQw/tblSgqTqBwxkY0oWt/14= github.com/urfave/cli v1.20.0/go.mod h1:70zkFmudgCuE/ngEzBv17Jvp/497gISqfk5gWijbERA= github.com/urfave/cli v1.22.1/go.mod h1:Gos4lmkARVdJ6EkW0WaNv/tZAAMe9V7XWyB60NtXRu0= +github.com/vishvananda/netlink v1.1.0/go.mod h1:cTgwzPIzzgDAYoQrMm0EdrjRUBkTqKYppBueQtXaqoE= +github.com/vishvananda/netns v0.0.0-20191106174202-0a2b9b5464df/go.mod h1:JP3t17pCcGlemwknint6hfoeCVQrEMVwxRLRjXpq+BU= github.com/xiang90/probing v0.0.0-20190116061207-43a291ad63a2/go.mod h1:UETIi67q53MR2AWcXfiuqkDkRtnGDLqkBTpCHuJHxtU= github.com/xordataexchange/crypt v0.0.3-0.20170626215501-b2862e3d0a77/go.mod h1:aYKd//L2LvnjZzWKhF00oedf4jCCReLcmhLdhm1A27Q= github.com/yuin/goldmark v1.1.25/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= @@ -1084,18 +1107,20 @@ go.opentelemetry.io/proto/otlp v0.7.0/go.mod h1:PqfVotwruBrMGOCsRd/89rSnXhoiJIqe go.uber.org/atomic v1.3.2/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE= go.uber.org/atomic v1.4.0/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE= go.uber.org/atomic v1.5.0/go.mod h1:sABNBOSYdrvTF6hTgEIbc7YasKWGhgEQZyfxyTvoXHQ= -go.uber.org/atomic v1.10.0 h1:9qC72Qh0+3MqyJbAn8YU5xVq1frD8bn3JtD2oXtafVQ= -go.uber.org/atomic v1.10.0/go.mod h1:LUxbIzbOniOlMKjJjyPfpl4v+PKK2cNJn91OQbhoJI0= -go.uber.org/goleak v1.1.12 h1:gZAh5/EyT/HQwlpkCy6wTpqfH9H8Lz8zbm3dZh+OyzA= +go.uber.org/atomic v1.7.0/go.mod h1:fEN4uk6kAWBTFdckzkM89CLk9XfWZrxpCo0nPH17wJc= +go.uber.org/goleak v1.1.10/go.mod h1:8a7PlsEVH3e/a/GLqe5IIrQx6GzcnRmZEufDUTk4A7A= +go.uber.org/goleak v1.2.0 h1:xqgm/S+aQvhWFTtR0XK3Jvg7z8kGV8P4X14IzwN3Eqk= go.uber.org/multierr v1.1.0/go.mod h1:wR5kodmAFQ0UK8QlbwjlSNy0Z68gJhDJUG5sjR94q/0= go.uber.org/multierr v1.3.0/go.mod h1:VgVr7evmIr6uPjLBxg28wmKNXyqE9akIJ5XnfpiKl+4= +go.uber.org/multierr v1.6.0/go.mod h1:cdWPpRnG4AhwMwsgIHip0KRBQjJy5kYEpYjJxpXp9iU= go.uber.org/multierr v1.11.0 h1:blXXJkSxSSfBVBlC76pxqeO+LN3aDfLQo+309xJstO0= go.uber.org/multierr v1.11.0/go.mod h1:20+QtiLqy0Nd6FdQB9TLXag12DsQkrbs3htMFfDN80Y= go.uber.org/tools v0.0.0-20190618225709-2cfd321de3ee/go.mod h1:vJERXedbb3MVM5f9Ejo0C68/HhF8uaILCdgjnY+goOA= go.uber.org/zap v1.10.0/go.mod h1:vwi/ZaCAaUcBkycHslxD9B2zi4UTXhF60s6SWpuDF0Q= go.uber.org/zap v1.13.0/go.mod h1:zwrFLgMcdUuIBviXEYEH1YKNaOBnKXsx2IPda5bBwHM= -go.uber.org/zap v1.24.0 h1:FiJd5l1UOLj0wCgbSE0rwwXHzEdAZS6hiiSnxJN/D60= -go.uber.org/zap v1.24.0/go.mod h1:2kMP+WWQ8aoFoedH3T2sq6iJ2yDWpHbP0f6MQbS9Gkg= +go.uber.org/zap v1.18.1/go.mod h1:xg/QME4nWcxGxrpdeYfq7UvYrLh66cuVKdrbD1XF/NI= +go.uber.org/zap v1.25.0 h1:4Hvk6GtkucQ790dqmj7l1eEnRdKm3k3ZUrUMS2d5+5c= +go.uber.org/zap v1.25.0/go.mod h1:JIAUzQIH94IC4fOJQm7gMmBJP5k7wQfdcnYdPoEXJYk= golang.org/x/crypto v0.0.0-20170613210332-850760c427c5/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= golang.org/x/crypto v0.0.0-20181029021203-45a5f77698d3/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= @@ -1112,8 +1137,8 @@ golang.org/x/crypto v0.0.0-20210421170649-83a5a9bb288b/go.mod h1:T9bdIzuCu7OtxOm golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= golang.org/x/crypto v0.0.0-20220314234659-1baeb1ce4c0b/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4= golang.org/x/crypto v0.0.0-20220722155217-630584e8d5aa/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4= -golang.org/x/crypto v0.11.0 h1:6Ewdq3tDic1mg5xRO4milcWCfMVQhI4NkqWWvqejpuA= -golang.org/x/crypto v0.11.0/go.mod h1:xgJhtzW8F9jGdVFWZESrid1U1bjeNy4zgy5cRr/CIio= +golang.org/x/crypto v0.12.0 h1:tFM/ta59kqch6LlvYnPa0yx5a83cL2nHflFhYKvv9Yk= +golang.org/x/crypto v0.12.0/go.mod h1:NF0Gs7EO5K4qLn+Ylc+fih8BSTeIjAP05siRnAh98yw= golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= golang.org/x/exp v0.0.0-20190306152737-a1d7652674e8/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= golang.org/x/exp v0.0.0-20190510132918-efd6b22b2522/go.mod h1:ZjyILWgesfNpC6sMxTJOJm9Kp84zZh5NQWvqDGG3Qr8= @@ -1125,8 +1150,8 @@ golang.org/x/exp v0.0.0-20200119233911-0405dc783f0a/go.mod h1:2RIsYlXP63K8oxa1u0 golang.org/x/exp v0.0.0-20200207192155-f17229e696bd/go.mod h1:J/WKrq2StrnmMY6+EHIKF9dgMWnmCNThgcyBT1FY9mM= golang.org/x/exp v0.0.0-20200224162631-6cc2880d07d6/go.mod h1:3jZMyOhIsHpP37uCMkUooju7aAi5cS1Q23tOzKc+0MU= golang.org/x/exp v0.0.0-20200331195152-e8c3332aa8e5/go.mod h1:4M0jN8W1tt0AVLNr8HDosyJCDCDuyL9N9+3m7wDWgKw= -golang.org/x/exp v0.0.0-20230515195305-f3d0a9c9a5cc h1:mCRnTeVUjcrhlRmO0VK8a6k6Rrf6TF9htwo2pJVSjIU= -golang.org/x/exp v0.0.0-20230515195305-f3d0a9c9a5cc/go.mod h1:V1LtkGg67GoY2N1AnLN78QLrzxkLyJw7RJb1gzOOz9w= +golang.org/x/exp v0.0.0-20230711153332-06a737ee72cb h1:xIApU0ow1zwMa2uL1VDNeQlNVFTWMQxZUZCMDy0Q4Us= +golang.org/x/exp v0.0.0-20230711153332-06a737ee72cb/go.mod h1:FXUEEKJgO7OQYeo8N01OfiKP8RXMtf6e8aTskBGqWdc= golang.org/x/image v0.0.0-20190227222117-0694c2d4d067/go.mod h1:kZ7UVZpmo3dzQBMxlp+ypCbDeSB+sBbTgSJuh5dn5js= golang.org/x/image v0.0.0-20190802002840-cff245a6509b/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0= golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= @@ -1216,8 +1241,8 @@ golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug golang.org/x/net v0.0.0-20220909164309-bea034e7d591/go.mod h1:YDH+HFinaLZZlnHAfSS6ZXJJ9M9t4Dl22yv3iI2vPwk= golang.org/x/net v0.0.0-20221014081412-f15817d10f9b/go.mod h1:YDH+HFinaLZZlnHAfSS6ZXJJ9M9t4Dl22yv3iI2vPwk= golang.org/x/net v0.1.0/go.mod h1:Cx3nUiGt4eDBEyega/BKRp+/AlGL8hYe7U9odMt2Cco= -golang.org/x/net v0.12.0 h1:cfawfvKITfUsFCeJIHJrbSxpeu/E81khclypR0GVT50= -golang.org/x/net v0.12.0/go.mod h1:zEVYFnQC7m/vmpQFELhcD1EWkZlX69l4oqgmer6hfKA= +golang.org/x/net v0.14.0 h1:BONx9s002vGdD9umnlX1Po8vOZmrgH34qlHcD1MfK14= +golang.org/x/net v0.14.0/go.mod h1:PpSgVXXLK0OxS0F31C1/tv6XNguvCrnXIDrFMspZIUI= golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= @@ -1278,6 +1303,7 @@ golang.org/x/sys v0.0.0-20190422165155-953cdadca894/go.mod h1:h1NjWce9XRLGQEsW7w golang.org/x/sys v0.0.0-20190502145724-3ef323f4f1fd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190507160741-ecd444e8653b/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190606165138-5da285871e9c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190606203320-7fc4e5ec1444/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190624142023-c5567b49c5d0/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190626221950-04f50cda93cb/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190726091711-fc99dfbffb4e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= @@ -1286,6 +1312,7 @@ golang.org/x/sys v0.0.0-20190904154756-749cb33beabd/go.mod h1:h1NjWce9XRLGQEsW7w golang.org/x/sys v0.0.0-20191001151750-bb3f8db39f24/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191005200804-aed5e4c7ecf9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191026070338-33540a1f6037/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20191115151921-52ab43148777/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191120155948-bd437916bb0e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191204072324-ce4227a45e2e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191220142924-d4481acd189f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= @@ -1315,6 +1342,7 @@ golang.org/x/sys v0.0.0-20201201145000-ef89a241ccb3/go.mod h1:h1NjWce9XRLGQEsW7w golang.org/x/sys v0.0.0-20210104204734-6f8348627aad/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210112080510-489259a85091/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210119212857-b64e53b001e4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210124154548-22da62e12c0c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210220050731-9a76102bfb43/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210225134936-a50acf3fe073/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210305230114-8fe3ee5dd75b/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= @@ -1333,8 +1361,11 @@ golang.org/x/sys v0.0.0-20210806184541-e5e7981a1069/go.mod h1:oPkhp1MJrh7nUepCBc golang.org/x/sys v0.0.0-20210809222454-d867a43fc93e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20210819135213-f52c844e1c1c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20210823070655-63515b42dcdf/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20210906170528-6f6e22806c34/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20210908233432-aa78b53d3365/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20210927094055-39ccf1dd6fa6/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20211025201205-69cdffdb9359/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20211116061358-0a5406a5449c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20211124211545-fe61309f8881/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20211210111614-af8b64212486/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20211216021012-1d35b9e2eb4e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= @@ -1359,13 +1390,13 @@ golang.org/x/sys v0.0.0-20220908164124-27713097b956/go.mod h1:oPkhp1MJrh7nUepCBc golang.org/x/sys v0.0.0-20221010170243-090e33056c14/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.1.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.10.0 h1:SqMFp9UcQJZa+pmYuAKjd9xq1f0j5rLcDIk0mj4qAsA= -golang.org/x/sys v0.10.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.11.0 h1:eG7RXZHdqOJ1i+0lgLgCpSXAp6M3LYlAo6osgSi0xOM= +golang.org/x/sys v0.11.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= golang.org/x/term v0.1.0/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= -golang.org/x/term v0.10.0 h1:3R7pNqamzBraeqj/Tj8qt1aQ2HpmlC+Cx/qL/7hn4/c= -golang.org/x/term v0.10.0/go.mod h1:lpqdcUyK/oCiQxvxVrppt5ggO2KCZ5QblwqPnfZ6d5o= +golang.org/x/term v0.11.0 h1:F9tnn/DA/Im8nCwm+fX+1/eBwi4qFjRT++MhtVC4ZX0= +golang.org/x/term v0.11.0/go.mod h1:zC9APTIj3jG3FdV/Ons+XE1riIZXG4aZ4GTHiPZJPIU= golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= @@ -1377,13 +1408,13 @@ golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ= golang.org/x/text v0.3.8/go.mod h1:E6s5w1FMmriuDzIBO73fBruAKo1PCIq6d2Q6DHfQ8WQ= golang.org/x/text v0.4.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8= -golang.org/x/text v0.11.0 h1:LAntKIrcmeSKERyiOh0XMV39LXS8IE9UL2yP7+f5ij4= -golang.org/x/text v0.11.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE= +golang.org/x/text v0.12.0 h1:k+n5B8goJNdU7hSvEtMUz3d1Q6D/XW4COJSJR6fN0mc= +golang.org/x/text v0.12.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE= golang.org/x/time v0.0.0-20180412165947-fbb02b2291d2/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.0.0-20191024005414-555d28b269f0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= -golang.org/x/time v0.1.0 h1:xYY+Bajn2a7VBmTM5GikTmnK8ZuX8YgnQCqZpbBNtmA= +golang.org/x/time v0.3.0 h1:rg5rLMjNzMS1RkNLzCG38eapWhnYLFYXDXj2gOlr8j4= golang.org/x/tools v0.0.0-20180828015842-6cd1fcedba52/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= @@ -1403,6 +1434,7 @@ golang.org/x/tools v0.0.0-20190911174233-4f2ddba30aff/go.mod h1:b+2E5dAYhXwXZwtn golang.org/x/tools v0.0.0-20191012152004-8de300cfc20a/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20191029041327-9cc4af7d6b2c/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20191029190741-b9c20aec41a5/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20191108193012-7d206e10da11/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20191113191852-77e3bb0ad9e7/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20191115202509-3a792d9c32b2/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= @@ -1445,8 +1477,8 @@ golang.org/x/tools v0.1.3/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= golang.org/x/tools v0.1.4/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= golang.org/x/tools v0.1.5/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc= -golang.org/x/tools v0.11.0 h1:EMCa6U9S2LtZXLAMoWiR/R8dAQFRqbAitmbJ2UKhoi8= -golang.org/x/tools v0.11.0/go.mod h1:anzJrxPjNtfgiYQYirP2CPGzGLxrH2u2QBhn6Bf3qY8= +golang.org/x/tools v0.12.0 h1:YW6HUoUmYBpwSgyaGaZq1fHjrBjX1rlpZ54T6mu2kss= +golang.org/x/tools v0.12.0/go.mod h1:Sc0INKfu04TlqNoRA1hgpFZbhYXHPr4V5DzpSBTPqQM= golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= @@ -1747,16 +1779,16 @@ modernc.org/ccgo/v3 v3.16.13 h1:Mkgdzl46i5F/CNR/Kj80Ri59hC8TKAhZrYSaqvkwzUw= modernc.org/ccgo/v3 v3.16.13/go.mod h1:2Quk+5YgpImhPjv2Qsob1DnZ/4som1lJTodubIcoUkY= modernc.org/ccorpus v1.11.6 h1:J16RXiiqiCgua6+ZvQot4yUuUy8zxgqbqEEUuGPlISk= modernc.org/httpfs v1.0.6 h1:AAgIpFZRXuYnkjftxTAZwMIiwEqAfk8aVB2/oA6nAeM= -modernc.org/libc v1.22.5 h1:91BNch/e5B0uPbJFgqbxXuOnxBQjlS//icfQEGmvyjE= -modernc.org/libc v1.22.5/go.mod h1:jj+Z7dTNX8fBScMVNRAYZ/jF91K8fdT2hYMThc3YjBY= +modernc.org/libc v1.24.1 h1:uvJSeCKL/AgzBo2yYIPPTy82v21KgGnizcGYfBHaNuM= +modernc.org/libc v1.24.1/go.mod h1:FmfO1RLrU3MHJfyi9eYYmZBfi/R+tqZ6+hQ3yQQUkak= modernc.org/mathutil v1.5.0 h1:rV0Ko/6SfM+8G+yKiyI830l3Wuz1zRutdslNoQ0kfiQ= modernc.org/mathutil v1.5.0/go.mod h1:mZW8CKdRPY1v87qxC/wUdX5O1qDzXMP5TH3wjfpga6E= -modernc.org/memory v1.5.0 h1:N+/8c5rE6EqugZwHii4IFsaJ7MUhoWX07J5tC/iI5Ds= -modernc.org/memory v1.5.0/go.mod h1:PkUhL0Mugw21sHPeskwZW4D6VscE/GQJOnIpCnW6pSU= +modernc.org/memory v1.6.0 h1:i6mzavxrE9a30whzMfwf7XWVODx2r5OYXvU46cirX7o= +modernc.org/memory v1.6.0/go.mod h1:PkUhL0Mugw21sHPeskwZW4D6VscE/GQJOnIpCnW6pSU= modernc.org/opt v0.1.3 h1:3XOZf2yznlhC+ibLltsDGzABUGVx8J6pnFMS3E4dcq4= modernc.org/opt v0.1.3/go.mod h1:WdSiB5evDcignE70guQKxYUl14mgWtbClRi5wmkkTX0= -modernc.org/sqlite v1.24.0 h1:EsClRIWHGhLTCX44p+Ri/JLD+vFGo0QGjasg2/F9TlI= -modernc.org/sqlite v1.24.0/go.mod h1:OrDj17Mggn6MhE+iPbBNf7RGKODDE9NFT0f3EwDzJqk= +modernc.org/sqlite v1.25.0 h1:AFweiwPNd/b3BoKnBOfFm+Y260guGMF+0UFk0savqeA= +modernc.org/sqlite v1.25.0/go.mod h1:FL3pVXie73rg3Rii6V/u5BoHlSoyeZeIgKZEgHARyCU= modernc.org/strutil v1.1.3 h1:fNMm+oJklMGYfU9Ylcywl0CO5O6nTfaowNsh2wpPjzY= modernc.org/strutil v1.1.3/go.mod h1:MEHNA7PdEnEwLvspRMtWTNnp2nnyvMfkimT1NKNAGbw= modernc.org/tcl v1.15.2 h1:C4ybAYCGJw968e+Me18oW55kD/FexcHbqH2xak1ROSY= @@ -1766,8 +1798,8 @@ modernc.org/z v1.7.3 h1:zDJf6iHjrnB+WRD88stbXokugjyc0/pB91ri1gO6LZY= nhooyr.io/websocket v1.8.6/go.mod h1:B70DZP8IakI65RVQ51MsWP/8jndNma26DVA/nFSCgW0= nhooyr.io/websocket v1.8.7 h1:usjR2uOr/zjjkVMy0lW+PPohFok7PCow5sDjLgX4P4g= nhooyr.io/websocket v1.8.7/go.mod h1:B70DZP8IakI65RVQ51MsWP/8jndNma26DVA/nFSCgW0= -pgregory.net/rapid v0.5.5 h1:jkgx1TjbQPD/feRoK+S/mXw9e1uj6WilpHrXJowi6oA= -pgregory.net/rapid v0.5.5/go.mod h1:PY5XlDGj0+V1FCq0o192FdRhpKHGTRIWBgqjDBTrq04= +pgregory.net/rapid v1.0.0 h1:iQaM2w5PZ6xvt6x7hbd7tiDS+nk7YPp5uCaEba+T/F4= +pgregory.net/rapid v1.0.0/go.mod h1:PY5XlDGj0+V1FCq0o192FdRhpKHGTRIWBgqjDBTrq04= rsc.io/binaryregexp v0.2.0/go.mod h1:qTv7/COck+e2FymRvadv62gMdZztPaShugOCi3I+8D8= rsc.io/quote/v3 v3.1.0/go.mod h1:yEA65RcK8LyAZtP9Kv3t0HmxON59tX3rD+tICJqUlj0= rsc.io/sampler v1.3.0/go.mod h1:T1hPZKmBbMNahiBKFy5HrXp6adAjACjK9JXDnKaTXpA= diff --git a/interchaintest/ibc_transfer_test.go b/interchaintest/ibc_transfer_test.go index 53857f897..444dfd7f3 100644 --- a/interchaintest/ibc_transfer_test.go +++ b/interchaintest/ibc_transfer_test.go @@ -4,6 +4,7 @@ import ( "context" "testing" + "cosmossdk.io/math" "github.com/strangelove-ventures/interchaintest/v7" "github.com/strangelove-ventures/interchaintest/v7/chain/cosmos" "github.com/strangelove-ventures/interchaintest/v7/ibc" @@ -118,7 +119,7 @@ func TestJunoGaiaIBCTransfer(t *testing.T) { require.Equal(t, genesisWalletAmount, gaiaOrigBal) // Compose an IBC transfer and send from Juno -> Gaia - const transferAmount = int64(1_000) + var transferAmount = math.NewInt(1_000) transfer := ibc.WalletAmount{ Address: gaiaUserAddr, Denom: juno.Config().Denom, @@ -160,7 +161,7 @@ func TestJunoGaiaIBCTransfer(t *testing.T) { // Assert that the funds are no longer present in user acc on Juno and are in the user acc on Gaia junoUpdateBal, err := juno.GetBalance(ctx, junoUserAddr, juno.Config().Denom) require.NoError(t, err) - require.Equal(t, junoOrigBal-transferAmount, junoUpdateBal) + require.Equal(t, junoOrigBal.Sub(transferAmount), junoUpdateBal) gaiaUpdateBal, err := gaia.GetBalance(ctx, gaiaUserAddr, junoIBCDenom) require.NoError(t, err) diff --git a/interchaintest/module_drip_test.go b/interchaintest/module_drip_test.go index 3d468446a..7afe6347b 100644 --- a/interchaintest/module_drip_test.go +++ b/interchaintest/module_drip_test.go @@ -4,6 +4,7 @@ import ( "fmt" "testing" + "cosmossdk.io/math" "github.com/strangelove-ventures/interchaintest/v7" "github.com/strangelove-ventures/interchaintest/v7/chain/cosmos" @@ -42,11 +43,11 @@ func TestJunoDrip(t *testing.T) { // New TF token to distributes tfDenom := helpers.CreateTokenFactoryDenom(t, ctx, juno, user, "dripme", fmt.Sprintf("0%s", Denom)) - distributeAmt := uint64(1_000_000) - helpers.MintTokenFactoryDenom(t, ctx, juno, user, distributeAmt, tfDenom) + distributeAmt := math.NewInt(1_000_000) + helpers.MintTokenFactoryDenom(t, ctx, juno, user, distributeAmt.Uint64(), tfDenom) if balance, err := juno.GetBalance(ctx, user.FormattedAddress(), tfDenom); err != nil { t.Fatal(err) - } else if uint64(balance) != distributeAmt { + } else if balance != distributeAmt { t.Fatalf("balance not %d, got %d", distributeAmt, balance) } diff --git a/interchaintest/module_feeshare_test.go b/interchaintest/module_feeshare_test.go index 04a1bd663..924286e8d 100644 --- a/interchaintest/module_feeshare_test.go +++ b/interchaintest/module_feeshare_test.go @@ -34,7 +34,7 @@ func TestJunoFeeShare(t *testing.T) { helpers.RegisterFeeShare(t, ctx, juno, user, contractAddr, feeRcvAddr) if balance, err := juno.GetBalance(ctx, feeRcvAddr, nativeDenom); err != nil { t.Fatal(err) - } else if balance != 0 { + } else if balance.Int64() != 0 { t.Fatal("balance not 0") } @@ -44,7 +44,7 @@ func TestJunoFeeShare(t *testing.T) { // check balance of nativeDenom now if balance, err := juno.GetBalance(ctx, feeRcvAddr, nativeDenom); err != nil { t.Fatal(err) - } else if balance != 5000 { + } else if balance.Int64() != 5000 { t.Fatal("balance not 5,000. it is ", balance, nativeDenom) } diff --git a/interchaintest/module_ibchooks_test.go b/interchaintest/module_ibchooks_test.go index 46031c03b..d4326c618 100644 --- a/interchaintest/module_ibchooks_test.go +++ b/interchaintest/module_ibchooks_test.go @@ -6,6 +6,7 @@ import ( "strings" "testing" + "cosmossdk.io/math" "github.com/strangelove-ventures/interchaintest/v7" "github.com/strangelove-ventures/interchaintest/v7/chain/cosmos" "github.com/strangelove-ventures/interchaintest/v7/ibc" @@ -134,7 +135,7 @@ func TestJunoIBCHooks(t *testing.T) { transfer := ibc.WalletAmount{ Address: contractAddr, Denom: juno.Config().Denom, - Amount: int64(1), + Amount: math.NewInt(1), } memo := ibc.TransferOptions{ diff --git a/interchaintest/module_pfm_test.go b/interchaintest/module_pfm_test.go index 2bafc5fee..19c54d2db 100644 --- a/interchaintest/module_pfm_test.go +++ b/interchaintest/module_pfm_test.go @@ -6,6 +6,7 @@ import ( "testing" "time" + "cosmossdk.io/math" "github.com/strangelove-ventures/interchaintest/v7" "github.com/strangelove-ventures/interchaintest/v7/chain/cosmos" "github.com/strangelove-ventures/interchaintest/v7/ibc" @@ -201,7 +202,7 @@ func TestPacketForwardMiddlewareRouter(t *testing.T) { // Get original account balances userA, userB, userC, userD := users[0], users[1], users[2], users[3] - const transferAmount int64 = 100000 + var transferAmount math.Int = math.NewInt(100_000) // Compose the prefixed denoms and ibc denom for asserting balances firstHopDenom := transfertypes.GetPrefixedDenom(baChan.PortID, baChan.ChannelID, chainA.Config().Denom) @@ -274,7 +275,7 @@ func TestPacketForwardMiddlewareRouter(t *testing.T) { chainDBalance, err := chainD.GetBalance(ctx, userD.FormattedAddress(), thirdHopIBCDenom) require.NoError(t, err) - require.Equal(t, userFunds-transferAmount, chainABalance) + require.Equal(t, userFunds-transferAmount.Int64(), chainABalance) require.Equal(t, int64(0), chainBBalance) require.Equal(t, int64(0), chainCBalance) require.Equal(t, transferAmount, chainDBalance) diff --git a/interchaintest/module_pob_test.go b/interchaintest/module_pob_test.go.archive similarity index 83% rename from interchaintest/module_pob_test.go rename to interchaintest/module_pob_test.go.archive index f41c2281f..909a65fde 100644 --- a/interchaintest/module_pob_test.go +++ b/interchaintest/module_pob_test.go.archive @@ -9,6 +9,9 @@ import ( "github.com/stretchr/testify/suite" ) +// TODO: This is archived for now becuase: +// /home/reece/.gvm/pkgsets/go1.21/global/pkg/mod/github.com/skip-mev/pob/tests/integration@v0.1.0/chain_setup.go:242:9: cannot use balance (variable of type "cosmossdk.io/math".Int) as int64 value in return statement + var ( numVals = 4 numFull = 0 diff --git a/interchaintest/module_tokenfactory_test.go b/interchaintest/module_tokenfactory_test.go index 86004c45c..07b218daf 100644 --- a/interchaintest/module_tokenfactory_test.go +++ b/interchaintest/module_tokenfactory_test.go @@ -37,7 +37,7 @@ func TestJunoTokenFactory(t *testing.T) { t.Log("minted tfDenom to user") if balance, err := juno.GetBalance(ctx, uaddr, tfDenom); err != nil { t.Fatal(err) - } else if balance != 100 { + } else if balance.Int64() != 100 { t.Fatal("balance not 100") } @@ -46,7 +46,7 @@ func TestJunoTokenFactory(t *testing.T) { t.Log("minted tfDenom to user") if balance, err := juno.GetBalance(ctx, uaddr2, tfDenom); err != nil { t.Fatal(err) - } else if balance != 70 { + } else if balance.Int64() != 70 { t.Fatal("balance not 70") } @@ -74,7 +74,7 @@ func TestJunoTokenFactory(t *testing.T) { // ensure uaddr2 has 31+70 = 101 if balance, err := juno.GetBalance(ctx, uaddr2, tfDenom); err != nil { t.Fatal(err) - } else if balance != 101 { + } else if balance.Int64() != 101 { t.Fatal("balance not 101") } From 14778809f03ef7eb46447c3c01ad74a7d1fa477b Mon Sep 17 00:00:00 2001 From: Reece Williams Date: Mon, 9 Oct 2023 13:02:23 -0500 Subject: [PATCH 43/79] add feepay test base --- Makefile | 3 ++ interchaintest/helpers/cosmwasm.go | 1 + interchaintest/helpers/feepay.go | 80 ++++++++++++++++++++++++++++ interchaintest/module_feepay_test.go | 79 +++++++++++++++++++++++++++ interchaintest/setup.go | 2 + 5 files changed, 165 insertions(+) create mode 100644 interchaintest/helpers/feepay.go create mode 100644 interchaintest/module_feepay_test.go diff --git a/Makefile b/Makefile index 1595cffd7..7238bb994 100644 --- a/Makefile +++ b/Makefile @@ -160,6 +160,9 @@ ictest-pob: rm-testcache ictest-drip: rm-testcache cd interchaintest && go test -race -v -run TestJunoDrip . +ictest-feepay: rm-testcache + cd interchaintest && go test -race -v -run TestJunoFeePay . + rm-testcache: go clean -testcache diff --git a/interchaintest/helpers/cosmwasm.go b/interchaintest/helpers/cosmwasm.go index e930c60b0..818c357df 100644 --- a/interchaintest/helpers/cosmwasm.go +++ b/interchaintest/helpers/cosmwasm.go @@ -12,6 +12,7 @@ import ( "github.com/cosmos/cosmos-sdk/crypto/keyring" ) + func SetupContract(t *testing.T, ctx context.Context, chain *cosmos.CosmosChain, keyname string, fileLoc string, message string) (codeId, contract string) { codeId, err := chain.StoreContract(ctx, keyname, fileLoc) if err != nil { diff --git a/interchaintest/helpers/feepay.go b/interchaintest/helpers/feepay.go new file mode 100644 index 000000000..652f31956 --- /dev/null +++ b/interchaintest/helpers/feepay.go @@ -0,0 +1,80 @@ +package helpers + +import ( + "context" + "fmt" + "testing" + + "github.com/strangelove-ventures/interchaintest/v7/chain/cosmos" + "github.com/strangelove-ventures/interchaintest/v7/ibc" + "github.com/strangelove-ventures/interchaintest/v7/testutil" + "github.com/stretchr/testify/require" + + "github.com/cosmos/cosmos-sdk/crypto/keyring" +) + +func RegisterFeePay(t *testing.T, ctx context.Context, chain *cosmos.CosmosChain, user ibc.Wallet, contract string, walletLimit uint) { + cmd := []string{ + "junod", "tx", "feepay", "register", contract, fmt.Sprintf("%d", walletLimit), + "--node", chain.GetRPCAddress(), + "--home", chain.HomeDir(), + "--chain-id", chain.Config().ChainID, + "--fees", "500ujuno", + "--from", user.KeyName(), + "--keyring-dir", chain.HomeDir(), + "--keyring-backend", keyring.BackendTest, + "-y", + } + stdout, _, err := chain.Exec(ctx, cmd, nil) + require.NoError(t, err) + + debugOutput(t, string(stdout)) + + err = testutil.WaitForBlocks(ctx, 2, chain) + require.NoError(t, err) +} + +func FundFeePayContract(t *testing.T, ctx context.Context, chain *cosmos.CosmosChain, user ibc.Wallet, contract string, amountCoin string) { + cmd := []string{ + "junod", "tx", "feepay", "fund", contract, amountCoin, + "--node", chain.GetRPCAddress(), + "--home", chain.HomeDir(), + "--chain-id", chain.Config().ChainID, + "--fees", "500ujuno", + "--from", user.KeyName(), + "--keyring-dir", chain.HomeDir(), + "--keyring-backend", keyring.BackendTest, + "-y", + } + stdout, _, err := chain.Exec(ctx, cmd, nil) + require.NoError(t, err) + + debugOutput(t, string(stdout)) + + err = testutil.WaitForBlocks(ctx, 2, chain) + require.NoError(t, err) +} + +func UpdateFeePayWalletLimit(t *testing.T, ctx context.Context, chain *cosmos.CosmosChain, user ibc.Wallet, contract string, newLimit uint64) { + cmd := []string{ + "junod", "tx", "feepay", "update-wallet-limit", contract, fmt.Sprintf("%d", newLimit), + "--node", chain.GetRPCAddress(), + "--home", chain.HomeDir(), + "--chain-id", chain.Config().ChainID, + "--from", user.KeyName(), + "--keyring-dir", chain.HomeDir(), + "--keyring-backend", keyring.BackendTest, + "-y", + } + stdout, _, err := chain.Exec(ctx, cmd, nil) + require.NoError(t, err) + + debugOutput(t, string(stdout)) + + err = testutil.WaitForBlocks(ctx, 2, chain) + require.NoError(t, err) +} + +// TODO: +// {"fee_pay_contract":{"contract_address":"juno14hj2tavq8fpesdwxxcu44rty3hh90vhujrvcmstl4zr3txmfvw9skjuwg8","balance":"1000000","wallet_limit":"5"}} +// feepay contract juno14hj2tavq8fpesdwxxcu44rty3hh90vhujrvcmstl4zr3txmfvw9skjuwg8 diff --git a/interchaintest/module_feepay_test.go b/interchaintest/module_feepay_test.go new file mode 100644 index 000000000..63e0a6c0e --- /dev/null +++ b/interchaintest/module_feepay_test.go @@ -0,0 +1,79 @@ +package interchaintest + +import ( + "fmt" + "testing" + + "github.com/strangelove-ventures/interchaintest/v7" + "github.com/strangelove-ventures/interchaintest/v7/chain/cosmos" + "github.com/strangelove-ventures/interchaintest/v7/testutil" + + helpers "github.com/CosmosContracts/juno/tests/interchaintest/helpers" +) + +// TestJunoFeePay +func TestJunoFeePay(t *testing.T) { + t.Parallel() + + cfg := junoConfig + cfg.GasPrices = "0.0025ujuno" + + // Base setup + chains := CreateChainWithCustomConfig(t, 1, 0, cfg) + ic, ctx, _, _ := BuildInitialChain(t, chains) + + // Chains + juno := chains[0].(*cosmos.CosmosChain) + + nativeDenom := juno.Config().Denom + + // Users + users := interchaintest.GetAndFundTestUsers(t, ctx, "default", int64(10_000_000), juno, juno) + admin := users[0] + user := users[1] + + // Upload & init contract payment to another address + codeId, err := juno.StoreContract(ctx, admin.KeyName(), "contracts/cw_template.wasm", "--fees", "50000ujuno") + if err != nil { + t.Fatal(err) + } + + contractAddr, err := juno.InstantiateContract(ctx, admin.KeyName(), codeId, `{"count":0}`, true) + if err != nil { + t.Fatal(err) + } + + // Register contract for 0 fee usage (x amount of times) + helpers.RegisterFeePay(t, ctx, juno, admin, contractAddr, 5) + helpers.FundFeePayContract(t, ctx, juno, admin, contractAddr, "1000000"+nativeDenom) + + // execute against it from another account with enough fees (standard Tx) + txHash, err := juno.ExecuteContract(ctx, user.KeyName(), contractAddr, `{"increment":{}}`, "--fees", "500"+nativeDenom) + if err != nil { + // TODO: + t.Log(err) + } + fmt.Println("txHash", txHash) + + // execute against it from another account and have the dev pay it + txHash, err = juno.ExecuteContract(ctx, user.KeyName(), contractAddr, `{"increment":{}}`, "--fees", "0"+nativeDenom) + if err != nil { + // TODO: + t.Log(err) + } + fmt.Println("txHash", txHash) + + // validate their balance did not go down, and that the contract did infact increase +=1 + // if balance, err := juno.GetBalance(ctx, feeRcvAddr, nativeDenom); err != nil { + // t.Fatal(err) + // } else if balance != 0 { + // t.Fatal("balance not 0") + // } + + // wait blocks + testutil.WaitForBlocks(ctx, 200, juno) + + t.Cleanup(func() { + _ = ic.Close() + }) +} diff --git a/interchaintest/setup.go b/interchaintest/setup.go index b2ec1f018..218c7d2c0 100644 --- a/interchaintest/setup.go +++ b/interchaintest/setup.go @@ -18,6 +18,7 @@ import ( testutil "github.com/cosmos/cosmos-sdk/types/module/testutil" ibclocalhost "github.com/cosmos/ibc-go/v7/modules/light-clients/09-localhost" + feepaytypes "github.com/CosmosContracts/juno/v17/x/feepay/types" feesharetypes "github.com/CosmosContracts/juno/v17/x/feeshare/types" tokenfactorytypes "github.com/CosmosContracts/juno/v17/x/tokenfactory/types" ) @@ -93,6 +94,7 @@ func junoEncoding() *testutil.TestEncodingConfig { wasmtypes.RegisterInterfaces(cfg.InterfaceRegistry) feesharetypes.RegisterInterfaces(cfg.InterfaceRegistry) tokenfactorytypes.RegisterInterfaces(cfg.InterfaceRegistry) + feepaytypes.RegisterInterfaces(cfg.InterfaceRegistry) return &cfg } From 9203aa044be8d0d01c4d2f9f2a6ee1a9888accf8 Mon Sep 17 00:00:00 2001 From: Reece Williams Date: Mon, 9 Oct 2023 13:47:16 -0500 Subject: [PATCH 44/79] fix: nil deduct fee if GlobalFee does not contain --- x/feepay/ante/deduct_fee.go | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/x/feepay/ante/deduct_fee.go b/x/feepay/ante/deduct_fee.go index 5faae248e..5ddce115e 100644 --- a/x/feepay/ante/deduct_fee.go +++ b/x/feepay/ante/deduct_fee.go @@ -164,13 +164,17 @@ func (dfd DeductFeeDecorator) handleZeroFees(ctx sdk.Context, deductFeesFromAcc } // Get the fee price in the chain denom - var feePrice sdk.DecCoin + var feePrice sdk.DecCoin = sdk.DecCoin{} for _, c := range dfd.globalfeeKeeper.GetParams(ctx).MinimumGasPrices { if c.Denom == dfd.bondDenom { feePrice = c } } + if feePrice == (sdk.DecCoin{}) { + return errorsmod.Wrapf(sdkerrors.ErrInvalidCoins, "fee price not found for denom %s in globalfee keeper", dfd.bondDenom) + } + // Get the tx gas feeTx := tx.(sdk.FeeTx) gas := sdkmath.LegacyNewDec(int64(feeTx.GetGas())) From 54de610bac0d1f556138fb26b86980783724628c Mon Sep 17 00:00:00 2001 From: Reece Williams Date: Mon, 9 Oct 2023 13:48:19 -0500 Subject: [PATCH 45/79] feepay e2e test --- interchaintest/helpers/feepay.go | 6 +- interchaintest/helpers/query_helpers.go | 89 +++++++++++++++++++++++++ interchaintest/module_feepay_test.go | 58 ++++++++++------ 3 files changed, 129 insertions(+), 24 deletions(-) diff --git a/interchaintest/helpers/feepay.go b/interchaintest/helpers/feepay.go index 652f31956..3d731fc57 100644 --- a/interchaintest/helpers/feepay.go +++ b/interchaintest/helpers/feepay.go @@ -13,7 +13,7 @@ import ( "github.com/cosmos/cosmos-sdk/crypto/keyring" ) -func RegisterFeePay(t *testing.T, ctx context.Context, chain *cosmos.CosmosChain, user ibc.Wallet, contract string, walletLimit uint) { +func RegisterFeePay(t *testing.T, ctx context.Context, chain *cosmos.CosmosChain, user ibc.Wallet, contract string, walletLimit int) { cmd := []string{ "junod", "tx", "feepay", "register", contract, fmt.Sprintf("%d", walletLimit), "--node", chain.GetRPCAddress(), @@ -74,7 +74,3 @@ func UpdateFeePayWalletLimit(t *testing.T, ctx context.Context, chain *cosmos.Co err = testutil.WaitForBlocks(ctx, 2, chain) require.NoError(t, err) } - -// TODO: -// {"fee_pay_contract":{"contract_address":"juno14hj2tavq8fpesdwxxcu44rty3hh90vhujrvcmstl4zr3txmfvw9skjuwg8","balance":"1000000","wallet_limit":"5"}} -// feepay contract juno14hj2tavq8fpesdwxxcu44rty3hh90vhujrvcmstl4zr3txmfvw9skjuwg8 diff --git a/interchaintest/helpers/query_helpers.go b/interchaintest/helpers/query_helpers.go index 4b88e5b60..0f95be30d 100644 --- a/interchaintest/helpers/query_helpers.go +++ b/interchaintest/helpers/query_helpers.go @@ -87,3 +87,92 @@ func GetValidators(t *testing.T, ctx context.Context, chain *cosmos.CosmosChain) return res } + +// FeePay + +type FeePayUses struct { + Uses string `json:"uses"` +} + +func GetFeePayUses(t *testing.T, ctx context.Context, chain *cosmos.CosmosChain, contract, wallet string) FeePayUses { + var res FeePayUses + + cmd := []string{"junod", "query", "feepay", "uses", contract, wallet, + "--node", chain.GetRPCAddress(), + "--chain-id", chain.Config().ChainID, + "--output", "json", + } + + stdout, _, err := chain.Exec(ctx, cmd, nil) + require.NoError(t, err) + + fmt.Println(string(stdout)) + + if err := json.Unmarshal(stdout, &res); err != nil { + t.Fatal(err) + } + + return res +} + +type FeePayContracts struct { + FeePayContracts []struct { + ContractAddress string `json:"contract_address"` + Balance string `json:"balance"` + WalletLimit string `json:"wallet_limit"` + } `json:"fee_pay_contracts"` + Pagination struct { + NextKey any `json:"next_key"` + Total string `json:"total"` + } `json:"pagination"` +} + +func GetFeePayContracts(t *testing.T, ctx context.Context, chain *cosmos.CosmosChain) FeePayContracts { + var res FeePayContracts + + cmd := []string{"junod", "query", "feepay", "contracts", + "--node", chain.GetRPCAddress(), + "--chain-id", chain.Config().ChainID, + "--output", "json", + } + + stdout, _, err := chain.Exec(ctx, cmd, nil) + require.NoError(t, err) + + fmt.Println(string(stdout)) + + if err := json.Unmarshal(stdout, &res); err != nil { + t.Fatal(err) + } + + return res +} + +type FeePayContract struct { + FeePayContract struct { + ContractAddress string `json:"contract_address"` + Balance string `json:"balance"` + WalletLimit string `json:"wallet_limit"` + } `json:"fee_pay_contract"` +} + +func GetFeePayContract(t *testing.T, ctx context.Context, chain *cosmos.CosmosChain, contract string) FeePayContract { + var res FeePayContract + + cmd := []string{"junod", "query", "feepay", "contract", contract, + "--node", chain.GetRPCAddress(), + "--chain-id", chain.Config().ChainID, + "--output", "json", + } + + stdout, _, err := chain.Exec(ctx, cmd, nil) + require.NoError(t, err) + + fmt.Println(string(stdout)) + + if err := json.Unmarshal(stdout, &res); err != nil { + t.Fatal(err) + } + + return res +} diff --git a/interchaintest/module_feepay_test.go b/interchaintest/module_feepay_test.go index 63e0a6c0e..68a08d89f 100644 --- a/interchaintest/module_feepay_test.go +++ b/interchaintest/module_feepay_test.go @@ -2,11 +2,13 @@ package interchaintest import ( "fmt" + "strconv" "testing" + sdk "github.com/cosmos/cosmos-sdk/types" "github.com/strangelove-ventures/interchaintest/v7" "github.com/strangelove-ventures/interchaintest/v7/chain/cosmos" - "github.com/strangelove-ventures/interchaintest/v7/testutil" + "github.com/stretchr/testify/require" helpers "github.com/CosmosContracts/juno/tests/interchaintest/helpers" ) @@ -18,6 +20,15 @@ func TestJunoFeePay(t *testing.T) { cfg := junoConfig cfg.GasPrices = "0.0025ujuno" + // 0.002500000000000000 + coin := sdk.NewDecCoinFromDec(cfg.Denom, sdk.NewDecWithPrec(25, 4)) + cfg.ModifyGenesis = cosmos.ModifyGenesis(append(defaultGenesisKV, []cosmos.GenesisKV{ + { + Key: "app_state.globalfee.params.minimum_gas_prices", + Value: sdk.DecCoins{coin}, + }, + }...)) + // Base setup chains := CreateChainWithCustomConfig(t, 1, 0, cfg) ic, ctx, _, _ := BuildInitialChain(t, chains) @@ -44,34 +55,43 @@ func TestJunoFeePay(t *testing.T) { } // Register contract for 0 fee usage (x amount of times) - helpers.RegisterFeePay(t, ctx, juno, admin, contractAddr, 5) - helpers.FundFeePayContract(t, ctx, juno, admin, contractAddr, "1000000"+nativeDenom) + limit := 5 + balance := 1_000_000 + helpers.RegisterFeePay(t, ctx, juno, admin, contractAddr, limit) + helpers.FundFeePayContract(t, ctx, juno, admin, contractAddr, strconv.Itoa(balance)+nativeDenom) + + beforeContract := helpers.GetFeePayContract(t, ctx, juno, contractAddr) + t.Log("beforeContract", beforeContract) + require.Equal(t, beforeContract.FeePayContract.Balance, strconv.Itoa(balance)) + require.Equal(t, beforeContract.FeePayContract.WalletLimit, strconv.Itoa(int(limit))) // execute against it from another account with enough fees (standard Tx) txHash, err := juno.ExecuteContract(ctx, user.KeyName(), contractAddr, `{"increment":{}}`, "--fees", "500"+nativeDenom) - if err != nil { - // TODO: - t.Log(err) - } + require.NoError(t, err) fmt.Println("txHash", txHash) + beforeBal, err := juno.GetBalance(ctx, user.FormattedAddress(), nativeDenom) + require.NoError(t, err) + // execute against it from another account and have the dev pay it txHash, err = juno.ExecuteContract(ctx, user.KeyName(), contractAddr, `{"increment":{}}`, "--fees", "0"+nativeDenom) - if err != nil { - // TODO: - t.Log(err) - } + require.NoError(t, err) fmt.Println("txHash", txHash) - // validate their balance did not go down, and that the contract did infact increase +=1 - // if balance, err := juno.GetBalance(ctx, feeRcvAddr, nativeDenom); err != nil { - // t.Fatal(err) - // } else if balance != 0 { - // t.Fatal("balance not 0") - // } + afterBal, err := juno.GetBalance(ctx, user.FormattedAddress(), nativeDenom) + require.NoError(t, err) + + // validate users balance did not change + require.Equal(t, beforeBal, afterBal) + + // validate the contract balance went down + afterContract := helpers.GetFeePayContract(t, ctx, juno, contractAddr) + t.Log("afterContract", afterContract) + require.Equal(t, afterContract.FeePayContract.Balance, strconv.Itoa(balance-500)) - // wait blocks - testutil.WaitForBlocks(ctx, 200, juno) + uses := helpers.GetFeePayUses(t, ctx, juno, contractAddr, user.FormattedAddress()) + t.Log("uses", uses) + require.Equal(t, uses.Uses, "1") t.Cleanup(func() { _ = ic.Close() From 540182fc4cb859be775e032715deae3eacd96fd9 Mon Sep 17 00:00:00 2001 From: Reece Williams Date: Tue, 10 Oct 2023 22:10:50 -0500 Subject: [PATCH 46/79] test: globalfee e2e --- .github/workflows/interchaintest-E2E.yml | 1 + Makefile | 3 + interchaintest/helpers/gov.go | 43 ++++++++ interchaintest/module_globalfee_test.go | 135 +++++++++++++++++++++++ interchaintest/setup.go | 2 + 5 files changed, 184 insertions(+) create mode 100644 interchaintest/helpers/gov.go create mode 100644 interchaintest/module_globalfee_test.go diff --git a/.github/workflows/interchaintest-E2E.yml b/.github/workflows/interchaintest-E2E.yml index 5d7b642ff..19539d86f 100644 --- a/.github/workflows/interchaintest-E2E.yml +++ b/.github/workflows/interchaintest-E2E.yml @@ -63,6 +63,7 @@ jobs: - "ictest-tokenfactory" - "ictest-feeshare" - "ictest-pfm" + - "ictest-globalfee" - "ictest-upgrade" - "ictest-ibc" - "ictest-unity-deploy" diff --git a/Makefile b/Makefile index 7238bb994..d5ff0f877 100644 --- a/Makefile +++ b/Makefile @@ -136,6 +136,9 @@ ictest-feeshare: rm-testcache ictest-pfm: rm-testcache cd interchaintest && go test -race -v -run TestPacketForwardMiddlewareRouter . +ictest-globalfee: rm-testcache + cd interchaintest && go test -race -v -run TestJunoGlobalFee . + # Executes a basic chain upgrade test via interchaintest ictest-upgrade: rm-testcache cd interchaintest && go test -race -v -run TestBasicJunoUpgrade . diff --git a/interchaintest/helpers/gov.go b/interchaintest/helpers/gov.go new file mode 100644 index 000000000..e25ab7d25 --- /dev/null +++ b/interchaintest/helpers/gov.go @@ -0,0 +1,43 @@ +package helpers + +import ( + "context" + "testing" + + "github.com/strangelove-ventures/interchaintest/v7/chain/cosmos" + "github.com/stretchr/testify/require" + "golang.org/x/sync/errgroup" +) + +// Modified from ictest +func VoteOnProposalAllValidators(ctx context.Context, c *cosmos.CosmosChain, proposalID string, vote string) error { + var eg errgroup.Group + valKey := "validator" + for _, n := range c.Nodes() { + if n.Validator { + n := n + eg.Go(func() error { + // gas-adjustment was using 1.3 default instead of the setup's 2.0+ for some reason. + // return n.VoteOnProposal(ctx, valKey, proposalID, vote) + + _, err := n.ExecTx(ctx, valKey, + "gov", "vote", + proposalID, vote, "--gas", "auto", "--gas-adjustment", "2.0", + ) + return err + }) + } + } + return eg.Wait() +} + +func ValidatorVote(t *testing.T, ctx context.Context, chain *cosmos.CosmosChain, proposalID string, searchHeightDelta uint64) { + err := VoteOnProposalAllValidators(ctx, chain, proposalID, cosmos.ProposalVoteYes) + require.NoError(t, err, "failed to vote on proposal") + + height, err := chain.Height(ctx) + require.NoError(t, err, "failed to get height") + + _, err = cosmos.PollForProposalStatus(ctx, chain, height, height+searchHeightDelta, proposalID, cosmos.ProposalStatusPassed) + require.NoError(t, err, "proposal status did not change to passed in expected number of blocks") +} diff --git a/interchaintest/module_globalfee_test.go b/interchaintest/module_globalfee_test.go new file mode 100644 index 000000000..1d0a8a986 --- /dev/null +++ b/interchaintest/module_globalfee_test.go @@ -0,0 +1,135 @@ +package interchaintest + +import ( + "context" + "fmt" + "testing" + + helpers "github.com/CosmosContracts/juno/tests/interchaintest/helpers" + globalfeetypes "github.com/CosmosContracts/juno/v17/x/globalfee/types" + "github.com/cosmos/cosmos-sdk/crypto/keyring" + sdk "github.com/cosmos/cosmos-sdk/types" + cosmosproto "github.com/cosmos/gogoproto/proto" + "github.com/strangelove-ventures/interchaintest/v7" + "github.com/strangelove-ventures/interchaintest/v7/chain/cosmos" + "github.com/strangelove-ventures/interchaintest/v7/ibc" + "github.com/strangelove-ventures/interchaintest/v7/testutil" + "github.com/stretchr/testify/require" +) + +// TestJunoGlobalFee +func TestJunoGlobalFee(t *testing.T) { + t.Parallel() + + cfg := junoConfig + cfg.GasPrices = "0.003ujuno" // this is used in the faucet cmd, must match initial globalfee + cfg.GasAdjustment = 2.5 + + // 0.002500000000000000 + coin := sdk.NewDecCoinFromDec(cfg.Denom, sdk.NewDecWithPrec(3, 3)) + cfg.ModifyGenesis = cosmos.ModifyGenesis(append(defaultGenesisKV, []cosmos.GenesisKV{ + { + Key: "app_state.globalfee.params.minimum_gas_prices", + Value: sdk.DecCoins{coin}, + }, + }...)) + + // Base setup + chains := CreateChainWithCustomConfig(t, 1, 0, cfg) + ic, ctx, _, _ := BuildInitialChain(t, chains) + + // Chains + juno := chains[0].(*cosmos.CosmosChain) + + nativeDenom := juno.Config().Denom + + // Users + initFunds := int64(10_000_000_000) + users := interchaintest.GetAndFundTestUsers(t, ctx, "default", initFunds, juno, juno) + sender := users[0] + receiver := users[1].FormattedAddress() + + // fail: send 1 token to the receiver, no fee provided. + std := bankSendWithFees(t, ctx, juno, sender, receiver, "1"+nativeDenom, "0"+nativeDenom, 200000) + require.Contains(t, std, "no fees were specified") + + // fail: not enough fees + std = bankSendWithFees(t, ctx, juno, sender, receiver, "1"+nativeDenom, "1"+nativeDenom, 200000) + require.Contains(t, std, "insufficient fees") + + // fail: wrong fee token + std = bankSendWithFees(t, ctx, juno, sender, receiver, "1"+nativeDenom, "1NOTATOKEN", 200000) + require.Contains(t, std, "fee denom is not accepted") + + // success: send with enough fee (200k gas * 0.003 = 600) + std = bankSendWithFees(t, ctx, juno, sender, receiver, "2"+nativeDenom, "600"+nativeDenom, 200000) + require.Contains(t, std, "raw_log: '[]'") + require.Contains(t, std, "code: 0") + + afterBal, err := juno.GetBalance(ctx, receiver, nativeDenom) + require.NoError(t, err) + require.Equal(t, initFunds+2, afterBal.Int64()) + + // param change proposal (lower fee), then validate it still works + propID := submitGlobalFeeParamChangeProposal(t, ctx, juno, sender) + helpers.ValidatorVote(t, ctx, juno, propID, 25) + + // success: validate the new value is in effect (200k gas * 0.005 = 200ujuno) + std = bankSendWithFees(t, ctx, juno, sender, receiver, "3"+nativeDenom, "1000"+nativeDenom, 200000) + require.Contains(t, std, "raw_log: '[]'") + require.Contains(t, std, "code: 0") + + afterBal, err = juno.GetBalance(ctx, receiver, nativeDenom) + require.NoError(t, err) + require.Equal(t, initFunds+2+3, afterBal.Int64()) + + t.Cleanup(func() { + _ = ic.Close() + }) +} + +func bankSendWithFees(t *testing.T, ctx context.Context, chain *cosmos.CosmosChain, from ibc.Wallet, toAddr, coins, feeCoin string, gasAmt int64) string { + cmd := []string{"junod", "tx", "bank", "send", from.KeyName(), toAddr, coins, + "--node", chain.GetRPCAddress(), + "--home", chain.HomeDir(), + "--chain-id", chain.Config().ChainID, + "--gas", fmt.Sprintf("%d", gasAmt), + "--fees", feeCoin, + "--keyring-dir", chain.HomeDir(), + "--keyring-backend", keyring.BackendTest, + "-y", + } + stdout, _, err := chain.Exec(ctx, cmd, nil) + require.NoError(t, err) + + t.Log(string(stdout)) + + if err := testutil.WaitForBlocks(ctx, 2, chain); err != nil { + t.Fatal(err) + } + + return string(stdout) +} + +func submitGlobalFeeParamChangeProposal(t *testing.T, ctx context.Context, chain *cosmos.CosmosChain, user ibc.Wallet) string { + upgradeMsg := []cosmosproto.Message{ + &globalfeetypes.MsgUpdateParams{ + Authority: "juno10d07y265gmmuvt4z0w9aw880jnsr700jvss730", + Params: globalfeetypes.Params{ + MinimumGasPrices: sdk.DecCoins{ + // 0.005ujuno + sdk.NewDecCoinFromDec(chain.Config().Denom, sdk.NewDecWithPrec(5, 3)), + }, + }, + }, + } + + proposal, err := chain.BuildProposal(upgradeMsg, "New Global Fee", "Summary desc", "ipfs://CID", fmt.Sprintf(`500000000%s`, chain.Config().Denom)) + require.NoError(t, err, "error building proposal") + + txProp, err := chain.SubmitProposal(ctx, user.KeyName(), proposal) + t.Log("txProp", txProp) + require.NoError(t, err, "error submitting proposal") + + return txProp.ProposalID +} diff --git a/interchaintest/setup.go b/interchaintest/setup.go index 218c7d2c0..942a87ba7 100644 --- a/interchaintest/setup.go +++ b/interchaintest/setup.go @@ -20,6 +20,7 @@ import ( feepaytypes "github.com/CosmosContracts/juno/v17/x/feepay/types" feesharetypes "github.com/CosmosContracts/juno/v17/x/feeshare/types" + globalfeetypes "github.com/CosmosContracts/juno/v17/x/globalfee/types" tokenfactorytypes "github.com/CosmosContracts/juno/v17/x/tokenfactory/types" ) @@ -95,6 +96,7 @@ func junoEncoding() *testutil.TestEncodingConfig { feesharetypes.RegisterInterfaces(cfg.InterfaceRegistry) tokenfactorytypes.RegisterInterfaces(cfg.InterfaceRegistry) feepaytypes.RegisterInterfaces(cfg.InterfaceRegistry) + globalfeetypes.RegisterInterfaces(cfg.InterfaceRegistry) return &cfg } From 562b535df9fd9258d513f3226bb097a0fec7666b Mon Sep 17 00:00:00 2001 From: Reece Williams Date: Tue, 10 Oct 2023 22:21:25 -0500 Subject: [PATCH 47/79] feepay v18 namespace --- app/decorators/feeprepay_poc.go.archive | 2 +- interchaintest/module_burn_test.go | 2 +- interchaintest/module_globalfee_test.go | 2 +- x/feepay/ante/deduct_fee.go | 6 +++--- x/feepay/client/cli/query.go | 2 +- x/feepay/client/cli/tx.go | 2 +- x/feepay/genesis.go | 4 ++-- x/feepay/genesis_test.go | 6 +++--- x/feepay/keeper/feepay.go | 2 +- x/feepay/keeper/keeper.go | 4 ++-- x/feepay/keeper/keeper_test.go | 6 +++--- x/feepay/keeper/msg_server.go | 2 +- x/feepay/keeper/msg_server_test.go | 2 +- x/feepay/keeper/params.go | 2 +- x/feepay/keeper/querier.go | 2 +- x/feepay/keeper/querier_test.go | 6 +++--- x/feepay/module.go | 6 +++--- 17 files changed, 29 insertions(+), 29 deletions(-) diff --git a/app/decorators/feeprepay_poc.go.archive b/app/decorators/feeprepay_poc.go.archive index 4ad8b1cd1..66a62c6fc 100644 --- a/app/decorators/feeprepay_poc.go.archive +++ b/app/decorators/feeprepay_poc.go.archive @@ -1,7 +1,7 @@ package decorators import ( - globalfeekeeper "github.com/CosmosContracts/juno/v17/x/globalfee/keeper" + globalfeekeeper "github.com/CosmosContracts/juno/v18/x/globalfee/keeper" sdk "github.com/cosmos/cosmos-sdk/types" sdkerrors "github.com/cosmos/cosmos-sdk/types/errors" diff --git a/interchaintest/module_burn_test.go b/interchaintest/module_burn_test.go index 69fbd0416..a34f38b13 100644 --- a/interchaintest/module_burn_test.go +++ b/interchaintest/module_burn_test.go @@ -52,7 +52,7 @@ func TestJunoBurnModule(t *testing.T) { // Verify the funds were sent, and burned. fmt.Println(balance, updatedBal) - assert.Equal(t, burnAmt, balance-updatedBal, fmt.Sprintf("balance should be %d less than updated balance", burnAmt)) + assert.Equal(t, burnAmt, balance.Sub(updatedBal), fmt.Sprintf("balance should be %d less than updated balance", burnAmt)) t.Cleanup(func() { _ = ic.Close() diff --git a/interchaintest/module_globalfee_test.go b/interchaintest/module_globalfee_test.go index 1d0a8a986..44e8e1527 100644 --- a/interchaintest/module_globalfee_test.go +++ b/interchaintest/module_globalfee_test.go @@ -6,7 +6,7 @@ import ( "testing" helpers "github.com/CosmosContracts/juno/tests/interchaintest/helpers" - globalfeetypes "github.com/CosmosContracts/juno/v17/x/globalfee/types" + globalfeetypes "github.com/CosmosContracts/juno/v18/x/globalfee/types" "github.com/cosmos/cosmos-sdk/crypto/keyring" sdk "github.com/cosmos/cosmos-sdk/types" cosmosproto "github.com/cosmos/gogoproto/proto" diff --git a/x/feepay/ante/deduct_fee.go b/x/feepay/ante/deduct_fee.go index 5ddce115e..6c5ea7147 100644 --- a/x/feepay/ante/deduct_fee.go +++ b/x/feepay/ante/deduct_fee.go @@ -7,9 +7,9 @@ import ( errorsmod "cosmossdk.io/errors" sdkmath "cosmossdk.io/math" wasmtypes "github.com/CosmWasm/wasmd/x/wasm/types" - feepaykeeper "github.com/CosmosContracts/juno/v17/x/feepay/keeper" - feepaytypes "github.com/CosmosContracts/juno/v17/x/feepay/types" - globalfeekeeper "github.com/CosmosContracts/juno/v17/x/globalfee/keeper" + feepaykeeper "github.com/CosmosContracts/juno/v18/x/feepay/keeper" + feepaytypes "github.com/CosmosContracts/juno/v18/x/feepay/types" + globalfeekeeper "github.com/CosmosContracts/juno/v18/x/globalfee/keeper" sdk "github.com/cosmos/cosmos-sdk/types" sdkerrors "github.com/cosmos/cosmos-sdk/types/errors" "github.com/cosmos/cosmos-sdk/x/auth/ante" diff --git a/x/feepay/client/cli/query.go b/x/feepay/client/cli/query.go index 420ca2b44..aeb4c2354 100644 --- a/x/feepay/client/cli/query.go +++ b/x/feepay/client/cli/query.go @@ -9,7 +9,7 @@ import ( "github.com/cosmos/cosmos-sdk/client" "github.com/cosmos/cosmos-sdk/client/flags" - "github.com/CosmosContracts/juno/v17/x/feepay/types" + "github.com/CosmosContracts/juno/v18/x/feepay/types" ) // NewQueryCmd returns the cli query commands for this module diff --git a/x/feepay/client/cli/tx.go b/x/feepay/client/cli/tx.go index 8e92a198f..f9da4da2a 100644 --- a/x/feepay/client/cli/tx.go +++ b/x/feepay/client/cli/tx.go @@ -10,7 +10,7 @@ import ( "github.com/cosmos/cosmos-sdk/client/tx" sdk "github.com/cosmos/cosmos-sdk/types" - "github.com/CosmosContracts/juno/v17/x/feepay/types" + "github.com/CosmosContracts/juno/v18/x/feepay/types" ) // NewTxCmd returns a root CLI command handler for certain modules/FeeShare diff --git a/x/feepay/genesis.go b/x/feepay/genesis.go index 496b540af..7a51d792b 100644 --- a/x/feepay/genesis.go +++ b/x/feepay/genesis.go @@ -3,8 +3,8 @@ package feepay import ( sdk "github.com/cosmos/cosmos-sdk/types" - "github.com/CosmosContracts/juno/v17/x/feepay/keeper" - "github.com/CosmosContracts/juno/v17/x/feepay/types" + "github.com/CosmosContracts/juno/v18/x/feepay/keeper" + "github.com/CosmosContracts/juno/v18/x/feepay/types" ) // InitGenesis import module genesis diff --git a/x/feepay/genesis_test.go b/x/feepay/genesis_test.go index 27bab51e1..781394b18 100644 --- a/x/feepay/genesis_test.go +++ b/x/feepay/genesis_test.go @@ -10,9 +10,9 @@ import ( sdk "github.com/cosmos/cosmos-sdk/types" - "github.com/CosmosContracts/juno/v17/app" - "github.com/CosmosContracts/juno/v17/x/feepay" - "github.com/CosmosContracts/juno/v17/x/feepay/types" + "github.com/CosmosContracts/juno/v18/app" + "github.com/CosmosContracts/juno/v18/x/feepay" + "github.com/CosmosContracts/juno/v18/x/feepay/types" ) type GenesisTestSuite struct { diff --git a/x/feepay/keeper/feepay.go b/x/feepay/keeper/feepay.go index 8e09bf984..5f95e69d3 100644 --- a/x/feepay/keeper/feepay.go +++ b/x/feepay/keeper/feepay.go @@ -3,7 +3,7 @@ package keeper import ( "cosmossdk.io/math" wasmtypes "github.com/CosmWasm/wasmd/x/wasm/types" - "github.com/CosmosContracts/juno/v17/x/feepay/types" + "github.com/CosmosContracts/juno/v18/x/feepay/types" "github.com/cosmos/cosmos-sdk/store/prefix" sdk "github.com/cosmos/cosmos-sdk/types" "github.com/cosmos/cosmos-sdk/types/query" diff --git a/x/feepay/keeper/keeper.go b/x/feepay/keeper/keeper.go index 25d08518d..7e9b6e869 100644 --- a/x/feepay/keeper/keeper.go +++ b/x/feepay/keeper/keeper.go @@ -11,8 +11,8 @@ import ( storetypes "github.com/cosmos/cosmos-sdk/store/types" sdk "github.com/cosmos/cosmos-sdk/types" - feepaytypes "github.com/CosmosContracts/juno/v17/x/feepay/types" - feesharetypes "github.com/CosmosContracts/juno/v17/x/feeshare/types" + feepaytypes "github.com/CosmosContracts/juno/v18/x/feepay/types" + feesharetypes "github.com/CosmosContracts/juno/v18/x/feeshare/types" bankkeeper "github.com/cosmos/cosmos-sdk/x/bank/keeper" ) diff --git a/x/feepay/keeper/keeper_test.go b/x/feepay/keeper/keeper_test.go index b28027744..b876cf626 100644 --- a/x/feepay/keeper/keeper_test.go +++ b/x/feepay/keeper/keeper_test.go @@ -18,9 +18,9 @@ import ( sdk "github.com/cosmos/cosmos-sdk/types" minttypes "github.com/cosmos/cosmos-sdk/x/mint/types" - "github.com/CosmosContracts/juno/v17/app" - "github.com/CosmosContracts/juno/v17/x/feepay/keeper" - "github.com/CosmosContracts/juno/v17/x/feepay/types" + "github.com/CosmosContracts/juno/v18/app" + "github.com/CosmosContracts/juno/v18/x/feepay/keeper" + "github.com/CosmosContracts/juno/v18/x/feepay/types" "github.com/cosmos/cosmos-sdk/testutil/testdata" ) diff --git a/x/feepay/keeper/msg_server.go b/x/feepay/keeper/msg_server.go index 511523fb0..568571754 100644 --- a/x/feepay/keeper/msg_server.go +++ b/x/feepay/keeper/msg_server.go @@ -8,7 +8,7 @@ import ( sdk "github.com/cosmos/cosmos-sdk/types" govtypes "github.com/cosmos/cosmos-sdk/x/gov/types" - "github.com/CosmosContracts/juno/v17/x/feepay/types" + "github.com/CosmosContracts/juno/v18/x/feepay/types" ) var _ types.MsgServer = &Keeper{} diff --git a/x/feepay/keeper/msg_server_test.go b/x/feepay/keeper/msg_server_test.go index 98f4d28c4..77e97c3ca 100644 --- a/x/feepay/keeper/msg_server_test.go +++ b/x/feepay/keeper/msg_server_test.go @@ -7,7 +7,7 @@ import ( sdk "github.com/cosmos/cosmos-sdk/types" // govtypes "github.com/cosmos/cosmos-sdk/x/gov/types" - "github.com/CosmosContracts/juno/v17/x/feepay/types" + "github.com/CosmosContracts/juno/v18/x/feepay/types" ) func (s *IntegrationTestSuite) TestRegisterFeePayContract() { diff --git a/x/feepay/keeper/params.go b/x/feepay/keeper/params.go index 235d759af..fc09a321a 100644 --- a/x/feepay/keeper/params.go +++ b/x/feepay/keeper/params.go @@ -3,7 +3,7 @@ package keeper import ( sdk "github.com/cosmos/cosmos-sdk/types" - "github.com/CosmosContracts/juno/v17/x/feepay/types" + "github.com/CosmosContracts/juno/v18/x/feepay/types" ) // Get the parameters for the fee pay module. diff --git a/x/feepay/keeper/querier.go b/x/feepay/keeper/querier.go index af94021e6..17014f101 100644 --- a/x/feepay/keeper/querier.go +++ b/x/feepay/keeper/querier.go @@ -5,7 +5,7 @@ import ( sdk "github.com/cosmos/cosmos-sdk/types" - "github.com/CosmosContracts/juno/v17/x/feepay/types" + "github.com/CosmosContracts/juno/v18/x/feepay/types" ) var _ types.QueryServer = Querier{} diff --git a/x/feepay/keeper/querier_test.go b/x/feepay/keeper/querier_test.go index f8f7e5a08..fdbc34d26 100644 --- a/x/feepay/keeper/querier_test.go +++ b/x/feepay/keeper/querier_test.go @@ -7,9 +7,9 @@ import ( //"github.com/cosmos/cosmos-sdk/types/query" - //"github.com/CosmosContracts/juno/v17/testutil/nullify" - "github.com/CosmosContracts/juno/v17/testutil/nullify" - "github.com/CosmosContracts/juno/v17/x/feepay/types" + //"github.com/CosmosContracts/juno/v18/testutil/nullify" + "github.com/CosmosContracts/juno/v18/testutil/nullify" + "github.com/CosmosContracts/juno/v18/x/feepay/types" ) func (s *IntegrationTestSuite) TestQueryContract() { diff --git a/x/feepay/module.go b/x/feepay/module.go index 4b9c51fc5..d1fd35957 100644 --- a/x/feepay/module.go +++ b/x/feepay/module.go @@ -19,9 +19,9 @@ import ( simtypes "github.com/cosmos/cosmos-sdk/types/simulation" authkeeper "github.com/cosmos/cosmos-sdk/x/auth/keeper" - "github.com/CosmosContracts/juno/v17/x/feepay/client/cli" - "github.com/CosmosContracts/juno/v17/x/feepay/keeper" - "github.com/CosmosContracts/juno/v17/x/feepay/types" + "github.com/CosmosContracts/juno/v18/x/feepay/client/cli" + "github.com/CosmosContracts/juno/v18/x/feepay/keeper" + "github.com/CosmosContracts/juno/v18/x/feepay/types" ) // type check to ensure the interface is properly implemented From a0aa013938d376713cb63e02028276875b6bc65b Mon Sep 17 00:00:00 2001 From: Reece Williams Date: Tue, 10 Oct 2023 22:29:14 -0500 Subject: [PATCH 48/79] minor cleanup --- app/ante.go | 4 +-- x/feepay/ante/deduct_fee.go | 34 ++++++++++++---------- x/feepay/client/cli/tx.go | 46 ++++++++++++++---------------- x/feepay/keeper/feepay.go | 28 +++++------------- x/feepay/keeper/keeper.go | 2 +- x/feepay/keeper/keeper_test.go | 4 +-- x/feepay/keeper/msg_server.go | 1 - x/feepay/keeper/msg_server_test.go | 2 -- x/feepay/keeper/querier.go | 2 -- x/feepay/keeper/querier_test.go | 3 -- x/feepay/types/constants.go | 4 +-- x/feepay/types/genesis.go | 5 +--- x/feepay/types/msg.go | 13 ++++----- 13 files changed, 60 insertions(+), 88 deletions(-) diff --git a/app/ante.go b/app/ante.go index f09db2374..76a8fa38b 100644 --- a/app/ante.go +++ b/app/ante.go @@ -16,6 +16,7 @@ import ( sdk "github.com/cosmos/cosmos-sdk/types" sdkerrors "github.com/cosmos/cosmos-sdk/types/errors" "github.com/cosmos/cosmos-sdk/x/auth/ante" + bankkeeper "github.com/cosmos/cosmos-sdk/x/bank/keeper" govkeeper "github.com/cosmos/cosmos-sdk/x/gov/keeper" stakingkeeper "github.com/cosmos/cosmos-sdk/x/staking/keeper" @@ -25,7 +26,6 @@ import ( feeshareante "github.com/CosmosContracts/juno/v18/x/feeshare/ante" feesharekeeper "github.com/CosmosContracts/juno/v18/x/feeshare/keeper" globalfeekeeper "github.com/CosmosContracts/juno/v18/x/globalfee/keeper" - bankkeeper "github.com/cosmos/cosmos-sdk/x/bank/keeper" ) // Lower back to 1 mil after https://github.com/cosmos/relayer/issues/1255 @@ -89,7 +89,7 @@ func NewAnteHandler(options HandlerOptions) (sdk.AnteHandler, error) { ante.NewTxTimeoutHeightDecorator(), ante.NewValidateMemoDecorator(options.AccountKeeper), ante.NewConsumeGasForTxSizeDecorator(options.AccountKeeper), - // globalfeeante.NewFeeDecorator(options.BypassMinFeeMsgTypes, options.GlobalFeeKeeper, options.StakingKeeper, maxBypassMinFeeMsgGasUsage), // TODO: Has a minimum fee requrement check. So if 0 fees are passed, but 500 fee is required, it fails. + // globalfeeante.NewFeeDecorator(options.BypassMinFeeMsgTypes, options.GlobalFeeKeeper, options.StakingKeeper, maxBypassMinFeeMsgGasUsage), // TODO: Has a minimum fee requirement check. So if 0 fees are passed, but 500 fee is required, it fails. feepayante.NewDeductFeeDecorator(options.FeePayKeeper, options.GlobalFeeKeeper, options.AccountKeeper, options.BankKeeper, options.FeegrantKeeper, options.TxFeeChecker, options.BondDenom), feeshareante.NewFeeSharePayoutDecorator(options.BankKeeper, options.FeeShareKeeper), // SetPubKeyDecorator must be called before all signature verification decorators diff --git a/x/feepay/ante/deduct_fee.go b/x/feepay/ante/deduct_fee.go index 6c5ea7147..fc242cecc 100644 --- a/x/feepay/ante/deduct_fee.go +++ b/x/feepay/ante/deduct_fee.go @@ -4,17 +4,20 @@ import ( "fmt" "math" + wasmtypes "github.com/CosmWasm/wasmd/x/wasm/types" + errorsmod "cosmossdk.io/errors" sdkmath "cosmossdk.io/math" - wasmtypes "github.com/CosmWasm/wasmd/x/wasm/types" - feepaykeeper "github.com/CosmosContracts/juno/v18/x/feepay/keeper" - feepaytypes "github.com/CosmosContracts/juno/v18/x/feepay/types" - globalfeekeeper "github.com/CosmosContracts/juno/v18/x/globalfee/keeper" + sdk "github.com/cosmos/cosmos-sdk/types" sdkerrors "github.com/cosmos/cosmos-sdk/types/errors" "github.com/cosmos/cosmos-sdk/x/auth/ante" "github.com/cosmos/cosmos-sdk/x/auth/types" bankkeeper "github.com/cosmos/cosmos-sdk/x/bank/keeper" + + feepaykeeper "github.com/CosmosContracts/juno/v18/x/feepay/keeper" + feepaytypes "github.com/CosmosContracts/juno/v18/x/feepay/types" + globalfeekeeper "github.com/CosmosContracts/juno/v18/x/globalfee/keeper" ) // DeductFeeDecorator deducts fees from the first signer of the tx @@ -104,7 +107,7 @@ func (dfd DeductFeeDecorator) checkDeductFee(ctx sdk.Context, sdkTx sdk.Tx, fee // if feegranter set deduct fee from feegranter account. // this works with only when feegrant enabled. if feeGranter != nil { - if &dfd.feegrantKeeper == nil { + if dfd.feegrantKeeper == nil { return sdkerrors.ErrInvalidRequest.Wrap("fee grants are not enabled") } else if !feeGranter.Equals(feePayer) { err := dfd.feegrantKeeper.UseGrantedFees(ctx, feeGranter, feePayer, fee, sdkTx.GetMsgs()) @@ -121,7 +124,7 @@ func (dfd DeductFeeDecorator) checkDeductFee(ctx sdk.Context, sdkTx sdk.Tx, fee return sdkerrors.ErrUnknownAddress.Wrapf("fee payer address: %s does not exist", deductFeesFrom) } - if isValidFeePayTransaction(ctx, sdkTx, fee) { + if isValidFeePayTransaction(sdkTx, fee) { err := dfd.handleZeroFees(ctx, deductFeesFromAcc, sdkTx, fee) if err != nil { return err @@ -147,9 +150,8 @@ func (dfd DeductFeeDecorator) checkDeductFee(ctx sdk.Context, sdkTx sdk.Tx, fee } // Handle zero fee transactions for fee prepay module -func (dfd DeductFeeDecorator) handleZeroFees(ctx sdk.Context, deductFeesFromAcc types.AccountI, tx sdk.Tx, fee sdk.Coins) error { - - // Prevent FeePay Tx from occuring when module is disabled +func (dfd DeductFeeDecorator) handleZeroFees(ctx sdk.Context, deductFeesFromAcc types.AccountI, tx sdk.Tx, _ sdk.Coins) error { + // Prevent FeePay Tx from occurring when module is disabled if !dfd.feepayKeeper.GetParams(ctx).EnableFeepay { return feepaytypes.ErrFeePayDisabled } @@ -164,7 +166,7 @@ func (dfd DeductFeeDecorator) handleZeroFees(ctx sdk.Context, deductFeesFromAcc } // Get the fee price in the chain denom - var feePrice sdk.DecCoin = sdk.DecCoin{} + feePrice := sdk.DecCoin{} for _, c := range dfd.globalfeeKeeper.GetParams(ctx).MinimumGasPrices { if c.Denom == dfd.bondDenom { feePrice = c @@ -188,7 +190,7 @@ func (dfd DeductFeeDecorator) handleZeroFees(ctx sdk.Context, deductFeesFromAcc } // Check if the contract has enough funds to cover the fee - if !dfd.feepayKeeper.CanContractCoverFee(ctx, feepayContract, requiredFee.Uint64()) { + if !dfd.feepayKeeper.CanContractCoverFee(feepayContract, requiredFee.Uint64()) { return errorsmod.Wrapf(feepaytypes.ErrContractNotEnoughFunds, "contract has insufficient funds; expected: %d, got: %d", requiredFee.Uint64(), feepayContract.Balance) } @@ -197,14 +199,16 @@ func (dfd DeductFeeDecorator) handleZeroFees(ctx sdk.Context, deductFeesFromAcc // Cover the fees of the transaction, send from FeePay Module to FeeCollector Module if err := dfd.bankKeeper.SendCoinsFromModuleToModule(ctx, feepaytypes.ModuleName, types.FeeCollectorName, payment); err != nil { - return errorsmod.Wrapf(sdkerrors.ErrInsufficientFunds, "error transfering funds from FeePay to FeeCollector; %s", err) + return errorsmod.Wrapf(sdkerrors.ErrInsufficientFunds, "error transferring funds from FeePay to FeeCollector; %s", err) } // Deduct the fee from the contract balance dfd.feepayKeeper.SetContractBalance(ctx, feepayContract, feepayContract.Balance-requiredFee.Uint64()) // Increment wallet usage - dfd.feepayKeeper.IncrementContractUses(ctx, feepayContract, accBech32, 1) + if err := dfd.feepayKeeper.IncrementContractUses(ctx, feepayContract, accBech32, 1); err != nil { + return errorsmod.Wrapf(err, "error incrementing contract uses") + } return nil } @@ -238,7 +242,7 @@ func checkTxFeeWithValidatorMinGasPrices(ctx sdk.Context, tx sdk.Tx) (sdk.Coins, // if this is a CheckTx. This is only for local mempool purposes, and thus // is only ran on check tx. // TODO: see if we can remove, since we do call this twice. - if ctx.IsCheckTx() && !isValidFeePayTransaction(ctx, tx, feeTx.GetFee()) { + if ctx.IsCheckTx() && !isValidFeePayTransaction(tx, feeTx.GetFee()) { minGasPrices := ctx.MinGasPrices() if !minGasPrices.IsZero() { requiredFees := make(sdk.Coins, len(minGasPrices)) @@ -283,7 +287,7 @@ func getTxPriority(fee sdk.Coins, gas int64) int64 { // Check if a transaction should be processed as a FeePay transaction. // A valid FeePay transaction has no fee, and only 1 message for executing a contract. -func isValidFeePayTransaction(ctx sdk.Context, tx sdk.Tx, fee sdk.Coins) bool { +func isValidFeePayTransaction(tx sdk.Tx, fee sdk.Coins) bool { // TODO: Future allow for multiple msgs. // Check if fee is zero, and tx has only 1 message for executing a contract diff --git a/x/feepay/client/cli/tx.go b/x/feepay/client/cli/tx.go index f9da4da2a..466185365 100644 --- a/x/feepay/client/cli/tx.go +++ b/x/feepay/client/cli/tx.go @@ -46,23 +46,22 @@ func NewRegisterFeePayContract() *cobra.Command { return err } - deployer_address := cliCtx.GetFromAddress() - contract_address := args[0] - wallet_limit := args[1] - dec_limit, err := strconv.ParseUint(wallet_limit, 10, 64) - + deployerAddress := cliCtx.GetFromAddress() + contractAddress := args[0] + walletLimit := args[1] + decLimit, err := strconv.ParseUint(walletLimit, 10, 64) if err != nil { return err } fpc := &types.FeePayContract{ - ContractAddress: contract_address, + ContractAddress: contractAddress, Balance: uint64(0), - WalletLimit: dec_limit, + WalletLimit: decLimit, } msg := &types.MsgRegisterFeePayContract{ - SenderAddress: deployer_address.String(), + SenderAddress: deployerAddress.String(), FeePayContract: fpc, } @@ -92,12 +91,12 @@ func NewUnregisterFeePayContract() *cobra.Command { return err } - sender_address := cliCtx.GetFromAddress() - contract_address := args[0] + senderAddress := cliCtx.GetFromAddress() + contractAddress := args[0] msg := &types.MsgUnregisterFeePayContract{ - SenderAddress: sender_address.String(), - ContractAddress: contract_address, + SenderAddress: senderAddress.String(), + ContractAddress: contractAddress, } if err := msg.ValidateBasic(); err != nil { @@ -126,16 +125,16 @@ func NewFundFeePayContract() *cobra.Command { return err } - sender_address := cliCtx.GetFromAddress() - contract_address := args[0] + senderAddress := cliCtx.GetFromAddress() + contractAddress := args[0] amount, err := sdk.ParseCoinsNormalized(args[1]) if err != nil { return err } msg := &types.MsgFundFeePayContract{ - SenderAddress: sender_address.String(), - ContractAddress: contract_address, + SenderAddress: senderAddress.String(), + ContractAddress: contractAddress, Amount: amount, } @@ -165,19 +164,18 @@ func NewUpdateFeePayContractWalletLimit() *cobra.Command { return err } - sender_address := cliCtx.GetFromAddress() - contract_address := args[0] - wallet_limit := args[1] - dec_limit, err := strconv.ParseUint(wallet_limit, 10, 64) - + senderAddress := cliCtx.GetFromAddress() + contractAddress := args[0] + walletLimit := args[1] + decLimit, err := strconv.ParseUint(walletLimit, 10, 64) if err != nil { return err } msg := &types.MsgUpdateFeePayContractWalletLimit{ - SenderAddress: sender_address.String(), - ContractAddress: contract_address, - WalletLimit: dec_limit, + SenderAddress: senderAddress.String(), + ContractAddress: contractAddress, + WalletLimit: decLimit, } if err := msg.ValidateBasic(); err != nil { diff --git a/x/feepay/keeper/feepay.go b/x/feepay/keeper/feepay.go index 5f95e69d3..f96643a5c 100644 --- a/x/feepay/keeper/feepay.go +++ b/x/feepay/keeper/feepay.go @@ -1,12 +1,15 @@ package keeper import ( - "cosmossdk.io/math" wasmtypes "github.com/CosmWasm/wasmd/x/wasm/types" - "github.com/CosmosContracts/juno/v18/x/feepay/types" + + "cosmossdk.io/math" + "github.com/cosmos/cosmos-sdk/store/prefix" sdk "github.com/cosmos/cosmos-sdk/types" "github.com/cosmos/cosmos-sdk/types/query" + + "github.com/CosmosContracts/juno/v18/x/feepay/types" ) // Check if a contract is registered as a fee pay contract @@ -17,7 +20,6 @@ func (k Keeper) IsContractRegistered(ctx sdk.Context, contractAddr string) bool // Get a contract from KV store func (k Keeper) GetContract(ctx sdk.Context, contractAddress string) (*types.FeePayContract, error) { - // Return nil, contract not registered if !k.IsContractRegistered(ctx, contractAddress) { return nil, types.ErrContractNotRegistered @@ -38,7 +40,6 @@ func (k Keeper) GetContract(ctx sdk.Context, contractAddress string) (*types.Fee // Get all registered fee pay contracts func (k Keeper) GetContracts(ctx sdk.Context, pag *query.PageRequest) (*types.QueryFeePayContractsResponse, error) { - store := prefix.NewStore(ctx.KVStore(k.storeKey), StoreKeyContracts) // Filter and paginate all contracts @@ -53,7 +54,6 @@ func (k Keeper) GetContracts(ctx sdk.Context, pag *query.PageRequest) (*types.Qu return &types.FeePayContract{} }, ) - if err != nil { return nil, err } @@ -90,7 +90,6 @@ func (k Keeper) GetAllContracts(ctx sdk.Context) []types.FeePayContract { // Register the contract in the module store func (k Keeper) RegisterContract(ctx sdk.Context, rfp *types.MsgRegisterFeePayContract) error { - // Return false because the contract was already registered if k.IsContractRegistered(ctx, rfp.FeePayContract.ContractAddress) { return types.ErrContractAlreadyRegistered @@ -128,7 +127,6 @@ func (k Keeper) SetFeePayContract(ctx sdk.Context, feepay types.FeePayContract) // Unregister contract (loop through usage store & remove all usage entries for contract) func (k Keeper) UnregisterContract(ctx sdk.Context, rfp *types.MsgUnregisterFeePayContract) error { - // Get fee pay contract contract, err := k.GetContract(ctx, rfp.ContractAddress) if err != nil { @@ -178,16 +176,11 @@ func (k Keeper) UnregisterContract(ctx sdk.Context, rfp *types.MsgUnregisterFeeP } // Send coins from the FeePay module to the refund address - if err := k.bankKeeper.SendCoinsFromModuleToAccount(ctx, types.ModuleName, sdk.MustAccAddressFromBech32(refundAddr), coins); err != nil { - return err - } - - return nil + return k.bankKeeper.SendCoinsFromModuleToAccount(ctx, types.ModuleName, sdk.MustAccAddressFromBech32(refundAddr), coins) } // Set the contract balance in the KV store func (k Keeper) SetContractBalance(ctx sdk.Context, fpc *types.FeePayContract, newBalance uint64) { - // Get the existing contract in KV store store := prefix.NewStore(ctx.KVStore(k.storeKey), StoreKeyContracts) @@ -198,7 +191,6 @@ func (k Keeper) SetContractBalance(ctx sdk.Context, fpc *types.FeePayContract, n // Fund an existing fee pay contract func (k Keeper) FundContract(ctx sdk.Context, fpc *types.FeePayContract, senderAddr sdk.AccAddress, coins sdk.Coins) error { - // Only transfer the bond denom var transferCoin sdk.Coin for _, c := range coins { @@ -223,13 +215,12 @@ func (k Keeper) FundContract(ctx sdk.Context, fpc *types.FeePayContract, senderA } // Check if a fee pay contract has a balance greater than or equal to the fee -func (k Keeper) CanContractCoverFee(ctx sdk.Context, fpc *types.FeePayContract, fee uint64) bool { +func (k Keeper) CanContractCoverFee(fpc *types.FeePayContract, fee uint64) bool { return fpc.Balance >= fee } // Get the number of times a wallet has interacted with a fee pay contract (err only if contract not registered) func (k Keeper) GetContractUses(ctx sdk.Context, fpc *types.FeePayContract, walletAddress string) (uint64, error) { - // Get usage from store store := prefix.NewStore(ctx.KVStore(k.storeKey), StoreKeyContractUses) key := []byte(fpc.ContractAddress + "-" + walletAddress) @@ -245,7 +236,6 @@ func (k Keeper) GetContractUses(ctx sdk.Context, fpc *types.FeePayContract, wall // Set the number of times a wallet has interacted with a fee pay contract func (k Keeper) IncrementContractUses(ctx sdk.Context, fpc *types.FeePayContract, walletAddress string, increment uint64) error { - uses, err := k.GetContractUses(ctx, fpc, walletAddress) if err != nil { return err @@ -259,7 +249,6 @@ func (k Keeper) IncrementContractUses(ctx sdk.Context, fpc *types.FeePayContract WalletAddress: walletAddress, Uses: uses + increment, }) - if err != nil { return err } @@ -270,7 +259,6 @@ func (k Keeper) IncrementContractUses(ctx sdk.Context, fpc *types.FeePayContract // Check if a wallet exceeded usage limit (defaults to true if contract not registered) func (k Keeper) HasWalletExceededUsageLimit(ctx sdk.Context, fpc *types.FeePayContract, walletAddress string) bool { - // Get account uses uses, err := k.GetContractUses(ctx, fpc, walletAddress) if err != nil { @@ -283,7 +271,6 @@ func (k Keeper) HasWalletExceededUsageLimit(ctx sdk.Context, fpc *types.FeePayCo // Update the wallet limit of an existing fee pay contract func (k Keeper) UpdateContractWalletLimit(ctx sdk.Context, fpc *types.FeePayContract, senderAddress string, walletLimit uint64) error { - // Check if a cw contract contractAddr, err := sdk.AccAddressFromBech32(fpc.ContractAddress) if err != nil { @@ -311,7 +298,6 @@ func (k Keeper) UpdateContractWalletLimit(ctx sdk.Context, fpc *types.FeePayCont // Check if a wallet is eligible to interact with a contract func (k Keeper) IsWalletEligible(ctx sdk.Context, fpc *types.FeePayContract, walletAddress string) (bool, error) { - // Check if wallet has exceeded usage limit if k.HasWalletExceededUsageLimit(ctx, fpc, walletAddress) { return false, types.ErrWalletExceededUsageLimit diff --git a/x/feepay/keeper/keeper.go b/x/feepay/keeper/keeper.go index 7e9b6e869..2112daf12 100644 --- a/x/feepay/keeper/keeper.go +++ b/x/feepay/keeper/keeper.go @@ -10,10 +10,10 @@ import ( "github.com/cosmos/cosmos-sdk/codec" storetypes "github.com/cosmos/cosmos-sdk/store/types" sdk "github.com/cosmos/cosmos-sdk/types" + bankkeeper "github.com/cosmos/cosmos-sdk/x/bank/keeper" feepaytypes "github.com/CosmosContracts/juno/v18/x/feepay/types" feesharetypes "github.com/CosmosContracts/juno/v18/x/feeshare/types" - bankkeeper "github.com/cosmos/cosmos-sdk/x/bank/keeper" ) var ( diff --git a/x/feepay/keeper/keeper_test.go b/x/feepay/keeper/keeper_test.go index b876cf626..6c479556e 100644 --- a/x/feepay/keeper/keeper_test.go +++ b/x/feepay/keeper/keeper_test.go @@ -7,7 +7,6 @@ import ( wasmkeeper "github.com/CosmWasm/wasmd/x/wasm/keeper" wasmtypes "github.com/CosmWasm/wasmd/x/wasm/types" - bankkeeper "github.com/cosmos/cosmos-sdk/x/bank/keeper" "github.com/stretchr/testify/suite" _ "embed" @@ -15,13 +14,14 @@ import ( tmproto "github.com/cometbft/cometbft/proto/tendermint/types" "github.com/cosmos/cosmos-sdk/baseapp" + "github.com/cosmos/cosmos-sdk/testutil/testdata" sdk "github.com/cosmos/cosmos-sdk/types" + bankkeeper "github.com/cosmos/cosmos-sdk/x/bank/keeper" minttypes "github.com/cosmos/cosmos-sdk/x/mint/types" "github.com/CosmosContracts/juno/v18/app" "github.com/CosmosContracts/juno/v18/x/feepay/keeper" "github.com/CosmosContracts/juno/v18/x/feepay/types" - "github.com/cosmos/cosmos-sdk/testutil/testdata" ) type IntegrationTestSuite struct { diff --git a/x/feepay/keeper/msg_server.go b/x/feepay/keeper/msg_server.go index 568571754..1ab32cb53 100644 --- a/x/feepay/keeper/msg_server.go +++ b/x/feepay/keeper/msg_server.go @@ -36,7 +36,6 @@ func (k Keeper) FundFeePayContract(goCtx context.Context, msg *types.MsgFundFeeP // Validate sender address senderAddr, err := sdk.AccAddressFromBech32(msg.SenderAddress) - if err != nil { return nil, errorsmod.Wrapf(types.ErrInvalidAddress, "invalid sender address: %s", msg.SenderAddress) } diff --git a/x/feepay/keeper/msg_server_test.go b/x/feepay/keeper/msg_server_test.go index 77e97c3ca..4e8142112 100644 --- a/x/feepay/keeper/msg_server_test.go +++ b/x/feepay/keeper/msg_server_test.go @@ -211,7 +211,6 @@ func (s *IntegrationTestSuite) TestFundFeePayContract() { tc := tc s.Run(tc.desc, func() { - _, err := s.app.AppKeepers.FeePayKeeper.FundFeePayContract(s.ctx, &types.MsgFundFeePayContract{ SenderAddress: tc.senderAddress, ContractAddress: tc.contractAddress, @@ -299,7 +298,6 @@ func (s *IntegrationTestSuite) TestUpdateFeePayContractWalletLimit() { tc := tc s.Run(tc.desc, func() { - _, err := s.app.AppKeepers.FeePayKeeper.UpdateFeePayContractWalletLimit(s.ctx, &types.MsgUpdateFeePayContractWalletLimit{ SenderAddress: tc.senderAddress, ContractAddress: tc.contractAddress, diff --git a/x/feepay/keeper/querier.go b/x/feepay/keeper/querier.go index 17014f101..a4028be61 100644 --- a/x/feepay/keeper/querier.go +++ b/x/feepay/keeper/querier.go @@ -38,11 +38,9 @@ func (q Querier) FeePayContract(ctx context.Context, req *types.QueryFeePayContr // FeePayContracts implements types.QueryServer. func (q Querier) FeePayContracts(ctx context.Context, req *types.QueryFeePayContracts) (*types.QueryFeePayContractsResponse, error) { - sdkCtx := sdk.UnwrapSDKContext(ctx) res, err := q.Keeper.GetContracts(sdkCtx, req.Pagination) - if err != nil { return nil, err } diff --git a/x/feepay/keeper/querier_test.go b/x/feepay/keeper/querier_test.go index fdbc34d26..bdf47ba0a 100644 --- a/x/feepay/keeper/querier_test.go +++ b/x/feepay/keeper/querier_test.go @@ -5,9 +5,6 @@ import ( sdk "github.com/cosmos/cosmos-sdk/types" "github.com/cosmos/cosmos-sdk/types/query" - //"github.com/cosmos/cosmos-sdk/types/query" - - //"github.com/CosmosContracts/juno/v18/testutil/nullify" "github.com/CosmosContracts/juno/v18/testutil/nullify" "github.com/CosmosContracts/juno/v18/x/feepay/types" ) diff --git a/x/feepay/types/constants.go b/x/feepay/types/constants.go index 86a05b49a..02e0cda69 100644 --- a/x/feepay/types/constants.go +++ b/x/feepay/types/constants.go @@ -15,6 +15,4 @@ const ( RouterKey = ModuleName ) -var ( - ParamsKey = []byte{prefixParamsKey} -) +var ParamsKey = []byte{prefixParamsKey} diff --git a/x/feepay/types/genesis.go b/x/feepay/types/genesis.go index 5501776a1..249984c99 100644 --- a/x/feepay/types/genesis.go +++ b/x/feepay/types/genesis.go @@ -27,10 +27,7 @@ func (gs GenesisState) Validate() error { // Loop through all fee pay contracts and validate they // have a valid bech32 address for _, contract := range gs.FeePayContracts { - - _, err := sdk.AccAddressFromBech32(contract.ContractAddress) - - if err != nil { + if _, err := sdk.AccAddressFromBech32(contract.ContractAddress); err != nil { return err } } diff --git a/x/feepay/types/msg.go b/x/feepay/types/msg.go index 36a60b054..ccf77b176 100644 --- a/x/feepay/types/msg.go +++ b/x/feepay/types/msg.go @@ -62,7 +62,6 @@ func (msg MsgUnregisterFeePayContract) Type() string { return TypeMsgUnregisterF // ValidateBasic runs stateless checks on the message func (msg MsgUnregisterFeePayContract) ValidateBasic() error { - if _, err := sdk.AccAddressFromBech32(msg.SenderAddress); err != nil { return err } @@ -93,7 +92,6 @@ func (msg MsgFundFeePayContract) Type() string { return TypeMsgFundFeePayContrac // ValidateBasic runs stateless checks on the message func (msg MsgFundFeePayContract) ValidateBasic() error { - if _, err := sdk.AccAddressFromBech32(msg.SenderAddress); err != nil { return err } @@ -130,7 +128,6 @@ func (msg MsgUpdateFeePayContractWalletLimit) Type() string { // ValidateBasic runs stateless checks on the message func (msg MsgUpdateFeePayContractWalletLimit) ValidateBasic() error { - if _, err := sdk.AccAddressFromBech32(msg.SenderAddress); err != nil { return err } @@ -164,17 +161,17 @@ func (msg MsgUpdateParams) Route() string { return RouterKey } func (msg MsgUpdateParams) Type() string { return TypeMsgUpdateParams } // ValidateBasic does a sanity check on the provided data. -func (m *MsgUpdateParams) ValidateBasic() error { +func (msg *MsgUpdateParams) ValidateBasic() error { return nil } // GetSignBytes implements the LegacyMsg interface. -func (m MsgUpdateParams) GetSignBytes() []byte { - return sdk.MustSortJSON(ModuleCdc.MustMarshalJSON(&m)) +func (msg MsgUpdateParams) GetSignBytes() []byte { + return sdk.MustSortJSON(ModuleCdc.MustMarshalJSON(&msg)) } // GetSigners returns the expected signers for a MsgUpdateParams message. -func (m *MsgUpdateParams) GetSigners() []sdk.AccAddress { - addr, _ := sdk.AccAddressFromBech32(m.Authority) +func (msg *MsgUpdateParams) GetSigners() []sdk.AccAddress { + addr, _ := sdk.AccAddressFromBech32(msg.Authority) return []sdk.AccAddress{addr} } From 11ba89fd90ebc48ee3545b00de9d513e219deef0 Mon Sep 17 00:00:00 2001 From: Reece Williams Date: Tue, 10 Oct 2023 22:35:31 -0500 Subject: [PATCH 49/79] add feepay to v18 upgrade handler --- app/upgrades/v18/constants.go | 2 ++ app/upgrades/v18/upgrades.go | 6 ++++++ 2 files changed, 8 insertions(+) diff --git a/app/upgrades/v18/constants.go b/app/upgrades/v18/constants.go index 9f38f6b5c..a36963752 100644 --- a/app/upgrades/v18/constants.go +++ b/app/upgrades/v18/constants.go @@ -5,6 +5,7 @@ import ( "github.com/CosmosContracts/juno/v18/app/upgrades" cwhooks "github.com/CosmosContracts/juno/v18/x/cw-hooks" + feepaytypes "github.com/CosmosContracts/juno/v18/x/feepay/types" ) // UpgradeName defines the on-chain upgrade name for the upgrade. @@ -16,6 +17,7 @@ var Upgrade = upgrades.Upgrade{ StoreUpgrades: store.StoreUpgrades{ Added: []string{ cwhooks.ModuleName, + feepaytypes.ModuleName, }, }, } diff --git a/app/upgrades/v18/upgrades.go b/app/upgrades/v18/upgrades.go index 0007dfa0a..e990175ab 100644 --- a/app/upgrades/v18/upgrades.go +++ b/app/upgrades/v18/upgrades.go @@ -10,6 +10,7 @@ import ( "github.com/CosmosContracts/juno/v18/app/keepers" "github.com/CosmosContracts/juno/v18/app/upgrades" cwhookstypes "github.com/CosmosContracts/juno/v18/x/cw-hooks/types" + feepaytypes "github.com/CosmosContracts/juno/v18/x/feepay/types" ) func CreateV18UpgradeHandler( @@ -37,6 +38,11 @@ func CreateV18UpgradeHandler( return nil, err } + // x/feepay + k.FeePayKeeper.SetParams(ctx, feepaytypes.Params{ + EnableFeepay: true, + }) + return versionMap, err } } From e9ba5327b93599caa7eb3fd1eb6823afcbb8addd Mon Sep 17 00:00:00 2001 From: Reece Williams Date: Wed, 11 Oct 2023 13:45:18 -0500 Subject: [PATCH 50/79] default disable feepay for all e2e --- interchaintest/module_feepay_test.go | 5 +++++ interchaintest/setup.go | 4 ++++ 2 files changed, 9 insertions(+) diff --git a/interchaintest/module_feepay_test.go b/interchaintest/module_feepay_test.go index 68a08d89f..c283d4fd8 100644 --- a/interchaintest/module_feepay_test.go +++ b/interchaintest/module_feepay_test.go @@ -27,6 +27,11 @@ func TestJunoFeePay(t *testing.T) { Key: "app_state.globalfee.params.minimum_gas_prices", Value: sdk.DecCoins{coin}, }, + { + // override default impl. + Key: "app_state.feepay.params.enable_feepay", + Value: true, + }, }...)) // Base setup diff --git a/interchaintest/setup.go b/interchaintest/setup.go index bcc24a30d..603daf828 100644 --- a/interchaintest/setup.go +++ b/interchaintest/setup.go @@ -58,6 +58,10 @@ var ( Key: "app_state.gov.params.min_deposit.0.denom", Value: Denom, }, + { + Key: "app_state.feepay.params.enable_feepay", + Value: false, + }, } junoConfig = ibc.ChainConfig{ From 8e177675b1a8945c2c9b5a2d6f288c5b1fbbb967 Mon Sep 17 00:00:00 2001 From: Reece Williams Date: Wed, 11 Oct 2023 13:45:38 -0500 Subject: [PATCH 51/79] only feepayTx check if isEnabled --- app/upgrades/v18/upgrades.go | 6 ++++-- interchaintest/module_burn_test.go | 2 +- x/feepay/ante/deduct_fee.go | 12 ++++++------ 3 files changed, 11 insertions(+), 9 deletions(-) diff --git a/app/upgrades/v18/upgrades.go b/app/upgrades/v18/upgrades.go index e990175ab..e35ff2e14 100644 --- a/app/upgrades/v18/upgrades.go +++ b/app/upgrades/v18/upgrades.go @@ -39,9 +39,11 @@ func CreateV18UpgradeHandler( } // x/feepay - k.FeePayKeeper.SetParams(ctx, feepaytypes.Params{ + if err := k.FeePayKeeper.SetParams(ctx, feepaytypes.Params{ EnableFeepay: true, - }) + }); err != nil { + return nil, err + } return versionMap, err } diff --git a/interchaintest/module_burn_test.go b/interchaintest/module_burn_test.go index a34f38b13..d56595c68 100644 --- a/interchaintest/module_burn_test.go +++ b/interchaintest/module_burn_test.go @@ -52,7 +52,7 @@ func TestJunoBurnModule(t *testing.T) { // Verify the funds were sent, and burned. fmt.Println(balance, updatedBal) - assert.Equal(t, burnAmt, balance.Sub(updatedBal), fmt.Sprintf("balance should be %d less than updated balance", burnAmt)) + assert.Equal(t, burnAmt, balance.Sub(updatedBal).Int64(), fmt.Sprintf("balance should be %d less than updated balance", burnAmt)) t.Cleanup(func() { _ = ic.Close() diff --git a/x/feepay/ante/deduct_fee.go b/x/feepay/ante/deduct_fee.go index fc242cecc..cc5b70d48 100644 --- a/x/feepay/ante/deduct_fee.go +++ b/x/feepay/ante/deduct_fee.go @@ -124,7 +124,9 @@ func (dfd DeductFeeDecorator) checkDeductFee(ctx sdk.Context, sdkTx sdk.Tx, fee return sdkerrors.ErrUnknownAddress.Wrapf("fee payer address: %s does not exist", deductFeesFrom) } - if isValidFeePayTransaction(sdkTx, fee) { + isFeePayEnabled := dfd.feepayKeeper.GetParams(ctx).EnableFeepay + + if isFeePayEnabled && isValidFeePayTransaction(sdkTx, fee) { err := dfd.handleZeroFees(ctx, deductFeesFromAcc, sdkTx, fee) if err != nil { return err @@ -151,11 +153,6 @@ func (dfd DeductFeeDecorator) checkDeductFee(ctx sdk.Context, sdkTx sdk.Tx, fee // Handle zero fee transactions for fee prepay module func (dfd DeductFeeDecorator) handleZeroFees(ctx sdk.Context, deductFeesFromAcc types.AccountI, tx sdk.Tx, _ sdk.Coins) error { - // Prevent FeePay Tx from occurring when module is disabled - if !dfd.feepayKeeper.GetParams(ctx).EnableFeepay { - return feepaytypes.ErrFeePayDisabled - } - msg := tx.GetMsgs()[0] cw := msg.(*wasmtypes.MsgExecuteContract) @@ -242,6 +239,7 @@ func checkTxFeeWithValidatorMinGasPrices(ctx sdk.Context, tx sdk.Tx) (sdk.Coins, // if this is a CheckTx. This is only for local mempool purposes, and thus // is only ran on check tx. // TODO: see if we can remove, since we do call this twice. + // TODO: Validate feepay is enabled here? if ctx.IsCheckTx() && !isValidFeePayTransaction(tx, feeTx.GetFee()) { minGasPrices := ctx.MinGasPrices() if !minGasPrices.IsZero() { @@ -290,6 +288,8 @@ func getTxPriority(fee sdk.Coins, gas int64) int64 { func isValidFeePayTransaction(tx sdk.Tx, fee sdk.Coins) bool { // TODO: Future allow for multiple msgs. + // TODO: and ofc validate that the FeePay is enabled + // Check if fee is zero, and tx has only 1 message for executing a contract if fee.IsZero() && len(tx.GetMsgs()) == 1 { _, ok := (tx.GetMsgs()[0]).(*wasmtypes.MsgExecuteContract) From 6963292cb175f7d4a6ab211755cb2cbff57b1ecb Mon Sep 17 00:00:00 2001 From: Reece Williams Date: Wed, 11 Oct 2023 23:13:40 -0500 Subject: [PATCH 52/79] fix drip test:: don't be overly assertive --- interchaintest/ibc_transfer_test.go | 2 +- interchaintest/module_drip_test.go | 5 ----- 2 files changed, 1 insertion(+), 6 deletions(-) diff --git a/interchaintest/ibc_transfer_test.go b/interchaintest/ibc_transfer_test.go index 444dfd7f3..07332c7fd 100644 --- a/interchaintest/ibc_transfer_test.go +++ b/interchaintest/ibc_transfer_test.go @@ -112,7 +112,7 @@ func TestJunoGaiaIBCTransfer(t *testing.T) { // Get original account balances junoOrigBal, err := juno.GetBalance(ctx, junoUserAddr, juno.Config().Denom) require.NoError(t, err) - require.Equal(t, genesisWalletAmount, junoOrigBal) + require.Equal(t, genesisWalletAmount, junoOrigBal.Int64()) gaiaOrigBal, err := gaia.GetBalance(ctx, gaiaUserAddr, gaia.Config().Denom) require.NoError(t, err) diff --git a/interchaintest/module_drip_test.go b/interchaintest/module_drip_test.go index 7afe6347b..fe99fc07b 100644 --- a/interchaintest/module_drip_test.go +++ b/interchaintest/module_drip_test.go @@ -45,11 +45,6 @@ func TestJunoDrip(t *testing.T) { tfDenom := helpers.CreateTokenFactoryDenom(t, ctx, juno, user, "dripme", fmt.Sprintf("0%s", Denom)) distributeAmt := math.NewInt(1_000_000) helpers.MintTokenFactoryDenom(t, ctx, juno, user, distributeAmt.Uint64(), tfDenom) - if balance, err := juno.GetBalance(ctx, user.FormattedAddress(), tfDenom); err != nil { - t.Fatal(err) - } else if balance != distributeAmt { - t.Fatalf("balance not %d, got %d", distributeAmt, balance) - } // Stake some tokens vals := helpers.GetValidators(t, ctx, juno) From f400f1cc9160f3d1cba4dbb704793b44fa426c18 Mon Sep 17 00:00:00 2001 From: Reece Williams Date: Wed, 11 Oct 2023 23:14:08 -0500 Subject: [PATCH 53/79] upgrade test: standalone old version genesis cfg --- interchaintest/chain_upgrade_test.go | 25 +++++++++++++++++++++++-- 1 file changed, 23 insertions(+), 2 deletions(-) diff --git a/interchaintest/chain_upgrade_test.go b/interchaintest/chain_upgrade_test.go index 71a53dd1f..9cd909e1e 100644 --- a/interchaintest/chain_upgrade_test.go +++ b/interchaintest/chain_upgrade_test.go @@ -48,8 +48,27 @@ func CosmosChainUpgradeTest(t *testing.T, chainName, upgradeBranchVersion, upgra t.Log(chainName, upgradeBranchVersion, upgradeRepo, upgradeName) - numVals, numNodes := 4, 4 - chains := CreateChain(t, numVals, numNodes, baseChain) + previousVersionGenesis := []cosmos.GenesisKV{ + { + Key: "app_state.gov.params.voting_period", + Value: VotingPeriod, + }, + { + Key: "app_state.gov.params.max_deposit_period", + Value: MaxDepositPeriod, + }, + { + Key: "app_state.gov.params.min_deposit.0.denom", + Value: Denom, + }, + } + + cfg := junoConfig + cfg.ModifyGenesis = cosmos.ModifyGenesis(previousVersionGenesis) + cfg.Images = []ibc.DockerImage{baseChain} + + numVals, numNodes := 4, 0 + chains := CreateChainWithCustomConfig(t, numVals, numNodes, cfg) chain := chains[0].(*cosmos.CosmosChain) ic, ctx, client, _ := BuildInitialChain(t, chains) @@ -72,6 +91,8 @@ func CosmosChainUpgradeTest(t *testing.T, chainName, upgradeBranchVersion, upgra ValidatorVoting(t, ctx, chain, proposalID, height, haltHeight) UpgradeNodes(t, ctx, chain, client, haltHeight, upgradeRepo, upgradeBranchVersion) + + // TODO: ibc & wasm conformance test here } func UpgradeNodes(t *testing.T, ctx context.Context, chain *cosmos.CosmosChain, client *client.Client, haltHeight uint64, upgradeRepo, upgradeBranchVersion string) { From 471bf5eb915dd0d923e6c02bf82e25311d4fee55 Mon Sep 17 00:00:00 2001 From: Reece Williams Date: Wed, 11 Oct 2023 23:19:37 -0500 Subject: [PATCH 54/79] go mod tidy --- interchaintest/go.mod | 4 ++++ interchaintest/go.sum | 24 ++++++++++++------------ 2 files changed, 16 insertions(+), 12 deletions(-) diff --git a/interchaintest/go.mod b/interchaintest/go.mod index e410bc230..7dbed211b 100644 --- a/interchaintest/go.mod +++ b/interchaintest/go.mod @@ -113,7 +113,9 @@ require ( github.com/go-kit/kit v0.12.0 // indirect github.com/go-kit/log v0.2.1 // indirect github.com/go-logfmt/logfmt v0.6.0 // indirect + github.com/go-playground/validator/v10 v10.11.2 // indirect github.com/go-stack/stack v1.8.1 // indirect + github.com/goccy/go-json v0.10.0 // indirect github.com/godbus/dbus v0.0.0-20190726142602-4481cbc300e2 // indirect github.com/gogo/googleapis v1.4.1 // indirect github.com/gogo/protobuf v1.3.3 // indirect @@ -141,6 +143,7 @@ require ( github.com/hashicorp/go-getter v1.7.1 // indirect github.com/hashicorp/go-immutable-radix v1.3.1 // indirect github.com/hashicorp/go-safetemp v1.0.0 // indirect + github.com/hashicorp/go-uuid v1.0.2 // indirect github.com/hashicorp/go-version v1.6.0 // indirect github.com/hashicorp/golang-lru v0.5.5-0.20210104140557-80c98217689d // indirect github.com/hashicorp/hcl v1.0.0 // indirect @@ -216,6 +219,7 @@ require ( github.com/tidwall/btree v1.6.0 // indirect github.com/tyler-smith/go-bip32 v1.0.0 // indirect github.com/tyler-smith/go-bip39 v1.1.0 // indirect + github.com/ugorji/go/codec v1.2.9 // indirect github.com/ulikunitz/xz v0.5.11 // indirect github.com/zondax/hid v0.9.1 // indirect github.com/zondax/ledger-go v0.14.1 // indirect diff --git a/interchaintest/go.sum b/interchaintest/go.sum index c84bb3243..8e4e0f125 100644 --- a/interchaintest/go.sum +++ b/interchaintest/go.sum @@ -502,14 +502,14 @@ github.com/go-ole/go-ole v1.2.6 h1:/Fpf6oFPoeFik9ty7siob0G6Ke8QvQEuVcuChpwXzpY= github.com/go-ole/go-ole v1.2.6/go.mod h1:pprOEPIfldk/42T2oK7lQ4v4JSDwmV0As9GaiUsvbm0= github.com/go-playground/assert/v2 v2.0.1/go.mod h1:VDjEfimB/XKnb+ZQfWdccd7VUvScMdVu0Titje2rxJ4= github.com/go-playground/locales v0.13.0/go.mod h1:taPMhCMXrRLJO55olJkUXHZBHCxTMfnGwq/HNwmWNS8= -github.com/go-playground/locales v0.14.0 h1:u50s323jtVGugKlcYeyzC0etD1HifMjqmJqb8WugfUU= -github.com/go-playground/locales v0.14.0/go.mod h1:sawfccIbzZTqEDETgFXqTho0QybSa7l++s0DH+LDiLs= +github.com/go-playground/locales v0.14.1 h1:EWaQ/wswjilfKLTECiXz7Rh+3BjFhfDFKv/oXslEjJA= +github.com/go-playground/locales v0.14.1/go.mod h1:hxrqLVvrK65+Rwrd5Fc6F2O76J/NuW9t0sjnWqG1slY= github.com/go-playground/universal-translator v0.17.0/go.mod h1:UkSxE5sNxxRwHyU+Scu5vgOQjsIJAF8j9muTVoKLVtA= -github.com/go-playground/universal-translator v0.18.0 h1:82dyy6p4OuJq4/CByFNOn/jYrnRPArHwAcmLoJZxyho= -github.com/go-playground/universal-translator v0.18.0/go.mod h1:UvRDBj+xPUEGrFYl+lu/H90nyDXpg0fqeB/AQUGNTVA= +github.com/go-playground/universal-translator v0.18.1 h1:Bcnm0ZwsGyWbCzImXv+pAJnYK9S473LQFuzCbDbfSFY= +github.com/go-playground/universal-translator v0.18.1/go.mod h1:xekY+UJKNuX9WP91TpwSH2VMlDf28Uj24BCp08ZFTUY= github.com/go-playground/validator/v10 v10.2.0/go.mod h1:uOYAAleCW8F/7oMFd6aG0GOhaH6EGOAJShg8Id5JGkI= -github.com/go-playground/validator/v10 v10.11.1 h1:prmOlTVv+YjZjmRmNSF3VmspqJIxJWXmqUsHwfTRRkQ= -github.com/go-playground/validator/v10 v10.11.1/go.mod h1:i+3WkQ1FvaUjjxh1kSvIA4dMGDBiPU55YFDl0WbKdWU= +github.com/go-playground/validator/v10 v10.11.2 h1:q3SHpufmypg+erIExEKUmsgmhDTyhcJ38oeKGACXohU= +github.com/go-playground/validator/v10 v10.11.2/go.mod h1:NieE624vt4SCTJtD87arVLvdmjPAeV8BQlHtMnw9D7s= github.com/go-sql-driver/mysql v1.4.0/go.mod h1:zAC/RDZ24gD3HViQzih4MyKcchzm+sOG5ZlKdlhCg5w= github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY= github.com/go-stack/stack v1.8.1 h1:ntEHSVwIt7PNXNpgPmVfMrNhLtgjlmnZha2kOpuRiDw= @@ -521,8 +521,8 @@ github.com/gobwas/pool v0.2.0 h1:QEmUOlnSjWtnpRGHF3SauEiOsy82Cup83Vf2LcMlnc8= github.com/gobwas/pool v0.2.0/go.mod h1:q8bcK0KcYlCgd9e7WYLm9LpyS+YeLd8JVDW6WezmKEw= github.com/gobwas/ws v1.0.2 h1:CoAavW/wd/kulfZmSIBt6p24n4j7tHgNVCjsfHVNUbo= github.com/gobwas/ws v1.0.2/go.mod h1:szmBTxLgaFppYjEmNtny/v3w89xOydFnnZMcgRRu/EM= -github.com/goccy/go-json v0.9.11 h1:/pAaQDLHEoCq/5FFmSKBswWmK6H0e8g4159Kc/X/nqk= -github.com/goccy/go-json v0.9.11/go.mod h1:6MelG93GURQebXPDq3khkgXZkazVtN9CRI+MGFi0w8I= +github.com/goccy/go-json v0.10.0 h1:mXKd9Qw4NuzShiRlOXKews24ufknHO7gx30lsDyokKA= +github.com/goccy/go-json v0.10.0/go.mod h1:6MelG93GURQebXPDq3khkgXZkazVtN9CRI+MGFi0w8I= github.com/godbus/dbus v0.0.0-20190726142602-4481cbc300e2 h1:ZpnhV/YsD2/4cESfV5+Hoeu/iUR3ruzNvZ+yQfO03a0= github.com/godbus/dbus v0.0.0-20190726142602-4481cbc300e2/go.mod h1:bBOAhwG1umN6/6ZUMtDFBMQR8jRg9O75tm9K00oMsK4= github.com/godbus/dbus/v5 v5.0.4/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA= @@ -699,8 +699,9 @@ github.com/hashicorp/go-safetemp v1.0.0/go.mod h1:oaerMy3BhqiTbVye6QuFhFtIceqFoD github.com/hashicorp/go-sockaddr v1.0.0/go.mod h1:7Xibr9yA9JjQq1JpNB2Vw7kxv8xerXegt+ozgdvDeDU= github.com/hashicorp/go-syslog v1.0.0/go.mod h1:qPfqrKkXGihmCqbJM2mZgkZGvKG1dFdvsLplgctolz4= github.com/hashicorp/go-uuid v1.0.0/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro= -github.com/hashicorp/go-uuid v1.0.1 h1:fv1ep09latC32wFoVwnqcnKJGnMSdBanPczbHAYm1BE= github.com/hashicorp/go-uuid v1.0.1/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro= +github.com/hashicorp/go-uuid v1.0.2 h1:cfejS+Tpcp13yd5nYHWDI6qVCny6wyX2Mt5SGur2IGE= +github.com/hashicorp/go-uuid v1.0.2/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro= github.com/hashicorp/go-version v1.2.0/go.mod h1:fltr4n8CU8Ke44wwGCBoEymUuxUHl09ZGVZPK5anwXA= github.com/hashicorp/go-version v1.6.0 h1:feTTfFNnjP967rlCxM/I9g701jU+RN74YKx2mOkIeek= github.com/hashicorp/go-version v1.6.0/go.mod h1:fltr4n8CU8Ke44wwGCBoEymUuxUHl09ZGVZPK5anwXA= @@ -1100,12 +1101,11 @@ github.com/tyler-smith/go-bip32 v1.0.0 h1:sDR9juArbUgX+bO/iblgZnMPeWY1KZMUC2AFUJ github.com/tyler-smith/go-bip32 v1.0.0/go.mod h1:onot+eHknzV4BVPwrzqY5OoVpyCvnwD7lMawL5aQupE= github.com/tyler-smith/go-bip39 v1.1.0 h1:5eUemwrMargf3BSLRRCalXT93Ns6pQJIjYQN2nyfOP8= github.com/tyler-smith/go-bip39 v1.1.0/go.mod h1:gUYDtqQw1JS3ZJ8UWVcGTGqqr6YIN3CWg+kkNaLt55U= -github.com/ugorji/go v1.1.7 h1:/68gy2h+1mWMrwZFeD1kQialdSzAb432dtpeJ42ovdo= github.com/ugorji/go v1.1.7/go.mod h1:kZn38zHttfInRq0xu/PH0az30d+z6vm202qpg1oXVMw= github.com/ugorji/go/codec v0.0.0-20181204163529-d75b2dcb6bc8/go.mod h1:VFNgLljTbGfSG7qAOspJ7OScBnGdDN/yBr0sguwnwf0= github.com/ugorji/go/codec v1.1.7/go.mod h1:Ax+UKWsSmolVDwsd+7N3ZtXu+yMGCf907BLYF3GoBXY= -github.com/ugorji/go/codec v1.2.7 h1:YPXUKf7fYbp/y8xloBqZOw2qaVggbfwMlI8WM3wZUJ0= -github.com/ugorji/go/codec v1.2.7/go.mod h1:WGN1fab3R1fzQlVQTkfxVtIBhWDRqOviHU95kRgeqEY= +github.com/ugorji/go/codec v1.2.9 h1:rmenucSohSTiyL09Y+l2OCk+FrMxGMzho2+tjr5ticU= +github.com/ugorji/go/codec v1.2.9/go.mod h1:UNopzCgEMSXjBc6AOMqYvWC1ktqTAfzJZUZgYf6w6lg= github.com/ulikunitz/xz v0.5.10/go.mod h1:nbz6k7qbPmH4IRqmfOplQw/tblSgqTqBwxkY0oWt/14= github.com/ulikunitz/xz v0.5.11 h1:kpFauv27b6ynzBNT/Xy+1k+fK4WswhN/6PN5WhFAGw8= github.com/ulikunitz/xz v0.5.11/go.mod h1:nbz6k7qbPmH4IRqmfOplQw/tblSgqTqBwxkY0oWt/14= From 5bad633a6a9bffac7b5225b530483db9100c532a Mon Sep 17 00:00:00 2001 From: Reece Williams Date: Wed, 11 Oct 2023 23:34:03 -0500 Subject: [PATCH 55/79] fix ibc_test int64 -> math.Int cmp --- interchaintest/ibc_transfer_test.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/interchaintest/ibc_transfer_test.go b/interchaintest/ibc_transfer_test.go index 07332c7fd..5227a281d 100644 --- a/interchaintest/ibc_transfer_test.go +++ b/interchaintest/ibc_transfer_test.go @@ -116,7 +116,7 @@ func TestJunoGaiaIBCTransfer(t *testing.T) { gaiaOrigBal, err := gaia.GetBalance(ctx, gaiaUserAddr, gaia.Config().Denom) require.NoError(t, err) - require.Equal(t, genesisWalletAmount, gaiaOrigBal) + require.Equal(t, genesisWalletAmount, gaiaOrigBal.Int64()) // Compose an IBC transfer and send from Juno -> Gaia var transferAmount = math.NewInt(1_000) @@ -191,5 +191,5 @@ func TestJunoGaiaIBCTransfer(t *testing.T) { gaiaUpdateBal, err = gaia.GetBalance(ctx, gaiaUserAddr, junoIBCDenom) require.NoError(t, err) - require.Equal(t, int64(0), gaiaUpdateBal) + require.Equal(t, int64(0), gaiaUpdateBal.Int64()) } From 6d29035572ff58f325c6a3b147ab181a7466f7ab Mon Sep 17 00:00:00 2001 From: Reece Williams Date: Thu, 12 Oct 2023 00:02:29 -0500 Subject: [PATCH 56/79] Adds back POB test (v0.2.1) --- interchaintest/go.mod | 5 ++-- interchaintest/go.sum | 30 ++++--------------- ...pob_test.go.archive => module_pob_test.go} | 3 -- interchaintest/setup.go | 3 ++ 4 files changed, 10 insertions(+), 31 deletions(-) rename interchaintest/{module_pob_test.go.archive => module_pob_test.go} (83%) diff --git a/interchaintest/go.mod b/interchaintest/go.mod index 7dbed211b..aa49eb03f 100644 --- a/interchaintest/go.mod +++ b/interchaintest/go.mod @@ -18,12 +18,12 @@ replace ( ) require ( - // github.com/skip-mev/pob/tests/integration v0.1.0 // TODO: does not return a math.Int (update ictest on their end) github.com/CosmosContracts/juno/v18 v18.0.0-00010101000000-000000000000 github.com/cosmos/cosmos-sdk v0.47.5 github.com/cosmos/gogoproto v1.4.10 github.com/cosmos/ibc-go/v7 v7.3.0 github.com/docker/docker v24.0.5+incompatible + github.com/skip-mev/pob/tests/integration v0.2.1 github.com/strangelove-ventures/interchaintest/v7 v7.0.0-20231009173908-4e98e35e363e github.com/stretchr/testify v1.8.4 go.uber.org/zap v1.25.0 @@ -143,7 +143,6 @@ require ( github.com/hashicorp/go-getter v1.7.1 // indirect github.com/hashicorp/go-immutable-radix v1.3.1 // indirect github.com/hashicorp/go-safetemp v1.0.0 // indirect - github.com/hashicorp/go-uuid v1.0.2 // indirect github.com/hashicorp/go-version v1.6.0 // indirect github.com/hashicorp/golang-lru v0.5.5-0.20210104140557-80c98217689d // indirect github.com/hashicorp/hcl v1.0.0 // indirect @@ -188,7 +187,6 @@ require ( github.com/multiformats/go-varint v0.0.7 // indirect github.com/opencontainers/go-digest v1.0.0 // indirect github.com/opencontainers/image-spec v1.1.0-rc2 // indirect - github.com/opencontainers/runc v1.1.5 // indirect github.com/pelletier/go-toml v1.9.5 // indirect github.com/pelletier/go-toml/v2 v2.0.9 // indirect github.com/petermattis/goid v0.0.0-20230518223814-80aa455d8761 // indirect @@ -206,6 +204,7 @@ require ( github.com/rs/cors v1.8.3 // indirect github.com/rs/zerolog v1.30.0 // indirect github.com/sasha-s/go-deadlock v0.3.1 // indirect + github.com/skip-mev/pob v1.0.4 // indirect github.com/spaolacci/murmur3 v1.1.0 // indirect github.com/spf13/afero v1.9.5 // indirect github.com/spf13/cast v1.5.1 // indirect diff --git a/interchaintest/go.sum b/interchaintest/go.sum index 8e4e0f125..c1b73fa20 100644 --- a/interchaintest/go.sum +++ b/interchaintest/go.sum @@ -304,7 +304,6 @@ github.com/cespare/xxhash v1.1.0/go.mod h1:XrSqR1VqqWfGrhpAt58auRo0WTKS1nRRg3ghf github.com/cespare/xxhash/v2 v2.1.1/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= github.com/cespare/xxhash/v2 v2.2.0 h1:DC2CZ1Ep5Y4k3ZQ899DldepgrayRUGE6BBZ/cd9Cj44= github.com/cespare/xxhash/v2 v2.2.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= -github.com/checkpoint-restore/go-criu/v5 v5.3.0/go.mod h1:E/eQpaFtUKGOOSEBZgmKAcn+zUUwWxqcaKZlF54wK8E= github.com/cheggaaa/pb v1.0.27/go.mod h1:pQciLPpbU0oxA0h+VJYYLxO+XeDQb5pZijXscXHm81s= github.com/chzyer/logex v1.1.10/go.mod h1:+Ywpsq7O8HXn0nuIou7OrIPyXbp3wmkHB+jjWRnGsAI= github.com/chzyer/logex v1.2.1 h1:XHDu3E6q+gdHgsdTPH6ImJMIp436vR6MPtH8gP05QzM= @@ -315,7 +314,6 @@ github.com/chzyer/readline v1.5.1/go.mod h1:Eh+b79XXUwfKfcPLepksvw2tcLE/Ct21YObk github.com/chzyer/test v0.0.0-20180213035817-a1ea475d72b1/go.mod h1:Q3SI9o4m/ZMnBNeIyt5eFwwo7qiLfzFZmjNmxjkiQlU= github.com/chzyer/test v1.0.0 h1:p3BQDXSxOhOG0P9z6/hGnII4LGiEPOYBhs8asl/fC04= github.com/chzyer/test v1.0.0/go.mod h1:2JlltgoNkt4TW/z9V/IzDdFaMTM2JPIi26O1pF38GC8= -github.com/cilium/ebpf v0.7.0/go.mod h1:/oI2+1shJiTGAMgl6/RgJr36Eo1jzrRcAWbcXO2usCA= github.com/circonus-labs/circonus-gometrics v2.3.1+incompatible/go.mod h1:nmEj6Dob7S7YxXgwXpfOuvO54S+tGdZdw9fuRZt25Ag= github.com/circonus-labs/circonusllhist v0.1.3/go.mod h1:kMXHVDlOchFAehlya5ePtbp5jckzBHf4XRpQvBOLI+I= github.com/clbanning/x2j v0.0.0-20191024224557-825249438eec/go.mod h1:jMjuTZXRI4dUb/I5gc9Hdhagfvm9+RyrPryS/auMzxE= @@ -349,14 +347,12 @@ github.com/cometbft/cometbft-db v0.8.0 h1:vUMDaH3ApkX8m0KZvOFFy9b5DZHBAjsnEuo9AK github.com/cometbft/cometbft-db v0.8.0/go.mod h1:6ASCP4pfhmrCBpfk01/9E1SI29nD3HfVHrY4PG8x5c0= github.com/confio/ics23/go v0.9.0 h1:cWs+wdbS2KRPZezoaaj+qBleXgUk5WOQFMP3CQFGTr4= github.com/confio/ics23/go v0.9.0/go.mod h1:4LPZ2NYqnYIVRklaozjNR1FScgDJ2s5Xrp+e/mYVRak= -github.com/containerd/console v1.0.3/go.mod h1:7LqA/THxQ86k76b8c/EMSiaJ3h1eZkMkXar0TQ1gf3U= github.com/containerd/continuity v0.3.0 h1:nisirsYROK15TAMVukJOUyGJjz4BNQJBVsNvAXZJ/eg= github.com/containerd/continuity v0.3.0/go.mod h1:wJEAIwKOm/pBZuBd0JmeTvnLquTB1Ag8espWhkykbPM= github.com/coreos/etcd v3.3.10+incompatible/go.mod h1:uF7uidLiAD3TWHmW31ZFd/JWoc32PjwdhPthX9715RE= github.com/coreos/go-etcd v2.0.0+incompatible/go.mod h1:Jez6KQU2B/sWsbdaef3ED8NzMklzPG4d5KIOhIy30Tk= github.com/coreos/go-semver v0.2.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3EedlOD2RNk= github.com/coreos/go-systemd v0.0.0-20180511133405-39ca1b05acc7/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4= -github.com/coreos/go-systemd/v22 v22.3.2/go.mod h1:Y58oyj3AT4RCenI/lSvhwexgC+NSVTIJ3seZv2GcEnc= github.com/coreos/go-systemd/v22 v22.5.0/go.mod h1:Y58oyj3AT4RCenI/lSvhwexgC+NSVTIJ3seZv2GcEnc= github.com/coreos/pkg v0.0.0-20160727233714-3ac0863d7acf/go.mod h1:E3G3o1h8I7cfcXa63jLwjI0eiQQMgzzUDFVpN/nH/eA= github.com/cosmos/btcutil v1.0.5 h1:t+ZFcX77LpKtDBhjucvnOH8C2l2ioGsBNEQ3jef8xFk= @@ -392,7 +388,6 @@ github.com/creachadair/taskgroup v0.4.2 h1:jsBLdAJE42asreGss2xZGZ8fJra7WtwnHWeJF github.com/creachadair/taskgroup v0.4.2/go.mod h1:qiXUOSrbwAY3u0JPGTzObbE3yf9hcXHDKBZ2ZjpCbgM= github.com/creack/pty v1.1.7/go.mod h1:lj5s0c3V2DBrqTV7llrYr5NG6My20zk30Fl46Y7DoTY= github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E= -github.com/cyphar/filepath-securejoin v0.2.3/go.mod h1:aPGpWjXOXUn2NCNjFvBE6aRxGGx79pTxQpKOJNYHHl4= github.com/danieljoos/wincred v1.1.2 h1:QLdCxFs1/Yl4zduvBdcHB8goaYk9RARS2SgLLRuAyr0= github.com/danieljoos/wincred v1.1.2/go.mod h1:GijpziifJoIBfYh+S7BbkdUTU4LfM+QnGqR5Vl2tAx0= github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= @@ -430,7 +425,6 @@ github.com/docker/docker v24.0.5+incompatible h1:WmgcE4fxyI6EEXxBRxsHnZXrO1pQ3sm github.com/docker/docker v24.0.5+incompatible/go.mod h1:eEKB0N0r5NX/I1kEveEz05bcu8tLC/8azJZsviup8Sk= github.com/docker/go-connections v0.4.0 h1:El9xVISelRB7BuFusrZozjnkIM5YnzCViNKohAFqRJQ= github.com/docker/go-connections v0.4.0/go.mod h1:Gbd7IOopHjR8Iph03tsViu4nIes5XhDvyHbTtUxmeec= -github.com/docker/go-units v0.4.0/go.mod h1:fgPhTUdO+D/Jk86RDLlptpiXQzgHJF7gydDDbaIK4Dk= github.com/docker/go-units v0.5.0 h1:69rxXcBk27SvSaaxTtLh/8llcHD8vYHT7WSdRZ/jvr4= github.com/docker/go-units v0.5.0/go.mod h1:fgPhTUdO+D/Jk86RDLlptpiXQzgHJF7gydDDbaIK4Dk= github.com/dustin/go-humanize v0.0.0-20171111073723-bb3d318650d4/go.mod h1:HtrtbFcZ19U5GC7JDqmcUSB87Iq5E25KnS6fMYU6eOk= @@ -464,7 +458,6 @@ github.com/fortytw2/leaktest v1.3.0 h1:u8491cBMTQ8ft8aeV+adlcytMZylmA5nnwwkRZjI8 github.com/fortytw2/leaktest v1.3.0/go.mod h1:jDsjWgpAGjm2CA7WthBh/CdZYEPF31XHquHwclZch5g= github.com/franela/goblin v0.0.0-20200105215937-c9ffbefa60db/go.mod h1:7dvUGVsVBjqR7JHJk0brhHOZYGmfBYOrK0ZhYMEtBr4= github.com/franela/goreq v0.0.0-20171204163338-bcd34c9993f8/go.mod h1:ZhphrRTfi2rbfLwlschooIH4+wKKDR4Pdxhh+TRoA20= -github.com/frankban/quicktest v1.11.3/go.mod h1:wRf/ReqHper53s+kmmSZizM8NamnL3IM0I9ntUbOk+k= github.com/frankban/quicktest v1.14.4 h1:g2rn0vABPOOXmZUj+vbmUp0lPoXEMuhTpIluN0XL9UY= github.com/frankban/quicktest v1.14.4/go.mod h1:4ptaffx2x8+WTWXmUCuVU6aPUX1/Mz7zb5vbUoiM6w0= github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo= @@ -526,7 +519,6 @@ github.com/goccy/go-json v0.10.0/go.mod h1:6MelG93GURQebXPDq3khkgXZkazVtN9CRI+MG github.com/godbus/dbus v0.0.0-20190726142602-4481cbc300e2 h1:ZpnhV/YsD2/4cESfV5+Hoeu/iUR3ruzNvZ+yQfO03a0= github.com/godbus/dbus v0.0.0-20190726142602-4481cbc300e2/go.mod h1:bBOAhwG1umN6/6ZUMtDFBMQR8jRg9O75tm9K00oMsK4= github.com/godbus/dbus/v5 v5.0.4/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA= -github.com/godbus/dbus/v5 v5.0.6/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA= github.com/gogo/googleapis v1.1.0/go.mod h1:gf4bu3Q80BeJ6H1S1vYPm8/ELATdvryBaNFGgqEef3s= github.com/gogo/googleapis v1.4.1-0.20201022092350-68b0159b7869/go.mod h1:5YRNX2z1oM5gXdAkurHa942MDgEJyk02w4OecKY87+c= github.com/gogo/googleapis v1.4.1 h1:1Yx4Myt7BxzvUr5ldGSbwYiZG6t9wGBZ+8/fX3Wvtq0= @@ -699,9 +691,8 @@ github.com/hashicorp/go-safetemp v1.0.0/go.mod h1:oaerMy3BhqiTbVye6QuFhFtIceqFoD github.com/hashicorp/go-sockaddr v1.0.0/go.mod h1:7Xibr9yA9JjQq1JpNB2Vw7kxv8xerXegt+ozgdvDeDU= github.com/hashicorp/go-syslog v1.0.0/go.mod h1:qPfqrKkXGihmCqbJM2mZgkZGvKG1dFdvsLplgctolz4= github.com/hashicorp/go-uuid v1.0.0/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro= +github.com/hashicorp/go-uuid v1.0.1 h1:fv1ep09latC32wFoVwnqcnKJGnMSdBanPczbHAYm1BE= github.com/hashicorp/go-uuid v1.0.1/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro= -github.com/hashicorp/go-uuid v1.0.2 h1:cfejS+Tpcp13yd5nYHWDI6qVCny6wyX2Mt5SGur2IGE= -github.com/hashicorp/go-uuid v1.0.2/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro= github.com/hashicorp/go-version v1.2.0/go.mod h1:fltr4n8CU8Ke44wwGCBoEymUuxUHl09ZGVZPK5anwXA= github.com/hashicorp/go-version v1.6.0 h1:feTTfFNnjP967rlCxM/I9g701jU+RN74YKx2mOkIeek= github.com/hashicorp/go-version v1.6.0/go.mod h1:fltr4n8CU8Ke44wwGCBoEymUuxUHl09ZGVZPK5anwXA= @@ -780,7 +771,6 @@ github.com/konsorten/go-windows-terminal-sequences v1.0.3/go.mod h1:T0+1ngSBFLxv github.com/kr/fs v0.1.0/go.mod h1:FFnZGqtBN9Gxj7eW1uZ42v5BccTP0vu6NEaFoC2HwRg= github.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515/go.mod h1:+0opPa2QZZtGFBFZlji/RkVcI2GknAs/DXo4wKdlNEc= github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= -github.com/kr/pretty v0.2.1/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI= github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE= github.com/kr/pretty v0.3.1/go.mod h1:hoEshYVHaxMs3cyo3Yncou5ZscifuDolrwPKZanG3xk= github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= @@ -847,7 +837,6 @@ github.com/mitchellh/mapstructure v0.0.0-20160808181253-ca63d7c062ee/go.mod h1:F github.com/mitchellh/mapstructure v1.1.2/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y= github.com/mitchellh/mapstructure v1.5.0 h1:jeMsZIYE/09sWLaz43PL7Gy6RuMjD2eJVyuac5Z2hdY= github.com/mitchellh/mapstructure v1.5.0/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo= -github.com/moby/sys/mountinfo v0.5.0/go.mod h1:3bMD3Rg+zkqx8MRYPi7Pyb0Ie97QEBmdxbhnCLlSvSU= github.com/moby/term v0.0.0-20220808134915-39b0c02b01ae h1:O4SWKdcHVCvYqyDV+9CJA1fcDN2L11Bule0iFy3YlAI= github.com/moby/term v0.0.0-20220808134915-39b0c02b01ae/go.mod h1:E2VnQOmVuvZB6UYnnDB0qG5Nq/1tD9acaOpo6xmt0Kw= github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= @@ -861,7 +850,6 @@ github.com/morikuni/aec v1.0.0 h1:nP9CBfwrvYnBRgY6qfDQkygYDmYwOilePFkwzv4dU8A= github.com/morikuni/aec v1.0.0/go.mod h1:BbKIizmSmc5MMPqRYbxO4ZU0S0+P200+tUnFx7PXmsc= github.com/mr-tron/base58 v1.2.0 h1:T/HDJBh4ZCPbU39/+c3rRvE0uKBQlU27+QI8LJ4t64o= github.com/mr-tron/base58 v1.2.0/go.mod h1:BinMc/sQntlIE1frQmRFPUoPA1Zkr8VRgBdjWI2mNwc= -github.com/mrunalp/fileutils v0.5.0/go.mod h1:M1WthSahJixYnrXQl/DFQuteStB1weuxD2QJNHXfbSQ= github.com/mtibben/percent v0.2.1 h1:5gssi8Nqo8QU/r2pynCm+hBQHpkB/uNK7BJCFogWdzs= github.com/mtibben/percent v0.2.1/go.mod h1:KG9uO+SZkUp+VkRHsCdYQV3XSZrrSpR3O9ibNBTZrns= github.com/multiformats/go-base32 v0.1.0 h1:pVx9xoSPqEIQG8o+UbAe7DNi51oej1NtK+aGkbLYxPE= @@ -917,8 +905,6 @@ github.com/opencontainers/image-spec v1.1.0-rc2 h1:2zx/Stx4Wc5pIPDvIxHXvXtQFW/7X github.com/opencontainers/image-spec v1.1.0-rc2/go.mod h1:3OVijpioIKYWTqjiG0zfF6wvoJ4fAXGbjdZuI2NgsRQ= github.com/opencontainers/runc v1.1.5 h1:L44KXEpKmfWDcS02aeGm8QNTFXTo2D+8MYGDIJ/GDEs= github.com/opencontainers/runc v1.1.5/go.mod h1:1J5XiS+vdZ3wCyZybsuxXZWGrgSr8fFJHLXuG2PsnNg= -github.com/opencontainers/runtime-spec v1.0.3-0.20210326190908-1c3f411f0417/go.mod h1:jwyrGlmzljRJv/Fgzds9SsS/C5hL+LL3ko9hs6T5lQ0= -github.com/opencontainers/selinux v1.10.0/go.mod h1:2i0OySw99QjzBBQByd1Gr9gSjvuho1lHsJxIJ3gGbJI= github.com/opentracing-contrib/go-observer v0.0.0-20170622124052-a52f23424492/go.mod h1:Ngi6UdF0k5OKD5t5wlmGhe/EDKPoUM3BXZSSfIuJbis= github.com/opentracing/basictracer-go v1.0.0/go.mod h1:QfBfYuafItcjQuMwinw9GhYKwFXS9KnPs5lxoYwgW74= github.com/opentracing/opentracing-go v1.0.2/go.mod h1:UkNAQd3GIcIGf0SeVgPpRdFStlNbqXla1AfSYxPUl2o= @@ -1021,7 +1007,6 @@ github.com/samuel/go-zookeeper v0.0.0-20190923202752-2cc03de413da/go.mod h1:gi+0 github.com/sasha-s/go-deadlock v0.3.1 h1:sqv7fDNShgjcaxkO0JNcOAlr8B9+cV5Ey/OB71efZx0= github.com/sasha-s/go-deadlock v0.3.1/go.mod h1:F73l+cr82YSh10GxyRI6qZiCgK64VaZjwesgfQ1/iLM= github.com/sean-/seed v0.0.0-20170313163322-e2103e2c3529/go.mod h1:DxrIzT+xaE7yg65j358z/aeFdxmN0P9QXhEzd20vsDc= -github.com/seccomp/libseccomp-golang v0.9.2-0.20220502022130-f33da4d89646/go.mod h1:JA8cRccbGaA1s33RQf7Y1+q9gHmZX1yB/z9WDN1C6fg= github.com/shirou/gopsutil v3.21.4-0.20210419000835-c7a38de76ee5+incompatible h1:Bn1aCHHRnjv4Bl16T8rcaFjYSrGrIZvpiGO6P3Q4GpU= github.com/shirou/gopsutil v3.21.4-0.20210419000835-c7a38de76ee5+incompatible/go.mod h1:5b4v6he4MtMOwMlS0TUMTu2PcXUg8+E1lC7eC3UO/RA= github.com/shurcooL/sanitized_anchor_name v1.0.0/go.mod h1:1NzhyTcUVG4SuEtjjoZeVRXNmyL/1OwPU0+IJeTBvfc= @@ -1029,9 +1014,12 @@ github.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPx github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE= github.com/sirupsen/logrus v1.6.0/go.mod h1:7uNnSEd1DgxDLC74fIahvMZmmYsHGZGEOFrfsX/uA88= github.com/sirupsen/logrus v1.7.0/go.mod h1:yWOB1SBYBC5VeMP7gHvWumXLIWorT60ONWic61uBYv0= -github.com/sirupsen/logrus v1.8.1/go.mod h1:yWOB1SBYBC5VeMP7gHvWumXLIWorT60ONWic61uBYv0= github.com/sirupsen/logrus v1.9.0 h1:trlNQbNUG3OdDrDil03MCb1H2o9nJ1x4/5LYw7byDE0= github.com/sirupsen/logrus v1.9.0/go.mod h1:naHLuLoDiP4jHNo9R0sCBMtWGeIprob74mVsIT4qYEQ= +github.com/skip-mev/pob v1.0.4 h1:Degz+Pdm9pCom16bbLawZhXi6PbYPiiJe6cGjBE5g30= +github.com/skip-mev/pob v1.0.4/go.mod h1:tpZivmkiDgCO6O79qBnK4eJQjuJeR9yUzc1jPlGaE1s= +github.com/skip-mev/pob/tests/integration v0.2.1 h1:wcPDPjoNxQuUXVEh4rxQiKcy+6RsFgR0KJtx1mpGHw8= +github.com/skip-mev/pob/tests/integration v0.2.1/go.mod h1:phISQRFLBUcY32qyiQLVzJ7lRNDTCpOHez7YwEyTWhQ= github.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d/go.mod h1:OnSkiWE9lh6wB0YB77sQom3nweQdgAjqCqsofrRNTgc= github.com/smartystreets/goconvey v1.6.4/go.mod h1:syvi0/a8iFYH4r/RixwvyeAJjdLS9QV7WQ/tjFTllLA= github.com/soheilhy/cmux v0.1.4/go.mod h1:IM3LyeVVIOuxMH7sFAkER9+bJ4dT7Ms6E4xg4kGIyLM= @@ -1084,7 +1072,6 @@ github.com/stretchr/testify v1.8.4 h1:CcVxjf3Q8PM0mHUKJCdn+eZZtm5yQwehR5yeSVQQcU github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo= github.com/subosito/gotenv v1.4.2 h1:X1TuBLAMDFbaTAChgCBLu3DU3UPyELpnF2jjJ2cz/S8= github.com/subosito/gotenv v1.4.2/go.mod h1:ayKnFf/c6rvx/2iiLrJUk1e6plDbT3edrFNGqEflhK0= -github.com/syndtr/gocapability v0.0.0-20200815063812-42c35b437635/go.mod h1:hkRG7XYTFWNJGYcbNJQlaLq0fg1yr4J4t/NcTQtrfww= github.com/syndtr/goleveldb v1.0.1-0.20220721030215-126854af5e6d h1:vfofYNRScrDdvS342BElfbETmL1Aiz3i2t0zfRj16Hs= github.com/syndtr/goleveldb v1.0.1-0.20220721030215-126854af5e6d/go.mod h1:RRCYJbIwD5jmqPI9XoAFR0OcDxqUctll6zUj/+B4S48= github.com/tendermint/go-amino v0.16.0 h1:GyhmgQKvqF82e2oZeuMSp9JTN0N09emoSZlb2lyGa2E= @@ -1111,8 +1098,6 @@ github.com/ulikunitz/xz v0.5.11 h1:kpFauv27b6ynzBNT/Xy+1k+fK4WswhN/6PN5WhFAGw8= github.com/ulikunitz/xz v0.5.11/go.mod h1:nbz6k7qbPmH4IRqmfOplQw/tblSgqTqBwxkY0oWt/14= github.com/urfave/cli v1.20.0/go.mod h1:70zkFmudgCuE/ngEzBv17Jvp/497gISqfk5gWijbERA= github.com/urfave/cli v1.22.1/go.mod h1:Gos4lmkARVdJ6EkW0WaNv/tZAAMe9V7XWyB60NtXRu0= -github.com/vishvananda/netlink v1.1.0/go.mod h1:cTgwzPIzzgDAYoQrMm0EdrjRUBkTqKYppBueQtXaqoE= -github.com/vishvananda/netns v0.0.0-20191106174202-0a2b9b5464df/go.mod h1:JP3t17pCcGlemwknint6hfoeCVQrEMVwxRLRjXpq+BU= github.com/xiang90/probing v0.0.0-20190116061207-43a291ad63a2/go.mod h1:UETIi67q53MR2AWcXfiuqkDkRtnGDLqkBTpCHuJHxtU= github.com/xordataexchange/crypt v0.0.3-0.20170626215501-b2862e3d0a77/go.mod h1:aYKd//L2LvnjZzWKhF00oedf4jCCReLcmhLdhm1A27Q= github.com/yuin/goldmark v1.1.25/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= @@ -1341,7 +1326,6 @@ golang.org/x/sys v0.0.0-20190422165155-953cdadca894/go.mod h1:h1NjWce9XRLGQEsW7w golang.org/x/sys v0.0.0-20190502145724-3ef323f4f1fd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190507160741-ecd444e8653b/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190606165138-5da285871e9c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20190606203320-7fc4e5ec1444/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190624142023-c5567b49c5d0/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190626221950-04f50cda93cb/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190726091711-fc99dfbffb4e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= @@ -1350,7 +1334,6 @@ golang.org/x/sys v0.0.0-20190904154756-749cb33beabd/go.mod h1:h1NjWce9XRLGQEsW7w golang.org/x/sys v0.0.0-20191001151750-bb3f8db39f24/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191005200804-aed5e4c7ecf9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191026070338-33540a1f6037/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20191115151921-52ab43148777/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191120155948-bd437916bb0e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191204072324-ce4227a45e2e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191220142924-d4481acd189f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= @@ -1380,7 +1363,6 @@ golang.org/x/sys v0.0.0-20201201145000-ef89a241ccb3/go.mod h1:h1NjWce9XRLGQEsW7w golang.org/x/sys v0.0.0-20210104204734-6f8348627aad/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210112080510-489259a85091/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210119212857-b64e53b001e4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20210124154548-22da62e12c0c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210220050731-9a76102bfb43/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210225134936-a50acf3fe073/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210305230114-8fe3ee5dd75b/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= @@ -1399,11 +1381,9 @@ golang.org/x/sys v0.0.0-20210806184541-e5e7981a1069/go.mod h1:oPkhp1MJrh7nUepCBc golang.org/x/sys v0.0.0-20210809222454-d867a43fc93e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20210819135213-f52c844e1c1c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20210823070655-63515b42dcdf/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20210906170528-6f6e22806c34/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20210908233432-aa78b53d3365/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20210927094055-39ccf1dd6fa6/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20211025201205-69cdffdb9359/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20211116061358-0a5406a5449c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20211124211545-fe61309f8881/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20211210111614-af8b64212486/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20211216021012-1d35b9e2eb4e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= diff --git a/interchaintest/module_pob_test.go.archive b/interchaintest/module_pob_test.go similarity index 83% rename from interchaintest/module_pob_test.go.archive rename to interchaintest/module_pob_test.go index 909a65fde..f41c2281f 100644 --- a/interchaintest/module_pob_test.go.archive +++ b/interchaintest/module_pob_test.go @@ -9,9 +9,6 @@ import ( "github.com/stretchr/testify/suite" ) -// TODO: This is archived for now becuase: -// /home/reece/.gvm/pkgsets/go1.21/global/pkg/mod/github.com/skip-mev/pob/tests/integration@v0.1.0/chain_setup.go:242:9: cannot use balance (variable of type "cosmossdk.io/math".Int) as int64 value in return statement - var ( numVals = 4 numFull = 0 diff --git a/interchaintest/setup.go b/interchaintest/setup.go index 603daf828..3c64c9126 100644 --- a/interchaintest/setup.go +++ b/interchaintest/setup.go @@ -88,6 +88,9 @@ var ( func init() { sdk.GetConfig().SetBech32PrefixForAccount("juno", "juno") + sdk.GetConfig().SetBech32PrefixForValidator("junovaloper", "juno") + sdk.GetConfig().SetBech32PrefixForConsensusNode("junovalcons", "juno") + sdk.GetConfig().SetCoinType(118) } // junoEncoding registers the Juno specific module codecs so that the associated types and msgs From 6c4dbe7229a95a0e5f696d96867e5201343848c0 Mon Sep 17 00:00:00 2001 From: Joel Smith Date: Fri, 13 Oct 2023 11:33:09 -0500 Subject: [PATCH 57/79] Integrate GlobalFee with FeePay (wip) --- app/ante.go | 3 ++- x/feepay/ante/deduct_fee.go | 9 ++++----- x/globalfee/ante/fee.go | 11 ++++++++++- 3 files changed, 16 insertions(+), 7 deletions(-) diff --git a/app/ante.go b/app/ante.go index 76a8fa38b..0df9bab7c 100644 --- a/app/ante.go +++ b/app/ante.go @@ -25,6 +25,7 @@ import ( feepaykeeper "github.com/CosmosContracts/juno/v18/x/feepay/keeper" feeshareante "github.com/CosmosContracts/juno/v18/x/feeshare/ante" feesharekeeper "github.com/CosmosContracts/juno/v18/x/feeshare/keeper" + globalfeeante "github.com/CosmosContracts/juno/v18/x/globalfee/ante" globalfeekeeper "github.com/CosmosContracts/juno/v18/x/globalfee/keeper" ) @@ -89,7 +90,7 @@ func NewAnteHandler(options HandlerOptions) (sdk.AnteHandler, error) { ante.NewTxTimeoutHeightDecorator(), ante.NewValidateMemoDecorator(options.AccountKeeper), ante.NewConsumeGasForTxSizeDecorator(options.AccountKeeper), - // globalfeeante.NewFeeDecorator(options.BypassMinFeeMsgTypes, options.GlobalFeeKeeper, options.StakingKeeper, maxBypassMinFeeMsgGasUsage), // TODO: Has a minimum fee requirement check. So if 0 fees are passed, but 500 fee is required, it fails. + globalfeeante.NewFeeDecorator(options.BypassMinFeeMsgTypes, options.GlobalFeeKeeper, options.StakingKeeper, maxBypassMinFeeMsgGasUsage), feepayante.NewDeductFeeDecorator(options.FeePayKeeper, options.GlobalFeeKeeper, options.AccountKeeper, options.BankKeeper, options.FeegrantKeeper, options.TxFeeChecker, options.BondDenom), feeshareante.NewFeeSharePayoutDecorator(options.BankKeeper, options.FeeShareKeeper), // SetPubKeyDecorator must be called before all signature verification decorators diff --git a/x/feepay/ante/deduct_fee.go b/x/feepay/ante/deduct_fee.go index cc5b70d48..244c3f410 100644 --- a/x/feepay/ante/deduct_fee.go +++ b/x/feepay/ante/deduct_fee.go @@ -238,8 +238,6 @@ func checkTxFeeWithValidatorMinGasPrices(ctx sdk.Context, tx sdk.Tx) (sdk.Coins, // Ensure that the provided fees meet a minimum threshold for the validator, // if this is a CheckTx. This is only for local mempool purposes, and thus // is only ran on check tx. - // TODO: see if we can remove, since we do call this twice. - // TODO: Validate feepay is enabled here? if ctx.IsCheckTx() && !isValidFeePayTransaction(tx, feeTx.GetFee()) { minGasPrices := ctx.MinGasPrices() if !minGasPrices.IsZero() { @@ -283,12 +281,13 @@ func getTxPriority(fee sdk.Coins, gas int64) int64 { return priority } -// Check if a transaction should be processed as a FeePay transaction. -// A valid FeePay transaction has no fee, and only 1 message for executing a contract. +// Check if a transaction should be processed as a FeePay transaction. Ensure that +// the Fee Pay module is enabled before calling this function. A valid FeePay transaction +// has no fee, and only 1 message for executing a contract. func isValidFeePayTransaction(tx sdk.Tx, fee sdk.Coins) bool { // TODO: Future allow for multiple msgs. - // TODO: and ofc validate that the FeePay is enabled + // TODO: Move to a new file to share with global fee, also check if FeePay is enabled // Check if fee is zero, and tx has only 1 message for executing a contract if fee.IsZero() && len(tx.GetMsgs()) == 1 { diff --git a/x/globalfee/ante/fee.go b/x/globalfee/ante/fee.go index dcfa44f87..210369f28 100644 --- a/x/globalfee/ante/fee.go +++ b/x/globalfee/ante/fee.go @@ -12,6 +12,8 @@ import ( stakingkeeper "github.com/cosmos/cosmos-sdk/x/staking/keeper" globalfeekeeper "github.com/CosmosContracts/juno/v18/x/globalfee/keeper" + + wasmtypes "github.com/CosmWasm/wasmd/x/wasm/types" ) // FeeWithBypassDecorator checks if the transaction's fee is at least as large @@ -50,8 +52,15 @@ func (mfd FeeDecorator) AnteHandle(ctx sdk.Context, tx sdk.Tx, simulate bool, ne return ctx, errorsmod.Wrap(sdkerrors.ErrTxDecode, "Tx must implement the sdk.FeeTx interface") } + isValidFeePayTx := false + + // TODO: Create helper function shared between FeePay and this, also check if FeePay is enabled + if feeTx.GetFee().IsZero() && len(tx.GetMsgs()) == 1 { + _, isValidFeePayTx = (tx.GetMsgs()[0]).(*wasmtypes.MsgExecuteContract) + } + // Only check for minimum fees and global fee if the execution mode is CheckTx - if !ctx.IsCheckTx() || simulate { + if !ctx.IsCheckTx() || simulate || isValidFeePayTx { return next(ctx, tx, simulate) } From b743dde04815a2cf515da076e039720108f811a5 Mon Sep 17 00:00:00 2001 From: Joel Smith Date: Sat, 14 Oct 2023 11:58:15 -0500 Subject: [PATCH 58/79] Fix missing zero fee check --- x/feepay/ante/deduct_fee.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/x/feepay/ante/deduct_fee.go b/x/feepay/ante/deduct_fee.go index 244c3f410..007d6ac29 100644 --- a/x/feepay/ante/deduct_fee.go +++ b/x/feepay/ante/deduct_fee.go @@ -131,7 +131,7 @@ func (dfd DeductFeeDecorator) checkDeductFee(ctx sdk.Context, sdkTx sdk.Tx, fee if err != nil { return err } - } else { + } else if !fee.IsZero() { // Std sdk route err := DeductFees(dfd.bankKeeper, ctx, deductFeesFromAcc, fee) if err != nil { From 31eec78d3bd75cdad9521f2edc193dff0d344c84 Mon Sep 17 00:00:00 2001 From: Reece Williams Date: Sat, 14 Oct 2023 12:29:49 -0500 Subject: [PATCH 59/79] pfm fix test --- interchaintest/module_pfm_test.go | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/interchaintest/module_pfm_test.go b/interchaintest/module_pfm_test.go index 19c54d2db..4c10f3e22 100644 --- a/interchaintest/module_pfm_test.go +++ b/interchaintest/module_pfm_test.go @@ -275,10 +275,10 @@ func TestPacketForwardMiddlewareRouter(t *testing.T) { chainDBalance, err := chainD.GetBalance(ctx, userD.FormattedAddress(), thirdHopIBCDenom) require.NoError(t, err) - require.Equal(t, userFunds-transferAmount.Int64(), chainABalance) - require.Equal(t, int64(0), chainBBalance) - require.Equal(t, int64(0), chainCBalance) - require.Equal(t, transferAmount, chainDBalance) + require.Equal(t, userFunds-transferAmount.Int64(), chainABalance.Int64()) + require.Equal(t, int64(0), chainBBalance.Int64()) + require.Equal(t, int64(0), chainCBalance.Int64()) + require.Equal(t, transferAmount.Int64(), chainDBalance.Int64()) firstHopEscrowBalance, err := chainA.GetBalance(ctx, firstHopEscrowAccount, chainA.Config().Denom) require.NoError(t, err) @@ -289,8 +289,8 @@ func TestPacketForwardMiddlewareRouter(t *testing.T) { thirdHopEscrowBalance, err := chainC.GetBalance(ctx, thirdHopEscrowAccount, secondHopIBCDenom) require.NoError(t, err) - require.Equal(t, transferAmount, firstHopEscrowBalance) - require.Equal(t, transferAmount, secondHopEscrowBalance) - require.Equal(t, transferAmount, thirdHopEscrowBalance) + require.Equal(t, transferAmount.Int64(), firstHopEscrowBalance.Int64()) + require.Equal(t, transferAmount.Int64(), secondHopEscrowBalance.Int64()) + require.Equal(t, transferAmount.Int64(), thirdHopEscrowBalance.Int64()) }) } From b40d2e5a9146364ca425269269ef67cb7b596cf7 Mon Sep 17 00:00:00 2001 From: Reece Williams Date: Sat, 14 Oct 2023 21:22:50 -0500 Subject: [PATCH 60/79] lintor --- go.mod | 6 +++--- go.sum | 12 ++++++------ interchaintest/go.mod | 10 +++------- x/globalfee/ante/fee.go | 4 ++-- 4 files changed, 14 insertions(+), 18 deletions(-) diff --git a/go.mod b/go.mod index 5c2fb6214..d008a1123 100644 --- a/go.mod +++ b/go.mod @@ -170,13 +170,13 @@ require ( github.com/zondax/ledger-go v0.14.1 // indirect go.etcd.io/bbolt v1.3.7 // indirect go.opencensus.io v0.24.0 // indirect - golang.org/x/crypto v0.11.0 // indirect + golang.org/x/crypto v0.12.0 // indirect golang.org/x/exp v0.0.0-20230711153332-06a737ee72cb // indirect - golang.org/x/net v0.12.0 // indirect + golang.org/x/net v0.14.0 // indirect golang.org/x/oauth2 v0.10.0 // indirect golang.org/x/sync v0.3.0 // indirect golang.org/x/sys v0.11.0 // indirect - golang.org/x/term v0.10.0 // indirect + golang.org/x/term v0.11.0 // indirect golang.org/x/text v0.12.0 // indirect golang.org/x/xerrors v0.0.0-20220907171357-04be3eba64a2 // indirect google.golang.org/api v0.126.0 // indirect diff --git a/go.sum b/go.sum index ddb2e8965..426da6f1a 100644 --- a/go.sum +++ b/go.sum @@ -1270,8 +1270,8 @@ golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5y golang.org/x/crypto v0.0.0-20220314234659-1baeb1ce4c0b/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4= golang.org/x/crypto v0.0.0-20220722155217-630584e8d5aa/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4= golang.org/x/crypto v0.5.0/go.mod h1:NK/OQwhpMQP3MwtdjgLlYHnH9ebylxKWv3e0fK+mkQU= -golang.org/x/crypto v0.11.0 h1:6Ewdq3tDic1mg5xRO4milcWCfMVQhI4NkqWWvqejpuA= -golang.org/x/crypto v0.11.0/go.mod h1:xgJhtzW8F9jGdVFWZESrid1U1bjeNy4zgy5cRr/CIio= +golang.org/x/crypto v0.12.0 h1:tFM/ta59kqch6LlvYnPa0yx5a83cL2nHflFhYKvv9Yk= +golang.org/x/crypto v0.12.0/go.mod h1:NF0Gs7EO5K4qLn+Ylc+fih8BSTeIjAP05siRnAh98yw= golang.org/x/exp v0.0.0-20180321215751-8460e604b9de/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= golang.org/x/exp v0.0.0-20180807140117-3d87b88a115f/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= @@ -1385,8 +1385,8 @@ golang.org/x/net v0.0.0-20221014081412-f15817d10f9b/go.mod h1:YDH+HFinaLZZlnHAfS golang.org/x/net v0.1.0/go.mod h1:Cx3nUiGt4eDBEyega/BKRp+/AlGL8hYe7U9odMt2Cco= golang.org/x/net v0.5.0/go.mod h1:DivGGAXEgPSlEBzxGzZI+ZLohi+xUj054jfeKui00ws= golang.org/x/net v0.7.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs= -golang.org/x/net v0.12.0 h1:cfawfvKITfUsFCeJIHJrbSxpeu/E81khclypR0GVT50= -golang.org/x/net v0.12.0/go.mod h1:zEVYFnQC7m/vmpQFELhcD1EWkZlX69l4oqgmer6hfKA= +golang.org/x/net v0.14.0 h1:BONx9s002vGdD9umnlX1Po8vOZmrgH34qlHcD1MfK14= +golang.org/x/net v0.14.0/go.mod h1:PpSgVXXLK0OxS0F31C1/tv6XNguvCrnXIDrFMspZIUI= golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= @@ -1548,8 +1548,8 @@ golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuX golang.org/x/term v0.1.0/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= golang.org/x/term v0.4.0/go.mod h1:9P2UbLfCdcvo3p/nzKvsmas4TnlujnuoV9hGgYzW1lQ= golang.org/x/term v0.5.0/go.mod h1:jMB1sMXY+tzblOD4FWmEbocvup2/aLOaQEp7JmGp78k= -golang.org/x/term v0.10.0 h1:3R7pNqamzBraeqj/Tj8qt1aQ2HpmlC+Cx/qL/7hn4/c= -golang.org/x/term v0.10.0/go.mod h1:lpqdcUyK/oCiQxvxVrppt5ggO2KCZ5QblwqPnfZ6d5o= +golang.org/x/term v0.11.0 h1:F9tnn/DA/Im8nCwm+fX+1/eBwi4qFjRT++MhtVC4ZX0= +golang.org/x/term v0.11.0/go.mod h1:zC9APTIj3jG3FdV/Ons+XE1riIZXG4aZ4GTHiPZJPIU= golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= diff --git a/interchaintest/go.mod b/interchaintest/go.mod index aa49eb03f..ea8129f76 100644 --- a/interchaintest/go.mod +++ b/interchaintest/go.mod @@ -18,6 +18,8 @@ replace ( ) require ( + cosmossdk.io/math v1.1.2 + github.com/CosmWasm/wasmd v0.41.0 github.com/CosmosContracts/juno/v18 v18.0.0-00010101000000-000000000000 github.com/cosmos/cosmos-sdk v0.47.5 github.com/cosmos/gogoproto v1.4.10 @@ -27,13 +29,6 @@ require ( github.com/strangelove-ventures/interchaintest/v7 v7.0.0-20231009173908-4e98e35e363e github.com/stretchr/testify v1.8.4 go.uber.org/zap v1.25.0 - -) - -require ( - cosmossdk.io/math v1.1.2 - github.com/CosmWasm/wasmd v0.41.0 - golang.org/x/sync v0.3.0 ) require ( @@ -230,6 +225,7 @@ require ( golang.org/x/mod v0.12.0 // indirect golang.org/x/net v0.14.0 // indirect golang.org/x/oauth2 v0.10.0 // indirect + golang.org/x/sync v0.3.0 golang.org/x/sys v0.11.0 // indirect golang.org/x/term v0.11.0 // indirect golang.org/x/text v0.12.0 // indirect diff --git a/x/globalfee/ante/fee.go b/x/globalfee/ante/fee.go index 210369f28..635bce0d6 100644 --- a/x/globalfee/ante/fee.go +++ b/x/globalfee/ante/fee.go @@ -3,6 +3,8 @@ package ante import ( "errors" + wasmtypes "github.com/CosmWasm/wasmd/x/wasm/types" + tmstrings "github.com/cometbft/cometbft/libs/strings" errorsmod "cosmossdk.io/errors" @@ -12,8 +14,6 @@ import ( stakingkeeper "github.com/cosmos/cosmos-sdk/x/staking/keeper" globalfeekeeper "github.com/CosmosContracts/juno/v18/x/globalfee/keeper" - - wasmtypes "github.com/CosmWasm/wasmd/x/wasm/types" ) // FeeWithBypassDecorator checks if the transaction's fee is at least as large From 6a1e48dbebaa56d3e0c32a8768bf05f6f622fb25 Mon Sep 17 00:00:00 2001 From: Joel Smith Date: Sun, 15 Oct 2023 13:54:34 -0500 Subject: [PATCH 61/79] Refactor Fee Pay Tx Validation --- app/ante.go | 2 +- x/feepay/ante/deduct_fee.go | 44 ++++-------------------- x/feepay/helpers/fee_pay_tx_validator.go | 31 +++++++++++++++++ x/globalfee/ante/fee.go | 15 ++++---- 4 files changed, 45 insertions(+), 47 deletions(-) create mode 100644 x/feepay/helpers/fee_pay_tx_validator.go diff --git a/app/ante.go b/app/ante.go index 0df9bab7c..324836fb1 100644 --- a/app/ante.go +++ b/app/ante.go @@ -90,7 +90,7 @@ func NewAnteHandler(options HandlerOptions) (sdk.AnteHandler, error) { ante.NewTxTimeoutHeightDecorator(), ante.NewValidateMemoDecorator(options.AccountKeeper), ante.NewConsumeGasForTxSizeDecorator(options.AccountKeeper), - globalfeeante.NewFeeDecorator(options.BypassMinFeeMsgTypes, options.GlobalFeeKeeper, options.StakingKeeper, maxBypassMinFeeMsgGasUsage), + globalfeeante.NewFeeDecorator(options.BypassMinFeeMsgTypes, options.GlobalFeeKeeper, options.StakingKeeper, options.FeePayKeeper, maxBypassMinFeeMsgGasUsage), feepayante.NewDeductFeeDecorator(options.FeePayKeeper, options.GlobalFeeKeeper, options.AccountKeeper, options.BankKeeper, options.FeegrantKeeper, options.TxFeeChecker, options.BondDenom), feeshareante.NewFeeSharePayoutDecorator(options.BankKeeper, options.FeeShareKeeper), // SetPubKeyDecorator must be called before all signature verification decorators diff --git a/x/feepay/ante/deduct_fee.go b/x/feepay/ante/deduct_fee.go index 007d6ac29..758c02153 100644 --- a/x/feepay/ante/deduct_fee.go +++ b/x/feepay/ante/deduct_fee.go @@ -15,6 +15,7 @@ import ( "github.com/cosmos/cosmos-sdk/x/auth/types" bankkeeper "github.com/cosmos/cosmos-sdk/x/bank/keeper" + feepayhelpers "github.com/CosmosContracts/juno/v18/x/feepay/helpers" feepaykeeper "github.com/CosmosContracts/juno/v18/x/feepay/keeper" feepaytypes "github.com/CosmosContracts/juno/v18/x/feepay/types" globalfeekeeper "github.com/CosmosContracts/juno/v18/x/globalfee/keeper" @@ -34,27 +35,16 @@ type DeductFeeDecorator struct { accountKeeper ante.AccountKeeper bankKeeper bankkeeper.Keeper feegrantKeeper ante.FeegrantKeeper - // TxFeeChecker check if the provided fee is enough and returns the effective fee and tx priority, - // the effective fee should be deducted later, and the priority should be returned in abci response. - // type TxFeeChecker func(ctx sdk.Context, tx sdk.Tx) (sdk.Coins, int64, error) - txFeeChecker ante.TxFeeChecker - - // TODO: test this. - bondDenom string + bondDenom string } func NewDeductFeeDecorator(fpk feepaykeeper.Keeper, gfk globalfeekeeper.Keeper, ak ante.AccountKeeper, bk bankkeeper.Keeper, fgk ante.FeegrantKeeper, tfc ante.TxFeeChecker, bondDenom string) DeductFeeDecorator { - if tfc == nil { - tfc = checkTxFeeWithValidatorMinGasPrices - } - return DeductFeeDecorator{ feepayKeeper: fpk, globalfeeKeeper: gfk, accountKeeper: ak, bankKeeper: bk, feegrantKeeper: fgk, - txFeeChecker: tfc, bondDenom: bondDenom, } } @@ -76,7 +66,7 @@ func (dfd DeductFeeDecorator) AnteHandle(ctx sdk.Context, tx sdk.Tx, simulate bo fee := feeTx.GetFee() if !simulate { - fee, priority, err = dfd.txFeeChecker(ctx, tx) + fee, priority, err = dfd.checkTxFeeWithValidatorMinGasPrices(ctx, tx) if err != nil { return ctx, err } @@ -124,9 +114,7 @@ func (dfd DeductFeeDecorator) checkDeductFee(ctx sdk.Context, sdkTx sdk.Tx, fee return sdkerrors.ErrUnknownAddress.Wrapf("fee payer address: %s does not exist", deductFeesFrom) } - isFeePayEnabled := dfd.feepayKeeper.GetParams(ctx).EnableFeepay - - if isFeePayEnabled && isValidFeePayTransaction(sdkTx, fee) { + if feepayhelpers.IsValidFeePayTransaction(ctx, dfd.feepayKeeper, sdkTx, fee) { err := dfd.handleZeroFees(ctx, deductFeesFromAcc, sdkTx, fee) if err != nil { return err @@ -225,8 +213,7 @@ func DeductFees(bankKeeper types.BankKeeper, ctx sdk.Context, acc types.AccountI } // from the SDK pulled out -// TODO: modify this in part with globalfee for bypasses with ibc, force set 0? need an override in the event of DOS attacks -func checkTxFeeWithValidatorMinGasPrices(ctx sdk.Context, tx sdk.Tx) (sdk.Coins, int64, error) { +func (dfd DeductFeeDecorator) checkTxFeeWithValidatorMinGasPrices(ctx sdk.Context, tx sdk.Tx) (sdk.Coins, int64, error) { feeTx, ok := tx.(sdk.FeeTx) if !ok { return nil, 0, errorsmod.Wrap(sdkerrors.ErrTxDecode, "Tx must be a FeeTx") @@ -238,7 +225,7 @@ func checkTxFeeWithValidatorMinGasPrices(ctx sdk.Context, tx sdk.Tx) (sdk.Coins, // Ensure that the provided fees meet a minimum threshold for the validator, // if this is a CheckTx. This is only for local mempool purposes, and thus // is only ran on check tx. - if ctx.IsCheckTx() && !isValidFeePayTransaction(tx, feeTx.GetFee()) { + if ctx.IsCheckTx() && !feepayhelpers.IsValidFeePayTransaction(ctx, dfd.feepayKeeper, tx, feeTx.GetFee()) { minGasPrices := ctx.MinGasPrices() if !minGasPrices.IsZero() { requiredFees := make(sdk.Coins, len(minGasPrices)) @@ -280,22 +267,3 @@ func getTxPriority(fee sdk.Coins, gas int64) int64 { return priority } - -// Check if a transaction should be processed as a FeePay transaction. Ensure that -// the Fee Pay module is enabled before calling this function. A valid FeePay transaction -// has no fee, and only 1 message for executing a contract. -func isValidFeePayTransaction(tx sdk.Tx, fee sdk.Coins) bool { - // TODO: Future allow for multiple msgs. - - // TODO: Move to a new file to share with global fee, also check if FeePay is enabled - - // Check if fee is zero, and tx has only 1 message for executing a contract - if fee.IsZero() && len(tx.GetMsgs()) == 1 { - _, ok := (tx.GetMsgs()[0]).(*wasmtypes.MsgExecuteContract) - return ok - } - - // The transaction includes a fee, has more than 1 message, or - // has a single message that is not for executing a contract - return false -} diff --git a/x/feepay/helpers/fee_pay_tx_validator.go b/x/feepay/helpers/fee_pay_tx_validator.go new file mode 100644 index 000000000..f44512ab1 --- /dev/null +++ b/x/feepay/helpers/fee_pay_tx_validator.go @@ -0,0 +1,31 @@ +package helpers + +import ( + sdk "github.com/cosmos/cosmos-sdk/types" + + feepaykeeper "github.com/CosmosContracts/juno/v18/x/feepay/keeper" + + wasmtypes "github.com/CosmWasm/wasmd/x/wasm/types" +) + +// Check if a transaction should be processed as a FeePay transaction. Ensure that +// the Fee Pay module is enabled before calling this function. A valid FeePay transaction +// has no fee, and only 1 message for executing a contract. +// +// TODO: Future allow for multiple msgs. +func IsValidFeePayTransaction(ctx sdk.Context, feePayKeeper feepaykeeper.Keeper, tx sdk.Tx, fee sdk.Coins) bool { + + // Defaults to false + isValid := false + + // Check if the fee pay module is enabled + isEnabled := feePayKeeper.GetParams(ctx).EnableFeepay + + // Check if fee is zero, and tx has only 1 message for executing a contract + if isEnabled && fee.IsZero() && len(tx.GetMsgs()) == 1 { + _, isValid = (tx.GetMsgs()[0]).(*wasmtypes.MsgExecuteContract) + } + + // Return if the tx is valid + return isValid +} diff --git a/x/globalfee/ante/fee.go b/x/globalfee/ante/fee.go index 210369f28..56f6781da 100644 --- a/x/globalfee/ante/fee.go +++ b/x/globalfee/ante/fee.go @@ -13,7 +13,8 @@ import ( globalfeekeeper "github.com/CosmosContracts/juno/v18/x/globalfee/keeper" - wasmtypes "github.com/CosmWasm/wasmd/x/wasm/types" + feepayhelpers "github.com/CosmosContracts/juno/v18/x/feepay/helpers" + feepaykeeper "github.com/CosmosContracts/juno/v18/x/feepay/keeper" ) // FeeWithBypassDecorator checks if the transaction's fee is at least as large @@ -33,14 +34,16 @@ type FeeDecorator struct { BypassMinFeeMsgTypes []string GlobalFeeKeeper globalfeekeeper.Keeper StakingKeeper stakingkeeper.Keeper + FeePayKeeper feepaykeeper.Keeper MaxTotalBypassMinFeeMsgGasUsage uint64 } -func NewFeeDecorator(bypassMsgTypes []string, gfk globalfeekeeper.Keeper, sk stakingkeeper.Keeper, maxTotalBypassMinFeeMsgGasUsage uint64) FeeDecorator { +func NewFeeDecorator(bypassMsgTypes []string, gfk globalfeekeeper.Keeper, sk stakingkeeper.Keeper, fpk feepaykeeper.Keeper, maxTotalBypassMinFeeMsgGasUsage uint64) FeeDecorator { return FeeDecorator{ BypassMinFeeMsgTypes: bypassMsgTypes, GlobalFeeKeeper: gfk, StakingKeeper: sk, + FeePayKeeper: fpk, MaxTotalBypassMinFeeMsgGasUsage: maxTotalBypassMinFeeMsgGasUsage, } } @@ -52,12 +55,8 @@ func (mfd FeeDecorator) AnteHandle(ctx sdk.Context, tx sdk.Tx, simulate bool, ne return ctx, errorsmod.Wrap(sdkerrors.ErrTxDecode, "Tx must implement the sdk.FeeTx interface") } - isValidFeePayTx := false - - // TODO: Create helper function shared between FeePay and this, also check if FeePay is enabled - if feeTx.GetFee().IsZero() && len(tx.GetMsgs()) == 1 { - _, isValidFeePayTx = (tx.GetMsgs()[0]).(*wasmtypes.MsgExecuteContract) - } + // Check if the tx is a FeePay transaction + isValidFeePayTx := feepayhelpers.IsValidFeePayTransaction(ctx, mfd.FeePayKeeper, tx, feeTx.GetFee()) // Only check for minimum fees and global fee if the execution mode is CheckTx if !ctx.IsCheckTx() || simulate || isValidFeePayTx { From 3f3548792102152e40a211f84ed5c1d4ed96b9af Mon Sep 17 00:00:00 2001 From: Reece Williams Date: Sun, 15 Oct 2023 18:32:52 -0500 Subject: [PATCH 62/79] tidy lint --- go.mod | 27 +++++++++++------------- go.sum | 20 +++++++++--------- interchaintest/go.mod | 10 ++++----- interchaintest/go.sum | 20 +++++++++--------- x/feepay/helpers/fee_pay_tx_validator.go | 5 ++--- x/globalfee/ante/fee.go | 3 +-- 6 files changed, 40 insertions(+), 45 deletions(-) diff --git a/go.mod b/go.mod index d008a1123..a4cd7f020 100644 --- a/go.mod +++ b/go.mod @@ -35,16 +35,6 @@ require ( gopkg.in/yaml.v2 v2.4.0 ) -require ( - github.com/cockroachdb/errors v1.10.0 // indirect - github.com/cockroachdb/logtags v0.0.0-20230118201751-21c54148d20b // indirect - github.com/cockroachdb/redact v1.1.5 // indirect - github.com/getsentry/sentry-go v0.23.0 // indirect - github.com/kr/pretty v0.3.1 // indirect - github.com/kr/text v0.2.0 // indirect - github.com/rogpeppe/go-internal v1.11.0 // indirect -) - require ( cloud.google.com/go v0.110.4 // indirect cloud.google.com/go/compute v1.21.0 // indirect @@ -68,6 +58,9 @@ require ( github.com/cespare/xxhash/v2 v2.2.0 // indirect github.com/chzyer/readline v1.5.1 // indirect github.com/cockroachdb/apd/v2 v2.0.2 // indirect + github.com/cockroachdb/errors v1.10.0 // indirect + github.com/cockroachdb/logtags v0.0.0-20230118201751-21c54148d20b // indirect + github.com/cockroachdb/redact v1.1.5 // indirect github.com/coinbase/rosetta-sdk-go v0.7.9 // indirect github.com/confio/ics23/go v0.9.0 // indirect github.com/cosmos/btcutil v1.0.5 // indirect @@ -91,6 +84,7 @@ require ( github.com/dvsekhvalnov/jose2go v1.5.0 // indirect github.com/felixge/httpsnoop v1.0.2 // indirect github.com/fsnotify/fsnotify v1.6.0 // indirect + github.com/getsentry/sentry-go v0.23.0 // indirect github.com/go-kit/kit v0.12.0 // indirect github.com/go-kit/log v0.2.1 // indirect github.com/go-logfmt/logfmt v0.6.0 // indirect @@ -131,6 +125,8 @@ require ( github.com/jmespath/go-jmespath v0.4.0 // indirect github.com/jmhodges/levigo v1.0.0 // indirect github.com/klauspost/compress v1.16.3 // indirect + github.com/kr/pretty v0.3.1 // indirect + github.com/kr/text v0.2.0 // indirect github.com/lib/pq v1.10.7 // indirect github.com/libp2p/go-buffer-pool v0.1.0 // indirect github.com/linxGnu/grocksdb v1.7.16 // indirect @@ -155,6 +151,7 @@ require ( github.com/prometheus/procfs v0.10.1 // indirect github.com/rakyll/statik v0.1.7 // indirect github.com/rcrowley/go-metrics v0.0.0-20201227073835-cf1acfcdf475 // indirect + github.com/rogpeppe/go-internal v1.11.0 // indirect github.com/rs/cors v1.8.3 // indirect github.com/rs/zerolog v1.30.0 // indirect github.com/sasha-s/go-deadlock v0.3.1 // indirect @@ -170,14 +167,14 @@ require ( github.com/zondax/ledger-go v0.14.1 // indirect go.etcd.io/bbolt v1.3.7 // indirect go.opencensus.io v0.24.0 // indirect - golang.org/x/crypto v0.12.0 // indirect + golang.org/x/crypto v0.14.0 // indirect golang.org/x/exp v0.0.0-20230711153332-06a737ee72cb // indirect - golang.org/x/net v0.14.0 // indirect + golang.org/x/net v0.17.0 // indirect golang.org/x/oauth2 v0.10.0 // indirect golang.org/x/sync v0.3.0 // indirect - golang.org/x/sys v0.11.0 // indirect - golang.org/x/term v0.11.0 // indirect - golang.org/x/text v0.12.0 // indirect + golang.org/x/sys v0.13.0 // indirect + golang.org/x/term v0.13.0 // indirect + golang.org/x/text v0.13.0 // indirect golang.org/x/xerrors v0.0.0-20220907171357-04be3eba64a2 // indirect google.golang.org/api v0.126.0 // indirect google.golang.org/appengine v1.6.7 // indirect diff --git a/go.sum b/go.sum index 426da6f1a..c959b6e84 100644 --- a/go.sum +++ b/go.sum @@ -1270,8 +1270,8 @@ golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5y golang.org/x/crypto v0.0.0-20220314234659-1baeb1ce4c0b/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4= golang.org/x/crypto v0.0.0-20220722155217-630584e8d5aa/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4= golang.org/x/crypto v0.5.0/go.mod h1:NK/OQwhpMQP3MwtdjgLlYHnH9ebylxKWv3e0fK+mkQU= -golang.org/x/crypto v0.12.0 h1:tFM/ta59kqch6LlvYnPa0yx5a83cL2nHflFhYKvv9Yk= -golang.org/x/crypto v0.12.0/go.mod h1:NF0Gs7EO5K4qLn+Ylc+fih8BSTeIjAP05siRnAh98yw= +golang.org/x/crypto v0.14.0 h1:wBqGXzWJW6m1XrIKlAH0Hs1JJ7+9KBwnIO8v66Q9cHc= +golang.org/x/crypto v0.14.0/go.mod h1:MVFd36DqK4CsrnJYDkBA3VC4m2GkXAM0PvzMCn4JQf4= golang.org/x/exp v0.0.0-20180321215751-8460e604b9de/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= golang.org/x/exp v0.0.0-20180807140117-3d87b88a115f/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= @@ -1385,8 +1385,8 @@ golang.org/x/net v0.0.0-20221014081412-f15817d10f9b/go.mod h1:YDH+HFinaLZZlnHAfS golang.org/x/net v0.1.0/go.mod h1:Cx3nUiGt4eDBEyega/BKRp+/AlGL8hYe7U9odMt2Cco= golang.org/x/net v0.5.0/go.mod h1:DivGGAXEgPSlEBzxGzZI+ZLohi+xUj054jfeKui00ws= golang.org/x/net v0.7.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs= -golang.org/x/net v0.14.0 h1:BONx9s002vGdD9umnlX1Po8vOZmrgH34qlHcD1MfK14= -golang.org/x/net v0.14.0/go.mod h1:PpSgVXXLK0OxS0F31C1/tv6XNguvCrnXIDrFMspZIUI= +golang.org/x/net v0.17.0 h1:pVaXccu2ozPjCXewfr1S7xza/zcXTity9cCdXQYSjIM= +golang.org/x/net v0.17.0/go.mod h1:NxSsAGuq816PNPmqtQdLE42eU2Fs7NoRIZrHJAlaCOE= golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= @@ -1540,16 +1540,16 @@ golang.org/x/sys v0.1.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.4.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.11.0 h1:eG7RXZHdqOJ1i+0lgLgCpSXAp6M3LYlAo6osgSi0xOM= -golang.org/x/sys v0.11.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.13.0 h1:Af8nKPmuFypiUBjVoU9V20FiaFXOcuZI21p0ycVYYGE= +golang.org/x/sys v0.13.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/term v0.0.0-20201117132131-f5c789dd3221/go.mod h1:Nr5EML6q2oocZ2LXRh80K7BxOlk5/8JxuGnuhpl+muw= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= golang.org/x/term v0.1.0/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= golang.org/x/term v0.4.0/go.mod h1:9P2UbLfCdcvo3p/nzKvsmas4TnlujnuoV9hGgYzW1lQ= golang.org/x/term v0.5.0/go.mod h1:jMB1sMXY+tzblOD4FWmEbocvup2/aLOaQEp7JmGp78k= -golang.org/x/term v0.11.0 h1:F9tnn/DA/Im8nCwm+fX+1/eBwi4qFjRT++MhtVC4ZX0= -golang.org/x/term v0.11.0/go.mod h1:zC9APTIj3jG3FdV/Ons+XE1riIZXG4aZ4GTHiPZJPIU= +golang.org/x/term v0.13.0 h1:bb+I9cTfFazGW51MZqBVmZy7+JEJMouUHTUSKVQLBek= +golang.org/x/term v0.13.0/go.mod h1:LTmsnFJwVN6bCy1rVCoS+qHT1HhALEFxKncY3WNNh4U= golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= @@ -1563,8 +1563,8 @@ golang.org/x/text v0.3.8/go.mod h1:E6s5w1FMmriuDzIBO73fBruAKo1PCIq6d2Q6DHfQ8WQ= golang.org/x/text v0.4.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8= golang.org/x/text v0.6.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8= golang.org/x/text v0.7.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8= -golang.org/x/text v0.12.0 h1:k+n5B8goJNdU7hSvEtMUz3d1Q6D/XW4COJSJR6fN0mc= -golang.org/x/text v0.12.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE= +golang.org/x/text v0.13.0 h1:ablQoSUd0tRdKxZewP80B+BaqeKJuVhuRxj/dkrun3k= +golang.org/x/text v0.13.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE= golang.org/x/time v0.0.0-20180412165947-fbb02b2291d2/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= diff --git a/interchaintest/go.mod b/interchaintest/go.mod index ea8129f76..472ddecd2 100644 --- a/interchaintest/go.mod +++ b/interchaintest/go.mod @@ -220,15 +220,15 @@ require ( go.etcd.io/bbolt v1.3.7 // indirect go.opencensus.io v0.24.0 // indirect go.uber.org/multierr v1.11.0 // indirect - golang.org/x/crypto v0.12.0 // indirect + golang.org/x/crypto v0.14.0 // indirect golang.org/x/exp v0.0.0-20230711153332-06a737ee72cb // indirect golang.org/x/mod v0.12.0 // indirect - golang.org/x/net v0.14.0 // indirect + golang.org/x/net v0.17.0 // indirect golang.org/x/oauth2 v0.10.0 // indirect golang.org/x/sync v0.3.0 - golang.org/x/sys v0.11.0 // indirect - golang.org/x/term v0.11.0 // indirect - golang.org/x/text v0.12.0 // indirect + golang.org/x/sys v0.13.0 // indirect + golang.org/x/term v0.13.0 // indirect + golang.org/x/text v0.13.0 // indirect golang.org/x/tools v0.12.0 // indirect golang.org/x/xerrors v0.0.0-20220907171357-04be3eba64a2 // indirect google.golang.org/api v0.126.0 // indirect diff --git a/interchaintest/go.sum b/interchaintest/go.sum index c1b73fa20..8d0489db7 100644 --- a/interchaintest/go.sum +++ b/interchaintest/go.sum @@ -1160,8 +1160,8 @@ golang.org/x/crypto v0.0.0-20210421170649-83a5a9bb288b/go.mod h1:T9bdIzuCu7OtxOm golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= golang.org/x/crypto v0.0.0-20220314234659-1baeb1ce4c0b/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4= golang.org/x/crypto v0.0.0-20220722155217-630584e8d5aa/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4= -golang.org/x/crypto v0.12.0 h1:tFM/ta59kqch6LlvYnPa0yx5a83cL2nHflFhYKvv9Yk= -golang.org/x/crypto v0.12.0/go.mod h1:NF0Gs7EO5K4qLn+Ylc+fih8BSTeIjAP05siRnAh98yw= +golang.org/x/crypto v0.14.0 h1:wBqGXzWJW6m1XrIKlAH0Hs1JJ7+9KBwnIO8v66Q9cHc= +golang.org/x/crypto v0.14.0/go.mod h1:MVFd36DqK4CsrnJYDkBA3VC4m2GkXAM0PvzMCn4JQf4= golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= golang.org/x/exp v0.0.0-20190306152737-a1d7652674e8/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= golang.org/x/exp v0.0.0-20190510132918-efd6b22b2522/go.mod h1:ZjyILWgesfNpC6sMxTJOJm9Kp84zZh5NQWvqDGG3Qr8= @@ -1264,8 +1264,8 @@ golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug golang.org/x/net v0.0.0-20220909164309-bea034e7d591/go.mod h1:YDH+HFinaLZZlnHAfSS6ZXJJ9M9t4Dl22yv3iI2vPwk= golang.org/x/net v0.0.0-20221014081412-f15817d10f9b/go.mod h1:YDH+HFinaLZZlnHAfSS6ZXJJ9M9t4Dl22yv3iI2vPwk= golang.org/x/net v0.1.0/go.mod h1:Cx3nUiGt4eDBEyega/BKRp+/AlGL8hYe7U9odMt2Cco= -golang.org/x/net v0.14.0 h1:BONx9s002vGdD9umnlX1Po8vOZmrgH34qlHcD1MfK14= -golang.org/x/net v0.14.0/go.mod h1:PpSgVXXLK0OxS0F31C1/tv6XNguvCrnXIDrFMspZIUI= +golang.org/x/net v0.17.0 h1:pVaXccu2ozPjCXewfr1S7xza/zcXTity9cCdXQYSjIM= +golang.org/x/net v0.17.0/go.mod h1:NxSsAGuq816PNPmqtQdLE42eU2Fs7NoRIZrHJAlaCOE= golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= @@ -1408,13 +1408,13 @@ golang.org/x/sys v0.0.0-20220908164124-27713097b956/go.mod h1:oPkhp1MJrh7nUepCBc golang.org/x/sys v0.0.0-20221010170243-090e33056c14/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.1.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.11.0 h1:eG7RXZHdqOJ1i+0lgLgCpSXAp6M3LYlAo6osgSi0xOM= -golang.org/x/sys v0.11.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.13.0 h1:Af8nKPmuFypiUBjVoU9V20FiaFXOcuZI21p0ycVYYGE= +golang.org/x/sys v0.13.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= golang.org/x/term v0.1.0/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= -golang.org/x/term v0.11.0 h1:F9tnn/DA/Im8nCwm+fX+1/eBwi4qFjRT++MhtVC4ZX0= -golang.org/x/term v0.11.0/go.mod h1:zC9APTIj3jG3FdV/Ons+XE1riIZXG4aZ4GTHiPZJPIU= +golang.org/x/term v0.13.0 h1:bb+I9cTfFazGW51MZqBVmZy7+JEJMouUHTUSKVQLBek= +golang.org/x/term v0.13.0/go.mod h1:LTmsnFJwVN6bCy1rVCoS+qHT1HhALEFxKncY3WNNh4U= golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= @@ -1426,8 +1426,8 @@ golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ= golang.org/x/text v0.3.8/go.mod h1:E6s5w1FMmriuDzIBO73fBruAKo1PCIq6d2Q6DHfQ8WQ= golang.org/x/text v0.4.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8= -golang.org/x/text v0.12.0 h1:k+n5B8goJNdU7hSvEtMUz3d1Q6D/XW4COJSJR6fN0mc= -golang.org/x/text v0.12.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE= +golang.org/x/text v0.13.0 h1:ablQoSUd0tRdKxZewP80B+BaqeKJuVhuRxj/dkrun3k= +golang.org/x/text v0.13.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE= golang.org/x/time v0.0.0-20180412165947-fbb02b2291d2/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= diff --git a/x/feepay/helpers/fee_pay_tx_validator.go b/x/feepay/helpers/fee_pay_tx_validator.go index f44512ab1..a349ba7f4 100644 --- a/x/feepay/helpers/fee_pay_tx_validator.go +++ b/x/feepay/helpers/fee_pay_tx_validator.go @@ -1,11 +1,11 @@ package helpers import ( + wasmtypes "github.com/CosmWasm/wasmd/x/wasm/types" + sdk "github.com/cosmos/cosmos-sdk/types" feepaykeeper "github.com/CosmosContracts/juno/v18/x/feepay/keeper" - - wasmtypes "github.com/CosmWasm/wasmd/x/wasm/types" ) // Check if a transaction should be processed as a FeePay transaction. Ensure that @@ -14,7 +14,6 @@ import ( // // TODO: Future allow for multiple msgs. func IsValidFeePayTransaction(ctx sdk.Context, feePayKeeper feepaykeeper.Keeper, tx sdk.Tx, fee sdk.Coins) bool { - // Defaults to false isValid := false diff --git a/x/globalfee/ante/fee.go b/x/globalfee/ante/fee.go index 56f6781da..72a546c25 100644 --- a/x/globalfee/ante/fee.go +++ b/x/globalfee/ante/fee.go @@ -11,10 +11,9 @@ import ( sdkerrors "github.com/cosmos/cosmos-sdk/types/errors" stakingkeeper "github.com/cosmos/cosmos-sdk/x/staking/keeper" - globalfeekeeper "github.com/CosmosContracts/juno/v18/x/globalfee/keeper" - feepayhelpers "github.com/CosmosContracts/juno/v18/x/feepay/helpers" feepaykeeper "github.com/CosmosContracts/juno/v18/x/feepay/keeper" + globalfeekeeper "github.com/CosmosContracts/juno/v18/x/globalfee/keeper" ) // FeeWithBypassDecorator checks if the transaction's fee is at least as large From cf64e8d774925d536e2fde02a739c3ea3ebef0de Mon Sep 17 00:00:00 2001 From: Joel Smith Date: Mon, 16 Oct 2023 18:53:39 -0500 Subject: [PATCH 63/79] Add query err checks --- x/feepay/keeper/querier.go | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/x/feepay/keeper/querier.go b/x/feepay/keeper/querier.go index a4028be61..a21269dcb 100644 --- a/x/feepay/keeper/querier.go +++ b/x/feepay/keeper/querier.go @@ -30,6 +30,9 @@ func (q Querier) FeePayContract(ctx context.Context, req *types.QueryFeePayContr sdkCtx := sdk.UnwrapSDKContext(ctx) contract, err := q.Keeper.GetContract(sdkCtx, req.ContractAddress) + if err != nil { + return nil, err + } return &types.QueryFeePayContractResponse{ FeePayContract: contract, @@ -68,6 +71,9 @@ func (q Querier) FeePayContractUses(ctx context.Context, req *types.QueryFeePayC } uses, err := q.Keeper.GetContractUses(sdkCtx, fpc, req.WalletAddress) + if err != nil { + return nil, err + } return &types.QueryFeePayContractUsesResponse{ Uses: uses, @@ -95,6 +101,9 @@ func (q Querier) FeePayWalletIsEligible(ctx context.Context, req *types.QueryFee // Return if wallet is eligible isEligible, err := q.Keeper.IsWalletEligible(sdkCtx, fpc, req.WalletAddress) + if err != nil { + return nil, err + } return &types.QueryFeePayWalletIsEligibleResponse{ Eligible: isEligible, From 9daebddff075abb20d36375268f4cb8a44951f30 Mon Sep 17 00:00:00 2001 From: Joel Smith Date: Mon, 16 Oct 2023 18:53:46 -0500 Subject: [PATCH 64/79] Use sdk errors --- x/feepay/types/errors.go | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/x/feepay/types/errors.go b/x/feepay/types/errors.go index 87b0baa5b..7c97c491f 100644 --- a/x/feepay/types/errors.go +++ b/x/feepay/types/errors.go @@ -2,9 +2,12 @@ package types import ( errorsmod "cosmossdk.io/errors" + + sdkerrors "github.com/cosmos/cosmos-sdk/types/errors" ) var ( + ErrInvalidAddress = sdkerrors.ErrInvalidAddress ErrContractNotRegistered = errorsmod.Register(ModuleName, 1, "contract not registered") ErrContractAlreadyRegistered = errorsmod.Register(ModuleName, 2, "contract already registered") ErrContractRegisterNotAdmin = errorsmod.Register(ModuleName, 3, "this address is not the contract admin, cannot register") @@ -14,7 +17,6 @@ var ( ErrContractNotCreator = errorsmod.Register(ModuleName, 7, "sender is not the contract creator") ErrInvalidWalletLimit = errorsmod.Register(ModuleName, 8, "invalid wallet limit; must be between 0 and 1,000,000") ErrInvalidJunoFundAmount = errorsmod.Register(ModuleName, 9, "fee pay contracts only accept juno funds") - ErrInvalidAddress = errorsmod.Register(ModuleName, 10, "invalid bech32 address") - ErrInvalidCWContract = errorsmod.Register(ModuleName, 11, "invalid CosmWasm contract") - ErrFeePayDisabled = errorsmod.Register(ModuleName, 12, "the FeePay module is disabled") + ErrInvalidCWContract = errorsmod.Register(ModuleName, 10, "invalid CosmWasm contract") + ErrFeePayDisabled = errorsmod.Register(ModuleName, 11, "the FeePay module is disabled") ) From d515e372a955dd5e43fd89b6404fc1625021dad7 Mon Sep 17 00:00:00 2001 From: Joel Smith Date: Mon, 16 Oct 2023 18:54:34 -0500 Subject: [PATCH 65/79] Force new contract balance of 0 --- x/feepay/keeper/msg_server.go | 2 ++ x/feepay/keeper/msg_server_test.go | 10 +++---- x/feepay/keeper/querier_test.go | 46 +++++++++++++++++++++++++++--- 3 files changed, 49 insertions(+), 9 deletions(-) diff --git a/x/feepay/keeper/msg_server.go b/x/feepay/keeper/msg_server.go index 1ab32cb53..4c4cd3369 100644 --- a/x/feepay/keeper/msg_server.go +++ b/x/feepay/keeper/msg_server.go @@ -16,6 +16,8 @@ var _ types.MsgServer = &Keeper{} // Register a new fee pay contract. func (k Keeper) RegisterFeePayContract(goCtx context.Context, msg *types.MsgRegisterFeePayContract) (*types.MsgRegisterFeePayContractResponse, error) { ctx := sdk.UnwrapSDKContext(goCtx) + // Prevent client from overriding initial contract balance of zero + msg.FeePayContract.Balance = uint64(0) return &types.MsgRegisterFeePayContractResponse{}, k.RegisterContract(ctx, msg) } diff --git a/x/feepay/keeper/msg_server_test.go b/x/feepay/keeper/msg_server_test.go index 4e8142112..7c4ed3cf2 100644 --- a/x/feepay/keeper/msg_server_test.go +++ b/x/feepay/keeper/msg_server_test.go @@ -92,8 +92,8 @@ func (s *IntegrationTestSuite) TestUnregisterFeePayContract() { creatorContract := s.InstantiateContract(sender.String(), "") adminContract := s.InstantiateContract(sender.String(), admin.String()) - s.registerFeePayContract(sender.String(), creatorContract, 1) - s.registerFeePayContract(admin.String(), adminContract, 0) + s.registerFeePayContract(sender.String(), creatorContract, 0, 1) + s.registerFeePayContract(admin.String(), adminContract, 0, 0) for _, tc := range []struct { desc string @@ -163,7 +163,7 @@ func (s *IntegrationTestSuite) TestFundFeePayContract() { contract := s.InstantiateContract(sender.String(), "") - s.registerFeePayContract(sender.String(), contract, 1) + s.registerFeePayContract(sender.String(), contract, 0, 1) for _, tc := range []struct { desc string @@ -235,8 +235,8 @@ func (s *IntegrationTestSuite) TestUpdateFeePayContractWalletLimit() { creatorContract := s.InstantiateContract(sender.String(), "") adminContract := s.InstantiateContract(sender.String(), admin.String()) - s.registerFeePayContract(sender.String(), creatorContract, 1) - s.registerFeePayContract(admin.String(), adminContract, 0) + s.registerFeePayContract(sender.String(), creatorContract, 0, 1) + s.registerFeePayContract(admin.String(), adminContract, 0, 0) for _, tc := range []struct { desc string diff --git a/x/feepay/keeper/querier_test.go b/x/feepay/keeper/querier_test.go index bdf47ba0a..bc5bc28ff 100644 --- a/x/feepay/keeper/querier_test.go +++ b/x/feepay/keeper/querier_test.go @@ -17,7 +17,7 @@ func (s *IntegrationTestSuite) TestQueryContract() { // Instantiate the contractAddr contractAddr := s.InstantiateContract(sender.String(), "") - s.registerFeePayContract(sender.String(), contractAddr, 1) + s.registerFeePayContract(sender.String(), contractAddr, 0, 1) s.Run("QueryContract", func() { // Query for the contract @@ -36,6 +36,44 @@ func (s *IntegrationTestSuite) TestQueryContract() { }) } +// Test that when a Fee Pay contract is registered, the balance is always 0. +func (s *IntegrationTestSuite) TestQueryContractBalance() { + // Get & fund creator + _, _, sender := testdata.KeyTestPubAddr() + _ = s.FundAccount(s.ctx, sender, sdk.NewCoins(sdk.NewCoin("stake", sdk.NewInt(1_000_000)))) + + s.Run("QueryContract", func() { + + for _, bal := range []struct { + balance uint64 + }{ + {balance: 0}, + {balance: 1_000_000}, + } { + bal := bal + + // Instantiate the contractAddr + contractAddr := s.InstantiateContract(sender.String(), "") + s.registerFeePayContract(sender.String(), contractAddr, bal.balance, 1) + + // Query for the contract + res, err := s.queryClient.FeePayContract(s.ctx, &types.QueryFeePayContract{ + ContractAddress: contractAddr, + }) + + // Ensure no error and response exists + s.Require().NoError(err) + s.Require().Equal(res, &types.QueryFeePayContractResponse{ + FeePayContract: &types.FeePayContract{ + ContractAddress: contractAddr, + Balance: 0, + WalletLimit: 1, + }, + }) + } + }) +} + func (s *IntegrationTestSuite) TestQueryContracts() { // Get & fund creator _, _, sender := testdata.KeyTestPubAddr() @@ -49,7 +87,7 @@ func (s *IntegrationTestSuite) TestQueryContracts() { contractAddr := s.InstantiateContract(sender.String(), "") // Register the fee pay contract - s.registerFeePayContract(sender.String(), contractAddr, 1) + s.registerFeePayContract(sender.String(), contractAddr, 0, 1) // Query for the contract res, err := s.queryClient.FeePayContract(s.ctx, &types.QueryFeePayContract{ @@ -123,7 +161,7 @@ func (s *IntegrationTestSuite) TestQueryEligibility() { contractAddr := s.InstantiateContract(sender.String(), "") // Register the fee pay contract - s.registerFeePayContract(sender.String(), contractAddr, 1) + s.registerFeePayContract(sender.String(), contractAddr, 0, 1) s.Run("QueryEligibilityNoFunds", func() { // Query for the contract @@ -187,7 +225,7 @@ func (s *IntegrationTestSuite) TestQueryUses() { contractAddr := s.InstantiateContract(sender.String(), "") // Register the fee pay contract - s.registerFeePayContract(sender.String(), contractAddr, 1) + s.registerFeePayContract(sender.String(), contractAddr, 0, 1) s.Run("QueryUses", func() { // Query for the contract From cb79e18797008b34da512cfd27931b93bf0ba344 Mon Sep 17 00:00:00 2001 From: Joel Smith Date: Mon, 16 Oct 2023 18:54:45 -0500 Subject: [PATCH 66/79] Removed unused file --- app/decorators/feeprepay_poc.go.archive | 108 ------------------------ 1 file changed, 108 deletions(-) delete mode 100644 app/decorators/feeprepay_poc.go.archive diff --git a/app/decorators/feeprepay_poc.go.archive b/app/decorators/feeprepay_poc.go.archive deleted file mode 100644 index 66a62c6fc..000000000 --- a/app/decorators/feeprepay_poc.go.archive +++ /dev/null @@ -1,108 +0,0 @@ -package decorators - -import ( - globalfeekeeper "github.com/CosmosContracts/juno/v18/x/globalfee/keeper" - - sdk "github.com/cosmos/cosmos-sdk/types" - sdkerrors "github.com/cosmos/cosmos-sdk/types/errors" - authante "github.com/cosmos/cosmos-sdk/x/auth/ante" - bankkeeper "github.com/cosmos/cosmos-sdk/x/bank/keeper" - feegrantkeeper "github.com/cosmos/cosmos-sdk/x/feegrant/keeper" - - errorsmod "cosmossdk.io/errors" -) - -type MsgFeePrepayDecorator struct { - BankKeeper bankkeeper.Keeper - // TODO: This could be incorrect. We may need the full AuthKeeper/AccountKeeper, not just from the ante - AccountKeeper authante.AccountKeeper - GlobalFeeKeeper globalfeekeeper.Keeper - - FeeGrantKeeper feegrantkeeper.Keeper -} - -func NewMsgFeePrepayDecorator(bank bankkeeper.Keeper, auth authante.AccountKeeper, globalFee globalfeekeeper.Keeper) MsgFeePrepayDecorator { - return MsgFeePrepayDecorator{ - BankKeeper: bank, - AccountKeeper: auth, - GlobalFeeKeeper: globalFee, - } -} - -// junod tx tokenfactory create-denom joel --fees=0ujuno --from=juno1 --home=/home/joel/.juno1 --chain-id=local-1 --keyring-backend=test -y --gas=2200000 -func (fpd MsgFeePrepayDecorator) AnteHandle(ctx sdk.Context, tx sdk.Tx, simulate bool, next sdk.AnteHandler) (newCtx sdk.Context, err error) { - - ctx.Logger().Error("MsgFeePrepayDecorator", "Starting", true) - - // 1. Confirm the transaction is a FeeTx - // 2. Calculate the total fee - // 3. Transfer funds to the user (either indirectly through the bank module or directly) - // 4. Set the new fee on the Tx - // 5. Continue processing as normal - - // if tx is read only - // tx := new sdk.Tx(...tx, set the new fee) - - // This may not be a FeeTx, so if error then don't exit early - feeTx, ok := tx.(sdk.FeeTx) - if !ok { - return ctx, errorsmod.Wrap(sdkerrors.ErrTxDecode, "Tx must implement the sdk.FeeTx interface") - } - - // feePrePayModuleAcc := fpd.AccountKeeper.GetModuleAddress("feeprepay") - // fpd.FeeGrantKeeper.GrantAllowance(ctx, feePrePayModuleAcc, feeTx.FeePayer(), &feegranttypes.{}) - - if ctx.BlockHeight() > 0 { - - // Global fee keeper params - p := fpd.GlobalFeeKeeper.GetParams(ctx) - - // Get min juno gas - var minGasPrice sdk.DecCoin - for _, c := range p.MinimumGasPrices { - if c.Denom == "ujuno" { - minGasPrice = c - } - } - - ctx.Logger().Error("MsgFeePrepayDecorator", "MinGas", minGasPrice) - ctx.Logger().Error("MsgFeePrepayDecorator", "FeeTx (gas)", feeTx.GetGas()) - ctx.Logger().Error("MsgFeePrepayDecorator", "Consumed Gas", ctx.GasMeter().GasConsumed()) - - // Calculate gas consumed - consumed := ctx.GasMeter().GasConsumed() - - // Determine fee by multiplying gas price by gas consumed - fee := minGasPrice.Amount.Mul(sdk.NewDec(int64(consumed))).RoundInt() - - ctx.Logger().Error("MsgFeePrepayDecorator", "Fee", fee) - - // payment := sdk.NewCoins(sdk.NewCoin("ujuno", fee)) - payment := sdk.NewCoins(sdk.NewCoin("ujuno", sdk.NewDec(500_000).RoundInt())) - fpd.BankKeeper.MintCoins(ctx, "mint", payment) - fpd.BankKeeper.SendCoinsFromModuleToAccount(ctx, "mint", feeTx.FeePayer(), payment) - - ctx.Logger().Error("MsgFeePrepayDecorator", "Minted & Sent to User", feeTx.FeePayer()) - } - - // TODOL: Thuis could give you funds and then make your next Tx successful. - // fpd.BankKeeper.MintCoins(ctx, "bank", coinsAmt) - // fpd.BankKeeper.SendCoinsFromModuleToAccount(ctx, "bank", "userAccount", coinsAmt) - // auto feeprepay with the TxFee or somethuing here? as an option - // set the Tx fee to be correct, set the accoiunt to be new and work, and then continue on - - ctx.Logger().Error("MsgFeePrepayDecorator", "Finished", true) - - return next(ctx, tx, simulate) -} - -// TODO: Future: execute contract only. -// func hasInvalidExecuteMsgs(msgs []sdk.Msg) bool { -// for _, msg := range msgs { -// if _, ok := msg.(*wasmtypes.msgExecuteContract); ok { -// return true -// } -// } - -// return false -// } From acecf59e9995fa50ece5d457897eee4766502c63 Mon Sep 17 00:00:00 2001 From: Joel Smith Date: Mon, 16 Oct 2023 18:54:55 -0500 Subject: [PATCH 67/79] Remove fee pay testing script --- scripts/feepay.sh | 53 ----------------------------------------------- 1 file changed, 53 deletions(-) delete mode 100644 scripts/feepay.sh diff --git a/scripts/feepay.sh b/scripts/feepay.sh deleted file mode 100644 index 54c39c8d1..000000000 --- a/scripts/feepay.sh +++ /dev/null @@ -1,53 +0,0 @@ -# Script to upload a contract to the chain -# Run this in the root of the directly. Cltr + alt + space can be used to run a command in VSCode terminal - -CONTRACT_FILE=scripts/fpexample.wasm -JUNOD_NODE=http://localhost:26657 - -# only run this 1 time per chain start. - -junod tx wasm store $CONTRACT_FILE --from juno1 --gas 2000000 -y --chain-id=local-1 --fees=75000ujuno -# Code id from THis is 1 - it is in the above Txhash, just hardcoding since we only need to upload once - -sleep 3 - -# instantiate and get an address -junod tx wasm instantiate 1 '{}' --from juno1 --label "test" --gas 2000000 -y --chain-id=local-1 --fees=75000ujuno --no-admin - -sleep 3 - -# execute on the contract -CONTRACT_ADDR=juno14hj2tavq8fpesdwxxcu44rty3hh90vhujrvcmstl4zr3txmfvw9skjuwg8 -junod tx wasm execute $CONTRACT_ADDR '{"increment":{}}' --gas 2000000 -y --chain-id=local-1 --fees=75000ujuno --from=juno1 - -sleep 3 - -# Query to ensure it went through, else you need to junod q tx from the above command -junod q wasm contract-state smart $CONTRACT_ADDR '{"get_config":{}}' --chain-id=local-1 - -sleep 3 - -# Register Contract -junod tx feepay register juno14hj2tavq8fpesdwxxcu44rty3hh90vhujrvcmstl4zr3txmfvw9skjuwg8 3 --home /home/joel/.juno1 --chain-id local-1 --from juno1 --keyring-backend=test --fees=500ujuno -y - -sleep 3 - -# Transfer funds from juno1 to fee pay module -# junod tx bank send juno1 juno1f7f2eapsz6w4s2fytlm34yu5w89ueaesg7x9v5 5000000ujuno --home /home/joel/.juno1 --chain-id local-1 --keyring-backend=test --fees=5000ujuno -y - -# sleep 3 - -# Fund the contract -junod tx feepay fund juno14hj2tavq8fpesdwxxcu44rty3hh90vhujrvcmstl4zr3txmfvw9skjuwg8 1000000ujuno --gas=200000 --fees=5000ujuno --home /home/joel/.juno1 --chain-id local-1 --keyring-backend=test -y --from juno1 - -sleep 3 - -junod q feepay contract juno14hj2tavq8fpesdwxxcu44rty3hh90vhujrvcmstl4zr3txmfvw9skjuwg8 --home /home/joel/.juno1 --chain-id local-1 - -sleep 3 - -junod tx feepay update-wallet-limit juno14hj2tavq8fpesdwxxcu44rty3hh90vhujrvcmstl4zr3txmfvw9skjuwg8 5 --gas=200000 --fees=5000ujuno --home /home/joel/.juno1 --chain-id local-1 --keyring-backend=test --from juno1 -y - -sleep 3 - -junod q feepay contract juno14hj2tavq8fpesdwxxcu44rty3hh90vhujrvcmstl4zr3txmfvw9skjuwg8 --home /home/joel/.juno1 --chain-id local-1 From 30fff1957e83c37d532186c482a2ba3df203d289 Mon Sep 17 00:00:00 2001 From: Joel Smith Date: Mon, 16 Oct 2023 18:55:04 -0500 Subject: [PATCH 68/79] Update query endpoints --- proto/juno/feepay/v1/query.proto | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/proto/juno/feepay/v1/query.proto b/proto/juno/feepay/v1/query.proto index 1aac276b9..accab94a1 100644 --- a/proto/juno/feepay/v1/query.proto +++ b/proto/juno/feepay/v1/query.proto @@ -13,22 +13,22 @@ option go_package = "github.com/CosmosContracts/juno/x/feepay/types"; service Query { // FeePayContract queries a single fee pay contract by address rpc FeePayContract(QueryFeePayContract) returns (QueryFeePayContractResponse) { - option (google.api.http).get = "/juno/feepay/v1/feepay/{contract_address}"; + option (google.api.http).get = "/juno/feepay/v1/contract/{contract_address}"; } // Retrieve all fee pay contracts rpc FeePayContracts(QueryFeePayContracts) returns (QueryFeePayContractsResponse) { - option (google.api.http).get = "/juno/feepay/v1/feepay"; + option (google.api.http).get = "/juno/feepay/v1/all_contracts"; } // Retrieve the number of uses on a fee pay contract by wallet rpc FeePayContractUses(QueryFeePayContractUses) returns (QueryFeePayContractUsesResponse) { - option (google.api.http).get = "/juno/feepay/v1/feepay/{contract_address}/uses/{wallet_address}"; + option (google.api.http).get = "/juno/feepay/v1/contract/{contract_address}/uses/{wallet_address}"; } // Query if sender is eligible for fee pay contract interaction rpc FeePayWalletIsEligible(QueryFeePayWalletIsEligible) returns (QueryFeePayWalletIsEligibleResponse) { - option (google.api.http).get = "/juno/feepay/v1/feepay/{contract_address}/eligible/{wallet_address}"; + option (google.api.http).get = "/juno/feepay/v1/contract/{contract_address}/eligible/{wallet_address}"; } // Params retrieves the FeePay module params From 54f6b66ce2f89890a9f64cecc592ba1ef683b72d Mon Sep 17 00:00:00 2001 From: Joel Smith Date: Mon, 16 Oct 2023 18:55:24 -0500 Subject: [PATCH 69/79] Remove incorrect comment --- x/feepay/helpers/fee_pay_tx_validator.go | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/x/feepay/helpers/fee_pay_tx_validator.go b/x/feepay/helpers/fee_pay_tx_validator.go index a349ba7f4..41bc495df 100644 --- a/x/feepay/helpers/fee_pay_tx_validator.go +++ b/x/feepay/helpers/fee_pay_tx_validator.go @@ -8,9 +8,9 @@ import ( feepaykeeper "github.com/CosmosContracts/juno/v18/x/feepay/keeper" ) -// Check if a transaction should be processed as a FeePay transaction. Ensure that -// the Fee Pay module is enabled before calling this function. A valid FeePay transaction -// has no fee, and only 1 message for executing a contract. +// Check if a transaction should be processed as a FeePay transaction. +// A valid FeePay transaction has no fee and only 1 message which +// executes a CW contract. // // TODO: Future allow for multiple msgs. func IsValidFeePayTransaction(ctx sdk.Context, feePayKeeper feepaykeeper.Keeper, tx sdk.Tx, fee sdk.Coins) bool { From 9cb22dcc6325f800efeec16988cbfafa31a6d9ff Mon Sep 17 00:00:00 2001 From: Joel Smith Date: Mon, 16 Oct 2023 18:56:23 -0500 Subject: [PATCH 70/79] Require balance in register contract helper method --- x/feepay/keeper/keeper_test.go | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/x/feepay/keeper/keeper_test.go b/x/feepay/keeper/keeper_test.go index 6c479556e..2f307e0b1 100644 --- a/x/feepay/keeper/keeper_test.go +++ b/x/feepay/keeper/keeper_test.go @@ -116,11 +116,12 @@ func (s *IntegrationTestSuite) InstantiateContract(sender string, admin string) } // Helper method for quickly registering a fee pay contract -func (s *IntegrationTestSuite) registerFeePayContract(senderAddress string, contractAddress string, walletLimit uint64) { +func (s *IntegrationTestSuite) registerFeePayContract(senderAddress string, contractAddress string, balance uint64, walletLimit uint64) { _, err := s.app.AppKeepers.FeePayKeeper.RegisterFeePayContract(s.ctx, &types.MsgRegisterFeePayContract{ SenderAddress: senderAddress, FeePayContract: &types.FeePayContract{ ContractAddress: contractAddress, + Balance: balance, WalletLimit: walletLimit, }, }) From 9bfd32bfeeb127472779c8fe2355fe4d4a7b0b08 Mon Sep 17 00:00:00 2001 From: Joel Smith Date: Mon, 16 Oct 2023 19:02:02 -0500 Subject: [PATCH 71/79] Update proto --- x/feepay/types/query.pb.go | 87 ++++++++++++++++++----------------- x/feepay/types/query.pb.gw.go | 8 ++-- 2 files changed, 48 insertions(+), 47 deletions(-) diff --git a/x/feepay/types/query.pb.go b/x/feepay/types/query.pb.go index 88edc0843..80797d1d1 100644 --- a/x/feepay/types/query.pb.go +++ b/x/feepay/types/query.pb.go @@ -524,49 +524,50 @@ func init() { func init() { proto.RegisterFile("juno/feepay/v1/query.proto", fileDescriptor_d6539df905bf35ca) } var fileDescriptor_d6539df905bf35ca = []byte{ - // 666 bytes of a gzipped FileDescriptorProto - 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xb4, 0x55, 0x4d, 0x6f, 0xd3, 0x40, - 0x10, 0x8d, 0x4b, 0x89, 0xca, 0x22, 0xd2, 0xb2, 0x54, 0xa5, 0x72, 0x2b, 0x17, 0xb9, 0x40, 0x29, - 0x45, 0x5e, 0xa5, 0x85, 0x33, 0xb4, 0x55, 0x3f, 0x50, 0x2f, 0xc1, 0x12, 0x42, 0xe2, 0x40, 0xb5, - 0x49, 0x27, 0xc6, 0x90, 0x78, 0x9d, 0xac, 0x13, 0x88, 0xaa, 0x5e, 0x90, 0xb8, 0x23, 0x21, 0xae, - 0xfc, 0x0d, 0xc4, 0x2f, 0xa0, 0xc7, 0x4a, 0x5c, 0x38, 0x21, 0x94, 0xf0, 0x43, 0x90, 0x77, 0xd7, - 0x2e, 0x36, 0x6e, 0xe2, 0x1e, 0xb8, 0x6d, 0x66, 0xdf, 0xbe, 0x79, 0x33, 0xf3, 0xc6, 0x41, 0xfa, - 0xab, 0x8e, 0xc7, 0x48, 0x1d, 0xc0, 0xa7, 0x3d, 0xd2, 0x2d, 0x93, 0x56, 0x07, 0xda, 0x3d, 0xcb, - 0x6f, 0xb3, 0x80, 0xe1, 0x52, 0x78, 0x67, 0xc9, 0x3b, 0xab, 0x5b, 0xd6, 0xef, 0xd6, 0x18, 0x6f, - 0x32, 0x4e, 0xaa, 0x94, 0x83, 0x04, 0x92, 0x6e, 0xb9, 0x0a, 0x01, 0x2d, 0x13, 0x9f, 0x3a, 0xae, - 0x47, 0x03, 0x97, 0x79, 0xf2, 0xad, 0x3e, 0x9f, 0xe2, 0x75, 0xc0, 0x03, 0xee, 0x72, 0x75, 0x3b, - 0x97, 0xba, 0x55, 0x39, 0xe4, 0xe5, 0xb4, 0xc3, 0x1c, 0x26, 0x8e, 0x24, 0x3c, 0x45, 0x84, 0x0e, - 0x63, 0x4e, 0x03, 0x08, 0xf5, 0x5d, 0x42, 0x3d, 0x8f, 0x05, 0x22, 0x9b, 0x22, 0x34, 0x1f, 0xa1, - 0x6b, 0x4f, 0x42, 0x41, 0xdb, 0x00, 0x15, 0xda, 0xdb, 0x64, 0x5e, 0xd0, 0xa6, 0xb5, 0x00, 0x2f, - 0xa3, 0xa9, 0x9a, 0x3a, 0xef, 0xd3, 0x83, 0x83, 0x36, 0x70, 0x3e, 0xab, 0xdd, 0xd0, 0xee, 0x5c, - 0xb2, 0x27, 0xa3, 0xf8, 0xba, 0x0c, 0x9b, 0x0e, 0x9a, 0xcb, 0x60, 0xb0, 0x81, 0xfb, 0xcc, 0xe3, - 0x80, 0x77, 0xd1, 0x54, 0x1d, 0x60, 0xdf, 0xa7, 0xbd, 0xfd, 0xe8, 0xa5, 0x60, 0xba, 0xbc, 0x6a, - 0x58, 0xc9, 0x36, 0x59, 0x29, 0x86, 0x52, 0x3d, 0xf1, 0xdb, 0x7c, 0x81, 0xa6, 0x33, 0x12, 0x71, - 0xbc, 0x8d, 0xd0, 0x69, 0x17, 0x15, 0xf7, 0x6d, 0x4b, 0xb6, 0xdc, 0x0a, 0x5b, 0x6e, 0xc9, 0xd9, - 0xa8, 0x96, 0x5b, 0x15, 0xea, 0x80, 0x0d, 0xad, 0x0e, 0xf0, 0xc0, 0xfe, 0xeb, 0xa5, 0xf9, 0x55, - 0x43, 0xf3, 0x59, 0x09, 0xe2, 0x52, 0x2a, 0xe8, 0x6a, 0xba, 0x94, 0xb0, 0x2b, 0x17, 0x46, 0xd7, - 0xb2, 0x31, 0x7e, 0xfc, 0x73, 0xa1, 0x60, 0x4f, 0xd6, 0x53, 0xd2, 0x77, 0x12, 0xd2, 0xc7, 0x84, - 0xf4, 0xa5, 0x91, 0xd2, 0xa5, 0x9c, 0x84, 0xf6, 0xd7, 0xe8, 0x7a, 0x86, 0xf4, 0xa7, 0x1c, 0xf8, - 0x39, 0x46, 0x89, 0x6f, 0xa1, 0xd2, 0x1b, 0xda, 0x68, 0xc0, 0x29, 0x70, 0x4c, 0x00, 0xaf, 0xc8, - 0x68, 0x34, 0xf1, 0x07, 0x68, 0xe1, 0x8c, 0x64, 0x71, 0xab, 0x30, 0x1a, 0xef, 0x70, 0x90, 0x89, - 0xc6, 0x6d, 0x71, 0x36, 0x59, 0xc2, 0x28, 0xcf, 0x04, 0xe5, 0x63, 0xbe, 0xd5, 0x70, 0x1d, 0xb7, - 0xda, 0x80, 0xff, 0xa0, 0x73, 0x1d, 0x2d, 0x0e, 0x49, 0x18, 0x6b, 0xd5, 0xd1, 0x04, 0xa8, 0x98, - 0x48, 0x38, 0x61, 0xc7, 0xbf, 0xcd, 0x69, 0x84, 0x05, 0x45, 0x85, 0xb6, 0x69, 0x93, 0x2b, 0xd7, - 0x98, 0x7b, 0x6a, 0x69, 0xa2, 0xa8, 0x22, 0xba, 0x8f, 0x8a, 0xbe, 0x88, 0x28, 0x13, 0xce, 0xa4, - 0x4d, 0x21, 0xf1, 0xca, 0x0c, 0x0a, 0xbb, 0xfa, 0xb9, 0x88, 0x2e, 0x0a, 0x36, 0xfc, 0x49, 0x43, - 0xa5, 0xd4, 0x1e, 0x2e, 0xa6, 0x29, 0x32, 0x1a, 0xaf, 0xaf, 0xe4, 0x00, 0x45, 0x22, 0xcd, 0xf2, - 0xbb, 0xef, 0xbf, 0x3f, 0x8e, 0xad, 0xe0, 0x65, 0x92, 0xf9, 0x29, 0x21, 0x87, 0xe9, 0x21, 0x1c, - 0xe1, 0xf7, 0x1a, 0x9a, 0x4c, 0x2f, 0xdd, 0xcd, 0x1c, 0x39, 0xb9, 0x7e, 0x2f, 0x0f, 0x2a, 0x96, - 0x66, 0x08, 0x69, 0xb3, 0x78, 0x26, 0x5b, 0x1a, 0xfe, 0xa2, 0x21, 0x9c, 0x61, 0xf0, 0xa5, 0x1c, - 0x49, 0x42, 0xa0, 0x4e, 0x72, 0x02, 0x63, 0x41, 0x3b, 0x42, 0xd0, 0x3a, 0x7e, 0x98, 0xbb, 0x57, - 0x24, 0x74, 0x3a, 0x39, 0x4c, 0xba, 0xf3, 0x08, 0x7f, 0xd3, 0xd0, 0xcc, 0x19, 0xb6, 0x1f, 0x36, - 0xbc, 0x34, 0x58, 0x5f, 0x3b, 0x07, 0x38, 0xae, 0x62, 0x4f, 0x54, 0xb1, 0x85, 0x37, 0xf3, 0x57, - 0x11, 0xf9, 0xff, 0xdf, 0x4a, 0x5a, 0xa8, 0x28, 0x5d, 0x8c, 0xcd, 0x4c, 0x2d, 0x89, 0x45, 0xd1, - 0x17, 0x87, 0x62, 0x46, 0x8d, 0x5d, 0x2e, 0xc8, 0xc6, 0xee, 0x71, 0xdf, 0xd0, 0x4e, 0xfa, 0x86, - 0xf6, 0xab, 0x6f, 0x68, 0x1f, 0x06, 0x46, 0xe1, 0x64, 0x60, 0x14, 0x7e, 0x0c, 0x8c, 0xc2, 0x73, - 0xcb, 0x71, 0x83, 0x97, 0x9d, 0xaa, 0x55, 0x63, 0x4d, 0xb2, 0x29, 0x3e, 0x9a, 0xb1, 0xa9, 0x24, - 0xd7, 0xdb, 0x88, 0x2d, 0xe8, 0xf9, 0xc0, 0xab, 0x45, 0xf1, 0x9f, 0xb7, 0xf6, 0x27, 0x00, 0x00, - 0xff, 0xff, 0x97, 0xc0, 0x24, 0x4b, 0xbc, 0x07, 0x00, 0x00, + // 680 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xb4, 0x55, 0x4f, 0x4f, 0xd4, 0x40, + 0x14, 0xdf, 0x22, 0x6e, 0x70, 0x8c, 0x0b, 0x8e, 0x04, 0x49, 0xc1, 0x62, 0x8a, 0x88, 0x8a, 0x76, + 0xb2, 0xa0, 0x77, 0x81, 0xf0, 0x2f, 0xc6, 0x64, 0x6d, 0x62, 0x4c, 0x3c, 0x48, 0x66, 0x97, 0xb7, + 0xb5, 0x5a, 0x3a, 0x65, 0xa7, 0x8b, 0x6e, 0x08, 0x17, 0xcf, 0x1e, 0x4c, 0x3c, 0xf8, 0x21, 0xfc, + 0x04, 0x7c, 0x03, 0xbc, 0x91, 0x78, 0xf1, 0x64, 0x0c, 0xf8, 0x41, 0x4c, 0x67, 0xa6, 0xc5, 0x8e, + 0x65, 0xd9, 0x3d, 0x78, 0x9b, 0x7d, 0xf3, 0x9b, 0xdf, 0xfb, 0xbd, 0xf7, 0x7e, 0xaf, 0x8b, 0xcc, + 0x37, 0xed, 0x90, 0x91, 0x26, 0x40, 0x44, 0x3b, 0x64, 0xb7, 0x4a, 0x76, 0xda, 0xd0, 0xea, 0x38, + 0x51, 0x8b, 0xc5, 0x0c, 0x57, 0x92, 0x3b, 0x47, 0xde, 0x39, 0xbb, 0x55, 0xf3, 0x5e, 0x83, 0xf1, + 0x6d, 0xc6, 0x49, 0x9d, 0x72, 0x90, 0x40, 0xb2, 0x5b, 0xad, 0x43, 0x4c, 0xab, 0x24, 0xa2, 0x9e, + 0x1f, 0xd2, 0xd8, 0x67, 0xa1, 0x7c, 0x6b, 0x4e, 0x6a, 0xbc, 0x1e, 0x84, 0xc0, 0x7d, 0xae, 0x6e, + 0x27, 0xb4, 0x5b, 0x95, 0x43, 0x5e, 0x8e, 0x7a, 0xcc, 0x63, 0xe2, 0x48, 0x92, 0x53, 0x4a, 0xe8, + 0x31, 0xe6, 0x05, 0x40, 0x68, 0xe4, 0x13, 0x1a, 0x86, 0x2c, 0x16, 0xd9, 0x14, 0xa1, 0xfd, 0x18, + 0x5d, 0x7b, 0x96, 0x08, 0x5a, 0x05, 0xa8, 0xd1, 0xce, 0x32, 0x0b, 0xe3, 0x16, 0x6d, 0xc4, 0xf8, + 0x2e, 0x1a, 0x69, 0xa8, 0xf3, 0x26, 0xdd, 0xda, 0x6a, 0x01, 0xe7, 0xe3, 0xc6, 0x4d, 0xe3, 0xce, + 0x25, 0x77, 0x38, 0x8d, 0x2f, 0xca, 0xb0, 0xed, 0xa1, 0x89, 0x02, 0x06, 0x17, 0x78, 0xc4, 0x42, + 0x0e, 0x78, 0x1d, 0x8d, 0x34, 0x01, 0x36, 0x23, 0xda, 0xd9, 0x4c, 0x5f, 0x0a, 0xa6, 0xcb, 0xf3, + 0x96, 0x93, 0x6f, 0x93, 0xa3, 0x31, 0x54, 0x9a, 0xb9, 0xdf, 0xf6, 0x2b, 0x34, 0x5a, 0x90, 0x88, + 0xe3, 0x55, 0x84, 0x4e, 0xbb, 0xa8, 0xb8, 0x6f, 0x3b, 0xb2, 0xe5, 0x4e, 0xd2, 0x72, 0x47, 0xce, + 0x46, 0xb5, 0xdc, 0xa9, 0x51, 0x0f, 0x5c, 0xd8, 0x69, 0x03, 0x8f, 0xdd, 0xbf, 0x5e, 0xda, 0x07, + 0x06, 0x9a, 0x2c, 0x4a, 0x90, 0x95, 0x52, 0x43, 0x57, 0xf5, 0x52, 0x92, 0xae, 0x5c, 0x38, 0xbf, + 0x96, 0xa5, 0xc1, 0xc3, 0x9f, 0x53, 0x25, 0x77, 0xb8, 0xa9, 0x49, 0x5f, 0xcb, 0x49, 0x1f, 0x10, + 0xd2, 0x67, 0xcf, 0x95, 0x2e, 0xe5, 0xe4, 0xb4, 0xbf, 0x45, 0xd7, 0x0b, 0xa4, 0x3f, 0xe7, 0xc0, + 0xfb, 0x18, 0x25, 0x9e, 0x41, 0x95, 0x77, 0x34, 0x08, 0xe0, 0x14, 0x38, 0x20, 0x80, 0x57, 0x64, + 0x34, 0x9d, 0xf8, 0x23, 0x34, 0x75, 0x46, 0xb2, 0xac, 0x55, 0x18, 0x0d, 0xb6, 0x39, 0xc8, 0x44, + 0x83, 0xae, 0x38, 0xdb, 0x2c, 0x67, 0x94, 0x17, 0x82, 0x72, 0x83, 0xaf, 0x04, 0xbe, 0xe7, 0xd7, + 0x03, 0xf8, 0x0f, 0x3a, 0x17, 0xd1, 0x74, 0x97, 0x84, 0x99, 0x56, 0x13, 0x0d, 0x81, 0x8a, 0x89, + 0x84, 0x43, 0x6e, 0xf6, 0xdb, 0x1e, 0x45, 0x58, 0x50, 0xd4, 0x68, 0x8b, 0x6e, 0x73, 0xe5, 0x1a, + 0xfb, 0x89, 0x5a, 0x9a, 0x34, 0xaa, 0x88, 0x1e, 0xa2, 0x72, 0x24, 0x22, 0xca, 0x84, 0x63, 0xba, + 0x29, 0x24, 0x5e, 0x99, 0x41, 0x61, 0xe7, 0xbf, 0x96, 0xd1, 0x45, 0xc1, 0x86, 0xbf, 0x18, 0xa8, + 0xa2, 0xed, 0xe1, 0xb4, 0x4e, 0x51, 0xd0, 0x78, 0x73, 0xae, 0x07, 0x50, 0x2a, 0xd2, 0x5e, 0xf8, + 0xf0, 0xfd, 0xf7, 0xe7, 0x81, 0x07, 0x78, 0x8e, 0x68, 0x9f, 0x92, 0xb4, 0xc9, 0x64, 0x4f, 0x1f, + 0xc3, 0x3e, 0xfe, 0x68, 0xa0, 0x61, 0x7d, 0xed, 0x6e, 0xf5, 0x90, 0x95, 0x9b, 0xf7, 0x7b, 0x41, + 0x65, 0xe2, 0x66, 0x84, 0xb8, 0x29, 0x7c, 0x43, 0x17, 0x47, 0x83, 0xe0, 0x74, 0xe7, 0xf0, 0x81, + 0x81, 0x70, 0x81, 0xd3, 0x67, 0x7b, 0xc8, 0x95, 0x00, 0x4d, 0xd2, 0x23, 0x30, 0xd3, 0xb5, 0x21, + 0x74, 0x2d, 0xe3, 0xc5, 0x3e, 0x9a, 0x46, 0x12, 0xd3, 0x93, 0xbd, 0xbc, 0x51, 0xf7, 0xf1, 0x37, + 0x03, 0x8d, 0x9d, 0xb1, 0x01, 0xdd, 0xe6, 0xa8, 0x83, 0xcd, 0x85, 0x3e, 0xc0, 0x59, 0x1d, 0x4f, + 0x45, 0x1d, 0x6b, 0x78, 0xa5, 0x9f, 0x3a, 0xd2, 0x65, 0xf8, 0xb7, 0x96, 0x1d, 0x54, 0x96, 0x96, + 0xc6, 0x76, 0xa1, 0x9a, 0xdc, 0xd6, 0x98, 0xd3, 0x5d, 0x31, 0x4a, 0xa1, 0x25, 0x14, 0x8e, 0xe3, + 0x31, 0x5d, 0xa1, 0xdc, 0x96, 0xa5, 0xf5, 0xc3, 0x63, 0xcb, 0x38, 0x3a, 0xb6, 0x8c, 0x5f, 0xc7, + 0x96, 0xf1, 0xe9, 0xc4, 0x2a, 0x1d, 0x9d, 0x58, 0xa5, 0x1f, 0x27, 0x56, 0xe9, 0xa5, 0xe3, 0xf9, + 0xf1, 0xeb, 0x76, 0xdd, 0x69, 0xb0, 0x6d, 0xb2, 0x2c, 0xbe, 0xa0, 0x99, 0xbf, 0x24, 0xd7, 0xfb, + 0x94, 0x2d, 0xee, 0x44, 0xc0, 0xeb, 0x65, 0xf1, 0x07, 0xb8, 0xf0, 0x27, 0x00, 0x00, 0xff, 0xff, + 0x44, 0xa8, 0x44, 0xd2, 0xc9, 0x07, 0x00, 0x00, } // Reference imports to suppress errors if they are not otherwise used. diff --git a/x/feepay/types/query.pb.gw.go b/x/feepay/types/query.pb.gw.go index 91c1f358e..fbf60d7d4 100644 --- a/x/feepay/types/query.pb.gw.go +++ b/x/feepay/types/query.pb.gw.go @@ -559,13 +559,13 @@ func RegisterQueryHandlerClient(ctx context.Context, mux *runtime.ServeMux, clie } var ( - pattern_Query_FeePayContract_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2, 2, 1, 1, 0, 4, 1, 5, 3}, []string{"juno", "feepay", "v1", "contract_address"}, "", runtime.AssumeColonVerbOpt(false))) + pattern_Query_FeePayContract_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2, 2, 3, 1, 0, 4, 1, 5, 4}, []string{"juno", "feepay", "v1", "contract", "contract_address"}, "", runtime.AssumeColonVerbOpt(false))) - pattern_Query_FeePayContracts_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2, 2, 1}, []string{"juno", "feepay", "v1"}, "", runtime.AssumeColonVerbOpt(false))) + pattern_Query_FeePayContracts_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2, 2, 3}, []string{"juno", "feepay", "v1", "all_contracts"}, "", runtime.AssumeColonVerbOpt(false))) - pattern_Query_FeePayContractUses_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2, 2, 1, 1, 0, 4, 1, 5, 3, 2, 4, 1, 0, 4, 1, 5, 5}, []string{"juno", "feepay", "v1", "contract_address", "uses", "wallet_address"}, "", runtime.AssumeColonVerbOpt(false))) + pattern_Query_FeePayContractUses_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2, 2, 3, 1, 0, 4, 1, 5, 4, 2, 5, 1, 0, 4, 1, 5, 6}, []string{"juno", "feepay", "v1", "contract", "contract_address", "uses", "wallet_address"}, "", runtime.AssumeColonVerbOpt(false))) - pattern_Query_FeePayWalletIsEligible_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2, 2, 1, 1, 0, 4, 1, 5, 3, 2, 4, 1, 0, 4, 1, 5, 5}, []string{"juno", "feepay", "v1", "contract_address", "eligible", "wallet_address"}, "", runtime.AssumeColonVerbOpt(false))) + pattern_Query_FeePayWalletIsEligible_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2, 2, 3, 1, 0, 4, 1, 5, 4, 2, 5, 1, 0, 4, 1, 5, 6}, []string{"juno", "feepay", "v1", "contract", "contract_address", "eligible", "wallet_address"}, "", runtime.AssumeColonVerbOpt(false))) pattern_Query_Params_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2, 2, 3}, []string{"juno", "feepay", "v1", "params"}, "", runtime.AssumeColonVerbOpt(false))) ) From 40a9d75b4142c73f95ce0905fec52f0bb7e4ea0a Mon Sep 17 00:00:00 2001 From: Joel Smith Date: Mon, 16 Oct 2023 19:04:02 -0500 Subject: [PATCH 72/79] Delete chain state export file --- state_export.json | 787 ---------------------------------------------- 1 file changed, 787 deletions(-) delete mode 100644 state_export.json diff --git a/state_export.json b/state_export.json deleted file mode 100644 index e62a0a7e6..000000000 --- a/state_export.json +++ /dev/null @@ -1,787 +0,0 @@ -{ - "app_hash": "", - "app_state": { - "auth": { - "accounts": [ - { - "@type": "/cosmos.auth.v1beta1.ModuleAccount", - "base_account": { - "account_number": "0", - "address": "juno19ejy8n9qsectrf4semdp9cpknflld0j6tj7k2a", - "pub_key": null, - "sequence": "0" - }, - "name": "tokenfactory", - "permissions": [ - "minter", - "burner" - ] - }, - { - "@type": "/cosmos.auth.v1beta1.BaseAccount", - "account_number": "10", - "address": "juno1f7f2eapsz6w4s2fytlm34yu5w89ueaesg7x9v5", - "pub_key": null, - "sequence": "0" - }, - { - "@type": "/cosmos.auth.v1beta1.ModuleAccount", - "base_account": { - "account_number": "5", - "address": "juno1fl48vsnmsdzcv85q5d2q4z5ajdha8yu3rf257t", - "pub_key": null, - "sequence": "0" - }, - "name": "bonded_tokens_pool", - "permissions": [ - "burner", - "staking" - ] - }, - { - "@type": "/cosmos.auth.v1beta1.ModuleAccount", - "base_account": { - "account_number": "6", - "address": "juno1tygms3xhhs3yv487phx3dw4a95jn7t7lhfk9gl", - "pub_key": null, - "sequence": "0" - }, - "name": "not_bonded_tokens_pool", - "permissions": [ - "burner", - "staking" - ] - }, - { - "@type": "/cosmos.auth.v1beta1.ModuleAccount", - "base_account": { - "account_number": "7", - "address": "juno10d07y265gmmuvt4z0w9aw880jnsr700jvss730", - "pub_key": null, - "sequence": "0" - }, - "name": "gov", - "permissions": [ - "burner" - ] - }, - { - "@type": "/cosmos.auth.v1beta1.BaseAccount", - "account_number": "2", - "address": "juno1see0htr47uapjvcvh0hu6385rp8lw3emu85lh5", - "pub_key": null, - "sequence": "0" - }, - { - "@type": "/cosmos.auth.v1beta1.ModuleAccount", - "base_account": { - "account_number": "4", - "address": "juno1jv65s3grqf6v6jl3dp4t6c9t9rk99cd83d88wr", - "pub_key": null, - "sequence": "0" - }, - "name": "distribution", - "permissions": [] - }, - { - "@type": "/cosmos.auth.v1beta1.BaseAccount", - "account_number": "9", - "address": "juno14hj2tavq8fpesdwxxcu44rty3hh90vhujrvcmstl4zr3txmfvw9skjuwg8", - "pub_key": null, - "sequence": "0" - }, - { - "@type": "/cosmos.auth.v1beta1.BaseAccount", - "account_number": "0", - "address": "juno1hj5fveer5cjtn4wd6wstzugjfdxzl0xps73ftl", - "pub_key": { - "@type": "/cosmos.crypto.secp256k1.PubKey", - "key": "ApZa31BR3NWLylRT6Qi5+f+zXtj2OpqtC76vgkUGLyww" - }, - "sequence": "8" - }, - { - "@type": "/cosmos.auth.v1beta1.BaseAccount", - "account_number": "1", - "address": "juno1efd63aw40lxf3n4mhf7dzhjkr453axurv2zdzk", - "pub_key": null, - "sequence": "0" - }, - { - "@type": "/cosmos.auth.v1beta1.ModuleAccount", - "base_account": { - "account_number": "8", - "address": "juno1m3h30wlvsf8llruxtpukdvsy0km2kum87ryrqu", - "pub_key": null, - "sequence": "0" - }, - "name": "mint", - "permissions": [ - "minter" - ] - }, - { - "@type": "/cosmos.auth.v1beta1.ModuleAccount", - "base_account": { - "account_number": "3", - "address": "juno17xpfvakm2amg962yls6f84z3kell8c5lxtqmvp", - "pub_key": null, - "sequence": "0" - }, - "name": "fee_collector", - "permissions": [] - } - ], - "params": { - "max_memo_characters": "256", - "sig_verify_cost_ed25519": "590", - "sig_verify_cost_secp256k1": "1000", - "tx_sig_limit": "7", - "tx_size_cost_per_byte": "10" - } - }, - "authz": { - "authorization": [] - }, - "bank": { - "balances": [ - { - "address": "juno1f7f2eapsz6w4s2fytlm34yu5w89ueaesg7x9v5", - "coins": [ - { - "amount": "5000000", - "denom": "ujuno" - } - ] - }, - { - "address": "juno1fl48vsnmsdzcv85q5d2q4z5ajdha8yu3rf257t", - "coins": [ - { - "amount": "1000000", - "denom": "ujuno" - } - ] - }, - { - "address": "juno1see0htr47uapjvcvh0hu6385rp8lw3emu85lh5", - "coins": [ - { - "amount": "100000000000", - "denom": "ujuno" - } - ] - }, - { - "address": "juno1jv65s3grqf6v6jl3dp4t6c9t9rk99cd83d88wr", - "coins": [ - { - "amount": "684160", - "denom": "ujuno" - } - ] - }, - { - "address": "juno1hj5fveer5cjtn4wd6wstzugjfdxzl0xps73ftl", - "coins": [ - { - "amount": "3759500", - "denom": "ujuno" - }, - { - "amount": "1000", - "denom": "utest" - } - ] - }, - { - "address": "juno1efd63aw40lxf3n4mhf7dzhjkr453axurv2zdzk", - "coins": [ - { - "amount": "1000000", - "denom": "ujuno" - }, - { - "amount": "1000", - "denom": "utest" - } - ] - } - ], - "denom_metadata": [], - "params": { - "default_send_enabled": true, - "send_enabled": [] - }, - "send_enabled": [], - "supply": [ - { - "amount": "100011443660", - "denom": "ujuno" - }, - { - "amount": "2000", - "denom": "utest" - } - ] - }, - "builder": { - "params": { - "escrow_account_address": "32sHF2qbF8xMmvwle9QEcy59Cbc=", - "front_running_protection": false, - "max_bundle_size": 4, - "min_bid_increment": { - "amount": "1000000", - "denom": "ujuno" - }, - "proposer_fee": "0.000000000000000000", - "reserve_fee": { - "amount": "1000000", - "denom": "ujuno" - } - } - }, - "capability": { - "index": "4", - "owners": [ - { - "index": "1", - "index_owners": { - "owners": [ - { - "module": "ibc", - "name": "ports/transfer" - }, - { - "module": "transfer", - "name": "ports/transfer" - } - ] - } - }, - { - "index": "2", - "index_owners": { - "owners": [ - { - "module": "ibc", - "name": "ports/icahost" - }, - { - "module": "icahost", - "name": "ports/icahost" - } - ] - } - }, - { - "index": "3", - "index_owners": { - "owners": [ - { - "module": "ibc", - "name": "ports/icqhost" - }, - { - "module": "interchainquery", - "name": "ports/icqhost" - } - ] - } - } - ] - }, - "consensus": null, - "crisis": { - "constant_fee": { - "amount": "1000", - "denom": "ujuno" - } - }, - "distribution": { - "delegator_starting_infos": [ - { - "delegator_address": "juno1hj5fveer5cjtn4wd6wstzugjfdxzl0xps73ftl", - "starting_info": { - "height": "0", - "previous_period": "1", - "stake": "1000000.000000000000000000" - }, - "validator_address": "junovaloper1hj5fveer5cjtn4wd6wstzugjfdxzl0xp0r8xsx" - } - ], - "delegator_withdraw_infos": [], - "fee_pool": { - "community_pool": [ - { - "amount": "13683.200000000000000000", - "denom": "ujuno" - } - ] - }, - "outstanding_rewards": [ - { - "outstanding_rewards": [ - { - "amount": "670476.800000000000000000", - "denom": "ujuno" - } - ], - "validator_address": "junovaloper1hj5fveer5cjtn4wd6wstzugjfdxzl0xp0r8xsx" - } - ], - "params": { - "base_proposer_reward": "0.000000000000000000", - "bonus_proposer_reward": "0.000000000000000000", - "community_tax": "0.020000000000000000", - "withdraw_addr_enabled": true - }, - "previous_proposer": "junovalcons1y8fgw9974fcxp9ghn3duftjt9v7q66vguel7cc", - "validator_accumulated_commissions": [ - { - "accumulated": { - "commission": [ - { - "amount": "67047.680000000000000000", - "denom": "ujuno" - } - ] - }, - "validator_address": "junovaloper1hj5fveer5cjtn4wd6wstzugjfdxzl0xp0r8xsx" - } - ], - "validator_current_rewards": [ - { - "rewards": { - "period": "2", - "rewards": [ - { - "amount": "603429.120000000000000000", - "denom": "ujuno" - } - ] - }, - "validator_address": "junovaloper1hj5fveer5cjtn4wd6wstzugjfdxzl0xp0r8xsx" - } - ], - "validator_historical_rewards": [ - { - "period": "1", - "rewards": { - "cumulative_reward_ratio": [], - "reference_count": 2 - }, - "validator_address": "junovaloper1hj5fveer5cjtn4wd6wstzugjfdxzl0xp0r8xsx" - } - ], - "validator_slash_events": [] - }, - "drip": { - "params": { - "allowed_addresses": [ - "juno1hj5fveer5cjtn4wd6wstzugjfdxzl0xps73ftl", - "juno1efd63aw40lxf3n4mhf7dzhjkr453axurv2zdzk" - ], - "enable_drip": true - } - }, - "evidence": { - "evidence": [] - }, - "feegrant": { - "allowances": [] - }, - "feeibc": { - "fee_enabled_channels": [], - "forward_relayers": [], - "identified_fees": [], - "registered_counterparty_payees": [], - "registered_payees": [] - }, - "feepay": { - "fee_contract": [], - "params": {} - }, - "feeshare": { - "fee_share": [], - "params": { - "allowed_denoms": [ - "ujuno" - ], - "developer_shares": "0.500000000000000000", - "enable_fee_share": true - } - }, - "genutil": { - "gen_txs": [] - }, - "globalfee": { - "params": { - "minimum_gas_prices": [ - { - "amount": "0.002500000000000000", - "denom": "ujuno" - } - ] - } - }, - "gov": { - "deposit_params": null, - "deposits": [], - "params": { - "burn_proposal_deposit_prevote": false, - "burn_vote_quorum": false, - "burn_vote_veto": true, - "max_deposit_period": "172800s", - "min_deposit": [ - { - "amount": "1000000", - "denom": "ujuno" - } - ], - "min_initial_deposit_ratio": "0.000000000000000000", - "quorum": "0.334000000000000000", - "threshold": "0.500000000000000000", - "veto_threshold": "0.334000000000000000", - "voting_period": "172800s" - }, - "proposals": [], - "starting_proposal_id": "1", - "tally_params": null, - "votes": [], - "voting_params": null - }, - "ibc": { - "channel_genesis": { - "ack_sequences": [], - "acknowledgements": [], - "channels": [], - "commitments": [], - "next_channel_sequence": "0", - "receipts": [], - "recv_sequences": [], - "send_sequences": [] - }, - "client_genesis": { - "clients": [ - { - "client_id": "09-localhost", - "client_state": { - "@type": "/ibc.lightclients.localhost.v2.ClientState", - "latest_height": { - "revision_height": "70", - "revision_number": "1" - } - } - } - ], - "clients_consensus": [], - "clients_metadata": [], - "create_localhost": false, - "next_client_sequence": "0", - "params": { - "allowed_clients": [ - "06-solomachine", - "07-tendermint", - "09-localhost" - ] - } - }, - "connection_genesis": { - "client_connection_paths": [], - "connections": [ - { - "client_id": "09-localhost", - "counterparty": { - "client_id": "09-localhost", - "connection_id": "connection-localhost", - "prefix": { - "key_prefix": "aWJj" - } - }, - "delay_period": "0", - "id": "connection-localhost", - "state": "STATE_OPEN", - "versions": [ - { - "features": [ - "ORDER_ORDERED", - "ORDER_UNORDERED" - ], - "identifier": "1" - } - ] - } - ], - "next_connection_sequence": "0", - "params": { - "max_expected_time_per_block": "30000000000" - } - } - }, - "ibchooks": {}, - "interchainaccounts": { - "controller_genesis_state": { - "active_channels": [], - "interchain_accounts": [], - "params": { - "controller_enabled": true - }, - "ports": [] - }, - "host_genesis_state": { - "active_channels": [], - "interchain_accounts": [], - "params": { - "allow_messages": [ - "*" - ], - "host_enabled": true - }, - "port": "icahost" - } - }, - "interchainquery": { - "host_port": "icqhost", - "params": { - "allow_queries": [], - "host_enabled": true - } - }, - "mint": { - "minter": { - "annual_provisions": "40004400000.000000000000000000", - "inflation": "0.400000000000000000", - "phase": "1", - "start_phase_block": "1", - "target_supply": "140015400000" - }, - "params": { - "blocks_per_year": "6311520", - "mint_denom": "ujuno" - } - }, - "nft": { - "classes": [], - "entries": [] - }, - "packetfowardmiddleware": { - "in_flight_packets": {}, - "params": { - "fee_percentage": "0.000000000000000000" - } - }, - "params": null, - "slashing": { - "missed_blocks": [ - { - "address": "junovalcons1y8fgw9974fcxp9ghn3duftjt9v7q66vguel7cc", - "missed_blocks": [] - } - ], - "params": { - "downtime_jail_duration": "600s", - "min_signed_per_window": "0.500000000000000000", - "signed_blocks_window": "100", - "slash_fraction_double_sign": "0.050000000000000000", - "slash_fraction_downtime": "0.010000000000000000" - }, - "signing_infos": [ - { - "address": "junovalcons1y8fgw9974fcxp9ghn3duftjt9v7q66vguel7cc", - "validator_signing_info": { - "address": "junovalcons1y8fgw9974fcxp9ghn3duftjt9v7q66vguel7cc", - "index_offset": "69", - "jailed_until": "1970-01-01T00:00:00Z", - "missed_blocks_counter": "0", - "start_height": "0", - "tombstoned": false - } - } - ] - }, - "staking": { - "delegations": [ - { - "delegator_address": "juno1hj5fveer5cjtn4wd6wstzugjfdxzl0xps73ftl", - "shares": "1000000.000000000000000000", - "validator_address": "junovaloper1hj5fveer5cjtn4wd6wstzugjfdxzl0xp0r8xsx" - } - ], - "exported": true, - "last_total_power": "1", - "last_validator_powers": [ - { - "address": "junovaloper1hj5fveer5cjtn4wd6wstzugjfdxzl0xp0r8xsx", - "power": "1" - } - ], - "params": { - "bond_denom": "ujuno", - "historical_entries": 10000, - "max_entries": 7, - "max_validators": 100, - "min_commission_rate": "0.050000000000000000", - "unbonding_time": "1814400s" - }, - "redelegations": [], - "unbonding_delegations": [], - "validators": [ - { - "commission": { - "commission_rates": { - "max_change_rate": "0.010000000000000000", - "max_rate": "0.200000000000000000", - "rate": "0.100000000000000000" - }, - "update_time": "2023-09-07T23:21:17.073977743Z" - }, - "consensus_pubkey": { - "@type": "/cosmos.crypto.ed25519.PubKey", - "key": "9cSyCx910OX4PtUt+iYO6sF6TXi4OIDclvVEDxThXu8=" - }, - "delegator_shares": "1000000.000000000000000000", - "description": { - "details": "", - "identity": "", - "moniker": "localjuno", - "security_contact": "", - "website": "" - }, - "jailed": false, - "min_self_delegation": "1", - "operator_address": "junovaloper1hj5fveer5cjtn4wd6wstzugjfdxzl0xp0r8xsx", - "status": "BOND_STATUS_BONDED", - "tokens": "1000000", - "unbonding_height": "0", - "unbonding_ids": [], - "unbonding_on_hold_ref_count": "0", - "unbonding_time": "1970-01-01T00:00:00Z" - } - ] - }, - "tokenfactory": { - "factory_denoms": [], - "params": { - "denom_creation_fee": [], - "denom_creation_gas_consume": "2000000" - } - }, - "transfer": { - "denom_traces": [], - "params": { - "receive_enabled": true, - "send_enabled": true - }, - "port_id": "transfer", - "total_escrowed": [] - }, - "upgrade": {}, - "vesting": {}, - "wasm": { - "codes": [ - { - "code_bytes": "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DRQgA0HQAWogA0GYAWoQlwEgAygC0AEiBEEVRg0FIAMoAtQBIQIgAygC3AEhCiADKALYASENIAkEQCAFELcBCyABBEAgAUEFdCEFIAZBFGohAQNAIAFBBGsoAgAEQCABKAIAELcBCyABQSBqIQEgBUEgayIFDQALCyACQQh2IQEgCEUNFSAGELcBDBULIBFFIQIgA0G8AWogAygC3AE2AgAgA0G0AWogAykC1AE3AgAgAyABNgKwASAJRQ0SIAUQtwEMEgsgA0G8AWogAygC3AE2AgAgA0G0AWogAykC1AE3AgAMCwsgA0HQAWogDBCYAQJAIAMoAtABIgJBFUcEQCADQfwBaiADQdwBaigCADYCACADIAMpAtQBNwL0AQwBCyADQfABaiAMEBwgAygC8AEiAkEVRg0GCyADQbQBaiADKQL0ATcCACADQbwBaiADQfwBaigCADYCACADIAI2ArABIAYNDgwPCyAGRQ0DIANBsAFqQa2CwABBBRAdIANBADYCrAEMDQsgEUUNASADQbABakGngsAAQQYQHSAGDQwMDQsgA0HQAWogA0GYAWoQlQEgAygC0AEiBEEVRwRAIAMoAtwBIQogAygC2AEhDSADKALUASECIAkEQCAFELcBCyABBEAgAUEFdCEFIAZBFGohAQNAIAFBBGsoAgAEQCABKAIAELcBCyABQSBqIQEgBUEgayIFDQALCyAIRQ0RIAYQtwEMEQsgAEEYaiABNgIAIABBFGogBjYCACAAQRBqIAg2AgAgAEEMaiAUNgIAIABBCGogBTYCACAAIAk2AgQgAEENNgIADBELIANB0AFqIAwQmAECfyADKALQASICQRVGBEAgA0HQAWogDBAeIAMoAtwBIRQgAygC2AEhESADKALUASIKIAMoAtABIgJBFUcNARogCiEcDAMLIAMoAtwBIRQgAygC2AEhESADKALUAQshBSADQbwBaiAUNgIAIANBuAFqIBE2AgAgA0G0AWogBTYCAAwGCyADQdABaiAMEJgBAn8CQAJAAkACQAJAAn8CQAJAAkAgAygC0AEiB0EVRgRAIANB6ABqIAwQmgEgAy0AaSEFAn8gAy0AaEEBcQRAIAVB/wFxQdsARwRAIAghBUEODAILIAwQlAEgA0HgAGogDBCSASADLQBkIAMoAmAhBkEAIRIgA0EANgLIASADQoCA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BEEVRg0AIAIoApgBIQUgByEDDA8LQQAhByADQYB+cUEBcgsiA0H/AXFFBEAgAkGIAWogARCXASACKAKIASIBQRVHDQMgAEEVNgIADBALIAJBiAFqIAUQmAECQAJAIAIoAogBIgRBFUcEQCACQYABaiAJQQhqKAIAIgE2AgAgAiAJKQIAIgs3A3ggCEEIaiABNgIAIAggCzcCAAwBCyACQegAaiAFEBwgAigCaCIEQRVGDQELIAIoAnQhBSACKAJwIQYgAi0AbCEDIAIvAG0gAi0Ab0EQdHIMDwsgAkEwaiAFEJoBIAItADEhBCACLQAwQQFxDQALCyADQYB+cSAEQf8BcXIhA0ECIQQMCwsgAkHwAGogAkGUAWooAgAiAzYCACACIAIpAowBIgs3A2ggAEEMaiADNgIAIAAgCzcCBCAAIAE2AgAMDAsgACADOgAEIABBBDYCAAwLCyACQfAAaiACQZQBaigCACIBNgIAIAIgAikCjAEiCzcDaCAAQQxqIAE2AgAgACALNwIEIAAgAzYCAAwKCyAAQQ42AgAMCQsgACADOgAEIABBBDYCAAwICyACKQKMASELIAAgAkGUAWopAgA3AgggACALNwIADAcLIABBDjYCAAwGCyAAIAM6AAQgAEEENgIADAULIABBFTYCAAwECyAAQQs2AgAMAwsgAEEONgIADAILIANBCHYLIgE7AAUgACAFNgAMIAAgBjYACCAAIAM6AAQgACAENgIAIABBB2ogAUEQdjoAAAsgAkGgAWokAAvTAQEBfyMAQfAAayIDJAAgAyACNgIMIAMgATYCCCADQRxqQQI2AgAgA0EkakEBNgIAIANBpI3AADYCGCADQQA2AhAgA0EBNgIsIAMgA0EoajYCICADIANBCGo2AiggA0EANgI4IANCgICAgBA3AzAgA0FAayIBIANBMGpBtIfAABD/ASADQRBqIAEQ9QEEQEHMh8AAQTcgA0HoAGpBhIjAAEHgiMAAEPYBAAsgACADKQMwNwIEIABBFDYCACAAQQxqIANBOGooAgA2AgAgA0HwAGokAAu7AgIEfwF+IwBBIGsiAiQAIAIgARCaASACLQABIQMCQAJAAkACQAJAIAItAABBAXEEQCADQSJHDQEgARCUASACQQhqIAEQmQEgAigCCA0CIAJBFGooAgAhASACQRBqKAIAIQMgAigC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QCACQdwBaiACQfwBaigAADYAACACQdgBaiADOgAAIAIgAigA+QE2ANkBIAIgBTYC1AEgAkEBNgLQAQwVCyACIAM6AOQBIAIgBTYC4AEgAkHwAWogAkHgAWpB64TAAEEIIAdBIGooAgAgB0EkaigCABATIAIoAvABBEAgAkHcAWogAkH8AWooAgA2AgAgAiACKQL0ATcC1AEgAkEBNgLQAQwVCyACQfABaiACQeABakHzhMAAQQUgB0EoahAWIAIoAvABBEAgAkHcAWogAkH8AWooAgA2AgAgAiACKQL0ATcC1AEgAkEBNgLQAQwVCyACQdABaiACKALgASACLQDkARCfASACKALQAQ0UIAQoAgghAwwVCyAEKAIIIgMgBCgCAEcNEgwRCyACQdwBaiACQfwBaigCADYCACACIAIpAvQBNwLUAQwSCyACQdwBaiACQfwBaigCADYCACACIAIpAvQBNwLUAQwRCyACQdwBaiACQfwBaigCADYCACACIAIpAvQBNwLUASACQQE2AtABDBALIAJBADoAvAEgAygCACAFRgRAIAMgBRAQIAMoAgghBQsgAygCBCAFakEiOgAAIAMgBUEBaiIFNgIIIAMoAgAgBWtBA00EQCADIAVBBBARIAMoAgghBQsgAygCBCAFakH23tGrBjYAACADIAVBBGoiBTYCCCADKAIAIAVrQQFNBEAgAyAFQQIQESADKAIIIQULIAMoAgQgBWpBovQAOwAAIAMgBUECajYCCAJAAkACQAJAAkAgDkEBaw4DAQIDAAsgAkHwAWogA0GohsAAQQMQowEMAwsgAkHwAWogA0GmhsAAQQIQowEMAgsgAkHwAWogA0GfhsAAQQcQowEMAQsgAkHwAWogA0GThsAAQQwQowELIAIoAvABBEAgAkHsAWogAkH8AWooAgA2AgAgAiACKQL0ATcC5AEMAQsgAkHgAWogA0EAEJ8BIAIoAuABDQAgBCgCCCIDIAQoAgBGDQ0MDgsgAkHcAWogAkHsAWooAgA2AgAgAiACKQLkATcC1AEgAkEBNgLQAQwOCyACQeABaiACKALAASACLQDEARCfAQwECyACIAM2ArgBIAdBLGooAgAhESAHQShqKAIAIQ4CQCAFBEAgAygCCCEFDAELIAMoAggiCiADKAIARgRAIAMgChAQIAMoAgghCgsgAyAKQQFqIgU2AgggAygCBCAKakEsOgAACyACQQA6ALwBIAMoAgAgBUYEQCADIAUQECADKAIIIQULIAMoAgQgBWpBIjoAACADIAVBAWoiBTYCCCADKAIAIAVrQQRNBEAgAyAFQQUQESADKAIIIQULIAMoAgQgBWoiCkHRhcAAKAAANgAAIApBBGpB1YXAAC0AADoAACADIAVBBWoiBTYCCCADKAIAIAVrQQFNBEAgAyAFQQIQESADKAIIIQULIAMoAgQgBWpBovQAOwAAIAMgBUECajYCCAJAIA5FBEAgAkHwAWogAxCiAQwBCyACQfABaiADIA4gERCdAQsCQAJAAkACQCACKALwAUUEQCACQfABaiACQbgBakH2hcAAQQcgB0HYAGopAwAQFSACKALwAQ0BIAJB8AFqIAJBuAFqQeiFwABBAyAHQTBqEBYgAigC8AENAiACQfABaiACQbgBakGtgsAAQQUgB0FAaygCACAHQcQAaigCABAPIAIoAvABDQMgAkHwAWogAkG4AWpB/YXAAEEFIAdBzABqKAIAIAdB0ABqKAIAEBMgAigC8AENBCACQeABaiACKAK4ASACLQC8ARCfAQwICyACQcgBaiAIQQhqKAIAIgM2AgAgAiAIKQIAIhI3A8ABIAZBCGogAzYCACAGIBI3AgAMBAsgBiAIKQIANwIAIAZBCGogCEEIaigCADYCAAwDCyAGIAgpAgA3AgAgBkEIaiAIQQhqKAIANgIADAILIAYgCCkCADcCACAGQQhqIAhBCGooAgA2AgAMAQsgBiAIKQIANwIAIAZBCGogCEEIaigCADYCAAsgAkEBNgLgAQwCCyACQeABaiACKALAASACLQDEARCfAQwBCyACQeABaiACKALAASACLQDEARCfAQsgAigC4AENACAEKAIIIgMgBCgCAEYNBgwHCyACQdwBaiAGQQhqKAIANgIAIAJBATYC0AEgAiAGKQIANwLUAQwHCyACKAK4ASEDAkAgAi0AvAEEQCADKAIIIQUMAQsgAygCCCIKIAMoAgBGBEAgAyAKEBAgAygCCCEKCyADIApBAWoiBTYCCCADKAIEIApqQSw6AAALIAJBADoAvAEgAygCACAFRgRAIAMgBRAQIAMoAgghBQsgAygCBCAFakEiOgAAIAMgBUEBaiIFNgIIIAMoAgAgBWtBBU0EQCADIAVBBhAR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KALwAQ0GIAJB8AFqIAJBwAFqIARBBGsoAgAgBCgCABAmIAIoAvABBEAgAkHsAWogAkH8AWooAgA2AgAgAiACKQL0ATcC5AEMCQsgAkHgAWogAigCwAEgAi0AxAEQnAEgAigC4AENCCAEQRhqIQRBASEDIA1BGGsiDQ0AC0EABSADC0H/AXFBAEcQngEgAigC0AENByAFKAIIIgQgBSgCAEYEQCAFIAQQECAFKAIIIQQLIAUoAgQgBGpBLDoAACAFIARBAWoiBDYCCCACQQA6AEwgBSgCACAERgRAIAUgBBAQIAUoAgghBAsgBSgCBCAEakEiOgAAIAUgBEEBaiIENgIIIAUoAgAgBGtBA00EQCAFIARBBBARIAUoAgghBAsgBSgCBCAEakHkwtGLBjYAACAFIARBBGoiBDYCCCAFKAIAIARrQQFNBEAgBSAEQQIQESAFKAIIIQQLIAUoAgQgBGpBovQAOwAAIAUgBEECajYCCCABKAIEDQEgAkHwAWogBRCiAQwCCyACQewBaiACQfwBaigAADYAACACQegBaiADOgAAIAIgAigA+QE2AOkBIAIgBzYC5AEMBQsgAkHgAWogARB3IAJB8AFqIAUgAigC5AEiASACKALoARCdASACKALgAUUNACABELcBCyACKALwAQRAIAJBxABqIAJB/AFqKAIANgIAIAIgAikC9AE3AjwMCQsgAkE4aiAFQQAQnAEgAigCOA0IIAIoAhAiBCACKAIIRgRAIAJBCGogBBAQIAIoAhAhBAsgAigCDCAEakH9ADoAACACIARBAWo2AhALIAJB6AFqIAJBEGooAgAiATYCACACIAIpAwgiEjcD4AEgAEEMaiABNgIAIAAgEjcCBCAAQQ02AgAMCQsgAkHsAWogAkH8AWooAgA2AgAgAiACKQL0ATcC5AEMAQsgAkHcAWogAkH8AWooAgA2AgAgAiACKQL0ATcC1AEMAQsgAkHcAWogAkHsAWooAgA2AgAgAiACKQLkATcC1AELIAJBxABqIAJB3AFqKAIANgIAIAIgAikC1AE3AjwMAwsgAkHsAGogAkH8AWooAgA2AgAgAiACKQL0ATcCZAwBCyACQewAaiACQYwBaigCADYCACACIAIpAoQBNwJkCyACQcQAaiACQewAaigCADYCACACIAIpAmQ3AjwLIAJBJGogAkHEAGoo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HEUNBAsgBigCABC3AQwDCyABQRxqKAIABEAgAUEgaigCABC3AQsgAUEoaigCAEUNAiABQSxqKAIAELcBDAILAn8CQAJAAkAgAw4CAQIACyABQRxqKAIARQ0EIAFBIGoMAgsgAUEcaigCAARAIAFBIGooAgAQtwELIAFBKGooAgAEQCABQSxqKAIAELcBCyABQfAAaigCAEUNAyABQfQAagwBCyABQRxqKAIABEAgAUEgaigCABC3AQsgAUEoaigCAEUNAiABQSxqCygCABC3AQwBCwJAAkACQAJAAkAgAUEgaigCAA4EAQIDBAALIAFBJGooAgBFDQQgAUEoaigCABC3AQwECyABQSRqKAIABEAgAUEoaigCABC3AQsgAUEwaigCAARAIAFBNGooAgAQtwELIAFBQGshBiABQcQAaigCACIDBEAgA0EFdCEDIAYoAgBBFGohAgNAIAJBBGsoAgAEQCACKAIAELcBCyACQSBqIQIgA0EgayIDDQALCyABKAI8RQ0DIAYoAgAQtwEMAwsCQCABQShqKAIAIgNFDQAgAUEkaigCAEUNACADELcBCyABQTBqKAIABEAgAUE0aigCABC3AQsgAUFAayEGIAFBxABqKAIAIgMEQCADQQV0IQMgBigCAEEUaiECA0AgAkEEaygCAARAIAIoAgAQtwELIAJBIGohAiADQSBrIgMNAAsLIAEoAjwEQCAGKAIAELcBCyABQcgAaigCAEUNAiABQcwAaigCABC3AQwCCyABQSRqKAIABEAgAUEoaigCABC3AQsgAUEwaigCAEUNASABQTRqKAIAELcBDAELIAFBJGooAgAEQCABQShqKAIAELcBCyABQTBqKAIARQ0AIAFBNGooAgAQtwELIAQgBUcNAAsLIAAoAgwEQCAAQRBqKAIAELcBCyAAQSBqKAIAIgQEQCAAQRxqKAIAIgIgBEEYbGohBANAIAIoAgAEQCACQQRqKAIAELcBCyACQQxqKAIABEAgAkEQaigCABC3AQsgAkEYaiICIARHDQALCyAAKAIYBEAgAEEcaigCABC3AQsgAEEsaigCACIEBEAgAEEoaigCACIFIARBGGxqIQEDQCAFKAIABEAgBUEEaigCABC3AQsgBUEQaiEDIAVBFGooAgAiBARAIAMoAgAiAiAEQRhsaiEEA0AgAigCAARAIAJBBGooAgAQtwELIAJBDGooAgAEQCACQRBqKAIAELcBCyACQRhqIgIgBEcNAAsLIAUoAgwEQCADKAIAELcBCyAFQRhqIgQhBSABIARHDQALCyAAKAIkBEAgAEEoaigCABC3AQsgAEEEaigCACIERQ0BIAAoAgBFDQEgBBC3AQ8LIAAoAgBFDQAgAEEEaigCABC3AQsLAwABCzUBAX8gACgCACAAKAIEKAIAEQUAIAAoAgQiAUEEaigCAARAIAFBCGooAgAaIAAoAgAQtwELCxUAIAAoAgAEQCAAQQRqKAIAELcBCwuTAgACQAJ/AkACQAJAAkACQAJAAkACQAJAAkAgACgCAA4MCwsBAgsDBAUGBwgJAAsgAEEUaigCAEUNCiAAQRhqDAkLIAAoAgRFDQkgAEEIagwICyAAKAIERQ0IIABBCGoMBwsgACgCBEUNByAAQQhqDAYLIAAoAgRFDQYgAEEIagwFCyAAKAIERQ0FIABBCGoMBAsgACgCBARAIABBCGooAgAQtwELIAAoAhBFDQQgAEEUagwDCyAAKAIEBEAgAEEIaigCABC3AQsgACgCEEUNAyAAQRRqDAILIAAoAgQEQCAAQQhqKAIAELcBCyAAQRBqKAIARQ0CIABBFGoMAQsgACgCBEUNASAAQQhqCygCABC3AQsLpgEBBn8jAEEgayIDJAACfyACRQRAQQAhAUEADAELIAFBBGooAgAoAgwhBSABKAIAIQZBACEBA0AgA0EIaiAGIAURAQBBASADKAIMIgdFDQEaIAMoAhghBCADKAIUIAMoAggEQCAHELcBC0EBIARFDQEaIAFBAWohAQRAIAQQtwELIAEgAkcNAAsgAiEBQQALIQIgACABNgIEIAAgAjYCACADQSBqJAALmgEBBH8jAEEgayIDJAACfyACRQRAQQAhAUEADAELIAFBBGooAgAoAgwhBCABKAIAIQVBACEBA0AgA0EIaiAFIAQRAQBBASADKAIMIgZFDQEaIAMoAhQEQCADKAIYELcBCyABQQFqIQEgAygCCARAIAYQtwELIAEgAkcNAAsgAiEBQQALIQIgACABNgIEIAAgAjYCACADQSBqJAALngIBB38jAEFAaiIDJAACQCACRQ0AIAFBBGooAgAoAgwhBiABKAIAIQcDQCADQQhqIAcgBhEBACADKAIMIghFBEBBASEEDAILIAMoAhghBSADKAIUIAMoAggEQCAIELcBCyAFRQRAQQEhBAwCCwRAIAUQtwELIAJBAWsiAg0ACwsCQCAERQRAIANBCGogASgCACABQQRqKAIAKAIMEQEAIAMoAgwiAUUEQCAAQQA2AgQMAgsgAygCCCADQThqIANBGGopAwA3AwAgA0EoaiIEIANBPGooAgA2AgAgAyADKQMQNwMwIAMgAykCNDcDIARAIAEQtwELIAAgAykDIDcCACAAQQhqIAQoAgA2AgAMAQsgAEEANgIECyADQUBrJAAL3AEBBX8jAEEgayIDJAACQCACRQ0AIAFBBGooAgAoAgwhBCABKAIAIQUDQCADQQhqIAUgBBEBACADKAIMIgZFBEBBASEHDAILIAMoAhQEQCADKAIYELcBCyADKAIIBEAgBhC3AQsgAkEBayICDQALCwJAIAdFBEAgA0EIaiABKAIAIAFBBGooAgAoAgwRAQAgAygCDEUEQCAAQQA2AgQMAgsgAygCFARAIAMoAhgQtwELIAAgAykDCDcCACAAQQhqIANBEGooAgA2AgAMAQsgAEEANgIECyADQSBqJAALDgAgACgCACABEDsaQQALzgIBAn8jAEEQayICJAACQAJ/AkACQCABQYABTwRAIAJBADYCDCABQYAQSQ0BIAFBgIAETw0CIAIgAUE/cUGAAXI6AA4gAiABQQx2QeABcjoADCACIAFBBnZBP3FBgAFyOgANQQMMAwsgACgCCCIDIAAoAgBGBEAgACADEBAgACgCCCEDCyAAIANBAWo2AgggACgCBCADaiABOgAADAMLIAIgAUE/cUGAAXI6AA0gAiABQQZ2QcABcjoADEECDAELIAIgAUE/cUGAAXI6AA8gAiABQQZ2QT9xQYABcjoADiACIAFBDHZBP3FBgAFyOgANIAIgAUESdkEHcUHwAXI6AAxBBAshASABIAAoAgAgACgCCCIDa0sEQCAAIAMgARARIAAoAgghAwsgACgCBCADaiACQQxqIAEQlwIaIAAgASADajYCCAsgAkEQaiQAQQALWgEBfyMAQSBrIgIkACACIAAoAgA2AgQgAkEYaiABQRBqKQIANwMAIAJBEGogAUEIaikCADcDACACIAEpAgA3AwggAkEEakGEjMAAIAJBCGoQ7AEgAkEgaiQAC0cBAX8gAiAAKAIAIgAoAgAgACgCCCIDa0sEQCAAIAMgAhARIAAoAgghAwsgACgCBCADaiABIAIQlwIaIAAgAiADajYCCEEAC/gFAQV/IwBBkAFrIgIkACACQQhqIAFBDGopAgA3AwAgAkEQaiABQRRqKQIANwMAIAJBGGogAUEcaikCADcDACACQSBqIAFBJGopAgA3AwAgAkEoaiABQSxqKQIANwMAIAIgASkCBDcDAAJAAkAgASgCAEUEQCAAIAFBBGoiASkCADcCACAAQShqIAFBKGopAgA3AgAgAEEgaiABQSBqKQIANwIAIABBGGogAUEYaikCADcCACAAQRBqIAFBEGopAgA3AgAgAEEIaiABQQhqKQIANwIADAELIAJByABqIAJBHGopAgA3AwAgAkFAayACQRRqKQIANwMAIAJBOGogAkEMaikCADcDACACIAIpAgQ3AzAgAkEANgJYIAJCgICAgBA3A1AgAkHgAGoiBCACQdAAakG0h8AAEP8BIwBBMGsiASQAAkACQAJAAkBBACACQTBqIgMoAgAiBUEMayIGIAUgBkkbQQFrDgIBAgALIAFBDGpBATYCACABQRRqQQE2AgAgAUHkj8AANgIIIAFBADYCACABQQQ2AhwgASADNgIsIAEgAUEYajYCECABIAFBLGo2AhgMAgsgAUEMakEBNgIAIAFBFGpBADYCACABQdyPwAA2AgggAUGcjMAANgIQIAFBADYCAAwBCyABQSRqQQU2AgAgAUEMakEDNgIAIAFBFGpBAjYCACABIANBBGo2AiggAUGcj8AANgIIIAFBADYCACABQQU2AhwgASADQRBqNgIsIAEgAUEYajYCECABIAFBLGo2AiAgASABQShqNgIYCyAEIAEQhAIgAUEwaiQADQEgACACKQNQNwIAIABBADYCECAAQQhqIAJB2ABqKAIANgIAAkACQEEAIAIoAjAiAEEMayIBIAAgAUkbDgIBAgALIAIoAjQEQCACQThqKAIAELcBCyACKAJARQ0BIAJBxABqKAIAELcBDAELIAJBMGoQNQsgAkGQAWokAA8LQcyHwABBNyACQYgBakGEiMAAQeCIwAAQ9gEAC0IBAX8gAiAAKAIAIAAoAggiA2tLBEAgACADIAIQESAAKAIIIQMLIAAoAgQgA2ogASACEJcCGiAAIAIgA2o2AghBAAurAQEBfwJAIAIEQAJ/AkACQAJAIAFBAE4EQCADKAIIRQ0CIAMoAgQiBA0BIAENAyACDAQLIABBCGpBADYCAAwFCyADKAIAIAQgAiABEEsMAgsgAQ0AIAIMAQsgASACEEoLIgMEQCAAIAM2AgQgAEEIaiABNgIAIABBADYCAA8LIAAgATYCBCAAQQhqIAI2AgAMAQsgACABNgIEIABBCGpBADYCAAsgAEEBNgIAC/cBAQF/IwBBgAFrIgQkACAEIAI2AgwgBCABNgIIIARBHGpBAjYCACAEQSRqQQI2AgAgBEE0akEDNgIAIARByI3AADYCGCAEQQA2AhAgBEEBNgIsIARBATYCPCAEIAM2AjggBCAEQShqNgIgIAQgBEE4ajYCMCAEIARBCGo2AiggBEEANgJIIARCgICAgBA3A0AgBEHQAGoiASAEQUBrQbSHwAAQ/wEgBEEQaiABEPUBBEBBzIfAAEE3IARB+ABqQYSIwABB4IjAABD2AQALIAAgBCkDQDcCBCAAQRQ2AgAgAEEMaiAEQcgAaigCADYCACAEQYABaiQAC58CAgN/AX4jAEEgayICJAAgAiABEJoBIAItAAEhAwJAAkACQCACLQAAQQFxBEAgA0EiRw0BIAEQlAEgAkEIaiABEJkBIAIoAggNAiACQRRqKAIAIQEgAkEQaigCACEDIAIoAgxFBEACQCABQQpGBEAgA0GYkMAAQQoQmQJFDQELIAAgAyABQaSQwAAQQQwFCyAAQRU2AgAMBAsCQAJAIAJBGGooAgAiBEEKRgRAIAFBmJDAAEEKEJkCRQ0BCyAAIAEgBEGkkMAAEEEMAQsgAEEVNgIACyADRQ0DIAEQtwEMAwsgACADOgAEIABBBDYCAAwCCyAAQQ42AgAMAQsgAikCDCEFIAAgAkEUaikCADcCCCAAIAU3AgALIAJBIGokAAufAgIDfwF+IwBBIGsiAiQAIAIgARCaASACLQABIQMCQAJAAkAgAi0AAEEBcQRAIANBIkcNASABEJQBIAJBCGogARCZASACKAIIDQIgAkEUaigCACEBIAJBEGooAgAhAyACKAIMRQRAAkAgAUEJRgRAIANB7I/AAEEJEJkCRQ0BCyAAIAMgAUH4j8AAEEEMBQsgAEEVNgIADAQLAkACQCACQRhqKAIAIgRBCUYEQCABQeyPwABBCRCZAkUNAQsgACABIARB+I/AABBBDAELIABBFTYCAAsgA0UNAyABELcBDAMLIAAgAzoABCAAQQQ2AgAMAgsgAEEONgIADAELIAIpAgwhBSAAIAJBFGopAgA3AgggACAFNwIACyACQSBqJAALnwICA38BfiMAQSBrIgIkACACIAEQmgEgAi0AASEDAkACQAJAIAItAABBAXEEQCADQSJHDQEgARCUASACQQhqIAEQmQEgAigCCA0CIAJBFGooAgAhASACQRBqKAIAIQMgAigCDEUEQAJAIAFBD0YEQCADQYCQwABBDxCZAkUNAQsgACADIAFBkJDAABBBDAULIABBFTYCAAwECwJAAkAgAkEYaigCACIEQQ9GBEAgAUGAkMAAQQ8QmQJFDQELIAAgASAEQZCQwAAQQQwBCyAAQRU2AgALIANFDQMgARC3AQwDCyAAIAM6AAQgAEEENgIADAILIABBDjYCAAwBCyACKQIMIQUgACACQRRqKQIANwIIIAAgBTcCAAsgAkEgaiQAC9wCAgJ/A34jAEFAaiIDJAAgA0EgaiABIAJBDGooAgAQKwJAAkAgAygCICIEQQ1GBEAgAygCJEEBaiIERQ0BIANBIGogBBAoIAMoAiAiBEENRgRAIAMoAiQgAUGjjsAAQQYgA0EoaigCACIBIANBLGooAgAgAigCHBEHAARAIAEQtwELIABBDzYCAAwDCyADQRBqIANBOGopAwAiBTcDACADIAMpAzAiBjcDCCADKQIkIQcgAygCLCEBIABBGGogBTcDACAAIAY3AxAgACABNgIMIAAgBzcCBCAAIAQ2AgAMAgsgA0EQaiADQTBqKQMAIgU3AwAgA0EYaiADQThqKQMAIgY3AwAgAyADKQMoIgc3AwggAygCJCEBIABBGGogBjcDACAAQRBqIAU3AwAgACAHNwMIIAAgATYCBCAAIAQ2AgAMAQtBgIDAAEEcQbiOwAAQ5wEACyADQUBrJAALxB8CD38DfiMAQaADayIDJAAQuQEgA0HgAGogABCMASADQfAAaiABEIwBIANBgAFqIAIQjAEgA0G4AmogAygCZCIPIAMoAmgQIQJAAkACQAJAAkACQAJAAkACQAJAAkACQCADKALYAkECRwRAIANBqAFqIANBwAJqKQMANwMAIANBmAFqIANB2AJqKQMANwMAIAMgAykDuAI3A6ABIAMgAykD0AI3A5ABIAMoAsgCIQUgAygCzAIhCCADKALgAiEJIAMoAuQCIQYgAykD6AIhEiADQbABaiADKAJ0IhAgAygCeBAaIAMoArABQQ1HDQIgA0HIAWooAgAhBCADQcQBaigCACEKIANBwAFqKAIAIQcgA0G8AWooAgAhDSADQbgBaigCACELIAMoArQBIQwgA0EwaiIAIAMoAoQBIhEgAygCiAEQkwEgA0EoaiAAEJoBQQQhASADLQApIQAgAy0AKEEBcUUNBSAAQf8BcUH7AEYNAUEOIQEMBQsgA0HIAWogA0HQAmopAwA3AwAgA0HAAWogA0HIAmopAwA3AwAgA0G4AWogA0HAAmopAwA3AwAgAyADKQO4AjcDsAEgA0EANgLYASADQoCAgIAQNwPQASADQeABaiIAIANB0AFqQbSHwAAQ/wEgA0GwAWogABCKAQ0LIANBOGogA0HYAWooAgA2AgAgAyADKQPQATcDMCADQQA2AkAgA0GwAWoQNQwJCyADQTBqIgAQlAEgA0EgaiAAEJIBIAMtACQgA0EYaiADKAIgIgIQmgFBAiEBIAMtABkhACADLQAYQQFxRQ0CQQFxIQECQAJAIABB/wFxIg5BLEcEQCAOQf0ARg0CIAENAUEJIQEMBQsgAQ0DIAIQlAEgA0EQaiACEJoBQQQhASADLQARIQAgAy0AEEEBcUUNBAsgAEH/AXEiAEH9AEcEQCAAQSJHDQMgA0EIaiACEJoBQQQhASADLQAJIQAgAy0ACEEBcUUNBEEOIQEgAEH/AXFBIkcNBCACEJQBIANBuAJqIAIQmQECQCADKAK4AkUEQCADQcQCaigCACEAIANBwAJqKAIAIQEgAygCvAJFBEAgA0HgAWogASAAQZyMwABBABAsDAILIANB4AFqIAAgA0HIAmooAgBBnIzAAEEAECwgAUUNASAAELcBDAELIAMgAykCvAI3A+ABIAMgA0HEAmopAgA3A+gBCyADIAMpAOUBNwPQASADIANB7AFqKAAANgDXASADKALgASIBQRVGDQEgAy0A5AEhAAwEC0ETIQEMAwsgA0G4AmogA0EwahCXASADKAK4AiIBQRVHBEAgAyADKQC9AjcDqAIgAyADQcQCaigAADYArwIgAy0AvAIhAAwECyADQbgCaiADQTBqEJUBIAMoArgCIgFBFUYNBSADIAMpAL0CNwOYAiADIANBxAJqKAAANgCfAiADLQC8AiEADAQLIANB+AFqIANByAFqKQMANwMAIANB8AFqIANBwAFqKQMANwMAIANB6AFqIANBuAFqKQMANwMAIAMgAykDsAE3A+ABIANBADYC2AEgA0KAgICAEDcD0AEgA0G4AmoiACADQdABakG0h8AAEP8BIANB4AFqIAAQigENCSADQThqIANB2AFqKAIANgIAIAMgAykD0AE3AzAgA0EANgJAIANB4AFqEDUMBgtBECEBCyADIAMoANcBNgCvAiADIAMpA9ABNwOoAgsgAyADKACvAjYAnwIgAyADKQOoAjcDmAILIANBxAJqIAMoAJ8CNgAAIAMgADoAvAIgAyABNgK4AiADIAMpA5gCNwC9AiADQbABakGOicAAQSIgA0G4AmoQICADKAKwAUENRw0BCyADQfACaiADQagBaikDADcDACADQfwCaiAINgIAIANB+AJqIAU2AgAgA0GAA2ogAykDkAE3AwAgA0GIA2ogA0GYAWopAwA3AwAgA0GYA2ogEjcDACADQZQDaiAGNgIAIANBkANqIAk2AgAgA0H4gcAANgLMAiADQcyBwAA2AsQCIANBqIHAADYCvAIgAyADKQOgATcD6AIgAyADQagCaiIANgLIAiADIAA2AsACIAMgADYCuAIgA0HkAmogBDYCACADQeACaiAKNgIAIANB3AJqIAc2AgAgA0HYAmogDTYCACADQdQCaiALNgIAIAMgDDYC0AIgA0HgAWoiDSEBIANB6AJqIQogA0HQAmohAkEAIQcjAEGgAWsiACQAIANBuAJqIgQoAgQhCyAEKAIAIQwCQAJAAkACQAJAAkACQAJAQRhBARBKIgUEQCAFQRBqQdiOwAApAAA3AAAgBUEIakHQjsAAKQAANwAAIAVByI7AACkAADcAAEEFQQEQSiIIRQ0BIAhBBGpB5I7AAC0AADoAACAIQeCOwAAoAAA2AAAgAEHoAGoiBBCgASAAQZABaiAEEKUBIAAoApABDQIgACAAKAKUATYCiAEgACAAQZgBai0AADoAjAEgAEGQAWogAEGIAWpBk4LAAEEIIAVBGBATIAAoApABDQMgAEGQAWogAEGIAWpBnYfAAEEHIAhBBRATIAAoApABBEAgAEGEAWogAEGcAWooAgA2AgAgACAAKQKUATcCfAwGCyAAQfgAaiAAKAKIASAALQCMARCcASAAKAJ4RQ0EDAULQRhBARDcAQALQQVBARDcAQALIABBhAFqIABBnAFqKAAANgAAIABBgAFqIABBmAFqLQAAOgAAIAAgACgAmQE2AIEBIAAgACgClAE2AnwMAgsgAEGEAWogAEGcAWooAgA2AgAgACAAKQKUATcCfAwBCyAAQTRqIABB8ABqKAIANgIAIAAgACkDaDcCLAwBCyAAQeAAaiIEIABBhAFqKAIANgIAIAAgACkCfDcDWCAAKAJoBEAgACgCbBC3AQsgAEGYAWogBCgCADYCACAAIAApA1g3A5ABIABBKGpBsInAAEEUIABBkAFqECcgACgCKCIJQQ1HDQELIAAoAiwhBkENIQkgDEGkh8AAQQ0gAEEwaigCACIEIABBNGooAgAgCygCHBEHACAGRQ0BIAQQtwEMAQsgAEEgaiAAQUBrKQMANwMAIAAgACkDODcDGCAAKAI0IQYgACgCMCEEIAAoAiwhBwsgBRC3ASAIELcBAkACQAJAAkACQCAJQQ1GBEAgAEEoakEAECggACgCKCIEQQ1HDQEgACgCLCAMQaOOwABBBiAAQTBqKAIAIgUgAEE0aigCACALKAIcEQcABEAgBRC3AQsgAEHUAGpBADYCACAAQcQAakIENwIAIABBPGpCADcCACAAQoCAgIDAADcCTCAAQoCAgICAATcCNCAAQQA2AixBBkEBEEoiCEUNAiAIQQRqQemOwAAvAAA7AAAgCEHljsAAKAAANgAAQQtBARBKIglFDQMgCUEHakHyhcAAKAAANgAAIAlB64XAACkAADcAACMAQSBrIgQkACAAQUBrIgUoAgAiBkEBdCIHQQEgB0EBSxsiB0EEIAdBBEsbIgdBGGwhCyAHQdaq1SpJQQJ0IQwCQCAGBEAgBCAGQRhsNgIUIARBBDYCGCAEIAVBBGooAgA2AhAMAQsgBEEANgIYCyAEIAsgDCAEQRBqEEAgBCgCBCEGAkAgBCgCAEUEQCAFIAc2AgAgBSAGNgIEDAELIARBCGooAgAiB0GBgICAeEYNACAHBEAgBiAHENwBAAsQ3QEACyAEQSBqJAAgAEHIAGoiBiAGKAIAIgRBAWo2AgAgASAAKQMoNwIEIAFBDGogAEEwaikDADcCACABQRRqIABBOGopAwA3AgAgAUEcaiAFKQMANwIAIAFBLGogAEHQAGopAwA3AgAgACgCRCAEQRhsaiIEQQs2AhQgBCAJNgIQIARChoCAgLABNwIIIAQgCDYCBCAEQQY2AgAgAUEkaiAGKQMANwIAIAFBADYCACACKAIABEAgAkEEaigCABC3AQsgAkEQaigCACEFIAJBFGooAgAiAQRAIAFBBXQhBCAFQRRqIQEDQCABQQRrKAIABEAgASgCABC3AQsgAUEgaiEBIARBIGsiBA0ACwsgAigCDARAIAUQtwELIAooAhBFDQUgCkEUaigCABC3AQwFCyAAQRBqIABBIGopAwAiEjcDACAAIAApAxgiEzcDCCABQSBqIBI3AgAgAUEYaiATNwIAIAFBFGogBjYCACABQRBqIAQ2AgAgAUEMaiAHNgIAIAEgCTYCCAwDCyAAQZgBaiAAQUBrKQMAIhI3AwAgACAAKQM4IhM3A5ABIAApAiwhFCAAKAI0IQUgAUEgaiASNwMAIAFBGGogEzcDACABQRRqIAU2AgAgAUEMaiAUNwIAIAEgBDYCCAwCC0EGQQEQ3AEAC0ELQQEQ3AEACyABQQE2AgAgAigCAARAIAJBBGooAgAQtwELIAJBEGooAgAhBSACQRRqKAIAIgEEQCABQQV0IQQgBUEUaiEBA0AgAUEEaygCAARAIAEoAgAQtwELIAFBIGohASAEQSBrIgQNAAsLIAIoAgwEQCAFELcBCyAKKAIQRQ0AIApBFGooAgAQtwELIAooAigEQCAKQSxqKAIAELcBCyAAQaABaiQAIANBMGogDRA+IAMoAoABBEAgERC3AQsgAygCcARAIBAQtwELIAMoAmBFDQMgDxC3AQwDCyADQfgBaiADQcgBaikDADcDACADQfABaiADQcABaikDADcDACADQegBaiADQbgBaikDADcDACADIAMpA7ABNwPgASADQQA2AtgBIANCgICAgBA3A9ABIANBuAJqIgAgA0HQAWpBtIfAABD/ASADQeABaiAAEIoBRQRAIANBOGogA0HYAWooAgA2AgAgAyADKQPQATcDMCADQQA2AkAgA0HgAWoQNSAMBEAgCxC3AQsgBARAIARBBXQhASAKQRRqIQADQCAAQQRrKAIABEAgACgCABC3AQsgAEEgaiEAIAFBIGsiAQ0ACwsgB0UNASAKELcBDAELDAMLIAUEQCAIELcBCyAJRQ0AIAYQtwELIAMoAoABBEAgAygChAEQtwELIAMoAnAEQCADKAJ0ELcBCyADKAJgRQ0AIA8QtwELIANB4AFqIANBMGoQJCADKALgAUENRgRAIANBuAFqIANB7AFqKAIAIgA2AgAgAyADKQLkASISNwOwASADQcACaiAANgIAIAMgEjcDuAIgA0G4AmoQiwEgA0EwahAxIANBoANqJAAPCyADQdACaiADQfgBaikDADcDACADQcgCaiADQfABaikDADcDACADQcACaiADQegBaikDADcDACADIAMpA+ABNwO4AkH4gsAAQSsgA0G4AmpBpIPAAEGghMAAEPYBAAtBzIfAAEE3IANBqAJqQYSIwABB4IjAABD2AQALwBYCEH8DfiMAQZADayIDJAAQuQEgA0HoAGogABCMASADQfgAaiABEIwBIANBiAFqIAIQjAEgA0GgAmogAygCbCIJIAMoAnAQIQJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkAgAygCwAJBAkcEQCADQbABaiADQagCaikDADcDACADQaABaiADQcACaikDADcDACADIAMpA6ACNwOoASADIAMpA7gCNwOYASADKAKwAiEHIAMoArQCIQogAygCyAIhCyADKALMAiEMIAMpA9ACIRQgA0G4AWogAygCfCIQIAMoAoABEBogAygCuAFBDUcNBSADQdABaigCACEFIANBzAFqKAIAIQYgA0HIAWooAgAhDSADQcQBaigCACERIANBwAFqKAIAIQ4gAygCvAEhDyADQThqIgAgAygCjAEiEiADKAKQARCTASADQTBqIAAQmgEgAy0AMSEAIAMtADBBAXFFDQEgAEEiRg0CIABB+wBGDQNBCiEBDAgLIANB0AFqIANBuAJqKQMANwMAIANByAFqIANBsAJqKQMANwMAIANBwAFqIANBqAJqKQMANwMAIAMgAykDoAI3A7gBIANBADYC4AEgA0KAgICAEDcD2AEgA0HoAWoiACADQdgBakG0h8AAEP8BIANBuAFqIAAQigENDSADQUBrIANB4AFqKAIANgIAIAMgAykD2AE3AzggA0EANgJIIANBuAFqEDUMCwsgACEEQQQhAQwGCyADQaACaiADQThqEEMgAygCoAIiAUEVRw0BQQ4hAQwFCyADQThqIgQQlAEgA0GgAmogBBBDIAMoAqACIgFBFUcNACADQaACaiAEEJgBIAMoAqACIgFB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EP8BIANB6AFqIAAQigFFBEAgA0FAayADQeABaigCADYCACADIAMpA9gBNwM4IANBADYCSCADQegBahA1IA8EQCAOELcBCyAFBEAgBUEFdCEBIAZBFGohAANAIABBBGsoAgAEQCAAKAIAELcBCyAAQSBqIQAgAUEgayIBDQALCyANRQ0BIAYQtwEMAQsMAwsgBwRAIAoQtwELIAtFDQAgDBC3AQsgAygCiAEEQCADKAKMARC3AQsgAygCeARAIAMoAnwQtwELIAMoAmhFDQAgCRC3AQsgA0HoAWogA0E4ahAkIAMoAugBQQ1GBEAgA0HAAWogA0H0AWooAgAiADYCACADIAMpAuwBIhM3A7gBIANBqAJqIAA2AgAgAyATNwOgAiADQaACahCLASADQThqEDEgA0GQA2okAA8LIANBuAJqIANBgAJqKQMANwMAIANBsAJqIANB+AFqKQMANwMAIANBqAJqIANB8AFqKQMANwMAIAMgAykD6AE3A6ACQfiCwABBKyADQaACakGkg8AAQZCEwAAQ9gEAC0HMh8AAQTcgA0GIA2pBhIjAAEHgiMAAEPYBAAvODgIKfwF+IwBBoAJrIgIkABC5ASACQegAaiAAEIwBIAJB+ABqIAEQjAEgAkG4AWogAigCbCIJIAIoAnAQIQJAAkACQAJAAkACQAJAAkAgAigC2AFBAkcEQCACKALkASEKIAIoAuABIQYgAigCzAEhByACKALIASEIIAJB8AFqIgAgAigCfCILIAIoAoABEJMBIAJBMGogABCaASACLQAxIQACQAJAAkAgAi0AMEEBcQRAIABBIkYNASAAQfsARg0CQQohAQwHCyAAIQNBBCEBDAYLIAJBuAFqIAJB8AFqEEQgAigCuAEiAUEVRw0BQQ4hAQwFCyACQfABaiIDEJQBIAJBuAFqIAMQRCACKAK4ASIBQRVHDQAgAkG4AWogAxCYASACKAK4ASIBQRVHDQAgAkEoaiADEJoBQQQhASACLQApIQAgAi0AKEEBcUUNAyAAQfsARwRAQQ4hAQwECyADEJQBIAJBIGogAxCSASACLQAkIAJBGGogAigCICIEEJoBIAItABkhACACLQAYQQFxRQRAQQIhAQwEC0EBcSEFAkACQCAAQSxHBEAgAEH9AEYNAiAFDQFBCSEBDAYLIAUNBCAEEJQBIAJBEGogBBCaASACLQARIQAgAi0AEEEBcUUNBQsCQAJAIABB/QBHBEAgAEEiRw0GIAJBCGogBBCaASACLQAJIQAgAi0ACEEBcUUNB0EOIQEgAEEiRw0HIAQQlAEgAkG4AWogBBCZASACKAK4AQ0BIAJBxAFqKAIAIQAgAkHAAWooAgAhASACKAK8AUUEQCACQThqIAEgAEGcjMAAQQAQLAwDCyACQThqIAAgAkHIAWooAgBBnIzAAEEAECwgAUUNAiAAELcBDAILQRMhAQwGCyACIAIpArwBNwM4IAIgAkHEAWopAgA3A0ALIAIoAjgiAUEVRg0AIAIvAD0gAi0AP0EQdHIhAyACKQNAIQwgAi0APCEADAQLIAJBuAFqIAMQlwEgAigCuAEiAUEVRwRAIAIvAL0BIAItAL8BQRB0ciEDIAIpA8ABIQwgAi0AvAEhAAwECyACIAMQmgEgAi0AASEAAkAgAi0AAEEBcQRAIABB/QBGDQFBCyEBDAYLIAAhA0EEIQEMBQsgAxCUASACQbgBaiACQfABahCVASACKAK4ASIBQRVGDQULIAIpA8ABIQwgAigCvAEhAwwDCyACQaABaiACQdABaikDADcDACACQZgBaiACQcgBaikDADcDACACQZABaiACQcABaikDADcDACACIAIpA7gBNwOIASACQQA2ArABIAJCgICAgBA3A6gBIAJB8AFqIgAgAkGoAWpBtIfAABD/ASACQYgBaiAAEIoBRQRAIAJBQGsgAkGwAWooAgA2AgAgAiACKQOoATcDOCACQQA2AkggAkGIAWoQNQwGCwwHC0EQIQELIANBCHQgAHIhAwsgAiAMNwPAASACIAM2ArwBIAIgATYCuAEgAkGIAWpBgIrAAEEbIAJBuAFqECAgAigCiAFBDUcNAQsgAkE4aiACQZgCakGogcAAEEUCQAJAIAIoAjgiAEEPRgRAIAJB6AFqQQA2AgAgAkHgAWpCgICAgMAANwMAIAJB2AFqQgQ3AwAgAkHQAWpCADcDACACQcgBakKAgICAgAE3AwAgAkHAAWpBADYCACACQQA2ArgBIAgEQCAHELcBCyAGDQEMAgsgAkHEAWogAikCPDcCACACQdwBaiACQdQAaigCADYCACACQdQBaiACQcwAaikCADcCACACQcwBaiACQcQAaikCADcCACACIAA2AsABIAJBATYCuAEgCARAIAcQtwELIAZFDQELIAoQtwELIAJBOGogAkG4AWoQPiACKAJ4BEAgCxC3AQsgAigCaEUNAiAJELcBDAILIAJBiAJqIAJBoAFqKQMANwMAIAJBgAJqIAJBmAFqKQMANwMAIAJB+AFqIAJBkAFqKQMANwMAIAIgAikDiAE3A/ABIAJBADYCsAEgAkKAgICAEDcDqAEgAkG4AWoiACACQagBakG0h8AAEP8BIAJB8AFqIAAQigFFBEAgAkFAayACQbABaigCADYCACACIAIpA6gBNwM4IAJBADYCSCACQfABahA1IAgEQCAHELcBCyAGRQ0BIAoQtwEMAQsMAgsgAigCeARAIAIoAnwQtwELIAIoAmhFDQAgCRC3AQsgAkHwAWogAkE4ahAkIAIoAvABQQ1GBEAgAkGQAWogAkH8AWooAgAiADYCACACIAIpAvQBIgw3A4gBIAJBwAFqIAA2AgAgAiAMNwO4ASACQbgBahCLASACQThqEDEgAkGgAmokAA8LIAJB0AFqIAJBiAJqKQMANwMAIAJByAFqIAJBgAJqKQMANwMAIAJBwAFqIAJB+AFqKQMANwMAIAIgAikD8AE3A7gBQfiCwABBKyACQbgBakGkg8AAQbCEwAAQ9gEAC0HMh8AAQTcgAkGYAmpBhIjAAEHgiMAAEPYBAAu7FwIKfwN+IwBBwAJrIgIkABC5ASACQdAAaiAAEIwBIAJBmAJqIAEQjAEgAkHIAWogAigCVCIHIAIoAlgQIQJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkAgAigC6AFBAkcEQCACQfgAaiACQdABaikDADcDACACQegAaiACQegBaikDADcDACACIAIpA8gBNwNwIAIgAikD4AE3A2AgAigC2AEhBSACKALcASEIIAIoAvABIQkgAigC9AEhCiACKQP4ASENIAJBQGsiACACKAKcAiILIAIoAqACEJMBIAJBOGogABCaASACLQA5IQACQAJAAkAgAi0AOEEBcQRAIABBIkYNASAAQfsARg0CQQohAQwHCyAAIQNBBCEBDAYLIAJByAFqIAJBQGsQQiACKALIASIBQRVHDQFBDiEBDAULIAJBQGsiAxCUASACQcgBaiADEEIgAigCyAEiAUEVRw0AIAJByAFqIAMQmAEgAigCyAEiAUEVRw0AIAJBMGogAxCaAUEEIQEgAi0AMSEAIAItADBBAXFFDQMgAEH7AEcEQEEOIQEMBAsgAxCUASACQShqIAMQkgEgAi0ALCACQSBqIAIoAigiBBCaASACLQAhIQAgAi0AIEEBcUUEQEECIQEMBAtBAXEhBgJAAkAgAEEsRwRAIABB/QBGDQIgBg0BQQkhAQwGCyAGDQQgBBCUASACQRhqIAQQmgEgAi0AGSEAIAItABhBAXFFDQULAkACQCAAQf0ARwRAIABBIkcNBiACQRBqIAQQmgEgAi0AESEAIAItABBBAXFFDQdBDiEBIABBIkcNByAEEJQBIAJByAFqIAQQmQEgAigCyAENASACQdQBaigCACEAIAJB0AFqKAIAIQEgAigCzAFFBEAgAkGgAWogASAAQZyMwABBABAsDAMLIAJBoAFqIAAgAkHYAWooAgBBnIzAAEEAECwgAUUNAiAAELcBDAILQRMhAQwGCyACIAIpAswBNwOgASACIAJB1AFqKQIANwOoAQsgAigCoAEiAUEVRg0AIAIvAKUBIAItAKcBQRB0ciEDIAIpA6gBIQwgAi0ApAEhAAwECyACQcgBaiADEJcBIAIoAsgBIgFBFUcEQCACLwDNASACLQDPAUEQdHIhAyACKQPQASEMIAItAMwBIQAMBAsgAkEIaiADEJoBIAItAAkhAAJAIAItAAhBAXEEQCAAQf0ARg0BQQshAQwGCyAAIQNBBCEBDAULIAMQlAEgAkHIAWogAkFAaxCVASACKALIASIBQRVGDQULIAIpA9ABIQwgAigCzAEhAwwDCyACQZgBaiACQeABaikDADcDACACQZABaiACQdgBaikDADcDACACQYgBaiACQdABaikDADcDACACIAIpA8gBNwOAASACQQA2ArACIAJCgICAgBA3A6gCIAJBoAFqIgAgAkGoAmpBtIfAABD/ASACQYABaiAAEIoBRQRAIAJBzABqIAJBsAJqKAIANgIAIAIgAikDqAI3AkQgAkEBNgJAIAJBgAFqEDUMCAsMDQtBECEBCyADQQh0IAByIQMLIAIgDDcD0AEgAiADNgLMASACIAE2AsgBIAJBgAFqQeiLwABBHCACQcgBahAgIAIoAoABQQ1HDQELIAJB6AFqIAJB+ABqKQMANwMAIAJB9AFqIAg2AgAgAkHwAWogBTYCACACQfgBaiACKQNgNwMAIAJBgAJqIAJB6ABqKQMANwMAIAJBkAJqIA03AwAgAkGMAmogCjYCACACQYgCaiAJNgIAIAJB+IHAADYC3AEgAkHMgcAANgLUASACQaiBwAA2AswBIAIgAikDcDcD4AEgAiACQbgCaiIANgLYASACIAA2AtABIAIgADYCyAEgAkGAAWohASACQeABaiEDIwBBQGoiACQAIABBIGogAkHIAWoiBCgCACAEKAIEQQxqKAIAECsCQCAAKAIgIgRBDUYEQCAAQSBqIAAoAiQQKAJAIAAoAiBBDUYEQCABIAApAiQ3AgQgAUENNgIAIAFBDGogAEEsaigCADYCAAwBCyABIAApAyA3AwAgAUEYaiAAQThqKQMANwMAIAFBEGogAEEwaikDADcDACABQQhqIABBKGopAwA3AwALIAMoAhBFDQEgA0EUaigCABC3AQwBCyAAQRBqIABBMGopAwAiDDcDACAAQRhqIABBOGopAwAiDTcDACAAIAApAygiDjcDCCAAKAIkIQUgAUEYaiANNwMAIAFBEGogDDcDACABIA43AwggASAFNgIEIAEgBDYCACADKAIQRQ0AIANBFGooAgAQtwELIAMoAigEQCADQSxqKAIAELcBCyAAQUBrJAAgAUEEciEAAkAgAigCgAEiAUENRgRAIAJBzABqIABBCGooAgA2AgAgAkEANgJAIAIgACkCADcCRAwBCyACQawBaiAAQQhqKAIANgIAIAJBuAFqIAJBmAFqKQMANwMAIAIgATYCoAEgAiACKQOQATcDsAEgAiAAKQIANwKkASACQQA2ArACIAJCgICAgBA3A6gCIAJByAFqIgAgAkGoAmpBtIfAABD/ASACQaABaiAAEIoBDQogAkHMAGogAkGwAmooAgA2AgAgAiACKQOoAjcCRCACQQE2AkAgAkGgAWoQNQsgAigCmAIEQCALELcBCyACKAJQBEAgBxC3AQsgAkGoAmoQoAEgAUENRw0EIAIoArACIgAgAigCqAJGBEAgAkGoAmogABAQIAIoArACIQALIAIoAqwCIABqQfsAOgAAIAIgAEEBajYCsAIgAkHIAWogAkGoAmpB2obAAEECEJ0BIAIoAsgBDQIgAigCsAIiACACKAKoAkYEQCACQagCaiAAEBAgAigCsAIhAAsgAigCrAIgAGpBOjoAACACIABBAWo2ArACIAJB8ABqIAJBQGtBBHIQdyACQcgBaiACQagCaiACKAJ0IgAgAigCeBCdASACKAJwBEAgABC3AQsgAigCyAENASACKAKwAiIAIAIoAqgCRgRAIAJBqAJqIAAQECACKAKwAiEACyACKAKsAiAAakH9ADoAACACIABBAWo2ArACDAULIAJBuAFqIAJBmAFqKQMANwMAIAJBsAFqIAJBkAFqKQMANwMAIAJBqAFqIAJBiAFqKQMANwMAIAIgAikDgAE3A6ABIAJBADYCsAIgAkKAgICAEDcDqAIgAkHIAWoiACACQagCakG0h8AAEP8BIAJBoAFqIAAQigENCCACQcwAaiACQbACaigCADYCACACIAIpA6gCNwJEIAJBATYCQCACQaABahA1IAUEQCAIELcBCyAJRQ0CIAoQtwEMAgsgAkGMAWogAkHUAWooAgA2AgAgAiACKQLMATcChAEMBAsgAkGMAWogAkHUAWooAgA2AgAgAiACKQLMATcChAEMAwsgAigCmAIEQCACKAKcAhC3AQsgAigCUARAIAcQtwELIAJBqAJqEKABCyACQYABaiACQagCaiACQcgAaigCACACQcwAaigCABAlIAIoAoABDQELIAJBrAFqIAJBsAJqKAIANgIAIAIgAikDqAI3AqQBDAELIAJBoAJqIgAgAkGMAWooAgA2AgAgAiACKQKEATcDmAIgAigCqAIEQCACKAKsAhC3AQsgAkHQAWogACgCADYCACACIAIpA5gCNwPIASACQaABakGUi8AAQdQAIAJByAFqECcgAigCoAFBDUcNAQsgAkHYAGogAkGsAWooAgAiADYCACACIAIpAqQBIgw3A1AgAkHQAWogADYCACACIAw3A8gBIAJByAFqEIsBIAIoAkAaIAIoAkQEQCACKAJIELcBCyACQcACaiQADwsgAkHgAWogAkG4AWopAwA3AwAgAkHYAWogAkGwAWopAwA3AwAgAkHQAWogAkGoAWopAwA3AwAgAiACKQOgATcDyAFB+ILAAEErIAJByAFqQaSDwABBwITAABD2AQALQcyHwABBNyACQbgCakGEiMAAQeCIwAAQ9gEACwkAIAAgARCxAQuWBwEGfwJ/AkACQAJAIAJBCU8EQCADIAIQsQEiBw0BQQAMBAtBCEEIEL8BIQFBFEEIEL8BIQJBEEEIEL8BIQRBAEEQQQgQvwFBAnRrIgVBgIB8IAQgASACamprQXdxQQNrIgEgASAFSxsgA00NAUEQIANBBGpBEEEIEL8BQQVrIANLG0EIEL8BIQIgABDPASIBIAEQwwEiBRDMASEEAkACQAJAAkACQAJAAkAgARDGAUUEQCACIAVNDQEgBEGwgsEAKAIARg0CIARBrILBACgCAEYNAyAEEMQBDQcgBBDDASIGIAVqIgggAkkNByAIIAJrIQUgBkGAAkkNBCAEELQBDAULIAEQwwEhBCACQYACSQ0GIAQgAmtBgYAISSACQQRqIARNcQ0FIAEoAgAiBSAEakEQaiEGIAJBH2pBgIAEEL8BIQRBACICRQ0GIAIgBWoiASAEIAVrIgBBEGsiAzYCBCABIAMQzAFBBzYCBCABIABBDGsQzAFBADYCBEG0gsEAQbSCwQAoAgAgBCAGa2oiADYCAEHAgsEAQcCCwQAoAgAiAyACIAIgA0sbNgIAQbiCwQBBuILBACgCACICIAAgACACSRs2AgAMCQtBEEEIEL8BIAUgAmsiBEsNBCABIAIQzAEhBSABIAIQxwEgBSAEEMcBIAUgBBCzAQwEC0GogsEAKAIAIAVqIgUgAk0NBCABIAIQzAEhBCABIAIQxwEgBCAFIAJrIgJBAXI2AgRBqILBACACNgIAQbCCwQAgBDYCAAwDC0GkgsEAKAIAIAVqIgUgAkkNAwJAQRBBCBC/ASAFIAJrIgRLBEAgASAFEMcBQQAhBEEAIQUMAQsgASACEMwBIgUgBBDMASEGIAEgAhDHASAFIAQQygEgBiAGKAIEQX5xNgIEC0GsgsEAIAU2AgBBpILBACAENgIADAILIARBDGooAgAiCSAEQQhqKAIAIgRHBEAgBCAJNgIMIAkgBDYCCAwBC0GcgsEAQZyCwQAoAgBBfiAGQQN2d3E2AgALQRBBCBC/ASAFTQRAIAEgAhDMASEEIAEgAhDHASAEIAUQxwEgBCAFELMBDAELIAEgCBDHAQsgAQ0DCyADELIBIgJFDQEgAiAAIAEQwwFBeEF8IAEQxgEbaiIBIAMgASADSRsQlwIgABC3AQwDCyAHIAAgASADIAEgA0kbEJcCGiAAELcBCyAHDAELIAEQxgEaIAEQzgELCw0AQsi14M/KhtvTiX8LOwEBfyMAQRBrIgIkACACIAAoAgA2AgwgAUHss8AAQRFB/bPAAEEHIAJBDGpBlJXAABCHAiACQRBqJAALFwAgAEEEaigCACAAQQhqKAIAIAEQjQILvwEBAX8gACgCACECIwBBEGsiACQAAn8CQAJAAkACQAJAAkACQCACKAIAQQFrDgYBAgMEBQYACyABQYu2wABBCBCDAgwGCyABQdexwABBChCDAgwFCyABQbKswABBERCDAgwECyABQZyswABBFhCDAgwDCyABQfi1wABBExCDAgwCCyABQYiswABBFBCDAgwBCyAAIAJBBGo2AgwgAUHkq8AAQQpB7qvAAEEKIABBDGpB+KvAABCHAgsgAEEQaiQAC8YDAgF+BH8gACgCACEAIAEQhQJFBEAgARCGAkUEQCAAIAEQkAIPCyMAQYABayIEJAAgACkDACECQYABIQAgBEGAAWohBQJAAkADQCAARQRAQQAhAAwDCyAFQQFrQTBBNyACpyIDQQ9xIgZBCkkbIAZqOgAAIAJCEFoEQCAFQQJrIgVBMEE3IANB/wFxIgNBoAFJGyADQQR2ajoAACAAQQJrIQAgAkKAAlQgAkIIiCECRQ0BDAILCyAAQQFrIQALIABBgQFJDQAgAEGAAUHs4sAAEOQBAAsgAUH84sAAQQIgACAEakGAASAAaxD5ASAEQYABaiQADwsjAEGAAWsiBCQAIAApAwAhAkGAASEAIARBgAFqIQUCQAJAA0AgAEUEQEEAIQAMAwsgBUEBa0EwQdcAIAKnIgNBD3EiBkEKSRsgBmo6AAAgAkIQWgRAIAVBAmsiBUEwQdcAIANB/wFxIgNBoAFJGyADQQR2ajoAACAAQQJrIQAgAkKAAlQgAkIIiCECRQ0BDAILCyAAQQFrIQALIABBgQFJDQAgAEGAAUHs4sAAEOQBAAsgAUH84sAAQQIgACAEakGAASAAaxD5ASAEQYABaiQACxwAIAAoAgAiAEEEaigCACAAQQhqKAIAIAEQigILhwEBAX8jAEEQayICJAACfwJAAkACQAJAIAAoAgAiACgCAEEBaw4DAQIDAAsgAUGyrMAAQREQgwIMAwsgAUGcrMAAQRYQgwIMAgsgAUGIrMAAQRQQgwIMAQsgAiAAQQRqNgIMIAFB5KvAAEEKQe6rwABBCiACQQxqQfirwAAQhwILIAJBEGokAAu7AgEDfyAAKAIAIQIgARCFAkUEQCABEIYCRQRAIAIgARDqAQ8LQQAhACMAQYABayIDJAAgAigCACECA0AgACADakH/AGpBMEE3IAJBD3EiBEEKSRsgBGo6AAAgAEEBayEAIAJBD0sgAkEEdiECDQALIABBgAFqIgJBgQFPBEAgAkGAAUHs4sAAEOQBAAsgAUH84sAAQQIgACADakGAAWpBACAAaxD5ASADQYABaiQADwtBACEAIwBBgAFrIgMkACACKAIAIQIDQCAAIANqQf8AakEwQdcAIAJBD3EiBEEKSRsgBGo6AAAgAEEBayEAIAJBD0sgAkEEdiECDQALIABBgAFqIgJBgQFPBEAgAkGAAUHs4sAAEOQBAAsgAUH84sAAQQIgACADakGAAWpBACAAaxD5ASADQYABaiQAC24BAX8jAEEQayICJAAgAiAAKAIAIgA2AgQgAiAAQQhqNgIIIAIgAEEQajYCDCABQZizwABBF0HYsMAAQQsgAkEEakGws8AAQe6wwABBCyACQQhqQbCzwABBwLPAAEEFIAJBDGoQiQIgAkEQaiQACxkAIAAoAgAiACgCACAAQQRqKAIAIAEQigILbgEBfyMAQRBrIgIkACACIAAoAgAiAEEYajYCBCACIAA2AgggAiAAQQxqNgIMIAFB4LLAAEENQe2ywABBCSACQQRqQfiywABBiLPAAEEIIAJBCGpBlJXAAEGQs8AAQQggAkEMahCJAiACQRBqJAALHQAgASAAKAIALQAAQQJ0Qai2wABqKAIAQQMQgwIL+gMBAX8gACgCACECIwBBMGsiACQAAn8CQAJAAkACQAJAAkACQCACKAIAQQFrDgYBAgMEBQYACyAAQRRqQQE2AgAgAEEcakEANgIAIABB8LXAADYCECAAQcyRwAA2AhggAEEANgIIIAEgAEEIahCEAgwGCyAAQRRqQQE2AgAgAEEcakEANgIAIABB3LXAADYCECAAQcyRwAA2AhggAEEANgIIIAEgAEEIahCEAgwFCyAAQRRqQQE2AgAgAEEcakEANgIAIABB3KvAADYCECAAQcyRwAA2AhggAEEANgIIIAEgAEEIahCEAgwECyAAQRRqQQE2AgAgAEEcakEANgIAIABBwKvAADYCECAAQcyRwAA2AhggAEEANgIIIAEgAEEIahCEAgwDCyAAQRRqQQE2AgAgAEEcakEANgIAIABBxLXAADYCECAAQcyRwAA2AhggAEEANgIIIAEgAEEIahCEAgwCCyAAQRRqQQE2AgAgAEEcakEANgIAIABBoKvAADYCECAAQcyRwAA2AhggAEEANgIIIAEgAEEIahCEAgwBCyAAQRRqQQE2AgAgAEEcakEBNgIAIABB4KrAADYCECAAQQA2AgggAEEoNgIkIAAgAkEEajYCLCAAIABBIGo2AhggACAAQSxqNgIgIAEgAEEIahCEAgsgAEEwaiQAC70CAQF/IAAoAgAhAiMAQTBrIgAkAAJ/AkACQAJAAkAgAigCAEEBaw4DAQIDAAsgAEEUakEBNgIAIABBHGpBADYCACAAQdyrwAA2AhAgAEHMkcAANgIYIABBADYCCCABIABBCGoQhAIMAwsgAEEUakEBNgIAIABBHGpBADYCACAAQcCrwAA2AhAgAEHMkcAANgIYIABBADYCCCABIABBCGoQhAIMAgsgAEEUakEBNgIAIABBHGpBADYCACAAQaCrwAA2AhAgAEHMkcAANgIYIABBADYCCCABIABBCGoQhAIMAQsgAEEUakEBNgIAIABBHGpBATYCACAAQeCqwAA2AhAgAEEANgIIIABBKDYCJCAAIAJBBGo2AiwgACAAQSBqNgIYIAAgAEEsajYCICABIABBCGoQhAILIABBMGokAAtsAQF/IwBBMGsiAiQAIAAoAgAhACACQRRqQQI2AgAgAkEcakEBNgIAIAJB3LPAADYCECACQQA2AgggAkEpNgIkIAIgADYCLCACIAJBIGo2AhggAiACQSxqNgIgIAEgAkEIahCEAiACQTBqJAALDAAgACgCACABEOoBC2gBAX8jAEEwayICJAAgAiAAKAIANgIMIAJBHGpBATYCACACQSRqQQE2AgAgAkHEk8AANgIYIAJBADYCECACQSo2AiwgAiACQShqNgIgIAIgAkEMajYCKCABIAJBEGoQhAIgAkEwaiQAC6UBAQF/IwBBQGoiAiQAIAAoAgAhACACQQxqQQM2AgAgAkEUakEDNgIAIAJBLGpBKTYCACACQSRqQSk2AgAgAiAAQRhqNgI0IAIgADYCOCACQciywAA2AgggAkEANgIAIAJBKzYCHCACIABBDGo2AjwgAiACQRhqNgIQIAIgAkE8ajYCKCACIAJBOGo2AiAgAiACQTRqNgIYIAEgAhCEAiACQUBrJAALDAAgACgCACABEJACC1cBAX8jAEEgayICJAAg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NgIYIAEgATYCKCABIAFBB2o2AiAgBCABQQhqEIQCDAILIAFBFGpBATYCACABQRxqQQA2AgAgAUGQxsAANgIQIAFB8MDAADYCGCABQQA2AgggBCABQQhqEIQCDAELIAEgAigCBDYCACABIAItAAE6AAcgAUEUakEDNgIAIAFBHGpBAjYCACABQSxqQdIANgIAIAFBzMXAADYCECABQQA2AgggAUHTADYCJCABIAFBIGo2AhggASABNgIoIAEgAUEHajYCICAEIAFBCGoQhAILIAFBMGokAA0BIAlBEGogCUEgaikDACITNwMAIAkgCSkDGCIUNwMIIAkpAzAhFSAJKAI4IQEgEEEYaiATNwMAIBAgFDcDECAQIAE2AgwgECAVNwIEIBBBAzYCAAsgCUHwAGokAAwCC0GgksAAQTcgCUHoAGpB2JLAAEG0k8AAEPYBAAtBoJHAAEEcQcicwAAQ5wEACwJAIAsoAhBBDUYEQCAAIAspAhQ3AgQgAEEVNgIAIABBDGogC0EcaigCADYCAAwBCyALQSw2AkQgCyALQQhqNgJAIAtBATYCXCALQQE2AlQgC0G8nsAANgJQIAtBADYCSCALIAtBQGs2AlggC0EwaiIBIAtByABqIgIQ3gEgAkEEciABEN8BIAtBFDYCSCALKAIwBEAgCygCNBC3AQsgACALKQNINwIAIABBCGogC0HQAGopAwA3AgAgC0EQahA1CyALQeAAaiQAC4UDAgN/AX4jAEEgayICJAAgAiABEJoBIAItAAEhAwJAAkACQAJAAkACQAJAAkAgAi0AAEEBcQRAIANBIkcNASABEJQBIAJBCGogARCZASACKAIIDQIgAkEUaigCACEBIAJBEGooAgAhAyACKAIMRQRAAkACQCABQQJrDgQACQkBCQsgAy8AAEHv1gFGDQkMCAsgA0GXtcAAQQUQmQINByAAQRU2AgAgAEEBOgAEDAkLAkACQCACQRhqKAIAIgRBAmsOBAAFBQEFCyABLwAAQe/WAUYNBQwECyABQZe1wABBBRCZAg0DIABBFTYCACAAQQE6AAQMBQsgACADOgAEIABBBDYCAAwHCyAAQQ42AgAMBgsgAikCDCEFIAAgAkEUaikCADcCCCAAIAU3AgAMBQsgACABIARBmLbAAEECEG0MAQsgAEEVNgIAIABBADoABAsgA0UNAiAB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IABBATYCACABQTBqEDUMAQsgACABKQMQNwMAIABBGGogAUEoaikDADcDACAAQRBqIAFBIGopAwA3AwAgAEEIaiABQRhqKQMANwMAIBdFDQAgFhC3AQsgFBC3ASABQZABaiQADwtBDEEEENwBAAsgAUEUakEBNgIAIAFBHGpBADYCACABQaSpwAA2AhAgAUHMkcAANgIYIAFBADYCCCABQQhqQYiqwAAQ4gEACyABQRRqQQE2AgAgAUEcakEANgIAIAFBuKrAADYCECABQcyRwAA2AhggAUEANgIIIAFBCGpBwKrAABDiAQALQaCSwABBNyABQYgBakHYksAAQbSTwAAQ9gEAC8wJAQF/IwBBMGsiAiQAAn8CQAJAAkACQAJAAkACQAJAAkACQAJAAkACQCAAKAIAQQFrDgwBAgMEBQYHCAkKCwwACyACQSRqQQE2AgAgAkEsakEBNgIAIAJB6K/AADYCICACQQA2AhggAkEuNgIEIAIgAEEEajYCFCACIAI2AiggAiACQRRqNgIAIAEgAkEYahCEAgwMCyACQSRqQQE2AgAgAkEsakEBNgIAIAJBzK/AADYCICACQQA2AhggAkEvNgIEIAIgAEEEajYCFCACIAI2AiggAiACQRRqNgIAIAEgAkEYahCEAgwLCyACQSRqQQE2AgAgAkEsakEBNgIAIAJBrK/AADYCICACQQA2AhggAkEpNgIEIAIgAEEEajYCFCACIAI2AiggAiACQRRqNgIAIAEgAkEYahCEAgwKCyACQSRqQQE2AgAgAkEsakEBNgIAIAJBlK/AADYCICACQQA2AhggAkEpNgIEIAIgAEEEajYCFCACIAI2AiggAiACQRRqNgIAIAEgAkEYahCEAgwJCyACQQxqQTA2AgAgAkEkakECNgIAIAJBLGpBAjYCACACIABBCGo2AhAgAkHsrsAANgIgIAJBADYCGCACQTA2AgQgAiAAQRBqNgIUIAIgAjYCKCACIAJBFGo2AgggAiACQRBqNgIAIAEgAkEYahCEAgwICyACQSRqQQE2AgAgAkEsakEBNgIAIAJBwK7AADYCICACQQA2AhggAkEpNgIEIAIgAEEEajYCFCACIAI2AiggAiACQRRqNgIAIAEgAkEYahCEAgwHCyACQSRqQQE2AgAgAkEsakEBNgIAIAJBpK7AADYCICACQQA2AhggAkEpNgIEIAIgAEEEajYCFCACIAI2AiggAiACQRRqNgIAIAEgAkEYahCEAgwGCyACQSRqQQI2AgAgAkEsakEBNgIAIAJB7K3AADYCICACQQA2AhggAkEpNgIEIAIgAEEEajYCFCACIAI2AiggAiACQRRqNgIAIAEgAkEYahCEAgwFCyACQQxqQSk2AgAgAkEkakECNgIAIAJBLGpBAjYCACACIABBBGo2AhAgAkHQrcAANgIgIAJBADYCGCACQSk2AgQgAiAAQRBqNgIUIAIgAjYCKCACIAJBFGo2AgggAiACQRBqNgIAIAEgAkEYahCEAgwECyACQQxqQSk2AgAgAkEkakECNgIAIAJBLGpBAjYCACACIABBBGo2AhAgAkGorcAANgIgIAJBADYCGCACQSk2AgQgAiAAQRBqNgIUIAIgAjYCKCACIAJBFGo2AgggAiACQRBqNgIAIAEgAkEYahCEAgwDCyACQSRqQQE2AgAgAkEsakEBNgIAIAJBhK3AADYCICACQQA2AhggAkExNgIEIAIgAEEEajYCFCACIAI2AiggAiACQRRqNgIAIAEgAkEYahCEAgwCCyACQSRqQQE2AgAgAkEsakEBNgIAIAJB8KzAADYCICACQQA2AhggAkEyNgIEIAIgAEEEajYCFCACIAI2AiggAiACQRRqNgIAIAEgAkEYahCEAgwBCyACQSRqQQE2AgAgAkEsakEANgIAIAJB2KzAADYCICACQcyRwAA2AiggAkEANgIYIAEgAkEYahCEAgsgAkEwaiQAC0MBAn8gAEEIaigCACEBIABBBGooAgAhAkEMQQQQSiIARQRAQQxBBBDcAQALIAAgATYCCCAAIAE2AgQgACACNgIAIAALvwEBAn8jAEEgayICJAACQCABBEAgASgCACIDDQEgAkEUakEBNgIAIAJBHGpBADYCACACQbiqwAA2AhAgAkHMkcAANgIYIAJBADYCCCACQQhqQcCqwAAQ4gEACyACQRRqQQE2AgAgAkEcakEANgIAIAJBpKnAADYCECACQcyRwAA2AhggAkEANgIIIAJBCGpBiKrAABDiAQALIAAgAzYCBCAAIAEoAgg2AgggACABKAIENgIAIAEQtwEgAkEgaiQAC7kFAQF/IwBBEGsiAiQAAn8CQAJAAkACQAJAAkACQAJAAkACQAJAAkACQCAAKAIAQQFrDgwBAgMEBQYHCAkKCwwACyACIABBBGo2AgwgAUGEssAAQQ9BgrDAAEEGIAJBDGpBlLLAABCHAgwMCyACIABBBGo2AgwgAUHhscAAQRBBgrDAAEEGIAJBDGpB9LHAABCHAgwLCyACIABBBGo2AgwgAUHXscAAQQpB47DAAEEDIAJBDGpBlJXAABCHAgwKCyACIABBBGo2AgwgAUHKscAAQQ1B47DAAEEDIAJBDGpBlJXAABCHAgwJCyACIABBCGo2AgggAiAAQRBqNgIMIAFBmrHAAEEPQamxwABBCCACQQhqQbSxwABBxLHAAEEGIAJBDGpBtLHAABCIAgwICyACIABBBGo2AgwgAUGQscAAQQpB47DAAEEDIAJBDGpBlJXAABCHAgwHCyACIABBBGo2AgwgAUGFscAAQQtB47DAAEEDIAJBDGpBlJXAABCHAgwGCyACIABBBGo2AgwgAUH5sMAAQQhBgbHAAEEEIAJBDGpBlJXAABCHAgwFCyACIABBBGo2AgggAiAAQRBqNgIMIAFB5rDAAEEIQe6wwABBCyACQQhqQZSVwABB47DAAEEDIAJBDGpBlJXAABCIAgwECyACIABBBGo2AgggAiAAQRBqNgIMIAFBzLDAAEEMQdiwwABBCyACQQhqQZSVwABB47DAAEEDIAJBDGpBlJXAABCIAgwDCyACIABBBGo2AgwgAUG0sMAAQQhBgrDAAEEGIAJBDGpBvLDAABCHAgwCCyACIABBBGo2AgwgAUGYsMAAQQxBgrDAAEEGIAJBDGpBpLDAABCHAgwBCyACIABBBGo2AgwgAUHwr8AAQRJBgrDAAEEGIAJBDGpBiLDAABCHAgsgAkEQaiQACx8AIAAoAgAoAgAiAEEEaigCACAAQQhqKAIAIAEQjQILzwEBA38jAEEgayICJAACQAJAIAFBAWoiA0UNACAAKAIAIgFBAXQiBCADIAMgBEkbIgNBCCADQQhLGyIDQX9zQR92IQQCQCABBEAgAiAAQQRqKAIANgIQIAIgATYCFCACIAFBf3NBH3Y2AhgMAQsgAkEANgIYCyACIAMgBCACQRBqEEAgAigCBCEBIAIoAgBFBEAgACADNgIAIAAgATYCBAwCCyACQQhqKAIAIgBBgYCAgHhGDQEgAEUNACABIAAQ3AEACxDdAQALIAJBIGokAAvRAQECfyMAQSBrIgMkAAJAAkAgASACaiICIAFJDQAgACgCACIBQQF0IgQgAiACIARJGyICQQggAkEISxsiAkF/c0EfdiEEAkAgAQRAIAMgAEEEaigCADYCECADIAE2AhQgAyABQX9zQR92NgIYDAELIANBADYCGAsgAyACIAQgA0EQahBAIAMoAgQhASADKAIARQRAIAAgAjYCACAAIAE2AgQMAgsgA0EIaigCACIAQYGAgIB4Rg0BIABFDQAgASAAENwBAAsQ3QEACyADQSBqJAAL9wMBAX8jAEEwayICJAACfwJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQCAAKAIAQQFrDhQBAgMEBQYHCAkKCwwNDg8QERITFAALIAJBrrzAADYCKEEiDBQLIAJBlbzAADYCKEEZDBMLIAJB+bvAADYCKEEcDBILIAJB3rvAADYCKEEbDBELIAJBv7vAADYCKEEfDBALIAJBmbvAADYCKEEmDA8LIAJB8brAADYCKEEoDA4LIAJBurrAADYCKEE3DA0LIAJBk7rAADYCKEEnDAwLIAJB27nAADYCKEE4DAsLIAJBo7nAADYCKEE4DAoLIAJB9bjAADYCKEEuDAkLIAJB3bjAADYCKEEYDAgLIAJBzrjAADYCKEEPDAcLIAJBwrjAADYCKEEMDAYLIAJBp7jAADYCKEEbDAULIAJBjLjAADYCKEEbDAQLIAJBvbfAADYCKEHPAAwDCyACQYG3wAA2AihBPAwCCyACQci2wAA2AihBOQwBCyACIABBCGooAgA2AiggAEEMaigCAAshACACQRRqQQE2AgAgAkEcakEBNgIAIAJBzwA2AiQgAiAANgIsIAJBwLbAADYCECACQQA2AgggAiACQShqNgIgIAIgAkEgajYCGCABIAJBCGoQhAIgAkEwaiQACxAAIABBAToABCAAIAE2AgALFwAgAEEANgIIIAAgAjYCBCAAIAE2AgALKQEBfyAAKAIIQQFqIgEEQCAAIAE2AggPC0HQvcAAQRxBuL/AABDnAQALXwEDfyAAAn8gASgCCCIAIAEoAgQiAkkEQCABKAIAIQMDQEESIAAgA2otAABBCWsiBEEXS0EBIAR0QZOAgARxRXINAhogASAAQQFqIgA2AgggACACRw0ACwtBFQs2AgALwgIBBX8CQAJAAkAC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akHcADoAACAEQQFqDAcLIAEoAgAgBEYEQCABIAQQjwEgASgCCCEECyABKAIEIARqQdwAOgAAIAEgBEEBaiIENgIIIAEoAgAgBEYEQCABIAQQjwEgASgCCCEECyABKAIEIARqQSI6AAAgBEEBagwGCyABKAIAIARGBEAgASAEEI8BIAEoAgghBAsgASgCBCAEakHcADoAACABIARBAWoiBDYCCCABKAIAIARGBEAgASAEEI8BIAEoAgghBAsgASgCBCAEakHiADoAACAEQQFqDAULIAEoAgAgBEYEQCABIAQQjwEgASgCCCEECyABKAIEIARqQdwAOgAAIAEgBEEBaiIENgIIIAEoAgAgBEYEQCABIAQQjwEgASgCCCEECyABKAIEIARqQfQAOgAAIARBAWoMBAsgASgCACAERgRAIAEgBBCPASABKAIIIQQLIAEoAgQgBGpB3AA6AAAgASAEQQFqIgQ2AgggASgCACAERgRAIAEgBBCPASABKAIIIQQLIAEoAgQgBGpB7gA6AAAgBEEBagwDCyABKAIAIARGBEAgASAEEI8BIAEoAgghBAsgASgCBCAEakHcADoAACABIARBAWoiBDYCCCABKAIAIARGBEAgASAEEI8BIAEoAgghBAsgASgCBCAEakHmADoAACAEQQFqDAILIAEoAgAgBEYEQCABIAQQjwEgASgCCCEECyABKAIEIARqQdwAOgAAIAEgBEEBaiIENgIIIAEoAgAgBEYEQCABIAQQjwEgASgCCCEECyABKAIEIARqQfIAOgAAIARBAWoMAQsCfwJAAkACQCAFQSBPBEAgBUGAAUkNASAFQYAQSQ0CIAVBgIAETw0DIAYgBUE/cUGAAXI6AA4gBiAFQQx2QeABcjoADCAGIAVBBnZBP3FBgAFyOgANQQMMBAsgASgCACAERgRAIAEgBBCPASABKAIIIQQLIAEoAgQgBGpB3AA6AAAgASAEQQFqIgQ2AgggASgCACAERgRAIAEgBBCPASABKAIIIQQLIAEoAgQgBGpB9QA6AAAgASAEQQFqIgQ2AgggASgCACAERgRAIAEgBBCPASABKAIIIQQLIAEoAgQgBGpBMDoAACABIARBAWoiBDYCCCABKAIAIARGBEAgASAEEI8BIAEoAgghBAsgASgCBCAEakEwOgAAIAEgBEEBaiIENgIIIAVBD3EiA0EKSSEHIAEoAgAgBEYEQCABIAQQjwEgASgCCCEECyABKAIEIARqIAVB8AFxQQR2QTByOgAAIAEgBEEBaiIENgIIIAEoAgAgBEYEQCABIAQQjwEgASgCCCEECyABKAIEIARqIANBMHIgA0E3aiAHGzoAACAEQQFqDAQLIAEoAgAgBEYEQCABIAQQjwEgASgCCCEECyABKAIEIARqIAU6AAAgBEEBagwDCyAGIAVBP3FBgAFyOgANIAYgBUEGdkHAAXI6AAxBAgwBCyAGIAVBP3FBgAFyOgAPIAYgBUESdkHwAXI6AAwgBiAFQQZ2QT9xQYABcjoADiAGIAVBDHZBP3FBgAFyOgANQQQLIQUgBSABKAIAIARrSwRAIAEgBCAFEJABIAEoAgghBAsgASgCBCAEaiAGQQxqIAUQlwIaIAQgBWoLIgQ2AgggAiAIRw0ACwsgASgCACAERgRAIAEgBBCPASABKAIIIQQLIABBADYCACABIARBAWo2AgggASgCBCAEakEiOgAAIAZBEGokAAs/ACABKAIIIgIgASgCAEYEQCABIAIQjwEgASgCCCECCyAAQQA2AgAgASACQQFqNgIIIAEoAgQgAmpB3QA6AAALgAEBAn8gASgCCCICIAEoAgAiBEYEQCABIAIQjwEgASgCACEEIAEoAgghAgsgASACQQFqIgM2AgggAiABKAIEIgJqQf0AOgAAIAMgBEYEQCABIAQQjwEgASgCCCEDIAEoAgQhAgsgAEEANgIAIAEgA0EBajYCCCACIANqQf0AOgAACzABAX9BgAhBARBKIgFFBEBBgAhBARDcAQALIABBADYCCCAAIAE2AgQgAEGACDYCAAv4AQIEfwF+IwBBIGsiBCQAIARBF2pBADYAACAEQRBqQgA3AwAgBEIANwMIIAQgAkIKgqdBMHI6ABtBEyEDAkACQCACQgpaBEADQCADRQ0CIANBAWsiAyAEQQhqaiACQgqAIgdCCoKnQTByOgAAIAJC5ABUIAchAkUNAAsgA0EVTw0CC0EUIANrIgYgASgCACABKAIIIgVrSwRAIAEgBSAGEJABIAEoAgghBQsgASgCBCAFaiAEQQhqIANqIAYQlwIaIABBADYCACABIAUgBmo2AgggBEEgaiQADwtBgL7AAEEhQeDAwAAQ5wEACyADQRRB4MDAABDkAQALSQEBfyABKAIAIAEoAggiAmtBA00EQCABIAJBBBCQASABKAIIIQILIABBADYCACABIAJBBGo2AgggASgCBCACakHu6rHjBjYAAAsNACAAIAEgAiADEJ0BC1IBAX8gASgCCCICIAEoAgBGBEAgASACEI8BIAEoAgghAgsgACABNgIEIABBADYCACABIAJBAWo2AgggAEEIakEBOgAAIAEoAgQgAmpB2wA6AAALUgEBfyABKAIIIgIgASgCAEYEQCABIAIQjwEgASgCCCECCyAAIAE2AgQgAEEANgIAIAEgAkEBajYCCCAAQQhqQQE6AAAgASgCBCACakH7ADoAAAueAgICfwF+IwBBIGsiBSQAIAEoAggiBCABKAIARgRAIAEgBBCPASABKAIIIQQLIAEgBEEBajYCCCABKAIEIARqQfsAOgAAIAVBEGogASACIAMQnQECQCAFKAIQRQRAIAEoAggiBCABKAIARgRAIAEgBBCPASABKAIIIQQLIAEoAgQgBGpBOjoAACABIARBAWoiBDYCCCABKAIAIARGBEAgASAEEI8BIAEoAgghBAsgACABNgIEIABBADYCACABIARBAWo2AgggAEEIakEBOgAAIAEoAgQgBGpB+wA6AAAMAQsgBUEIaiAFQRxqKAIAIgE2AgAgBSAFKQIUIgY3AwAgAEEMaiABNgIAIAAgBjcCBCAAQQE2AgALIAVBIGokAAsWACAAKAIAIgAoAgAgACgCBCABEI0CCx0AIAEoAgBFBEAACyAAQZzXwAA2AgQgACABNgIAC1UBAn8gASgCACECIAFBADYCAAJAIAIEQCABKAIEIQNBCEEEEEoiAUUNASABIAM2AgQgASACNgIAIABBnNfAADYCBCAAIAE2AgAPCwALQQhBBBDcAQALwAQBA38jAEEwayICJAACfwJAAkACQAJAIAAoAgQiAw4DAAIDAQsjAEEQayIAJAAgAEHc2MAANgIIIABBDjYCBCAAQc3YwAA2AgAjAEEQayIBJAAgAUEIaiAAQQhqKAIANgIAIAEgACkCADcDACMAQRBrIgAkACAAIAEpAgA3AwggAEEIakGI18AAQQAgASgCCEEBEL4BAAsgAkEkakEBNgIAIAJBLGpBADYCACACQbTXwAA2AiAgAkGc18AANgIoIAJBADYCGEEBIAEgAkEYahCEAg0CGiADQQN0IQMgACgCACEAAkADQCACIAA2AhQgBARAIAJBATYCJCACQcDXwAA2AiAgAkEANgIsIAJBnNfAADYCKCACQQA2AhggASACQRhqEIQCDQILIAJBAjYCJCACQcjXwAA2AiAgAkEBNgIsIAJBADYCGCACQdQANgIEIAIgAjYCKCACIAJBFGo2AgAgASACQRhqEIQCDQEgAEEIaiEAIARBAWshBCADQQhrIgMNAAtBAAwDC0EBDAILIAJBJGpBAjYCACACQSxqQQE2AgAgAkHI18AANgIgIAJBADYCGCACQdUANgIEIAIgACgCADYCACACIAI2AiggASACQRhqEIQCDAELIAJBDGpB1QA2AgAgAkEkakEDNgIAIAJBLGpBAjYCACACQeDXwAA2AiAgAkEANgIYIAJB1QA2AgQgAiAAKAIAIgA2AgAgAiAAQQhqNgIIIAIgAjYCKCABIAJBGGoQhAILIAJBMGokAAsMAELr0N2RtuLCvEgLDQBCz8Kptu6ZpbSRfwsLAEHIgsEAKAIARQshAQF/AkAgAEEEaigCACIBRQ0AIAAoAgBFDQAgARC3AQsL0wIBAn8jAEEQayICJAAgACgCACEAAkACfwJAIAFBgAFPBEAgAkEANgIMIAFBgBBPDQEgAiABQT9xQYABcjoADSACIAFBBnZBwAFyOgAMQQIMAgsgACgCCCIDIAAoAgBGBEAgACADEBAgACgCCCEDCyAAIANBAWo2AgggACgCBCADaiABOgAADAILIAFBgIAETwRAIAIgAUE/cUGAAXI6AA8gAiABQQZ2QT9xQYABcjoADiACIAFBDHZBP3FBgAFyOgANIAIgAUESdkEHcUHwAXI6AAxBBAwBCyACIAFBP3FBgAFyOgAOIAIgAUEMdkHgAXI6AAwgAiABQQZ2QT9xQYABcjoADUEDCyEBIAEgACgCACAAKAIIIgNrSwRAIAAgAyABEBEgACgCCCEDCyAAKAIEIANqIAJBDGogARCXAhogACABIANqNgIICyACQRBqJABBAAtaAQF/IwBBIGsiAiQAIAIgACgCADYCBCACQRhqIAFBEGopAgA3AwAgAkEQaiABQQhqKQIANwMAIAIgASkCADcDCCACQQRqQezYwAAgAkEIahDsASACQSBqJAALkwMBBX8CQAJAAkACQCABQQlPBEBBEEEIEL8BIAFLDQEMAgsgABCyASEE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AEEBNgIARQ0BC0GA/8AAKAIAQf////8HcUUNABCtAQ0AQfT+wABBAToAAAtB8P7AAEEANgIAAkAgAkUNACACIAEoAgARBQAgAUEEaigCAEUNACABQQhqKAIAGiACELcBCyAAQSBqJAAPCyAAQRRqQQE2AgAgAEEcakEANgIAIABBwNrAADYCECAAQYTZwAA2AhggAEEANgIIIABBCGpB5NrAABDiAQALAAuLAgIDfwF+IwBBMGsiAiQAIAEoAgRFBEAgASgCDCEDIAJBEGoiBEEANgIAIAJCgICAgBA3AwggAiACQQhqNgIUIAJBKGogA0EQaikCADcDACACQSBqIANBCGopAgA3AwAgAiADKQIANwMYIAJBFGpB7NjAACACQRhqEOwBGiABQQhqIAQoAgA2AgAgASACKQMINwIACyABKQIAIQUgAUKAgICAEDcCACACQSBqIgMgAUEIaiIBKAIANgIAIAFBADYCACACIAU3AxhBDEEEEEoiAUUEQEEMQQQQ3AEACyABIAIpAxg3AgAgAUEIaiADKAIANgIAIABBlNvAADYCBCAAIAE2AgAgAkEwaiQAC6oBAQN/IwBBMGsiAiQAIAEoAgRFBEAgASgCDCEDIAJBEGoiBEEANgIAIAJCgICAgBA3AwggAiACQQhqNgIUIAJBKGogA0EQaikCADcDACACQSBqIANBCGopAgA3AwAgAiADKQIANwMYIAJBFGpB7NjAACACQRhqEOwBGiABQQhqIAQoAgA2AgAgASACKQMINwIACyAAQZTbwAA2AgQgACABNgIAIAJBMGokAAtFAQJ/IAEoAgQhAiABKAIAIQNBCEEEEEoiAUUEQEEIQQQQ3AEACyABIAI2AgQgASADNgIAIABBpNvAADYCBCAAIAE2AgALEwAgAEGk28AANgIEIAAgATYCAAuIAgECfyMAQSBrIgUkAEGA/8AAQYD/wAAoAgAiBkEBajYCAAJAAkAgBkEASA0AQciCwQBByILBACgCAEEBaiIGNgIAIAZBAksNACAFIAQ6ABggBSADNgIUIAUgAjYCECAFQdzbwAA2AgwgBUGE2cAANgIIQfD+wAAoAgAiAkEASA0AQfD+wAAgAkEBaiICNgIAQfD+wABB+P7AACgCAAR/IAUgACABKAIQEQEAIAUgBSkDADcDCEH4/sAAKAIAIAVBCGpB/P7A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AxshAiADIAEgAxshAQsgCkUNAiAAQQxqKAIAIQcCQCACQRBPBEAgASACEIACIQQMAQsgAkUEQEEAIQQMAQsgAkEDcSEFAkAgAkEBa0EDSQRAQQAhBCABIQMMAQsgAkF8cSEGQQAhBCABIQMDQCAEIAMsAABBv39KaiADLAABQb9/SmogAywAAkG/f0pqIAMsAANBv39KaiEEIANBBGohAyAGQQRrIgYNAAsLIAVFDQADQCAEIAMsAABBv39KaiEEIANBAWohAyAFQQFrIgUNAAsLIAQgB0kEQCAHIARrIgQhBgJAAkACQEEAIAAtACAiAyADQQNGG0EDcSIDQQFrDgIAAQILQQAhBiAEIQMMAQsgBEEBdiEDIARBAWpBAXYhBgsgA0EBaiEDIABBBGooAgAhBCAAKAIcIQUgACgCACEAAkADQCADQQFrIgNFDQEgACAFIAQoAhARAABFDQALQQEPC0EBIQMgBUGAgMQARg0CIAAgASACIAQoAgwRAgANAkEAIQMDQCADIAZGBEBBAA8LIANBAWohAyAAIAUgBCgCEBEAAEUNAAsgA0EBayAGSQ8LDAILIAAoAgAgASACIAAoAgQoAgwRAgAhAwsgAw8LIAAoAgAgASACIAAoAgQoAgwRAgALUgEBfyMAQSBrIgMkACADQQxqQQE2AgAgA0EUakEANgIAIANB+N7AADYCECADQQA2AgAgAyABNgIcIAMgADYCGCADIANBGGo2AgggAyACEOIBAAt5AQF/IwBBMGsiAyQAIAMgATYCBCADIAA2AgAgA0EUakECNgIAIANBHGpBAjYCACADQSxqQdIANgIAIANBgOfAADYCECADQQA2AgggA0HSADYCJCADIANBIGo2AhggAyADQQRqNgIoIAMgAzYCICADQQhqIAIQ4gEACyUAIAEgAC0AAEECdCIAQdT+wABqKAIAIABBwP7AAGooAgAQ5gELDAAgADUCACABEJICC74CAQN/IwBBgAFrIgQkAAJAAkACQAJAIAEoAhgiAkEQcUUEQCACQSBxDQEgADUCACABEJICIQAMBAsgACgCACEAQQAhAgNAIAIgBGpB/wBqQTBB1wAgAEEPcSIDQQpJGyADajoAACACQQFrIQIgAEEPSyAAQQR2IQANAAsgAkGAAWoiAEGBAU8NASABQfziwABBAiACIARqQYABakEA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aiIAIARJDQALCyAEIAIgA2siAkF8cSIDaiEAIANBAEoEQCABQf8BcUGBgoQIbCEDA0AgBCADNgIAIARBBGoiBCAASQ0ACwsgAkEDcSECCyACBEAgACACaiECA0AgACABOgAAIABBAWoiACACSQ0ACwsLC6l+BgBBgIDAAAvHE2F0dGVtcHQgdG8gYWRkIHdpdGggb3ZlcmZsb3dJYmNNc2djbG9zZV9jaGFubmVsY2hhbm5lbF9pZHNlbmRfcGFja2V0ZGF0YXRpbWVvdXR0cmFuc2ZlcnRvX2FkZHJlc3NhbW91bnRJYmNUaW1lb3V0YmxvY2t0aW1lc3RhbXBJYmNUaW1lb3V0QmxvY2tyZXZpc2lvbmhlaWdodENvaW5kZW5vbQAAAAYAAAAAAAAAAQAAAAcAAAAIAAAACQAAAAoAAAALAAAADAAAAAYAAAAAAAAAAQAAAA0AAAAOAAAADwAAABAAAAARAAAAEgAAABMAAAAUAAAABgAAAAAAAAABAAAAFQAAAHRyYW5zYWN0aW9uY29udHJhY3R0aW1lY2hhaW5faWRzZW5kZXJmdW5kc2FkZHJlc3NpbmRleAAAFgAAAAgAAAAEAAAAFwAAABgAAAAZAAAAGgAAABYAAAAIAAAABAAAABsAAAAYAAAAHAAAAB0AAABjYWxsZWQgYFJlc3VsdDo6dW53cmFwKClgIG9uIGFuIGBFcnJgIHZhbHVlAB4AAAAgAAAACAAAAB8AAAAvdXNyL2xvY2FsL2NhcmdvL3JlZ2lzdHJ5L3NyYy9naXRodWIuY29tLTFlY2M2Mjk5ZGI5ZWM4MjMvY29zbXdhc20tc3RkLTEuMy4zL3NyYy9leHBvcnRzLnJzALQBEABbAAAAlQAAAA0AAAC0ARAAWwAAAHcAAAANAAAAtAEQAFsAAADFAAAADQAAALQBEABbAAAA8gAAAA0AAABDb3Ntb3NNc2dnb3Z3YXNtaWJjc3RhcmdhdGV0eXBlX3VybHZhbHVlY3VzdG9tYmFua0dvdk1zZ3ZvdGVwcm9wb3NhbF9pZEJhbmtNc2didXJuc2VuZFdhc21Nc2djbGVhcl9hZG1pbmNvbnRyYWN0X2FkZHJ1cGRhdGVfYWRtaW5hZG1pbm1pZ3JhdGVuZXdfY29kZV9pZG1zZ2luc3RhbnRpYXRlY29kZV9pZGxhYmVsZXhlY3V0ZVZvdGVPcHRpb25ub193aXRoX3ZldG9hYnN0YWlubm95ZXNTdWJNc2dpZGdhc19saW1pdFJlcGx5T25uZXZlcnN1Y2Nlc3NlcnJvcmFsd2F5c29rRW1wdHlFdmVudHR5cGVhdHRyaWJ1dGVzQXR0cmlidXRla2V5UmVzcG9uc2VldmVudHNDb250cmFjdFZlcnNpb252ZXJzaW9uY29udHJhY3RfaW5mbwAAACAAAAAMAAAABAAAACEAAAAiAAAAIwAAAGEgRGlzcGxheSBpbXBsZW1lbnRhdGlvbiByZXR1cm5lZCBhbiBlcnJvciB1bmV4cGVjdGVkbHkABgAAAAAAAAABAAAAJAAAAC9ydXN0Yy9kNWE4MmJiZDI2ZTFhZDhiNzQwMWY2YTcxOGE5YzU3Yzk2OTA1NDgzL2xpYnJhcnkvYWxsb2Mvc3JjL3N0cmluZy5ycwAUBBAASwAAAOgJAAAJAAAAY2xvY2tfZXhhbXBsZTo6bXNnOjpFeGVjdXRlTXNnY2xvY2tfZXhhbXBsZTo6bXNnOjpJbnN0YW50aWF0ZU1zZ2N3Mjo6Q29udHJhY3RWZXJzaW9uY29zbXdhc21fc3RkOjp0eXBlczo6TWVzc2FnZUluZm9jbG9ja19leGFtcGxlOjpzdGF0ZTo6Q29uZmlnY2xvY2tfZXhhbXBsZTo6bXNnOjpTdWRvTXNnY29zbXdhc21fc3RkOjp0eXBlczo6RW52Y29zbXdhc21fc3RkOjpyZXN1bHRzOjpjb250cmFjdF9yZXN1bHQ6OkNvbnRyYWN0UmVzdWx0PGNvc213YXNtX3N0ZDo6cmVzdWx0czo6cmVzcG9uc2U6OlJlc3BvbnNlPmNvc213YXNtX3N0ZDo6cmVzdWx0czo6Y29udHJhY3RfcmVzdWx0OjpDb250cmFjdFJlc3VsdDxjb3Ntd2FzbV9zdGQ6OmJpbmFyeTo6QmluYXJ5PmNsb2NrX2V4YW1wbGU6Om1zZzo6UXVlcnlNc2cGAAAABAAAAAQAAAAlAAAAJgAAACcAAABtaXNzaW5nIGZpZWxkIGBgHAYQAA8AAAArBhAAAQAAAHVua25vd24gZmllbGQgYGAsIGV4cGVjdGVkIAA8BhAADwAAAEsGEAAMAAAAYCwgdGhlcmUgYXJlIG5vIGZpZWxkcwAAPAYQAA8AAABoBhAAFgAAAGR1cGxpY2F0ZSBmaWVsZCBgAAAAkAYQABEAAAArBhAAAQAAAHVua25vd24gdmFyaWFudCBgAAAAtAYQABEAAABLBhAADAAAAGludmFsaWQgVWludDY0ICcnIC0g2AYQABAAAADoBhAABAAAAGludmFsaWQgVWludDEyOCAnAAAA/AYQABEAAADoBhAABAAAAHVsbGNvbmZpZ3NyYy9jb250cmFjdC5ycykHEAAPAAAAIgAAAAUAAABjcmF0ZXMuaW86Y3ctaWJjLWV4YW1wbGUwLjEuMG1ldGhvZGludmFsaWQgSUJDIGNoYW5uZWwgdmVyc2lvbi4gR290ICgpLCBleHBlY3RlZCAoKQBrBxAAIgAAAI0HEAANAAAAmgcQAAEAAABvbmx5IHVub3JkZXJlZCBjaGFubmVscyBhcmUgc3VwcG9ydGVkAAAAtAcQACUAAAAcBhAAAAAAAGluY3JlbWVudAAAAOwHEAAJAAAAY2xvY2tfZW5kX2Jsb2NrAAAIEAAPAAAAZ2V0X2NvbmZpZwAAGAgQAAoAAABDb25maWd2YWwAAAAyCBAAAwAAAC9ydXN0Yy9kNWE4MmJiZDI2ZTFhZDhiNzQwMWY2YTcxOGE5YzU3Yzk2OTA1NDgzL2xpYnJhcnkvY29yZS9zcmMvaXRlci9hZGFwdGVycy9lbnVtZXJhdGUucnMAAAAAAGF0dGVtcHQgdG8gYWRkIHdpdGggb3ZlcmZsb3dACBAAWwAAADAAAAAJAAAAAAAAAGF0dGVtcHQgdG8gc3VidHJhY3Qgd2l0aCBvdmVyZmxvdwAAADMAAAAIAAAABAAAADQAAAA1AAAANgAAAAwAAAAEAAAANwAAADgAAAA5AAAAYSBEaXNwbGF5IGltcGxlbWVudGF0aW9uIHJldHVybmVkIGFuIGVycm9yIHVuZXhwZWN0ZWRseQAzAAAAAAAAAAEAAAAkAAAAL3J1c3RjL2Q1YTgyYmJkMjZlMWFkOGI3NDAxZjZhNzE4YTljNTdjOTY5MDU0ODMvbGlicmFyeS9hbGxvYy9zcmMvc3RyaW5nLnJzAGgJEABLAAAA6AkAAAkAAADMCBAAQdCTwAAL8SlhdHRlbXB0IHRvIG11bHRpcGx5IHdpdGggb3ZlcmZsb3djb3Ntd2FzbV9zdGQ6OnJlc3VsdHM6OnN5c3RlbV9yZXN1bHQ6OlN5c3RlbVJlc3VsdDxjb3Ntd2FzbV9zdGQ6OnJlc3VsdHM6OmNvbnRyYWN0X3Jlc3VsdDo6Q29udHJhY3RSZXN1bHQ8Y29zbXdhc21fc3RkOjpiaW5hcnk6OkJpbmFyeT4+AAAAMwAAAAQAAAAEAAAAOgAAADsAAAA8AAAAMwAAAAQAAAAEAAAAPQAAAGludGVybmFsIGVycm9yOiBlbnRlcmVkIHVucmVhY2hhYmxlIGNvZGU6IAAApAoQACoAAAAvcnVzdGMvZDVhODJiYmQyNmUxYWQ4Yjc0MDFmNmE3MThhOWM1N2M5NjkwNTQ4My9saWJyYXJ5L2NvcmUvc3JjL2l0ZXIvdHJhaXRzL2FjY3VtLnJzAAAA2AoQAFUAAACNAAAAAQAAAG1pc3NpbmcgZmllbGQgYGBACxAADwAAAE8LEAABAAAAZHVwbGljYXRlIGZpZWxkIGAAAABgCxAAEQAAAE8LEAABAAAAdW5rbm93biB2YXJpYW50IGBgLCBleHBlY3RlZCAAAACECxAAEQAAAJULEAAMAAAAZGVjb2RlZCBsZW5ndGggY2FsY3VsYXRpb24gb3ZlcmZsb3cvdXNyL2xvY2FsL2NhcmdvL3JlZ2lzdHJ5L3NyYy9naXRodWIuY29tLTFlY2M2Mjk5ZGI5ZWM4MjMvYmFzZTY0LTAuMTMuMS9zcmMvZGVjb2RlLnJz1wsQAFUAAABuAAAAIwAAANcLEABVAAAACgEAADcAAADXCxAAVQAAAAoBAAAkAAAA1wsQAFUAAAALAQAAKQAAANcLEABVAAAAKAEAABEAAADXCxAAVQAAADEBAAApAAAA1wsQAFUAAAAxAQAAFgAAANcLEABVAAAANQEAACkAAADXCxAAVQAAADUBAAAoAAAA1wsQAFUAAAA0AQAAGgAAANcLEABVAAAAOgEAABEAAADXCxAAVQAAAEgBAAAOAAAA1wsQAFUAAABLAQAAJwAAANcLEABVAAAASwEAABIAAADXCxAAVQAAAE4BAAAJAAAA1wsQAFUAAABfAQAAEwAAANcLEABVAAAAbQEAACkAAADXCxAAVQAAAH8BAAANAAAA1wsQAFUAAACJAQAAEQAAANcLEABVAAAAkQEAABUAAADXCxAAVQAAAJUBAAAxAAAASW1wb3NzaWJsZTogbXVzdCBvbmx5IGhhdmUgMCB0byA4IGlucHV0IGJ5dGVzIGluIGxhc3QgY2h1bmssIHdpdGggbm8gaW52YWxpZCBsZW5ndGhzfA0QAFQAAADXCxAAVQAAAKQBAAAOAAAA1wsQAFUAAACvAQAADQAAANcLEABVAAAAuAEAAAkAAABPdmVyZmxvdyB3aGVuIGNhbGN1bGF0aW5nIG91dHB1dCBidWZmZXIgbGVuZ3RoAADXCxAAVQAAAJoAAAAgAAAA1wsQAFUAAAAuAgAABQAAAC91c3IvbG9jYWwvY2FyZ28vcmVnaXN0cnkvc3JjL2dpdGh1Yi5jb20tMWVjYzYyOTlkYjllYzgyMy9iYXNlNjQtMC4xMy4xL3NyYy9lbmNvZGUucnNJbnZhbGlkIFVURjgAAAA+AAAAFAAAAAQAAAA/AAAAWA4QAFUAAAA0AAAABQAAAGludGVnZXIgb3ZlcmZsb3cgd2hlbiBjYWxjdWxhdGluZyBidWZmZXIgc2l6ZQAAAFgOEABVAAAALwAAABEAAAAzAAAACAAAAAQAAABAAAAAaW52YWxpZCBiYXNlNjQ6ICwPEAAQAAAAMwAAAAAAAAABAAAAQQAAAEIAAABCAAAAL3Vzci9sb2NhbC9jYXJnby9yZWdpc3RyeS9zcmMvZ2l0aHViLmNvbS0xZWNjNjI5OWRiOWVjODIzL2Nvc213YXNtLXN0ZC0xLjMuMy9zcmMvc2VjdGlvbnMucnNcDxAAXAAAABoAAAAQAAAAXA8QAFwAAAAaAAAABQAAAFwPEABcAAAAOQAAABgAAABDYW5ub3QgcmVhZCBzZWN0aW9uIGxlbmd0aAAA6A8QABoAAABcDxAAXAAAADcAAAAJAAAAVEw7RFI6IFZhbHVlIG11c3Qgbm90IGJlIGVtcHR5IGluIFN0b3JhZ2U6OnNldCBidXQgaW4gbW9zdCBjYXNlcyB5b3UgY2FuIHVzZSBTdG9yYWdlOjpyZW1vdmUgaW5zdGVhZC4gTG9uZyBzdG9yeTogR2V0dGluZyBlbXB0eSB2YWx1ZXMgZnJvbSBzdG9yYWdlIGlzIG5vdCB3ZWxsIHN1cHBvcnRlZCBhdCB0aGUgbW9tZW50LiBTb21lIG9mIG91ciBpbnRlcm5hbCBpbnRlcmZhY2VzIGNhbm5vdCBkaWZmZXJlbnRpYXRlIGJldHdlZW4gYSBub24tZXhpc3RlbnQga2V5IGFuZCBhbiBlbXB0eSB2YWx1ZS4gUmlnaHQgbm93LCB5b3UgY2Fubm90IHJlbHkgb24gdGhlIGJlaGF2aW91ciBvZiBlbXB0eSB2YWx1ZXMuIFRvIHByb3RlY3QgeW91IGZyb20gdHJvdWJsZSBsYXRlciBvbiwgd2Ugc3RvcCBoZXJlLiBTb3JyeSBmb3IgdGhlIGluY29udmVuaWVuY2UhIFdlIGhpZ2hseSB3ZWxjb21lIHlvdSB0byBjb250cmlidXRlIHRvIENvc21XYXNtLCBtYWtpbmcgdGhpcyBtb3JlIHNvbGlkIG9uZSB3YXkgb3IgdGhlIG90aGVyLhwQEAAIAgAAL3Vzci9sb2NhbC9jYXJnby9yZWdpc3RyeS9zcmMvZ2l0aHViLmNvbS0xZWNjNjI5OWRiOWVjODIzL2Nvc213YXNtLXN0ZC0xLjMuMy9zcmMvaW1wb3J0cy5ycwAsEhAAWwAAAGsAAAANAAAAMwAAAAQAAAAEAAAAQwAAAEQAAABFAAAARgAAAGlucHV0IHRvbyBsb25nIGZvciBhZGRyX3ZhbGlkYXRlYWRkcl92YWxpZGF0ZSBlcnJvcmVkOiAA1BIQABcAAABpbnB1dCB0b28gbG9uZyBmb3IgYWRkcl9jYW5vbmljYWxpemVhZGRyX2Nhbm9uaWNhbGl6ZSBlcnJvcmVkOiAAGBMQABsAAABhZGRyX2h1bWFuaXplIGVycm9yZWQ6IAA8ExAAFwAAAE1lc3NhZ2VUb29Mb25nIG11c3Qgbm90IGhhcHBlbi4gVGhpcyBpcyBhIGJ1ZyBpbiB0aGUgVk0uXBMQADgAAAAsEhAAWwAAAAgBAAASAAAALBIQAFsAAAAlAQAAEgAAAEludmFsaWRIYXNoRm9ybWF0IG11c3Qgbm90IGhhcHBlbi4gVGhpcyBpcyBhIGJ1ZyBpbiB0aGUgVk0uALwTEAA7AAAALBIQAFsAAAA/AQAAEgAAAEVycm9yIGNvZGUgMiB1bnVzZWQgc2luY2UgQ29zbVdhc20gMC4xNS4gVGhpcyBpcyBhIGJ1ZyBpbiB0aGUgVk0uAAAAEBQQAEEAAAAsEhAAWwAAAD4BAAASAAAALBIQAFsAAABfAQAAEgAAACwSEABbAAAAXgEAABIAAABSZWdpb24gcG9pbnRlciBpcyBudWxsAACMFBAAFgAAAC91c3IvbG9jYWwvY2FyZ28vcmVnaXN0cnkvc3JjL2dpdGh1Yi5jb20tMWVjYzYyOTlkYjllYzgyMy9jb3Ntd2FzbS1zdGQtMS4zLjMvc3JjL21lbW9yeS5ycwAArBQQAFoAAAA5AAAABQAAAFJlZ2lvbiBzdGFydHMgYXQgbnVsbCBwb2ludGVyAAAAGBUQAB0AAACsFBAAWgAAAD8AAAAFAAAAVW5rbm93biBlcnJvcjogAFAVEAAPAAAASW52YWxpZCByZWNvdmVyeSBwYXJhbWV0ZXIuIFN1cHBvcnRlZCB2YWx1ZXM6IDAgYW5kIDEuAABoFRAANgAAAEludmFsaWQgc2lnbmF0dXJlIGZvcm1hdKgVEAAYAAAASW52YWxpZCBoYXNoIGZvcm1hdADIFRAAEwAAAFVua25vd25FcnJlcnJvcl9jb2RlMwAAAAQAAAAEAAAARwAAAEludmFsaWRSZWNvdmVyeVBhcmFtSW52YWxpZFNpZ25hdHVyZUZvcm1hdEludmFsaWRIYXNoRm9ybWF0Q29udmVyc2lvbiBlcnJvcjogAAAAQxYQABIAAABEaXZpZGUgYnkgemVybzogYBYQABAAAABPdmVyZmxvdzogAAB4FhAACgAAAEVycm9yIHNlcmlhbGl6aW5nIHR5cGUgOiAAAACMFhAAFwAAAKMWEAACAAAARXJyb3IgcGFyc2luZyBpbnRvIHR5cGUguBYQABgAAACjFhAAAgAAACBub3QgZm91bmQAAMwIEAAAAAAA4BYQAAoAAABDYW5ub3QgZGVjb2RlIFVURjggYnl0ZXMgaW50byBzdHJpbmc6IAAA/BYQACYAAABJbnZhbGlkIGhleCBzdHJpbmc6ICwXEAAUAAAASW52YWxpZCBkYXRhIHNpemU6IGV4cGVjdGVkPSBhY3R1YWw9SBcQABwAAABkFxAACAAAAEludmFsaWQgQmFzZTY0IHN0cmluZzogAHwXEAAXAAAAR2VuZXJpYyBlcnJvcjogAJwXEAAPAAAAUmVjb3ZlciBwdWJrZXkgZXJyb3I6IAAAtBcQABYAAABWZXJpZmljYXRpb24gZXJyb3I6INQXEAAUAAAAQ29udmVyc2lvbk92ZXJmbG93c291cmNlMwAAAAQAAAAEAAAASAAAAERpdmlkZUJ5WmVybzMAAAAEAAAABAAAAEkAAABPdmVyZmxvdzMAAAAEAAAABAAAAEoAAABTZXJpYWxpemVFcnJzb3VyY2VfdHlwZW1zZ1BhcnNlRXJydGFyZ2V0X3R5cGVOb3RGb3VuZGtpbmRJbnZhbGlkVXRmOEludmFsaWRIZXhJbnZhbGlkRGF0YVNpemVleHBlY3RlZAAAADMAAAAEAAAABAAAAEsAAABhY3R1YWxJbnZhbGlkQmFzZTY0R2VuZXJpY0VyclJlY292ZXJQdWJrZXlFcnIAAAAzAAAABAAAAAQAAABMAAAAVmVyaWZpY2F0aW9uRXJyADMAAAAEAAAABAAAAE0AAABTaGxTaHJQb3dNdWxTdWJBZGRDYW5ub3QgIHdpdGggIGFuZCA2GRAABwAAAD0ZEAAGAAAAQxkQAAUAAABPdmVyZmxvd0Vycm9yb3BlcmF0aW9uAAAzAAAABAAAAAQAAAAqAAAAb3BlcmFuZDFvcGVyYW5kMkNvbnZlcnNpb25PdmVyZmxvd0Vycm9yADMAAAAEAAAABAAAAE4AAAB2YWx1ZUNhbm5vdCBkaXZpZGUgIGJ5IHplcm8AxRkQAA4AAADTGRAACAAAAERpdmlkZUJ5WmVyb0Vycm9yb3BlcmFuZGludmFsaWRfcmVxdWVzdGludmFsaWRfcmVzcG9uc2Vub19zdWNoX2NvbnRyYWN0bm9fc3VjaF9jb2RldW5rbm93bnVuc3VwcG9ydGVkX3JlcXVlc3QAAAAEGhAADwAAABMaEAAQAAAAIxoQABAAAAAzGhAADAAAAD8aEAAHAAAARhoQABMAAABjb2RlX2lkYWRkcmVycm9ycmVzcG9uc2VyZXF1ZXN0SW52YWxpZCBwdWJsaWMga2V5IGZvcm1hdKsaEAAZAAAAR2VuZXJpYyBlcnJvcgAAAMwaEAANAAAAQmF0Y2ggZXJyb3IA5BoQAAsAAABJbnZhbGlkUHVia2V5Rm9ybWF0QmF0Y2hFcnJvawAAABMbEAACAAAAlxoQAAUAAAAzGRAAMBkQAC0ZEAAqGRAAJxkQACQZEABAGxAAAAAAAEpTT04gaGFzIGEgY29tbWEgYWZ0ZXIgdGhlIGxhc3QgdmFsdWUgaW4gYW4gYXJyYXkgb3IgbWFwLkpTT04gaGFzIG5vbi13aGl0ZXNwYWNlIHRyYWlsaW5nIGNoYXJhY3RlcnMgYWZ0ZXIgdGhlIHZhbHVlLkZvdW5kIGEgbG9uZSBzdXJyb2dhdGUsIHdoaWNoIGNhbiBleGlzdCBpbiBKU09OIGJ1dCBjYW5ub3QgYmUgZW5jb2RlZCB0byBVVEYtOC5PYmplY3Qga2V5IGlzIG5vdCBhIHN0cmluZy5JbnZhbGlkIHVuaWNvZGUgY29kZSBwb2ludC5JbnZhbGlkIHR5cGVJbnZhbGlkIG51bWJlci5JbnZhbGlkIGVzY2FwZSBzZXF1ZW5jZS5FeHBlY3RlZCB0aGlzIGNoYXJhY3RlciB0byBzdGFydCBhIEpTT04gdmFsdWUuRXhwZWN0ZWQgdG8gcGFyc2UgZWl0aGVyIGEgYHRydWVgLCBgZmFsc2VgLCBvciBhIGBudWxsYC5FeHBlY3RlZCB0aGlzIGNoYXJhY3RlciB0byBiZSBlaXRoZXIgYSBgJywnYCBvciBhIGAnfSdgLkV4cGVjdGVkIGEgbG93IHN1cnJvZ2F0ZSAoREMwMOKAk0RGRkYpLkV4cGVjdGVkIHRoaXMgY2hhcmFjdGVyIHRvIGJlIGVpdGhlciBhIGAnLCdgIG9yYSBgJ10nYC5FeHBlY3RlZCBhIGhpZ2ggc3Vycm9nYXRlIChEODAw4oCTREJGRikuRXhwZWN0ZWQgdGhpcyBjaGFyYWN0ZXIgdG8gYmUgYSBgJzonYC5FT0Ygd2hpbGUgcGFyc2luZyBhIEpTT04gdmFsdWUuRU9GIHdoaWxlIHBhcnNpbmcgYSBzdHJpbmcuRU9GIHdoaWxlIHBhcnNpbmcgYW4gb2JqZWN0LkVPRiB3aGlsZSBwYXJzaW5nIGEgbGlzdC5Db250cm9sIGNoYXJhY3RlciBmb3VuZCBpbiBzdHJpbmcuL3Vzci9sb2NhbC9jYXJnby9yZWdpc3RyeS9zcmMvZ2l0aHViLmNvbS0xZWNjNjI5OWRiOWVjODIzL3NlcmRlLWpzb24td2FzbS0wLjUuMS9zcmMvZGUvdW5lc2NhcGUucnMAAFAeEABiAAAAJQAAABUAQdC9wAAL0QNhdHRlbXB0IHRvIGFkZCB3aXRoIG92ZXJmbG93UB4QAGIAAAAzAAAAKQAAAAAAAABhdHRlbXB0IHRvIHN1YnRyYWN0IHdpdGggb3ZlcmZsb3dOb24taGV4IEFTQ0lJIGNoYXJhY3RlciBmb3VuZAAAIR8QAB0AAABQHhAAYgAAAJkAAAAOAAAAL3Vzci9sb2NhbC9jYXJnby9yZWdpc3RyeS9zcmMvZ2l0aHViLmNvbS0xZWNjNjI5OWRiOWVjODIzL3NlcmRlLWpzb24td2FzbS0wLjUuMS9zcmMvZGUvbW9kLnJzAAAAWB8QAF0AAAAkAAAACQAAAFgfEABdAAAAfQAAACIAAABYHxAAXQAAAIEAAAAsAAAAQnVmZmVyIGlzIGZ1bGwAAOgfEAAOAAAAL3Vzci9sb2NhbC9jYXJnby9yZWdpc3RyeS9zcmMvZ2l0aHViLmNvbS0xZWNjNjI5OWRiOWVjODIzL3NlcmRlLWpzb24td2FzbS0wLjUuMS9zcmMvc2VyL21vZC5ycwAAACAQAF4AAADdAAAACQAAAGludGVybmFsIGVycm9yOiBlbnRlcmVkIHVucmVhY2hhYmxlIGNvZGU6IAAAcCAQACoAQbDBwAAL4CZhdHRlbXB0IHRvIGFkZCB3aXRoIG92ZXJmbG93L3Vzci9sb2NhbC9jYXJnby9yZWdpc3RyeS9zcmMvZ2l0aHViLmNvbS0xZWNjNjI5OWRiOWVjODIzL2Jhc2U2NC0wLjEzLjEvc3JjL2VuY29kZS5ycwAAAMwgEABVAAAAkgAAACcAAAB1c2l6ZSBvdmVyZmxvdyB3aGVuIGNhbGN1bGF0aW5nIGI2NCBsZW5ndGgAAMwgEABVAAAAlwAAABkAAADMIBAAVQAAALYAAAAgAAAAzCAQAFUAAAC3AAAAOgAAAMwgEABVAAAAtwAAACUAAADMIBAAVQAAAPwAAAAvAAAAzCAQAFUAAAD8AAAAHAAAAMwgEABVAAAA/QAAADYAAADMIBAAVQAAAP0AAAAhAAAAzCAQAFUAAAATAQAALgAAAMwgEABVAAAAEwEAAAkAAADMIBAAVQAAABQBAAAJAAAAzCAQAFUAAAALAQAALgAAAMwgEABVAAAACwEAAAkAAADMIBAAVQAAAA0BAAAPAAAAzCAQAFUAAAAMAQAACQAAAMwgEABVAAAADwEAAAkAAADMIBAAVQAAABEBAAAJAAAASW1wb3NzaWJsZSByZW1haW5kZXJwIhAAFAAAAMwgEABVAAAAKgEAABYAAADMIBAAVQAAADsBAAAJAAAASW52YWxpZCBsYXN0IHN5bWJvbCAsIG9mZnNldCAuAACsIhAAFAAAAMAiEAAJAAAAySIQAAEAAABFbmNvZGVkIHRleHQgY2Fubm90IGhhdmUgYSA2LWJpdCByZW1haW5kZXIuAOQiEAArAAAASW52YWxpZCBieXRlIAAAABgjEAANAAAAwCIQAAkAAADJIhAAAQAAAE92ZXJmbG93IHdoZW4gY2FsY3VsYXRpbmcgbnVtYmVyIG9mIGNodW5rcyBpbiBpbnB1dC91c3IvbG9jYWwvY2FyZ28vcmVnaXN0cnkvc3JjL2dpdGh1Yi5jb20tMWVjYzYyOTlkYjllYzgyMy9iYXNlNjQtMC4xMy4xL3NyYy9kZWNvZGUucnNzIxAAVQAAAMAAAAAFAAAAISIjJCUmJygpKissLTAxMjM0NTY3ODlAQUJDREVGR0hJSktMTU5QUVJTVFVWWFlaW2BhYmNkZWhpamtsbXBxckFCQ0RFRkdISUpLTE1OT1BRUlNUVVZXWFlaYWJjZGVmZ2hpamtsbW5vcHFyc3R1dnd4eXowMTIzNDU2Nzg5KywuL0FCQ0RFRkdISUpLTE1OT1BRUlNUVVZXWFlaYWJjZGVmZ2hpamtsbW5vcHFyc3R1dnd4eXowMTIzNDU2Nzg5Li8wMTIzNDU2Nzg5QUJDREVGR0hJSktMTU5PUFFSU1RVVldYWVphYmNkZWZnaGlqa2xtbm9wcXJzdHV2d3h5ekFCQ0RFRkdISUpLTE1OT1BRUlNUVVZXWFlaYWJjZGVmZ2hpamtsbW5vcHFyc3R1dnd4eXowMTIzNDU2Nzg5LV9BQkNERUZHSElKS0xNTk9QUVJTVFVWV1hZWmFiY2RlZmdoaWprbG1ub3BxcnN0dXZ3eHl6MDEyMzQ1Njc4OSsv////////////////////////////////////////////AAECAwQFBgcICQoLDP//DQ4PEBESExQVFv///////xcYGRobHB0eHyAhIiMkJf8mJygpKiss/y0uLzD/////MTIzNDU2//83ODk6Ozz//z0+P/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////8+P////zQ1Njc4OTo7PD3/////////AAECAwQFBgcICQoLDA0ODxAREhMUFRYXGBn///////8aGxwdHh8gISIjJCUmJygpKissLS4vMDEyM///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////AAE2Nzg5Ojs8PT4//////////wIDBAUGBwgJCgsMDQ4PEBESExQVFhcYGRob////////HB0eHyAhIiMkJSYnKCkqKywtLi8wMTIzNDX//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////wABAgMEBQYHCAkKC/////////8MDQ4PEBESExQVFhcYGRobHB0eHyAhIiMkJf///////yYnKCkqKywtLi8wMTIzNDU2Nzg5Ojs8PT4//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////z7//zQ1Njc4OTo7PD3/////////AAECAwQFBgcICQoLDA0ODxAREhMUFRYXGBn/////P/8aGxwdHh8gISIjJCUmJygpKissLS4vMDEyM///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////Pv///z80NTY3ODk6Ozw9/////////wABAgMEBQYHCAkKCwwNDg8QERITFBUWFxgZ////////GhscHR4fICEiIyQlJicoKSorLC0uLzAxMjP/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////GCUQANgkEACYJBAAWCQQABgkEADYIxAAWCoQAFgpEABYKBAAWCcQAFgmEABYJRAAVgAAAAgAAAAEAAAAVwAAAFgAAABWAAAACAAAAAQAAABZAAAAYG9uZSBvZiCtKxAABwAAACwgAAC8KxAAAgAAAKwrEAABAAAArCsQAAEAAABgIG9yIGAAAKwrEAABAAAA2CsQAAYAAACsKxAAAQAAAC91c3IvbG9jYWwvY2FyZ28vcmVnaXN0cnkvc3JjL2dpdGh1Yi5jb20tMWVjYzYyOTlkYjllYzgyMy9zZXJkZS0xLjAuMTg2L3NyYy9kZS9tb2QucnNleHBsaWNpdCBwYW5pYwD4KxAAVQAAAOoIAAASAAAAWwAAAAQAAAAEAAAAXAAAAF0AAABeAAAAY2FsbGVkIGBPcHRpb246OnVud3JhcCgpYCBvbiBhIGBOb25lYCB2YWx1ZW1lbW9yeSBhbGxvY2F0aW9uIG9mICBieXRlcyBmYWlsZWQKAACvLBAAFQAAAMQsEAAOAAAAbGlicmFyeS9zdGQvc3JjL2FsbG9jLnJz5CwQABgAAABVAQAACQAAAGNhbm5vdCBtb2RpZnkgdGhlIHBhbmljIGhvb2sgZnJvbSBhIHBhbmlja2luZyB0aHJlYWQM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", - "code_id": "1", - "code_info": { - "code_hash": "yEDfFQZ0Y/r68t1icFEjtQSnXZV0KrrHuCoJUs87vNo=", - "creator": "juno1hj5fveer5cjtn4wd6wstzugjfdxzl0xps73ftl", - "instantiate_config": { - "addresses": [], - "permission": "Everybody" - } - }, - "pinned": false - } - ], - "contracts": [ - { - "contract_address": "juno14hj2tavq8fpesdwxxcu44rty3hh90vhujrvcmstl4zr3txmfvw9skjuwg8", - "contract_code_history": [ - { - "code_id": "1", - "msg": {}, - "operation": "CONTRACT_CODE_HISTORY_OPERATION_TYPE_INIT", - "updated": { - "block_height": "4", - "tx_index": "0" - } - } - ], - "contract_info": { - "admin": "", - "code_id": "1", - "created": { - "block_height": "4", - "tx_index": "0" - }, - "creator": "juno1hj5fveer5cjtn4wd6wstzugjfdxzl0xps73ftl", - "extension": null, - "ibc_port_id": "", - "label": "test" - }, - "contract_state": [ - { - "key": "636F6E666967", - "value": "eyJ2YWwiOjF9" - }, - { - "key": "636F6E74726163745F696E666F", - "value": "eyJjb250cmFjdCI6ImNyYXRlcy5pbzpjdy1pYmMtZXhhbXBsZSIsInZlcnNpb24iOiIwLjEuMCJ9" - } - ] - } - ], - "params": { - "code_upload_access": { - "addresses": [], - "permission": "Everybody" - }, - "instantiate_default_permission": "Everybody" - }, - "sequences": [ - { - "id_key": "BGxhc3RDb2RlSWQ=", - "value": "2" - }, - { - "id_key": "BGxhc3RDb250cmFjdElk", - "value": "2" - } - ] - } - }, - "chain_id": "local-1", - "consensus_params": { - "block": { - "max_bytes": "22020096", - "max_gas": "100000000" - }, - "evidence": { - "max_age_duration": "172800000000000", - "max_age_num_blocks": "100000", - "max_bytes": "1048576" - }, - "validator": { - "pub_key_types": [ - "ed25519" - ] - }, - "version": { - "app": "0" - } - }, - "genesis_time": "2023-09-07T23:21:17.073977743Z", - "initial_height": "71", - "validators": [ - { - "address": "21D28714BEAA706095179C5BC4AE4B2B3C0D6988", - "name": "localjuno", - "power": "1", - "pub_key": { - "type": "tendermint/PubKeyEd25519", - "value": "9cSyCx910OX4PtUt+iYO6sF6TXi4OIDclvVEDxThXu8=" - } - } - ] -} \ No newline at end of file From ed27a119e6ffb0f0fa3262e981650b1641533f09 Mon Sep 17 00:00:00 2001 From: Joel Smith Date: Mon, 16 Oct 2023 19:56:10 -0500 Subject: [PATCH 73/79] Removed unused parameter --- app/ante.go | 2 +- x/feepay/ante/deduct_fee.go | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/app/ante.go b/app/ante.go index 324836fb1..7d3ce5486 100644 --- a/app/ante.go +++ b/app/ante.go @@ -91,7 +91,7 @@ func NewAnteHandler(options HandlerOptions) (sdk.AnteHandler, error) { ante.NewValidateMemoDecorator(options.AccountKeeper), ante.NewConsumeGasForTxSizeDecorator(options.AccountKeeper), globalfeeante.NewFeeDecorator(options.BypassMinFeeMsgTypes, options.GlobalFeeKeeper, options.StakingKeeper, options.FeePayKeeper, maxBypassMinFeeMsgGasUsage), - feepayante.NewDeductFeeDecorator(options.FeePayKeeper, options.GlobalFeeKeeper, options.AccountKeeper, options.BankKeeper, options.FeegrantKeeper, options.TxFeeChecker, options.BondDenom), + feepayante.NewDeductFeeDecorator(options.FeePayKeeper, options.GlobalFeeKeeper, options.AccountKeeper, options.BankKeeper, options.FeegrantKeeper, options.BondDenom), feeshareante.NewFeeSharePayoutDecorator(options.BankKeeper, options.FeeShareKeeper), // SetPubKeyDecorator must be called before all signature verification decorators ante.NewSetPubKeyDecorator(options.AccountKeeper), diff --git a/x/feepay/ante/deduct_fee.go b/x/feepay/ante/deduct_fee.go index 758c02153..f4127179b 100644 --- a/x/feepay/ante/deduct_fee.go +++ b/x/feepay/ante/deduct_fee.go @@ -38,7 +38,7 @@ type DeductFeeDecorator struct { bondDenom string } -func NewDeductFeeDecorator(fpk feepaykeeper.Keeper, gfk globalfeekeeper.Keeper, ak ante.AccountKeeper, bk bankkeeper.Keeper, fgk ante.FeegrantKeeper, tfc ante.TxFeeChecker, bondDenom string) DeductFeeDecorator { +func NewDeductFeeDecorator(fpk feepaykeeper.Keeper, gfk globalfeekeeper.Keeper, ak ante.AccountKeeper, bk bankkeeper.Keeper, fgk ante.FeegrantKeeper, bondDenom string) DeductFeeDecorator { return DeductFeeDecorator{ feepayKeeper: fpk, globalfeeKeeper: gfk, From 6b5590e67b81606d81a9e718b2748cafebe8fa8d Mon Sep 17 00:00:00 2001 From: Joel Smith Date: Mon, 16 Oct 2023 20:00:40 -0500 Subject: [PATCH 74/79] Remove contract balance check for eligiblity --- x/feepay/keeper/feepay.go | 5 ----- x/feepay/keeper/querier_test.go | 8 ++++---- 2 files changed, 4 insertions(+), 9 deletions(-) diff --git a/x/feepay/keeper/feepay.go b/x/feepay/keeper/feepay.go index f96643a5c..3ed6e3046 100644 --- a/x/feepay/keeper/feepay.go +++ b/x/feepay/keeper/feepay.go @@ -303,11 +303,6 @@ func (k Keeper) IsWalletEligible(ctx sdk.Context, fpc *types.FeePayContract, wal return false, types.ErrWalletExceededUsageLimit } - // Check if contract has enough funds - if fpc.Balance == 0 { - return true, types.ErrContractNotEnoughFunds - } - return true, nil } diff --git a/x/feepay/keeper/querier_test.go b/x/feepay/keeper/querier_test.go index bc5bc28ff..e7c3d60be 100644 --- a/x/feepay/keeper/querier_test.go +++ b/x/feepay/keeper/querier_test.go @@ -170,9 +170,9 @@ func (s *IntegrationTestSuite) TestQueryEligibility() { WalletAddress: sender.String(), }) - // Should error, contract should have no funds - s.Require().Error(err) - s.Require().Nil(res) + // Should not error, user has not exceeded limit + s.Require().NoError(err) + s.Require().True(res.Eligible) }) // Add funds @@ -190,7 +190,7 @@ func (s *IntegrationTestSuite) TestQueryEligibility() { WalletAddress: sender.String(), }) - // Should error, contract should have no funds + // Should not error, user has not exceeded limit s.Require().NoError(err) s.Require().True(res.Eligible) }) From 82574c2872a0a3d0a72a628861cd6aafac40120b Mon Sep 17 00:00:00 2001 From: Reece Williams Date: Tue, 17 Oct 2023 08:42:53 -0500 Subject: [PATCH 75/79] lintor --- x/feepay/keeper/querier.go | 6 +++--- x/feepay/keeper/querier_test.go | 1 - 2 files changed, 3 insertions(+), 4 deletions(-) diff --git a/x/feepay/keeper/querier.go b/x/feepay/keeper/querier.go index a21269dcb..6937f793b 100644 --- a/x/feepay/keeper/querier.go +++ b/x/feepay/keeper/querier.go @@ -36,7 +36,7 @@ func (q Querier) FeePayContract(ctx context.Context, req *types.QueryFeePayContr return &types.QueryFeePayContractResponse{ FeePayContract: contract, - }, err + }, nil } // FeePayContracts implements types.QueryServer. @@ -77,7 +77,7 @@ func (q Querier) FeePayContractUses(ctx context.Context, req *types.QueryFeePayC return &types.QueryFeePayContractUsesResponse{ Uses: uses, - }, err + }, nil } // FeePayContractEligible implements types.QueryServer. @@ -107,7 +107,7 @@ func (q Querier) FeePayWalletIsEligible(ctx context.Context, req *types.QueryFee return &types.QueryFeePayWalletIsEligibleResponse{ Eligible: isEligible, - }, err + }, nil } // Params returns the feepay module params diff --git a/x/feepay/keeper/querier_test.go b/x/feepay/keeper/querier_test.go index e7c3d60be..8ea0070ae 100644 --- a/x/feepay/keeper/querier_test.go +++ b/x/feepay/keeper/querier_test.go @@ -43,7 +43,6 @@ func (s *IntegrationTestSuite) TestQueryContractBalance() { _ = s.FundAccount(s.ctx, sender, sdk.NewCoins(sdk.NewCoin("stake", sdk.NewInt(1_000_000)))) s.Run("QueryContract", func() { - for _, bal := range []struct { balance uint64 }{ From d3012fa53249569ed7519e311f89d4ab948c8a56 Mon Sep 17 00:00:00 2001 From: Joel Smith Date: Mon, 23 Oct 2023 08:58:11 -0500 Subject: [PATCH 76/79] Update Msg Server Endpoints --- proto/juno/feepay/v1/tx.proto | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/proto/juno/feepay/v1/tx.proto b/proto/juno/feepay/v1/tx.proto index f3833ca00..a402aec36 100644 --- a/proto/juno/feepay/v1/tx.proto +++ b/proto/juno/feepay/v1/tx.proto @@ -17,25 +17,25 @@ service Msg { // RegisterFeeShare registers a new contract for receiving transaction fees rpc RegisterFeePayContract(MsgRegisterFeePayContract) returns (MsgRegisterFeePayContractResponse) { - option (google.api.http).post = "/juno/feepay/v1/tx/registerFeePayContract"; + option (google.api.http).post = "/juno/feepay/v1/tx/register"; }; // UnregisterFeeShare unregisters a contract for receiving transaction fees rpc UnregisterFeePayContract(MsgUnregisterFeePayContract) returns (MsgUnregisterFeePayContractResponse) { - option (google.api.http).post = "/juno/feepay/v1/tx/unregisterFeePayContract"; + option (google.api.http).post = "/juno/feepay/v1/tx/unregister"; }; // Fund a fee pay contract rpc FundFeePayContract(MsgFundFeePayContract) returns (MsgFundFeePayContractResponse) { - option (google.api.http).post = "/juno/feepay/v1/tx/fundFeePayContract"; + option (google.api.http).post = "/juno/feepay/v1/tx/fund"; }; // Update a fee pay contract wallet limit rpc UpdateFeePayContractWalletLimit(MsgUpdateFeePayContractWalletLimit) returns (MsgUpdateFeePayContractWalletLimitResponse) { - option (google.api.http).post = "/juno/feepay/v1/tx/updateFeePayContractWalletLimit"; + option (google.api.http).post = "/juno/feepay/v1/tx/update_wallet_limit"; }; // Update the params of the module through gov v1 type. From a1b2d18a0bf5552c11ca094b5338701b3611b801 Mon Sep 17 00:00:00 2001 From: Reece Williams Date: Tue, 24 Oct 2023 14:12:52 -0500 Subject: [PATCH 77/79] ictest v7 latest --- interchaintest/go.mod | 6 ++++-- interchaintest/go.sum | 14 ++++++++------ interchaintest/module_pfm_test.go | 31 +++++++++++++++---------------- interchaintest/setup.go | 31 +++++++++++++++---------------- 4 files changed, 42 insertions(+), 40 deletions(-) diff --git a/interchaintest/go.mod b/interchaintest/go.mod index fe567fcb3..bca9dc702 100644 --- a/interchaintest/go.mod +++ b/interchaintest/go.mod @@ -24,13 +24,15 @@ require ( github.com/cosmos/cosmos-sdk v0.47.5 github.com/cosmos/gogoproto v1.4.10 github.com/cosmos/ibc-go/v7 v7.3.1 - github.com/docker/docker v24.0.4+incompatible + github.com/docker/docker v24.0.5+incompatible github.com/skip-mev/pob/tests/integration v0.1.0 - github.com/strangelove-ventures/interchaintest/v7 v7.0.0-20230721183422-fb937bb0e165 + github.com/strangelove-ventures/interchaintest/v7 v7.0.0-20231018200122-b988aa9a3a4b github.com/stretchr/testify v1.8.4 go.uber.org/zap v1.25.0 ) +require github.com/cosmos/ibc-go/modules/capability v1.0.0-rc1 // indirect + require ( cloud.google.com/go v0.110.4 // indirect cloud.google.com/go/compute v1.21.0 // indirect diff --git a/interchaintest/go.sum b/interchaintest/go.sum index 6af5d225c..2d0e353ce 100644 --- a/interchaintest/go.sum +++ b/interchaintest/go.sum @@ -371,6 +371,8 @@ github.com/cosmos/gogoproto v1.4.10 h1:QH/yT8X+c0F4ZDacDv3z+xE3WU1P1Z3wQoLMBRJoK github.com/cosmos/gogoproto v1.4.10/go.mod h1:3aAZzeRWpAwr+SS/LLkICX2/kDFyaYVzckBDzygIxek= github.com/cosmos/iavl v0.20.1 h1:rM1kqeG3/HBT85vsZdoSNsehciqUQPWrR4BYmqE2+zg= github.com/cosmos/iavl v0.20.1/go.mod h1:WO7FyvaZJoH65+HFOsDir7xU9FWk2w9cHXNW1XHcl7A= +github.com/cosmos/ibc-go/modules/capability v1.0.0-rc1 h1:BvSKnPFKxL+TTSLxGKwJN4x0ndCZj0yfXhSvmsQztSA= +github.com/cosmos/ibc-go/modules/capability v1.0.0-rc1/go.mod h1:A+CxAQdn2j6ihDTbClpEEBdHthWgAUAcHbRAQPY8sl4= github.com/cosmos/ibc-go/v7 v7.3.1 h1:bil1IjnHdyWDASFYKfwdRiNtFP6WK3osW7QFEAgU4I8= github.com/cosmos/ibc-go/v7 v7.3.1/go.mod h1:wvx4pPBofe5ZdMNV3OFRxSI4auEP5Qfqf8JXLLNV04g= github.com/cosmos/ics23/go v0.10.0 h1:iXqLLgp2Lp+EdpIuwXTYIQU+AiHj9mOC2X9ab++bZDM= @@ -419,8 +421,8 @@ github.com/dgryski/go-farm v0.0.0-20200201041132-a6ae2369ad13 h1:fAjc9m62+UWV/WA github.com/dgryski/go-farm v0.0.0-20200201041132-a6ae2369ad13/go.mod h1:SqUrOPUnsFjfmXRMNPybcSiG0BgUW2AuFH8PAnS2iTw= github.com/docker/distribution v2.8.2+incompatible h1:T3de5rq0dB1j30rp0sA2rER+m322EBzniBPB6ZIzuh8= github.com/docker/distribution v2.8.2+incompatible/go.mod h1:J2gT2udsDAN96Uj4KfcMRqY0/ypR+oyYUYmja8H+y+w= -github.com/docker/docker v24.0.4+incompatible h1:s/LVDftw9hjblvqIeTiGYXBCD95nOEEl7qRsRrIOuQI= -github.com/docker/docker v24.0.4+incompatible/go.mod h1:eEKB0N0r5NX/I1kEveEz05bcu8tLC/8azJZsviup8Sk= +github.com/docker/docker v24.0.5+incompatible h1:WmgcE4fxyI6EEXxBRxsHnZXrO1pQ3smi0k/jho4HLeY= +github.com/docker/docker v24.0.5+incompatible/go.mod h1:eEKB0N0r5NX/I1kEveEz05bcu8tLC/8azJZsviup8Sk= github.com/docker/go-connections v0.4.0 h1:El9xVISelRB7BuFusrZozjnkIM5YnzCViNKohAFqRJQ= github.com/docker/go-connections v0.4.0/go.mod h1:Gbd7IOopHjR8Iph03tsViu4nIes5XhDvyHbTtUxmeec= github.com/docker/go-units v0.5.0 h1:69rxXcBk27SvSaaxTtLh/8llcHD8vYHT7WSdRZ/jvr4= @@ -894,8 +896,8 @@ github.com/onsi/gomega v1.7.1/go.mod h1:XdKZgCCFLUoM/7CFJVPcG8C1xQ1AJ0vpAezJrB7J github.com/onsi/gomega v1.10.1/go.mod h1:iN09h71vgCQne3DLsj+A5owkum+a2tYe+TOCB1ybHNo= github.com/onsi/gomega v1.17.0/go.mod h1:HnhC7FXeEQY45zxNK3PPoIUhzk/80Xly9PcubAlGdZY= github.com/onsi/gomega v1.19.0/go.mod h1:LY+I3pBVzYsTBU1AnDwOSxaYi9WoWiqgwooUqq9yPro= -github.com/onsi/gomega v1.20.0 h1:8W0cWlwFkflGPLltQvLRB7ZVD5HuP6ng320w2IS245Q= -github.com/onsi/gomega v1.20.0/go.mod h1:DtrZpjmvpn2mPm4YWQa0/ALMDj9v4YxLgojwPeREyVo= +github.com/onsi/gomega v1.27.4 h1:Z2AnStgsdSayCMDiCU42qIz+HLqEPcgiOCXjAU/w+8E= +github.com/onsi/gomega v1.27.4/go.mod h1:riYq/GJKh8hhoM01HN6Vmuy93AarCXCBGpvFDK3q3fQ= github.com/op/go-logging v0.0.0-20160315200505-970db520ece7/go.mod h1:HzydrMdWErDVzsI23lYNej1Htcns9BCg93Dk0bBINWk= github.com/opencontainers/go-digest v1.0.0 h1:apOUWs51W5PlhuyGyz9FCeeBIOUDA/6nW8Oi/yOhh5U= github.com/opencontainers/go-digest v1.0.0/go.mod h1:0JzlMkj0TRzQZfJkVvzbP0HBR3IKzErnv2BNG4W4MAM= @@ -1045,8 +1047,8 @@ github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An github.com/spf13/viper v1.3.2/go.mod h1:ZiWeW+zYFKm7srdB9IoDzzZXaJaI5eL9QjNiN/DMA2s= github.com/spf13/viper v1.16.0 h1:rGGH0XDZhdUOryiDWjmIvUSWpbNqisK8Wk0Vyefw8hc= github.com/spf13/viper v1.16.0/go.mod h1:yg78JgCJcbrQOvV9YLXgkLaZqUidkY9K+Dd1FofRzQg= -github.com/strangelove-ventures/interchaintest/v7 v7.0.0-20230721183422-fb937bb0e165 h1:uVCHoklBlbAy77RT6iQBaK7oo8rTn5uI0hrRn1LL5Sw= -github.com/strangelove-ventures/interchaintest/v7 v7.0.0-20230721183422-fb937bb0e165/go.mod h1:WUglvTs5dOXiI7z+VRiVibkFcd2pvTfoDEcXnjYONrw= +github.com/strangelove-ventures/interchaintest/v7 v7.0.0-20231018200122-b988aa9a3a4b h1:LuPVurydDpJ50pIEqVk1pYpT72SSMzjSVq9wp4P0INY= +github.com/strangelove-ventures/interchaintest/v7 v7.0.0-20231018200122-b988aa9a3a4b/go.mod h1:8oeA4y0gCxEK8tgp+/oaHC4+iZXaAS2Sx+rd84hWzMQ= github.com/streadway/amqp v0.0.0-20190404075320-75d898a42a94/go.mod h1:AZpEONHx3DKn8O/DFsRAY58/XVQiIPMTMB1SddzLXVw= github.com/streadway/amqp v0.0.0-20190827072141-edfb9018d271/go.mod h1:AZpEONHx3DKn8O/DFsRAY58/XVQiIPMTMB1SddzLXVw= github.com/streadway/handy v0.0.0-20190108123426-d5acb3125c2a/go.mod h1:qNTQ5P5JnDBl6z3cMAg/SywNDC5ABu5ApDIw6lUbRmI= diff --git a/interchaintest/module_pfm_test.go b/interchaintest/module_pfm_test.go index 4c10f3e22..ba2318c97 100644 --- a/interchaintest/module_pfm_test.go +++ b/interchaintest/module_pfm_test.go @@ -52,22 +52,21 @@ func TestPacketForwardMiddlewareRouter(t *testing.T) { // base config which all networks will use as defaults. baseCfg := ibc.ChainConfig{ - Type: "cosmos", - Name: "juno", - ChainID: "", // change this for each - Images: []ibc.DockerImage{JunoImage}, - Bin: "junod", - Bech32Prefix: "juno", - Denom: "ujuno", - CoinType: "118", - GasPrices: "0ujuno", - GasAdjustment: 2.0, - TrustingPeriod: "112h", - NoHostMount: false, - ConfigFileOverrides: nil, - EncodingConfig: junoEncoding(), - UsingNewGenesisCommand: true, - ModifyGenesis: cosmos.ModifyGenesis(defaultGenesisKV), + Type: "cosmos", + Name: "juno", + ChainID: "", // change this for each + Images: []ibc.DockerImage{JunoImage}, + Bin: "junod", + Bech32Prefix: "juno", + Denom: "ujuno", + CoinType: "118", + GasPrices: "0ujuno", + GasAdjustment: 2.0, + TrustingPeriod: "112h", + NoHostMount: false, + ConfigFileOverrides: nil, + EncodingConfig: junoEncoding(), + ModifyGenesis: cosmos.ModifyGenesis(defaultGenesisKV), } // Set specific chain ids for each so they are their own unique networks diff --git a/interchaintest/setup.go b/interchaintest/setup.go index 3c64c9126..cf9ec3b73 100644 --- a/interchaintest/setup.go +++ b/interchaintest/setup.go @@ -65,22 +65,21 @@ var ( } junoConfig = ibc.ChainConfig{ - Type: "cosmos", - Name: "juno", - ChainID: "juno-2", - Images: []ibc.DockerImage{JunoImage}, - Bin: "junod", - Bech32Prefix: "juno", - Denom: Denom, - CoinType: "118", - GasPrices: fmt.Sprintf("0%s", Denom), - GasAdjustment: 2.0, - TrustingPeriod: "112h", - NoHostMount: false, - ConfigFileOverrides: nil, - EncodingConfig: junoEncoding(), - UsingNewGenesisCommand: true, - ModifyGenesis: cosmos.ModifyGenesis(defaultGenesisKV), + Type: "cosmos", + Name: "juno", + ChainID: "juno-2", + Images: []ibc.DockerImage{JunoImage}, + Bin: "junod", + Bech32Prefix: "juno", + Denom: Denom, + CoinType: "118", + GasPrices: fmt.Sprintf("0%s", Denom), + GasAdjustment: 2.0, + TrustingPeriod: "112h", + NoHostMount: false, + ConfigFileOverrides: nil, + EncodingConfig: junoEncoding(), + ModifyGenesis: cosmos.ModifyGenesis(defaultGenesisKV), } genesisWalletAmount = int64(10_000_000) From c3ba792da0ee91a2e411afa1a829b917ac1c0c1b Mon Sep 17 00:00:00 2001 From: Reece Williams Date: Tue, 24 Oct 2023 14:13:04 -0500 Subject: [PATCH 78/79] remove pob test for now (works, just out of date) --- interchaintest/go.mod | 8 +++--- interchaintest/go.sum | 27 ++++++++++++++++--- ...pob_test.go => module_pob_test.go.archive} | 0 3 files changed, 28 insertions(+), 7 deletions(-) rename interchaintest/{module_pob_test.go => module_pob_test.go.archive} (100%) diff --git a/interchaintest/go.mod b/interchaintest/go.mod index bca9dc702..c6aaabaa9 100644 --- a/interchaintest/go.mod +++ b/interchaintest/go.mod @@ -25,13 +25,16 @@ require ( github.com/cosmos/gogoproto v1.4.10 github.com/cosmos/ibc-go/v7 v7.3.1 github.com/docker/docker v24.0.5+incompatible - github.com/skip-mev/pob/tests/integration v0.1.0 + // github.com/skip-mev/pob/tests/integration v0.1.0 github.com/strangelove-ventures/interchaintest/v7 v7.0.0-20231018200122-b988aa9a3a4b github.com/stretchr/testify v1.8.4 go.uber.org/zap v1.25.0 ) -require github.com/cosmos/ibc-go/modules/capability v1.0.0-rc1 // indirect +require ( + github.com/cosmos/ibc-go/modules/capability v1.0.0-rc1 // indirect + github.com/opencontainers/runc v1.1.5 // indirect +) require ( cloud.google.com/go v0.110.4 // indirect @@ -200,7 +203,6 @@ require ( github.com/rs/cors v1.8.3 // indirect github.com/rs/zerolog v1.30.0 // indirect github.com/sasha-s/go-deadlock v0.3.1 // indirect - github.com/skip-mev/pob v1.0.4 // indirect github.com/spaolacci/murmur3 v1.1.0 // indirect github.com/spf13/afero v1.9.5 // indirect github.com/spf13/cast v1.5.1 // indirect diff --git a/interchaintest/go.sum b/interchaintest/go.sum index 2d0e353ce..f4d398b8f 100644 --- a/interchaintest/go.sum +++ b/interchaintest/go.sum @@ -304,6 +304,7 @@ github.com/cespare/xxhash v1.1.0/go.mod h1:XrSqR1VqqWfGrhpAt58auRo0WTKS1nRRg3ghf github.com/cespare/xxhash/v2 v2.1.1/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= github.com/cespare/xxhash/v2 v2.2.0 h1:DC2CZ1Ep5Y4k3ZQ899DldepgrayRUGE6BBZ/cd9Cj44= github.com/cespare/xxhash/v2 v2.2.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= +github.com/checkpoint-restore/go-criu/v5 v5.3.0/go.mod h1:E/eQpaFtUKGOOSEBZgmKAcn+zUUwWxqcaKZlF54wK8E= github.com/cheggaaa/pb v1.0.27/go.mod h1:pQciLPpbU0oxA0h+VJYYLxO+XeDQb5pZijXscXHm81s= github.com/chzyer/logex v1.1.10/go.mod h1:+Ywpsq7O8HXn0nuIou7OrIPyXbp3wmkHB+jjWRnGsAI= github.com/chzyer/logex v1.2.1 h1:XHDu3E6q+gdHgsdTPH6ImJMIp436vR6MPtH8gP05QzM= @@ -314,6 +315,7 @@ github.com/chzyer/readline v1.5.1/go.mod h1:Eh+b79XXUwfKfcPLepksvw2tcLE/Ct21YObk github.com/chzyer/test v0.0.0-20180213035817-a1ea475d72b1/go.mod h1:Q3SI9o4m/ZMnBNeIyt5eFwwo7qiLfzFZmjNmxjkiQlU= github.com/chzyer/test v1.0.0 h1:p3BQDXSxOhOG0P9z6/hGnII4LGiEPOYBhs8asl/fC04= github.com/chzyer/test v1.0.0/go.mod h1:2JlltgoNkt4TW/z9V/IzDdFaMTM2JPIi26O1pF38GC8= +github.com/cilium/ebpf v0.7.0/go.mod h1:/oI2+1shJiTGAMgl6/RgJr36Eo1jzrRcAWbcXO2usCA= github.com/circonus-labs/circonus-gometrics v2.3.1+incompatible/go.mod h1:nmEj6Dob7S7YxXgwXpfOuvO54S+tGdZdw9fuRZt25Ag= github.com/circonus-labs/circonusllhist v0.1.3/go.mod h1:kMXHVDlOchFAehlya5ePtbp5jckzBHf4XRpQvBOLI+I= github.com/clbanning/x2j v0.0.0-20191024224557-825249438eec/go.mod h1:jMjuTZXRI4dUb/I5gc9Hdhagfvm9+RyrPryS/auMzxE= @@ -347,12 +349,14 @@ github.com/cometbft/cometbft-db v0.8.0 h1:vUMDaH3ApkX8m0KZvOFFy9b5DZHBAjsnEuo9AK github.com/cometbft/cometbft-db v0.8.0/go.mod h1:6ASCP4pfhmrCBpfk01/9E1SI29nD3HfVHrY4PG8x5c0= github.com/confio/ics23/go v0.9.0 h1:cWs+wdbS2KRPZezoaaj+qBleXgUk5WOQFMP3CQFGTr4= github.com/confio/ics23/go v0.9.0/go.mod h1:4LPZ2NYqnYIVRklaozjNR1FScgDJ2s5Xrp+e/mYVRak= +github.com/containerd/console v1.0.3/go.mod h1:7LqA/THxQ86k76b8c/EMSiaJ3h1eZkMkXar0TQ1gf3U= github.com/containerd/continuity v0.3.0 h1:nisirsYROK15TAMVukJOUyGJjz4BNQJBVsNvAXZJ/eg= github.com/containerd/continuity v0.3.0/go.mod h1:wJEAIwKOm/pBZuBd0JmeTvnLquTB1Ag8espWhkykbPM= github.com/coreos/etcd v3.3.10+incompatible/go.mod h1:uF7uidLiAD3TWHmW31ZFd/JWoc32PjwdhPthX9715RE= github.com/coreos/go-etcd v2.0.0+incompatible/go.mod h1:Jez6KQU2B/sWsbdaef3ED8NzMklzPG4d5KIOhIy30Tk= github.com/coreos/go-semver v0.2.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3EedlOD2RNk= github.com/coreos/go-systemd v0.0.0-20180511133405-39ca1b05acc7/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4= +github.com/coreos/go-systemd/v22 v22.3.2/go.mod h1:Y58oyj3AT4RCenI/lSvhwexgC+NSVTIJ3seZv2GcEnc= github.com/coreos/go-systemd/v22 v22.5.0/go.mod h1:Y58oyj3AT4RCenI/lSvhwexgC+NSVTIJ3seZv2GcEnc= github.com/coreos/pkg v0.0.0-20160727233714-3ac0863d7acf/go.mod h1:E3G3o1h8I7cfcXa63jLwjI0eiQQMgzzUDFVpN/nH/eA= github.com/cosmos/btcutil v1.0.5 h1:t+ZFcX77LpKtDBhjucvnOH8C2l2ioGsBNEQ3jef8xFk= @@ -388,6 +392,7 @@ github.com/creachadair/taskgroup v0.4.2 h1:jsBLdAJE42asreGss2xZGZ8fJra7WtwnHWeJF github.com/creachadair/taskgroup v0.4.2/go.mod h1:qiXUOSrbwAY3u0JPGTzObbE3yf9hcXHDKBZ2ZjpCbgM= github.com/creack/pty v1.1.7/go.mod h1:lj5s0c3V2DBrqTV7llrYr5NG6My20zk30Fl46Y7DoTY= github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E= +github.com/cyphar/filepath-securejoin v0.2.3/go.mod h1:aPGpWjXOXUn2NCNjFvBE6aRxGGx79pTxQpKOJNYHHl4= github.com/danieljoos/wincred v1.1.2 h1:QLdCxFs1/Yl4zduvBdcHB8goaYk9RARS2SgLLRuAyr0= github.com/danieljoos/wincred v1.1.2/go.mod h1:GijpziifJoIBfYh+S7BbkdUTU4LfM+QnGqR5Vl2tAx0= github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= @@ -425,6 +430,7 @@ github.com/docker/docker v24.0.5+incompatible h1:WmgcE4fxyI6EEXxBRxsHnZXrO1pQ3sm github.com/docker/docker v24.0.5+incompatible/go.mod h1:eEKB0N0r5NX/I1kEveEz05bcu8tLC/8azJZsviup8Sk= github.com/docker/go-connections v0.4.0 h1:El9xVISelRB7BuFusrZozjnkIM5YnzCViNKohAFqRJQ= github.com/docker/go-connections v0.4.0/go.mod h1:Gbd7IOopHjR8Iph03tsViu4nIes5XhDvyHbTtUxmeec= +github.com/docker/go-units v0.4.0/go.mod h1:fgPhTUdO+D/Jk86RDLlptpiXQzgHJF7gydDDbaIK4Dk= github.com/docker/go-units v0.5.0 h1:69rxXcBk27SvSaaxTtLh/8llcHD8vYHT7WSdRZ/jvr4= github.com/docker/go-units v0.5.0/go.mod h1:fgPhTUdO+D/Jk86RDLlptpiXQzgHJF7gydDDbaIK4Dk= github.com/dustin/go-humanize v0.0.0-20171111073723-bb3d318650d4/go.mod h1:HtrtbFcZ19U5GC7JDqmcUSB87Iq5E25KnS6fMYU6eOk= @@ -458,6 +464,7 @@ github.com/fortytw2/leaktest v1.3.0 h1:u8491cBMTQ8ft8aeV+adlcytMZylmA5nnwwkRZjI8 github.com/fortytw2/leaktest v1.3.0/go.mod h1:jDsjWgpAGjm2CA7WthBh/CdZYEPF31XHquHwclZch5g= github.com/franela/goblin v0.0.0-20200105215937-c9ffbefa60db/go.mod h1:7dvUGVsVBjqR7JHJk0brhHOZYGmfBYOrK0ZhYMEtBr4= github.com/franela/goreq v0.0.0-20171204163338-bcd34c9993f8/go.mod h1:ZhphrRTfi2rbfLwlschooIH4+wKKDR4Pdxhh+TRoA20= +github.com/frankban/quicktest v1.11.3/go.mod h1:wRf/ReqHper53s+kmmSZizM8NamnL3IM0I9ntUbOk+k= github.com/frankban/quicktest v1.14.4 h1:g2rn0vABPOOXmZUj+vbmUp0lPoXEMuhTpIluN0XL9UY= github.com/frankban/quicktest v1.14.4/go.mod h1:4ptaffx2x8+WTWXmUCuVU6aPUX1/Mz7zb5vbUoiM6w0= github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo= @@ -519,6 +526,7 @@ github.com/goccy/go-json v0.10.0/go.mod h1:6MelG93GURQebXPDq3khkgXZkazVtN9CRI+MG github.com/godbus/dbus v0.0.0-20190726142602-4481cbc300e2 h1:ZpnhV/YsD2/4cESfV5+Hoeu/iUR3ruzNvZ+yQfO03a0= github.com/godbus/dbus v0.0.0-20190726142602-4481cbc300e2/go.mod h1:bBOAhwG1umN6/6ZUMtDFBMQR8jRg9O75tm9K00oMsK4= github.com/godbus/dbus/v5 v5.0.4/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA= +github.com/godbus/dbus/v5 v5.0.6/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA= github.com/gogo/googleapis v1.1.0/go.mod h1:gf4bu3Q80BeJ6H1S1vYPm8/ELATdvryBaNFGgqEef3s= github.com/gogo/googleapis v1.4.1-0.20201022092350-68b0159b7869/go.mod h1:5YRNX2z1oM5gXdAkurHa942MDgEJyk02w4OecKY87+c= github.com/gogo/googleapis v1.4.1 h1:1Yx4Myt7BxzvUr5ldGSbwYiZG6t9wGBZ+8/fX3Wvtq0= @@ -771,6 +779,7 @@ github.com/konsorten/go-windows-terminal-sequences v1.0.3/go.mod h1:T0+1ngSBFLxv github.com/kr/fs v0.1.0/go.mod h1:FFnZGqtBN9Gxj7eW1uZ42v5BccTP0vu6NEaFoC2HwRg= github.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515/go.mod h1:+0opPa2QZZtGFBFZlji/RkVcI2GknAs/DXo4wKdlNEc= github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= +github.com/kr/pretty v0.2.1/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI= github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE= github.com/kr/pretty v0.3.1/go.mod h1:hoEshYVHaxMs3cyo3Yncou5ZscifuDolrwPKZanG3xk= github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= @@ -837,6 +846,7 @@ github.com/mitchellh/mapstructure v0.0.0-20160808181253-ca63d7c062ee/go.mod h1:F github.com/mitchellh/mapstructure v1.1.2/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y= github.com/mitchellh/mapstructure v1.5.0 h1:jeMsZIYE/09sWLaz43PL7Gy6RuMjD2eJVyuac5Z2hdY= github.com/mitchellh/mapstructure v1.5.0/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo= +github.com/moby/sys/mountinfo v0.5.0/go.mod h1:3bMD3Rg+zkqx8MRYPi7Pyb0Ie97QEBmdxbhnCLlSvSU= github.com/moby/term v0.0.0-20220808134915-39b0c02b01ae h1:O4SWKdcHVCvYqyDV+9CJA1fcDN2L11Bule0iFy3YlAI= github.com/moby/term v0.0.0-20220808134915-39b0c02b01ae/go.mod h1:E2VnQOmVuvZB6UYnnDB0qG5Nq/1tD9acaOpo6xmt0Kw= github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= @@ -850,6 +860,7 @@ github.com/morikuni/aec v1.0.0 h1:nP9CBfwrvYnBRgY6qfDQkygYDmYwOilePFkwzv4dU8A= github.com/morikuni/aec v1.0.0/go.mod h1:BbKIizmSmc5MMPqRYbxO4ZU0S0+P200+tUnFx7PXmsc= github.com/mr-tron/base58 v1.2.0 h1:T/HDJBh4ZCPbU39/+c3rRvE0uKBQlU27+QI8LJ4t64o= github.com/mr-tron/base58 v1.2.0/go.mod h1:BinMc/sQntlIE1frQmRFPUoPA1Zkr8VRgBdjWI2mNwc= +github.com/mrunalp/fileutils v0.5.0/go.mod h1:M1WthSahJixYnrXQl/DFQuteStB1weuxD2QJNHXfbSQ= github.com/mtibben/percent v0.2.1 h1:5gssi8Nqo8QU/r2pynCm+hBQHpkB/uNK7BJCFogWdzs= github.com/mtibben/percent v0.2.1/go.mod h1:KG9uO+SZkUp+VkRHsCdYQV3XSZrrSpR3O9ibNBTZrns= github.com/multiformats/go-base32 v0.1.0 h1:pVx9xoSPqEIQG8o+UbAe7DNi51oej1NtK+aGkbLYxPE= @@ -905,6 +916,8 @@ github.com/opencontainers/image-spec v1.1.0-rc2 h1:2zx/Stx4Wc5pIPDvIxHXvXtQFW/7X github.com/opencontainers/image-spec v1.1.0-rc2/go.mod h1:3OVijpioIKYWTqjiG0zfF6wvoJ4fAXGbjdZuI2NgsRQ= github.com/opencontainers/runc v1.1.5 h1:L44KXEpKmfWDcS02aeGm8QNTFXTo2D+8MYGDIJ/GDEs= github.com/opencontainers/runc v1.1.5/go.mod h1:1J5XiS+vdZ3wCyZybsuxXZWGrgSr8fFJHLXuG2PsnNg= +github.com/opencontainers/runtime-spec v1.0.3-0.20210326190908-1c3f411f0417/go.mod h1:jwyrGlmzljRJv/Fgzds9SsS/C5hL+LL3ko9hs6T5lQ0= +github.com/opencontainers/selinux v1.10.0/go.mod h1:2i0OySw99QjzBBQByd1Gr9gSjvuho1lHsJxIJ3gGbJI= github.com/opentracing-contrib/go-observer v0.0.0-20170622124052-a52f23424492/go.mod h1:Ngi6UdF0k5OKD5t5wlmGhe/EDKPoUM3BXZSSfIuJbis= github.com/opentracing/basictracer-go v1.0.0/go.mod h1:QfBfYuafItcjQuMwinw9GhYKwFXS9KnPs5lxoYwgW74= github.com/opentracing/opentracing-go v1.0.2/go.mod h1:UkNAQd3GIcIGf0SeVgPpRdFStlNbqXla1AfSYxPUl2o= @@ -1007,6 +1020,7 @@ github.com/samuel/go-zookeeper v0.0.0-20190923202752-2cc03de413da/go.mod h1:gi+0 github.com/sasha-s/go-deadlock v0.3.1 h1:sqv7fDNShgjcaxkO0JNcOAlr8B9+cV5Ey/OB71efZx0= github.com/sasha-s/go-deadlock v0.3.1/go.mod h1:F73l+cr82YSh10GxyRI6qZiCgK64VaZjwesgfQ1/iLM= github.com/sean-/seed v0.0.0-20170313163322-e2103e2c3529/go.mod h1:DxrIzT+xaE7yg65j358z/aeFdxmN0P9QXhEzd20vsDc= +github.com/seccomp/libseccomp-golang v0.9.2-0.20220502022130-f33da4d89646/go.mod h1:JA8cRccbGaA1s33RQf7Y1+q9gHmZX1yB/z9WDN1C6fg= github.com/shirou/gopsutil v3.21.4-0.20210419000835-c7a38de76ee5+incompatible h1:Bn1aCHHRnjv4Bl16T8rcaFjYSrGrIZvpiGO6P3Q4GpU= github.com/shirou/gopsutil v3.21.4-0.20210419000835-c7a38de76ee5+incompatible/go.mod h1:5b4v6he4MtMOwMlS0TUMTu2PcXUg8+E1lC7eC3UO/RA= github.com/shurcooL/sanitized_anchor_name v1.0.0/go.mod h1:1NzhyTcUVG4SuEtjjoZeVRXNmyL/1OwPU0+IJeTBvfc= @@ -1014,12 +1028,9 @@ github.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPx github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE= github.com/sirupsen/logrus v1.6.0/go.mod h1:7uNnSEd1DgxDLC74fIahvMZmmYsHGZGEOFrfsX/uA88= github.com/sirupsen/logrus v1.7.0/go.mod h1:yWOB1SBYBC5VeMP7gHvWumXLIWorT60ONWic61uBYv0= +github.com/sirupsen/logrus v1.8.1/go.mod h1:yWOB1SBYBC5VeMP7gHvWumXLIWorT60ONWic61uBYv0= github.com/sirupsen/logrus v1.9.0 h1:trlNQbNUG3OdDrDil03MCb1H2o9nJ1x4/5LYw7byDE0= github.com/sirupsen/logrus v1.9.0/go.mod h1:naHLuLoDiP4jHNo9R0sCBMtWGeIprob74mVsIT4qYEQ= -github.com/skip-mev/pob v1.0.4 h1:Degz+Pdm9pCom16bbLawZhXi6PbYPiiJe6cGjBE5g30= -github.com/skip-mev/pob v1.0.4/go.mod h1:tpZivmkiDgCO6O79qBnK4eJQjuJeR9yUzc1jPlGaE1s= -github.com/skip-mev/pob/tests/integration v0.1.0 h1:Rag5gcOxMyqOQIY1/C9ZQ1PMRkO01DUkZSKfVs3l7lQ= -github.com/skip-mev/pob/tests/integration v0.1.0/go.mod h1:BJtVD+0ic4YPLw1ljSnMlB2VI2KlFJVDW61P2p6+888= github.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d/go.mod h1:OnSkiWE9lh6wB0YB77sQom3nweQdgAjqCqsofrRNTgc= github.com/smartystreets/goconvey v1.6.4/go.mod h1:syvi0/a8iFYH4r/RixwvyeAJjdLS9QV7WQ/tjFTllLA= github.com/soheilhy/cmux v0.1.4/go.mod h1:IM3LyeVVIOuxMH7sFAkER9+bJ4dT7Ms6E4xg4kGIyLM= @@ -1072,6 +1083,7 @@ github.com/stretchr/testify v1.8.4 h1:CcVxjf3Q8PM0mHUKJCdn+eZZtm5yQwehR5yeSVQQcU github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo= github.com/subosito/gotenv v1.4.2 h1:X1TuBLAMDFbaTAChgCBLu3DU3UPyELpnF2jjJ2cz/S8= github.com/subosito/gotenv v1.4.2/go.mod h1:ayKnFf/c6rvx/2iiLrJUk1e6plDbT3edrFNGqEflhK0= +github.com/syndtr/gocapability v0.0.0-20200815063812-42c35b437635/go.mod h1:hkRG7XYTFWNJGYcbNJQlaLq0fg1yr4J4t/NcTQtrfww= github.com/syndtr/goleveldb v1.0.1-0.20220721030215-126854af5e6d h1:vfofYNRScrDdvS342BElfbETmL1Aiz3i2t0zfRj16Hs= github.com/syndtr/goleveldb v1.0.1-0.20220721030215-126854af5e6d/go.mod h1:RRCYJbIwD5jmqPI9XoAFR0OcDxqUctll6zUj/+B4S48= github.com/tendermint/go-amino v0.16.0 h1:GyhmgQKvqF82e2oZeuMSp9JTN0N09emoSZlb2lyGa2E= @@ -1098,6 +1110,8 @@ github.com/ulikunitz/xz v0.5.11 h1:kpFauv27b6ynzBNT/Xy+1k+fK4WswhN/6PN5WhFAGw8= github.com/ulikunitz/xz v0.5.11/go.mod h1:nbz6k7qbPmH4IRqmfOplQw/tblSgqTqBwxkY0oWt/14= github.com/urfave/cli v1.20.0/go.mod h1:70zkFmudgCuE/ngEzBv17Jvp/497gISqfk5gWijbERA= github.com/urfave/cli v1.22.1/go.mod h1:Gos4lmkARVdJ6EkW0WaNv/tZAAMe9V7XWyB60NtXRu0= +github.com/vishvananda/netlink v1.1.0/go.mod h1:cTgwzPIzzgDAYoQrMm0EdrjRUBkTqKYppBueQtXaqoE= +github.com/vishvananda/netns v0.0.0-20191106174202-0a2b9b5464df/go.mod h1:JP3t17pCcGlemwknint6hfoeCVQrEMVwxRLRjXpq+BU= github.com/xiang90/probing v0.0.0-20190116061207-43a291ad63a2/go.mod h1:UETIi67q53MR2AWcXfiuqkDkRtnGDLqkBTpCHuJHxtU= github.com/xordataexchange/crypt v0.0.3-0.20170626215501-b2862e3d0a77/go.mod h1:aYKd//L2LvnjZzWKhF00oedf4jCCReLcmhLdhm1A27Q= github.com/yuin/goldmark v1.1.25/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= @@ -1326,6 +1340,7 @@ golang.org/x/sys v0.0.0-20190422165155-953cdadca894/go.mod h1:h1NjWce9XRLGQEsW7w golang.org/x/sys v0.0.0-20190502145724-3ef323f4f1fd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190507160741-ecd444e8653b/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190606165138-5da285871e9c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190606203320-7fc4e5ec1444/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190624142023-c5567b49c5d0/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190626221950-04f50cda93cb/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190726091711-fc99dfbffb4e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= @@ -1334,6 +1349,7 @@ golang.org/x/sys v0.0.0-20190904154756-749cb33beabd/go.mod h1:h1NjWce9XRLGQEsW7w golang.org/x/sys v0.0.0-20191001151750-bb3f8db39f24/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191005200804-aed5e4c7ecf9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191026070338-33540a1f6037/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20191115151921-52ab43148777/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191120155948-bd437916bb0e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191204072324-ce4227a45e2e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191220142924-d4481acd189f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= @@ -1363,6 +1379,7 @@ golang.org/x/sys v0.0.0-20201201145000-ef89a241ccb3/go.mod h1:h1NjWce9XRLGQEsW7w golang.org/x/sys v0.0.0-20210104204734-6f8348627aad/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210112080510-489259a85091/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210119212857-b64e53b001e4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210124154548-22da62e12c0c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210220050731-9a76102bfb43/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210225134936-a50acf3fe073/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210305230114-8fe3ee5dd75b/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= @@ -1381,9 +1398,11 @@ golang.org/x/sys v0.0.0-20210806184541-e5e7981a1069/go.mod h1:oPkhp1MJrh7nUepCBc golang.org/x/sys v0.0.0-20210809222454-d867a43fc93e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20210819135213-f52c844e1c1c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20210823070655-63515b42dcdf/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20210906170528-6f6e22806c34/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20210908233432-aa78b53d3365/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20210927094055-39ccf1dd6fa6/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20211025201205-69cdffdb9359/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20211116061358-0a5406a5449c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20211124211545-fe61309f8881/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20211210111614-af8b64212486/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20211216021012-1d35b9e2eb4e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= diff --git a/interchaintest/module_pob_test.go b/interchaintest/module_pob_test.go.archive similarity index 100% rename from interchaintest/module_pob_test.go rename to interchaintest/module_pob_test.go.archive From d5b37503f05070a119a46780c86af6a47b77dba2 Mon Sep 17 00:00:00 2001 From: Reece Williams Date: Tue, 24 Oct 2023 14:24:37 -0500 Subject: [PATCH 79/79] adds back feepay e2e --- .github/workflows/interchaintest-E2E.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.github/workflows/interchaintest-E2E.yml b/.github/workflows/interchaintest-E2E.yml index c08f6c5e9..7c7490624 100644 --- a/.github/workflows/interchaintest-E2E.yml +++ b/.github/workflows/interchaintest-E2E.yml @@ -71,6 +71,7 @@ jobs: - "ictest-unity-gov" - "ictest-pob" - "ictest-drip" + - "ictest-feepay" - "ictest-burn" - "ictest-cwhooks" - "ictest-clock"