Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add other confidential tx methods to seid #1933

Merged
merged 9 commits into from
Nov 19, 2024
Merged
Show file tree
Hide file tree
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
299 changes: 288 additions & 11 deletions x/confidentialtransfers/client/cli/tx.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
"crypto/ecdsa"
"encoding/hex"
"errors"
"strconv"

"github.com/cosmos/cosmos-sdk/client"
"github.com/cosmos/cosmos-sdk/client/flags"
Expand Down Expand Up @@ -33,6 +34,10 @@

txCmd.AddCommand(NewInitializeAccountTxCmd())
txCmd.AddCommand(NewCloseAccountTxCmd())
txCmd.AddCommand(NewTransferTxCmd())
txCmd.AddCommand(NewWithdrawTxCmd())
txCmd.AddCommand(NewDepositTxCmd())
txCmd.AddCommand(NewApplyPendingBalanceTxCmd())

return txCmd
}
Expand Down Expand Up @@ -138,17 +143,7 @@
return err
}

req := &types.GetCtAccountRequest{
Address: clientCtx.GetFromAddress().String(),
Denom: args[0],
}

ctAccount, err := queryClient.GetCtAccount(context.Background(), req)
if err != nil {
return err
}

account, err := ctAccount.GetAccount().FromProto()
account, err := getAccount(queryClient, clientCtx.GetFromAddress().String(), args[0])
if err != nil {
return err
}
Expand All @@ -173,3 +168,285 @@

return tx.GenerateOrBroadcastTxCLI(clientCtx, cmd.Flags(), msg)
}

// NewTransferTxCmd returns a CLI command handler for creating a MsgTransfer transaction.
func NewTransferTxCmd() *cobra.Command {
cmd := &cobra.Command{
Use: "transfer [denom] [to_address] [amount] [flags]",
Short: "Make a confidential transfer to another address",
Long: `Transfer command create a confidential transfer of the specified amount of the specified denomination to the specified address.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit: We could also add some example commands in long description. I think i rushed my piece in without it though

passed in .`,
Args: cobra.ExactArgs(3),
RunE: makeTransferCmd,
}

flags.AddTxFlagsToCmd(cmd)
cmd.Flags().StringSlice("auditors", []string{}, "List of auditors")

return cmd
}

func makeTransferCmd(cmd *cobra.Command, args []string) error {
clientCtx, err := client.GetClientTxContext(cmd)
if err != nil {
return err
}

queryClientCtx, err := client.GetClientQueryContext(cmd)
if err != nil {
return err
}

queryClient := types.NewQueryClient(queryClientCtx)

privKey, err := getPrivateKey(cmd)
if err != nil {
return err
}

fromAddress := clientCtx.GetFromAddress().String()
denom := args[0]
toAddress := args[1]
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

we may want to validate inputs. I think I skipped those checks in commands I implemented, and we may need to revisit here and other places

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Updated the commands with denom and address validation

amount, err := strconv.ParseUint(args[2], 10, 64)
if err != nil {
return err
}

senderAccount, err := getAccount(queryClient, fromAddress, denom)
if err != nil {
return err
}

recipientAccount, err := getAccount(queryClient, toAddress, denom)
if err != nil {
return err
}

auditorAddrs, err := cmd.Flags().GetStringSlice("auditors")
if err != nil {
return err
}

auditors := make([]types.AuditorInput, len(auditorAddrs))
for i, auditorAddr := range auditorAddrs {
auditorAccount, err := getAccount(queryClient, auditorAddr, denom)
if err != nil {
return err
}
auditors[i] = types.AuditorInput{

Check failure on line 236 in x/confidentialtransfers/client/cli/tx.go

View workflow job for this annotation

GitHub Actions / lint

composites: github.com/sei-protocol/sei-chain/x/confidentialtransfers/types.AuditorInput struct literal uses unkeyed fields (govet)
auditorAddr,
&auditorAccount.PublicKey,
}
}

transfer, err := types.NewTransfer(
privKey,
fromAddress,
toAddress,
args[0],
senderAccount.DecryptableAvailableBalance,
senderAccount.AvailableBalance,
amount,
&recipientAccount.PublicKey,
auditors)

if err != nil {
return err
}

msg := types.NewMsgTransferProto(transfer)

if err = msg.ValidateBasic(); err != nil {
return err
}

return tx.GenerateOrBroadcastTxCLI(clientCtx, cmd.Flags(), msg)
}

// NewWithdrawTxCmd returns a CLI command handler for creating a MsgWithdraw transaction.
func NewWithdrawTxCmd() *cobra.Command {
cmd := &cobra.Command{
Use: "withdraw [denom] [amount] [flags]",
Short: "Withdraw from confidential transfers account",
Long: `Withdraws the specified amount from the confidential transfers account for the specified denomination and address
passed in --from flag.`,
Args: cobra.ExactArgs(2),
RunE: makeWithdrawCmd,
}

flags.AddTxFlagsToCmd(cmd)

return cmd
}

