diff --git a/README.md b/README.md index 5142f6f..4367912 100644 --- a/README.md +++ b/README.md @@ -4,25 +4,69 @@ eibc-client is a bot designed to continuously scan for eIBC demand orders and fu ## Features -- **Account Setup**: The bot is configured with a Dymension account that can be found in the local keyring. The account is used to fulfill demand orders. +- **Order Scanning**: The bot scans the hub for demand orders that are unfulfilled and have not expired. + - Gets unfulfilled demand orders from the indexer by polling periodically + - Gets orders from events emitted by the Hub for new demand orders. +- **Order Fulfillment Criteria**: + - An order needs to provide the minimum amount of fee earnings to the operator and the LP + - The Rollapp where the order comes needs to be supported by at least one LP + - The Denom of the order needs to be supported by at least one LP + - The order needs to be within the max price of the LP + - The order needs to be within the spend limit of the LP +- **LP Grants Refresh**: The bot periodically refreshes its list of LP grants to ensure it has the most up-to-date LP information. +- **Order Fulfillment**: The bot fulfills unfulfilled pending demand orders it finds on the hub, by sourcing the funds from LPs. +- **Fee/Gas Payment**: The operator grants all the running bot accounts the permission to pay for fees on their behalf. +- **Concurrency**: Run multiple bots concurrently to fulfill orders faster. Also, fulfill multiple orders per transaction. -- **Order Refresh**: The bot periodically refreshes its demand order list to ensure it has the most up-to-date information. -Apart from refreshing the order list, the bot also checks for new orders by subscribing to eIBC events. - -- **Order Fulfillment**: The bot fulfills unfulfilled pending demand orders it finds on the hub. +## Setup -- **Balance Checks**: Every time the bot attempts to fulfill orders it will first check its balances for the denominations it needs to fulfill them. -If it lacks funds for a particular denomination as specified in the order price, it will send an alert by posting a message on Slack, -and will skip trying to fulfill that order until its account is topped up. +To set up the bot, you need to have Go installed on your machine. Once Go is installed, you can clone this repository and run the bot. -- **Gas Payment**: The bot uses DYM coins to pay for gas. If it runs out of DYM coins, it will send an alert by posting a message on Slack, -and will pause all order fulfillments until it is topped up. +- **Operator Setup**: The eibc client will expect certain environment to be set up before it can run. +1. The operator account needs to be set up with some adym coins to pay for gas/fees. + dymd keys add operator +2. A group needs to be created where the operator account is the admin: + + dymd tx group create-group operator --keyring-backend test "==A" members.json --fees 1dym -y + +members.json + ``` + { + "members": [ + { + "address": "", + "weight": "1", "metadata": "president" + } + ] + } + ``` +3. The group needs a policy that can be granted by LPs in order to source funds from them and sign order fulfillment messages on their behalf: + + dymd tx group create-group-policy operator 1 "==A" policy.json --fees 1dym -y + +policy.json +``` +{ + "@type": "/cosmos.group.v1.PercentageDecisionPolicy", + "percentage": "0.0001", + "windows": { + "voting_period": "1s", + "min_execution_period": "0s" + } +} +``` -- **Order Cleanup**: The bot periodically checks and flushes fulfilled demand orders. +4. At least one LP needs to grant authorization to the group to fulfill orders: -## Setup - -To set up the bot, you need to have Go installed on your machine. Once Go is installed, you can clone this repository and run the bot. + dymd tx eibc grant \ + --from lp_key --keyring-backend test \ + --spend-limit 10000adym \ + --rollapp rollapp1 \ + --denoms "adym,uatom" \ + --min-lp-fee-percentage "0.1" \ + --max-price 10000adym \ + --operator-fee-share 0.1 \ + --settlement-validated --fees 1dym -y ## Usage @@ -33,13 +77,5 @@ To run the bot, use the following command: ```bash make install -eibc-client --config -``` - -### Docker - -```bash -make docker-build - -docker run -v :/.eibc-client.yaml eibc-client --config /.eibc-client.yaml +eibc-client start --config ``` diff --git a/account.go b/account.go deleted file mode 100644 index 980c207..0000000 --- a/account.go +++ /dev/null @@ -1,354 +0,0 @@ -package main - -import ( - "context" - "fmt" - "slices" - "strings" - "time" - - "github.com/cosmos/cosmos-sdk/client" - "github.com/cosmos/cosmos-sdk/crypto/keyring" - sdk "github.com/cosmos/cosmos-sdk/types" - "github.com/cosmos/cosmos-sdk/types/tx" - "github.com/cosmos/cosmos-sdk/x/auth/types" - banktypes "github.com/cosmos/cosmos-sdk/x/bank/types" - "github.com/google/uuid" - "go.uber.org/zap" - - "github.com/dymensionxyz/cosmosclient/cosmosclient" - - "github.com/dymensionxyz/eibc-client/store" -) - -type accountService struct { - client cosmosclient.Client - store accountStore - logger *zap.Logger - account client.Account - balances sdk.Coins - minimumGasBalance sdk.Coin - accountName string - topUpFactor int - topUpCh chan<- topUpRequest -} - -type accountStore interface { - GetBot(ctx context.Context, address string, _ ...store.BotOption) (*store.Bot, error) - SaveBot(ctx context.Context, bot *store.Bot) error -} - -type option func(*accountService) - -func withTopUpFactor(topUpFactor int) option { - return func(s *accountService) { - s.topUpFactor = topUpFactor - } -} - -func newAccountService( - client cosmosclient.Client, - store accountStore, - logger *zap.Logger, - accountName string, - minimumGasBalance sdk.Coin, - topUpCh chan topUpRequest, - options ...option, -) (*accountService, error) { - a := &accountService{ - client: client, - store: store, - logger: logger.With(zap.String("module", "account-service")), - accountName: accountName, - minimumGasBalance: minimumGasBalance, - topUpCh: topUpCh, - } - - for _, opt := range options { - opt(a) - } - - if err := a.setupAccount(); err != nil { - return nil, fmt.Errorf("failed to setup account: %w", err) - } - - return a, nil -} - -func addAccount(client cosmosclient.Client, name string) error { - _, err := client.AccountRegistry.GetByName(name) - if err == nil { - return nil - } - - _, _, err = client.AccountRegistry.Create(name) - return err -} - -func getBotAccounts(client cosmosclient.Client) (accs []string, err error) { - var accounts []account - accounts, err = listAccounts(client) - if err != nil { - return - } - - for _, acc := range accounts { - if !strings.HasPrefix(acc.Name, botNamePrefix) { - continue - } - accs = append(accs, acc.Name) - } - return -} - -func listAccounts(client cosmosclient.Client) ([]account, error) { - accs, err := client.AccountRegistry.List() - if err != nil { - return nil, fmt.Errorf("failed to get accounts: %w", err) - } - - var accounts []account - for _, acc := range accs { - addr, err := acc.Record.GetAddress() - if err != nil { - return nil, fmt.Errorf("failed to get account address: %w", err) - } - acct := account{ - Name: acc.Name, - Address: addr.String(), - } - accounts = append(accounts, acct) - } - - return accounts, nil -} - -func createBotAccounts(client cosmosclient.Client, count int) (names []string, err error) { - for range count { - botName := fmt.Sprintf("%s%s", botNamePrefix, uuid.New().String()[0:5]) - if err = addAccount(client, botName); err != nil { - err = fmt.Errorf("failed to create account: %w", err) - return - } - names = append(names, botName) - } - return -} - -// TODO: if not found...? -func (a *accountService) setupAccount() error { - acc, err := a.client.AccountRegistry.GetByName(a.accountName) - if err != nil { - return fmt.Errorf("failed to get account: %w", err) - } - a.account = mustConvertAccount(acc.Record) - - a.logger.Debug("using account", - zap.String("name", a.accountName), - zap.String("pub key", a.account.GetPubKey().String()), - zap.String("address", a.account.GetAddress().String()), - zap.String("keyring-backend", a.client.AccountRegistry.Keyring.Backend()), - zap.String("home-dir", a.client.Context().HomeDir), - ) - return nil -} - -func (a *accountService) ensureBalances(coins sdk.Coins) ([]string, error) { - // check if gas balance is below minimum - gasBalance := a.balanceOf(a.minimumGasBalance.Denom) - gasDiff := a.minimumGasBalance.Amount.Sub(gasBalance) - - toTopUp := sdk.NewCoins() - if gasDiff.IsPositive() { - toTopUp = toTopUp.Add(a.minimumGasBalance) // add the whole amount instead of the difference - } - - fundedDenoms := make([]string, 0, len(coins)) - - // check if balance is below required - for _, coin := range coins { - balance := a.balanceOf(coin.Denom) - diff := coin.Amount.Sub(balance) - if diff.IsPositive() { - // add x times the coin amount to the top up - // to avoid frequent top ups - coin.Amount = coin.Amount.MulRaw(int64(a.topUpFactor)) - toTopUp = toTopUp.Add(coin) // add the whole amount instead of the difference - } else { - fundedDenoms = append(fundedDenoms, coin.Denom) - } - } - - if toTopUp.Empty() { - // shouldn't happen - return fundedDenoms, nil - } - - // blocking operation - resCh := make(chan []string) - topUpReq := topUpRequest{ - coins: toTopUp, - toAddr: a.account.GetAddress().String(), - res: resCh, - } - - a.topUpCh <- topUpReq - res := <-resCh - close(resCh) - - fundedDenoms = slices.Concat(fundedDenoms, res) - return fundedDenoms, nil -} - -func (a *accountService) sendCoins(coins sdk.Coins, toAddrStr string) error { - toAddr, err := sdk.AccAddressFromBech32(toAddrStr) - if err != nil { - return fmt.Errorf("failed to parse address: %w", err) - } - - msg := banktypes.NewMsgSend( - a.account.GetAddress(), - toAddr, - coins, - ) - start := time.Now() - - rsp, err := a.client.BroadcastTx(a.accountName, msg) - if err != nil { - return fmt.Errorf("failed to broadcast tx: %w", err) - } - - if err = a.WaitForTx(rsp.TxHash); err != nil { - return fmt.Errorf("failed to wait for tx: %w", err) - } - - a.logger.Debug("coins sent", zap.String("to", toAddrStr), zap.Duration("duration", time.Since(start))) - - return nil -} - -func (a *accountService) WaitForTx(txHash string) error { - serviceClient := tx.NewServiceClient(a.client.Context()) - ctx, cancel := context.WithTimeout(context.Background(), 20*time.Second) - ticker := time.NewTicker(time.Second) - - defer func() { - cancel() - ticker.Stop() - }() - - for { - select { - case <-ctx.Done(): - return fmt.Errorf("timed out waiting for tx %s", txHash) - case <-ticker.C: - resp, err := serviceClient.GetTx(ctx, &tx.GetTxRequest{Hash: txHash}) - if err != nil { - continue - } - if resp.TxResponse.Code == 0 { - return nil - } else { - return fmt.Errorf("tx failed with code %d: %s", resp.TxResponse.Code, resp.TxResponse.RawLog) - } - } - } -} - -func (a *accountService) balanceOf(denom string) sdk.Int { - return a.balances.AmountOf(denom) -} - -type fundsOption func(*fundsRequest) - -type fundsRequest struct { - rewards []string -} - -func addRewards(rewards ...string) fundsOption { - return func(r *fundsRequest) { - r.rewards = rewards - } -} - -func (a *accountService) refreshBalances(ctx context.Context) error { - balances, err := a.getAccountBalances(ctx) - if err != nil { - return fmt.Errorf("failed to get account balances: %w", err) - } - a.balances = balances - return nil -} - -func (a *accountService) updateFunds(ctx context.Context, opts ...fundsOption) error { - if err := a.refreshBalances(ctx); err != nil { - return fmt.Errorf("failed to refresh account balances: %w", err) - } - - b, err := a.store.GetBot(ctx, a.account.GetAddress().String()) - if err != nil { - return fmt.Errorf("failed to get bot: %w", err) - } - if b == nil { - b = &store.Bot{ - Address: a.account.GetAddress().String(), - Name: a.accountName, - } - } - - b.Balances = make([]string, 0, len(a.balances)) - for _, balance := range a.balances { - b.Balances = append(b.Balances, balance.String()) - } - - pendingRewards := b.PendingRewards.ToCoins() - - req := &fundsRequest{} - for _, opt := range opts { - opt(req) - } - - if len(req.rewards) > 0 { - for _, r := range req.rewards { - pr, err := sdk.ParseCoinNormalized(r) - if err != nil { - return fmt.Errorf("failed to parse reward coin: %w", err) - } - pendingRewards = pendingRewards.Add(pr) - } - - b.PendingRewards = store.CoinsToStrings(pendingRewards) - } - - if err := a.store.SaveBot(ctx, b); err != nil { - return fmt.Errorf("failed to update bot: %w", err) - } - - return nil -} - -func (a *accountService) address() string { - return a.account.GetAddress().String() -} - -func (a *accountService) getAccountBalances(ctx context.Context) (sdk.Coins, error) { - resp, err := banktypes.NewQueryClient(a.client.Context()).SpendableBalances(ctx, &banktypes.QuerySpendableBalancesRequest{ - Address: a.account.GetAddress().String(), - }) - if err != nil { - return nil, err - } - return resp.Balances, nil -} - -func mustConvertAccount(rec *keyring.Record) client.Account { - address, err := rec.GetAddress() - if err != nil { - panic(fmt.Errorf("failed to get account address: %w", err)) - } - pubKey, err := rec.GetPubKey() - if err != nil { - panic(fmt.Errorf("failed to get account pubkey: %w", err)) - } - return types.NewBaseAccount(address, pubKey, 0, 0) -} diff --git a/alert.go b/alert.go deleted file mode 100644 index c14198d..0000000 --- a/alert.go +++ /dev/null @@ -1,71 +0,0 @@ -package main - -import ( - "context" - "fmt" - "time" - - sdk "github.com/cosmos/cosmos-sdk/types" - "github.com/slack-go/slack" - "go.uber.org/zap" -) - -type slacker struct { - *slack.Client // TODO: abstract this out - channelID string - enabled bool - logger *zap.Logger -} - -func newSlacker(config slackConfig, logger *zap.Logger) *slacker { - return &slacker{ - Client: slack.New(config.AppToken), - channelID: config.ChannelID, - enabled: config.Enabled, - logger: logger.With(zap.String("module", "slack")), - } -} - -func (oc *slacker) begOnSlack( - ctx context.Context, - address string, - coin, balance sdk.Coin, - chainID, node string, -) (string, error) { - if !oc.enabled { - oc.logger.Debug("Slack is disabled") - return "", nil - } - - oc.logger.With( - zap.String("amount", coin.String()), - zap.String("balance", balance.String()), - zap.String("address", address), - ).Debug("Slack post @poor-bots") - - message := fmt.Sprintf("Please sir, send %s to my account %s. I'm on chain '%s', on node %s and I only have %s.", - coin.String(), address, chainID, node, balance.String()) - - respChannel, respTimestamp, err := oc.PostMessageContext( - ctx, - oc.channelID, - slack.MsgOptionText(message, false), - ) - if err != nil { - return "", err - } - - oc.logger.With( - zap.String("channel", respChannel), - zap.String("timestamp", respTimestamp), - ).Debug("Slack message successfully sent") - - time.Sleep(time.Second * 5) - - _, _, _ = oc.PostMessageContext( - ctx, - oc.channelID, - slack.MsgOptionText("I can wait...", false), - ) - return respTimestamp, nil -} diff --git a/cmd.go b/cmd.go deleted file mode 100644 index e74c94d..0000000 --- a/cmd.go +++ /dev/null @@ -1,338 +0,0 @@ -package main - -import ( - "fmt" - "log" - "os" - "strconv" - "strings" - - sdk "github.com/cosmos/cosmos-sdk/types" - "github.com/mitchellh/go-homedir" - "github.com/spf13/cobra" - "github.com/spf13/viper" - - "github.com/dymensionxyz/eibc-client/cmd/version" - "github.com/dymensionxyz/eibc-client/store" - utils "github.com/dymensionxyz/eibc-client/utils/viper" -) - -var rootCmd = &cobra.Command{ - Use: "eibc-client", - Short: "eIBC Order client for Dymension Hub", - Long: `Order client for Dymension Hub that scans for demand orders and fulfills them.`, - Run: func(cmd *cobra.Command, args []string) { - // If no arguments are provided, print usage information - if len(args) == 0 { - if err := cmd.Usage(); err != nil { - log.Fatalf("Error printing usage: %v", err) - } - } - }, -} - -var initCmd = &cobra.Command{ - Use: "init", - Short: "Initialize the order client", - Long: `Initialize the order client by generating a config file with default values.`, - Run: func(cmd *cobra.Command, args []string) { - config := Config{} - if err := viper.Unmarshal(&config); err != nil { - log.Fatalf("failed to unmarshal config: %v", err) - } - - // if home dir doesn't exist, create it - if _, err := os.Stat(config.HomeDir); os.IsNotExist(err) { - if err := os.MkdirAll(config.HomeDir, 0o755); err != nil { - log.Fatalf("failed to create home directory: %v", err) - } - } - - if err := viper.WriteConfigAs(cfgFile); err != nil { - log.Fatalf("failed to write config file: %v", err) - } - - fmt.Printf("Config file created: %s\n", cfgFile) - fmt.Println() - fmt.Println("Edit the config file to set the correct values for your environment.") - }, -} - -var startCmd = &cobra.Command{ - Use: "start", - Short: "Start the order client", - Long: `Start the order client that scans for demand orders and fulfills them.`, - Run: func(cmd *cobra.Command, args []string) { - viper.AutomaticEnv() - - if err := viper.ReadInConfig(); err == nil { - fmt.Println("Using config file:", viper.ConfigFileUsed()) - } - - config := Config{} - if err := viper.Unmarshal(&config); err != nil { - log.Fatalf("failed to unmarshal config: %v", err) - } - - log.Printf("using config file: %+v", viper.ConfigFileUsed()) - - oc, err := newOrderClient(cmd.Context(), config) - if err != nil { - log.Fatalf("failed to create order client: %v", err) - } - - if config.Bots.NumberOfBots == 0 { - log.Println("no bots to start") - return - } - - if err := oc.start(cmd.Context()); err != nil { - log.Fatalf("failed to start order client: %v", err) - } - }, -} - -var balancesCmd = &cobra.Command{ - Use: "funds", - Short: "Get account funds", - Long: `Get account balances and pending rewards for the configured whale account and the bot accounts.`, - Run: func(cmd *cobra.Command, args []string) { - viper.AutomaticEnv() - - if err := viper.ReadInConfig(); err == nil { - fmt.Println("Using config file:", viper.ConfigFileUsed()) - } - - config := Config{} - if err := viper.Unmarshal(&config); err != nil { - log.Fatalf("failed to unmarshal config: %v", err) - } - - config.SkipRefund = true - - oc, err := newOrderClient(cmd.Context(), config) - if err != nil { - log.Fatalf("failed to create order client: %v", err) - } - - defer oc.orderTracker.store.Close() - - if err := oc.whale.accountSvc.refreshBalances(cmd.Context()); err != nil { - log.Fatalf("failed to refresh whale account balances: %v", err) - } - - longestAmountStr := 0 - - for _, bal := range oc.whale.accountSvc.balances { - amtStr := formatAmount(bal.Amount.String()) - if len(amtStr) > longestAmountStr { - longestAmountStr = len(amtStr) - } - } - - fmt.Println() - fmt.Println("Bots Funds:") - - bots, err := oc.orderTracker.store.GetBots(cmd.Context(), store.OnlyWithFunds()) - if err != nil { - log.Fatalf("failed to get bots from db: %v", err) - } - - for _, b := range bots { - balances, err := sdk.ParseCoinsNormalized(strings.Join(b.Balances, ",")) - if err != nil { - log.Fatalf("failed to parse balance: %v", err) - } - - pendingRewards, err := sdk.ParseCoinsNormalized(strings.Join(b.PendingRewards, ",")) - if err != nil { - log.Fatalf("failed to parse pending rewards: %v", err) - } - - for _, bal := range balances { - if len(bal.Amount.String()) > longestAmountStr { - longestAmountStr = len(bal.Amount.String()) - } - } - - for _, pr := range pendingRewards { - if len(pr.Amount.String()) > longestAmountStr { - longestAmountStr = len(pr.Amount.String()) - } - } - } - - maxDen := 68 - - dividerItem := "" - dividerFunds := "" - - for i := 0; i < longestAmountStr+maxDen+3; i++ { - dividerItem += "=" - dividerFunds += "-" - } - - totalBalances := sdk.NewCoins(oc.whale.accountSvc.balances...) - totalPendingRewards := sdk.NewCoins() - - i := 0 - for _, b := range bots { - i++ - - balances, err := sdk.ParseCoinsNormalized(strings.Join(b.Balances, ",")) - if err != nil { - log.Fatalf("failed to parse balance: %v", err) - } - - pendingRewards, err := sdk.ParseCoinsNormalized(strings.Join(b.PendingRewards, ",")) - if err != nil { - log.Fatalf("failed to parse pending rewards: %v", err) - } - - totalBalances = totalBalances.Add(balances...) - totalPendingRewards = totalPendingRewards.Add(pendingRewards...) - - if !balances.IsZero() { - accPref := fmt.Sprintf("%d. | '%s': ", i, b.Name) - printAccountSlot(b.Address, accPref, dividerItem) - fmt.Println("Balances:") - printBalances(balances, longestAmountStr, maxDen) - fmt.Println() - } - - if !pendingRewards.IsZero() { - fmt.Println("Pending Rewards:") - fmt.Println(dividerFunds) - printBalances(pendingRewards, longestAmountStr, maxDen) - } - } - - fmt.Println() - fmt.Println("Whale Balances:") - - if !oc.whale.accountSvc.balances.IsZero() { - accPref := fmt.Sprintf("Whale | '%s': ", oc.whale.accountSvc.accountName) - printAccountSlot( - oc.whale.accountSvc.account.GetAddress().String(), - accPref, - dividerItem, - ) - printBalances(oc.whale.accountSvc.balances, longestAmountStr, maxDen) - fmt.Println() - } - - fmt.Println() - fmt.Println("Total:") - fmt.Println(dividerItem) - fmt.Println("Balances:") - printBalances(totalBalances, longestAmountStr, maxDen) - - fmt.Println(dividerFunds) - fmt.Println("Pending Rewards:") - printBalances(totalPendingRewards, longestAmountStr, maxDen) - }, -} - -var scaleCmd = &cobra.Command{ - Use: "scale [count]", - Short: "scale bot count", - Long: `scale the number of bot accounts that fulfill the eibc orders`, - Args: cobra.ExactArgs(1), - Run: func(cmd *cobra.Command, args []string) { - newBotCount, err := strconv.Atoi(args[0]) - if err != nil { - return - } - - home, err := homedir.Dir() - if err != nil { - log.Fatalf("failed to get home directory: %v", err) - } - - defaultHomeDir := home + "/.eibc-client" - cfgFile = defaultHomeDir + "/config.yaml" - - viper.SetConfigFile(cfgFile) - err = viper.ReadInConfig() - if err != nil { - return - } - - err = utils.UpdateViperConfig("bots.number_of_bots", newBotCount, viper.ConfigFileUsed()) - if err != nil { - return - } - - fmt.Printf( - "bot count successfully scaled to %d, please restart the eibc process if it's running\n", - newBotCount, - ) - }, -} - -func printAccountSlot(address string, accPref, dividerItem string) { - dividerAcc := "" - - fmt.Printf("%s", dividerItem) - - accLine := fmt.Sprintf("\n %s%s |", accPref, address) - for i := 0; i < len(accLine)-1; i++ { - dividerAcc += "-" - } - fmt.Printf("%s\n", accLine) - fmt.Printf("%s\n", dividerAcc) -} - -func printBalances(balances sdk.Coins, maxBal, maxDen int) { - dividerBal, dividerDen := "", "" - - for i := 0; i < maxBal; i++ { - dividerBal += "-" - } - - for i := 0; i < maxDen; i++ { - dividerDen += "-" - } - - fmt.Printf("%*s | Denom\n", maxBal, "Amount") - fmt.Printf("%*s | %s\n", maxBal, dividerBal, dividerDen) - - for _, bl := range balances { - amtStr := bl.Amount.String() - - if bl.Denom == "adym" { - amtStr = formatAmount(bl.Amount.String()) - bl.Denom = "dym" - } - fmt.Printf("%*s | %-s\n", maxBal, amtStr, bl.Denom) - } -} - -func formatAmount(numStr string) string { - if len(numStr) <= 18 { - return "0," + strings.Repeat("0", 18-len(numStr)) + numStr - } - return numStr[:len(numStr)-18] + "," + numStr[len(numStr)-18:] -} - -var cfgFile string - -func init() { - rootCmd.CompletionOptions.DisableDefaultCmd = true - rootCmd.AddCommand(initCmd) - rootCmd.AddCommand(startCmd) - rootCmd.AddCommand(scaleCmd) - - balancesCmd.Flags().BoolP("all", "a", false, "Filter by fulfillment status") - rootCmd.AddCommand(balancesCmd) - - rootCmd.AddCommand(version.Cmd()) - - cobra.OnInitialize(initConfig) - - rootCmd.PersistentFlags().StringVar(&cfgFile, "config", "", "config file") - - // Cobra also supports local flags, which will only run - // when this action is called directly. - rootCmd.Flags().BoolP("toggle", "t", false, "Help message for toggle") -} diff --git a/cmd/cmd.go b/cmd/cmd.go new file mode 100644 index 0000000..fd549d6 --- /dev/null +++ b/cmd/cmd.go @@ -0,0 +1,186 @@ +package cmd + +import ( + "fmt" + "log" + "os" + "strconv" + + "github.com/mitchellh/go-homedir" + "github.com/spf13/cobra" + "github.com/spf13/viper" + "go.uber.org/zap" + "go.uber.org/zap/zapcore" + + "github.com/dymensionxyz/eibc-client/config" + "github.com/dymensionxyz/eibc-client/eibc" + utils "github.com/dymensionxyz/eibc-client/utils/viper" + "github.com/dymensionxyz/eibc-client/version" +) + +var RootCmd = &cobra.Command{ + Use: "eibc-client", + Short: "eIBC Order client for Dymension Hub", + Long: `Order client for Dymension Hub that scans for demand orders and fulfills them.`, + Run: func(cmd *cobra.Command, args []string) { + // If no arguments are provided, print usage information + if len(args) == 0 { + if err := cmd.Usage(); err != nil { + log.Fatalf("Error printing usage: %v", err) + } + } + }, +} + +var initCmd = &cobra.Command{ + Use: "init", + Short: "Initialize the order client", + Long: `Initialize the order client by generating a config file with default values.`, + Run: func(cmd *cobra.Command, args []string) { + cfg := config.Config{} + if err := viper.Unmarshal(&cfg); err != nil { + log.Fatalf("failed to unmarshal config: %v", err) + } + + // if bot key dir doesn't exist, create it + if _, err := os.Stat(cfg.Bots.KeyringDir); os.IsNotExist(err) { + if err := os.MkdirAll(cfg.Bots.KeyringDir, 0o755); err != nil { + log.Fatalf("failed to create bot key directory: %v", err) + } + } + + if err := viper.WriteConfigAs(config.CfgFile); err != nil { + log.Fatalf("failed to write config file: %v", err) + } + + fmt.Printf("Config file created: %s\n", config.CfgFile) + fmt.Println() + fmt.Println("Edit the config file to set the correct values for your environment.") + }, +} + +var startCmd = &cobra.Command{ + Use: "start", + Short: "Start the order client", + Long: `Start the order client that scans for demand orders and fulfills them.`, + Run: func(cmd *cobra.Command, args []string) { + viper.AutomaticEnv() + + if err := viper.ReadInConfig(); err == nil { + fmt.Println("Using config file:", viper.ConfigFileUsed()) + } + + cfg := config.Config{} + if err := viper.Unmarshal(&cfg); err != nil { + log.Fatalf("failed to unmarshal config: %v", err) + } + + if !cfg.Validation.FallbackLevel.Validate() { + log.Fatalf("invalid fallback validation level: %s", cfg.Validation.FallbackLevel) + } + + log.Printf("using config file: %+v", viper.ConfigFileUsed()) + + logger, err := buildLogger(cfg.LogLevel) + if err != nil { + log.Fatalf("failed to build logger: %v", err) + } + + // Ensure all logs are written + defer logger.Sync() // nolint: errcheck + + oc, err := eibc.NewOrderClient(cfg, logger) + if err != nil { + log.Fatalf("failed to create order client: %v", err) + } + + if cfg.Bots.NumberOfBots == 0 { + log.Println("no bots to start") + return + } + + if err := oc.Start(cmd.Context()); err != nil { + log.Fatalf("failed to start order client: %v", err) + } + }, +} + +func buildLogger(logLevel string) (*zap.Logger, error) { + var level zapcore.Level + if err := level.Set(logLevel); err != nil { + return nil, fmt.Errorf("failed to set log level: %w", err) + } + + encoderConfig := zap.NewProductionEncoderConfig() + encoderConfig.EncodeTime = zapcore.ISO8601TimeEncoder + + logger := zap.New(zapcore.NewCore( + zapcore.NewJSONEncoder(encoderConfig), + zapcore.Lock(os.Stdout), + level, + )) + + return logger, nil +} + +var scaleCmd = &cobra.Command{ + Use: "scale [count]", + Short: "scale bot count", + Long: `scale the number of bot accounts that fulfill the eibc orders`, + Args: cobra.ExactArgs(1), + Run: func(cmd *cobra.Command, args []string) { + newBotCount, err := strconv.Atoi(args[0]) + if err != nil { + return + } + + home, err := homedir.Dir() + if err != nil { + log.Fatalf("failed to get home directory: %v", err) + } + + defaultHomeDir := home + "/.eibc-client" + config.CfgFile = defaultHomeDir + "/config.yaml" + + viper.SetConfigFile(config.CfgFile) + err = viper.ReadInConfig() + if err != nil { + return + } + + err = utils.UpdateViperConfig("bots.number_of_bots", newBotCount, viper.ConfigFileUsed()) + if err != nil { + return + } + + fmt.Printf( + "bot count successfully scaled to %d, please restart the eibc process if it's running\n", + newBotCount, + ) + }, +} + +var versionCmd = &cobra.Command{ + Use: "version", + Short: "Print the version of roller", + Run: func(cmd *cobra.Command, args []string) { + fmt.Println(version.BuildVersion) + }, +} + +func init() { + RootCmd.CompletionOptions.DisableDefaultCmd = true + RootCmd.AddCommand(initCmd) + RootCmd.AddCommand(startCmd) + RootCmd.AddCommand(scaleCmd) + + RootCmd.AddCommand(versionCmd) + + cobra.OnInitialize(config.InitConfig) + + RootCmd.PersistentFlags().StringVar(&config.CfgFile, "config", "", "config file") + + // Cobra also supports local flags, which will only run + // when this action is called directly. + RootCmd.Flags().BoolP("toggle", "t", false, "Help message for toggle") +} diff --git a/cmd/version/version.go b/cmd/version/version.go deleted file mode 100644 index cc12248..0000000 --- a/cmd/version/version.go +++ /dev/null @@ -1,20 +0,0 @@ -package version - -import ( - "fmt" - - "github.com/spf13/cobra" - - "github.com/dymensionxyz/eibc-client/version" -) - -func Cmd() *cobra.Command { - versionCmd := &cobra.Command{ - Use: "version", - Short: "Print the version of roller", - Run: func(cmd *cobra.Command, args []string) { - fmt.Println(version.BuildVersion) - }, - } - return versionCmd -} diff --git a/config.go b/config.go deleted file mode 100644 index 1c796ef..0000000 --- a/config.go +++ /dev/null @@ -1,160 +0,0 @@ -package main - -import ( - "log" - "time" - - "github.com/dymensionxyz/cosmosclient/cosmosclient" - "github.com/ignite/cli/ignite/pkg/cosmosaccount" - "github.com/mitchellh/go-homedir" - "github.com/spf13/viper" -) - -type Config struct { - HomeDir string `mapstructure:"home_dir"` - NodeAddress string `mapstructure:"node_address"` - DBPath string `mapstructure:"db_path"` - Gas GasConfig `mapstructure:"gas"` - OrderPolling OrderPollingConfig `mapstructure:"order_polling"` - - Whale whaleConfig `mapstructure:"whale"` - Bots botConfig `mapstructure:"bots"` - FulfillCriteria fulfillCriteria `mapstructure:"fulfill_criteria"` - - LogLevel string `mapstructure:"log_level"` - SlackConfig slackConfig `mapstructure:"slack"` - SkipRefund bool `mapstructure:"skip_refund"` -} - -type OrderPollingConfig struct { - IndexerURL string `mapstructure:"indexer_url"` - Interval time.Duration `mapstructure:"interval"` - Enabled bool `mapstructure:"enabled"` -} - -type GasConfig struct { - Prices string `mapstructure:"prices"` - Fees string `mapstructure:"fees"` - MinimumGasBalance string `mapstructure:"minimum_gas_balance"` -} - -type botConfig struct { - NumberOfBots int `mapstructure:"number_of_bots"` - KeyringBackend cosmosaccount.KeyringBackend `mapstructure:"keyring_backend"` - KeyringDir string `mapstructure:"keyring_dir"` - TopUpFactor int `mapstructure:"top_up_factor"` - MaxOrdersPerTx int `mapstructure:"max_orders_per_tx"` -} - -type whaleConfig struct { - AccountName string `mapstructure:"account_name"` - KeyringBackend cosmosaccount.KeyringBackend `mapstructure:"keyring_backend"` - KeyringDir string `mapstructure:"keyring_dir"` - AllowedBalanceThresholds map[string]string `mapstructure:"allowed_balance_thresholds"` -} - -type fulfillCriteria struct { - MinFeePercentage minFeePercentage `mapstructure:"min_fee_percentage"` -} - -type minFeePercentage struct { - Chain map[string]float32 `mapstructure:"chain"` - Asset map[string]float32 `mapstructure:"asset"` -} - -type slackConfig struct { - Enabled bool `mapstructure:"enabled"` - BotToken string `mapstructure:"bot_token"` - AppToken string `mapstructure:"app_token"` - ChannelID string `mapstructure:"channel_id"` -} - -const ( - defaultNodeAddress = "http://localhost:36657" - defaultDBPath = "mongodb://localhost:27017" - hubAddressPrefix = "dym" - pubKeyPrefix = "pub" - defaultLogLevel = "info" - defaultHubDenom = "adym" - defaultGasFees = "3000000000000000" + defaultHubDenom - defaultMinimumGasBalance = "1000000000000000000" + defaultHubDenom - testKeyringBackend = "test" - - botNamePrefix = "bot-" - defaultWhaleAccountName = "client" - defaultBotTopUpFactor = 5 - defaultNumberOfBots = 30 - newOrderBufferSize = 100 - defaultMaxOrdersPerTx = 10 - defaultOrderRefreshInterval = 30 * time.Second -) - -var defaultBalanceThresholds = map[string]string{defaultHubDenom: "1000000000000"} - -func initConfig() { - // Set default values - // Find home directory. - home, err := homedir.Dir() - if err != nil { - log.Fatalf("failed to get home directory: %v", err) - } - defaultHomeDir := home + "/.eibc-client" - - viper.SetDefault("log_level", defaultLogLevel) - viper.SetDefault("home_dir", defaultHomeDir) - viper.SetDefault("node_address", defaultNodeAddress) - viper.SetDefault("db_path", defaultDBPath) - - viper.SetDefault("order_polling.interval", defaultOrderRefreshInterval) - viper.SetDefault("order_polling.enabled", false) - - viper.SetDefault("gas.fees", defaultGasFees) - viper.SetDefault("gas.minimum_gas_balance", defaultMinimumGasBalance) - - viper.SetDefault("whale.account_name", defaultWhaleAccountName) - viper.SetDefault("whale.keyring_backend", testKeyringBackend) - viper.SetDefault("whale.allowed_balance_thresholds", defaultBalanceThresholds) - viper.SetDefault("whale.keyring_dir", defaultHomeDir) - - viper.SetDefault("bots.keyring_backend", testKeyringBackend) - viper.SetDefault("bots.keyring_dir", defaultHomeDir) - viper.SetDefault("bots.number_of_bots", defaultNumberOfBots) - viper.SetDefault("bots.top_up_factor", defaultBotTopUpFactor) - viper.SetDefault("bots.max_orders_per_tx", defaultMaxOrdersPerTx) - - viper.SetDefault("slack.enabled", false) - viper.SetDefault("slack.app_token", "") - viper.SetDefault("slack.channel_id", "") - - viper.SetConfigType("yaml") - if cfgFile != "" { - // Use config file from the flag. - viper.SetConfigFile(cfgFile) - } else { - cfgFile = defaultHomeDir + "/config.yaml" - viper.AddConfigPath(defaultHomeDir) - viper.AddConfigPath(".") - viper.SetConfigName("config") - } -} - -type clientConfig struct { - homeDir string - nodeAddress string - gasFees string - gasPrices string - keyringBackend cosmosaccount.KeyringBackend -} - -func getCosmosClientOptions(config clientConfig) []cosmosclient.Option { - options := []cosmosclient.Option{ - cosmosclient.WithAddressPrefix(hubAddressPrefix), - cosmosclient.WithHome(config.homeDir), - cosmosclient.WithNodeAddress(config.nodeAddress), - cosmosclient.WithFees(config.gasFees), - cosmosclient.WithGasPrices(config.gasPrices), - cosmosclient.WithKeyringBackend(config.keyringBackend), - cosmosclient.WithKeyringDir(config.homeDir), - } - return options -} diff --git a/config/config.go b/config/config.go new file mode 100644 index 0000000..b08f24f --- /dev/null +++ b/config/config.go @@ -0,0 +1,163 @@ +package config + +import ( + "log" + "time" + + "github.com/ignite/cli/ignite/pkg/cosmosaccount" + "github.com/mitchellh/go-homedir" + "github.com/spf13/viper" + + "github.com/dymensionxyz/cosmosclient/cosmosclient" +) + +type Config struct { + NodeAddress string `mapstructure:"node_address"` + Gas GasConfig `mapstructure:"gas"` + OrderPolling OrderPollingConfig `mapstructure:"order_polling"` + Rollapps map[string]RollappConfig `mapstructure:"rollapps"` + + Operator OperatorConfig `mapstructure:"operator"` + Bots BotConfig `mapstructure:"bots"` + Validation ValidationConfig `mapstructure:"validation"` + + LogLevel string `mapstructure:"log_level"` +} + +type OrderPollingConfig struct { + IndexerURL string `mapstructure:"indexer_url"` + Interval time.Duration `mapstructure:"interval"` + Enabled bool `mapstructure:"enabled"` +} + +type GasConfig struct { + Prices string `mapstructure:"prices"` + Fees string `mapstructure:"fees"` +} + +type BotConfig struct { + NumberOfBots int `mapstructure:"number_of_bots"` + OperatorAddress string `mapstructure:"operator_address"` + PolicyAddress string `mapstructure:"policy_address"` + KeyringBackend cosmosaccount.KeyringBackend `mapstructure:"keyring_backend"` + KeyringDir string `mapstructure:"keyring_dir"` + MaxOrdersPerTx int `mapstructure:"max_orders_per_tx"` +} + +type OperatorConfig struct { + AccountName string `mapstructure:"account_name"` + KeyringBackend cosmosaccount.KeyringBackend `mapstructure:"keyring_backend"` + KeyringDir string `mapstructure:"keyring_dir"` + GroupID int `mapstructure:"group_id"` + MinFeeShare string `mapstructure:"min_fee_share"` +} + +type ValidationConfig struct { + FallbackLevel ValidationLevel `mapstructure:"fallback_level"` + ValidationWaitTime time.Duration `mapstructure:"validation_wait_time"` +} + +type RollappConfig struct { + FullNodes []string `mapstructure:"full_nodes"` + MinConfirmations int `mapstructure:"min_confirmations"` +} + +const ( + defaultNodeAddress = "http://localhost:36657" + defaultDBPath = "mongodb://localhost:27017" + HubAddressPrefix = "dym" + PubKeyPrefix = "pub" + defaultLogLevel = "info" + defaultHubDenom = "adym" + defaultGasFees = "3000000000000000" + defaultHubDenom + testKeyringBackend = "test" + + BotNamePrefix = "bot-" + defaultOperatorAccountName = "client" + defaultNumberOfBots = 30 + NewOrderBufferSize = 100 + defaultMaxOrdersPerTx = 10 + defaultOrderRefreshInterval = 30 * time.Second +) + +type ValidationLevel string + +const ( + ValidationModeSequencer ValidationLevel = "sequencer" + ValidationModeP2P ValidationLevel = "p2p" + ValidationModeSettlement ValidationLevel = "settlement" +) + +func (f ValidationLevel) Validate() bool { + return f == ValidationModeSequencer || f == ValidationModeP2P || f == ValidationModeSettlement +} + +func InitConfig() { + // Set default values + // Find home directory. + home, err := homedir.Dir() + if err != nil { + log.Fatalf("failed to get home directory: %v", err) + } + defaultHomeDir := home + "/.eibc-client" + + viper.SetDefault("server_address", ":8000") + viper.SetDefault("log_level", defaultLogLevel) + viper.SetDefault("node_address", defaultNodeAddress) + viper.SetDefault("db_path", defaultDBPath) + + viper.SetDefault("order_polling.interval", defaultOrderRefreshInterval) + viper.SetDefault("order_polling.enabled", false) + + viper.SetDefault("gas.fees", defaultGasFees) + + viper.SetDefault("operator.account_name", defaultOperatorAccountName) + viper.SetDefault("operator.keyring_backend", testKeyringBackend) + viper.SetDefault("operator.keyring_dir", defaultHomeDir) + + viper.SetDefault("bots.keyring_backend", testKeyringBackend) + viper.SetDefault("bots.keyring_dir", defaultHomeDir) + viper.SetDefault("bots.number_of_bots", defaultNumberOfBots) + viper.SetDefault("bots.max_orders_per_tx", defaultMaxOrdersPerTx) + + viper.SetDefault("slack.enabled", false) + viper.SetDefault("slack.app_token", "") + viper.SetDefault("slack.channel_id", "") + + viper.SetConfigType("yaml") + if CfgFile != "" { + // Use config file from the flag. + viper.SetConfigFile(CfgFile) + } else { + CfgFile = defaultHomeDir + "/config.yaml" + viper.AddConfigPath(defaultHomeDir) + viper.AddConfigPath(".") + viper.SetConfigName("config") + } +} + +var CfgFile string + +type ClientConfig struct { + HomeDir string + NodeAddress string + GasFees string + GasPrices string + FeeGranter string + KeyringBackend cosmosaccount.KeyringBackend +} + +func GetCosmosClientOptions(config ClientConfig) []cosmosclient.Option { + options := []cosmosclient.Option{ + cosmosclient.WithAddressPrefix(HubAddressPrefix), + cosmosclient.WithHome(config.HomeDir), + cosmosclient.WithNodeAddress(config.NodeAddress), + cosmosclient.WithFees(config.GasFees), + cosmosclient.WithGas(cosmosclient.GasAuto), + cosmosclient.WithGasPrices(config.GasPrices), + cosmosclient.WithKeyringBackend(config.KeyringBackend), + cosmosclient.WithKeyringDir(config.HomeDir), + cosmosclient.WithFeeGranter(config.FeeGranter), + } + return options +} diff --git a/docker-compose.yml b/docker-compose.yml deleted file mode 100644 index 3c5f30f..0000000 --- a/docker-compose.yml +++ /dev/null @@ -1,47 +0,0 @@ -version: "3.9" - -services: - eibc-init: - build: - context: . - dockerfile: ./Dockerfile - command: ["./eibc-client", "init"] - volumes: - - ${CONFIG_PATH}:/app/config.yaml - - ${KEYRING_DIR}:/app/.eibc-client - - eibc-start: - build: - context: . - dockerfile: ./Dockerfile - depends_on: - - db - environment: - - DB_PATH=mongodb://db:27017 - command: ["./eibc-client", "start", "--config", "/app/config.yaml"] - volumes: - - ${CONFIG_PATH}:/app/config.yaml - - ${KEYRING_DIR}:/app/.eibc-client - - eibc-funds: - build: - context: . - dockerfile: ./Dockerfile - depends_on: - - db - environment: - - DB_PATH=mongodb://db:27017 - command: ["./eibc-client", "funds", "--config", "/app/config.yaml"] - volumes: - - ${CONFIG_PATH}:/app/config.yaml - - ${KEYRING_DIR}:/app/.eibc-client - - db: - image: mongo:7.0 - ports: - - "27017:27017" - volumes: - - mongodb_data:/data/db - -volumes: - mongodb_data: diff --git a/eibc/account.go b/eibc/account.go new file mode 100644 index 0000000..f3113bf --- /dev/null +++ b/eibc/account.go @@ -0,0 +1,344 @@ +package eibc + +import ( + "context" + "fmt" + "slices" + "strings" + "time" + + "github.com/cosmos/cosmos-sdk/client" + sdk "github.com/cosmos/cosmos-sdk/types" + "github.com/cosmos/cosmos-sdk/types/tx" + authtypes "github.com/cosmos/cosmos-sdk/x/auth/types" + banktypes "github.com/cosmos/cosmos-sdk/x/bank/types" + "github.com/cosmos/cosmos-sdk/x/feegrant" + "github.com/cosmos/cosmos-sdk/x/group" + "github.com/google/uuid" + "go.uber.org/zap" + "google.golang.org/grpc/status" + + "github.com/dymensionxyz/cosmosclient/cosmosclient" + + "github.com/dymensionxyz/eibc-client/config" +) + +func addAccount(client cosmosclient.Client, name string) (string, error) { + acc, err := client.AccountRegistry.GetByName(name) + if err == nil { + address, err := acc.Record.GetAddress() + if err != nil { + return "", fmt.Errorf("failed to get account address: %w", err) + } + return address.String(), nil + } + + acc, _, err = client.AccountRegistry.Create(name) + if err != nil { + return "", fmt.Errorf("failed to create account: %w", err) + } + + address, err := acc.Record.GetAddress() + if err != nil { + return "", fmt.Errorf("failed to get account address: %w", err) + } + return address.String(), nil +} + +func getBotAccounts(client cosmosclient.Client) (accs []account, err error) { + var accounts []account + accounts, err = listAccounts(client) + if err != nil { + return + } + + for _, acc := range accounts { + if !strings.HasPrefix(acc.Name, config.BotNamePrefix) { + continue + } + accs = append(accs, acc) + } + return +} + +func listAccounts(client cosmosclient.Client) ([]account, error) { + accs, err := client.AccountRegistry.List() + if err != nil { + return nil, fmt.Errorf("failed to get accounts: %w", err) + } + + var accounts []account + for _, acc := range accs { + addr, err := acc.Record.GetAddress() + if err != nil { + return nil, fmt.Errorf("failed to get account address: %w", err) + } + acct := account{ + Name: acc.Name, + Address: addr.String(), + } + accounts = append(accounts, acct) + } + + return accounts, nil +} + +func createBotAccounts(client cosmosclient.Client, count int) (accs []account, err error) { + for range count { + botName := fmt.Sprintf("%s%s", config.BotNamePrefix, uuid.New().String()[0:5]) + addr, err := addAccount(client, botName) + if err != nil { + return nil, fmt.Errorf("failed to create account: %w", err) + } + acc := account{ + Name: botName, + Address: addr, + } + accs = append(accs, acc) + } + return +} + +func sendCoinsMulti(client cosmosClient, coins sdk.Coins, fromName string, fromAddr sdk.AccAddress, toAddrStr ...string) error { + outputs := make([]banktypes.Output, 0, len(toAddrStr)) + for _, addrStr := range toAddrStr { + toAddr, err := sdk.AccAddressFromBech32(addrStr) + if err != nil { + return fmt.Errorf("failed to parse address: %w", err) + } + outputs = append(outputs, banktypes.NewOutput(toAddr, coins)) + } + + inputCoins, ok := coins.SafeMulInt(sdk.NewInt(int64(len(toAddrStr)))) + if !ok { + return fmt.Errorf("failed to calculate input coins") + } + msg := banktypes.NewMsgMultiSend([]banktypes.Input{banktypes.NewInput(fromAddr, inputCoins)}, outputs) + + rsp, err := client.BroadcastTx(fromName, msg) + if err != nil { + return fmt.Errorf("failed to broadcast tx: %w", err) + } + + if _, err = waitForTx(client, rsp.TxHash); err != nil { + return fmt.Errorf("failed to wait for tx: %w", err) + } + + return nil +} + +func waitForTx(client cosmosClient, txHash string) (*tx.GetTxResponse, error) { + serviceClient := tx.NewServiceClient(client.Context()) + ctx, cancel := context.WithTimeout(context.Background(), 20*time.Second) + ticker := time.NewTicker(time.Second) + + defer func() { + cancel() + ticker.Stop() + }() + + for { + select { + case <-ctx.Done(): + return nil, fmt.Errorf("timed out waiting for tx %s", txHash) + case <-ticker.C: + resp, err := serviceClient.GetTx(ctx, &tx.GetTxRequest{Hash: txHash}) + if err != nil { + continue + } + if resp.TxResponse.Code == 0 { + return resp, nil + } else { + return nil, fmt.Errorf("tx failed with code %d: %s", resp.TxResponse.Code, resp.TxResponse.RawLog) + } + } + } +} + +func addBotAccounts(numBots int, clientConfig config.ClientConfig, logger *zap.Logger) ([]account, error) { + cosmosClient, err := cosmosclient.New(config.GetCosmosClientOptions(clientConfig)...) + if err != nil { + return nil, fmt.Errorf("failed to create cosmos client for bot: %w", err) + } + + accs, err := getBotAccounts(cosmosClient) + if err != nil { + return nil, fmt.Errorf("failed to get bot accounts: %w", err) + } + + numFoundBots := len(accs) + + botsAccountsToCreate := max(0, numBots) - numFoundBots + if botsAccountsToCreate > 0 { + logger.Info("creating bot accounts", zap.Int("accounts", botsAccountsToCreate)) + } + + newAccs, err := createBotAccounts(cosmosClient, botsAccountsToCreate) + if err != nil { + return nil, fmt.Errorf("failed to create bot accounts: %w", err) + } + + accs = slices.Concat(accs, newAccs) + + if len(accs) < numBots { + return nil, fmt.Errorf("expected %d bot accounts, got %d", numBots, len(accs)) + } + return accs, nil +} + +func addBotsToGroup(operatorName, operatorAddress string, groupID int, client cosmosclient.Client, newAccs []account) error { + ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second) + defer cancel() + + c := group.NewQueryClient(client.Context()) + members, err := c.GroupMembers(ctx, &group.QueryGroupMembersRequest{ + GroupId: uint64(groupID), + }) + if err != nil { + return err + } + + memberMap := make(map[string]struct{}) + + memberUpdates := make([]group.MemberRequest, 0, len(members.Members)) + for _, m := range members.Members { + memberUpdates = append(memberUpdates, group.MemberRequest{ + Address: m.Member.Address, + Weight: m.Member.Weight, + }) + memberMap[m.Member.Address] = struct{}{} + } + + countAddMembers := 0 + + for _, acc := range newAccs { + if _, ok := memberMap[acc.Address]; ok { + continue + } + memberUpdates = append(memberUpdates, group.MemberRequest{ + Address: acc.Address, + Weight: "1", + }) + countAddMembers++ + } + + if countAddMembers == 0 { + return nil + } + + msg := group.MsgUpdateGroupMembers{ + Admin: operatorAddress, + GroupId: uint64(groupID), + MemberUpdates: memberUpdates, + } + + resp, err := client.BroadcastTx(operatorName, &msg) + if err != nil { + return err + } + + if _, err = waitForTx(client, resp.TxHash); err != nil { + return fmt.Errorf("failed to wait for tx: %w", err) + } + + return nil +} + +func primeAccounts(client cosmosClient, fromName string, fromAddr sdk.AccAddress, toAddr ...string) error { + if err := sendCoinsMulti(client, sdk.NewCoins(sdk.NewCoin("adym", sdk.NewInt(1))), fromName, fromAddr, toAddr...); err != nil { + return fmt.Errorf("failed to send coins: %w", err) + } + return nil +} + +func accountExists(clientCtx client.Context, address string) (bool, error) { + // Parse the address + addr, err := sdk.AccAddressFromBech32(address) + if err != nil { + return false, fmt.Errorf("invalid address: %v", err) + } + + // Create a query client for the auth module + authClient := authtypes.NewQueryClient(clientCtx) + + // Prepare the request + req := &authtypes.QueryAccountRequest{ + Address: addr.String(), + } + + ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second) + defer cancel() + // Query the account + res, err := authClient.Account(ctx, req) + if err != nil { + // Check if the error indicates that the account does not exist + if grpcErrorCode(err) == "NotFound" { + return false, nil + } + return false, fmt.Errorf("failed to query account: %v", err) + } + + // If res.Account is not nil, account exists + if res.Account != nil { + return true, nil + } + + return false, nil +} + +func hasFeeGranted(client cosmosClient, granterAddr, granteeAddr string) (bool, error) { + feeGrantClient := feegrant.NewQueryClient(client.Context()) + ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second) + defer cancel() + + res, err := feeGrantClient.Allowances( + ctx, + &feegrant.QueryAllowancesRequest{ + Grantee: granteeAddr, + }, + ) + if err != nil { + return false, fmt.Errorf("failed to query fee grants: %w", err) + } + + for _, allowance := range res.Allowances { + if allowance.Granter == granterAddr { + return true, nil + } + } + + // Check if the account has enough balance + return false, nil +} + +func addFeeGrantToBot(client cosmosClient, fromName string, granterAddr sdk.AccAddress, granteeAddr ...sdk.AccAddress) error { + msgs := make([]sdk.Msg, 0, len(granteeAddr)) + for _, addr := range granteeAddr { + msg, err := feegrant.NewMsgGrantAllowance( + &feegrant.BasicAllowance{}, + granterAddr, + addr, + ) + if err != nil { + return fmt.Errorf("failed to create fee grant msg: %w", err) + } + msgs = append(msgs, msg) + } + rsp, err := client.BroadcastTx(fromName, msgs...) + if err != nil { + return fmt.Errorf("failed to broadcast tx: %w", err) + } + + if _, err = waitForTx(client, rsp.TxHash); err != nil { + return fmt.Errorf("failed to wait for tx: %w", err) + } + + return nil +} + +func grpcErrorCode(err error) string { + if grpcStatus, ok := status.FromError(err); ok { + return grpcStatus.Code().String() + } + return "" +} diff --git a/eibc/lp.go b/eibc/lp.go new file mode 100644 index 0000000..f7520d2 --- /dev/null +++ b/eibc/lp.go @@ -0,0 +1,122 @@ +package eibc + +import ( + "context" + "sync" + "time" + + sdk "github.com/cosmos/cosmos-sdk/types" + "github.com/cosmos/cosmos-sdk/x/bank/types" + "go.uber.org/zap" +) + +type lp struct { + address string + rollapps map[string]rollappCriteria + bmu sync.Mutex + balance sdk.Coins + reservedFunds sdk.Coins +} + +type rollappCriteria struct { + rollappID string + denoms map[string]bool + maxPrice sdk.Coins + minFeePercentage sdk.Dec + operatorFeeShare sdk.Dec + settlementValidated bool +} + +func (l *lp) hasBalance(amount sdk.Coins) bool { + return l.spendableBalance().IsAllGTE(amount) +} + +func (l *lp) setBalance(balance sdk.Coins) { + l.bmu.Lock() + defer l.bmu.Unlock() + l.balance = balance +} + +func (l *lp) reserveFunds(amount sdk.Coins) { + l.bmu.Lock() + defer l.bmu.Unlock() + l.reservedFunds = l.reservedFunds.Add(amount...) +} + +func (l *lp) releaseFunds(amount sdk.Coins) { + l.bmu.Lock() + defer l.bmu.Unlock() + + var fail bool + l.reservedFunds, fail = l.reservedFunds.SafeSub(amount...) + if fail { + l.reservedFunds = sdk.NewCoins() + } +} + +func (l *lp) debitReservedFunds(amount sdk.Coins) { + l.bmu.Lock() + defer l.bmu.Unlock() + var fail bool + l.reservedFunds, fail = l.reservedFunds.SafeSub(amount...) + if fail { + l.reservedFunds = sdk.NewCoins() + } + + l.balance, fail = l.balance.SafeSub(amount...) + if fail { + l.balance = sdk.NewCoins() + } +} + +func (l *lp) spendableBalance() sdk.Coins { + l.bmu.Lock() + defer l.bmu.Unlock() + + return l.balance.Sub(l.reservedFunds...) +} + +func (or *orderTracker) releaseAllReservedOrdersFunds(demandOrder ...*demandOrder) { + for _, order := range demandOrder { + or.lpmu.Lock() + if lp, ok := or.lps[order.lpAddress]; ok { + lp.releaseFunds(order.amount) + } + or.lpmu.Unlock() + } +} + +func (or *orderTracker) debitAllReservedOrdersFunds(demandOrder ...*demandOrder) { + for _, order := range demandOrder { + or.lpmu.Lock() + if lp, ok := or.lps[order.lpAddress]; ok { + lp.debitReservedFunds(order.amount) + } + or.lpmu.Unlock() + } +} + +func (or *orderTracker) balanceRefresher(ctx context.Context) { + t := time.NewTicker(or.balanceRefreshInterval) + for { + select { + case <-ctx.Done(): + return + case <-t.C: + or.refreshBalances(ctx) + } + } +} + +func (or *orderTracker) refreshBalances(ctx context.Context) { + for _, lp := range or.lps { + resp, err := or.getBalances(ctx, &types.QuerySpendableBalancesRequest{ + Address: lp.address, + }) + if err != nil { + or.logger.Error("failed to get balances", zap.Error(err)) + continue + } + lp.setBalance(resp.Balances) + } +} diff --git a/eibc/node_client.go b/eibc/node_client.go new file mode 100644 index 0000000..b2541af --- /dev/null +++ b/eibc/node_client.go @@ -0,0 +1,143 @@ +package eibc + +import ( + "context" + "encoding/json" + "fmt" + "net/http" + "strconv" + "sync" + "sync/atomic" + "time" + + "github.com/dymensionxyz/eibc-client/config" +) + +type nodeClient struct { + client *http.Client + rollapps map[string]config.RollappConfig + get getFn +} + +type getFn func(ctx context.Context, url string) (*blockValidatedResponse, error) + +type blockValidatedResponse struct { + ChainID string `json:"ChainID"` + Result validationLevel `json:"Result"` +} + +type JSONResponse struct { + Jsonrpc string `json:"jsonrpc"` + Result struct { + Result string `json:"Result"` + } `json:"result"` + Id int `json:"id"` +} + +type validationLevel int + +const ( + validationLevelNone validationLevel = iota + validationLevelP2P + validationLevelSettlement +) + +func newNodeClient(rollapps map[string]config.RollappConfig) (*nodeClient, error) { + for rollappID, cfg := range rollapps { + if cfg.MinConfirmations == 0 { + return nil, fmt.Errorf("rollapp ID %s: minimum validated nodes must be greater than 0", rollappID) + } + if len(cfg.FullNodes) < cfg.MinConfirmations { + return nil, fmt.Errorf("rollapp ID %s: not enough locations to validate blocks", rollappID) + } + } + n := &nodeClient{ + client: &http.Client{ + Timeout: 10 * time.Second, + }, + rollapps: rollapps, + } + n.get = n.getHttp + return n, nil +} + +const ( + blockValidatedPath = "/block_validated" +) + +func (c *nodeClient) BlockValidated(ctx context.Context, rollappID string, height int64, expectedValidationLevel validationLevel) (bool, error) { + var validatedNodes int32 + var wg sync.WaitGroup + rollappConfig := c.rollapps[rollappID] + errChan := make(chan error, len(rollappConfig.FullNodes)) + + for _, location := range rollappConfig.FullNodes { + wg.Add(1) + go func(ctx context.Context, rollappID, location string) { + defer wg.Done() + valid, err := c.nodeBlockValidated(ctx, rollappID, location, height, expectedValidationLevel) + if err != nil { + errChan <- err + return + } + if valid { + atomic.AddInt32(&validatedNodes, 1) + } + }(ctx, rollappID, location) + } + + wg.Wait() + close(errChan) + + if len(errChan) > 0 { + return false, <-errChan + } + + return int(validatedNodes) >= rollappConfig.MinConfirmations, nil +} + +func (c *nodeClient) nodeBlockValidated( + ctx context.Context, + rollappID, + location string, + height int64, + expectedValidationLevel validationLevel, +) (bool, error) { + url := fmt.Sprintf("%s%s?height=%d", location, blockValidatedPath, height) + validated, err := c.get(ctx, url) + if err != nil { + return false, err + } + + if validated.ChainID != rollappID { + return false, fmt.Errorf("invalid chain ID! want: %s, got: %s, height: %d", rollappID, validated.ChainID, height) + } + + return validated.Result >= expectedValidationLevel, nil +} + +func (c *nodeClient) getHttp(ctx context.Context, url string) (*blockValidatedResponse, error) { + req, err := http.NewRequestWithContext(ctx, http.MethodGet, url, nil) + if err != nil { + return nil, fmt.Errorf("failed to create request: %w", err) + } + resp, err := c.client.Do(req) + if err != nil { + return nil, fmt.Errorf("failed to get %s: %w", url, err) + } + defer resp.Body.Close() + + jsonResp := new(JSONResponse) + if err := json.NewDecoder(resp.Body).Decode(&jsonResp); err != nil { + return nil, fmt.Errorf("failed to decode response: %w", err) + } + + result, err := strconv.ParseInt(jsonResp.Result.Result, 10, 32) + if err != nil { + return nil, fmt.Errorf("failed to parse result: %w", err) + } + blockValidated := &blockValidatedResponse{ + Result: validationLevel(result), + } + return blockValidated, err +} diff --git a/eibc/node_client_test.go b/eibc/node_client_test.go new file mode 100644 index 0000000..8eb4f2a --- /dev/null +++ b/eibc/node_client_test.go @@ -0,0 +1,105 @@ +package eibc + +import ( + "context" + "fmt" + "net/http" + "testing" + + "github.com/stretchr/testify/assert" + + "github.com/dymensionxyz/eibc-client/config" +) + +func Test_nodeClient_nodeBlockValidated(t *testing.T) { + t.Skip() + + type fields struct { + client *http.Client + rollapps map[string]config.RollappConfig + expectedValidationLevel validationLevel + } + type args struct { + height int64 + rollappID string + } + tests := []struct { + name string + fields fields + args args + want bool + wantErr assert.ErrorAssertionFunc + }{ + { + name: "success: p2p at height 1", + fields: fields{ + client: &http.Client{}, + rollapps: map[string]config.RollappConfig{ + "rollapp1": { + MinConfirmations: 1, + FullNodes: []string{"http://localhost:26657"}, + }, + }, + expectedValidationLevel: validationLevelP2P, + }, + args: args{ + height: 1, + rollappID: "rollapp1", + }, + want: true, + wantErr: assert.NoError, + }, { + name: "failure: p2p at height 100", + fields: fields{ + client: &http.Client{}, + rollapps: map[string]config.RollappConfig{ + "rollapp1": { + MinConfirmations: 1, + FullNodes: []string{"http://localhost:26657"}, + }, + }, + expectedValidationLevel: validationLevelP2P, + }, + args: args{ + height: 100, + rollappID: "rollapp1", + }, + want: false, + wantErr: assert.NoError, + }, { + name: "failure: settlement at height 1", + fields: fields{ + client: &http.Client{}, + rollapps: map[string]config.RollappConfig{ + "rollapp1": { + MinConfirmations: 1, + FullNodes: []string{"http://localhost:26657"}, + }, + }, + expectedValidationLevel: validationLevelSettlement, + }, + args: args{ + height: 1, + rollappID: "rollapp1", + }, + want: false, + wantErr: assert.NoError, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + c := &nodeClient{ + client: tt.fields.client, + rollapps: tt.fields.rollapps, + } + c.get = c.getHttp + + ctx := context.Background() + got, err := c.nodeBlockValidated(ctx, tt.args.rollappID, tt.fields.rollapps[tt.args.rollappID].FullNodes[0], tt.args.height, tt.fields.expectedValidationLevel) + if !tt.wantErr(t, err, fmt.Sprintf("nodeBlockValidated(%s, %s, %v)", tt.args.rollappID, tt.fields.rollapps[tt.args.rollappID].FullNodes[0], tt.args.height)) { + return + } + assert.Equalf(t, tt.want, got, "nodeBlockValidated(%s, %s, %v)", tt.args.rollappID, tt.fields.rollapps[tt.args.rollappID].FullNodes[0], tt.args.height) + }) + } +} diff --git a/eibc/order_client.go b/eibc/order_client.go new file mode 100644 index 0000000..12c17df --- /dev/null +++ b/eibc/order_client.go @@ -0,0 +1,261 @@ +package eibc + +import ( + "context" + "fmt" + "math/rand" + + sdk "github.com/cosmos/cosmos-sdk/types" + "github.com/cosmos/cosmos-sdk/types/bech32" + "go.uber.org/zap" + + "github.com/dymensionxyz/cosmosclient/cosmosclient" + + "github.com/dymensionxyz/eibc-client/config" +) + +type orderClient struct { + logger *zap.Logger + config config.Config + bots map[string]*orderFulfiller + + orderEventer *orderEventer + orderPoller *orderPoller + orderTracker *orderTracker +} + +func NewOrderClient(cfg config.Config, logger *zap.Logger) (*orderClient, error) { + sdkcfg := sdk.GetConfig() + sdkcfg.SetBech32PrefixForAccount(config.HubAddressPrefix, config.PubKeyPrefix) + + //nolint:gosec + subscriberID := fmt.Sprintf("eibc-client-%d", rand.Int()) + + orderCh := make(chan []*demandOrder, config.NewOrderBufferSize) + fulfilledOrdersCh := make(chan *orderBatch, config.NewOrderBufferSize) // TODO: make buffer size configurable + + hubClient, err := getHubClient(cfg) + if err != nil { + return nil, fmt.Errorf("failed to create hub client: %w", err) + } + + fullNodeClient, err := getFullNodeClients(cfg) + if err != nil { + return nil, fmt.Errorf("failed to create full node clients: %w", err) + } + + // create bots + bots := make(map[string]*orderFulfiller) + + minOperatorFeeShare, err := sdk.NewDecFromStr(cfg.Operator.MinFeeShare) + if err != nil { + return nil, fmt.Errorf("failed to parse min operator fee share: %w", err) + } + + ordTracker := newOrderTracker( + hubClient, + cfg.Bots.PolicyAddress, + minOperatorFeeShare, + fullNodeClient, + fulfilledOrdersCh, + bots, + subscriberID, + cfg.Bots.MaxOrdersPerTx, + &cfg.Validation, + orderCh, + cfg.OrderPolling.Interval, // we can use the same interval for order polling and LP balance checking + logger, + ) + + eventer := newOrderEventer( + hubClient, + subscriberID, + ordTracker, + logger, + ) + + operatorClientCfg := config.ClientConfig{ + HomeDir: cfg.Operator.KeyringDir, + KeyringBackend: cfg.Operator.KeyringBackend, + NodeAddress: cfg.NodeAddress, + GasFees: cfg.Gas.Fees, + GasPrices: cfg.Gas.Prices, + } + + operatorClient, err := cosmosclient.New(config.GetCosmosClientOptions(operatorClientCfg)...) + if err != nil { + return nil, fmt.Errorf("failed to create cosmos client for bot: %w", err) + } + + operatorName := cfg.Operator.AccountName + operatorAddress, err := operatorClient.Address(operatorName) + if err != nil { + return nil, fmt.Errorf("failed to get operator address: %w", err) + } + + botClientCfg := config.ClientConfig{ + HomeDir: cfg.Bots.KeyringDir, + KeyringBackend: cfg.Bots.KeyringBackend, + NodeAddress: cfg.NodeAddress, + GasFees: cfg.Gas.Fees, + GasPrices: cfg.Gas.Prices, + FeeGranter: operatorAddress.String(), + } + + accs, err := addBotAccounts(cfg.Bots.NumberOfBots, botClientCfg, logger) + if err != nil { + return nil, err + } + + activeAccs := make([]account, 0, len(accs)) + granteeAddrs := make([]sdk.AccAddress, 0, len(accs)) + primeAddrs := make([]string, 0, len(accs)) + + var botIdx int + for botIdx = range cfg.Bots.NumberOfBots { + acc := accs[botIdx] + exist, err := accountExists(operatorClient.Context(), acc.Address) + if err != nil { + return nil, fmt.Errorf("failed to check if bot account exists: %w", err) + } + if !exist { + primeAddrs = append(primeAddrs, acc.Address) + } + + hasGrant, err := hasFeeGranted(operatorClient, operatorAddress.String(), acc.Address) + if err != nil { + return nil, fmt.Errorf("failed to check if fee is granted: %w", err) + } + if !hasGrant { + _, granteeAddr, err := bech32.DecodeAndConvert(acc.Address) + if err != nil { + return nil, fmt.Errorf("failed to decode bot address: %w", err) + } + granteeAddrs = append(granteeAddrs, granteeAddr) + } + + b, err := buildBot( + acc, + operatorAddress.String(), + logger, + cfg.Bots, + botClientCfg, + orderCh, + fulfilledOrdersCh, + ordTracker.releaseAllReservedOrdersFunds, + ordTracker.debitAllReservedOrdersFunds, + ) + if err != nil { + return nil, fmt.Errorf("failed to create bot: %w", err) + } + bots[b.account.Name] = b + activeAccs = append(activeAccs, acc) + } + + if len(primeAddrs) > 0 { + logger.Info("priming bot accounts", zap.Strings("addresses", primeAddrs)) + if err = primeAccounts(operatorClient, operatorName, operatorAddress, primeAddrs...); err != nil { + return nil, fmt.Errorf("failed to prime bot account: %w", err) + } + } + + if len(granteeAddrs) > 0 { + logger.Info("adding fee grant to bot accounts", zap.Strings("addresses", primeAddrs)) + if err = addFeeGrantToBot(operatorClient, operatorName, operatorAddress, granteeAddrs...); err != nil { + return nil, fmt.Errorf("failed to add grant to bot: %w", err) + } + } + + err = addBotsToGroup(operatorName, operatorAddress.String(), cfg.Operator.GroupID, operatorClient, activeAccs) + if err != nil { + return nil, err + } + + oc := &orderClient{ + orderEventer: eventer, + orderTracker: ordTracker, + bots: bots, + config: cfg, + logger: logger, + } + + if cfg.OrderPolling.Enabled { + oc.orderPoller = newOrderPoller( + hubClient.Context().ChainID, + ordTracker, + cfg.OrderPolling, + logger, + ) + } + + return oc, nil +} + +func getHubClient(cfg config.Config) (cosmosclient.Client, error) { + // init cosmos client for order fetcher + hubClientCfg := config.ClientConfig{ + HomeDir: cfg.Bots.KeyringDir, + NodeAddress: cfg.NodeAddress, + GasFees: cfg.Gas.Fees, + GasPrices: cfg.Gas.Prices, + KeyringBackend: cfg.Bots.KeyringBackend, + } + + hubClient, err := cosmosclient.New(config.GetCosmosClientOptions(hubClientCfg)...) + if err != nil { + return cosmosclient.Client{}, fmt.Errorf("failed to create cosmos client: %w", err) + } + + return hubClient, nil +} + +func getFullNodeClients(cfg config.Config) (*nodeClient, error) { + switch cfg.Validation.FallbackLevel { + case config.ValidationModeSequencer: + return &nodeClient{}, nil + } + + client, err := newNodeClient(cfg.Rollapps) + if err != nil { + return nil, fmt.Errorf("failed to create full node client: %w", err) + } + + return client, nil +} + +func (oc *orderClient) Start(ctx context.Context) error { + oc.logger.Info("starting demand order tracker...") + + if err := oc.orderTracker.start(ctx); err != nil { + return fmt.Errorf("failed to start order tracker: %w", err) + } + + // start order fetcher + oc.logger.Info("starting demand order eventer...") + if err := oc.orderEventer.start(ctx); err != nil { + return fmt.Errorf("failed to subscribe to demand orders: %w", err) + } + + // start order polling + if oc.orderPoller != nil { + oc.logger.Info("starting order polling...") + if err := oc.orderPoller.start(ctx); err != nil { + return fmt.Errorf("failed to start order polling: %w", err) + } + } + + oc.logger.Info("starting bots...") + + // start bots + for _, b := range oc.bots { + go func() { + if err := b.start(ctx); err != nil { + oc.logger.Error("failed to bot", zap.Error(err)) + } + }() + } + + <-make(chan bool) + + return nil +} diff --git a/eibc/order_client_test.go b/eibc/order_client_test.go new file mode 100644 index 0000000..4e2c006 --- /dev/null +++ b/eibc/order_client_test.go @@ -0,0 +1,451 @@ +package eibc + +import ( + "context" + "fmt" + "net/url" + "strconv" + "strings" + "testing" + "time" + + "github.com/cosmos/cosmos-sdk/client" + cdctypes "github.com/cosmos/cosmos-sdk/codec/types" + sdk "github.com/cosmos/cosmos-sdk/types" + "github.com/cosmos/cosmos-sdk/x/authz" + banktypes "github.com/cosmos/cosmos-sdk/x/bank/types" + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" + rpcclient "github.com/tendermint/tendermint/rpc/client" + coretypes "github.com/tendermint/tendermint/rpc/core/types" + "go.uber.org/zap" + "google.golang.org/grpc" + + "github.com/dymensionxyz/cosmosclient/cosmosclient" + + "github.com/dymensionxyz/eibc-client/config" + "github.com/dymensionxyz/eibc-client/types" +) + +func TestOrderClient(t *testing.T) { + type lpConfig struct { + grant *types.FulfillOrderAuthorization + balance sdk.Coins + } + tests := []struct { + name string + config config.Config + lpConfigs []lpConfig + hubClient mockNodeClient + fullNodeClient *nodeClient + pollOrders []Order + eventOrders []Order + expectLPFulfilledOrderIDs map[string]string // orderID -> lpAddress + }{ + { + name: "p2p mode, orders from poller: fulfilled", + config: config.Config{ + OrderPolling: config.OrderPollingConfig{ + Interval: time.Second, + Enabled: true, + }, + Operator: config.OperatorConfig{ + MinFeeShare: "0.1", + }, + Bots: config.BotConfig{ + NumberOfBots: 3, + MaxOrdersPerTx: 4, + }, + Validation: config.ValidationConfig{ + ValidationWaitTime: time.Second, + }, + }, + lpConfigs: []lpConfig{ + { + grant: &types.FulfillOrderAuthorization{ + Rollapps: []*types.RollappCriteria{ + { + RollappId: "rollapp1", + Denoms: []string{"stake", "adym"}, + MinLpFeePercentage: sdk.DecProto{Dec: sdk.MustNewDecFromStr("0.1")}, + MaxPrice: sdk.NewCoins(sdk.NewCoin("stake", sdk.NewInt(210)), sdk.NewCoin("adym", sdk.NewInt(150))), + OperatorFeeShare: sdk.DecProto{Dec: sdk.MustNewDecFromStr("0.1")}, + SpendLimit: nil, + SettlementValidated: false, + }, { + RollappId: "rollapp2", + Denoms: []string{"stake", "adym"}, + MinLpFeePercentage: sdk.DecProto{Dec: sdk.MustNewDecFromStr("0.1")}, + MaxPrice: sdk.NewCoins(sdk.NewCoin("stake", sdk.NewInt(210)), sdk.NewCoin("adym", sdk.NewInt(150))), + SpendLimit: nil, + OperatorFeeShare: sdk.DecProto{Dec: sdk.MustNewDecFromStr("0.1")}, + }}, + }, + balance: sdk.NewCoins(sdk.NewCoin("stake", sdk.NewInt(201)), sdk.NewCoin("adym", sdk.NewInt(140))), + }, { + grant: &types.FulfillOrderAuthorization{ + Rollapps: []*types.RollappCriteria{{ + RollappId: "rollapp2", + Denoms: []string{"adym"}, + MinLpFeePercentage: sdk.DecProto{Dec: sdk.MustNewDecFromStr("0.1")}, + MaxPrice: sdk.NewCoins(sdk.NewCoin("adym", sdk.NewInt(450))), + SpendLimit: nil, + OperatorFeeShare: sdk.DecProto{Dec: sdk.MustNewDecFromStr("0.2")}, + SettlementValidated: true, + }}, + }, + balance: sdk.NewCoins(sdk.NewCoin("adym", sdk.NewInt(500))), + }, { + grant: &types.FulfillOrderAuthorization{ + Rollapps: []*types.RollappCriteria{{ + RollappId: "rollapp1", + Denoms: []string{"stake"}, + MinLpFeePercentage: sdk.DecProto{Dec: sdk.MustNewDecFromStr("0.1")}, + MaxPrice: sdk.NewCoins(sdk.NewCoin("stake", sdk.NewInt(450))), + SpendLimit: nil, + OperatorFeeShare: sdk.DecProto{Dec: sdk.MustNewDecFromStr("0.2")}, + SettlementValidated: false, + }}, + }, + balance: sdk.NewCoins(sdk.NewCoin("stake", sdk.NewInt(200)), sdk.NewCoin("adym", sdk.NewInt(100))), + }, + }, + hubClient: mockNodeClient{}, + fullNodeClient: &nodeClient{ + rollapps: map[string]config.RollappConfig{ + "rollapp1": { + MinConfirmations: 2, + FullNodes: []string{"location1", "location2"}, + }, + "rollapp2": { + MinConfirmations: 2, + FullNodes: []string{"location3", "location4"}, + }, + }, + get: mockValidGet(map[string]map[int64]*blockValidatedResponse{ + "location1": { + 1: {Result: validationLevelP2P, ChainID: "rollapp1"}, + 2: {Result: validationLevelP2P, ChainID: "rollapp1"}, + 5: {Result: validationLevelP2P, ChainID: "rollapp1"}, + }, + "location2": { + 1: {Result: validationLevelP2P, ChainID: "rollapp1"}, + 2: {Result: validationLevelP2P, ChainID: "rollapp1"}, + 5: {Result: validationLevelP2P, ChainID: "rollapp1"}, + }, + "location3": { + 3: {Result: validationLevelP2P, ChainID: "rollapp2"}, + 4: {Result: validationLevelSettlement, ChainID: "rollapp2"}, + 6: {Result: validationLevelP2P, ChainID: "rollapp2"}, + }, + "location4": { + 3: {Result: validationLevelP2P, ChainID: "rollapp2"}, + 4: {Result: validationLevelSettlement, ChainID: "rollapp2"}, + 6: {Result: validationLevelNone, ChainID: "rollapp2"}, + }, + }), + }, + pollOrders: []Order{ + { + EibcOrderId: "order1", + Amount: "80", + Fee: "12stake", + RollappId: "rollapp1", + BlockHeight: "1", + }, { + EibcOrderId: "order2", + Amount: "202", + Fee: "25stake", + RollappId: "rollapp2", + BlockHeight: "2", + }, { + EibcOrderId: "order5", + Amount: "201", + Fee: "50stake", + RollappId: "rollapp1", + BlockHeight: "5", + }, + }, + eventOrders: []Order{ + { + EibcOrderId: "order3", + Amount: "100adym", + Fee: "20adym", + RollappId: "rollapp2", + BlockHeight: "3", + }, { + EibcOrderId: "order4", + Amount: "250adym", + Fee: "35adym", + RollappId: "rollapp2", + BlockHeight: "4", + }, { + EibcOrderId: "order6", + Amount: "250adym", + Fee: "35adym", + RollappId: "rollapp2", + BlockHeight: "6", + }, + }, + expectLPFulfilledOrderIDs: map[string]string{ + "order1": "lp-3-address", // lp3 (lp1 and lp3 selected because they fulfill for rollapp1, lp3 preferred because operator fee is higher) + // "order2": "", // not fulfilled (lp1 has not enough balance, lp2 does not fulfill stake orders, lp3 does not fulfill for rollapp2) + "order3": "lp-1-address", // lp1 (both selected but lp1 preferred due to no settlement validation required) + "order4": "lp-2-address", // lp2 (selected - max price is high enough) + "order5": "lp-1-address", // lp1 (between lp1 and lp3, only lp1 has enough balance, lp2 doesn't fulfill adym orders) + // "order6": "lp-2-address", // not fulfilled, only got 1/2 validation + }, + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + var fulfilledOrders []*demandOrder + fulfillOrdersFn := func(demandOrder ...*demandOrder) error { + fulfilledOrders = append(fulfilledOrders, demandOrder...) + return nil + } + + var grants []*authz.GrantAuthorization + lpBalances := make(map[string]sdk.Coins) + for i, g := range tt.lpConfigs { + a, err := cdctypes.NewAnyWithValue(g.grant) + if err != nil { + t.Fatal(err) + } + lpAddr := fmt.Sprintf("lp-%d-address", i+1) + grants = append(grants, &authz.GrantAuthorization{ + Granter: lpAddr, + Authorization: a, + }) + lpBalances[lpAddr] = g.balance + } + + getLPGrants := func(ctx context.Context, in *authz.QueryGranteeGrantsRequest, opts ...grpc.CallOption) (*authz.QueryGranteeGrantsResponse, error) { + return &authz.QueryGranteeGrantsResponse{ + Grants: grants, + }, nil + } + + oc, err := setupTestOrderClient( + tt.config, + mockGetPollerOrders(tt.pollOrders), + tt.hubClient, + tt.fullNodeClient, + getLPGrants, + fulfillOrdersFn, + lpBalances, + sdk.MustNewDecFromStr(tt.config.Operator.MinFeeShare), + ) + require.NoError(t, err) + + go func() { + err = oc.Start(context.Background()) + require.NoError(t, err) + }() + + // orders from events will be picked up first + for _, order := range tt.eventOrders { + oc.orderEventer.eventClient.(*mockNodeClient).addOrderCh <- coretypes.ResultEvent{ + Events: map[string][]string{ + createdEvent + ".order_id": {order.EibcOrderId}, + createdEvent + ".price": {order.Amount}, + createdEvent + ".packet_status": {"PENDING"}, + createdEvent + ".fee": {order.Fee}, + createdEvent + ".rollapp_id": {order.RollappId}, + createdEvent + ".proof_height": {order.BlockHeight}, + }, + } + } + + // wait a bit for the client to fulfill orders + time.Sleep(3 * time.Second) + + // ======= after fulfilling ========= + require.Len(t, fulfilledOrders, len(tt.expectLPFulfilledOrderIDs)) + + expectTotalLPSpent := map[string]sdk.Coins{} + + for _, o := range fulfilledOrders { + lpAddr, ok := tt.expectLPFulfilledOrderIDs[o.id] + require.True(t, ok) + require.Equal(t, lpAddr, o.lpAddress) + expectTotalLPSpent[o.lpAddress] = expectTotalLPSpent[o.lpAddress].Add(o.amount...) + } + + for _, lp := range oc.orderTracker.lps { + assert.Truef(t, lp.reservedFunds.Empty(), "lp %s has reserved funds; got: %s", lp.address, lp.reservedFunds) + expectBalance := lpBalances[lp.address].Sub(expectTotalLPSpent[lp.address]...) + assert.Truef(t, expectBalance.IsEqual(lp.balance), + "lp %s balance is not correct; expect: %s, got: %s", lp.address, expectBalance, lp.balance) + } + }) + } +} + +func setupTestOrderClient( + cfg config.Config, + pollOrders func() ([]Order, error), + hubClient mockNodeClient, + fullNodeClient *nodeClient, + grantsFn getLPGrantsFn, + fulfillOrdersFn func(demandOrder ...*demandOrder) error, + lpBalances map[string]sdk.Coins, + minOperatorFeeShare sdk.Dec, +) (*orderClient, error) { + logger, _ := zap.NewDevelopment() + orderCh := make(chan []*demandOrder, config.NewOrderBufferSize) + fulfilledOrdersCh := make(chan *orderBatch, config.NewOrderBufferSize) + + // tracker + trackerClient := hubClient + + // bots + bots := make(map[string]*orderFulfiller) + + ordTracker := newOrderTracker( + &trackerClient, + "policyAddress", + minOperatorFeeShare, + fullNodeClient, + fulfilledOrdersCh, + bots, + "subscriber", + cfg.Bots.MaxOrdersPerTx, + &cfg.Validation, + orderCh, + cfg.OrderPolling.Interval, + logger, + ) + ordTracker.getLPGrants = grantsFn + // LPs always have enough balance + ordTracker.getBalances = mockGetBalances(lpBalances) + + // eventer + eventerClient := hubClient + eventerClient.finalizeOrderCh = make(chan coretypes.ResultEvent, 1) + eventerClient.addOrderCh = make(chan coretypes.ResultEvent, 1) + eventerClient.stateInfoCh = make(chan coretypes.ResultEvent, 1) + + eventer := newOrderEventer( + cosmosclient.Client{ + RPC: &eventerClient, + WSEvents: &eventerClient, + }, + "", + ordTracker, + logger, + ) + + chainID := "test-chain-id" + + for i := range cfg.Bots.NumberOfBots { + botName := fmt.Sprintf("bot-%d", i+1) + + hc := hubClient + acc := account{ + Name: botName, + Address: botName + "-address", + } + b := newOrderFulfiller( + orderCh, + fulfilledOrdersCh, + &hc, + acc, + "policyAddress", + "operatorAddress", + ordTracker.releaseAllReservedOrdersFunds, + ordTracker.debitAllReservedOrdersFunds, + logger, + ) + b.FulfillDemandOrders = fulfillOrdersFn + bots[b.account.Name] = b + } + + // poller + var poller *orderPoller + if cfg.OrderPolling.Enabled { + poller = newOrderPoller( + chainID, + ordTracker, + cfg.OrderPolling, + logger, + ) + poller.getOrders = pollOrders + } + + // order client + oc := &orderClient{ + orderEventer: eventer, + orderTracker: ordTracker, + bots: bots, + config: cfg, + logger: logger, + orderPoller: poller, + } + + return oc, nil +} + +func mockGetPollerOrders(orders []Order) func() ([]Order, error) { + return func() ([]Order, error) { + // after polling once, remove orders + defer func() { + orders = nil + }() + return orders, nil + } +} + +func mockGetBalances(lpBalances map[string]sdk.Coins) getSpendableBalancesFn { + return func(ctx context.Context, in *banktypes.QuerySpendableBalancesRequest, opts ...grpc.CallOption) (*banktypes.QuerySpendableBalancesResponse, error) { + return &banktypes.QuerySpendableBalancesResponse{ + Balances: lpBalances[in.Address], + }, nil + } +} + +func mockValidGet(resps map[string]map[int64]*blockValidatedResponse) getFn { + return func(ctx context.Context, urlStr string) (*blockValidatedResponse, error) { + for loc, rspMap := range resps { + if strings.Contains(urlStr, loc) { + u, _ := url.Parse(urlStr) + h, _ := strconv.ParseInt(u.Query().Get("height"), 10, 64) + + if rspMap[h] != nil { + return rspMap[h], nil + } + } + } + return &blockValidatedResponse{ + Result: validationLevelNone, + }, nil + } +} + +type mockNodeClient struct { + rpcclient.Client + finalizeOrderCh chan coretypes.ResultEvent + addOrderCh chan coretypes.ResultEvent + stateInfoCh chan coretypes.ResultEvent +} + +func (m *mockNodeClient) Start() error { + return nil +} + +func (m *mockNodeClient) Context() client.Context { + return client.Context{} +} + +func (m *mockNodeClient) BroadcastTx(string, ...sdk.Msg) (cosmosclient.Response, error) { + return cosmosclient.Response{TxResponse: &sdk.TxResponse{}}, nil +} + +func (m *mockNodeClient) Subscribe(_ context.Context, _ string, query string, _ ...int) (out <-chan coretypes.ResultEvent, err error) { + switch query { + case fmt.Sprintf("%s.is_fulfilled='false'", createdEvent): + return m.addOrderCh, nil + } + return nil, fmt.Errorf("invalid query") +} diff --git a/eibc/order_eventer.go b/eibc/order_eventer.go new file mode 100644 index 0000000..cdfcb23 --- /dev/null +++ b/eibc/order_eventer.go @@ -0,0 +1,171 @@ +package eibc + +import ( + "context" + "fmt" + "strconv" + "time" + + sdk "github.com/cosmos/cosmos-sdk/types" + rpcclient "github.com/tendermint/tendermint/rpc/client" + tmtypes "github.com/tendermint/tendermint/rpc/core/types" + "go.uber.org/zap" + + "github.com/dymensionxyz/cosmosclient/cosmosclient" +) + +type orderEventer struct { + rpc rpcclient.Client + subscribedStateUpdateRollapps map[string]struct{} + eventClient rpcclient.EventsClient + logger *zap.Logger + + orderTracker *orderTracker + subscriberID string +} + +func newOrderEventer( + client cosmosclient.Client, + subscriberID string, + orderTracker *orderTracker, + logger *zap.Logger, +) *orderEventer { + return &orderEventer{ + rpc: client.RPC, + eventClient: client.WSEvents, + subscriberID: subscriberID, + subscribedStateUpdateRollapps: make(map[string]struct{}), + logger: logger.With(zap.String("module", "order-eventer")), + orderTracker: orderTracker, + } +} + +const ( + createdEvent = "dymensionxyz.dymension.eibc.EventDemandOrderCreated" +) + +func (e *orderEventer) start(ctx context.Context) error { + if err := e.rpc.Start(); err != nil { + return fmt.Errorf("start rpc client: %w", err) + } + + if err := e.subscribeToPendingDemandOrders(ctx); err != nil { + return fmt.Errorf("failed to subscribe to pending demand orders: %w", err) + } + + return nil +} + +func (e *orderEventer) enqueueEventOrders(_ context.Context, res tmtypes.ResultEvent) error { + newOrders := e.parseOrdersFromEvents(res) + if len(newOrders) == 0 { + return nil + } + + if e.logger.Level() <= zap.DebugLevel { + ids := make([]string, 0, len(newOrders)) + for _, order := range newOrders { + ids = append(ids, order.id) + } + e.logger.Debug("new demand orders", zap.Strings("ids", ids)) + } else { + e.logger.Info("new demand orders", zap.Int("count", len(newOrders))) + } + + e.orderTracker.addOrder(newOrders...) + + return nil +} + +func (e *orderEventer) parseOrdersFromEvents(res tmtypes.ResultEvent) []*demandOrder { + ids := res.Events[createdEvent+".order_id"] + + if len(ids) == 0 { + return nil + } + + prices := res.Events[createdEvent+".price"] + fees := res.Events[createdEvent+".fee"] + statuses := res.Events[createdEvent+".packet_status"] + rollapps := res.Events[createdEvent+".rollapp_id"] + heights := res.Events[createdEvent+".proof_height"] + newOrders := make([]*demandOrder, 0, len(ids)) + + for i, id := range ids { + price, err := sdk.ParseCoinsNormalized(prices[i]) + if err != nil { + e.logger.Error("failed to parse price", zap.Error(err)) + continue + } + + if fees[i] == "" { + continue + } + + fee, err := sdk.ParseCoinNormalized(fees[i]) + if err != nil { + e.logger.Error("failed to parse fee", zap.Error(err)) + continue + } + + height, err := strconv.ParseInt(heights[i], 10, 64) + if err != nil { + e.logger.Error("failed to parse block height", zap.Error(err)) + continue + } + + validationWaitTime := e.orderTracker.validation.ValidationWaitTime + validDeadline := time.Now().Add(validationWaitTime) + + order := &demandOrder{ + id: id, + denom: fee.Denom, + amount: price, + fee: fee, + status: statuses[i], + rollappId: rollapps[i], + proofHeight: height, + validDeadline: validDeadline, + } + + if !e.orderTracker.canFulfillOrder(order) { + continue + } + + if err := e.orderTracker.findLPForOrder(order); err != nil { + e.logger.Warn("failed to find LP for order", zap.Error(err), zap.String("order_id", order.id)) + continue + } + + newOrders = append(newOrders, order) + } + + return newOrders +} + +func (e *orderEventer) subscribeToPendingDemandOrders(ctx context.Context) error { + query := fmt.Sprintf("%s.is_fulfilled='false'", createdEvent) + return e.subscribeToEvent(ctx, "pending demand", query, e.enqueueEventOrders) +} + +func (e *orderEventer) subscribeToEvent(ctx context.Context, event string, query string, callback func(ctx context.Context, event tmtypes.ResultEvent) error) error { + resCh, err := e.eventClient.Subscribe(ctx, e.subscriberID, query) + if err != nil { + return fmt.Errorf("failed to subscribe to %s events: %w", event, err) + } + + go func() { + for { + select { + case res := <-resCh: + if err := callback(ctx, res); err != nil { + e.logger.Error(fmt.Sprintf("failed to process %s event", event), zap.Error(err)) + } + case <-ctx.Done(): + return + } + } + }() + + return nil +} diff --git a/eibc/order_fulfiller.go b/eibc/order_fulfiller.go new file mode 100644 index 0000000..7b172ff --- /dev/null +++ b/eibc/order_fulfiller.go @@ -0,0 +1,247 @@ +package eibc + +import ( + "context" + "encoding/json" + "fmt" + "strings" + + "github.com/cosmos/cosmos-sdk/client" + sdk "github.com/cosmos/cosmos-sdk/types" + "github.com/cosmos/cosmos-sdk/types/bech32" + "github.com/cosmos/cosmos-sdk/x/authz" + "go.uber.org/zap" + + "github.com/dymensionxyz/cosmosclient/cosmosclient" + + "github.com/dymensionxyz/eibc-client/config" + "github.com/dymensionxyz/eibc-client/types" +) + +type orderFulfiller struct { + account account + policyAddress string + operatorAddress string + client cosmosClient + logger *zap.Logger + FulfillDemandOrders func(demandOrder ...*demandOrder) error + + releaseAllReservedOrdersFunds func(demandOrder ...*demandOrder) + debitAllReservedOrdersFunds func(demandOrder ...*demandOrder) + newOrdersCh chan []*demandOrder + fulfilledOrdersCh chan<- *orderBatch +} + +type cosmosClient interface { + BroadcastTx(accountName string, msgs ...sdk.Msg) (cosmosclient.Response, error) + Context() client.Context +} + +func newOrderFulfiller( + newOrdersCh chan []*demandOrder, + fulfilledOrdersCh chan<- *orderBatch, + client cosmosClient, + acc account, + policyAddress string, + operatorAddress string, + releaseAllReservedOrdersFunds func(demandOrder ...*demandOrder), + debitAllReservedOrdersFunds func(demandOrder ...*demandOrder), + logger *zap.Logger, +) *orderFulfiller { + o := &orderFulfiller{ + account: acc, + policyAddress: policyAddress, + operatorAddress: operatorAddress, + client: client, + fulfilledOrdersCh: fulfilledOrdersCh, + newOrdersCh: newOrdersCh, + releaseAllReservedOrdersFunds: releaseAllReservedOrdersFunds, + debitAllReservedOrdersFunds: debitAllReservedOrdersFunds, + logger: logger.With(zap.String("module", "order-fulfiller"), + zap.String("bot-name", acc.Name), zap.String("address", acc.Address)), + } + o.FulfillDemandOrders = o.fulfillAuthorizedDemandOrders + return o +} + +// add command that creates all the bots to be used? + +func buildBot( + acc account, + operatorAddress string, + logger *zap.Logger, + cfg config.BotConfig, + clientCfg config.ClientConfig, + newOrderCh chan []*demandOrder, + fulfilledCh chan *orderBatch, + releaseAllReservedOrdersFunds func(demandOrder ...*demandOrder), + debitAllReservedOrdersFunds func(demandOrder ...*demandOrder), +) (*orderFulfiller, error) { + cosmosClient, err := cosmosclient.New(config.GetCosmosClientOptions(clientCfg)...) + if err != nil { + return nil, fmt.Errorf("failed to create cosmos client for bot: %s;err: %w", acc.Name, err) + } + + return newOrderFulfiller( + newOrderCh, + fulfilledCh, + cosmosClient, + acc, + cfg.PolicyAddress, + operatorAddress, + releaseAllReservedOrdersFunds, + debitAllReservedOrdersFunds, + logger, + ), nil +} + +func (ol *orderFulfiller) start(ctx context.Context) error { + ol.logger.Info("starting fulfiller...") + + ol.fulfillOrders(ctx) + return nil +} + +func (ol *orderFulfiller) fulfillOrders(ctx context.Context) { + for { + select { + case <-ctx.Done(): + return + case orders := <-ol.newOrdersCh: + if err := ol.processBatch(orders); err != nil { + ol.logger.Error("failed to process batch", zap.Error(err)) + } + } + } +} + +func (ol *orderFulfiller) processBatch(batch []*demandOrder) error { + if len(batch) == 0 { + ol.logger.Debug("no orders to fulfill") + return nil + } + + var ids []string + for _, order := range batch { + ids = append(ids, order.id) + } + + ol.logger.Info("fulfilling orders", zap.Strings("ids", ids)) + + if err := ol.FulfillDemandOrders(batch...); err != nil { + ol.releaseAllReservedOrdersFunds(batch...) + return fmt.Errorf("failed to fulfill orders: ids: %v; %w", ids, err) + } else { + ol.debitAllReservedOrdersFunds(batch...) + } + + ol.logger.Info("orders fulfilled", zap.Strings("ids", ids)) + + go func() { + if len(ids) == 0 { + return + } + + ol.fulfilledOrdersCh <- &orderBatch{ + orders: batch, + fulfiller: ol.account.Address, // TODO + } + }() + + return nil +} + +/* +1. dymd tx eibc fulfill-order-authorized 388cedaafbe9ea05c5b6422970005d4a9cb13b2b679afedb99aa82ccff8784aa 10 --rollapp-id rollappwasme_1235-1 --fulfiller-address dym1s5y26zt0msaypsafujrltq7f0h04zzu0e8q5kr --operator-address dym1qhxedstgx9fv3zmjuj687y6lh5cwm9czhqajhw --price 1000adym --fulfiller-fee-part 0.4 --settlement-validated --from alex --generate-only > tx.json +2. dymd tx authz exec tx.json --from dym1c799jddmlz7segvg6jrw6w2k6svwafganjdznard3tc74n7td7rqrx4c5e --fees 1dym -y --generate-only > tx_exec.json +3. dymd tx group submit-proposal proposal.json --from xela --fees 1dym --exec try --gas auto --fee-granter dym1qhxedstgx9fv3zmjuj687y6lh5cwm9czhqajhw -y +*/ +func (ol *orderFulfiller) fulfillAuthorizedDemandOrders(demandOrder ...*demandOrder) error { + fulfillMsgs := make([]sdk.Msg, len(demandOrder)) + + for i, order := range demandOrder { + fulfillMsgs[i] = types.NewMsgFulfillOrderAuthorized( + order.id, + order.rollappId, + order.lpAddress, + ol.operatorAddress, + order.fee.Amount.String(), + order.amount, + order.operatorFeePart, + order.settlementValidated, + ) + } + + // bech32 decode the policy address + _, policyAddress, err := bech32.DecodeAndConvert(ol.policyAddress) + if err != nil { + return fmt.Errorf("failed to decode policy address: %w", err) + } + + authzMsg := authz.NewMsgExec(policyAddress, fulfillMsgs) + + proposalMsg, err := types.NewMsgSubmitProposal( + ol.policyAddress, + []string{ol.account.Address}, + []sdk.Msg{&authzMsg}, + "== Fulfill Order ==", + types.Exec_EXEC_TRY, + "fulfill-order-authorized", + "fulfill-order-authorized", + ) + if err != nil { + return fmt.Errorf("failed to create proposal message: %w", err) + } + + rsp, err := ol.client.BroadcastTx(ol.account.Name, proposalMsg) + if err != nil { + return fmt.Errorf("failed to broadcast tx: %w", err) + } + + ol.logger.Info("broadcast tx", zap.String("tx-hash", rsp.TxHash)) + + resp, err := waitForTx(ol.client, rsp.TxHash) + if err != nil { + return fmt.Errorf("failed to wait for tx: %w", err) + } + + var presp []proposalResp + if err = json.Unmarshal([]byte(resp.TxResponse.RawLog), &presp); err != nil { + return fmt.Errorf("failed to unmarshal tx response: %w", err) + } + + // hack to extract error from logs + for _, p := range presp { + for _, ev := range p.Events { + if ev.Type == "cosmos.group.v1.EventExec" { + for _, attr := range ev.Attributes { + if attr.Key == "logs" && strings.Contains(attr.Value, "proposal execution failed") { + theErr := "" + parts := strings.Split(attr.Value, " : ") + if len(parts) > 1 { + theErr = parts[1] + } else { + theErr = attr.Value + } + return fmt.Errorf("proposal execution failed: %s", theErr) + } + } + } + } + } + + ol.logger.Info("tx executed", zap.String("tx-hash", rsp.TxHash)) + + return nil +} + +type proposalResp struct { + MsgIndex int `json:"msg_index"` + Events []struct { + Type string `json:"type"` + Attributes []struct { + Key string `json:"key"` + Value string `json:"value"` + } `json:"attributes"` + } `json:"events"` +} diff --git a/order_poller.go b/eibc/order_poller.go similarity index 57% rename from order_poller.go rename to eibc/order_poller.go index b385ee8..11084e5 100644 --- a/order_poller.go +++ b/eibc/order_poller.go @@ -1,4 +1,4 @@ -package main +package eibc import ( "context" @@ -12,43 +12,39 @@ import ( "time" sdk "github.com/cosmos/cosmos-sdk/types" - "github.com/dymensionxyz/cosmosclient/cosmosclient" "go.uber.org/zap" + + "github.com/dymensionxyz/eibc-client/config" ) type orderPoller struct { - client cosmosclient.Client + chainID string indexerURL string interval time.Duration indexerClient *http.Client logger *zap.Logger - batchSize int - newOrders chan []*demandOrder - canFulfillOrder func(*demandOrder) bool + getOrders func() ([]Order, error) + orderTracker *orderTracker sync.Mutex - pathMap map[string]string } func newOrderPoller( - client cosmosclient.Client, - canFulfillOrder func(*demandOrder) bool, - pollingCfg OrderPollingConfig, - batchSize int, - newOrders chan []*demandOrder, + chainID string, + orderTracker *orderTracker, + pollingCfg config.OrderPollingConfig, logger *zap.Logger, ) *orderPoller { - return &orderPoller{ - client: client, - indexerURL: pollingCfg.IndexerURL, - interval: pollingCfg.Interval, - batchSize: batchSize, - logger: logger.With(zap.String("module", "order-poller")), - newOrders: newOrders, - canFulfillOrder: canFulfillOrder, - pathMap: make(map[string]string), - indexerClient: &http.Client{Timeout: 25 * time.Second}, + o := &orderPoller{ + chainID: chainID, + indexerURL: pollingCfg.IndexerURL, + interval: pollingCfg.Interval, + logger: logger.With(zap.String("module", "order-poller")), + orderTracker: orderTracker, + indexerClient: &http.Client{Timeout: 25 * time.Second}, } + o.getOrders = o.getDemandOrdersFromIndexer + return o } const ( @@ -71,7 +67,11 @@ type ordersResponse struct { } `json:"data"` } -func (p *orderPoller) start(ctx context.Context) { +func (p *orderPoller) start(ctx context.Context) error { + if err := p.pollPendingDemandOrders(); err != nil { + return fmt.Errorf("failed to refresh demand orders: %w", err) + } + go func() { for c := time.Tick(p.interval); ; <-c { select { @@ -84,35 +84,34 @@ func (p *orderPoller) start(ctx context.Context) { } } }() + return nil } func (p *orderPoller) pollPendingDemandOrders() error { - demandOrders, err := p.getDemandOrdersFromIndexer() + demandOrders, err := p.getOrders() if err != nil { return fmt.Errorf("failed to get demand orders: %w", err) } - orders := p.convertOrders(demandOrders) - batch := make([]*demandOrder, 0, p.batchSize) - ids := make([]string, 0, len(orders)) + newOrders := p.convertOrders(demandOrders) - for _, order := range orders { - batch = append(batch, order) - ids = append(ids, order.id) - - if len(batch) >= p.batchSize || len(batch) == len(orders) { - p.newOrders <- batch - batch = make([]*demandOrder, 0, p.batchSize) - ids = make([]string, 0, len(orders)) + if len(newOrders) == 0 { + p.logger.Debug("no new orders") + return nil + } - if p.logger.Level() <= zap.DebugLevel { - p.logger.Debug("new orders batch", zap.Strings("count", ids)) - } else { - p.logger.Info("new orders batch", zap.Int("count", len(ids))) - } + if p.logger.Level() <= zap.DebugLevel { + ids := make([]string, 0, len(newOrders)) + for _, order := range newOrders { + ids = append(ids, order.id) } + p.logger.Debug("new demand orders", zap.Strings("ids", ids)) + } else { + p.logger.Info("new demand orders", zap.Int("count", len(newOrders))) } + p.orderTracker.addOrder(newOrders...) + return nil } @@ -123,40 +122,47 @@ func (p *orderPoller) convertOrders(demandOrders []Order) (orders []*demandOrder continue } - fee, err := sdk.ParseCoinsNormalized(order.Fee) + fee, err := sdk.ParseCoinNormalized(order.Fee) if err != nil { p.logger.Error("failed to parse fee", zap.Error(err)) continue } - denom := fee.GetDenomByIndex(0) - - amountStr := fmt.Sprintf("%s%s", order.Amount, denom) + amountStr := fmt.Sprintf("%s%s", order.Amount, fee.Denom) amount, err := sdk.ParseCoinsNormalized(amountStr) if err != nil { p.logger.Error("failed to parse amount", zap.Error(err)) continue } - var blockHeight uint64 + var blockHeight int64 if order.BlockHeight != "" { - blockHeight, err = strconv.ParseUint(order.BlockHeight, 10, 64) + blockHeight, err = strconv.ParseInt(order.BlockHeight, 10, 64) if err != nil { p.logger.Error("failed to parse block height", zap.Error(err)) continue } } + validationWaitTime := p.orderTracker.validation.ValidationWaitTime + validDeadline := time.Now().Add(validationWaitTime) + newOrder := &demandOrder{ - id: order.EibcOrderId, - amount: amount, - fee: fee, - denom: denom, - rollappId: order.RollappId, - blockHeight: blockHeight, + id: order.EibcOrderId, + amount: amount, + fee: fee, + denom: fee.Denom, + rollappId: order.RollappId, + proofHeight: blockHeight, + validDeadline: validDeadline, + } + + if !p.orderTracker.canFulfillOrder(newOrder) { + continue } - if !p.canFulfillOrder(newOrder) { + if err := p.orderTracker.findLPForOrder(newOrder); err != nil { + p.logger.Warn("failed to find LP for order", zap.Error(err), zap.String("order_id", newOrder.id)) continue } @@ -164,7 +170,7 @@ func (p *orderPoller) convertOrders(demandOrders []Order) (orders []*demandOrder } sort.Slice(orders, func(i, j int) bool { - return orders[i].blockHeight < orders[j].blockHeight + return orders[i].proofHeight < orders[j].proofHeight }) return orders } @@ -172,7 +178,7 @@ func (p *orderPoller) convertOrders(demandOrders []Order) (orders []*demandOrder func (p *orderPoller) getDemandOrdersFromIndexer() ([]Order, error) { p.logger.Debug("getting demand orders from indexer") - queryStr := fmt.Sprintf(ordersQuery, p.client.Context().ChainID) + queryStr := fmt.Sprintf(ordersQuery, p.chainID) body := strings.NewReader(queryStr) resp, err := p.indexerClient.Post(p.indexerURL, "application/json", body) diff --git a/eibc/order_tracker.go b/eibc/order_tracker.go new file mode 100644 index 0000000..830a24b --- /dev/null +++ b/eibc/order_tracker.go @@ -0,0 +1,448 @@ +package eibc + +import ( + "context" + "fmt" + "math/rand" + "sort" + "sync" + "time" + + sdk "github.com/cosmos/cosmos-sdk/types" + "github.com/cosmos/cosmos-sdk/x/authz" + banktypes "github.com/cosmos/cosmos-sdk/x/bank/types" + "github.com/cosmos/gogoproto/proto" + "go.uber.org/zap" + "google.golang.org/grpc" + + "github.com/dymensionxyz/eibc-client/config" + "github.com/dymensionxyz/eibc-client/types" +) + +type orderTracker struct { + getBalances getSpendableBalancesFn + getLPGrants getLPGrantsFn + fullNodeClient *nodeClient + logger *zap.Logger + bots map[string]*orderFulfiller + policyAddress string + + fomu sync.Mutex + lpmu sync.Mutex + fulfilledOrders map[string]*demandOrder + validOrdersCh chan []*demandOrder + outputOrdersCh chan<- []*demandOrder + lps map[string]*lp + minOperatorFeeShare sdk.Dec + + pool orderPool + + batchSize int + validation *config.ValidationConfig + fulfilledOrdersCh chan *orderBatch + subscriberID string + balanceRefreshInterval time.Duration +} + +type ( + getSpendableBalancesFn func(ctx context.Context, in *banktypes.QuerySpendableBalancesRequest, opts ...grpc.CallOption) (*banktypes.QuerySpendableBalancesResponse, error) + getLPGrantsFn func(ctx context.Context, in *authz.QueryGranteeGrantsRequest, opts ...grpc.CallOption) (*authz.QueryGranteeGrantsResponse, error) +) + +func newOrderTracker( + hubClient cosmosClient, + policyAddress string, + minOperatorFeeShare sdk.Dec, + fullNodeClient *nodeClient, + fulfilledOrdersCh chan *orderBatch, + bots map[string]*orderFulfiller, + subscriberID string, + batchSize int, + validation *config.ValidationConfig, + ordersCh chan<- []*demandOrder, + balanceRefreshInterval time.Duration, + logger *zap.Logger, +) *orderTracker { + azc := authz.NewQueryClient(hubClient.Context()) + bc := banktypes.NewQueryClient(hubClient.Context()) + return &orderTracker{ + getBalances: bc.SpendableBalances, + getLPGrants: azc.GranteeGrants, + policyAddress: policyAddress, + minOperatorFeeShare: minOperatorFeeShare, + fullNodeClient: fullNodeClient, + pool: orderPool{orders: make(map[string]*demandOrder)}, + fulfilledOrdersCh: fulfilledOrdersCh, + bots: bots, + lps: make(map[string]*lp), + batchSize: batchSize, + validation: validation, + validOrdersCh: make(chan []*demandOrder), + outputOrdersCh: ordersCh, + logger: logger.With(zap.String("module", "order-resolver")), + subscriberID: subscriberID, + balanceRefreshInterval: balanceRefreshInterval, + fulfilledOrders: make(map[string]*demandOrder), + } +} + +func (or *orderTracker) start(ctx context.Context) error { + if err := or.refreshLPs(ctx); err != nil { + return fmt.Errorf("failed to load LPs: %w", err) + } + + or.selectOrdersWorker(ctx) + + go or.fulfilledOrdersWorker(ctx) + + return nil +} + +func (or *orderTracker) refreshLPs(ctx context.Context) error { + if err := or.loadLPs(ctx); err != nil { + return fmt.Errorf("failed to load LPs: %w", err) + } + + go or.lpLoader(ctx) + go or.balanceRefresher(ctx) + + return nil +} + +func (or *orderTracker) lpLoader(ctx context.Context) { + t := time.NewTicker(5 * time.Minute) + for { + select { + case <-ctx.Done(): + return + case <-t.C: + if err := or.loadLPs(ctx); err != nil { + or.logger.Error("failed to load LPs", zap.Error(err)) + } + } + } +} + +func (or *orderTracker) loadLPs(ctx context.Context) error { + grants, err := or.getLPGrants(ctx, &authz.QueryGranteeGrantsRequest{ + Grantee: or.policyAddress, + }) + if err != nil { + return fmt.Errorf("failed to get LP grants: %w", err) + } + + or.lpmu.Lock() + defer or.lpmu.Unlock() + + for _, grant := range grants.Grants { + if grant.Authorization == nil { + continue + } + + g := new(types.FulfillOrderAuthorization) + if err = proto.Unmarshal(grant.Authorization.Value, g); err != nil { + return fmt.Errorf("failed to unmarshal grant: %w", err) + } + + resp, err := or.getBalances(ctx, &banktypes.QuerySpendableBalancesRequest{ + Address: grant.Granter, + }) + if err != nil { + return fmt.Errorf("failed to get LP balances: %w", err) + } + + lp := &lp{ + address: grant.Granter, + rollapps: make(map[string]rollappCriteria), + balance: resp.Balances, + } + + for _, rollapp := range g.Rollapps { + // check the operator fee is the minimum for what the operator wants + if rollapp.OperatorFeeShare.Dec.LT(or.minOperatorFeeShare) { + continue + } + + denoms := make(map[string]bool) + for _, denom := range rollapp.Denoms { + denoms[denom] = true + } + lp.rollapps[rollapp.RollappId] = rollappCriteria{ + rollappID: rollapp.RollappId, + denoms: denoms, + maxPrice: rollapp.MaxPrice, + minFeePercentage: rollapp.MinLpFeePercentage.Dec, + operatorFeeShare: rollapp.OperatorFeeShare.Dec, + settlementValidated: rollapp.SettlementValidated, + } + } + + if len(lp.rollapps) == 0 { + continue + } + + or.lps[grant.Granter] = lp + } + + return nil +} + +// Demand orders are first added: +// - in sequencer mode, the first batch is sent to the output channel, and the rest of the orders are added to the pool +// - in p2p and settlement mode, all orders are added to the pool +// Then, the orders are periodically popped (fetched and deleted) from the pool and checked for validity. +// If the order is valid, it is sent to the output channel. +// If the order is not valid, it is added back to the pool. +// After the order validity deadline is expired, the order is removed permanently. +// Once an order is fulfilled, it is removed from the store +func (or *orderTracker) selectOrdersWorker(ctx context.Context) { + toCheckOrdersCh := make(chan []*demandOrder, or.batchSize) + go or.pullOrders(ctx, toCheckOrdersCh) + go or.enqueueValidOrders(ctx, toCheckOrdersCh) +} + +func (or *orderTracker) pullOrders(ctx context.Context, toCheckOrdersCh chan []*demandOrder) { + ticker := time.NewTicker(500 * time.Millisecond) + for { + select { + case <-ctx.Done(): + return + case <-ticker.C: + orders := or.pool.popOrders(or.batchSize) + if len(orders) == 0 { + continue + } + // in "sequencer" mode send the orders directly to be fulfilled, + // in other modes, send the orders to be checked for validity + if or.validation.FallbackLevel == config.ValidationModeSequencer { + or.outputOrdersCh <- orders + } else { + toCheckOrdersCh <- orders + } + } + } +} + +func (or *orderTracker) enqueueValidOrders(ctx context.Context, toCheckOrdersCh <-chan []*demandOrder) { + for { + select { + case <-ctx.Done(): + return + case orders := <-toCheckOrdersCh: + validOrders, retryOrders := or.getValidAndRetryOrders(ctx, orders) + if len(validOrders) > 0 { + or.outputOrdersCh <- validOrders + } + if len(retryOrders) > 0 { + or.pool.addOrder(retryOrders...) + } + } + } +} + +func (or *orderTracker) getValidAndRetryOrders(ctx context.Context, orders []*demandOrder) (validOrders, invalidOrders []*demandOrder) { + for _, order := range orders { + expectedValidationLevel := validationLevelP2P + if order.settlementValidated { + expectedValidationLevel = validationLevelSettlement + } + valid, err := or.fullNodeClient.BlockValidated(ctx, order.rollappId, order.proofHeight, expectedValidationLevel) + if err != nil { + or.logger.Error("failed to check validation of block", zap.Error(err)) + continue + } + if valid { + validOrders = append(validOrders, order) + continue + } + if or.isOrderExpired(order) { + or.releaseAllReservedOrdersFunds(order) + or.logger.Debug("order has expired", zap.String("id", order.id)) + continue + } + or.logger.Debug("order is not valid yet", zap.String("id", order.id)) + // order is not valid yet, so add it back to the pool + invalidOrders = append(invalidOrders, order) + } + return +} + +func (or *orderTracker) isOrderExpired(order *demandOrder) bool { + return time.Now().After(order.validDeadline) +} + +func (or *orderTracker) addOrder(orders ...*demandOrder) { + // - in mode "sequencer" we send a batch directly to be fulfilled, + // and any orders that overflow the batch are added to the pool + // - in mode "p2p" and "settlement" all orders are added to the pool + if or.validation.FallbackLevel == config.ValidationModeSequencer { + var ( + batchToSend []*demandOrder + batchToPool []*demandOrder + ) + // send one batch to fulfilling, add the rest to the pool + for _, o := range orders { + if len(batchToSend) < or.batchSize { + batchToSend = append(batchToSend, o) + continue + } + batchToPool = append(batchToPool, o) + } + or.outputOrdersCh <- batchToSend + orders = batchToPool + } + or.pool.addOrder(orders...) +} + +func (or *orderTracker) fulfilledOrdersWorker(ctx context.Context) { + for { + select { + case batch := <-or.fulfilledOrdersCh: + if err := or.addFulfilledOrders(batch); err != nil { + or.logger.Error("failed to add fulfilled orders", zap.Error(err)) + } + case <-ctx.Done(): + return + } + } +} + +// addFulfilledOrders adds the fulfilled orders to the fulfilledOrders cache, and removes them from the orderPool. +// It also persists the state to the database. +func (or *orderTracker) addFulfilledOrders(batch *orderBatch) error { + or.fomu.Lock() + for _, order := range batch.orders { + if len(order.amount) == 0 { + continue + } + // add to cache + or.fulfilledOrders[order.id] = order + or.pool.removeOrder(order.id) // just in case it's still in the pool + } + or.fomu.Unlock() + return nil +} + +func (or *orderTracker) canFulfillOrder(order *demandOrder) bool { + if !or.isRollappSupported(order.rollappId) { + return false + } + + if or.isOrderFulfilled(order.id) { + return false + } + // we are already processing this order + if or.isOrderInPool(order.id) { + return false + } + + return true +} + +func (or *orderTracker) findLPForOrder(order *demandOrder) error { + or.lpmu.Lock() + defer or.lpmu.Unlock() + + lps := or.filterLPsForOrder(order) + if len(lps) == 0 { + return fmt.Errorf("no LPs found for order") + } + + // randomize the list of LPs to avoid always selecting the same one + // this is important for the case where multiple LPs have the same operatorFeeShare + // and the same settlementValidated status + shuffleLPs(lps) + + bestLP := selectBestLP(lps, order.rollappId) + if bestLP == nil { + return fmt.Errorf("LP not found") + } + + order.lpAddress = bestLP.address + order.settlementValidated = bestLP.rollapps[order.rollappId].settlementValidated + order.operatorFeePart = bestLP.rollapps[order.rollappId].operatorFeeShare + + // optimistically deduct from the LP's balance + bestLP.reserveFunds(order.amount) + + return nil +} + +func shuffleLPs(lps []*lp) { + rand.Shuffle(len(lps), func(i, j int) { + lps[i], lps[j] = lps[j], lps[i] + }) +} + +func (or *orderTracker) filterLPsForOrder(order *demandOrder) []*lp { + lps := make([]*lp, 0, len(or.lps)) + for _, lp := range or.lps { + amount := order.amount + if !lp.hasBalance(amount) { + continue + } + + // check the rollapp is allowed + rollapp, ok := lp.rollapps[order.rollappId] + if !ok { + continue + } + + // check the denom is allowed + if len(rollapp.denoms) > 0 && !rollapp.denoms[order.fee.Denom] { + continue + } + + // check the order price does not exceed the max price + if rollapp.maxPrice.IsAllPositive() && order.amount.IsAnyGT(rollapp.maxPrice) { + continue + } + + // check the fee is at least the minimum for what the lp wants + operatorFee := sdk.NewDecFromInt(order.fee.Amount).Mul(rollapp.operatorFeeShare).RoundInt() + amountDec := sdk.NewDecFromInt(order.amount[0].Amount.Add(order.fee.Amount)) + minLPFee := amountDec.Mul(rollapp.minFeePercentage).RoundInt() + lpFee := order.fee.Amount.Sub(operatorFee) + + if lpFee.LT(minLPFee) { + continue + } + + lps = append(lps, lp) + } + return lps +} + +func selectBestLP(lps []*lp, rollappID string) *lp { + if len(lps) == 0 { + return nil + } + + sort.Slice(lps, func(i, j int) bool { + // first criterion: settlementValidated (false comes before true) + if lps[i].rollapps[rollappID].settlementValidated != lps[j].rollapps[rollappID].settlementValidated { + return !lps[i].rollapps[rollappID].settlementValidated && lps[j].rollapps[rollappID].settlementValidated + } + // second criterion: higher operatorFeeShare + return lps[i].rollapps[rollappID].operatorFeeShare.GT(lps[j].rollapps[rollappID].operatorFeeShare) + }) + + return lps[0] +} + +func (or *orderTracker) isRollappSupported(rollappID string) bool { + _, ok := or.fullNodeClient.rollapps[rollappID] + return ok +} + +func (or *orderTracker) isOrderFulfilled(id string) bool { + or.fomu.Lock() + defer or.fomu.Unlock() + + _, ok := or.fulfilledOrders[id] + return ok +} + +func (or *orderTracker) isOrderInPool(id string) bool { + return or.pool.hasOrder(id) +} diff --git a/eibc/pool.go b/eibc/pool.go new file mode 100644 index 0000000..dfef2a3 --- /dev/null +++ b/eibc/pool.go @@ -0,0 +1,53 @@ +package eibc + +import "sync" + +// orderPool is the order pool used for tracking orders that are waiting to be fulfilled +type orderPool struct { + opmu sync.Mutex + orders map[string]*demandOrder +} + +func (op *orderPool) addOrder(order ...*demandOrder) { + op.opmu.Lock() + defer op.opmu.Unlock() + + for _, o := range order { + // skip if the order is already in the pool + if op.orders[o.id] != nil { + continue + } + op.orders[o.id] = o + } +} + +func (op *orderPool) removeOrder(id string) { + op.opmu.Lock() + defer op.opmu.Unlock() + + delete(op.orders, id) +} + +func (op *orderPool) hasOrder(id string) bool { + op.opmu.Lock() + defer op.opmu.Unlock() + + _, ok := op.orders[id] + return ok +} + +func (op *orderPool) popOrders(limit int) []*demandOrder { + op.opmu.Lock() + defer op.opmu.Unlock() + + var orders []*demandOrder + for _, order := range op.orders { + orders = append(orders, order) + delete(op.orders, order.id) + if len(orders) == limit { + break + } + } + + return orders +} diff --git a/eibc/types.go b/eibc/types.go new file mode 100644 index 0000000..d06ecc4 --- /dev/null +++ b/eibc/types.go @@ -0,0 +1,31 @@ +package eibc + +import ( + "time" + + sdk "github.com/cosmos/cosmos-sdk/types" +) + +type orderBatch struct { + orders []*demandOrder + fulfiller string +} + +type demandOrder struct { + id string + denom string + amount sdk.Coins + fee sdk.Coin + rollappId string + status string + proofHeight int64 + validDeadline time.Time + settlementValidated bool + operatorFeePart sdk.Dec + lpAddress string +} + +type account struct { + Name string `json:"name"` + Address string `json:"address"` +} diff --git a/go.mod b/go.mod index 827b9aa..48a1e5c 100644 --- a/go.mod +++ b/go.mod @@ -4,20 +4,17 @@ go 1.22.2 require ( cosmossdk.io/errors v1.0.1 + github.com/cosmos/cosmos-proto v1.0.0-beta.3 github.com/cosmos/cosmos-sdk v0.46.16 github.com/cosmos/gogoproto v1.5.0 - github.com/cosmos/ibc-go/v6 v6.2.1 - github.com/dymensionxyz/cosmosclient v0.4.2-beta.0.20240821141048-7a6b0d748908 + github.com/dymensionxyz/cosmosclient v0.4.2-beta.0.20241030100014-36b8a586fdf3 github.com/google/uuid v1.6.0 github.com/ignite/cli v0.26.1 github.com/mitchellh/go-homedir v1.1.0 - github.com/ory/dockertest/v3 v3.9.1 - github.com/slack-go/slack v0.12.5 github.com/spf13/cobra v1.8.0 github.com/spf13/viper v1.18.1 github.com/stretchr/testify v1.8.4 github.com/tendermint/tendermint v0.34.29 - go.mongodb.org/mongo-driver v1.15.0 go.uber.org/zap v1.24.0 google.golang.org/grpc v1.62.1 gopkg.in/yaml.v3 v3.0.1 @@ -28,10 +25,7 @@ require ( filippo.io/edwards25519 v1.0.0-rc.1 // indirect github.com/99designs/go-keychain v0.0.0-20191008050251-8e49817e8af4 // indirect github.com/99designs/keyring v1.2.1 // indirect - github.com/Azure/go-ansiterm v0.0.0-20230124172434-306776ec8161 // indirect github.com/ChainSafe/go-schnorrkel v1.0.0 // indirect - github.com/Microsoft/go-winio v0.6.1 // indirect - github.com/Nvveen/Gotty v0.0.0-20120604004816-cd527374f1e5 // indirect github.com/armon/go-metrics v0.4.1 // indirect github.com/beorn7/perks v1.0.1 // indirect github.com/bgentry/speakeasy v0.1.1-0.20220910012023-760eaf8b6816 // indirect @@ -41,26 +35,21 @@ require ( github.com/btcsuite/btcd/btcutil v1.1.3 // indirect github.com/btcsuite/btcd/chaincfg/chainhash v1.0.1 // indirect github.com/cenkalti/backoff v2.2.1+incompatible // indirect - github.com/cenkalti/backoff/v4 v4.1.3 // indirect github.com/cespare/xxhash v1.1.0 // indirect github.com/cespare/xxhash/v2 v2.2.0 // indirect + github.com/cockroachdb/apd/v2 v2.0.2 // indirect github.com/confio/ics23/go v0.9.0 // indirect - github.com/containerd/continuity v0.3.0 // indirect github.com/cosmos/btcutil v1.0.5 // indirect - github.com/cosmos/cosmos-proto v1.0.0-beta.3 // indirect github.com/cosmos/go-bip39 v1.0.0 // indirect github.com/cosmos/gorocksdb v1.2.0 // indirect github.com/cosmos/iavl v0.19.6 // indirect + github.com/cosmos/ibc-go/v6 v6.2.1 // indirect github.com/cosmos/ledger-cosmos-go v0.12.4 // indirect github.com/danieljoos/wincred v1.1.2 // indirect github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc // indirect github.com/decred/dcrd/dcrec/secp256k1/v4 v4.1.0 // indirect github.com/dgraph-io/badger/v3 v3.2103.3 // indirect github.com/dgraph-io/ristretto v0.1.1 // indirect - github.com/docker/cli v23.0.1+incompatible // indirect - github.com/docker/docker v23.0.1+incompatible // indirect - github.com/docker/go-connections v0.4.0 // indirect - github.com/docker/go-units v0.5.0 // indirect github.com/dustin/go-humanize v1.0.1 // indirect github.com/dvsekhvalnov/jose2go v1.5.0 // indirect github.com/ethereum/go-ethereum v1.10.26 // indirect @@ -79,7 +68,6 @@ require ( github.com/google/btree v1.1.2 // indirect github.com/google/flatbuffers v2.0.8+incompatible // indirect github.com/google/go-cmp v0.6.0 // indirect - github.com/google/shlex v0.0.0-20191202100458-e7afc7fbc510 // indirect github.com/gorilla/mux v1.8.1 // indirect github.com/gorilla/websocket v1.5.0 // indirect github.com/grpc-ecosystem/go-grpc-middleware v1.3.0 // indirect @@ -92,7 +80,6 @@ require ( github.com/hashicorp/golang-lru v0.5.5-0.20210104140557-80c98217689d // indirect github.com/hashicorp/hcl v1.0.0 // indirect github.com/hdevalence/ed25519consensus v0.0.0-20220222234857-c00d1f31bab3 // indirect - github.com/imdario/mergo v0.3.13 // indirect github.com/inconshreveable/mousetrap v1.1.0 // indirect github.com/jmhodges/levigo v1.0.0 // indirect github.com/klauspost/compress v1.17.0 // indirect @@ -102,12 +89,7 @@ require ( github.com/matttproud/golang_protobuf_extensions v1.0.4 // indirect github.com/mimoo/StrobeGo v0.0.0-20220103164710-9a04d6ca976b // indirect github.com/mitchellh/mapstructure v1.5.0 // indirect - github.com/moby/term v0.0.0-20221205130635-1aeaba878587 // indirect - github.com/montanaflynn/stats v0.0.0-20171201202039-1bf9dbcd8cbe // indirect github.com/mtibben/percent v0.2.1 // 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.4 // indirect github.com/pelletier/go-toml/v2 v2.1.0 // indirect github.com/petermattis/goid v0.0.0-20230317030725-371a4b8eda08 // indirect github.com/pkg/errors v0.9.1 // indirect @@ -117,12 +99,10 @@ require ( github.com/prometheus/common v0.42.0 // indirect github.com/prometheus/procfs v0.12.0 // indirect github.com/rcrowley/go-metrics v0.0.0-20201227073835-cf1acfcdf475 // indirect - github.com/regen-network/cosmos-proto v0.3.1 // indirect github.com/rs/cors v1.9.0 // indirect github.com/sagikazarmark/locafero v0.4.0 // indirect github.com/sagikazarmark/slog-shim v0.1.0 // indirect github.com/sasha-s/go-deadlock v0.3.1 // indirect - github.com/sirupsen/logrus v1.9.3 // indirect github.com/sourcegraph/conc v0.3.0 // indirect github.com/spf13/afero v1.11.0 // indirect github.com/spf13/cast v1.6.0 // indirect @@ -137,13 +117,6 @@ require ( github.com/tidwall/pretty v1.2.0 // indirect github.com/tidwall/sjson v1.2.5 // indirect github.com/tyler-smith/go-bip39 v1.1.0 // indirect - github.com/xdg-go/pbkdf2 v1.0.0 // indirect - github.com/xdg-go/scram v1.1.2 // indirect - github.com/xdg-go/stringprep v1.0.4 // indirect - github.com/xeipuuv/gojsonpointer v0.0.0-20190905194746-02993c407bfb // indirect - github.com/xeipuuv/gojsonreference v0.0.0-20180127040603-bd5ef7bd5415 // indirect - github.com/xeipuuv/gojsonschema v1.2.0 // indirect - github.com/youmark/pkcs8 v0.0.0-20181117223130-1be2e3e5546d // indirect github.com/zondax/hid v0.9.2 // indirect github.com/zondax/ledger-go v0.14.3 // indirect go.etcd.io/bbolt v1.3.8 // indirect @@ -160,7 +133,6 @@ require ( golang.org/x/sys v0.18.0 // indirect golang.org/x/term v0.18.0 // indirect golang.org/x/text v0.14.0 // indirect - golang.org/x/tools v0.14.0 // indirect google.golang.org/genproto v0.0.0-20240123012728-ef4313101c80 // indirect google.golang.org/genproto/googleapis/api v0.0.0-20240125205218-1f4bbc51befe // indirect google.golang.org/genproto/googleapis/rpc v0.0.0-20240125205218-1f4bbc51befe // indirect diff --git a/go.sum b/go.sum index c916a8d..339db06 100644 --- a/go.sum +++ b/go.sum @@ -20,16 +20,10 @@ github.com/99designs/go-keychain v0.0.0-20191008050251-8e49817e8af4 h1:/vQbFIOMb github.com/99designs/go-keychain v0.0.0-20191008050251-8e49817e8af4/go.mod h1:hN7oaIRCjzsZ2dE+yG5k+rsdt3qcwykqK6HVGcKwsw4= github.com/99designs/keyring v1.2.1 h1:tYLp1ULvO7i3fI5vE21ReQuj99QFSs7lGm0xWyJo87o= github.com/99designs/keyring v1.2.1/go.mod h1:fc+wB5KTk9wQ9sDx0kFXB3A0MaeGHM9AwRStKOQ5vOA= -github.com/Azure/go-ansiterm v0.0.0-20230124172434-306776ec8161 h1:L/gRVlceqvL25UVaW/CKtUDjefjrs0SPonmDGUVOYP0= -github.com/Azure/go-ansiterm v0.0.0-20230124172434-306776ec8161/go.mod h1:xomTg63KZ2rFqZQzSB4Vz2SUXa1BpHTVz9L5PTmPC4E= github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= github.com/ChainSafe/go-schnorrkel v1.0.0 h1:3aDA67lAykLaG1y3AOjs88dMxC88PgUuHRrLeDnvGIM= github.com/ChainSafe/go-schnorrkel v1.0.0/go.mod h1:dpzHYVxLZcp8pjlV+O+UR8K0Hp/z7vcchBSbMBEhCw4= github.com/DataDog/datadog-go v3.2.0+incompatible/go.mod h1:LButxg5PwREeZtORoXG3tL4fMGNddJ+vMq1mwgfaqoQ= -github.com/Microsoft/go-winio v0.6.1 h1:9/kr64B9VUZrLm5YYwbGtUJnMgqWVOdUAXu6Migciow= -github.com/Microsoft/go-winio v0.6.1/go.mod h1:LRdKpFKfdobln8UmuiYcKPot9D2v6svN5+sAH+4kjUM= -github.com/Nvveen/Gotty v0.0.0-20120604004816-cd527374f1e5 h1:TngWCqHvy9oXAN6lEVMRuU21PR1EtLVZJmdB18Gu3Rw= -github.com/Nvveen/Gotty v0.0.0-20120604004816-cd527374f1e5/go.mod h1:lmUJ/7eu/Q8D7ML55dXQrVaamCz2vxCfdQBasLZfHKk= github.com/OneOfOne/xxhash v1.2.2 h1:KMrpdQIwFcEqXDklaen+P1axHaj9BSKzvpUUfnHldSE= github.com/OneOfOne/xxhash v1.2.2/go.mod h1:HSdplMjZKSmBqAxg5vPj2TmRDmfkzw+cTzAElWljhcU= github.com/StackExchange/wmi v1.2.1 h1:VIkavFPXSjcnS+O8yTq7NI32k0R5Aj+v39y29VYDOSA= @@ -98,13 +92,11 @@ 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/chzyer/logex v1.1.10/go.mod h1:+Ywpsq7O8HXn0nuIou7OrIPyXbp3wmkHB+jjWRnGsAI= github.com/chzyer/readline v0.0.0-20180603132655-2972be24d48e/go.mod h1:nSuG5e5PlCu98SY8svDHJxuZscDgtXS6KTTbou5AhLI= github.com/chzyer/readline v1.5.0 h1:lSwwFrbNviGePhkewF1az4oLmcwqCZijQ2/Wi3BGHAI= github.com/chzyer/readline v1.5.0/go.mod h1:x22KAscuvRqlLoK9CsoYsmxoXZMMFVyOl86cAH8qUic= github.com/chzyer/test v0.0.0-20180213035817-a1ea475d72b1/go.mod h1:Q3SI9o4m/ZMnBNeIyt5eFwwo7qiLfzFZmjNmxjkiQlU= -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/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw= @@ -117,13 +109,9 @@ github.com/cometbft/cometbft-db v0.7.0 h1:uBjbrBx4QzU0zOEnU8KxoDl18dMNgDh+zZRUE0 github.com/cometbft/cometbft-db v0.7.0/go.mod h1:yiKJIm2WKrt6x8Cyxtq9YTEcIMPcEe4XPxhgX59Fzf0= 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/v22 v22.3.2/go.mod h1:Y58oyj3AT4RCenI/lSvhwexgC+NSVTIJ3seZv2GcEnc= 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= @@ -144,13 +132,9 @@ github.com/cosmos/ibc-go/v6 v6.2.1/go.mod h1:XLsARy4Y7+GtAqzMcxNdlQf6lx+ti1e8KcM github.com/cosmos/ledger-cosmos-go v0.12.4 h1:drvWt+GJP7Aiw550yeb3ON/zsrgW0jgh5saFCr7pDnw= github.com/cosmos/ledger-cosmos-go v0.12.4/go.mod h1:fjfVWRf++Xkygt9wzCsjEBdjcf7wiiY35fv3ctT+k4M= github.com/cpuguy83/go-md2man v1.0.10/go.mod h1:SmD6nW6nTyfqj6ABTjUi3V3JVMnlJmwcJI5acqYI6dE= -github.com/cpuguy83/go-md2man/v2 v2.0.0-20190314233015-f79a8a8ca69d/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU= github.com/cpuguy83/go-md2man/v2 v2.0.3/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o= github.com/creachadair/taskgroup v0.3.2 h1:zlfutDS+5XG40AOxcHDSThxKzns8Tnr9jnr6VqkYlkM= github.com/creachadair/taskgroup v0.3.2/go.mod h1:wieWwecHVzsidg2CsUnFinW1faVN4+kq+TDlRJQ0Wbk= -github.com/creack/pty v1.1.18 h1:n56/Zwd5o6whRC5PMGretI4IdRLlmBXYNjScPaBgsbY= -github.com/creack/pty v1.1.18/go.mod h1:MOBLtS5ELjhRRrroQr9kyvTxUAFNvYEK993ew/Vr4O4= -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 v0.0.0-20171005155431-ecdeabc65495/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= @@ -179,15 +163,6 @@ 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/dlclark/regexp2 v1.4.1-0.20201116162257-a2a8dda75c91 h1:Izz0+t1Z5nI16/II7vuEo/nHjodOg0p7+OiDpjX5t1E= github.com/dlclark/regexp2 v1.4.1-0.20201116162257-a2a8dda75c91/go.mod h1:2pZnwuY/m+8K6iRw6wQdMtk+rH5tNGR1i55kozfMjCc= -github.com/docker/cli v23.0.1+incompatible h1:LRyWITpGzl2C9e9uGxzisptnxAn1zfZKXy13Ul2Q5oM= -github.com/docker/cli v23.0.1+incompatible/go.mod h1:JLrzqnKDaYBop7H2jaqPtU4hHvMKP+vjCwu2uszcLI8= -github.com/docker/docker v23.0.1+incompatible h1:vjgvJZxprTTE1A37nm+CLNAdwu6xZekyoiVlUZEINcY= -github.com/docker/docker v23.0.1+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/dop251/goja v0.0.0-20220405120441-9037c2b61cbf h1:Yt+4K30SdjOkRoRRm3vYNQgR+/ZIy0RmeUDZo7Y8zeQ= github.com/dop251/goja v0.0.0-20220405120441-9037c2b61cbf/go.mod h1:R9ET47fwRVRPZnOGvHxxhuZcbrMCuiqOz3Rlrh4KSnk= github.com/dustin/go-humanize v1.0.0/go.mod h1:HtrtbFcZ19U5GC7JDqmcUSB87Iq5E25KnS6fMYU6eOk= @@ -197,8 +172,8 @@ github.com/dvsekhvalnov/jose2go v1.5.0 h1:3j8ya4Z4kMCwT5nXIKFSV84YS+HdqSSO0VsTQx github.com/dvsekhvalnov/jose2go v1.5.0/go.mod h1:QsHjhyTlD/lAVqn/NSbVZmSCGeDehTB/mPZadG+mhXU= github.com/dymensionxyz/cometbft v0.34.29-0.20240807121422-5299b866061c h1:urXou6bq/jDqW+g4ZaW63VHjD46OIJDuiRemrtJpnVs= github.com/dymensionxyz/cometbft v0.34.29-0.20240807121422-5299b866061c/go.mod h1:L9shMfbkZ8B+7JlwANEr+NZbBcn+hBpwdbeYvA5rLCw= -github.com/dymensionxyz/cosmosclient v0.4.2-beta.0.20240821141048-7a6b0d748908 h1:p0TX8RFSDxL1Pt4VZEXYcg+3M2uHSFacPlPZEC1NDpI= -github.com/dymensionxyz/cosmosclient v0.4.2-beta.0.20240821141048-7a6b0d748908/go.mod h1:3weqpVj/TqTFpC0LjEB3H+HZSpm7BrQ1QkEg1Ahy6KY= +github.com/dymensionxyz/cosmosclient v0.4.2-beta.0.20241030100014-36b8a586fdf3 h1:KNQw5QBLRwZ+pK3VkcZQG1TzjEOWNQ65XmkiLi1pOyU= +github.com/dymensionxyz/cosmosclient v0.4.2-beta.0.20241030100014-36b8a586fdf3/go.mod h1:3weqpVj/TqTFpC0LjEB3H+HZSpm7BrQ1QkEg1Ahy6KY= github.com/dymensionxyz/evmos/v12 v12.1.6-dymension-v0.4.2 h1:aVP3off7u2vsvRH7lHAUPTLdf9/AfnzC/rvvi0wC/co= github.com/dymensionxyz/evmos/v12 v12.1.6-dymension-v0.4.2/go.mod h1:CI6D89pkoiIm4BjoMFNnEaCLdKBEobLuwvhS0c1zh7Y= github.com/edsrzf/mmap-go v1.0.0 h1:CEBF7HpRnUCSJgGUb5h1Gm7e3VkmVDrR8lvWVLtrOFw= @@ -219,7 +194,6 @@ github.com/felixge/httpsnoop v1.0.1 h1:lvB5Jl89CsZtGIWuTcDM1E/vkVs49/Ml7JJe07l8S github.com/felixge/httpsnoop v1.0.1/go.mod h1:m8KPJKqk1gH5J9DgRY2ASl2lWCfGKXixSwevea8zH2U= github.com/fortytw2/leaktest v1.3.0 h1:u8491cBMTQ8ft8aeV+adlcytMZylmA5nnwwkRZjI8vw= github.com/fortytw2/leaktest v1.3.0/go.mod h1:jDsjWgpAGjm2CA7WthBh/CdZYEPF31XHquHwclZch5g= -github.com/frankban/quicktest v1.11.3/go.mod h1:wRf/ReqHper53s+kmmSZizM8NamnL3IM0I9ntUbOk+k= github.com/frankban/quicktest v1.14.6 h1:7Xjx+VpznH+oBnejlPUj8oUpdxnVs4f8XU8WnHkI4W8= github.com/frankban/quicktest v1.14.6/go.mod h1:4ptaffx2x8+WTWXmUCuVU6aPUX1/Mz7zb5vbUoiM6w0= github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo= @@ -249,17 +223,11 @@ 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-sourcemap/sourcemap v2.1.3+incompatible h1:W1iEw64niKVGogNgBN3ePyLFfuisuzeidWPMPWmECqU= github.com/go-sourcemap/sourcemap v2.1.3+incompatible/go.mod h1:F8jJfvm2KbVjc5NqelyYJmf/v5J0dwNLS2mL4sNA1Jg= -github.com/go-sql-driver/mysql v1.6.0 h1:BCTh4TKNUYmOmMUcQ3IipzF5prigylS7XXjEkfCHuOE= -github.com/go-sql-driver/mysql v1.6.0/go.mod h1:DCzpHaOWr8IXmIStZouvnhqoel9Qv2LBy8hT2VhHyBg= github.com/go-stack/stack v1.8.0 h1:5SgMzNM5HxrEjV0ww2lTmX6E2Izsfxas4+YHWRs3Lsk= github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY= github.com/go-task/slim-sprig v0.0.0-20210107165309-348f09dbbbc0/go.mod h1:fyg7847qk6SyHyPtNmDHnmrv/HOrqktSC+C9fM+CJOE= -github.com/go-test/deep v1.0.4 h1:u2CU3YKy9I2pmu9pX0eq50wCgjfGIt539SqR7FbHiho= -github.com/go-test/deep v1.0.4/go.mod h1:wGDj63lr65AM2AQyKZd/NYHGb0R+1RLqB8NKt3aSFNA= 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/gateway v1.1.0 h1:u0SuhL9+Il+UbjM9VIE3ntfRujKbvVpFvNB4HbjeVQ0= github.com/gogo/gateway v1.1.0/go.mod h1:S7rR8FRQyG3QFESeSv4l2WnsyzlCLG0CzBbUUo/mbic= github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q= @@ -307,7 +275,6 @@ github.com/google/go-cmp v0.5.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/ github.com/google/go-cmp v0.5.3/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.5.4/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= -github.com/google/go-cmp v0.5.7/go.mod h1:n+brtR0CgQNWTVd5ZUFpTBC8YFBDLK/h/bpaJ8/DtOE= github.com/google/go-cmp v0.5.9/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI= github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= @@ -320,8 +287,6 @@ github.com/google/orderedcode v0.0.1/go.mod h1:iVyU4/qPKHY5h/wSd6rZZCDcLJNxiWO6d github.com/google/pprof v0.0.0-20210407192527-94a9f03dee38/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= github.com/google/s2a-go v0.1.7 h1:60BLSyTrOV4/haCDW4zb1guZItoSq8foHCXrAnjBo/o= github.com/google/s2a-go v0.1.7/go.mod h1:50CgR4k1jNlWBu4UfS4AcfhVe1r6pdZPygJ3R8F0Qdw= -github.com/google/shlex v0.0.0-20191202100458-e7afc7fbc510 h1:El6M4kTTCOh6aBiKaUGG7oYTSPP8MxqL4YI3kZKwcP4= -github.com/google/shlex v0.0.0-20191202100458-e7afc7fbc510/go.mod h1:pupxD2MaaD3pAXIBCelhxNneeOaAeabZDe5s4K6zSpQ= github.com/google/uuid v1.1.2/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0= github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= @@ -333,7 +298,6 @@ github.com/gorilla/handlers v1.5.1 h1:9lRY6j8DEeeBT10CvO9hGW0gmky0BprnvDI5vfhUHH github.com/gorilla/handlers v1.5.1/go.mod h1:t8XrUpc4KVXb7HGyJ4/cEnwQiaxrX/hz1Zv/4g96P1Q= github.com/gorilla/mux v1.8.1 h1:TuBL49tXwgrFYWhqrNgrUNEY92u81SPhu7sTdzQEiWY= github.com/gorilla/mux v1.8.1/go.mod h1:AKf9I4AEqPTmMytcMc0KkNouC66V3BtZ4qD5fmWSiMQ= -github.com/gorilla/websocket v1.4.2/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE= github.com/gorilla/websocket v1.5.0 h1:PPwGk2jz7EePpoHN/+ClbZu8SPxiqlu12wZP/3sWmnc= github.com/gorilla/websocket v1.5.0/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE= github.com/grpc-ecosystem/go-grpc-middleware v1.3.0 h1:+9834+KizmvFV7pXQGSXQTsaWhq2GjuNUt0aUU0YBYw= @@ -380,8 +344,6 @@ github.com/huin/goupnp v1.0.3/go.mod h1:ZxNlw5WqJj6wSsRK5+YfflQGXYfccj5VgQsMNixH github.com/ianlancetaylor/demangle v0.0.0-20200824232613-28f6c0f3b639/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc= github.com/ignite/cli v0.26.1 h1:T4qMjM9H38JOBsgCruilGcsfrlDGHO2K1V88gIe0ubs= github.com/ignite/cli v0.26.1/go.mod h1:0BQcJCseK0O5RG8HYP/lvVTFbZQjkw+AY8B+wDklj38= -github.com/imdario/mergo v0.3.13 h1:lFzP57bqS/wsqKssCGmtLAb8A0wKjLGrve2q3PPVcBk= -github.com/imdario/mergo v0.3.13/go.mod h1:4lJ1jqUDcsbIECGy0RUJAXNIhg+6ocWgb1ALK2O4oXg= github.com/improbable-eng/grpc-web v0.15.0 h1:BN+7z6uNXZ1tQGcNAuaU1YjsLTApzkjt2tzCixLaUPQ= github.com/improbable-eng/grpc-web v0.15.0/go.mod h1:1sy9HKV4Jt9aEs9JSnkWlRJPuPtwNr0l57L4f878wP8= github.com/inconshreveable/mousetrap v1.0.0/go.mod h1:PxqpIevigyE2G7u3NXJIT2ANytuPF1OarO4DADm73n8= @@ -408,7 +370,6 @@ github.com/klauspost/compress v1.17.0/go.mod h1:ntbaceVETuRiXiv4DpjP66DpAtAGkEQs github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= 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= @@ -445,16 +406,10 @@ github.com/mitchellh/go-testing-interface v1.14.1/go.mod h1:gfgS7OtZj6MA4U1UrDRp 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-20221205130635-1aeaba878587 h1:HfkjXDfhgVaN5rmueG8cL8KKeFNecRCXFhaJ2qZ5SKA= -github.com/moby/term v0.0.0-20221205130635-1aeaba878587/go.mod h1:8FzsFHVUBGZdbDsJw/ot+X+d5HLUbvklYLJ9uGfcI3Y= github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= github.com/modern-go/reflect2 v0.0.0-20180701023420-4b7aa43c6742/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= github.com/modern-go/reflect2 v1.0.1/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= -github.com/montanaflynn/stats v0.0.0-20171201202039-1bf9dbcd8cbe h1:iruDEfMl2E6fbMZ9s0scYfZQ84/6SPL6zC8ACM2oIL0= -github.com/montanaflynn/stats v0.0.0-20171201202039-1bf9dbcd8cbe/go.mod h1:wL8QJuTMNUDYhXwkmfOly8iTdp5TEcJFWZD2D7SIkUc= -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/mwitkow/go-conntrack v0.0.0-20161129095857-cc309e4a2223/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U= @@ -480,17 +435,7 @@ github.com/onsi/gomega v1.17.0/go.mod h1:HnhC7FXeEQY45zxNK3PPoIUhzk/80Xly9PcubAl github.com/onsi/gomega v1.19.0/go.mod h1:LY+I3pBVzYsTBU1AnDwOSxaYi9WoWiqgwooUqq9yPro= 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/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.4 h1:nRCz/8sKg6K6jgYAFLDlXzPeITBZJyX28DBVhWD+5dg= -github.com/opencontainers/runc v1.1.4/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/opentracing-go v1.1.0/go.mod h1:UkNAQd3GIcIGf0SeVgPpRdFStlNbqXla1AfSYxPUl2o= -github.com/ory/dockertest/v3 v3.9.1 h1:v4dkG+dlu76goxMiTT2j8zV7s4oPPEppKT8K8p2f1kY= -github.com/ory/dockertest/v3 v3.9.1/go.mod h1:42Ir9hmvaAPm0Mgibk6mBPi7SFvTXxEcnztDYOJ//uM= github.com/pascaldekloe/goe v0.1.0 h1:cBOtyMzM9HTpWjXfbbunk26uA6nG3a8n06Wieeh0MwY= github.com/pascaldekloe/goe v0.1.0/go.mod h1:lzWF7FIEvWOWxwDKqyGYQf6ZUaNfKdP144TG7ZOy1lc= github.com/pelletier/go-toml v1.2.0/go.mod h1:5z9KED0ma1S8pY6P1sdut58dfprrGBbd/94hg7ilaic= @@ -548,7 +493,6 @@ github.com/rs/cors v1.9.0/go.mod h1:XyqrcTp5zjWr1wsJ8PIRZssZ8b/WMcMf71DJnit4EMU= github.com/rs/zerolog v1.29.1 h1:cO+d60CHkknCbvzEWxP0S9K6KqyTjrCNUy1LdQLCGPc= github.com/rs/zerolog v1.29.1/go.mod h1:Le6ESbR7hc+DP6Lt1THiV8CQSdkkNrd3R0XbEgp3ZBU= 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= github.com/sagikazarmark/locafero v0.4.0 h1:HApY1R9zGo4DBgr7dqsTH/JJxLTTsOt7u6keLGt6kNQ= github.com/sagikazarmark/locafero v0.4.0/go.mod h1:Pe1W6UlPYUk/+wc/6KFhbORCfqzgYEpgQ3O5fPuL3H4= @@ -556,17 +500,10 @@ github.com/sagikazarmark/slog-shim v0.1.0 h1:diDBnUNK9N/354PgrxMywXnAwEr1QZcOr6g github.com/sagikazarmark/slog-shim v0.1.0/go.mod h1:SrcSrq8aKtyuqEI1uvTDTK1arOWRIczQRv+GVI1AkeQ= 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/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= 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.8.1/go.mod h1:yWOB1SBYBC5VeMP7gHvWumXLIWorT60ONWic61uBYv0= -github.com/sirupsen/logrus v1.9.3 h1:dueUQJ1C2q9oE3F7wvmSGAaVtTmUizReu6fjN8uqzbQ= -github.com/sirupsen/logrus v1.9.3/go.mod h1:naHLuLoDiP4jHNo9R0sCBMtWGeIprob74mVsIT4qYEQ= -github.com/slack-go/slack v0.12.5 h1:ddZ6uz6XVaB+3MTDhoW04gG+Vc/M/X1ctC+wssy2cqs= -github.com/slack-go/slack v0.12.5/go.mod h1:hlGi5oXA+Gt+yWTPP0plCdRKmjsDxecdHxYQdlMQKOw= github.com/sourcegraph/conc v0.3.0 h1:OQTbbt6P72L20UqAkXXuLOj79LfEanQ+YQFNpLA9ySo= github.com/sourcegraph/conc v0.3.0/go.mod h1:Sdozi7LEKbFPqYX2/J+iBAM6HpqSLTASQIKqDmF7Mt0= github.com/spaolacci/murmur3 v0.0.0-20180118202830-f09979ecbc72/go.mod h1:JwIasOWyU6f++ZhiEuf87xNszmSA2myDM2Kzu9HwQUA= @@ -609,7 +546,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.6.0 h1:9NlTDc1FTs4qu0DDq7AEtTPNw6SVm7uBMsUCUjABIf8= github.com/subosito/gotenv v1.6.0/go.mod h1:Dk4QP5c2W3ibzajGcXpNraDfq2IrhjMIvMSWPKKo0FU= -github.com/syndtr/gocapability v0.0.0-20200815063812-42c35b437635/go.mod h1:hkRG7XYTFWNJGYcbNJQlaLq0fg1yr4J4t/NcTQtrfww= github.com/syndtr/goleveldb v1.0.1-0.20210819022825-2ae1ddf74ef7/go.mod h1:q4W45IWZaF22tdD+VEXcAWRA037jwmWEB5VWYORlTpc= 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= @@ -640,36 +576,15 @@ github.com/tyler-smith/go-bip39 v1.1.0/go.mod h1:gUYDtqQw1JS3ZJ8UWVcGTGqqr6YIN3C github.com/ugorji/go/codec v0.0.0-20181204163529-d75b2dcb6bc8/go.mod h1:VFNgLljTbGfSG7qAOspJ7OScBnGdDN/yBr0sguwnwf0= github.com/ulikunitz/xz v0.5.10 h1:t92gobL9l3HE202wg3rlk19F6X+JOxl9BBrCCMYEYd8= github.com/ulikunitz/xz v0.5.10/go.mod h1:nbz6k7qbPmH4IRqmfOplQw/tblSgqTqBwxkY0oWt/14= -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/xdg-go/pbkdf2 v1.0.0 h1:Su7DPu48wXMwC3bs7MCNG+z4FhcyEuz5dlvchbq0B0c= -github.com/xdg-go/pbkdf2 v1.0.0/go.mod h1:jrpuAogTd400dnrH08LKmI/xc1MbPOebTwRqcT5RDeI= -github.com/xdg-go/scram v1.1.2 h1:FHX5I5B4i4hKRVRBCFRxq1iQRej7WO3hhBuJf+UUySY= -github.com/xdg-go/scram v1.1.2/go.mod h1:RT/sEzTbU5y00aCK8UOx6R7YryM0iF1N2MOmC3kKLN4= -github.com/xdg-go/stringprep v1.0.4 h1:XLI/Ng3O1Atzq0oBs3TWm+5ZVgkq2aqdlvP9JtoZ6c8= -github.com/xdg-go/stringprep v1.0.4/go.mod h1:mPGuuIYwz7CmR2bT9j4GbQqutWS1zV24gijq1dTyGkM= -github.com/xeipuuv/gojsonpointer v0.0.0-20180127040702-4e3ac2762d5f/go.mod h1:N2zxlSyiKSe5eX1tZViRH5QA0qijqEDrYZiPEAiq3wU= -github.com/xeipuuv/gojsonpointer v0.0.0-20190905194746-02993c407bfb h1:zGWFAtiMcyryUHoUjUJX0/lt1H2+i2Ka2n+D3DImSNo= -github.com/xeipuuv/gojsonpointer v0.0.0-20190905194746-02993c407bfb/go.mod h1:N2zxlSyiKSe5eX1tZViRH5QA0qijqEDrYZiPEAiq3wU= -github.com/xeipuuv/gojsonreference v0.0.0-20180127040603-bd5ef7bd5415 h1:EzJWgHovont7NscjpAxXsDA8S8BMYve8Y5+7cuRE7R0= -github.com/xeipuuv/gojsonreference v0.0.0-20180127040603-bd5ef7bd5415/go.mod h1:GwrjFmJcFw6At/Gs6z4yjiIwzuJ1/+UwLxMQDVQXShQ= -github.com/xeipuuv/gojsonschema v1.2.0 h1:LhYJRs+L4fBtjZUfuSZIKGeVu0QRy8e5Xi7D17UxZ74= -github.com/xeipuuv/gojsonschema v1.2.0/go.mod h1:anYRn/JVcOK2ZgGU+IjEV4nwlhoK5sQluxsYJ78Id3Y= github.com/xordataexchange/crypt v0.0.3-0.20170626215501-b2862e3d0a77/go.mod h1:aYKd//L2LvnjZzWKhF00oedf4jCCReLcmhLdhm1A27Q= -github.com/youmark/pkcs8 v0.0.0-20181117223130-1be2e3e5546d h1:splanxYIlg+5LfHAM6xpdFEAYOk8iySO56hMFq6uLyA= -github.com/youmark/pkcs8 v0.0.0-20181117223130-1be2e3e5546d/go.mod h1:rHwXgn7JulP+udvsHwJoVG1YGAP6VLg4y9I5dyZdqmA= github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= -github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY= github.com/zondax/hid v0.9.2 h1:WCJFnEDMiqGF64nlZz28E9qLVZ0KSJ7xpc5DLEyma2U= github.com/zondax/hid v0.9.2/go.mod h1:l5wttcP0jwtdLjqjMMWFVEE7d1zO0jvSPA9OPZxWpEM= github.com/zondax/ledger-go v0.14.3 h1:wEpJt2CEcBJ428md/5MgSLsXLBos98sBOyxNmCjfUCw= github.com/zondax/ledger-go v0.14.3/go.mod h1:IKKaoxupuB43g4NxeQmbLXv7T9AlQyie1UpHb342ycI= go.etcd.io/bbolt v1.3.8 h1:xs88BrvEv273UsB79e0hcVrlUWmS0a8upikMFhSyAtA= go.etcd.io/bbolt v1.3.8/go.mod h1:N9Mkw9X8x5fupy0IKsmuqVtoGDyxsaDlbk4Rd05IAQw= -go.mongodb.org/mongo-driver v1.15.0 h1:rJCKC8eEliewXjZGf0ddURtl7tTVy1TK3bfl0gkUSLc= -go.mongodb.org/mongo-driver v1.15.0/go.mod h1:Vzb0Mk/pa7e6cWw85R4F/endUC3u0U9jGcNU603k65c= go.opencensus.io v0.22.5/go.mod h1:5pWMHQbX5EPX2/62yrJeAkowc+lfs/XD7Uxpq3pI6kk= go.opencensus.io v0.24.0 h1:y73uSU6J157QMP2kn2r30vwW1A2W2WFwSCGnAVxeaD0= go.opencensus.io v0.24.0/go.mod h1:vNK8G9p7aAivkbmorf4v+7Hgx+Zs0yY+0fOtgBfjQKo= @@ -696,7 +611,6 @@ golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8U golang.org/x/crypto v0.0.0-20191206172530-e9b2fee46413/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/crypto v0.0.0-20200728195943-123391ffb6de/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= -golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= golang.org/x/crypto v0.21.0 h1:X31++rzVUdKhX5sWmSOFZxx8UW/ldWx55cbf08iNAMA= golang.org/x/crypto v0.21.0/go.mod h1:0BP7YvVV9gBbVKyeTG0Gyn+gZm94bibOW5BjDEYAOMs= golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= @@ -707,7 +621,6 @@ golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvx golang.org/x/lint v0.0.0-20190313153728-d0100b6bd8b3/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= -golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4= golang.org/x/mod v0.13.0 h1:I/DsJXRlw/8l/0c24sM9yb0T4z9liZTduXvdAWYiysY= golang.org/x/mod v0.13.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c= golang.org/x/net v0.0.0-20180719180050-a680a1efc54d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= @@ -728,12 +641,9 @@ golang.org/x/net v0.0.0-20200813134508-3edf25e44fcc/go.mod h1:/O7V0waA8r7cgGh81R golang.org/x/net v0.0.0-20200822124328-c89045814202/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA= golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= golang.org/x/net v0.0.0-20201110031124-69a78807bb2b/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= -golang.org/x/net v0.0.0-20201224014010-6772e930b67b/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= -golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= golang.org/x/net v0.0.0-20210428140749-89ef3d95e781/go.mod h1:OJAsFXCWl8Ukc7SiCT/9KSuxbyM7479/AVlXFRxuMCk= golang.org/x/net v0.0.0-20220225172249-27dd8689420f/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk= golang.org/x/net v0.0.0-20220607020251-c690dde0001d/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c= -golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c= golang.org/x/net v0.23.0 h1:7EYJ93RZ9vYSZAIb2x3lnuvqO5zneoD6IvWjuhfxjTs= golang.org/x/net v0.23.0/go.mod h1:JKghWKKOSdJwpW2GEx0Ja7fmaKnMsbu+MWVZTokSYmg= golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= @@ -747,7 +657,6 @@ golang.org/x/sync v0.0.0-20190227155943-e225da77a7e6/go.mod h1:RxMgew5VJxzue5/jJ golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.6.0 h1:5BMeUDZ7vkXGfEr1x9B4bRcTH4lpkTkpdh0T/J+qjbQ= golang.org/x/sync v0.6.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk= golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= @@ -759,11 +668,8 @@ golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5h golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190422165155-953cdadca894/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190502145724-3ef323f4f1fd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20190606203320-7fc4e5ec1444/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190904154756-749cb33beabd/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-20200122134326-e047566fdf82/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= @@ -773,19 +679,12 @@ golang.org/x/sys v0.0.0-20200814200057-3d37ad5750ed/go.mod h1:h1NjWce9XRLGQEsW7w golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210112080510-489259a85091/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20210124154548-22da62e12c0c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20210616094352-59db8d763f22/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-20210906170528-6f6e22806c34/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-20211216021012-1d35b9e2eb4e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220412211240-33da011f77ad/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20221010170243-090e33056c14/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.18.0 h1:DBdB3niSjOA/O0blCZBqDefyWNYveAYMNF1Wum0DYQ4= @@ -799,7 +698,6 @@ golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk= golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= 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.14.0 h1:ScX5w1eTa3QqT8oi6+ziP7dTV1S2+ALU0bI+0zXKWiQ= golang.org/x/text v0.14.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU= golang.org/x/time v0.5.0 h1:o7cqy6amK/52YcAKIPlM3a+Fpj35zvRj2TP+e1xFSfk= @@ -813,9 +711,6 @@ golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtn golang.org/x/tools v0.0.0-20200619180055-7c47624df98f/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= golang.org/x/tools v0.0.0-20201224043029-2b0845dc783e/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= golang.org/x/tools v0.0.0-20210106214847-113979e3529a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= -golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc= -golang.org/x/tools v0.14.0 h1:jvNa2pY0M4r62jkRQ6RwEZZyPcymeL9XZMLBbV7U2nc= -golang.org/x/tools v0.14.0/go.mod h1:uYBEerGOWcJyEORxN+Ek8+TT266gXkNlHdJBwexUsBg= 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= @@ -863,7 +758,6 @@ google.golang.org/protobuf v1.23.1-0.20200526195155-81db48ad09cc/go.mod h1:EGpAD google.golang.org/protobuf v1.25.0/go.mod h1:9JNX74DMeImyA3h4bdi1ymwjUzf21/xIlbajtzgsN7c= google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw= google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc= -google.golang.org/protobuf v1.27.1/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc= google.golang.org/protobuf v1.33.0 h1:uNO2rsAINq/JlFpSdYEKIZ0uKD/R9cpdv0T+yoGwGmI= google.golang.org/protobuf v1.33.0/go.mod h1:c6P6GXX6sHbq/GpV6MGZEdwhWPcYBgnhAHhKbcUYpos= gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw= @@ -888,14 +782,13 @@ gopkg.in/yaml.v2 v2.3.0/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY= gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ= gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= -gopkg.in/yaml.v3 v3.0.0/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= -gotest.tools/v3 v3.4.0 h1:ZazjZUfuVeZGLAmlKKuyv3IKP5orXcwtOwDQH6YVr6o= -gotest.tools/v3 v3.4.0/go.mod h1:CtbdzLSsqVhDgMtKsx03ird5YTGB3ar27v0u/yKBW5g= honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= 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= sigs.k8s.io/yaml v1.4.0 h1:Mk1wCc2gy/F0THH0TAp1QYyJNzRm2KCLy3o5ASXVI5E= sigs.k8s.io/yaml v1.4.0/go.mod h1:Ejl7/uTz7PSA4eKMyQCUTnhZYNmLIl+5c2lQPGR2BPY= diff --git a/main.go b/main.go index ff89668..539cb22 100644 --- a/main.go +++ b/main.go @@ -2,10 +2,12 @@ package main import ( "log" + + "github.com/dymensionxyz/eibc-client/cmd" ) func main() { - if err := rootCmd.Execute(); err != nil { + if err := cmd.RootCmd.Execute(); err != nil { log.Fatalf("failed to execute root command: %v", err) } } diff --git a/order_client.go b/order_client.go deleted file mode 100644 index b34fc6a..0000000 --- a/order_client.go +++ /dev/null @@ -1,356 +0,0 @@ -package main - -import ( - "context" - "fmt" - "math/rand" - "os" - "slices" - - sdk "github.com/cosmos/cosmos-sdk/types" - "go.uber.org/zap" - "go.uber.org/zap/zapcore" - - "github.com/dymensionxyz/cosmosclient/cosmosclient" - - "github.com/dymensionxyz/eibc-client/store" -) - -type orderClient struct { - logger *zap.Logger - config Config - bots map[string]*orderFulfiller - whale *whale - - orderEventer *orderEventer - orderPoller *orderPoller - orderTracker *orderTracker -} - -func newOrderClient(ctx context.Context, config Config) (*orderClient, error) { - sdkcfg := sdk.GetConfig() - sdkcfg.SetBech32PrefixForAccount(hubAddressPrefix, pubKeyPrefix) - - logger, err := buildLogger(config.LogLevel) - if err != nil { - return nil, fmt.Errorf("failed to create logger: %w", err) - } - - // Ensure all logs are written - defer logger.Sync() // nolint: errcheck - - minGasBalance, err := sdk.ParseCoinNormalized(config.Gas.MinimumGasBalance) - if err != nil { - return nil, fmt.Errorf("failed to parse minimum gas balance: %w", err) - } - - // init cosmos client for order fetcher - fetcherClientCfg := clientConfig{ - homeDir: config.Bots.KeyringDir, - nodeAddress: config.NodeAddress, - gasFees: config.Gas.Fees, - gasPrices: config.Gas.Prices, - keyringBackend: config.Bots.KeyringBackend, - } - - fetcherCosmosClient, err := cosmosclient.New(getCosmosClientOptions(fetcherClientCfg)...) - if err != nil { - return nil, fmt.Errorf("failed to create cosmos client: %w", err) - } - - //nolint:gosec - subscriberID := fmt.Sprintf("eibc-client-%d", rand.Int()) - - orderCh := make(chan []*demandOrder, newOrderBufferSize) - - db, err := store.NewDB(ctx, config.DBPath) - if err != nil { - return nil, fmt.Errorf("failed to create db: %w", err) - } - - fulfilledOrdersCh := make(chan *orderBatch, newOrderBufferSize) // TODO: make buffer size configurable - bstore := store.NewBotStore(db) - - ordTracker := newOrderTracker( - fetcherCosmosClient, - bstore, - fulfilledOrdersCh, - subscriberID, - &config.FulfillCriteria, - logger, - ) - - eventer := newOrderEventer( - fetcherCosmosClient, - subscriberID, - ordTracker.canFulfillOrder, - config.Bots.MaxOrdersPerTx, - orderCh, - logger, - ) - - topUpCh := make(chan topUpRequest, config.Bots.NumberOfBots) // TODO: make buffer size configurable - slackClient := newSlacker(config.SlackConfig, logger) - - whaleSvc, err := buildWhale( - ctx, - logger, - config.Whale, - slackClient, - config.NodeAddress, - config.Gas.Fees, - config.Gas.Prices, - minGasBalance, - topUpCh, - ) - if err != nil { - return nil, fmt.Errorf("failed to create whale: %w", err) - } - - botClientCfg := clientConfig{ - homeDir: config.Bots.KeyringDir, - keyringBackend: config.Bots.KeyringBackend, - nodeAddress: config.NodeAddress, - gasFees: config.Gas.Fees, - gasPrices: config.Gas.Prices, - } - - accs, err := addBotAccounts(ctx, config.Bots.NumberOfBots, botClientCfg, logger) - if err != nil { - return nil, err - } - - // create bots - bots := make(map[string]*orderFulfiller) - - var botIdx int - for botIdx = range config.Bots.NumberOfBots { - b, err := buildBot( - ctx, - accs[botIdx], - logger, - config.Bots, - botClientCfg, - bstore, - minGasBalance, - orderCh, - fulfilledOrdersCh, - topUpCh, - ) - if err != nil { - return nil, fmt.Errorf("failed to create bot: %w", err) - } - bots[b.accountSvc.accountName] = b - } - - if !config.SkipRefund { - refundFromExtraBotsToWhale( - ctx, - bstore, - config, - botIdx, - accs, - whaleSvc.accountSvc, - config.Gas.Fees, - logger, - ) - } - - oc := &orderClient{ - orderEventer: eventer, - orderTracker: ordTracker, - bots: bots, - whale: whaleSvc, - config: config, - logger: logger, - } - - if config.OrderPolling.Enabled { - oc.orderPoller = newOrderPoller( - fetcherCosmosClient, - ordTracker.canFulfillOrder, - config.OrderPolling, - config.Bots.MaxOrdersPerTx, - orderCh, - logger, - ) - } - - return oc, nil -} - -func (oc *orderClient) start(ctx context.Context) error { - oc.logger.Info("starting demand order fetcher...") - // start order fetcher - if err := oc.orderEventer.start(ctx); err != nil { - return fmt.Errorf("failed to subscribe to demand orders: %w", err) - } - - // start order polling - if oc.orderPoller != nil { - oc.logger.Info("starting order polling...") - oc.orderPoller.start(ctx) - } - - // start whale service - if err := oc.whale.start(ctx); err != nil { - return fmt.Errorf("failed to start whale service: %w", err) - } - - oc.logger.Info("starting bots...") - - // start bots - for _, b := range oc.bots { - go func() { - if err := b.start(ctx); err != nil { - oc.logger.Error("failed to bot", zap.Error(err)) - } - }() - } - - if err := oc.orderTracker.start(ctx); err != nil { - return fmt.Errorf("failed to start order tracker: %w", err) - } - - // TODO: block more nicely - <-make(chan struct{}) - - return nil -} - -func addBotAccounts(ctx context.Context, numBots int, botConfig clientConfig, logger *zap.Logger) ([]string, error) { - cosmosClient, err := cosmosclient.New(getCosmosClientOptions(botConfig)...) - if err != nil { - return nil, fmt.Errorf("failed to create cosmos client for bot: %w", err) - } - - accs, err := getBotAccounts(cosmosClient) - if err != nil { - return nil, fmt.Errorf("failed to get bot accounts: %w", err) - } - - numFoundBots := len(accs) - - botsAccountsToCreate := max(0, numBots) - numFoundBots - if botsAccountsToCreate > 0 { - logger.Info("creating bot accounts", zap.Int("accounts", botsAccountsToCreate)) - } - - newNames, err := createBotAccounts(cosmosClient, botsAccountsToCreate) - if err != nil { - return nil, fmt.Errorf("failed to create bot accounts: %w", err) - } - - accs = slices.Concat(accs, newNames) - - if len(accs) < numBots { - return nil, fmt.Errorf("expected %d bot accounts, got %d", numBots, len(accs)) - } - return accs, nil -} - -func refundFromExtraBotsToWhale( - ctx context.Context, - store accountStore, - config Config, - startBotIdx int, - accs []string, - whaleAccSvc *accountService, - gasFeesStr string, - logger *zap.Logger, -) { - logger.Info("refunding funds from idle bots to whale", zap.String("whale", whaleAccSvc.address())) - - refunded := sdk.NewCoins() - - gasFees, err := sdk.ParseCoinNormalized(gasFeesStr) - if err != nil { - logger.Error("failed to parse gas fees", zap.Error(err)) - return - } - - botClientCfg := clientConfig{ - homeDir: config.Bots.KeyringDir, - keyringBackend: config.Bots.KeyringBackend, - nodeAddress: config.NodeAddress, - gasFees: config.Gas.Fees, - gasPrices: config.Gas.Prices, - } - - // return funds from extra bots to whale - for ; startBotIdx < len(accs); startBotIdx++ { - b, err := buildBot( - ctx, - accs[startBotIdx], - logger, - config.Bots, - botClientCfg, - store, - sdk.Coin{}, nil, nil, nil, - ) - if err != nil { - logger.Error("failed to create bot", zap.Error(err)) - continue - } - - if err := b.accountSvc.updateFunds(ctx); err != nil { - logger.Error("failed to update bot funds", zap.Error(err)) - continue - } - - if b.accountSvc.balances.IsZero() { - continue - } - - // if bot doesn't have enough DYM to pay the fees - // transfer some from the whale - if diff := gasFees.Amount.Sub(b.accountSvc.balanceOf(gasFees.Denom)); diff.IsPositive() { - logger.Info("topping up bot account", zap.String("bot", b.accountSvc.accountName), - zap.String("denom", gasFees.Denom), zap.String("amount", diff.String())) - topUp := sdk.NewCoin(gasFees.Denom, diff) - if err := whaleAccSvc.sendCoins(sdk.NewCoins(topUp), b.accountSvc.address()); err != nil { - logger.Error("failed to top up bot account with gas", zap.Error(err)) - continue - } - // update bot balance with topped up gas amount - b.accountSvc.balances = b.accountSvc.balances.Add(topUp) - } - // subtract gas fees from bot balance, so there is enough to pay for the fees - b.accountSvc.balances = b.accountSvc.balances.Sub(gasFees) - - if err = b.accountSvc.sendCoins(b.accountSvc.balances, whaleAccSvc.address()); err != nil { - logger.Error("failed to return funds to whale", zap.Error(err)) - continue - } - - if err := b.accountSvc.updateFunds(ctx); err != nil { - logger.Error("failed to update bot funds", zap.Error(err)) - continue - } - - refunded = refunded.Add(b.accountSvc.balances...) - } - - if !refunded.Empty() { - logger.Info("refunded funds from extra bots to whale", - zap.Int("bots", len(accs)-config.Bots.NumberOfBots), zap.String("refunded", refunded.String())) - } -} - -func buildLogger(logLevel string) (*zap.Logger, error) { - var level zapcore.Level - if err := level.Set(logLevel); err != nil { - return nil, fmt.Errorf("failed to set log level: %w", err) - } - - encoderConfig := zap.NewProductionEncoderConfig() - encoderConfig.EncodeTime = zapcore.ISO8601TimeEncoder - - logger := zap.New(zapcore.NewCore( - zapcore.NewJSONEncoder(encoderConfig), - zapcore.Lock(os.Stdout), - level, - )) - - return logger, nil -} diff --git a/order_eventer.go b/order_eventer.go deleted file mode 100644 index 617d6f7..0000000 --- a/order_eventer.go +++ /dev/null @@ -1,155 +0,0 @@ -package main - -import ( - "context" - "fmt" - - sdk "github.com/cosmos/cosmos-sdk/types" - tmtypes "github.com/tendermint/tendermint/rpc/core/types" - "go.uber.org/zap" - - "github.com/dymensionxyz/cosmosclient/cosmosclient" -) - -type orderEventer struct { - client cosmosclient.Client - logger *zap.Logger - - batchSize int - newOrders chan []*demandOrder - canFulfillOrder func(*demandOrder) bool - subscriberID string -} - -func newOrderEventer( - client cosmosclient.Client, - subscriberID string, - canFulfillOrder func(*demandOrder) bool, - batchSize int, - newOrders chan []*demandOrder, - logger *zap.Logger, -) *orderEventer { - return &orderEventer{ - client: client, - subscriberID: subscriberID, - batchSize: batchSize, - logger: logger.With(zap.String("module", "order-eventer")), - newOrders: newOrders, - canFulfillOrder: canFulfillOrder, - } -} - -func (e *orderEventer) start(ctx context.Context) error { - if err := e.client.RPC.Start(); err != nil { - return fmt.Errorf("start rpc client: %w", err) - } - - if err := e.subscribeToPendingDemandOrders(ctx); err != nil { - return fmt.Errorf("failed to subscribe to pending demand orders: %w", err) - } - - return nil -} - -func (e *orderEventer) enqueueEventOrders(res tmtypes.ResultEvent) error { - newOrders := e.parseOrdersFromEvents(res) - - if e.logger.Level() <= zap.DebugLevel { - ids := make([]string, 0, len(newOrders)) - for _, order := range newOrders { - ids = append(ids, order.id) - } - e.logger.Debug("new demand orders", zap.Strings("ids", ids)) - } else { - e.logger.Info("new demand orders", zap.Int("count", len(newOrders))) - } - - batch := make([]*demandOrder, 0, e.batchSize) - - for _, order := range newOrders { - batch = append(batch, order) - - if len(batch) >= e.batchSize || len(batch) == len(newOrders) { - e.newOrders <- batch - batch = make([]*demandOrder, 0, e.batchSize) - } - } - - if len(batch) == 0 { - return nil - } - - return nil -} - -const createdEvent = "dymensionxyz.dymension.eibc.EventDemandOrderCreated" - -func (e *orderEventer) parseOrdersFromEvents(res tmtypes.ResultEvent) []*demandOrder { - ids := res.Events[createdEvent+".order_id"] - - if len(ids) == 0 { - return nil - } - - prices := res.Events[createdEvent+".price"] - fees := res.Events[createdEvent+".fee"] - statuses := res.Events[createdEvent+".packet_status"] - rollapps := res.Events[createdEvent+".rollapp_id"] - newOrders := make([]*demandOrder, 0, len(ids)) - - for i, id := range ids { - price, err := sdk.ParseCoinsNormalized(prices[i]) - if err != nil { - e.logger.Error("failed to parse price", zap.Error(err)) - continue - } - - fee, err := sdk.ParseCoinsNormalized(fees[i]) - if err != nil { - e.logger.Error("failed to parse fee", zap.Error(err)) - continue - } - - order := &demandOrder{ - id: id, - denom: price.GetDenomByIndex(0), - amount: price, - fee: fee, - status: statuses[i], - rollappId: rollapps[i], - // blockHeight: height, - } - - if !e.canFulfillOrder(order) { - continue - } - - newOrders = append(newOrders, order) - } - - return newOrders -} - -func (e *orderEventer) subscribeToPendingDemandOrders(ctx context.Context) error { - const query = createdEvent + ".is_fulfilled='false'" - - resCh, err := e.client.WSEvents.Subscribe(ctx, e.subscriberID, query) - if err != nil { - return fmt.Errorf("failed to subscribe to demand orders: %w", err) - } - - go func() { - for { - select { - case res := <-resCh: - if err := e.enqueueEventOrders(res); err != nil { - e.logger.Error("failed to enqueue event orders", zap.Error(err)) - } - case <-ctx.Done(): - return - } - } - }() - - return nil -} diff --git a/order_fulfiller.go b/order_fulfiller.go deleted file mode 100644 index 84ccf7c..0000000 --- a/order_fulfiller.go +++ /dev/null @@ -1,193 +0,0 @@ -package main - -import ( - "context" - "fmt" - "slices" - - sdk "github.com/cosmos/cosmos-sdk/types" - "github.com/dymensionxyz/cosmosclient/cosmosclient" - "go.uber.org/zap" - - "github.com/dymensionxyz/eibc-client/types" -) - -type orderFulfiller struct { - accountSvc *accountService - client cosmosclient.Client - logger *zap.Logger - - newOrdersCh chan []*demandOrder - fulfilledOrdersCh chan<- *orderBatch -} - -func newOrderFulfiller( - accountSvc *accountService, - newOrdersCh chan []*demandOrder, - fulfilledOrdersCh chan<- *orderBatch, - client cosmosclient.Client, - logger *zap.Logger, -) *orderFulfiller { - return &orderFulfiller{ - accountSvc: accountSvc, - client: client, - fulfilledOrdersCh: fulfilledOrdersCh, - newOrdersCh: newOrdersCh, - logger: logger.With(zap.String("module", "order-fulfiller"), zap.String("name", accountSvc.accountName)), - } -} - -// add command that creates all the bots to be used? - -func buildBot( - ctx context.Context, - name string, - logger *zap.Logger, - config botConfig, - clientCfg clientConfig, - store accountStore, - minimumGasBalance sdk.Coin, - newOrderCh chan []*demandOrder, - fulfilledCh chan *orderBatch, - topUpCh chan topUpRequest, -) (*orderFulfiller, error) { - cosmosClient, err := cosmosclient.New(getCosmosClientOptions(clientCfg)...) - if err != nil { - return nil, fmt.Errorf("failed to create cosmos client for bot: %s;err: %w", name, err) - } - - accountSvc, err := newAccountService( - cosmosClient, - store, - logger, - name, - minimumGasBalance, - topUpCh, - withTopUpFactor(config.TopUpFactor), - ) - if err != nil { - return nil, fmt.Errorf("failed to create account service for bot: %s;err: %w", name, err) - } - - return newOrderFulfiller(accountSvc, newOrderCh, fulfilledCh, cosmosClient, logger), nil -} - -func (ol *orderFulfiller) start(ctx context.Context) error { - if err := ol.accountSvc.updateFunds(ctx); err != nil { - return fmt.Errorf("failed to update account funds: %w", err) - } - - ol.logger.Info("starting fulfiller...", zap.String("balances", ol.accountSvc.balances.String())) - - ol.fulfillOrders(ctx) - return nil -} - -func (ol *orderFulfiller) fulfillOrders(ctx context.Context) { - for { - select { - case <-ctx.Done(): - return - case orders := <-ol.newOrdersCh: - if err := ol.processBatch(ctx, orders); err != nil { - ol.logger.Error("failed to process batch", zap.Error(err)) - } - } - } -} - -func (ol *orderFulfiller) processBatch(ctx context.Context, batch []*demandOrder) error { - var ( - rewards, ids []string - demandOrders []*demandOrder - ) - - coins := sdk.NewCoins() - - for _, order := range batch { - coins = coins.Add(order.amount...) - } - - ol.logger.Debug("ensuring balances for orders") - - ensuredDenoms, err := ol.accountSvc.ensureBalances(coins) - if err != nil { - return fmt.Errorf("failed to ensure balances: %w", err) - } - - if len(ensuredDenoms) > 0 { - ol.logger.Info("ensured balances for orders", zap.Strings("denoms", ensuredDenoms)) - } - - leftoverBatch := make([]string, 0, len(batch)) - demandOrders = make([]*demandOrder, 0, len(batch)) - -outer: - for _, order := range batch { - for _, price := range order.amount { - if !slices.Contains(ensuredDenoms, price.Denom) { - leftoverBatch = append(leftoverBatch, order.id) - continue outer - } - - ids = append(ids, order.id) - demandOrders = append(demandOrders, order) - } - } - - if len(ids) == 0 { - ol.logger.Debug( - "no orders to fulfill", - zap.String("bot-name", ol.accountSvc.accountName), - zap.Int("leftover count", len(leftoverBatch)), - ) - return nil - } - - ol.logger.Info("fulfilling orders", zap.Int("count", len(ids))) - - if err := ol.fulfillDemandOrders(demandOrders...); err != nil { - return fmt.Errorf("failed to fulfill orders: ids: %v; %w", ids, err) - } - - ol.logger.Info("orders fulfilled", zap.Int("count", len(ids))) - - go func() { - if len(ids) == 0 { - return - } - - for _, order := range batch { - if slices.Contains(ids, order.id) { - rewards = append(rewards, order.amount.String()) - } - } - - // TODO: check if balances get updated before the new batch starts processing - if err := ol.accountSvc.updateFunds(ctx, addRewards(rewards...)); err != nil { - ol.logger.Error("failed to refresh balances", zap.Error(err)) - } - - ol.fulfilledOrdersCh <- &orderBatch{ - orders: demandOrders, - fulfiller: ol.accountSvc.account.GetAddress().String(), - } - }() - - return nil -} - -func (ol *orderFulfiller) fulfillDemandOrders(demandOrder ...*demandOrder) error { - msgs := make([]sdk.Msg, len(demandOrder)) - - for i, order := range demandOrder { - msgs[i] = types.NewMsgFulfillOrder(ol.accountSvc.account.GetAddress().String(), order.id, order.feeStr) - } - - _, err := ol.client.BroadcastTx(ol.accountSvc.accountName, msgs...) - if err != nil { - return fmt.Errorf("failed to broadcast tx: %w", err) - } - - return nil -} diff --git a/order_tracker.go b/order_tracker.go deleted file mode 100644 index 894d339..0000000 --- a/order_tracker.go +++ /dev/null @@ -1,280 +0,0 @@ -package main - -import ( - "context" - "fmt" - "strings" - "sync" - - sdk "github.com/cosmos/cosmos-sdk/types" - "github.com/dymensionxyz/cosmosclient/cosmosclient" - tmtypes "github.com/tendermint/tendermint/rpc/core/types" - "go.uber.org/zap" - - "github.com/dymensionxyz/eibc-client/store" -) - -type orderTracker struct { - client cosmosclient.Client - store botStore - logger *zap.Logger - - comu sync.Mutex - currentOrders map[string]struct{} - tomu sync.Mutex - trackedOrders map[string]struct{} - fulfillCriteria *fulfillCriteria - fulfilledOrdersCh chan *orderBatch - subscriberID string -} - -type botStore interface { - GetOrders(ctx context.Context, opts ...store.OrderOption) ([]*store.Order, error) - GetOrder(ctx context.Context, id string) (*store.Order, error) - SaveManyOrders(ctx context.Context, orders []*store.Order) error - DeleteOrder(ctx context.Context, id string) error - GetBot(ctx context.Context, key string, opts ...store.BotOption) (*store.Bot, error) - GetBots(ctx context.Context, opts ...store.BotOption) ([]*store.Bot, error) - SaveBot(ctx context.Context, bot *store.Bot) error - Close() -} - -func newOrderTracker( - client cosmosclient.Client, - store botStore, - fulfilledOrdersCh chan *orderBatch, - subscriberID string, - fCriteria *fulfillCriteria, - logger *zap.Logger, -) *orderTracker { - return &orderTracker{ - client: client, - store: store, - currentOrders: make(map[string]struct{}), - fulfilledOrdersCh: fulfilledOrdersCh, - fulfillCriteria: fCriteria, - logger: logger.With(zap.String("module", "order-resolver")), - subscriberID: subscriberID, - trackedOrders: make(map[string]struct{}), - } -} - -func (or *orderTracker) start(ctx context.Context) error { - if err := or.loadTrackedOrders(ctx); err != nil { - return fmt.Errorf("failed to load orders: %w", err) - } - - // TODO: consider that if the client is offline if might miss finalized orders, and the state might not be updated - if err := or.waitForFinalizedOrder(ctx); err != nil { - or.logger.Error("failed to wait for finalized order", zap.Error(err)) - } - - go func() { - for { - select { - case batch := <-or.fulfilledOrdersCh: - if err := or.addFulfilledOrders(ctx, batch); err != nil { - or.logger.Error("failed to add fulfilled orders", zap.Error(err)) - } - case <-ctx.Done(): - return - } - } - }() - - return nil -} - -func (or *orderTracker) loadTrackedOrders(ctx context.Context) error { - // load tracked orders from the database - orders, err := or.store.GetOrders(ctx, store.FilterByStatus(store.OrderStatusPending)) - if err != nil { - return fmt.Errorf("failed to get pending orders: %w", err) - } - - or.tomu.Lock() - for _, order := range orders { - or.trackedOrders[order.ID] = struct{}{} - } - or.tomu.Unlock() - or.logger.Info("loaded tracked orders", zap.Int("count", len(or.trackedOrders))) - - return nil -} - -func (or *orderTracker) addFulfilledOrders(ctx context.Context, batch *orderBatch) error { - storeOrders := make([]*store.Order, len(batch.orders)) - or.tomu.Lock() - or.comu.Lock() - for i, order := range batch.orders { - if len(order.amount) == 0 { - continue - } - // add to cache - or.trackedOrders[order.id] = struct{}{} - delete(or.currentOrders, order.id) - - storeOrders[i] = &store.Order{ - ID: order.id, - Fulfiller: batch.fulfiller, - Amount: order.amount[0].String(), - Status: store.OrderStatusPending, - } - } - or.tomu.Unlock() - or.comu.Unlock() - - if err := or.store.SaveManyOrders(ctx, storeOrders); err != nil { - return fmt.Errorf("failed to save orders: %w", err) - } - - return nil -} - -func (or *orderTracker) canFulfillOrder(order *demandOrder) bool { - if or.isOrderFulfilled(order.id) { - return false - } - if or.isOrderCurrent(order.id) { - return false - } - if !or.checkFeePercentage(order) { - return false - } - - return true -} - -func (or *orderTracker) checkFeePercentage(order *demandOrder) bool { - assetMinPercentage, ok := or.fulfillCriteria.MinFeePercentage.Asset[strings.ToLower(order.denom)] - if !ok { - return false - } - - chainMinPercentage, ok := or.fulfillCriteria.MinFeePercentage.Chain[order.rollappId] - if !ok { - return false - } - - feePercentage := order.feePercentage() - okFee := feePercentage >= assetMinPercentage && feePercentage >= chainMinPercentage - return okFee -} - -func (or *orderTracker) isOrderFulfilled(id string) bool { - or.tomu.Lock() - defer or.tomu.Unlock() - - _, ok := or.trackedOrders[id] - return ok -} - -func (or *orderTracker) isOrderCurrent(id string) bool { - or.comu.Lock() - defer or.comu.Unlock() - - _, ok := or.currentOrders[id] - if !ok { - or.currentOrders[id] = struct{}{} - } - return ok -} - -const finalizedEvent = "dymensionxyz.dymension.eibc.EventDemandOrderPacketStatusUpdated" - -func (or *orderTracker) waitForFinalizedOrder(ctx context.Context) error { - // TODO: should filter by fulfiller (one of the bots)? - query := fmt.Sprintf("%s.is_fulfilled='true' AND %s.new_packet_status='FINALIZED'", finalizedEvent, finalizedEvent) - - resCh, err := or.client.RPC.Subscribe(ctx, or.subscriberID, query) - if err != nil { - return fmt.Errorf("failed to subscribe to demand orders: %w", err) - } - - go func() { - for { - select { - case res := <-resCh: - if err := or.finalizeOrder(ctx, res); err != nil { - or.logger.Error("failed to finalize order", zap.Error(err)) - } - case <-ctx.Done(): - return - } - } - }() - - return nil -} - -func (or *orderTracker) finalizeOrder(ctx context.Context, res tmtypes.ResultEvent) error { - ids := res.Events[finalizedEvent+".order_id"] - - if len(ids) == 0 { - return nil - } - - for _, id := range ids { - if err := or.finalizeOrderWithID(ctx, id); err != nil { - return fmt.Errorf("failed to finalize order with id %s: %w", id, err) - } - } - - return nil -} - -func (or *orderTracker) finalizeOrderWithID(ctx context.Context, id string) error { - or.tomu.Lock() - defer or.tomu.Unlock() - - _, ok := or.trackedOrders[id] - if !ok { - return nil - } - - order, err := or.store.GetOrder(ctx, id) - if err != nil { - return fmt.Errorf("failed to get order: %w", err) - } - - b, err := or.store.GetBot(ctx, order.Fulfiller) - if err != nil { - return fmt.Errorf("failed to get bot: %w", err) - } - - orderAmount, err := sdk.ParseCoinNormalized(order.Amount) - if err != nil { - return fmt.Errorf("failed to parse order amount: %w", err) - } - - pendingRewards, err := sdk.ParseCoinsNormalized(strings.Join(b.PendingRewards, ",")) - if err != nil { - return fmt.Errorf("failed to parse pending rewards: %w", err) - } - - balances, err := sdk.ParseCoinsNormalized(strings.Join(b.Balances, ",")) - if err != nil { - return fmt.Errorf("failed to parse balances: %w", err) - } - - if pendingRewards.IsAnyGTE(sdk.NewCoins(orderAmount)) { - pendingRewards = pendingRewards.Sub(orderAmount) - balances = balances.Add(orderAmount) - b.PendingRewards = store.CoinsToStrings(pendingRewards) - b.Balances = store.CoinsToStrings(balances) - } - - if err := or.store.SaveBot(ctx, b); err != nil { - return fmt.Errorf("failed to update bot: %w", err) - } - - if err := or.store.DeleteOrder(ctx, id); err != nil { - return fmt.Errorf("failed to delete order: %w", err) - } - - delete(or.trackedOrders, id) - - or.logger.Info("finalized order", zap.String("id", id)) - - return nil -} diff --git a/order_tracker_test.go b/order_tracker_test.go deleted file mode 100644 index 4b3820c..0000000 --- a/order_tracker_test.go +++ /dev/null @@ -1,141 +0,0 @@ -package main - -import ( - "testing" - - sdk "github.com/cosmos/cosmos-sdk/types" -) - -func Test_orderTracker_canFulfillOrder(t *testing.T) { - type fields struct { - currentOrders map[string]struct{} - trackedOrders map[string]struct{} - fulfillCriteria *fulfillCriteria - } - type args struct { - order *demandOrder - } - tests := []struct { - name string - fields fields - args args - want bool - }{ - { - name: "can fulfill order", - fields: fields{ - fulfillCriteria: &fulfillCriteria{ - MinFeePercentage: sampleMinFeePercentage, - }, - }, - args: args{ - order: sampleDemandOrder, - }, - want: true, - }, { - name: "cannot fulfill order: order already fulfilled", - fields: fields{ - trackedOrders: map[string]struct{}{ - sampleDemandOrder.id: {}, - }, - fulfillCriteria: &fulfillCriteria{ - MinFeePercentage: sampleMinFeePercentage, - }, - }, - args: args{ - order: sampleDemandOrder, - }, - want: false, - }, { - name: "cannot fulfill order: order already being processed", - fields: fields{ - currentOrders: map[string]struct{}{ - sampleDemandOrder.id: {}, - }, - fulfillCriteria: &fulfillCriteria{ - MinFeePercentage: sampleMinFeePercentage, - }, - }, - args: args{ - order: sampleDemandOrder, - }, - want: false, - }, { - name: "cannot fulfill order: asset fee percentage is lower than minimum", - fields: fields{ - fulfillCriteria: &fulfillCriteria{ - MinFeePercentage: minFeePercentage{ - Asset: map[string]float32{ - sampleDemandOrder.denom: 0.2, - }, - Chain: map[string]float32{ - sampleDemandOrder.rollappId: 0.1, - }, - }, - }, - }, - args: args{ - order: sampleDemandOrder, - }, - want: false, - }, { - name: "cannot fulfill order: chain fee percentage is lower than minimum", - fields: fields{ - fulfillCriteria: &fulfillCriteria{ - MinFeePercentage: minFeePercentage{ - Asset: map[string]float32{ - sampleDemandOrder.denom: 0.1, - }, - Chain: map[string]float32{ - sampleDemandOrder.rollappId: 0.2, - }, - }, - }, - }, - args: args{ - order: sampleDemandOrder, - }, - want: false, - }, - } - for _, tt := range tests { - t.Run(tt.name, func(t *testing.T) { - or := &orderTracker{ - currentOrders: tt.fields.currentOrders, - trackedOrders: tt.fields.trackedOrders, - fulfillCriteria: tt.fields.fulfillCriteria, - } - if or.currentOrders == nil { - or.currentOrders = make(map[string]struct{}) - } - if or.trackedOrders == nil { - or.trackedOrders = make(map[string]struct{}) - } - if got := or.canFulfillOrder(tt.args.order); got != tt.want { - t.Errorf("canFulfillOrder() = %v, want %v", got, tt.want) - } - }) - } -} - -var ( - sampleMinFeePercentage = minFeePercentage{ - Asset: map[string]float32{ - sampleDemandOrder.denom: 0.1, - }, - Chain: map[string]float32{ - sampleDemandOrder.rollappId: 0.1, - }, - } - - sampleDemandOrder = &demandOrder{ - id: "order1", - amount: amount, - fee: fee, - denom: amount.GetDenomByIndex(0), - rollappId: "rollappId", - } - - amount, _ = sdk.ParseCoinsNormalized("10526097010000000000denom") - fee, _ = sdk.ParseCoinsNormalized("15789145514999998denom") -) diff --git a/store/bots.go b/store/bots.go deleted file mode 100644 index 88b2356..0000000 --- a/store/bots.go +++ /dev/null @@ -1,126 +0,0 @@ -package store - -import ( - "context" - "errors" - "fmt" - - sdk "github.com/cosmos/cosmos-sdk/types" - "go.mongodb.org/mongo-driver/bson" - "go.mongodb.org/mongo-driver/mongo" - "go.mongodb.org/mongo-driver/mongo/options" -) - -type Bot struct { - Address string `bson:"_id,omitempty"` - Name string - Balances []string - PendingRewards PendingRewards - Orders []*Order -} - -type PendingRewards []string - -func (pr PendingRewards) ToCoins() sdk.Coins { - coins := sdk.NewCoins() - for _, reward := range pr { - coin, err := sdk.ParseCoinNormalized(reward) - if err != nil { - continue - } - coins = coins.Add(coin) - } - return coins -} - -func CoinsToStrings(coins sdk.Coins) []string { - coinStrings := make([]string, 0, len(coins)) - for _, coin := range coins { - coinStrings = append(coinStrings, coin.String()) - } - return coinStrings -} - -type BotOption func(*botFilter) - -func IncludePendingOrders() BotOption { - return func(f *botFilter) { - f.includePendingOrders = true - } -} - -func OnlyWithFunds() BotOption { - return func(f *botFilter) { - f.withFunds = true - } -} - -type botFilter struct { - includePendingOrders bool - withFunds bool -} - -func (s *botStore) GetBot(ctx context.Context, key string, opts ...BotOption) (*Bot, error) { - botsCollection := s.Database(botDatabase).Collection(botCollection) - - var bot Bot - err := botsCollection.FindOne(ctx, bson.M{"_id": key}).Decode(&bot) - if err != nil { - if errors.Is(err, mongo.ErrNoDocuments) { - return nil, nil - } - return nil, fmt.Errorf("failed to get bot: %w", err) - } - - var filter botFilter - for _, opt := range opts { - opt(&filter) - } - - if filter.includePendingOrders { - bot.Orders, err = s.GetOrders(ctx, FilterByFulfiller(key), FilterByStatus(OrderStatusPending)) - if err != nil { - return nil, fmt.Errorf("failed to get bot orders: %w", err) - } - } - - return &bot, nil -} - -func (s *botStore) GetBots(ctx context.Context, opts ...BotOption) ([]*Bot, error) { - botsCollection := s.Database(botDatabase).Collection(botCollection) - - var filter botFilter - for _, opt := range opts { - opt(&filter) - } - - f := bson.M{} - - if filter.withFunds { - f["balances"] = bson.M{"$exists": true, "$ne": bson.A{}} - } - - cursor, err := botsCollection.Find(ctx, f) - if err != nil { - return nil, fmt.Errorf("failed to get all bots: %w", err) - } - - var bots []*Bot - if err = cursor.All(ctx, &bots); err != nil { - return nil, fmt.Errorf("failed to get all bots: %w", err) - } - - return bots, nil -} - -func (s *botStore) SaveBot(ctx context.Context, bot *Bot) error { - botsCollection := s.Database(botDatabase).Collection(botCollection) - upsert := true - _, err := botsCollection.ReplaceOne(ctx, bson.M{"_id": bot.Address}, bot, &options.ReplaceOptions{Upsert: &upsert}) - if err != nil { - return fmt.Errorf("failed to update bot: %w", err) - } - - return nil -} diff --git a/store/db.go b/store/db.go deleted file mode 100644 index 2477ebc..0000000 --- a/store/db.go +++ /dev/null @@ -1,24 +0,0 @@ -package store - -import ( - "context" - "fmt" - - "go.mongodb.org/mongo-driver/mongo" - "go.mongodb.org/mongo-driver/mongo/options" -) - -func NewDB(ctx context.Context, url string) (*mongo.Client, error) { - clientOptions := options.Client().ApplyURI(url) - - client, err := mongo.Connect(ctx, clientOptions) - if err != nil { - return nil, fmt.Errorf("failed to connect to MongoDB: %w", err) - } - - if err = client.Ping(ctx, nil); err != nil { - return nil, fmt.Errorf("failed to ping MongoDB: %w", err) - } - - return client, nil -} diff --git a/store/orders.go b/store/orders.go deleted file mode 100644 index a6adb09..0000000 --- a/store/orders.go +++ /dev/null @@ -1,120 +0,0 @@ -package store - -import ( - "context" - "fmt" - - "go.mongodb.org/mongo-driver/bson" -) - -type Order struct { - ID string `bson:"_id,omitempty"` - Fulfiller string - Amount string - FulfilledHeight uint64 - ExpectedFinalizedHeight uint64 - Status OrderStatus -} - -type OrderStatus string - -const ( - OrderStatusPending OrderStatus = "pending" - OrderStatusFinalized OrderStatus = "finalized" -) - -type OrderOption func(*orderFilter) - -type orderFilter struct { - status OrderStatus - fulfillerKey string -} - -func FilterByStatus(status OrderStatus) OrderOption { - return func(f *orderFilter) { - f.status = status - } -} - -func FilterByFulfiller(fulfiller string) OrderOption { - return func(f *orderFilter) { - f.fulfillerKey = fulfiller - } -} - -func (s *botStore) GetOrder(ctx context.Context, id string) (*Order, error) { - ordersCollection := s.Database(botDatabase).Collection(orderCollection) - - var order Order - err := ordersCollection.FindOne(ctx, bson.M{"_id": id}).Decode(&order) - if err != nil { - return nil, fmt.Errorf("failed to get order: %w", err) - } - - return &order, nil -} - -func (s *botStore) GetOrders(ctx context.Context, opts ...OrderOption) ([]*Order, error) { - ordersCollection := s.Database(botDatabase).Collection(orderCollection) - - var filter orderFilter - for _, opt := range opts { - opt(&filter) - } - - query := bson.M{} - if filter.status != "" { - query["status"] = filter.status - } - if filter.fulfillerKey != "" { - query["fulfillerkey"] = filter.fulfillerKey - } - - cursor, err := ordersCollection.Find(ctx, query) - if err != nil { - return nil, fmt.Errorf("failed to get orders: %w", err) - } - - var orders []*Order - if err = cursor.All(ctx, &orders); err != nil { - return nil, fmt.Errorf("failed to get orders: %w", err) - } - - return orders, nil -} - -func (s *botStore) SaveOrder(ctx context.Context, order *Order) error { - ordersCollection := s.Database(botDatabase).Collection(orderCollection) - _, err := ordersCollection.InsertOne(ctx, order) - if err != nil { - return fmt.Errorf("failed to save order: %w", err) - } - - return nil -} - -func (s *botStore) SaveManyOrders(ctx context.Context, orders []*Order) error { - ordersCollection := s.Database(botDatabase).Collection(orderCollection) - records := make([]interface{}, len(orders)) - - for i, order := range orders { - records[i] = order - } - - _, err := ordersCollection.InsertMany(ctx, records) - if err != nil { - return fmt.Errorf("failed to insert many orders: %w", err) - } - - return nil -} - -func (s *botStore) DeleteOrder(ctx context.Context, id string) error { - ordersCollection := s.Database(botDatabase).Collection(orderCollection) - _, err := ordersCollection.DeleteOne(ctx, bson.M{"_id": id}) - if err != nil { - return fmt.Errorf("failed to update order: %w", err) - } - - return nil -} diff --git a/store/store.go b/store/store.go deleted file mode 100644 index 31877d3..0000000 --- a/store/store.go +++ /dev/null @@ -1,25 +0,0 @@ -package store - -import ( - "context" - - "go.mongodb.org/mongo-driver/mongo" -) - -type botStore struct { - *mongo.Client -} - -const ( - botDatabase = "botstore" - botCollection = "bots" - orderCollection = "orders" -) - -func NewBotStore(client *mongo.Client) *botStore { - return &botStore{client} -} - -func (s *botStore) Close() { - _ = s.Client.Disconnect(context.Background()) -} diff --git a/store/store_test.go b/store/store_test.go deleted file mode 100644 index 45f4423..0000000 --- a/store/store_test.go +++ /dev/null @@ -1,142 +0,0 @@ -package store_test - -import ( - "context" - "testing" - - "github.com/ory/dockertest/v3" - "github.com/ory/dockertest/v3/docker" - "github.com/stretchr/testify/require" - "go.mongodb.org/mongo-driver/mongo" - "go.mongodb.org/mongo-driver/mongo/options" - - "github.com/dymensionxyz/eibc-client/store" -) - -func TestBotStore(t *testing.T) { - // Create a new Docker pool - pool, err := dockertest.NewPool("") - require.NoError(t, err) - - // Start a new MongoDB container - resource, err := pool.RunWithOptions(&dockertest.RunOptions{ - Repository: "mongo", - Tag: "4.2", - Env: []string{}, - }, func(config *docker.HostConfig) { - // Set AutoRemove to true so that stopped container gets deleted - config.AutoRemove = true - config.RestartPolicy = docker.RestartPolicy{Name: "no"} - }) - require.NoError(t, err) - - defer func() { - require.NoError(t, pool.Purge(resource)) - }() - - var client *mongo.Client - - ctx := context.Background() - - err = pool.Retry(func() error { - url := "mongodb://localhost:" + resource.GetPort("27017/tcp") - client, err = mongo.Connect(ctx, options.Client().ApplyURI(url)) - if err != nil { - return err - } - return client.Ping(ctx, nil) - }) - require.NoError(t, err) - - key := "bot-1" - t.Run("test bot creation", func(t *testing.T) { - s := store.NewBotStore(client) - bot := &store.Bot{ - Address: key, - Balances: []string{ - "1000000000000adym", - }, - } - - err = s.SaveBot(ctx, bot) - require.NoError(t, err) - - b, err := s.GetBot(ctx, key) - require.NoError(t, err) - require.Equal(t, bot, b) - }) - - t.Run("test order creation", func(t *testing.T) { - s := store.NewBotStore(client) - id := "order-1" - order := &store.Order{ - ID: id, - Fulfiller: key, - Amount: "1000000000000adym", - FulfilledHeight: 100, - ExpectedFinalizedHeight: 200, - Status: store.OrderStatusPending, - } - - err = s.SaveOrder(ctx, order) - require.NoError(t, err) - - o, err := s.GetOrder(ctx, id) - require.NoError(t, err) - require.Equal(t, order, o) - }) - - t.Run("test order retrieval by status", func(t *testing.T) { - s := store.NewBotStore(client) - id := "order-2" - order := &store.Order{ - ID: id, - Fulfiller: key, - Amount: "1000000000000adym", - FulfilledHeight: 100, - ExpectedFinalizedHeight: 200, - Status: store.OrderStatusFinalized, - } - - err = s.SaveOrder(ctx, order) - require.NoError(t, err) - - o, err := s.GetOrders(ctx, store.FilterByStatus(store.OrderStatusFinalized)) - require.NoError(t, err) - require.Len(t, o, 1) - require.Equal(t, order, o[0]) - }) - - t.Run("test get bot with pending orders", func(t *testing.T) { - s := store.NewBotStore(client) - - botKey := "bot-2" - bot := &store.Bot{ - Address: botKey, - Balances: []string{ - "1000000000000adym", - }, - } - - err = s.SaveBot(ctx, bot) - require.NoError(t, err) - - id := "order-3" - order := &store.Order{ - ID: id, - Fulfiller: botKey, - Amount: "1000000000000adym", - FulfilledHeight: 100, - ExpectedFinalizedHeight: 200, - Status: store.OrderStatusPending, - } - - err = s.SaveOrder(ctx, order) - require.NoError(t, err) - - b, err := s.GetBot(ctx, botKey, store.IncludePendingOrders()) - require.NoError(t, err) - require.Len(t, b.Orders, 1) - require.Equal(t, order, b.Orders[0]) - }) -} diff --git a/types.go b/types.go deleted file mode 100644 index 15243f7..0000000 --- a/types.go +++ /dev/null @@ -1,51 +0,0 @@ -package main - -import ( - "math/big" - - sdk "github.com/cosmos/cosmos-sdk/types" -) - -type orderBatch struct { - orders []*demandOrder - fulfiller string -} - -type demandOrder struct { - id string - denom string - amount sdk.Coins - fee sdk.Coins - feeStr string - rollappId string - status string - blockHeight uint64 -} - -func (o *demandOrder) feePercentage() float32 { - amount := o.amount.AmountOf(o.denom) - if amount.IsZero() { - return 0 - } - - price, _, err := big.ParseFloat(amount.String(), 10, 64, big.ToNearestEven) - if err != nil { - panic(err) - } - - o.feeStr = o.fee.AmountOf(o.denom).String() - - fee, _, err := big.ParseFloat(o.feeStr, 10, 64, big.ToNearestEven) - if err != nil { - panic(err) - } - - feeProportion, _ := new(big.Float).Quo(fee, price).Float32() - feePercent := feeProportion * 100 - return feePercent -} - -type account struct { - Name string `json:"name"` - Address string `json:"address"` -} diff --git a/types/authz.pb.go b/types/authz.pb.go new file mode 100644 index 0000000..4499a30 --- /dev/null +++ b/types/authz.pb.go @@ -0,0 +1,861 @@ +// Code generated by protoc-gen-gogo. DO NOT EDIT. +// source: dymensionxyz/dymension/eibc/authz.proto + +package types + +import ( + fmt "fmt" + io "io" + math "math" + math_bits "math/bits" + + _ "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/gogoproto/gogoproto" + proto "github.com/cosmos/gogoproto/proto" +) + +// Reference imports to suppress errors if they are not otherwise used. +var _ = proto.Marshal +var _ = fmt.Errorf +var _ = math.Inf + +// This is a compile-time assertion to ensure that this generated file +// is compatible with the proto package it is being compiled against. +// A compilation error at this line likely means your copy of the +// proto package needs to be updated. +const _ = proto.GoGoProtoPackageIsVersion3 // please upgrade the proto package + +// FulfillOrderAuthorization allows the grantee to fulfill eIBC demand orders from the granter's account. +type FulfillOrderAuthorization struct { + // rollapps is an optional list of rollapp criteria that the grantee can fulfill demand orders from + Rollapps []*RollappCriteria `protobuf:"bytes,1,rep,name=rollapps,proto3" json:"rollapps,omitempty"` +} + +func (m *FulfillOrderAuthorization) Reset() { *m = FulfillOrderAuthorization{} } +func (m *FulfillOrderAuthorization) String() string { return proto.CompactTextString(m) } +func (*FulfillOrderAuthorization) ProtoMessage() {} +func (*FulfillOrderAuthorization) Descriptor() ([]byte, []int) { + return fileDescriptor_b67acbbd9757b985, []int{0} +} +func (m *FulfillOrderAuthorization) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *FulfillOrderAuthorization) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_FulfillOrderAuthorization.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 *FulfillOrderAuthorization) XXX_Merge(src proto.Message) { + xxx_messageInfo_FulfillOrderAuthorization.Merge(m, src) +} +func (m *FulfillOrderAuthorization) XXX_Size() int { + return m.Size() +} +func (m *FulfillOrderAuthorization) XXX_DiscardUnknown() { + xxx_messageInfo_FulfillOrderAuthorization.DiscardUnknown(m) +} + +var xxx_messageInfo_FulfillOrderAuthorization proto.InternalMessageInfo + +func (m *FulfillOrderAuthorization) GetRollapps() []*RollappCriteria { + if m != nil { + return m.Rollapps + } + return nil +} + +type RollappCriteria struct { + // rollapp_id is the unique identifier of the rollapp that the grantee can fulfill demand orders from + RollappId string `protobuf:"bytes,1,opt,name=rollapp_id,json=rollappId,proto3" json:"rollapp_id,omitempty"` + // denoms is an optional list of denoms that the grantee can fulfill demand orders for + Denoms []string `protobuf:"bytes,2,rep,name=denoms,proto3" json:"denoms,omitempty"` + // max_price is the optional maximum order price acceptable to the granter + MaxPrice github_com_cosmos_cosmos_sdk_types.Coins `protobuf:"bytes,3,rep,name=max_price,json=maxPrice,proto3,castrepeated=github.com/cosmos/cosmos-sdk/types.Coins" json:"max_price"` + // min_lp_fee_percentage is the minimum fee earning percentage the LP is willing to get from a demand order + MinLpFeePercentage types.DecProto `protobuf:"bytes,4,opt,name=min_lp_fee_percentage,json=minLpFeePercentage,proto3,castrepeated=github.com/cosmos/cosmos-sdk/types.DecProto" json:"min_lp_fee_percentage"` + // operator_fee_share is the share of the fee earnings willing to give to the operator + OperatorFeeShare types.DecProto `protobuf:"bytes,5,opt,name=operator_fee_share,json=operatorFeeShare,proto3,castrepeated=github.com/cosmos/cosmos-sdk/types.DecProto" json:"operator_fee_share"` + // settlement_validated is the flag to only fulfill demand orders that have been settlement validated + SettlementValidated bool `protobuf:"varint,6,opt,name=settlement_validated,json=settlementValidated,proto3" json:"settlement_validated,omitempty"` + // spend_limit is the optional maximum amount of coins that can be spent by the grantee + SpendLimit github_com_cosmos_cosmos_sdk_types.Coins `protobuf:"bytes,7,rep,name=spend_limit,json=spendLimit,proto3,castrepeated=github.com/cosmos/cosmos-sdk/types.Coins" json:"spend_limit"` +} + +func (m *RollappCriteria) Reset() { *m = RollappCriteria{} } +func (m *RollappCriteria) String() string { return proto.CompactTextString(m) } +func (*RollappCriteria) ProtoMessage() {} +func (*RollappCriteria) Descriptor() ([]byte, []int) { + return fileDescriptor_b67acbbd9757b985, []int{1} +} +func (m *RollappCriteria) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *RollappCriteria) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_RollappCriteria.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 *RollappCriteria) XXX_Merge(src proto.Message) { + xxx_messageInfo_RollappCriteria.Merge(m, src) +} +func (m *RollappCriteria) XXX_Size() int { + return m.Size() +} +func (m *RollappCriteria) XXX_DiscardUnknown() { + xxx_messageInfo_RollappCriteria.DiscardUnknown(m) +} + +var xxx_messageInfo_RollappCriteria proto.InternalMessageInfo + +func (m *RollappCriteria) GetRollappId() string { + if m != nil { + return m.RollappId + } + return "" +} + +func (m *RollappCriteria) GetDenoms() []string { + if m != nil { + return m.Denoms + } + return nil +} + +func (m *RollappCriteria) GetMaxPrice() github_com_cosmos_cosmos_sdk_types.Coins { + if m != nil { + return m.MaxPrice + } + return nil +} + +func (m *RollappCriteria) GetMinLpFeePercentage() types.DecProto { + if m != nil { + return m.MinLpFeePercentage + } + return types.DecProto{} +} + +func (m *RollappCriteria) GetOperatorFeeShare() types.DecProto { + if m != nil { + return m.OperatorFeeShare + } + return types.DecProto{} +} + +func (m *RollappCriteria) GetSettlementValidated() bool { + if m != nil { + return m.SettlementValidated + } + return false +} + +func (m *RollappCriteria) GetSpendLimit() github_com_cosmos_cosmos_sdk_types.Coins { + if m != nil { + return m.SpendLimit + } + return nil +} + +func init() { + proto.RegisterType((*FulfillOrderAuthorization)(nil), "dymensionxyz.dymension.eibc.FulfillOrderAuthorization") + proto.RegisterType((*RollappCriteria)(nil), "dymensionxyz.dymension.eibc.RollappCriteria") +} + +func init() { + proto.RegisterFile("dymensionxyz/dymension/eibc/authz.proto", fileDescriptor_b67acbbd9757b985) +} + +var fileDescriptor_b67acbbd9757b985 = []byte{ + // 517 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xb4, 0x53, 0x3f, 0x6f, 0xd3, 0x40, + 0x14, 0xcf, 0xd1, 0x12, 0x92, 0xcb, 0x00, 0x3a, 0x0a, 0x38, 0x45, 0x75, 0xa3, 0x0c, 0x60, 0x09, + 0x6a, 0x93, 0x66, 0x63, 0x23, 0x45, 0x11, 0x88, 0x4a, 0x44, 0x46, 0x62, 0x60, 0xb1, 0x2e, 0xf6, + 0x6b, 0x72, 0xc2, 0x77, 0x67, 0xdd, 0x5d, 0xa2, 0x24, 0x13, 0x0b, 0x23, 0x12, 0x9f, 0x83, 0x99, + 0x0f, 0x51, 0x31, 0x75, 0x64, 0x2a, 0x28, 0xf9, 0x22, 0xc8, 0xf6, 0x25, 0x14, 0x04, 0x88, 0x01, + 0xa6, 0xf3, 0xf3, 0xef, 0xfd, 0xfe, 0xe8, 0x3d, 0x3d, 0x7c, 0x37, 0x99, 0x73, 0x10, 0x9a, 0x49, + 0x31, 0x9b, 0x2f, 0x82, 0x4d, 0x11, 0x00, 0x1b, 0xc6, 0x01, 0x9d, 0x98, 0xf1, 0xc2, 0xcf, 0x94, + 0x34, 0x92, 0xdc, 0xbe, 0xd8, 0xe8, 0x6f, 0x0a, 0x3f, 0x6f, 0xdc, 0xdd, 0x19, 0xc9, 0x91, 0x2c, + 0xfa, 0x82, 0xfc, 0xab, 0xa4, 0xec, 0xde, 0x8a, 0xa5, 0xe6, 0x52, 0x07, 0x5c, 0x8f, 0x82, 0x69, + 0x27, 0x7f, 0x2c, 0xd0, 0x2c, 0x81, 0xa8, 0x64, 0x94, 0x85, 0x85, 0x5c, 0xcb, 0x19, 0x52, 0x0d, + 0xc1, 0xb4, 0x33, 0x04, 0x43, 0x3b, 0x41, 0x2c, 0x99, 0x28, 0xf1, 0xf6, 0x3b, 0x84, 0x9b, 0xfd, + 0x49, 0x7a, 0xc2, 0xd2, 0xf4, 0xb9, 0x4a, 0x40, 0x3d, 0x9a, 0x98, 0xb1, 0x54, 0x6c, 0x41, 0x0d, + 0x93, 0x82, 0x3c, 0xc1, 0x35, 0x25, 0xd3, 0x94, 0x66, 0x99, 0x76, 0x50, 0x6b, 0xcb, 0x6b, 0x1c, + 0xde, 0xf7, 0xff, 0x90, 0xdb, 0x0f, 0xcb, 0xe6, 0x23, 0xc5, 0x0c, 0x28, 0x46, 0xc3, 0x0d, 0xfb, + 0xe1, 0x9d, 0x4f, 0x1f, 0x0f, 0xda, 0x36, 0x59, 0x39, 0x06, 0x1b, 0xc6, 0xff, 0xc1, 0xb1, 0x7d, + 0xbe, 0x8d, 0xaf, 0xfe, 0xa4, 0x42, 0xf6, 0x30, 0xb6, 0x3a, 0x11, 0x4b, 0x1c, 0xd4, 0x42, 0x5e, + 0x3d, 0xac, 0xdb, 0x3f, 0x4f, 0x13, 0x72, 0x13, 0x57, 0x13, 0x10, 0x92, 0x6b, 0xe7, 0x52, 0x6b, + 0xcb, 0xab, 0x87, 0xb6, 0x22, 0x63, 0x5c, 0xe7, 0x74, 0x16, 0x65, 0x8a, 0xc5, 0xe0, 0x6c, 0x15, + 0xe9, 0x9b, 0xbe, 0x8d, 0x90, 0x8f, 0x63, 0x93, 0xe0, 0x48, 0x32, 0xd1, 0x7b, 0x70, 0x7a, 0xbe, + 0x5f, 0xf9, 0xf0, 0x65, 0xdf, 0x1b, 0x31, 0x33, 0x9e, 0x0c, 0xfd, 0x58, 0x72, 0x3b, 0x49, 0xfb, + 0x1c, 0xe8, 0xe4, 0x75, 0x60, 0xe6, 0x19, 0xe8, 0x82, 0xa0, 0xc3, 0x1a, 0xa7, 0xb3, 0x41, 0x2e, + 0x4e, 0xde, 0x22, 0x7c, 0x83, 0x33, 0x11, 0xa5, 0x59, 0x74, 0x02, 0x10, 0x65, 0xa0, 0x62, 0x10, + 0x86, 0x8e, 0xc0, 0xd9, 0x6e, 0x21, 0xaf, 0x71, 0xb8, 0xf7, 0x4b, 0xdb, 0xc7, 0x10, 0x0f, 0xf2, + 0x1d, 0xf4, 0xba, 0xd6, 0xfa, 0xde, 0x5f, 0x58, 0xaf, 0x49, 0x21, 0xe1, 0x4c, 0x1c, 0x67, 0x7d, + 0x80, 0xc1, 0xc6, 0x8d, 0xbc, 0x41, 0x98, 0xc8, 0x0c, 0x14, 0x35, 0x52, 0x15, 0x49, 0xf4, 0x98, + 0x2a, 0x70, 0x2e, 0xff, 0xb7, 0x10, 0xd7, 0xd6, 0x6e, 0x7d, 0x80, 0x17, 0xb9, 0x17, 0xe9, 0xe0, + 0x1d, 0x0d, 0xc6, 0xa4, 0xc0, 0x41, 0x98, 0x68, 0x4a, 0x53, 0x96, 0x50, 0x03, 0x89, 0x53, 0x6d, + 0x21, 0xaf, 0x16, 0x5e, 0xff, 0x8e, 0xbd, 0x5c, 0x43, 0x24, 0xc5, 0x0d, 0x9d, 0x81, 0x48, 0xa2, + 0x94, 0x71, 0x66, 0x9c, 0x2b, 0xff, 0x7e, 0x53, 0xb8, 0xd0, 0x3f, 0xce, 0xe5, 0x7b, 0xcf, 0x4e, + 0x97, 0x2e, 0x3a, 0x5b, 0xba, 0xe8, 0xeb, 0xd2, 0x45, 0xef, 0x57, 0x6e, 0xe5, 0x6c, 0xe5, 0x56, + 0x3e, 0xaf, 0xdc, 0xca, 0xab, 0xce, 0x05, 0xbd, 0xdf, 0x5c, 0xf1, 0xb4, 0x1b, 0xcc, 0xca, 0x53, + 0x2e, 0xe4, 0x87, 0xd5, 0xe2, 0x88, 0xba, 0xdf, 0x02, 0x00, 0x00, 0xff, 0xff, 0x05, 0x81, 0xb7, + 0x5d, 0xf6, 0x03, 0x00, 0x00, +} + +func (m *FulfillOrderAuthorization) 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 *FulfillOrderAuthorization) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *FulfillOrderAuthorization) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + if len(m.Rollapps) > 0 { + for iNdEx := len(m.Rollapps) - 1; iNdEx >= 0; iNdEx-- { + { + size, err := m.Rollapps[iNdEx].MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarintAuthz(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0xa + } + } + return len(dAtA) - i, nil +} + +func (m *RollappCriteria) 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 *RollappCriteria) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *RollappCriteria) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + if len(m.SpendLimit) > 0 { + for iNdEx := len(m.SpendLimit) - 1; iNdEx >= 0; iNdEx-- { + { + size, err := m.SpendLimit[iNdEx].MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarintAuthz(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0x3a + } + } + if m.SettlementValidated { + i-- + if m.SettlementValidated { + dAtA[i] = 1 + } else { + dAtA[i] = 0 + } + i-- + dAtA[i] = 0x30 + } + { + size, err := m.OperatorFeeShare.MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarintAuthz(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0x2a + { + size, err := m.MinLpFeePercentage.MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarintAuthz(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0x22 + if len(m.MaxPrice) > 0 { + for iNdEx := len(m.MaxPrice) - 1; iNdEx >= 0; iNdEx-- { + { + size, err := m.MaxPrice[iNdEx].MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarintAuthz(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0x1a + } + } + if len(m.Denoms) > 0 { + for iNdEx := len(m.Denoms) - 1; iNdEx >= 0; iNdEx-- { + i -= len(m.Denoms[iNdEx]) + copy(dAtA[i:], m.Denoms[iNdEx]) + i = encodeVarintAuthz(dAtA, i, uint64(len(m.Denoms[iNdEx]))) + i-- + dAtA[i] = 0x12 + } + } + if len(m.RollappId) > 0 { + i -= len(m.RollappId) + copy(dAtA[i:], m.RollappId) + i = encodeVarintAuthz(dAtA, i, uint64(len(m.RollappId))) + i-- + dAtA[i] = 0xa + } + return len(dAtA) - i, nil +} + +func encodeVarintAuthz(dAtA []byte, offset int, v uint64) int { + offset -= sovAuthz(v) + base := offset + for v >= 1<<7 { + dAtA[offset] = uint8(v&0x7f | 0x80) + v >>= 7 + offset++ + } + dAtA[offset] = uint8(v) + return base +} +func (m *FulfillOrderAuthorization) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + if len(m.Rollapps) > 0 { + for _, e := range m.Rollapps { + l = e.Size() + n += 1 + l + sovAuthz(uint64(l)) + } + } + return n +} + +func (m *RollappCriteria) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + l = len(m.RollappId) + if l > 0 { + n += 1 + l + sovAuthz(uint64(l)) + } + if len(m.Denoms) > 0 { + for _, s := range m.Denoms { + l = len(s) + n += 1 + l + sovAuthz(uint64(l)) + } + } + if len(m.MaxPrice) > 0 { + for _, e := range m.MaxPrice { + l = e.Size() + n += 1 + l + sovAuthz(uint64(l)) + } + } + l = m.MinLpFeePercentage.Size() + n += 1 + l + sovAuthz(uint64(l)) + l = m.OperatorFeeShare.Size() + n += 1 + l + sovAuthz(uint64(l)) + if m.SettlementValidated { + n += 2 + } + if len(m.SpendLimit) > 0 { + for _, e := range m.SpendLimit { + l = e.Size() + n += 1 + l + sovAuthz(uint64(l)) + } + } + return n +} + +func sovAuthz(x uint64) (n int) { + return (math_bits.Len64(x|1) + 6) / 7 +} +func sozAuthz(x uint64) (n int) { + return sovAuthz(uint64((x << 1) ^ uint64((int64(x) >> 63)))) +} +func (m *FulfillOrderAuthorization) 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 ErrIntOverflowAuthz + } + 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: FulfillOrderAuthorization: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: FulfillOrderAuthorization: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Rollapps", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowAuthz + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return ErrInvalidLengthAuthz + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return ErrInvalidLengthAuthz + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.Rollapps = append(m.Rollapps, &RollappCriteria{}) + if err := m.Rollapps[len(m.Rollapps)-1].Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + default: + iNdEx = preIndex + skippy, err := skipAuthz(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return ErrInvalidLengthAuthz + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func (m *RollappCriteria) 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 ErrIntOverflowAuthz + } + 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: RollappCriteria: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: RollappCriteria: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field RollappId", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowAuthz + } + 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 ErrInvalidLengthAuthz + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthAuthz + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.RollappId = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + case 2: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Denoms", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowAuthz + } + 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 ErrInvalidLengthAuthz + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthAuthz + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.Denoms = append(m.Denoms, string(dAtA[iNdEx:postIndex])) + iNdEx = postIndex + case 3: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field MaxPrice", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowAuthz + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return ErrInvalidLengthAuthz + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return ErrInvalidLengthAuthz + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.MaxPrice = append(m.MaxPrice, types.Coin{}) + if err := m.MaxPrice[len(m.MaxPrice)-1].Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + case 4: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field MinLpFeePercentage", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowAuthz + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return ErrInvalidLengthAuthz + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return ErrInvalidLengthAuthz + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + if err := m.MinLpFeePercentage.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + case 5: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field OperatorFeeShare", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowAuthz + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return ErrInvalidLengthAuthz + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return ErrInvalidLengthAuthz + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + if err := m.OperatorFeeShare.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + case 6: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field SettlementValidated", wireType) + } + var v int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowAuthz + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + v |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + m.SettlementValidated = bool(v != 0) + case 7: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field SpendLimit", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowAuthz + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return ErrInvalidLengthAuthz + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return ErrInvalidLengthAuthz + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.SpendLimit = append(m.SpendLimit, types.Coin{}) + if err := m.SpendLimit[len(m.SpendLimit)-1].Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + default: + iNdEx = preIndex + skippy, err := skipAuthz(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return ErrInvalidLengthAuthz + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func skipAuthz(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, ErrIntOverflowAuthz + } + 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, ErrIntOverflowAuthz + } + 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, ErrIntOverflowAuthz + } + 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, ErrInvalidLengthAuthz + } + iNdEx += length + case 3: + depth++ + case 4: + if depth == 0 { + return 0, ErrUnexpectedEndOfGroupAuthz + } + depth-- + case 5: + iNdEx += 4 + default: + return 0, fmt.Errorf("proto: illegal wireType %d", wireType) + } + if iNdEx < 0 { + return 0, ErrInvalidLengthAuthz + } + if depth == 0 { + return iNdEx, nil + } + } + return 0, io.ErrUnexpectedEOF +} + +var ( + ErrInvalidLengthAuthz = fmt.Errorf("proto: negative length found during unmarshaling") + ErrIntOverflowAuthz = fmt.Errorf("proto: integer overflow") + ErrUnexpectedEndOfGroupAuthz = fmt.Errorf("proto: unexpected end of group") +) diff --git a/types/group.pb.go b/types/group.pb.go new file mode 100644 index 0000000..d990eb3 --- /dev/null +++ b/types/group.pb.go @@ -0,0 +1,910 @@ +package types + +import ( + "context" + "fmt" + "io" + "math" + + sdkerrors "cosmossdk.io/errors" + _ "github.com/cosmos/cosmos-proto" + "github.com/cosmos/cosmos-sdk/codec/types" + sdk "github.com/cosmos/cosmos-sdk/types" + _ "github.com/cosmos/cosmos-sdk/types/msgservice" + "github.com/cosmos/cosmos-sdk/types/tx" + "github.com/cosmos/cosmos-sdk/x/authz/codec" + "github.com/cosmos/cosmos-sdk/x/group/errors" + _ "github.com/cosmos/gogoproto/gogoproto" + "github.com/cosmos/gogoproto/proto" + "google.golang.org/grpc" +) + +// 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 + +// Exec defines modes of execution of a proposal on creation or on new vote. +type Exec int32 + +const ( + // An empty value means that there should be a separate + // MsgExec request for the proposal to execute. + Exec_EXEC_UNSPECIFIED Exec = 0 + // Try to execute the proposal immediately. + // If the proposal is not allowed per the DecisionPolicy, + // the proposal will still be open and could + // be executed at a later point. + Exec_EXEC_TRY Exec = 1 +) + +var Exec_name = map[int32]string{ + 0: "EXEC_UNSPECIFIED", + 1: "EXEC_TRY", +} + +var Exec_value = map[string]int32{ + "EXEC_UNSPECIFIED": 0, + "EXEC_TRY": 1, +} + +func (x Exec) String() string { + return proto.EnumName(Exec_name, int32(x)) +} + +func (Exec) EnumDescriptor() ([]byte, []int) { + return fileDescriptor_6b8d3d629f136420, []int{0} +} + +var _ sdk.Msg = &MsgSubmitProposal{} + +// NewMsgSubmitProposal creates a new MsgSubmitProposal. +func NewMsgSubmitProposal(address string, proposers []string, msgs []sdk.Msg, metadata string, exec Exec, title, summary string) (*MsgSubmitProposal, error) { + m := &MsgSubmitProposal{ + GroupPolicyAddress: address, + Proposers: proposers, + Metadata: metadata, + Exec: exec, + Title: title, + Summary: summary, + } + err := m.SetMsgs(msgs) + if err != nil { + return nil, err + } + return m, nil +} + +// MsgSubmitProposal is the Msg/SubmitProposal request type. +type MsgSubmitProposal struct { + // group_policy_address is the account address of group policy. + GroupPolicyAddress string `protobuf:"bytes,1,opt,name=group_policy_address,json=groupPolicyAddress,proto3" json:"group_policy_address,omitempty"` + // proposers are the account addresses of the proposers. + // Proposers signatures will be counted as yes votes. + Proposers []string `protobuf:"bytes,2,rep,name=proposers,proto3" json:"proposers,omitempty"` + // metadata is any arbitrary metadata attached to the proposal. + Metadata string `protobuf:"bytes,3,opt,name=metadata,proto3" json:"metadata,omitempty"` + // messages is a list of `sdk.Msg`s that will be executed if the proposal passes. + Messages []*types.Any `protobuf:"bytes,4,rep,name=messages,proto3" json:"messages,omitempty"` + // exec defines the mode of execution of the proposal, + // whether it should be executed immediately on creation or not. + // If so, proposers signatures are considered as Yes votes. + Exec Exec `protobuf:"varint,5,opt,name=exec,proto3,enum=cosmos.group.v1.Exec" json:"exec,omitempty"` + // title is the title of the proposal. + // + // Since: cosmos-sdk 0.47 + Title string `protobuf:"bytes,6,opt,name=title,proto3" json:"title,omitempty"` + // summary is the summary of the proposal. + // + // Since: cosmos-sdk 0.47 + Summary string `protobuf:"bytes,7,opt,name=summary,proto3" json:"summary,omitempty"` +} + +func (m *MsgSubmitProposal) Reset() { *m = MsgSubmitProposal{} } +func (m *MsgSubmitProposal) String() string { return proto.CompactTextString(m) } +func (*MsgSubmitProposal) ProtoMessage() {} +func (*MsgSubmitProposal) Descriptor() ([]byte, []int) { + return fileDescriptor_6b8d3d629f136420, []int{18} +} +func (m *MsgSubmitProposal) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *MsgSubmitProposal) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_MsgSubmitProposal.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 *MsgSubmitProposal) XXX_Merge(src proto.Message) { + xxx_messageInfo_MsgSubmitProposal.Merge(m, src) +} +func (m *MsgSubmitProposal) XXX_Size() int { + return m.Size() +} +func (m *MsgSubmitProposal) XXX_DiscardUnknown() { + xxx_messageInfo_MsgSubmitProposal.DiscardUnknown(m) +} + +var xxx_messageInfo_MsgSubmitProposal proto.InternalMessageInfo + +// MsgSubmitProposalResponse is the Msg/SubmitProposal response type. +type MsgSubmitProposalResponse struct { + // proposal is the unique ID of the proposal. + ProposalId uint64 `protobuf:"varint,1,opt,name=proposal_id,json=proposalId,proto3" json:"proposal_id,omitempty"` +} + +func (m *MsgSubmitProposalResponse) Reset() { *m = MsgSubmitProposalResponse{} } +func (m *MsgSubmitProposalResponse) String() string { return proto.CompactTextString(m) } +func (*MsgSubmitProposalResponse) ProtoMessage() {} +func (*MsgSubmitProposalResponse) Descriptor() ([]byte, []int) { + return fileDescriptor_6b8d3d629f136420, []int{19} +} +func (m *MsgSubmitProposalResponse) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *MsgSubmitProposalResponse) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_MsgSubmitProposalResponse.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 *MsgSubmitProposalResponse) XXX_Merge(src proto.Message) { + xxx_messageInfo_MsgSubmitProposalResponse.Merge(m, src) +} +func (m *MsgSubmitProposalResponse) XXX_Size() int { + return m.Size() +} +func (m *MsgSubmitProposalResponse) XXX_DiscardUnknown() { + xxx_messageInfo_MsgSubmitProposalResponse.DiscardUnknown(m) +} + +var xxx_messageInfo_MsgSubmitProposalResponse proto.InternalMessageInfo + +func (m *MsgSubmitProposalResponse) GetProposalId() uint64 { + if m != nil { + return m.ProposalId + } + return 0 +} + +// Route Implements Msg. +func (m MsgSubmitProposal) Route() string { + return sdk.MsgTypeURL(&m) +} + +// Type Implements Msg. +func (m MsgSubmitProposal) Type() string { return sdk.MsgTypeURL(&m) } + +// GetSignBytes Implements Msg. +func (m MsgSubmitProposal) GetSignBytes() []byte { + return sdk.MustSortJSON(codec.ModuleCdc.MustMarshalJSON(&m)) +} + +func (MsgSubmitProposal) XXX_MessageName() string { + return "cosmos.group.v1.MsgSubmitProposal" +} + +// GetSigners returns the expected signers for a MsgSubmitProposal. +func (m MsgSubmitProposal) GetSigners() []sdk.AccAddress { + addrs, err := m.getProposerAccAddresses() + if err != nil { + panic(err) + } + + return addrs +} + +// ValidateBasic does a sanity check on the provided proposal, such as +// verifying proposer addresses, and performing ValidateBasic on each +// individual `sdk.Msg`. +func (m MsgSubmitProposal) ValidateBasic() error { + _, err := sdk.AccAddressFromBech32(m.GroupPolicyAddress) + if err != nil { + return sdkerrors.Wrap(err, "group policy") + } + + if m.Title == "" { + return sdkerrors.Wrap(errors.ErrEmpty, "title") + } + + if m.Summary == "" { + return sdkerrors.Wrap(errors.ErrEmpty, "summary") + } + + if len(m.Proposers) == 0 { + return sdkerrors.Wrap(errors.ErrEmpty, "proposers") + } + + addrs, err := m.getProposerAccAddresses() + if err != nil { + return sdkerrors.Wrap(err, "group proposers") + } + + if err := accAddresses(addrs).ValidateBasic(); err != nil { + return sdkerrors.Wrap(err, "proposers") + } + + msgs, err := m.GetMsgs() + if err != nil { + return err + } + + for i, msg := range msgs { + if err := msg.ValidateBasic(); err != nil { + return sdkerrors.Wrapf(err, "msg %d", i) + } + } + return nil +} + +type accAddresses []sdk.AccAddress + +// ValidateBasic verifies that there's no duplicate address. +// Individual account address validation has to be done separately. +func (a accAddresses) ValidateBasic() error { + index := make(map[string]struct{}, len(a)) + for i := range a { + accAddr := a[i] + addr := string(accAddr) + if _, exists := index[addr]; exists { + return sdkerrors.Wrapf(errors.ErrDuplicate, "address: %s", accAddr.String()) + } + index[addr] = struct{}{} + } + return nil +} + +// getProposerAccAddresses returns the proposers as `[]sdk.AccAddress`. +func (m *MsgSubmitProposal) getProposerAccAddresses() ([]sdk.AccAddress, error) { + addrs := make([]sdk.AccAddress, len(m.Proposers)) + for i, proposer := range m.Proposers { + addr, err := sdk.AccAddressFromBech32(proposer) + if err != nil { + return nil, sdkerrors.Wrap(err, "proposers") + } + addrs[i] = addr + } + + return addrs, nil +} + +// SetMsgs packs msgs into Any's +func (m *MsgSubmitProposal) SetMsgs(msgs []sdk.Msg) error { + anys, err := tx.SetMsgs(msgs) + if err != nil { + return err + } + m.Messages = anys + return nil +} + +// GetMsgs unpacks m.Messages Any's into sdk.Msg's +func (m MsgSubmitProposal) GetMsgs() ([]sdk.Msg, error) { + return tx.GetMsgs(m.Messages, "proposal") +} + +// UnpackInterfaces implements UnpackInterfacesMessage.UnpackInterfaces +func (m MsgSubmitProposal) UnpackInterfaces(unpacker types.AnyUnpacker) error { + return tx.UnpackInterfaces(unpacker, m.Messages) +} + +func init() { + proto.RegisterEnum("cosmos.group.v1.Exec", Exec_name, Exec_value) + proto.RegisterType((*MsgSubmitProposal)(nil), "cosmos.group.v1.MsgSubmitProposal") + proto.RegisterType((*MsgSubmitProposalResponse)(nil), "cosmos.group.v1.MsgSubmitProposalResponse") +} + +func init() { proto.RegisterFile("cosmos/group/v1/tx.proto", fileDescriptor_6b8d3d629f136420) } + +var fileDescriptor_6b8d3d629f136420 = []byte{ + // 1443 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xc4, 0x58, 0xcf, 0x6f, 0x1b, 0xc5, + 0x17, 0xcf, 0xda, 0xce, 0xaf, 0x97, 0x6f, 0xdd, 0x64, 0x9b, 0xb4, 0x9b, 0x6d, 0x6b, 0xbb, 0xd3, + 0xb4, 0x49, 0xad, 0xc6, 0x6e, 0x9c, 0x6f, 0x2b, 0x61, 0x10, 0xa8, 0x49, 0x0d, 0x0a, 0xc2, 0x10, + 0x6d, 0x5b, 0x0a, 0x5c, 0xcc, 0x26, 0xde, 0x6e, 0x57, 0x64, 0xbd, 0xc6, 0xb3, 0x4e, 0x93, 0x1b, + 0x3f, 0x2e, 0xd0, 0x0b, 0x48, 0xf0, 0x07, 0xc0, 0x8d, 0x63, 0x91, 0x7a, 0xe0, 0xc6, 0x0d, 0x55, + 0xe5, 0x52, 0x71, 0xe2, 0x84, 0xa0, 0x15, 0xea, 0x8d, 0x7f, 0x01, 0xb4, 0x33, 0xbb, 0xe3, 0x1d, + 0xef, 0xae, 0x77, 0x6b, 0x59, 0x70, 0x89, 0xb2, 0xf3, 0x3e, 0xef, 0xd7, 0xe7, 0xbd, 0x79, 0x33, + 0x63, 0x90, 0x76, 0x2d, 0x6c, 0x5a, 0xb8, 0xac, 0x77, 0xac, 0x6e, 0xbb, 0xbc, 0xbf, 0x56, 0xb6, + 0x0f, 0x4a, 0xed, 0x8e, 0x65, 0x5b, 0xe2, 0x51, 0x2a, 0x29, 0x11, 0x49, 0x69, 0x7f, 0x4d, 0x9e, + 0xd7, 0x2d, 0xdd, 0x22, 0xb2, 0xb2, 0xf3, 0x1f, 0x85, 0xc9, 0x8b, 0x14, 0xd6, 0xa0, 0x02, 0x57, + 0xc7, 0x15, 0xe9, 0x96, 0xa5, 0xef, 0x69, 0x65, 0xf2, 0xb5, 0xd3, 0xbd, 0x5d, 0x56, 0x5b, 0x87, + 0xae, 0xe8, 0x64, 0xc0, 0xed, 0x61, 0x5b, 0xf3, 0xf4, 0x4e, 0xb8, 0x42, 0x13, 0xeb, 0x8e, 0xc8, + 0xc4, 0xba, 0x2b, 0x98, 0x53, 0x4d, 0xa3, 0x65, 0x95, 0xc9, 0x5f, 0xba, 0x84, 0x7e, 0x16, 0x20, + 0x5b, 0xc7, 0xfa, 0x66, 0x47, 0x53, 0x6d, 0xed, 0x35, 0xc7, 0x9a, 0x58, 0x82, 0x71, 0xb5, 0x69, + 0x1a, 0x2d, 0x49, 0x28, 0x08, 0x2b, 0xd3, 0x1b, 0xd2, 0x2f, 0x0f, 0x56, 0xe7, 0xdd, 0xb8, 0xae, + 0x36, 0x9b, 0x1d, 0x0d, 0xe3, 0xeb, 0x76, 0xc7, 0x68, 0xe9, 0x0a, 0x85, 0x89, 0x9b, 0x30, 0x69, + 0x6a, 0xe6, 0x8e, 0xd6, 0xc1, 0x52, 0xaa, 0x90, 0x5e, 0x99, 0xa9, 0xe4, 0x4a, 0x7d, 0xa9, 0x97, + 0xea, 0x44, 0xae, 0x68, 0x1f, 0x76, 0x35, 0x6c, 0x6f, 0x4c, 0x3f, 0xfc, 0x2d, 0x3f, 0xf6, 0xdd, + 0xb3, 0xfb, 0x45, 0x41, 0xf1, 0x34, 0x45, 0x19, 0xa6, 0x4c, 0xcd, 0x56, 0x9b, 0xaa, 0xad, 0x4a, + 0x69, 0xc7, 0xaf, 0xc2, 0xbe, 0xab, 0x2b, 0x9f, 0x3c, 0xbb, 0x5f, 0xa4, 0xce, 0xee, 0x3d, 0xbb, + 0x5f, 0x74, 0x19, 0x5b, 0xc5, 0xcd, 0x0f, 0xca, 0x7c, 0xe8, 0x68, 0x1d, 0x8e, 0xf3, 0x2b, 0x8a, + 0x86, 0xdb, 0x56, 0x0b, 0x6b, 0xe2, 0x22, 0x4c, 0x91, 0x68, 0x1a, 0x46, 0x93, 0xe4, 0x95, 0x51, + 0x26, 0xc9, 0xf7, 0x56, 0x13, 0xfd, 0x29, 0xc0, 0x42, 0x1d, 0xeb, 0x37, 0xdb, 0x4d, 0x4f, 0xab, + 0xee, 0x06, 0xf5, 0xbc, 0x4c, 0xf8, 0x9d, 0xa4, 0x38, 0x27, 0xe2, 0x36, 0x64, 0x69, 0xaa, 0x8d, + 0x2e, 0xf1, 0x83, 0xa5, 0xf4, 0xf3, 0x72, 0x75, 0x84, 0x1a, 0xa0, 0x71, 0xe2, 0x6a, 0x99, 0x67, + 0xa5, 0xc0, 0xb3, 0x12, 0xcc, 0x06, 0xe5, 0xe1, 0x74, 0xa8, 0xc0, 0xe3, 0x08, 0xfd, 0x24, 0xc0, + 0x31, 0x1e, 0x71, 0x95, 0xa4, 0x35, 0x42, 0x1a, 0x2e, 0xc3, 0x74, 0x4b, 0xbb, 0xdb, 0xa0, 0xe6, + 0xd2, 0x31, 0xe6, 0xa6, 0x5a, 0xda, 0x5d, 0x12, 0x41, 0x75, 0x95, 0xcf, 0x35, 0x17, 0x99, 0x2b, + 0x81, 0xa3, 0xd3, 0x70, 0x32, 0x64, 0x99, 0xe5, 0xf9, 0xbd, 0x40, 0xda, 0x84, 0x63, 0x82, 0xb6, + 0xda, 0x28, 0x53, 0x1d, 0xd4, 0xd1, 0x97, 0xf8, 0x7c, 0xce, 0x0c, 0xa8, 0x1d, 0xd5, 0x40, 0x05, + 0xc8, 0x85, 0x4b, 0x58, 0x56, 0x5f, 0xa7, 0x60, 0x9e, 0x6f, 0xfe, 0x6d, 0x6b, 0xcf, 0xd8, 0x3d, + 0xfc, 0x97, 0x72, 0x12, 0x55, 0x38, 0xda, 0xd4, 0x76, 0x0d, 0x6c, 0x58, 0xad, 0x46, 0x9b, 0x78, + 0x96, 0x32, 0x05, 0x61, 0x65, 0xa6, 0x32, 0x5f, 0xa2, 0x73, 0xac, 0xe4, 0xcd, 0xb1, 0xd2, 0xd5, + 0xd6, 0xe1, 0x06, 0x7a, 0xf4, 0x60, 0x35, 0xd7, 0xdf, 0xfb, 0xd7, 0x5c, 0x03, 0x34, 0x72, 0x25, + 0xdb, 0xe4, 0xbe, 0xab, 0x95, 0xcf, 0xbe, 0xc9, 0x8f, 0xf1, 0xd4, 0xe5, 0x23, 0x87, 0x01, 0xd5, + 0x41, 0x0a, 0x9c, 0x0a, 0x5b, 0x67, 0x83, 0xa1, 0x02, 0x93, 0x2a, 0x65, 0x21, 0x96, 0x1f, 0x0f, + 0x88, 0x3e, 0x4d, 0xc1, 0x22, 0x5f, 0x0d, 0x6a, 0x74, 0xb8, 0xed, 0xf2, 0x3a, 0xcc, 0x53, 0xbe, + 0x29, 0x6b, 0x0d, 0x2f, 0x9c, 0x54, 0x8c, 0xba, 0xa8, 0xfb, 0x3d, 0x13, 0xc9, 0xb0, 0xfb, 0x6b, + 0x9d, 0x27, 0x75, 0x29, 0xb2, 0x1f, 0x7d, 0x79, 0xa2, 0xb3, 0x70, 0x26, 0x52, 0xc8, 0xba, 0xf2, + 0x87, 0x34, 0x48, 0x3c, 0xff, 0xb7, 0x0c, 0xfb, 0xce, 0x90, 0x9d, 0x39, 0x92, 0x93, 0xe6, 0x1c, + 0x64, 0x29, 0xdd, 0x7d, 0x9d, 0x7c, 0x44, 0xe7, 0x26, 0x41, 0x05, 0x16, 0xb8, 0xaa, 0x30, 0x74, + 0x86, 0xa0, 0x8f, 0xf9, 0xc8, 0x67, 0x3a, 0x6b, 0x7d, 0x3a, 0x2a, 0x76, 0x2b, 0x31, 0x5e, 0x10, + 0x56, 0xa6, 0xf8, 0x82, 0x61, 0xda, 0x2c, 0x21, 0xbb, 0x66, 0x62, 0xc4, 0xbb, 0xe6, 0x4a, 0x70, + 0xd7, 0x9c, 0x8d, 0xdc, 0x35, 0xbd, 0xea, 0xa0, 0xcf, 0x05, 0x28, 0x44, 0x09, 0x13, 0x9c, 0xab, + 0xa3, 0xec, 0x6b, 0xf4, 0x63, 0x0a, 0x50, 0x58, 0xb3, 0xf1, 0xa9, 0xff, 0xa7, 0x5b, 0x2f, 0xa4, + 0x92, 0xe9, 0x11, 0x57, 0xb2, 0x1a, 0xac, 0xe4, 0x72, 0xe4, 0x56, 0xe5, 0x6d, 0xa1, 0x8b, 0x50, + 0x8c, 0x27, 0x90, 0x6d, 0xdb, 0xbf, 0x04, 0x32, 0x36, 0x03, 0xf0, 0xa1, 0x0f, 0xca, 0x51, 0x32, + 0x3d, 0xe8, 0x64, 0xbd, 0x92, 0x94, 0x1e, 0x3e, 0x1f, 0x74, 0x1e, 0x96, 0x06, 0xc9, 0x19, 0x31, + 0x7f, 0xa4, 0x60, 0xae, 0x8e, 0xf5, 0xeb, 0xdd, 0x1d, 0xd3, 0xb0, 0xb7, 0x3b, 0x56, 0xdb, 0xc2, + 0xea, 0x5e, 0x64, 0x76, 0xc2, 0x10, 0xd9, 0x9d, 0x82, 0xe9, 0x36, 0xb1, 0xeb, 0x8d, 0xb9, 0x69, + 0xa5, 0xb7, 0x30, 0xf0, 0x04, 0xbe, 0xe4, 0xc8, 0x30, 0x56, 0x75, 0x0d, 0x4b, 0x19, 0x32, 0x1f, + 0x43, 0x5b, 0x4f, 0x61, 0x28, 0xf1, 0x02, 0x64, 0xb4, 0x03, 0x6d, 0x97, 0xcc, 0xa7, 0x6c, 0x65, + 0x21, 0x30, 0x4d, 0x6b, 0x07, 0xda, 0xae, 0x42, 0x20, 0xe2, 0x3c, 0x8c, 0xdb, 0x86, 0xbd, 0xa7, + 0x91, 0xf1, 0x34, 0xad, 0xd0, 0x0f, 0x51, 0x82, 0x49, 0xdc, 0x35, 0x4d, 0xb5, 0x73, 0x28, 0x4d, + 0x92, 0x75, 0xef, 0xb3, 0xfa, 0x82, 0xd7, 0xab, 0xbd, 0xe0, 0x9d, 0x82, 0x20, 0x5f, 0x41, 0xe8, + 0xe3, 0x25, 0xc0, 0x26, 0x7a, 0x89, 0x9c, 0xae, 0xfc, 0x22, 0x1b, 0x38, 0x79, 0x98, 0x69, 0xbb, + 0x6b, 0xbd, 0x99, 0x03, 0xde, 0xd2, 0x56, 0x13, 0x7d, 0x4b, 0x6f, 0xb1, 0xce, 0xac, 0x6a, 0x76, + 0xd4, 0xbb, 0xac, 0x46, 0x71, 0x8a, 0xfe, 0x9b, 0x40, 0x2a, 0xe1, 0x4d, 0xa0, 0x7a, 0xd9, 0xc9, + 0xd0, 0xfb, 0xea, 0x3f, 0x3a, 0x59, 0x7e, 0xfd, 0xb1, 0xb8, 0x17, 0xd4, 0xfe, 0x65, 0xd6, 0x64, + 0x7f, 0x0b, 0x30, 0x59, 0xc7, 0xfa, 0xdb, 0x96, 0x1d, 0x9f, 0xaf, 0xb3, 0x13, 0xf7, 0x2d, 0x5b, + 0xeb, 0xc4, 0x06, 0x4d, 0x61, 0xe2, 0x3a, 0x4c, 0x58, 0x6d, 0xdb, 0xb0, 0xe8, 0xfd, 0x20, 0x5b, + 0x39, 0x19, 0xa8, 0xba, 0xe3, 0xf7, 0x2d, 0x02, 0x51, 0x5c, 0x28, 0xd7, 0x76, 0x99, 0xbe, 0xb6, + 0x4b, 0xde, 0x44, 0xd5, 0x65, 0xb2, 0x3b, 0x49, 0x1c, 0x0e, 0x59, 0x52, 0x18, 0x59, 0x8e, 0x77, + 0x34, 0x07, 0x47, 0xdd, 0x7f, 0x19, 0x29, 0xf7, 0x28, 0x29, 0x8e, 0xb5, 0x78, 0x52, 0xfe, 0x0f, + 0x53, 0x8e, 0xc3, 0xae, 0x6d, 0xc5, 0xf3, 0xc2, 0x90, 0xf4, 0xa1, 0x39, 0x81, 0x0d, 0xbd, 0x35, + 0x20, 0x3e, 0x27, 0x00, 0xa4, 0x90, 0xf8, 0x48, 0x66, 0x5e, 0x63, 0xbe, 0x02, 0x13, 0x1d, 0x0d, + 0x77, 0xf7, 0x6c, 0xe2, 0x30, 0x5b, 0x59, 0x0e, 0x10, 0xe1, 0xd5, 0xb9, 0xe6, 0xfa, 0x53, 0x08, + 0x5c, 0x71, 0xd5, 0xd0, 0x17, 0x02, 0x1c, 0xa9, 0x63, 0xfd, 0x0d, 0x4d, 0xdd, 0x77, 0x5f, 0xe2, + 0x43, 0xdc, 0x4d, 0x07, 0xdc, 0xde, 0xe9, 0x8b, 0xd1, 0xdf, 0xac, 0xb9, 0xb0, 0xfc, 0x7a, 0xfe, + 0xd1, 0x09, 0xf2, 0x30, 0xee, 0x2d, 0x78, 0xb9, 0x16, 0x8b, 0x90, 0xa9, 0xd1, 0xa1, 0x30, 0x5b, + 0x7b, 0xa7, 0xb6, 0xd9, 0xb8, 0xf9, 0xe6, 0xf5, 0xed, 0xda, 0xe6, 0xd6, 0xab, 0x5b, 0xb5, 0x6b, + 0xb3, 0x63, 0xe2, 0xff, 0x60, 0x8a, 0xac, 0xde, 0x50, 0xde, 0x9d, 0x15, 0x2a, 0x8f, 0x66, 0x20, + 0x5d, 0xc7, 0xba, 0x78, 0x0b, 0x66, 0xfc, 0xbf, 0x32, 0xe4, 0x83, 0x57, 0x37, 0xee, 0xae, 0x21, + 0x2f, 0xc7, 0x00, 0x18, 0xf1, 0x7b, 0x20, 0x86, 0xbc, 0xdd, 0xcf, 0x87, 0xa9, 0x07, 0x71, 0x72, + 0x29, 0x19, 0x8e, 0x79, 0xbb, 0x0d, 0xb3, 0x81, 0x07, 0xf2, 0x52, 0x8c, 0x0d, 0x82, 0x92, 0x2f, + 0x26, 0x41, 0x31, 0x3f, 0x16, 0x1c, 0x0b, 0x7b, 0xa0, 0x2e, 0xc7, 0x86, 0x4b, 0x81, 0x72, 0x39, + 0x21, 0x90, 0x39, 0x34, 0x60, 0x2e, 0xf8, 0x76, 0x3c, 0x17, 0x53, 0x04, 0x0a, 0x93, 0x57, 0x13, + 0xc1, 0x98, 0xab, 0x2e, 0x2c, 0x84, 0x3f, 0x08, 0x2e, 0xc4, 0xd8, 0xe9, 0x41, 0xe5, 0xb5, 0xc4, + 0x50, 0xe6, 0xf6, 0x00, 0x8e, 0x47, 0x3c, 0xd9, 0x8a, 0x31, 0x64, 0xf9, 0xb0, 0x72, 0x25, 0x39, + 0x96, 0x79, 0xfe, 0x4a, 0x80, 0x7c, 0xdc, 0xdd, 0x75, 0x3d, 0x91, 0x5d, 0x5e, 0x49, 0x7e, 0x71, + 0x08, 0x25, 0x16, 0xd5, 0xc7, 0x02, 0x2c, 0x46, 0xdf, 0xf0, 0x56, 0x13, 0x99, 0x66, 0xfd, 0x76, + 0xf9, 0xb9, 0xe0, 0x2c, 0x86, 0xf7, 0x21, 0xdb, 0x77, 0x97, 0x42, 0x61, 0x86, 0x78, 0x8c, 0x5c, + 0x8c, 0xc7, 0xf8, 0x37, 0x6c, 0xe0, 0x2e, 0x10, 0xba, 0x61, 0xfb, 0x51, 0xe1, 0x1b, 0x36, 0xea, + 0xd0, 0x16, 0x37, 0x20, 0x43, 0x0e, 0x6c, 0x29, 0x4c, 0xcb, 0x91, 0xc8, 0x85, 0x28, 0x89, 0xdf, + 0x06, 0x99, 0xab, 0xa1, 0x36, 0x1c, 0x49, 0xb8, 0x0d, 0xee, 0x1c, 0xba, 0x01, 0xe0, 0x3b, 0x42, + 0x72, 0x61, 0xf8, 0x9e, 0x5c, 0x3e, 0x3f, 0x58, 0xee, 0x59, 0x95, 0xc7, 0x3f, 0x72, 0x5e, 0xd1, + 0x1b, 0x2f, 0x3f, 0x7c, 0x92, 0x13, 0x1e, 0x3f, 0xc9, 0x09, 0xbf, 0x3f, 0xc9, 0x09, 0x5f, 0x3e, + 0xcd, 0x8d, 0x3d, 0x7e, 0x9a, 0x1b, 0xfb, 0xf5, 0x69, 0x6e, 0xec, 0xbd, 0x25, 0xdd, 0xb0, 0xef, + 0x74, 0x77, 0x4a, 0xbb, 0x96, 0xe9, 0xfe, 0x8a, 0x5d, 0xf6, 0x9d, 0x2e, 0x07, 0xf4, 0x7c, 0xd9, + 0x99, 0x20, 0x17, 0xd1, 0xf5, 0x7f, 0x02, 0x00, 0x00, 0xff, 0xff, 0x4d, 0x77, 0x54, 0x7d, 0x37, + 0x17, 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 + +func (m *MsgSubmitProposal) 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 *MsgSubmitProposal) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *MsgSubmitProposal) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + if len(m.Summary) > 0 { + i -= len(m.Summary) + copy(dAtA[i:], m.Summary) + i = encodeVarintTx(dAtA, i, uint64(len(m.Summary))) + i-- + dAtA[i] = 0x3a + } + if len(m.Title) > 0 { + i -= len(m.Title) + copy(dAtA[i:], m.Title) + i = encodeVarintTx(dAtA, i, uint64(len(m.Title))) + i-- + dAtA[i] = 0x32 + } + if m.Exec != 0 { + i = encodeVarintTx(dAtA, i, uint64(m.Exec)) + i-- + dAtA[i] = 0x28 + } + if len(m.Messages) > 0 { + for iNdEx := len(m.Messages) - 1; iNdEx >= 0; iNdEx-- { + { + size, err := m.Messages[iNdEx].MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarintTx(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0x22 + } + } + if len(m.Metadata) > 0 { + i -= len(m.Metadata) + copy(dAtA[i:], m.Metadata) + i = encodeVarintTx(dAtA, i, uint64(len(m.Metadata))) + i-- + dAtA[i] = 0x1a + } + if len(m.Proposers) > 0 { + for iNdEx := len(m.Proposers) - 1; iNdEx >= 0; iNdEx-- { + i -= len(m.Proposers[iNdEx]) + copy(dAtA[i:], m.Proposers[iNdEx]) + i = encodeVarintTx(dAtA, i, uint64(len(m.Proposers[iNdEx]))) + i-- + dAtA[i] = 0x12 + } + } + if len(m.GroupPolicyAddress) > 0 { + i -= len(m.GroupPolicyAddress) + copy(dAtA[i:], m.GroupPolicyAddress) + i = encodeVarintTx(dAtA, i, uint64(len(m.GroupPolicyAddress))) + i-- + dAtA[i] = 0xa + } + return len(dAtA) - i, nil +} + +func (m *MsgSubmitProposalResponse) 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 *MsgSubmitProposalResponse) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *MsgSubmitProposalResponse) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + if m.ProposalId != 0 { + i = encodeVarintTx(dAtA, i, uint64(m.ProposalId)) + i-- + dAtA[i] = 0x8 + } + return len(dAtA) - i, nil +} + +func (m *MsgSubmitProposal) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + l = len(m.GroupPolicyAddress) + if l > 0 { + n += 1 + l + sovTx(uint64(l)) + } + if len(m.Proposers) > 0 { + for _, s := range m.Proposers { + l = len(s) + n += 1 + l + sovTx(uint64(l)) + } + } + l = len(m.Metadata) + if l > 0 { + n += 1 + l + sovTx(uint64(l)) + } + if len(m.Messages) > 0 { + for _, e := range m.Messages { + l = e.Size() + n += 1 + l + sovTx(uint64(l)) + } + } + if m.Exec != 0 { + n += 1 + sovTx(uint64(m.Exec)) + } + l = len(m.Title) + if l > 0 { + n += 1 + l + sovTx(uint64(l)) + } + l = len(m.Summary) + if l > 0 { + n += 1 + l + sovTx(uint64(l)) + } + return n +} + +func (m *MsgSubmitProposalResponse) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + if m.ProposalId != 0 { + n += 1 + sovTx(uint64(m.ProposalId)) + } + return n +} + +func (m *MsgSubmitProposal) 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: MsgSubmitProposal: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: MsgSubmitProposal: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field GroupPolicyAddress", 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.GroupPolicyAddress = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + case 2: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Proposers", 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.Proposers = append(m.Proposers, string(dAtA[iNdEx:postIndex])) + iNdEx = postIndex + case 3: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Metadata", 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.Metadata = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + case 4: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Messages", 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.Messages = append(m.Messages, &types.Any{}) + if err := m.Messages[len(m.Messages)-1].Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + case 5: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field Exec", wireType) + } + m.Exec = 0 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowTx + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + m.Exec |= Exec(b&0x7F) << shift + if b < 0x80 { + break + } + } + case 6: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Title", 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.Title = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + case 7: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Summary", 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.Summary = 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 *MsgSubmitProposalResponse) 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: MsgSubmitProposalResponse: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: MsgSubmitProposalResponse: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field ProposalId", wireType) + } + m.ProposalId = 0 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowTx + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + m.ProposalId |= 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 +} diff --git a/types/tx.go b/types/tx.go index 10eda9d..9dbb9c4 100644 --- a/types/tx.go +++ b/types/tx.go @@ -2,91 +2,97 @@ package types import ( "encoding/hex" + "errors" "fmt" errorsmod "cosmossdk.io/errors" - sdkerrors "github.com/cosmos/cosmos-sdk/types/errors" - sdk "github.com/cosmos/cosmos-sdk/types" + sdkerrors "github.com/cosmos/cosmos-sdk/types/errors" ) var ( - _ = sdk.Msg(&MsgFulfillOrder{}) - _ = sdk.Msg(&MsgUpdateDemandOrder{}) + _ = sdk.Msg(&MsgFulfillOrderAuthorized{}) + _ = sdk.Msg(&MsgFinalizePacketByPacketKey{}) ) -func NewMsgFulfillOrder(fulfillerAddress, orderId, expectedFee string) *MsgFulfillOrder { - return &MsgFulfillOrder{ - FulfillerAddress: fulfillerAddress, - OrderId: orderId, - ExpectedFee: expectedFee, +func NewMsgFulfillOrderAuthorized( + orderId, + rollappId, + granterAddress, + operatorFeeAddress, + expectedFee string, + price sdk.Coins, + operatorFeePart sdk.Dec, + settlementValidated bool, +) *MsgFulfillOrderAuthorized { + return &MsgFulfillOrderAuthorized{ + OrderId: orderId, + RollappId: rollappId, + LpAddress: granterAddress, + OperatorFeeAddress: operatorFeeAddress, + ExpectedFee: expectedFee, + Price: price, + OperatorFeeShare: sdk.DecProto{Dec: operatorFeePart}, + SettlementValidated: settlementValidated, } } -func (msg *MsgFulfillOrder) Route() string { +func (msg *MsgFulfillOrderAuthorized) Route() string { return RouterKey } -func (msg *MsgFulfillOrder) Type() string { +func (msg *MsgFulfillOrderAuthorized) Type() string { return sdk.MsgTypeURL(msg) } -func (*MsgFulfillOrder) XXX_MessageName() string { - return "dymensionxyz.dymension.eibc.MsgFulfillOrder" +func (*MsgFulfillOrderAuthorized) XXX_MessageName() string { + return "dymensionxyz.dymension.eibc.MsgFulfillOrderAuthorized" } -func (msg *MsgFulfillOrder) GetSigners() []sdk.AccAddress { - creator, err := sdk.AccAddressFromBech32(msg.FulfillerAddress) +func (msg *MsgFulfillOrderAuthorized) GetSigners() []sdk.AccAddress { + creator, err := sdk.AccAddressFromBech32(msg.LpAddress) if err != nil { panic(err) } return []sdk.AccAddress{creator} } -func (msg *MsgFulfillOrder) GetSignBytes() []byte { +func (msg *MsgFulfillOrderAuthorized) GetSignBytes() []byte { bz := ModuleCdc.MustMarshalJSON(msg) return sdk.MustSortJSON(bz) } -func (m *MsgFulfillOrder) ValidateBasic() error { - err := validateCommon(m.OrderId, m.FulfillerAddress, m.ExpectedFee) +func (msg *MsgFulfillOrderAuthorized) ValidateBasic() error { + if msg.RollappId == "" { + return errorsmod.Wrap(sdkerrors.ErrInvalidRequest, "rollapp id cannot be empty") + } + + err := validateCommon(msg.OrderId, msg.ExpectedFee, msg.OperatorFeeAddress, msg.LpAddress) if err != nil { return errorsmod.Wrap(sdkerrors.ErrInvalidRequest, err.Error()) } - return nil -} - -func (m *MsgFulfillOrder) GetFulfillerBech32Address() []byte { - return sdk.MustAccAddressFromBech32(m.FulfillerAddress) -} -func NewMsgUpdateDemandOrder(ownerAddr, orderId, newFee string) *MsgUpdateDemandOrder { - return &MsgUpdateDemandOrder{ - OrderId: orderId, - OwnerAddress: ownerAddr, - NewFee: newFee, + if msg.Price.IsAnyNegative() { + return errorsmod.Wrap(sdkerrors.ErrInvalidRequest, "price cannot be negative") } -} -func (m *MsgUpdateDemandOrder) GetSigners() []sdk.AccAddress { - creator, err := sdk.AccAddressFromBech32(m.OwnerAddress) - if err != nil { - panic(err) + if msg.OperatorFeeShare.Dec.IsNegative() { + return errorsmod.Wrap(sdkerrors.ErrInvalidRequest, "operator fee share cannot be negative") } - return []sdk.AccAddress{creator} -} -func (m *MsgUpdateDemandOrder) ValidateBasic() error { - err := validateCommon(m.OrderId, m.OwnerAddress, m.NewFee) - if err != nil { - return errorsmod.Wrap(sdkerrors.ErrInvalidRequest, err.Error()) + if msg.OperatorFeeShare.Dec.GT(sdk.OneDec()) { + return errorsmod.Wrap(sdkerrors.ErrInvalidRequest, "operator fee share cannot be greater than 1") } return nil } -func (m *MsgUpdateDemandOrder) GetSignerAddr() sdk.AccAddress { - return sdk.MustAccAddressFromBech32(m.OwnerAddress) +func (msg *MsgFulfillOrderAuthorized) GetLPBech32Address() []byte { + return sdk.MustAccAddressFromBech32(msg.LpAddress) +} + +func (msg *MsgFulfillOrderAuthorized) GetOperatorFeeBech32Address() []byte { + return sdk.MustAccAddressFromBech32(msg.OperatorFeeAddress) } func isValidOrderId(orderId string) bool { @@ -99,13 +105,16 @@ func isValidOrderId(orderId string) bool { return len(hashBytes) == 32 } -func validateCommon(orderId, address, fee string) error { +func validateCommon(orderId, fee string, address ...string) error { if !isValidOrderId(orderId) { return fmt.Errorf("%w: %s", ErrInvalidOrderID, orderId) } - _, err := sdk.AccAddressFromBech32(address) - if err != nil { - return err + + for _, addr := range address { + _, err := sdk.AccAddressFromBech32(addr) + if err != nil { + return err + } } feeInt, ok := sdk.NewIntFromString(fee) @@ -119,3 +128,27 @@ func validateCommon(orderId, address, fee string) error { return nil } + +func (m MsgFinalizePacketByPacketKey) ValidateBasic() error { + _, err := sdk.AccAddressFromBech32(m.Sender) + if err != nil { + return errors.Join( + sdkerrors.ErrInvalidAddress, + errorsmod.Wrapf(err, "sender must be a valid bech32 address: %s", m.Sender), + ) + } + if len(m.PacketKey) == 0 { + return fmt.Errorf("packet key must be non-empty") + } + + return nil +} + +func (m MsgFinalizePacketByPacketKey) GetSigners() []sdk.AccAddress { + signer, _ := sdk.AccAddressFromBech32(m.Sender) + return []sdk.AccAddress{signer} +} + +func (*MsgFinalizePacketByPacketKey) XXX_MessageName() string { + return "dymensionxyz.dymension.delayedack.MsgFinalizePacketByPacketKey" +} diff --git a/types/tx.pb.go b/types/tx.pb.go index 9b8afb6..7c9e45a 100644 --- a/types/tx.pb.go +++ b/types/tx.pb.go @@ -1,21 +1,20 @@ // Code generated by protoc-gen-gogo. DO NOT EDIT. -// source: dymensionxyz/dymension/eibc/tx.proto +// source: dymensionxyz/dymension/eibc/tx_auth.proto package types import ( - context "context" fmt "fmt" io "io" math "math" math_bits "math/bits" + _ "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" - grpc1 "github.com/cosmos/gogoproto/grpc" + _ "github.com/cosmos/gogoproto/gogoproto" proto "github.com/cosmos/gogoproto/proto" - grpc "google.golang.org/grpc" - codes "google.golang.org/grpc/codes" - status "google.golang.org/grpc/status" ) // Reference imports to suppress errors if they are not otherwise used. @@ -29,28 +28,41 @@ var _ = math.Inf // proto package needs to be updated. const _ = proto.GoGoProtoPackageIsVersion3 // please upgrade the proto package -// MsgFulfillOrder defines the FulfillOrder request type. -type MsgFulfillOrder struct { - // fulfiller_address is the bech32-encoded address of the account which the message was sent from. - FulfillerAddress string `protobuf:"bytes,1,opt,name=fulfiller_address,json=fulfillerAddress,proto3" json:"fulfiller_address,omitempty"` +// MsgFulfillOrderAuthorized defines the FulfillOrderAuthorized request type. +type MsgFulfillOrderAuthorized struct { // order_id is the unique identifier of the order to be fulfilled. - OrderId string `protobuf:"bytes,2,opt,name=order_id,json=orderId,proto3" json:"order_id,omitempty"` + OrderId string `protobuf:"bytes,1,opt,name=order_id,json=orderId,proto3" json:"order_id,omitempty"` + // rollapp_id is the unique identifier of the rollapp that the order is associated with. + RollappId string `protobuf:"bytes,2,opt,name=rollapp_id,json=rollappId,proto3" json:"rollapp_id,omitempty"` + // price is the price of the demand order + Price github_com_cosmos_cosmos_sdk_types.Coins `protobuf:"bytes,3,rep,name=price,proto3,castrepeated=github.com/cosmos/cosmos-sdk/types.Coins" json:"price"` + // lp_address is the bech32-encoded address of the account which the authorization was granted from. + // This account will receive the price amount at the finalization phase. + LpAddress string `protobuf:"bytes,4,opt,name=lp_address,json=lpAddress,proto3" json:"lp_address,omitempty"` + // operator_fee_address is an optional bech32-encoded address of an account that would collect the operator_fee_part + // if it's empty, the operator_fee_part will go to the operator_address + OperatorFeeAddress string `protobuf:"bytes,5,opt,name=operator_fee_address,json=operatorFeeAddress,proto3" json:"operator_fee_address,omitempty"` // expected_fee is the nominal fee set in the order. - ExpectedFee string `protobuf:"bytes,3,opt,name=expected_fee,json=expectedFee,proto3" json:"expected_fee,omitempty"` + ExpectedFee string `protobuf:"bytes,6,opt,name=expected_fee,json=expectedFee,proto3" json:"expected_fee,omitempty"` + // operator_fee_share is the share of the fee earnings that goes to the operator + // it will be deduced from the fee of the demand order and paid out immediately + OperatorFeeShare types.DecProto `protobuf:"bytes,7,opt,name=operator_fee_share,json=operatorFeeShare,proto3,castrepeated=github.com/cosmos/cosmos-sdk/types.DecProto" json:"operator_fee_share"` + // settlement_validated signals if the block behind the demand order needs to be "settlement validated" or not + SettlementValidated bool `protobuf:"varint,8,opt,name=settlement_validated,json=settlementValidated,proto3" json:"settlement_validated,omitempty"` } -func (m *MsgFulfillOrder) Reset() { *m = MsgFulfillOrder{} } -func (m *MsgFulfillOrder) String() string { return proto.CompactTextString(m) } -func (*MsgFulfillOrder) ProtoMessage() {} -func (*MsgFulfillOrder) Descriptor() ([]byte, []int) { - return fileDescriptor_47537f11f512b254, []int{0} +func (m *MsgFulfillOrderAuthorized) Reset() { *m = MsgFulfillOrderAuthorized{} } +func (m *MsgFulfillOrderAuthorized) String() string { return proto.CompactTextString(m) } +func (*MsgFulfillOrderAuthorized) ProtoMessage() {} +func (*MsgFulfillOrderAuthorized) Descriptor() ([]byte, []int) { + return fileDescriptor_d7e8da19b02f0731, []int{0} } -func (m *MsgFulfillOrder) XXX_Unmarshal(b []byte) error { +func (m *MsgFulfillOrderAuthorized) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) } -func (m *MsgFulfillOrder) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { +func (m *MsgFulfillOrderAuthorized) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { if deterministic { - return xxx_messageInfo_MsgFulfillOrder.Marshal(b, m, deterministic) + return xxx_messageInfo_MsgFulfillOrderAuthorized.Marshal(b, m, deterministic) } else { b = b[:cap(b)] n, err := m.MarshalToSizedBuffer(b) @@ -60,332 +72,117 @@ func (m *MsgFulfillOrder) XXX_Marshal(b []byte, deterministic bool) ([]byte, err return b[:n], nil } } -func (m *MsgFulfillOrder) XXX_Merge(src proto.Message) { - xxx_messageInfo_MsgFulfillOrder.Merge(m, src) +func (m *MsgFulfillOrderAuthorized) XXX_Merge(src proto.Message) { + xxx_messageInfo_MsgFulfillOrderAuthorized.Merge(m, src) } -func (m *MsgFulfillOrder) XXX_Size() int { +func (m *MsgFulfillOrderAuthorized) XXX_Size() int { return m.Size() } -func (m *MsgFulfillOrder) XXX_DiscardUnknown() { - xxx_messageInfo_MsgFulfillOrder.DiscardUnknown(m) +func (m *MsgFulfillOrderAuthorized) XXX_DiscardUnknown() { + xxx_messageInfo_MsgFulfillOrderAuthorized.DiscardUnknown(m) } -var xxx_messageInfo_MsgFulfillOrder proto.InternalMessageInfo +var xxx_messageInfo_MsgFulfillOrderAuthorized proto.InternalMessageInfo -func (m *MsgFulfillOrder) GetFulfillerAddress() string { - if m != nil { - return m.FulfillerAddress - } - return "" -} - -func (m *MsgFulfillOrder) GetOrderId() string { +func (m *MsgFulfillOrderAuthorized) GetOrderId() string { if m != nil { return m.OrderId } return "" } -func (m *MsgFulfillOrder) GetExpectedFee() string { +func (m *MsgFulfillOrderAuthorized) GetRollappId() string { if m != nil { - return m.ExpectedFee + return m.RollappId } return "" } -// MsgFulfillOrderResponse defines the FulfillOrder response type. -type MsgFulfillOrderResponse struct { -} - -func (m *MsgFulfillOrderResponse) Reset() { *m = MsgFulfillOrderResponse{} } -func (m *MsgFulfillOrderResponse) String() string { return proto.CompactTextString(m) } -func (*MsgFulfillOrderResponse) ProtoMessage() {} -func (*MsgFulfillOrderResponse) Descriptor() ([]byte, []int) { - return fileDescriptor_47537f11f512b254, []int{1} -} -func (m *MsgFulfillOrderResponse) XXX_Unmarshal(b []byte) error { - return m.Unmarshal(b) -} -func (m *MsgFulfillOrderResponse) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { - if deterministic { - return xxx_messageInfo_MsgFulfillOrderResponse.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 *MsgFulfillOrderResponse) XXX_Merge(src proto.Message) { - xxx_messageInfo_MsgFulfillOrderResponse.Merge(m, src) -} -func (m *MsgFulfillOrderResponse) XXX_Size() int { - return m.Size() -} -func (m *MsgFulfillOrderResponse) XXX_DiscardUnknown() { - xxx_messageInfo_MsgFulfillOrderResponse.DiscardUnknown(m) -} - -var xxx_messageInfo_MsgFulfillOrderResponse proto.InternalMessageInfo - -type MsgUpdateDemandOrder struct { - // owner_address is the bech32-encoded address of the account owns the order. - // This is expected to be the address of the order recipient. - OwnerAddress string `protobuf:"bytes,1,opt,name=owner_address,json=ownerAddress,proto3" json:"owner_address,omitempty"` - // order_id is the unique identifier of the order to be updated. - OrderId string `protobuf:"bytes,2,opt,name=order_id,json=orderId,proto3" json:"order_id,omitempty"` - // new_fee is the new fee amount to be set in the order. - NewFee string `protobuf:"bytes,3,opt,name=new_fee,json=newFee,proto3" json:"new_fee,omitempty"` -} - -func (m *MsgUpdateDemandOrder) Reset() { *m = MsgUpdateDemandOrder{} } -func (m *MsgUpdateDemandOrder) String() string { return proto.CompactTextString(m) } -func (*MsgUpdateDemandOrder) ProtoMessage() {} -func (*MsgUpdateDemandOrder) Descriptor() ([]byte, []int) { - return fileDescriptor_47537f11f512b254, []int{2} -} -func (m *MsgUpdateDemandOrder) XXX_Unmarshal(b []byte) error { - return m.Unmarshal(b) -} -func (m *MsgUpdateDemandOrder) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { - if deterministic { - return xxx_messageInfo_MsgUpdateDemandOrder.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 *MsgFulfillOrderAuthorized) GetPrice() github_com_cosmos_cosmos_sdk_types.Coins { + if m != nil { + return m.Price } -} -func (m *MsgUpdateDemandOrder) XXX_Merge(src proto.Message) { - xxx_messageInfo_MsgUpdateDemandOrder.Merge(m, src) -} -func (m *MsgUpdateDemandOrder) XXX_Size() int { - return m.Size() -} -func (m *MsgUpdateDemandOrder) XXX_DiscardUnknown() { - xxx_messageInfo_MsgUpdateDemandOrder.DiscardUnknown(m) + return nil } -var xxx_messageInfo_MsgUpdateDemandOrder proto.InternalMessageInfo - -func (m *MsgUpdateDemandOrder) GetOwnerAddress() string { +func (m *MsgFulfillOrderAuthorized) GetLpAddress() string { if m != nil { - return m.OwnerAddress + return m.LpAddress } return "" } -func (m *MsgUpdateDemandOrder) GetOrderId() string { +func (m *MsgFulfillOrderAuthorized) GetOperatorFeeAddress() string { if m != nil { - return m.OrderId + return m.OperatorFeeAddress } return "" } -func (m *MsgUpdateDemandOrder) GetNewFee() string { +func (m *MsgFulfillOrderAuthorized) GetExpectedFee() string { if m != nil { - return m.NewFee + return m.ExpectedFee } return "" } -type MsgUpdateDemandOrderResponse struct { +func (m *MsgFulfillOrderAuthorized) GetOperatorFeeShare() types.DecProto { + if m != nil { + return m.OperatorFeeShare + } + return types.DecProto{} } -func (m *MsgUpdateDemandOrderResponse) Reset() { *m = MsgUpdateDemandOrderResponse{} } -func (m *MsgUpdateDemandOrderResponse) String() string { return proto.CompactTextString(m) } -func (*MsgUpdateDemandOrderResponse) ProtoMessage() {} -func (*MsgUpdateDemandOrderResponse) Descriptor() ([]byte, []int) { - return fileDescriptor_47537f11f512b254, []int{3} -} -func (m *MsgUpdateDemandOrderResponse) XXX_Unmarshal(b []byte) error { - return m.Unmarshal(b) -} -func (m *MsgUpdateDemandOrderResponse) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { - if deterministic { - return xxx_messageInfo_MsgUpdateDemandOrderResponse.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 *MsgFulfillOrderAuthorized) GetSettlementValidated() bool { + if m != nil { + return m.SettlementValidated } -} -func (m *MsgUpdateDemandOrderResponse) XXX_Merge(src proto.Message) { - xxx_messageInfo_MsgUpdateDemandOrderResponse.Merge(m, src) -} -func (m *MsgUpdateDemandOrderResponse) XXX_Size() int { - return m.Size() -} -func (m *MsgUpdateDemandOrderResponse) XXX_DiscardUnknown() { - xxx_messageInfo_MsgUpdateDemandOrderResponse.DiscardUnknown(m) + return false } -var xxx_messageInfo_MsgUpdateDemandOrderResponse proto.InternalMessageInfo - func init() { - proto.RegisterType((*MsgFulfillOrder)(nil), "dymensionxyz.dymension.eibc.MsgFulfillOrder") - proto.RegisterType((*MsgFulfillOrderResponse)(nil), "dymensionxyz.dymension.eibc.MsgFulfillOrderResponse") - proto.RegisterType((*MsgUpdateDemandOrder)(nil), "dymensionxyz.dymension.eibc.MsgUpdateDemandOrder") - proto.RegisterType((*MsgUpdateDemandOrderResponse)(nil), "dymensionxyz.dymension.eibc.MsgUpdateDemandOrderResponse") + proto.RegisterType((*MsgFulfillOrderAuthorized)(nil), "dymensionxyz.dymension.eibc.MsgFulfillOrderAuthorized") } func init() { - proto.RegisterFile("dymensionxyz/dymension/eibc/tx.proto", fileDescriptor_47537f11f512b254) -} - -var fileDescriptor_47537f11f512b254 = []byte{ - // 374 bytes of a gzipped FileDescriptorProto - 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xe2, 0x52, 0x49, 0xa9, 0xcc, 0x4d, - 0xcd, 0x2b, 0xce, 0xcc, 0xcf, 0xab, 0xa8, 0xac, 0xd2, 0x87, 0x73, 0xf4, 0x53, 0x33, 0x93, 0x92, - 0xf5, 0x4b, 0x2a, 0xf4, 0x0a, 0x8a, 0xf2, 0x4b, 0xf2, 0x85, 0xa4, 0x91, 0x55, 0xe9, 0xc1, 0x39, - 0x7a, 0x20, 0x55, 0x52, 0xe2, 0xc9, 0xf9, 0xc5, 0xb9, 0xf9, 0xc5, 0xfa, 0xb9, 0xc5, 0xe9, 0xfa, - 0x65, 0x86, 0x20, 0x0a, 0xa2, 0x4b, 0x69, 0x0a, 0x23, 0x17, 0xbf, 0x6f, 0x71, 0xba, 0x5b, 0x69, - 0x4e, 0x5a, 0x66, 0x4e, 0x8e, 0x7f, 0x51, 0x4a, 0x6a, 0x91, 0x90, 0x36, 0x97, 0x60, 0x1a, 0x84, - 0x9f, 0x5a, 0x14, 0x9f, 0x98, 0x92, 0x52, 0x94, 0x5a, 0x5c, 0x2c, 0xc1, 0xa8, 0xc0, 0xa8, 0xc1, - 0x19, 0x24, 0x00, 0x97, 0x70, 0x84, 0x88, 0x0b, 0x49, 0x72, 0x71, 0xe4, 0x83, 0x74, 0xc5, 0x67, - 0xa6, 0x48, 0x30, 0x81, 0xd5, 0xb0, 0x83, 0xf9, 0x9e, 0x29, 0x42, 0x8a, 0x5c, 0x3c, 0xa9, 0x15, - 0x05, 0xa9, 0xc9, 0x25, 0xa9, 0x29, 0xf1, 0x69, 0xa9, 0xa9, 0x12, 0xcc, 0x60, 0x69, 0x6e, 0x98, - 0x98, 0x5b, 0x6a, 0xaa, 0x95, 0x58, 0xd3, 0xf3, 0x0d, 0x5a, 0x98, 0xb6, 0x29, 0x49, 0x72, 0x89, - 0xa3, 0xb9, 0x2a, 0x28, 0xb5, 0xb8, 0x20, 0x3f, 0xaf, 0x38, 0x55, 0xa9, 0x99, 0x91, 0x4b, 0xc4, - 0xb7, 0x38, 0x3d, 0xb4, 0x20, 0x25, 0xb1, 0x24, 0xd5, 0x25, 0x35, 0x37, 0x31, 0x2f, 0x05, 0xe2, - 0x6c, 0x65, 0x2e, 0xde, 0xfc, 0xf2, 0x3c, 0x0c, 0x27, 0xf3, 0x80, 0x05, 0x89, 0x70, 0xae, 0x38, - 0x17, 0x7b, 0x5e, 0x6a, 0x39, 0x92, 0x4b, 0xd9, 0xf2, 0x52, 0xcb, 0x41, 0x8e, 0x14, 0x02, 0x39, - 0x12, 0xd5, 0x6c, 0x25, 0x39, 0x2e, 0x19, 0x6c, 0x8e, 0x80, 0xb9, 0xd2, 0xa8, 0x91, 0x89, 0x8b, - 0xd9, 0xb7, 0x38, 0x5d, 0xa8, 0x84, 0x8b, 0x07, 0x25, 0x6c, 0x75, 0xf4, 0xf0, 0x44, 0x93, 0x1e, - 0x9a, 0x9f, 0xa5, 0x4c, 0x48, 0x51, 0x0d, 0x0f, 0x21, 0x06, 0xa1, 0x66, 0x46, 0x2e, 0x41, 0xcc, - 0x00, 0x32, 0x24, 0x64, 0x1a, 0x86, 0x16, 0x29, 0x4b, 0x92, 0xb5, 0x20, 0x5c, 0xe1, 0xe4, 0x7d, - 0xe2, 0x91, 0x1c, 0xe3, 0x85, 0x47, 0x72, 0x8c, 0x0f, 0x1e, 0xc9, 0x31, 0x4e, 0x78, 0x2c, 0xc7, - 0x70, 0xe1, 0xb1, 0x1c, 0xc3, 0x8d, 0xc7, 0x72, 0x0c, 0x51, 0x86, 0xe9, 0x99, 0x25, 0x19, 0xa5, - 0x49, 0x7a, 0xc9, 0xf9, 0xb9, 0xfa, 0x38, 0x12, 0x77, 0x99, 0xb1, 0x7e, 0x05, 0x34, 0x85, 0x57, - 0x16, 0xa4, 0x16, 0x27, 0xb1, 0x81, 0xd3, 0xab, 0x31, 0x20, 0x00, 0x00, 0xff, 0xff, 0xc8, 0x69, - 0xa9, 0xa4, 0x0d, 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 { - FulfillOrder(ctx context.Context, in *MsgFulfillOrder, opts ...grpc.CallOption) (*MsgFulfillOrderResponse, error) - UpdateDemandOrder(ctx context.Context, in *MsgUpdateDemandOrder, opts ...grpc.CallOption) (*MsgUpdateDemandOrderResponse, error) -} - -type msgClient struct { - cc grpc1.ClientConn -} - -func NewMsgClient(cc grpc1.ClientConn) MsgClient { - return &msgClient{cc} -} - -func (c *msgClient) FulfillOrder(ctx context.Context, in *MsgFulfillOrder, opts ...grpc.CallOption) (*MsgFulfillOrderResponse, error) { - out := new(MsgFulfillOrderResponse) - err := c.cc.Invoke(ctx, "/dymensionxyz.dymension.eibc.Msg/FulfillOrder", in, out, opts...) - if err != nil { - return nil, err - } - return out, nil -} - -func (c *msgClient) UpdateDemandOrder(ctx context.Context, in *MsgUpdateDemandOrder, opts ...grpc.CallOption) (*MsgUpdateDemandOrderResponse, error) { - out := new(MsgUpdateDemandOrderResponse) - err := c.cc.Invoke(ctx, "/dymensionxyz.dymension.eibc.Msg/UpdateDemandOrder", in, out, opts...) - if err != nil { - return nil, err - } - return out, nil -} - -// MsgServer is the server API for Msg service. -type MsgServer interface { - FulfillOrder(context.Context, *MsgFulfillOrder) (*MsgFulfillOrderResponse, error) - UpdateDemandOrder(context.Context, *MsgUpdateDemandOrder) (*MsgUpdateDemandOrderResponse, error) -} - -// UnimplementedMsgServer can be embedded to have forward compatible implementations. -type UnimplementedMsgServer struct { -} - -func (*UnimplementedMsgServer) FulfillOrder(ctx context.Context, req *MsgFulfillOrder) (*MsgFulfillOrderResponse, error) { - return nil, status.Errorf(codes.Unimplemented, "method FulfillOrder not implemented") -} -func (*UnimplementedMsgServer) UpdateDemandOrder(ctx context.Context, req *MsgUpdateDemandOrder) (*MsgUpdateDemandOrderResponse, error) { - return nil, status.Errorf(codes.Unimplemented, "method UpdateDemandOrder not implemented") -} - -func RegisterMsgServer(s grpc1.Server, srv MsgServer) { - s.RegisterService(&_Msg_serviceDesc, srv) -} - -func _Msg_FulfillOrder_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { - in := new(MsgFulfillOrder) - if err := dec(in); err != nil { - return nil, err - } - if interceptor == nil { - return srv.(MsgServer).FulfillOrder(ctx, in) - } - info := &grpc.UnaryServerInfo{ - Server: srv, - FullMethod: "/dymensionxyz.dymension.eibc.Msg/FulfillOrder", - } - handler := func(ctx context.Context, req interface{}) (interface{}, error) { - return srv.(MsgServer).FulfillOrder(ctx, req.(*MsgFulfillOrder)) - } - return interceptor(ctx, in, info, handler) -} - -func _Msg_UpdateDemandOrder_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { - in := new(MsgUpdateDemandOrder) - if err := dec(in); err != nil { - return nil, err - } - if interceptor == nil { - return srv.(MsgServer).UpdateDemandOrder(ctx, in) - } - info := &grpc.UnaryServerInfo{ - Server: srv, - FullMethod: "/dymensionxyz.dymension.eibc.Msg/UpdateDemandOrder", - } - handler := func(ctx context.Context, req interface{}) (interface{}, error) { - return srv.(MsgServer).UpdateDemandOrder(ctx, req.(*MsgUpdateDemandOrder)) - } - return interceptor(ctx, in, info, handler) -} - -var _Msg_serviceDesc = grpc.ServiceDesc{ - ServiceName: "dymensionxyz.dymension.eibc.Msg", - HandlerType: (*MsgServer)(nil), - Methods: []grpc.MethodDesc{ - { - MethodName: "FulfillOrder", - Handler: _Msg_FulfillOrder_Handler, - }, - { - MethodName: "UpdateDemandOrder", - Handler: _Msg_UpdateDemandOrder_Handler, - }, - }, - Streams: []grpc.StreamDesc{}, - Metadata: "dymensionxyz/dymension/eibc/tx.proto", -} - -func (m *MsgFulfillOrder) Marshal() (dAtA []byte, err error) { + proto.RegisterFile("dymensionxyz/dymension/eibc/tx_auth.proto", fileDescriptor_d7e8da19b02f0731) +} + +var fileDescriptor_d7e8da19b02f0731 = []byte{ + // 468 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x8c, 0x52, 0xcf, 0x6e, 0xd3, 0x30, + 0x18, 0x6f, 0x28, 0xdb, 0x3a, 0x17, 0x09, 0x14, 0x2a, 0x91, 0x0e, 0x2d, 0x2b, 0x9c, 0x02, 0x88, + 0x78, 0x59, 0x6f, 0xdc, 0x56, 0x50, 0xa5, 0x09, 0x21, 0x50, 0x91, 0x38, 0x70, 0x89, 0x9c, 0xf8, + 0x5b, 0x6a, 0x91, 0xc4, 0x96, 0xed, 0x56, 0xed, 0x4e, 0x88, 0x27, 0xe0, 0x39, 0x38, 0xf1, 0x18, + 0x3b, 0xee, 0xc8, 0x09, 0x50, 0x7b, 0xe0, 0x01, 0x78, 0x01, 0xe4, 0xc4, 0x29, 0x45, 0x02, 0x89, + 0x93, 0xf3, 0xfb, 0xe7, 0xfc, 0x3e, 0xeb, 0x43, 0x0f, 0xe8, 0xb2, 0x80, 0x52, 0x31, 0x5e, 0x2e, + 0x96, 0x17, 0x78, 0x03, 0x30, 0xb0, 0x24, 0xc5, 0x7a, 0x11, 0x93, 0x99, 0x9e, 0x86, 0x42, 0x72, + 0xcd, 0xdd, 0xbb, 0xdb, 0xd6, 0x70, 0x03, 0x42, 0x63, 0x3d, 0xb8, 0x93, 0x72, 0x55, 0x70, 0x85, + 0x0b, 0x95, 0xe1, 0x79, 0x64, 0x8e, 0x3a, 0x75, 0xd0, 0xaf, 0x85, 0xb8, 0x42, 0xb8, 0x06, 0x56, + 0xea, 0x65, 0x3c, 0xe3, 0x35, 0x6f, 0xbe, 0x2c, 0xeb, 0xdb, 0x9b, 0x12, 0xa2, 0x00, 0xcf, 0xa3, + 0x04, 0x34, 0x89, 0x70, 0xca, 0x59, 0x59, 0xeb, 0xf7, 0x7f, 0xb6, 0x51, 0xff, 0x85, 0xca, 0xc6, + 0xb3, 0xfc, 0x9c, 0xe5, 0xf9, 0x4b, 0x49, 0x41, 0x9e, 0xce, 0xf4, 0x94, 0x4b, 0x76, 0x01, 0xd4, + 0xed, 0xa3, 0x0e, 0x37, 0x54, 0xcc, 0xa8, 0xe7, 0x0c, 0x9c, 0x60, 0x7f, 0xb2, 0x57, 0xe1, 0x33, + 0xea, 0x1e, 0x22, 0x24, 0x79, 0x9e, 0x13, 0x21, 0x8c, 0x78, 0xad, 0x12, 0xf7, 0x2d, 0x73, 0x46, + 0x5d, 0x82, 0x76, 0x84, 0x64, 0x29, 0x78, 0xed, 0x41, 0x3b, 0xe8, 0x9e, 0xf4, 0x43, 0xdb, 0xd5, + 0xf4, 0x08, 0x6d, 0x8f, 0xf0, 0x29, 0x67, 0xe5, 0xe8, 0xf8, 0xf2, 0xeb, 0x51, 0xeb, 0xd3, 0xb7, + 0xa3, 0x20, 0x63, 0x7a, 0x3a, 0x4b, 0xc2, 0x94, 0x17, 0x76, 0x30, 0x7b, 0x3c, 0x56, 0xf4, 0x1d, + 0xd6, 0x4b, 0x01, 0xaa, 0x0a, 0xa8, 0x49, 0x7d, 0xb3, 0x69, 0x90, 0x8b, 0x98, 0x50, 0x2a, 0x41, + 0x29, 0xef, 0x7a, 0xdd, 0x20, 0x17, 0xa7, 0x35, 0xe1, 0x1e, 0xa3, 0x1e, 0x17, 0x20, 0x89, 0xe6, + 0x32, 0x3e, 0x07, 0xd8, 0x18, 0x77, 0x2a, 0xa3, 0xdb, 0x68, 0x63, 0x80, 0x26, 0x71, 0x0f, 0xdd, + 0x80, 0x85, 0x80, 0x54, 0x03, 0x35, 0x09, 0x6f, 0xb7, 0x72, 0x76, 0x1b, 0x6e, 0x0c, 0xe0, 0xbe, + 0x77, 0x90, 0xfb, 0xc7, 0xad, 0x6a, 0x4a, 0x24, 0x78, 0x7b, 0x03, 0x27, 0xe8, 0x9e, 0x1c, 0xfe, + 0x75, 0xc8, 0x67, 0x90, 0xbe, 0x32, 0x4f, 0x3d, 0x1a, 0xda, 0x41, 0x1f, 0xfd, 0xc7, 0xa0, 0x4d, + 0x68, 0x72, 0x6b, 0xab, 0xe7, 0x6b, 0xf3, 0x2f, 0x37, 0x42, 0x3d, 0x05, 0x5a, 0xe7, 0x50, 0x40, + 0xa9, 0xe3, 0x39, 0xc9, 0x19, 0x25, 0x1a, 0xa8, 0xd7, 0x19, 0x38, 0x41, 0x67, 0x72, 0xfb, 0xb7, + 0xf6, 0xa6, 0x91, 0x9e, 0xdc, 0xfc, 0xf0, 0xe3, 0xf3, 0xc3, 0xad, 0xc7, 0x1a, 0x3d, 0xbf, 0x5c, + 0xf9, 0xce, 0xd5, 0xca, 0x77, 0xbe, 0xaf, 0x7c, 0xe7, 0xe3, 0xda, 0x6f, 0x5d, 0xad, 0xfd, 0xd6, + 0x97, 0xb5, 0xdf, 0x7a, 0x1b, 0x6d, 0x95, 0xfb, 0xc7, 0x32, 0xcf, 0x87, 0x78, 0x61, 0x37, 0xda, + 0x74, 0x4d, 0x76, 0xab, 0x4d, 0x1a, 0xfe, 0x0a, 0x00, 0x00, 0xff, 0xff, 0xf1, 0x5a, 0xae, 0x40, + 0xfd, 0x02, 0x00, 0x00, +} + +func (m *MsgFulfillOrderAuthorized) Marshal() (dAtA []byte, err error) { size := m.Size() dAtA = make([]byte, size) n, err := m.MarshalToSizedBuffer(dAtA[:size]) @@ -395,130 +192,88 @@ func (m *MsgFulfillOrder) Marshal() (dAtA []byte, err error) { return dAtA[:n], nil } -func (m *MsgFulfillOrder) MarshalTo(dAtA []byte) (int, error) { +func (m *MsgFulfillOrderAuthorized) MarshalTo(dAtA []byte) (int, error) { size := m.Size() return m.MarshalToSizedBuffer(dAtA[:size]) } -func (m *MsgFulfillOrder) MarshalToSizedBuffer(dAtA []byte) (int, error) { +func (m *MsgFulfillOrderAuthorized) MarshalToSizedBuffer(dAtA []byte) (int, error) { i := len(dAtA) _ = i var l int _ = l + if m.SettlementValidated { + i-- + if m.SettlementValidated { + dAtA[i] = 1 + } else { + dAtA[i] = 0 + } + i-- + dAtA[i] = 0x40 + } + { + size, err := m.OperatorFeeShare.MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarintTx(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0x3a if len(m.ExpectedFee) > 0 { i -= len(m.ExpectedFee) copy(dAtA[i:], m.ExpectedFee) i = encodeVarintTx(dAtA, i, uint64(len(m.ExpectedFee))) i-- - dAtA[i] = 0x1a + dAtA[i] = 0x32 } - if len(m.OrderId) > 0 { - i -= len(m.OrderId) - copy(dAtA[i:], m.OrderId) - i = encodeVarintTx(dAtA, i, uint64(len(m.OrderId))) + if len(m.OperatorFeeAddress) > 0 { + i -= len(m.OperatorFeeAddress) + copy(dAtA[i:], m.OperatorFeeAddress) + i = encodeVarintTx(dAtA, i, uint64(len(m.OperatorFeeAddress))) i-- - dAtA[i] = 0x12 + dAtA[i] = 0x2a } - if len(m.FulfillerAddress) > 0 { - i -= len(m.FulfillerAddress) - copy(dAtA[i:], m.FulfillerAddress) - i = encodeVarintTx(dAtA, i, uint64(len(m.FulfillerAddress))) + if len(m.LpAddress) > 0 { + i -= len(m.LpAddress) + copy(dAtA[i:], m.LpAddress) + i = encodeVarintTx(dAtA, i, uint64(len(m.LpAddress))) i-- - dAtA[i] = 0xa - } - return len(dAtA) - i, nil -} - -func (m *MsgFulfillOrderResponse) 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 *MsgFulfillOrderResponse) MarshalTo(dAtA []byte) (int, error) { - size := m.Size() - return m.MarshalToSizedBuffer(dAtA[:size]) -} - -func (m *MsgFulfillOrderResponse) MarshalToSizedBuffer(dAtA []byte) (int, error) { - i := len(dAtA) - _ = i - var l int - _ = l - return len(dAtA) - i, nil -} - -func (m *MsgUpdateDemandOrder) Marshal() (dAtA []byte, err error) { - size := m.Size() - dAtA = make([]byte, size) - n, err := m.MarshalToSizedBuffer(dAtA[:size]) - if err != nil { - return nil, err + dAtA[i] = 0x22 + } + if len(m.Price) > 0 { + for iNdEx := len(m.Price) - 1; iNdEx >= 0; iNdEx-- { + { + size, err := m.Price[iNdEx].MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarintTx(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0x1a + } } - return dAtA[:n], nil -} - -func (m *MsgUpdateDemandOrder) MarshalTo(dAtA []byte) (int, error) { - size := m.Size() - return m.MarshalToSizedBuffer(dAtA[:size]) -} - -func (m *MsgUpdateDemandOrder) MarshalToSizedBuffer(dAtA []byte) (int, error) { - i := len(dAtA) - _ = i - var l int - _ = l - if len(m.NewFee) > 0 { - i -= len(m.NewFee) - copy(dAtA[i:], m.NewFee) - i = encodeVarintTx(dAtA, i, uint64(len(m.NewFee))) + if len(m.RollappId) > 0 { + i -= len(m.RollappId) + copy(dAtA[i:], m.RollappId) + i = encodeVarintTx(dAtA, i, uint64(len(m.RollappId))) i-- - dAtA[i] = 0x1a + dAtA[i] = 0x12 } if len(m.OrderId) > 0 { i -= len(m.OrderId) copy(dAtA[i:], m.OrderId) i = encodeVarintTx(dAtA, i, uint64(len(m.OrderId))) i-- - dAtA[i] = 0x12 - } - if len(m.OwnerAddress) > 0 { - i -= len(m.OwnerAddress) - copy(dAtA[i:], m.OwnerAddress) - i = encodeVarintTx(dAtA, i, uint64(len(m.OwnerAddress))) - i-- dAtA[i] = 0xa } return len(dAtA) - i, nil } -func (m *MsgUpdateDemandOrderResponse) 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 *MsgUpdateDemandOrderResponse) MarshalTo(dAtA []byte) (int, error) { - size := m.Size() - return m.MarshalToSizedBuffer(dAtA[:size]) -} - -func (m *MsgUpdateDemandOrderResponse) 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 @@ -530,73 +285,56 @@ func encodeVarintTx(dAtA []byte, offset int, v uint64) int { dAtA[offset] = uint8(v) return base } -func (m *MsgFulfillOrder) Size() (n int) { + +func (m *MsgFulfillOrderAuthorized) Size() (n int) { if m == nil { return 0 } var l int _ = l - l = len(m.FulfillerAddress) - if l > 0 { - n += 1 + l + sovTx(uint64(l)) - } l = len(m.OrderId) if l > 0 { n += 1 + l + sovTx(uint64(l)) } - l = len(m.ExpectedFee) + l = len(m.RollappId) if l > 0 { n += 1 + l + sovTx(uint64(l)) } - return n -} - -func (m *MsgFulfillOrderResponse) Size() (n int) { - if m == nil { - return 0 - } - var l int - _ = l - return n -} - -func (m *MsgUpdateDemandOrder) Size() (n int) { - if m == nil { - return 0 + if len(m.Price) > 0 { + for _, e := range m.Price { + l = e.Size() + n += 1 + l + sovTx(uint64(l)) + } } - var l int - _ = l - l = len(m.OwnerAddress) + l = len(m.LpAddress) if l > 0 { n += 1 + l + sovTx(uint64(l)) } - l = len(m.OrderId) + l = len(m.OperatorFeeAddress) if l > 0 { n += 1 + l + sovTx(uint64(l)) } - l = len(m.NewFee) + l = len(m.ExpectedFee) if l > 0 { n += 1 + l + sovTx(uint64(l)) } - return n -} - -func (m *MsgUpdateDemandOrderResponse) Size() (n int) { - if m == nil { - return 0 + l = m.OperatorFeeShare.Size() + n += 1 + l + sovTx(uint64(l)) + if m.SettlementValidated { + n += 2 } - 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 *MsgFulfillOrder) Unmarshal(dAtA []byte) error { + +func (m *MsgFulfillOrderAuthorized) Unmarshal(dAtA []byte) error { l := len(dAtA) iNdEx := 0 for iNdEx < l { @@ -619,15 +357,15 @@ func (m *MsgFulfillOrder) Unmarshal(dAtA []byte) error { fieldNum := int32(wire >> 3) wireType := int(wire & 0x7) if wireType == 4 { - return fmt.Errorf("proto: MsgFulfillOrder: wiretype end group for non-group") + return fmt.Errorf("proto: MsgFulfillOrderAuthorized: wiretype end group for non-group") } if fieldNum <= 0 { - return fmt.Errorf("proto: MsgFulfillOrder: illegal tag %d (wire type %d)", fieldNum, wire) + return fmt.Errorf("proto: MsgFulfillOrderAuthorized: illegal tag %d (wire type %d)", fieldNum, wire) } switch fieldNum { case 1: if wireType != 2 { - return fmt.Errorf("proto: wrong wireType = %d for field FulfillerAddress", wireType) + return fmt.Errorf("proto: wrong wireType = %d for field OrderId", wireType) } var stringLen uint64 for shift := uint(0); ; shift += 7 { @@ -655,11 +393,11 @@ func (m *MsgFulfillOrder) Unmarshal(dAtA []byte) error { if postIndex > l { return io.ErrUnexpectedEOF } - m.FulfillerAddress = string(dAtA[iNdEx:postIndex]) + m.OrderId = string(dAtA[iNdEx:postIndex]) iNdEx = postIndex case 2: if wireType != 2 { - return fmt.Errorf("proto: wrong wireType = %d for field OrderId", wireType) + return fmt.Errorf("proto: wrong wireType = %d for field RollappId", wireType) } var stringLen uint64 for shift := uint(0); ; shift += 7 { @@ -687,13 +425,13 @@ func (m *MsgFulfillOrder) Unmarshal(dAtA []byte) error { if postIndex > l { return io.ErrUnexpectedEOF } - m.OrderId = string(dAtA[iNdEx:postIndex]) + m.RollappId = string(dAtA[iNdEx:postIndex]) iNdEx = postIndex case 3: if wireType != 2 { - return fmt.Errorf("proto: wrong wireType = %d for field ExpectedFee", wireType) + return fmt.Errorf("proto: wrong wireType = %d for field Price", wireType) } - var stringLen uint64 + var msglen int for shift := uint(0); ; shift += 7 { if shift >= 64 { return ErrIntOverflowTx @@ -703,127 +441,29 @@ func (m *MsgFulfillOrder) 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.ExpectedFee = 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 *MsgFulfillOrderResponse) 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: MsgFulfillOrderResponse: wiretype end group for non-group") - } - if fieldNum <= 0 { - return fmt.Errorf("proto: MsgFulfillOrderResponse: illegal tag %d (wire type %d)", fieldNum, wire) - } - switch fieldNum { - default: - iNdEx = preIndex - skippy, err := skipTx(dAtA[iNdEx:]) - if err != nil { + m.Price = append(m.Price, types.Coin{}) + if err := m.Price[len(m.Price)-1].Unmarshal(dAtA[iNdEx:postIndex]); 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 *MsgUpdateDemandOrder) 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: MsgUpdateDemandOrder: wiretype end group for non-group") - } - if fieldNum <= 0 { - return fmt.Errorf("proto: MsgUpdateDemandOrder: illegal tag %d (wire type %d)", fieldNum, wire) - } - switch fieldNum { - case 1: + iNdEx = postIndex + case 4: if wireType != 2 { - return fmt.Errorf("proto: wrong wireType = %d for field OwnerAddress", wireType) + return fmt.Errorf("proto: wrong wireType = %d for field LpAddress", wireType) } var stringLen uint64 for shift := uint(0); ; shift += 7 { @@ -851,11 +491,11 @@ func (m *MsgUpdateDemandOrder) Unmarshal(dAtA []byte) error { if postIndex > l { return io.ErrUnexpectedEOF } - m.OwnerAddress = string(dAtA[iNdEx:postIndex]) + m.LpAddress = string(dAtA[iNdEx:postIndex]) iNdEx = postIndex - case 2: + case 5: if wireType != 2 { - return fmt.Errorf("proto: wrong wireType = %d for field OrderId", wireType) + return fmt.Errorf("proto: wrong wireType = %d for field OperatorFeeAddress", wireType) } var stringLen uint64 for shift := uint(0); ; shift += 7 { @@ -883,11 +523,11 @@ func (m *MsgUpdateDemandOrder) Unmarshal(dAtA []byte) error { if postIndex > l { return io.ErrUnexpectedEOF } - m.OrderId = string(dAtA[iNdEx:postIndex]) + m.OperatorFeeAddress = string(dAtA[iNdEx:postIndex]) iNdEx = postIndex - case 3: + case 6: if wireType != 2 { - return fmt.Errorf("proto: wrong wireType = %d for field NewFee", wireType) + return fmt.Errorf("proto: wrong wireType = %d for field ExpectedFee", wireType) } var stringLen uint64 for shift := uint(0); ; shift += 7 { @@ -915,58 +555,61 @@ func (m *MsgUpdateDemandOrder) Unmarshal(dAtA []byte) error { if postIndex > l { return io.ErrUnexpectedEOF } - m.NewFee = string(dAtA[iNdEx:postIndex]) + m.ExpectedFee = string(dAtA[iNdEx:postIndex]) iNdEx = postIndex - default: - iNdEx = preIndex - skippy, err := skipTx(dAtA[iNdEx:]) - if err != nil { - return err + case 7: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field OperatorFeeShare", wireType) } - if (skippy < 0) || (iNdEx+skippy) < 0 { + 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 } - if (iNdEx + skippy) > l { + postIndex := iNdEx + msglen + if postIndex < 0 { + return ErrInvalidLengthTx + } + if postIndex > l { return io.ErrUnexpectedEOF } - iNdEx += skippy - } - } - - if iNdEx > l { - return io.ErrUnexpectedEOF - } - return nil -} -func (m *MsgUpdateDemandOrderResponse) 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 err := m.OperatorFeeShare.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err } - if iNdEx >= l { - return io.ErrUnexpectedEOF + iNdEx = postIndex + case 8: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field SettlementValidated", wireType) } - b := dAtA[iNdEx] - iNdEx++ - wire |= uint64(b&0x7F) << shift - if b < 0x80 { - break + var v int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowTx + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + v |= int(b&0x7F) << shift + if b < 0x80 { + break + } } - } - fieldNum := int32(wire >> 3) - wireType := int(wire & 0x7) - if wireType == 4 { - return fmt.Errorf("proto: MsgUpdateDemandOrderResponse: wiretype end group for non-group") - } - if fieldNum <= 0 { - return fmt.Errorf("proto: MsgUpdateDemandOrderResponse: illegal tag %d (wire type %d)", fieldNum, wire) - } - switch fieldNum { + m.SettlementValidated = bool(v != 0) default: iNdEx = preIndex skippy, err := skipTx(dAtA[iNdEx:]) @@ -988,6 +631,7 @@ func (m *MsgUpdateDemandOrderResponse) Unmarshal(dAtA []byte) error { } return nil } + func skipTx(dAtA []byte) (n int, err error) { l := len(dAtA) iNdEx := 0 diff --git a/types/tx_da.pb.go b/types/tx_da.pb.go new file mode 100644 index 0000000..1a2e0c0 --- /dev/null +++ b/types/tx_da.pb.go @@ -0,0 +1,426 @@ +// Code generated by protoc-gen-gogo. DO NOT EDIT. +// source: dymensionxyz/dymension/delayedack/tx.proto + +package types + +import ( + context "context" + fmt "fmt" + io "io" + math "math" + + _ "github.com/cosmos/cosmos-sdk/types/msgservice" + proto "github.com/cosmos/gogoproto/proto" + grpc "google.golang.org/grpc" +) + +// 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 + +// MsgFinalizePacketByPacketKey finalizes a single packet by the packet key. +type MsgFinalizePacketByPacketKey struct { + // Sender is the signer of the message. + Sender string `protobuf:"bytes,1,opt,name=sender,proto3" json:"sender,omitempty"` + // PacketKey is a key of the packet. + PacketKey string `protobuf:"bytes,2,opt,name=packet_key,json=packetKey,proto3" json:"packet_key,omitempty"` +} + +func (m *MsgFinalizePacketByPacketKey) Reset() { *m = MsgFinalizePacketByPacketKey{} } +func (m *MsgFinalizePacketByPacketKey) String() string { return proto.CompactTextString(m) } +func (*MsgFinalizePacketByPacketKey) ProtoMessage() {} +func (*MsgFinalizePacketByPacketKey) Descriptor() ([]byte, []int) { + return fileDescriptor_604a74c1ca57f5ed, []int{2} +} +func (m *MsgFinalizePacketByPacketKey) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *MsgFinalizePacketByPacketKey) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_MsgFinalizePacketByPacketKey.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 *MsgFinalizePacketByPacketKey) XXX_Merge(src proto.Message) { + xxx_messageInfo_MsgFinalizePacketByPacketKey.Merge(m, src) +} +func (m *MsgFinalizePacketByPacketKey) XXX_Size() int { + return m.Size() +} +func (m *MsgFinalizePacketByPacketKey) XXX_DiscardUnknown() { + xxx_messageInfo_MsgFinalizePacketByPacketKey.DiscardUnknown(m) +} + +var xxx_messageInfo_MsgFinalizePacketByPacketKey proto.InternalMessageInfo + +func (m *MsgFinalizePacketByPacketKey) GetSender() string { + if m != nil { + return m.Sender + } + return "" +} + +func (m *MsgFinalizePacketByPacketKey) GetPacketKey() string { + if m != nil { + return m.PacketKey + } + return "" +} + +type MsgFinalizePacketByPacketKeyResponse struct { +} + +func (m *MsgFinalizePacketByPacketKeyResponse) Reset() { *m = MsgFinalizePacketByPacketKeyResponse{} } +func (m *MsgFinalizePacketByPacketKeyResponse) String() string { return proto.CompactTextString(m) } +func (*MsgFinalizePacketByPacketKeyResponse) ProtoMessage() {} +func (*MsgFinalizePacketByPacketKeyResponse) Descriptor() ([]byte, []int) { + return fileDescriptor_604a74c1ca57f5ed, []int{3} +} +func (m *MsgFinalizePacketByPacketKeyResponse) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *MsgFinalizePacketByPacketKeyResponse) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_MsgFinalizePacketByPacketKeyResponse.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 *MsgFinalizePacketByPacketKeyResponse) XXX_Merge(src proto.Message) { + xxx_messageInfo_MsgFinalizePacketByPacketKeyResponse.Merge(m, src) +} +func (m *MsgFinalizePacketByPacketKeyResponse) XXX_Size() int { + return m.Size() +} +func (m *MsgFinalizePacketByPacketKeyResponse) XXX_DiscardUnknown() { + xxx_messageInfo_MsgFinalizePacketByPacketKeyResponse.DiscardUnknown(m) +} + +var xxx_messageInfo_MsgFinalizePacketByPacketKeyResponse proto.InternalMessageInfo + +func init() { + proto.RegisterType((*MsgFinalizePacketByPacketKey)(nil), "dymensionxyz.dymension.delayedack.MsgFinalizePacketByPacketKey") + proto.RegisterType((*MsgFinalizePacketByPacketKeyResponse)(nil), "dymensionxyz.dymension.delayedack.MsgFinalizePacketByPacketKeyResponse") +} + +func init() { + proto.RegisterFile("dymensionxyz/dymension/delayedack/tx.proto", fileDescriptor_604a74c1ca57f5ed) +} + +var fileDescriptor_604a74c1ca57f5ed = []byte{ + // 584 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xac, 0x95, 0x4d, 0x6f, 0xd3, 0x4c, + 0x10, 0xc7, 0xbb, 0x7d, 0x89, 0x9e, 0x4c, 0xa5, 0x3c, 0xd4, 0x48, 0xc5, 0x35, 0xd4, 0x0a, 0xe1, + 0xa5, 0x51, 0x00, 0x5b, 0x4d, 0x91, 0x90, 0x10, 0x12, 0x28, 0x48, 0xa5, 0x08, 0x15, 0x15, 0x03, + 0x17, 0x2e, 0x91, 0x63, 0x0f, 0x89, 0x15, 0xc7, 0x6b, 0xbc, 0x6e, 0x14, 0x97, 0x0b, 0x42, 0x70, + 0xe7, 0x3b, 0x20, 0x24, 0x8e, 0x15, 0x47, 0x3e, 0x01, 0xc7, 0x1e, 0x39, 0xa2, 0xe4, 0xd0, 0xaf, + 0x81, 0xe2, 0x5d, 0x9b, 0x98, 0x28, 0x29, 0xa4, 0x9c, 0x36, 0xb3, 0x33, 0xf3, 0x9f, 0x5f, 0x66, + 0x76, 0xbd, 0x50, 0xb1, 0xa3, 0x0e, 0x7a, 0xcc, 0xa1, 0x5e, 0x2f, 0x3a, 0xd0, 0x53, 0x43, 0xb7, + 0xd1, 0x35, 0x23, 0xb4, 0x4d, 0xab, 0xad, 0x87, 0x3d, 0xcd, 0x0f, 0x68, 0x48, 0xa5, 0x8b, 0xa3, + 0xb1, 0x5a, 0x6a, 0x68, 0xbf, 0x62, 0x95, 0x73, 0x16, 0x65, 0x1d, 0xca, 0xf4, 0x0e, 0x6b, 0xea, + 0xdd, 0xcd, 0xe1, 0xc2, 0x73, 0x95, 0xea, 0x84, 0x3a, 0x16, 0xed, 0x74, 0xa8, 0xa7, 0x07, 0xd4, + 0x75, 0x4d, 0xdf, 0xaf, 0xfb, 0xa6, 0xd5, 0xc6, 0x90, 0xe7, 0x94, 0xbe, 0xcc, 0xc3, 0xca, 0x2e, + 0x6b, 0x6e, 0x3b, 0x9e, 0xe9, 0x3a, 0x07, 0xb8, 0x17, 0xfb, 0xa4, 0x55, 0xc8, 0x31, 0xf4, 0x6c, + 0x0c, 0x64, 0x52, 0x24, 0xe5, 0xbc, 0x21, 0x2c, 0x69, 0x1d, 0x20, 0x51, 0x71, 0x6c, 0x79, 0x3e, + 0xf6, 0xe5, 0xc5, 0xce, 0x43, 0x5b, 0xd2, 0xe0, 0x2c, 0x17, 0xaf, 0xfb, 0x01, 0xa5, 0x2f, 0xeb, + 0x2d, 0x74, 0x9a, 0xad, 0x50, 0x5e, 0x28, 0x92, 0xf2, 0xa2, 0xb1, 0xc2, 0x5d, 0x7b, 0x43, 0xcf, + 0x4e, 0xec, 0x90, 0x0c, 0x58, 0x16, 0xf1, 0x61, 0xe4, 0xa3, 0xbc, 0x58, 0x24, 0xe5, 0x42, 0x75, + 0x53, 0x9b, 0xd0, 0x02, 0xfe, 0x37, 0x34, 0x83, 0x97, 0xe3, 0xa4, 0xda, 0xb3, 0xc8, 0x47, 0x03, + 0xb8, 0xca, 0xf0, 0xb7, 0x74, 0x1d, 0x24, 0xa1, 0xc9, 0x02, 0xab, 0x6e, 0xb5, 0x4c, 0xcf, 0x43, + 0x57, 0x5e, 0x8a, 0x51, 0xcf, 0x70, 0xcf, 0xd3, 0xc0, 0xba, 0xcf, 0xf7, 0xa5, 0x0d, 0xf8, 0x3f, + 0x89, 0xc6, 0x57, 0xfb, 0xe8, 0x59, 0x28, 0xe7, 0x62, 0xda, 0x82, 0x08, 0x15, 0xbb, 0xb7, 0x97, + 0xdf, 0x1e, 0x1f, 0x56, 0x44, 0x1b, 0x4a, 0xe7, 0x61, 0x6d, 0xac, 0x67, 0x06, 0x32, 0x9f, 0x7a, + 0x0c, 0x4b, 0x0d, 0xb8, 0x30, 0xe6, 0xac, 0x45, 0x7c, 0x7d, 0x84, 0xd1, 0xb4, 0xde, 0x0a, 0x94, + 0x36, 0x46, 0x49, 0x6f, 0xfd, 0x24, 0x2d, 0x0b, 0x70, 0x15, 0x2e, 0x4f, 0xab, 0x91, 0xb2, 0xbc, + 0x86, 0xf5, 0xb1, 0x38, 0xf6, 0xdc, 0x0b, 0x1d, 0x57, 0x4c, 0x60, 0xc6, 0x41, 0xaf, 0x42, 0x2e, + 0x33, 0x5b, 0x61, 0x65, 0x21, 0x37, 0xe0, 0xca, 0xd4, 0xe2, 0x29, 0xe5, 0x7b, 0x02, 0x97, 0x46, + 0x22, 0x33, 0x03, 0x66, 0xb5, 0xc8, 0x40, 0x0b, 0x9d, 0x2e, 0x06, 0xb3, 0xc2, 0x2a, 0xf0, 0x5f, + 0x20, 0x24, 0x62, 0xdc, 0xbc, 0x91, 0xda, 0x59, 0xe0, 0x1b, 0x70, 0xed, 0x0f, 0x30, 0x12, 0xec, + 0xea, 0xc7, 0x25, 0x58, 0xd8, 0x65, 0x4d, 0xe9, 0x1d, 0x81, 0xc2, 0x6f, 0xf7, 0xe7, 0xa6, 0x76, + 0xe2, 0x35, 0xd6, 0xc6, 0x7a, 0xa3, 0xdc, 0x99, 0x25, 0x2b, 0xc1, 0x91, 0x3e, 0x11, 0x58, 0x9b, + 0x7c, 0xea, 0xee, 0xce, 0xa2, 0x3d, 0x22, 0xa0, 0x3c, 0x38, 0xa5, 0x40, 0xca, 0xf9, 0x99, 0x80, + 0x32, 0xe5, 0x44, 0xde, 0x9b, 0xa5, 0xce, 0xa8, 0x82, 0xb2, 0x73, 0x5a, 0x85, 0x14, 0xf5, 0x2b, + 0x81, 0xe2, 0x89, 0xa7, 0x72, 0xfb, 0xef, 0xca, 0x4d, 0xd2, 0x51, 0x1e, 0xff, 0x1b, 0x9d, 0x04, + 0x5e, 0x59, 0x7a, 0x73, 0x7c, 0x58, 0x21, 0xb5, 0x27, 0xdf, 0xfa, 0x2a, 0x39, 0xea, 0xab, 0xe4, + 0x47, 0x5f, 0x25, 0x1f, 0x06, 0xea, 0xdc, 0xd1, 0x40, 0x9d, 0xfb, 0x3e, 0x50, 0xe7, 0x5e, 0xdc, + 0x6a, 0x3a, 0x61, 0x6b, 0xbf, 0x31, 0xfc, 0xae, 0xea, 0x13, 0x5e, 0x8e, 0xee, 0x96, 0xde, 0xcb, + 0x3c, 0x53, 0x91, 0x8f, 0xac, 0x91, 0x8b, 0x9f, 0x8e, 0xad, 0x9f, 0x01, 0x00, 0x00, 0xff, 0xff, + 0xe1, 0xca, 0x2c, 0xf7, 0xd8, 0x06, 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 + +func (m *MsgFinalizePacketByPacketKey) 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 *MsgFinalizePacketByPacketKey) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *MsgFinalizePacketByPacketKey) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + if len(m.PacketKey) > 0 { + i -= len(m.PacketKey) + copy(dAtA[i:], m.PacketKey) + i = encodeVarintTx(dAtA, i, uint64(len(m.PacketKey))) + i-- + dAtA[i] = 0x12 + } + if len(m.Sender) > 0 { + i -= len(m.Sender) + copy(dAtA[i:], m.Sender) + i = encodeVarintTx(dAtA, i, uint64(len(m.Sender))) + i-- + dAtA[i] = 0xa + } + return len(dAtA) - i, nil +} + +func (m *MsgFinalizePacketByPacketKeyResponse) 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 *MsgFinalizePacketByPacketKeyResponse) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *MsgFinalizePacketByPacketKeyResponse) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + return len(dAtA) - i, nil +} + +func (m *MsgFinalizePacketByPacketKey) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + l = len(m.Sender) + if l > 0 { + n += 1 + l + sovTx(uint64(l)) + } + l = len(m.PacketKey) + if l > 0 { + n += 1 + l + sovTx(uint64(l)) + } + return n +} + +func (m *MsgFinalizePacketByPacketKeyResponse) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + return n +} + +func (m *MsgFinalizePacketByPacketKey) 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: MsgFinalizePacketByPacketKey: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: MsgFinalizePacketByPacketKey: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Sender", 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.Sender = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + case 2: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field PacketKey", 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.PacketKey = 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 *MsgFinalizePacketByPacketKeyResponse) 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: MsgFinalizePacketByPacketKeyResponse: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: MsgFinalizePacketByPacketKeyResponse: 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 +} diff --git a/whale.go b/whale.go deleted file mode 100644 index cabd969..0000000 --- a/whale.go +++ /dev/null @@ -1,231 +0,0 @@ -package main - -import ( - "context" - "fmt" - "strings" - "sync" - - sdk "github.com/cosmos/cosmos-sdk/types" - "github.com/dymensionxyz/cosmosclient/cosmosclient" - "go.uber.org/zap" -) - -type whale struct { - accountSvc *accountService - logger *zap.Logger - topUpCh <-chan topUpRequest - balanceThresholds map[string]sdk.Coin - admu sync.Mutex - alertedDenoms map[string]struct{} - slack *slacker - chainID, node string -} - -type topUpRequest struct { - coins sdk.Coins - toAddr string - res chan []string -} - -func newWhale( - accountSvc *accountService, - balanceThresholds map[string]sdk.Coin, - logger *zap.Logger, - slack *slacker, - chainID, node string, - topUpCh <-chan topUpRequest, -) *whale { - return &whale{ - accountSvc: accountSvc, - logger: logger.With(zap.String("module", "whale")), - topUpCh: topUpCh, - slack: slack, - balanceThresholds: balanceThresholds, - alertedDenoms: make(map[string]struct{}), - chainID: chainID, - node: node, - } -} - -func buildWhale( - ctx context.Context, - logger *zap.Logger, - config whaleConfig, - slack *slacker, - nodeAddress, gasFees, gasPrices string, - minimumGasBalance sdk.Coin, - topUpCh chan topUpRequest, -) (*whale, error) { - clientCfg := clientConfig{ - homeDir: config.KeyringDir, - keyringBackend: config.KeyringBackend, - nodeAddress: nodeAddress, - gasFees: gasFees, - gasPrices: gasPrices, - } - - balanceThresholdMap := make(map[string]sdk.Coin) - for denom, threshold := range config.AllowedBalanceThresholds { - coinStr := threshold + denom - coin, err := sdk.ParseCoinNormalized(coinStr) - if err != nil { - return nil, fmt.Errorf("failed to parse threshold coin: %w", err) - } - - balanceThresholdMap[denom] = coin - } - - cosmosClient, err := cosmosclient.New(getCosmosClientOptions(clientCfg)...) - if err != nil { - return nil, fmt.Errorf("failed to create cosmos client for whale: %w", err) - } - - accountSvc, err := newAccountService( - cosmosClient, - nil, // whale doesn't need a store for now - logger, - config.AccountName, - minimumGasBalance, - topUpCh, - ) - if err != nil { - return nil, fmt.Errorf("failed to create account service for whale: %w", err) - } - - return newWhale( - accountSvc, - balanceThresholdMap, - logger, - slack, - cosmosClient.Context().ChainID, - clientCfg.nodeAddress, - topUpCh, - ), nil -} - -func (w *whale) start(ctx context.Context) error { - balances, err := w.accountSvc.getAccountBalances(ctx) - if err != nil { - return fmt.Errorf("failed to get account balances: %w", err) - } - - w.logger.Info("starting service...", - zap.String("account", w.accountSvc.accountName), - zap.String("address", w.accountSvc.account.GetAddress().String()), - zap.String("balances", balances.String())) - - go w.topUpBalances(ctx) - return nil -} - -func (w *whale) topUpBalances(ctx context.Context) { - for { - select { - case <-ctx.Done(): - return - case req := <-w.topUpCh: - toppedUp := w.topUp(ctx, req.coins, req.toAddr) - req.res <- toppedUp - } - } -} - -func (w *whale) topUp(ctx context.Context, coins sdk.Coins, toAddr string) []string { - whaleBalances, err := w.accountSvc.getAccountBalances(ctx) - if err != nil { - w.logger.Error("failed to get account balances", zap.Error(err)) - return nil - } - - canTopUp := sdk.NewCoins() - for _, coin := range coins { - balance := whaleBalances.AmountOf(coin.Denom) - - // if balance thresholds are defined, - // we check if this coin is in the list - threshold, ok := w.balanceThresholds[strings.ToLower(coin.Denom)] - if !ok && len(w.balanceThresholds) > 0 { - continue - } - - diff := balance.Sub(coin.Amount) - if diff.IsPositive() { - // if the balance is greater than the required amount, remove the alert - go w.removeAlerted(coin.Denom) - - canTopUp = canTopUp.Add(coin) - whaleBalances = whaleBalances.Sub(coin) - newBalance := whaleBalances.AmountOf(coin.Denom) - - // if balance thresholds are defined and the new balance is below the threshold, - // we alert the user - if len(w.balanceThresholds) > 0 && newBalance.LTE(threshold.Amount) { - go w.alertLowBalance(ctx, coin, sdk.NewCoin(coin.Denom, newBalance)) - } - } else { - go w.alertLowBalance(ctx, coin, sdk.NewCoin(coin.Denom, balance)) - } - } - - if canTopUp.Empty() { - w.logger.Debug( - "no denoms to top up", - zap.String("to", toAddr), - zap.String("coins", coins.String())) - - return nil - } - - w.logger.Debug( - "topping up account", - zap.String("to", toAddr), - zap.String("coins", canTopUp.String()), - ) - - if err = w.accountSvc.sendCoins(canTopUp, toAddr); err != nil { - w.logger.Error("failed to top up account", zap.Error(err)) - return nil - } - - toppedUp := make([]string, len(canTopUp)) - for i, coin := range canTopUp { - toppedUp[i] = coin.Denom - } - - return toppedUp -} - -func (w *whale) alertLowBalance(ctx context.Context, coin, balance sdk.Coin) { - w.admu.Lock() - defer w.admu.Unlock() - - if _, ok := w.alertedDenoms[coin.Denom]; ok { - return - } - w.alertedDenoms[coin.Denom] = struct{}{} - - w.logger.Warn( - "account doesn't have enough balance", - zap.String("balance", balance.String()), - zap.String("required", coin.String())) - - _, err := w.slack.begOnSlack( - ctx, - w.accountSvc.account.GetAddress().String(), - coin, - balance, - w.chainID, - w.node, - ) - if err != nil { - w.logger.Error("failed to beg on slack", zap.Error(err)) - } -} - -func (w *whale) removeAlerted(denom string) { - w.admu.Lock() - defer w.admu.Unlock() - - delete(w.alertedDenoms, denom) -}