Skip to content

Commit

Permalink
CT types - Apply balance close account (#1919)
Browse files Browse the repository at this point in the history
* pending balance type

* convert apply pending balance to a message type

* close account type
  • Loading branch information
dssei authored Nov 4, 2024
1 parent 6ec024a commit f68d3be
Show file tree
Hide file tree
Showing 7 changed files with 1,892 additions and 159 deletions.
24 changes: 24 additions & 0 deletions proto/confidentialtransfers/tx.proto
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,12 @@ option go_package = "github.com/sei-protocol/sei-chain/x/confidentialtransfers/t
service Msg {
// Transfer defines a method for sending coins from one account to another account.
rpc Transfer(MsgTransfer) returns (MsgTransferResponse);

// ApplyPendingBalance defines a method for applying pending balance to an account.
rpc ApplyPendingBalance(MsgApplyPendingBalance) returns (MsgApplyPendingBalanceResponse);

// CloseAccount defines a method for closing an account.
rpc CloseAccount(MsgCloseAccount) returns (MsgCloseAccountResponse);
}

// MsgTransfer represents a message to send coins from one account to another.
Expand Down Expand Up @@ -44,3 +50,21 @@ message Auditor {
CiphertextCiphertextEqualityProof transfer_amount_lo_equality_proof = 6 [(gogoproto.moretags) = "yaml:\"transfer_amount_lo_equality_proof\""];
CiphertextCiphertextEqualityProof transfer_amount_hi_equality_proof = 7 [(gogoproto.moretags) = "yaml:\"transfer_amount_hi_equality_proof\""];
}

// Message to be used in apply pending balance instruction/transaction
message MsgApplyPendingBalance {
string address = 1;
string denom = 2;
string new_decryptable_available_balance = 3;
}

message MsgApplyPendingBalanceResponse {}

// Message to be used in close account instruction/transaction
message MsgCloseAccount {
string address = 1;
string denom = 2;
CloseAccountProof proof = 3;
}

message MsgCloseAccountResponse {}
12 changes: 12 additions & 0 deletions proto/confidentialtransfers/zk.proto
Original file line number Diff line number Diff line change
Expand Up @@ -54,3 +54,15 @@ message CiphertextCiphertextEqualityProof {
bytes zx = 6;
bytes zr = 7;
}

message ZeroBalanceProof {
bytes y_p = 1;
bytes y_d = 2;
bytes z = 3;
}

message CloseAccountProof {
ZeroBalanceProof zero_available_balance_proof = 1;
ZeroBalanceProof zero_pending_balance_lo_proof = 2;
ZeroBalanceProof zero_pending_balance_hi_proof = 3;
}
74 changes: 73 additions & 1 deletion x/confidentialtransfers/types/msgs.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,9 @@ import (

// confidential transfers message types
const (
TypeMsgTransfer = "transfer"
TypeMsgTransfer = "transfer"
TypeMsgApplyPendingBalance = "apply_pending_balance"
TypeMsgCloseAccount = "close_account"
)

var _ sdk.Msg = &MsgTransfer{}
Expand Down Expand Up @@ -134,3 +136,73 @@ func (m *MsgTransfer) FromProto() (*Transfer, error) {
Auditors: auditors,
}, nil
}

var _ sdk.Msg = &MsgApplyPendingBalance{}

// Route Implements Msg.
func (m *MsgApplyPendingBalance) Route() string { return RouterKey }

// Type Implements Msg.
func (m *MsgApplyPendingBalance) Type() string { return TypeMsgApplyPendingBalance }

func (m *MsgApplyPendingBalance) ValidateBasic() error {
if len(m.Address) == 0 {
return sdkerrors.Wrap(sdkerrors.ErrInvalidRequest, "Address is required")
}

if len(m.Denom) == 0 {
return sdkerrors.Wrap(sdkerrors.ErrInvalidRequest, "Denom is required")
}

if len(m.NewDecryptableAvailableBalance) == 0 {
return sdkerrors.Wrap(sdkerrors.ErrInvalidRequest, "NewDecryptableAvailableBalance is required")
}
return nil
}

func (m *MsgApplyPendingBalance) GetSignBytes() []byte {
return sdk.MustSortJSON(ModuleCdc.MustMarshalJSON(m))
}

func (m *MsgApplyPendingBalance) GetSigners() []sdk.AccAddress {
sender, _ := sdk.AccAddressFromBech32(m.Address)
return []sdk.AccAddress{sender}
}

var _ sdk.Msg = &MsgCloseAccount{}

// Route Implements Msg.
func (m *MsgCloseAccount) Route() string { return RouterKey }

// Type Implements Msg.
func (m *MsgCloseAccount) Type() string { return TypeMsgCloseAccount }

func (m *MsgCloseAccount) ValidateBasic() error {
if len(m.Address) == 0 {
return sdkerrors.Wrap(sdkerrors.ErrInvalidRequest, "Address is required")
}

if len(m.Denom) == 0 {
return sdkerrors.Wrap(sdkerrors.ErrInvalidRequest, "Denom is required")
}

if m.Proof == nil {
return sdkerrors.Wrap(sdkerrors.ErrInvalidRequest, "Proofs is required")
}

err := m.Proof.Validate()
if err != nil {
return err
}

return nil
}

func (m *MsgCloseAccount) GetSignBytes() []byte {
return sdk.MustSortJSON(ModuleCdc.MustMarshalJSON(m))
}

func (m *MsgCloseAccount) GetSigners() []sdk.AccAddress {
sender, _ := sdk.AccAddressFromBech32(m.Address)
return []sdk.AccAddress{sender}
}
71 changes: 71 additions & 0 deletions x/confidentialtransfers/types/msgs_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -397,3 +397,74 @@ func TestMsgTransfer_ValidateBasic(t *testing.T) {
})
}
}

