-
Notifications
You must be signed in to change notification settings - Fork 340
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
feat(eibc): fulfill demand orders with authorization from granter acc…
…ount (#1326)
- Loading branch information
Showing
17 changed files
with
2,488 additions
and
59 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,47 @@ | ||
syntax = "proto3"; | ||
package dymensionxyz.dymension.eibc; | ||
|
||
import "gogoproto/gogo.proto"; | ||
import "cosmos/msg/v1/msg.proto"; | ||
import "cosmos_proto/cosmos.proto"; | ||
import "cosmos/base/v1beta1/coin.proto"; | ||
|
||
option go_package = "github.com/dymensionxyz/dymension/v3/x/eibc/types"; | ||
|
||
// FulfillOrderAuthorization allows the grantee to fulfill eIBC demand orders from the granter's account. | ||
message FulfillOrderAuthorization { | ||
option (cosmos_proto.implements_interface) = "cosmos.authz.v1beta1.Authorization"; | ||
|
||
// rollapps is an optional list of rollapp IDs that the grantee can fulfill demand orders from | ||
repeated string rollapps = 1; | ||
|
||
// denoms is an optional list of denoms that the grantee can fulfill demand orders for | ||
repeated string denoms = 2; | ||
|
||
// min_lp_fee_percentage is the minimum fee earning percentage the LP is willing to get from a demand order | ||
cosmos.base.v1beta1.DecProto min_lp_fee_percentage = 3 [ | ||
(gogoproto.nullable) = false, | ||
(gogoproto.castrepeated) = "github.com/cosmos/cosmos-sdk/types.DecProto" | ||
]; | ||
|
||
// max_price is the optional maximum order price acceptable to the granter | ||
repeated cosmos.base.v1beta1.Coin max_price = 4 [ | ||
(gogoproto.nullable) = false, | ||
(gogoproto.castrepeated) = "github.com/cosmos/cosmos-sdk/types.Coins" | ||
]; | ||
|
||
// operator_fee_share is the share of the fee earnings willing to give to the operator | ||
cosmos.base.v1beta1.DecProto operator_fee_share = 5 [ | ||
(gogoproto.nullable) = false, | ||
(gogoproto.castrepeated) = "github.com/cosmos/cosmos-sdk/types.DecProto" | ||
]; | ||
|
||
// settlement_validated is the flag to only fulfill demand orders that have been settlement validated | ||
bool settlement_validated = 6; | ||
|
||
// spend_limit is the optional maximum amount of coins that can be spent by the grantee | ||
repeated cosmos.base.v1beta1.Coin spend_limit = 7 [ | ||
(gogoproto.nullable) = false, | ||
(gogoproto.castrepeated) = "github.com/cosmos/cosmos-sdk/types.Coins" | ||
]; | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,162 @@ | ||
package cli | ||
|
||
import ( | ||
"fmt" | ||
"strings" | ||
"time" | ||
|
||
"github.com/cosmos/cosmos-sdk/client" | ||
"github.com/cosmos/cosmos-sdk/client/flags" | ||
"github.com/cosmos/cosmos-sdk/client/tx" | ||
sdk "github.com/cosmos/cosmos-sdk/types" | ||
"github.com/cosmos/cosmos-sdk/version" | ||
"github.com/cosmos/cosmos-sdk/x/authz" | ||
"github.com/spf13/cobra" | ||
|
||
"github.com/dymensionxyz/dymension/v3/x/eibc/types" | ||
) | ||
|
||
const ( | ||
FlagSpendLimit = "spend-limit" | ||
FlagExpiration = "expiration" | ||
FlagRollapps = "rollapps" | ||
FlagDenoms = "denoms" | ||
FlagMinLPFeePercentage = "min-lp-fee-percentage" | ||
FlagMaxPrice = "max-price" | ||
FlagOperatorFeePart = "operator-fee-part" | ||
FlagSettlementValidated = "settlement-validated" | ||
) | ||
|
||
// NewCmdGrantAuthorization returns a CLI command handler for creating a MsgGrant transaction. | ||
func NewCmdGrantAuthorization() *cobra.Command { | ||
cmd := &cobra.Command{ | ||
Use: "grant <grantee> --from <granter>", | ||
Short: "Grant authorization to an address", | ||
Long: strings.TrimSpace( | ||
fmt.Sprintf(`create a new grant authorization to an address to execute a transaction on your behalf: | ||
Examples: | ||
$ %s tx %s grant dym1skjw.. --spend-limit=1000stake... --from=dym1skl..`, version.AppName, authz.ModuleName), | ||
), | ||
Args: cobra.ExactArgs(1), | ||
RunE: func(cmd *cobra.Command, args []string) error { | ||
clientCtx, err := client.GetClientTxContext(cmd) | ||
if err != nil { | ||
return fmt.Errorf("failed to get client context: %w", err) | ||
} | ||
|
||
grantee, err := sdk.AccAddressFromBech32(args[0]) | ||
if err != nil { | ||
return fmt.Errorf("failed to parse grantee address: %w", err) | ||
} | ||
|
||
rollapps, err := cmd.Flags().GetStringSlice(FlagRollapps) | ||
if err != nil { | ||
return fmt.Errorf("failed to get rollapps: %w", err) | ||
} | ||
denoms, err := cmd.Flags().GetStringSlice(FlagDenoms) | ||
if err != nil { | ||
return fmt.Errorf("failed to get denoms: %w", err) | ||
} | ||
|
||
minFeeStr, err := cmd.Flags().GetString(FlagMinLPFeePercentage) | ||
if err != nil { | ||
return fmt.Errorf("failed to get min fee: %w", err) | ||
} | ||
|
||
minFeePercDec, err := sdk.NewDecFromStr(minFeeStr) | ||
if err != nil { | ||
return fmt.Errorf("invalid min lp fee percentage: %w", err) | ||
} | ||
minLPFeePercent := sdk.DecProto{Dec: minFeePercDec} | ||
|
||
maxPriceStr, err := cmd.Flags().GetString(FlagMaxPrice) | ||
if err != nil { | ||
return fmt.Errorf("failed to get max price: %w", err) | ||
} | ||
|
||
maxPrice, err := sdk.ParseCoinsNormalized(maxPriceStr) | ||
if err != nil { | ||
return fmt.Errorf("failed to parse max price: %w", err) | ||
} | ||
|
||
fulfillerFeePartStr, err := cmd.Flags().GetString(FlagOperatorFeePart) | ||
if err != nil { | ||
return fmt.Errorf("failed to get fulfiller fee part: %w", err) | ||
} | ||
|
||
fulfillerFeePartDec, err := sdk.NewDecFromStr(fulfillerFeePartStr) | ||
if err != nil { | ||
return fmt.Errorf("failed to parse fulfiller fee part: %w", err) | ||
} | ||
fulfillerFeePart := sdk.DecProto{Dec: fulfillerFeePartDec} | ||
|
||
settlementValidated, err := cmd.Flags().GetBool(FlagSettlementValidated) | ||
if err != nil { | ||
return fmt.Errorf("failed to get settlement validated: %w", err) | ||
} | ||
|
||
limit, err := cmd.Flags().GetString(FlagSpendLimit) | ||
if err != nil { | ||
return fmt.Errorf("failed to get spend limit: %w", err) | ||
} | ||
|
||
var spendLimit sdk.Coins | ||
if limit != "" { | ||
spendLimit, err = sdk.ParseCoinsNormalized(limit) | ||
if err != nil { | ||
return fmt.Errorf("failed to parse spend limit: %w", err) | ||
} | ||
|
||
if !spendLimit.IsAllPositive() { | ||
return fmt.Errorf("spend-limit should be greater than zero") | ||
} | ||
} | ||
|
||
authorization := types.NewFulfillOrderAuthorization( | ||
rollapps, | ||
denoms, | ||
minLPFeePercent, | ||
maxPrice, | ||
fulfillerFeePart, | ||
settlementValidated, | ||
spendLimit, | ||
) | ||
|
||
expire, err := getExpireTime(cmd) | ||
if err != nil { | ||
return fmt.Errorf("failed to get expiration time: %w", err) | ||
} | ||
|
||
msg, err := authz.NewMsgGrant(clientCtx.GetFromAddress(), grantee, authorization, expire) | ||
if err != nil { | ||
return fmt.Errorf("failed to create MsgGrant: %w", err) | ||
} | ||
|
||
return tx.GenerateOrBroadcastTxCLI(clientCtx, cmd.Flags(), msg) | ||
}, | ||
} | ||
|
||
flags.AddTxFlagsToCmd(cmd) | ||
cmd.Flags().StringSlice(FlagRollapps, []string{}, "An array of Rollapp IDs allowed") | ||
cmd.Flags().StringSlice(FlagDenoms, []string{}, "An array of denoms allowed to use") | ||
cmd.Flags().String(FlagSpendLimit, "", "An array of Coins allowed to spend") | ||
cmd.Flags().Bool(FlagSettlementValidated, false, "Settlement validated flag") | ||
cmd.Flags().String(FlagMinLPFeePercentage, "", "Minimum fee") | ||
cmd.Flags().String(FlagMaxPrice, "", "Maximum price") | ||
cmd.Flags().String(FlagOperatorFeePart, "", "Fulfiller fee part") | ||
cmd.Flags().Int64(FlagExpiration, 0, "Expire time as Unix timestamp. Set zero (0) for no expiry. Default is 0.") | ||
return cmd | ||
} | ||
|
||
func getExpireTime(cmd *cobra.Command) (*time.Time, error) { | ||
exp, err := cmd.Flags().GetInt64(FlagExpiration) | ||
if err != nil { | ||
return nil, err | ||
} | ||
if exp == 0 { | ||
return nil, nil | ||
} | ||
e := time.Unix(exp, 0) | ||
return &e, nil | ||
} |
Oops, something went wrong.