func makeWithdrawCmd(cmd *cobra.Command, args []string) error {
clientCtx, err := client.GetClientTxContext(cmd)
if err != nil {
return err
}

queryClientCtx, err := client.GetClientQueryContext(cmd)
if err != nil {
return err
}

queryClient := types.NewQueryClient(queryClientCtx)

privKey, err := getPrivateKey(cmd)
if err != nil {
return err
}
address := clientCtx.GetFromAddress().String()
denom := args[0]
amount, err := strconv.ParseUint(args[1], 10, 64)
if err != nil {
return err
}
account, err := getAccount(queryClient, address, denom)
if err != nil {
return err
}

withdraw, err := types.NewWithdraw(
*privKey,
account.AvailableBalance,
denom,
address,
account.DecryptableAvailableBalance,
amount)

if err != nil {
return err
}

msg := types.NewMsgWithdrawProto(withdraw)

if err = msg.ValidateBasic(); err != nil {
return err
}

return tx.GenerateOrBroadcastTxCLI(clientCtx, cmd.Flags(), msg)
}

// NewDepositTxCmd returns a CLI command handler for creating a MsgDeposit transaction.
func NewDepositTxCmd() *cobra.Command {
cmd := &cobra.Command{
Use: "deposit [denom] [amount] [flags]",
Short: "Deposit funds into confidential transfers account",
Long: `Deposit the specified amount into the confidential transfers account for the specified denomination and address
passed in --from flag.`,
Args: cobra.ExactArgs(2),
RunE: makeDepositCmd,
}

flags.AddTxFlagsToCmd(cmd)

return cmd
}

func makeDepositCmd(cmd *cobra.Command, args []string) error {
clientCtx, err := client.GetClientTxContext(cmd)
if err != nil {
return err
}

address := clientCtx.GetFromAddress().String()
denom := args[0]
amount, err := strconv.ParseUint(args[1], 10, 64)
if err != nil {
return err
}

msg := &types.MsgDeposit{
FromAddress: address,
Denom: denom,
Amount: amount,
}

if err = msg.ValidateBasic(); err != nil {
return err
}

return tx.GenerateOrBroadcastTxCLI(clientCtx, cmd.Flags(), msg)
}

// NewApplyPendingBalanceCmd returns a CLI command handler for creating a MsgDeposit transaction.
func NewApplyPendingBalanceTxCmd() *cobra.Command {
cmd := &cobra.Command{
Use: "apply-pending-balance [denom] [flags]",
Short: "Applies the pending balances to the available balances",
Long: `Makes the pending balances of the confidential token account for the specified denomination and address
passed in --from flag spendable by moving them to the available balance.`,
Args: cobra.ExactArgs(1),
RunE: makeApplyPendingBalanceCmd,
}

flags.AddTxFlagsToCmd(cmd)

return cmd
}

func makeApplyPendingBalanceCmd(cmd *cobra.Command, args []string) error {
clientCtx, err := client.GetClientTxContext(cmd)
if err != nil {
return err
}

queryClientCtx, err := client.GetClientQueryContext(cmd)
if err != nil {
return err
}

queryClient := types.NewQueryClient(queryClientCtx)
privKey, err := getPrivateKey(cmd)
if err != nil {
return err
}

address := clientCtx.GetFromAddress().String()
denom := args[0]
if err != nil {
return err
}

account, err := getAccount(queryClient, clientCtx.GetFromAddress().String(), args[0])
if err != nil {
return err
}

msg, err := types.NewMsgApplyPendingBalance(
*privKey,
address,
denom,
account.DecryptableAvailableBalance,
account.PendingBalanceLo,
account.PendingBalanceHi)

if err != nil {
return err
}

if err = msg.ValidateBasic(); err != nil {
return err
}

return tx.GenerateOrBroadcastTxCLI(clientCtx, cmd.Flags(), msg)
}

// Uses the query client to get the account data for the given address and denomination.
func getAccount(queryClient types.QueryClient, address, denom string) (*types.Account, error) {
ctAccount, err := queryClient.GetCtAccount(context.Background(), &types.GetCtAccountRequest{
Address: address,
Denom: denom,
})
if err != nil {
return nil, err
}

account, err := ctAccount.GetAccount().FromProto()
if err != nil {
return nil, err
}

return account, nil
}
4 changes: 4 additions & 0 deletions x/confidentialtransfers/keeper/msg_server.go
Original file line number Diff line number Diff line change
Expand Up @@ -358,6 +358,10 @@ func (m msgServer) Transfer(goCtx context.Context, req *types.MsgTransfer) (*typ
return nil, sdkerrors.Wrap(sdkerrors.ErrInvalidRequest, "invalid msg")
}

if instruction.FromAddress == instruction.ToAddress {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I guess I agree, but In bank module though, I think it's a valid case

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Disabled this because the way we write this is
senderState = getAccount(sender)
recipientState = getAccount(recipient)

senderState.Balance += Amount
recipientState.Balance -= Amount

keeper.Store(senderState, sender)
keeper.Store(recipientState, recipient).

If sender and recipient are same address, the updated 'recipientState' overrides the updated 'senderState' for the key 'sender' and funds are not deducted. If we want to enable this we need to write a special case.

return nil, sdkerrors.Wrap(sdkerrors.ErrInvalidRequest, "sender and recipient addresses must be different")
}

// Check that sender and recipient accounts exist.
senderAccount, exists := m.Keeper.GetAccount(ctx, req.FromAddress, req.Denom)
if !exists {
Expand Down
Loading
Loading