func TestMsgCloseAccount_FromProto(t *testing.T) {
address := sdk.AccAddress("address1")
testDenom := "factory/sei1ft98au55a24vnu9tvd92cz09pzcfqkm5vlx99w/TEST"
privateKey, _ := elgamal.GenerateKey()
eg := elgamal.NewTwistedElgamal()
keypair, _ := eg.KeyGen(*privateKey, testDenom)
availableBalanceCiphertext, _, _ := eg.Encrypt(keypair.PublicKey, 0)
pendingBalanceLoCiphertext, _, _ := eg.Encrypt(keypair.PublicKey, 0)
pendingBalanceHiCiphertext, _, _ := eg.Encrypt(keypair.PublicKey, 0)

availableBalanceProof, err := zkproofs.NewZeroBalanceProof(keypair, availableBalanceCiphertext)
require.NoError(t, err)
pendingBalanceProofLo, err := zkproofs.NewZeroBalanceProof(keypair, pendingBalanceLoCiphertext)
require.NoError(t, err)
pendingBalanceProofHi, err := zkproofs.NewZeroBalanceProof(keypair, pendingBalanceHiCiphertext)
require.NoError(t, err)

closeAccountProofs := &CloseAccountProofs{
ZeroAvailableBalanceProof: availableBalanceProof,
ZeroPendingBalanceLoProof: pendingBalanceProofLo,
ZeroPendingBalanceHiProof: pendingBalanceProofHi,
}

closeAccountProof := CloseAccountProof{}
proof := closeAccountProof.ToProto(closeAccountProofs)

m := &MsgCloseAccount{
Address: address.String(),
Denom: testDenom,
Proof: proof,
}

marshalled, err := m.Marshal()
require.NoError(t, err)

// Reset the message
result := &MsgCloseAccount{}
err = result.Unmarshal(marshalled)
require.NoError(t, err)

assert.Equal(t, m.Address, result.Address)
assert.Equal(t, m.Denom, result.Denom)
resultProof, err := result.Proof.FromProto()
require.NoError(t, err)

assert.NoError(t, result.ValidateBasic())

assert.True(t, closeAccountProofs.ZeroAvailableBalanceProof.Yd.Equal(resultProof.ZeroAvailableBalanceProof.Yd))
assert.True(t, closeAccountProofs.ZeroAvailableBalanceProof.Yp.Equal(resultProof.ZeroAvailableBalanceProof.Yp))
assert.Equal(t, closeAccountProofs.ZeroAvailableBalanceProof.Z, resultProof.ZeroAvailableBalanceProof.Z)

assert.True(t, closeAccountProofs.ZeroPendingBalanceLoProof.Yd.Equal(resultProof.ZeroPendingBalanceLoProof.Yd))
assert.True(t, closeAccountProofs.ZeroPendingBalanceLoProof.Yp.Equal(resultProof.ZeroPendingBalanceLoProof.Yp))
assert.Equal(t, closeAccountProofs.ZeroPendingBalanceLoProof.Z, resultProof.ZeroPendingBalanceLoProof.Z)

assert.True(t, closeAccountProofs.ZeroPendingBalanceHiProof.Yd.Equal(resultProof.ZeroPendingBalanceHiProof.Yd))
assert.True(t, closeAccountProofs.ZeroPendingBalanceHiProof.Yp.Equal(resultProof.ZeroPendingBalanceHiProof.Yp))
assert.Equal(t, closeAccountProofs.ZeroPendingBalanceHiProof.Z, resultProof.ZeroPendingBalanceHiProof.Z)

// Make sure the proofs are valid
assert.True(t, zkproofs.VerifyZeroBalance(
resultProof.ZeroAvailableBalanceProof, &keypair.PublicKey, availableBalanceCiphertext))

assert.True(t, zkproofs.VerifyZeroBalance(
resultProof.ZeroPendingBalanceLoProof, &keypair.PublicKey, pendingBalanceLoCiphertext))

assert.True(t, zkproofs.VerifyZeroBalance(
resultProof.ZeroPendingBalanceHiProof, &keypair.PublicKey, pendingBalanceHiCiphertext))

}
Loading

0 comments on commit f68d3be

Please sign in to comment.