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

feat(accounts): make x/accounts more depinject friendly #21928

Open
wants to merge 9 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all 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
2 changes: 2 additions & 0 deletions simapp/app.go
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ import (
"cosmossdk.io/x/accounts/accountstd"
baseaccount "cosmossdk.io/x/accounts/defaults/base"
lockup "cosmossdk.io/x/accounts/defaults/lockup"
"cosmossdk.io/x/accounts/defaults/multisig"
"cosmossdk.io/x/accounts/testing/account_abstraction"
"cosmossdk.io/x/accounts/testing/counter"
"cosmossdk.io/x/authz"
Expand Down Expand Up @@ -315,6 +316,7 @@ func NewSimApp(
accountstd.AddAccount(lockup.PERIODIC_LOCKING_ACCOUNT, lockup.NewPeriodicLockingAccount),
accountstd.AddAccount(lockup.DELAYED_LOCKING_ACCOUNT, lockup.NewDelayedLockingAccount),
accountstd.AddAccount(lockup.PERMANENT_LOCKING_ACCOUNT, lockup.NewPermanentLockingAccount),
accountstd.AddAccount("multisig", multisig.NewAccount),
// PRODUCTION: add
baseaccount.NewAccount("base", txConfig.SignModeHandler(), baseaccount.WithSecp256K1PubKey()),
)
Expand Down
24 changes: 24 additions & 0 deletions simapp/app_di.go
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,9 @@ import (
"cosmossdk.io/depinject"
"cosmossdk.io/log"
"cosmossdk.io/x/accounts"
basedepinject "cosmossdk.io/x/accounts/defaults/base/depinject"
lockupdepinject "cosmossdk.io/x/accounts/defaults/lockup/depinject"
multisigdepinject "cosmossdk.io/x/accounts/defaults/multisig/depinject"
bankkeeper "cosmossdk.io/x/bank/keeper"
circuitkeeper "cosmossdk.io/x/circuit/keeper"
consensuskeeper "cosmossdk.io/x/consensus/keeper"
Expand Down Expand Up @@ -155,6 +158,27 @@ func NewSimApp(
// For providing a custom inflation function for x/mint add here your
// custom function that implements the minttypes.MintFn interface.
),
depinject.Provide(
// inject desired account types:
multisigdepinject.ProvideAccount,
basedepinject.ProvideAccount,
lockupdepinject.ProvideAllLockupAccounts,

// provide base account options
basedepinject.ProvideSecp256K1PubKey,
// if you want to provide a custom public key you
// can do it from here.
// Example:
// basedepinject.ProvideCustomPubkey[Ed25519PublicKey]()
//
// You can also provide a custom public key with a custom validation function:
//
// basedepinject.ProvideCustomPubKeyAndValidationFunc(func(pub Ed25519PublicKey) error {
// if len(pub.Key) != 64 {
// return fmt.Errorf("invalid pub key size")
// }
// })
),
)
)

Expand Down
2 changes: 1 addition & 1 deletion simapp/go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,7 @@ require (

require (
cosmossdk.io/x/accounts/defaults/base v0.0.0-00010101000000-000000000000
cosmossdk.io/x/accounts/defaults/multisig v0.0.0-00010101000000-000000000000
google.golang.org/grpc v1.67.0
)

Expand All @@ -62,7 +63,6 @@ require (
cloud.google.com/go/storage v1.43.0 // indirect
cosmossdk.io/errors v1.0.1 // indirect
cosmossdk.io/schema v0.3.0 // indirect
cosmossdk.io/x/accounts/defaults/multisig v0.0.0-00010101000000-000000000000 // indirect
filippo.io/edwards25519 v1.1.0 // indirect
github.com/99designs/go-keychain v0.0.0-20191008050251-8e49817e8af4 // indirect
github.com/99designs/keyring v1.2.2 // indirect
Expand Down
22 changes: 22 additions & 0 deletions simapp/v2/app_di.go
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,9 @@ import (
"cosmossdk.io/log"
"cosmossdk.io/runtime/v2"
"cosmossdk.io/store/v2/root"
basedepinject "cosmossdk.io/x/accounts/defaults/base/depinject"
lockupdepinject "cosmossdk.io/x/accounts/defaults/lockup/depinject"
multisigdepinject "cosmossdk.io/x/accounts/defaults/multisig/depinject"
upgradekeeper "cosmossdk.io/x/upgrade/keeper"

"github.com/cosmos/cosmos-sdk/client"
Expand Down Expand Up @@ -119,6 +122,25 @@ func NewSimApp[T transaction.Tx](
codec.ProvideAddressCodec,
codec.ProvideProtoCodec,
codec.ProvideLegacyAmino,
// inject desired account types:
multisigdepinject.ProvideAccount,
basedepinject.ProvideAccount,
lockupdepinject.ProvideAllLockupAccounts,

// provide base account options
basedepinject.ProvideSecp256K1PubKey,
// if you want to provide a custom public key you
// can do it from here.
// Example:
// basedepinject.ProvideCustomPubkey[Ed25519PublicKey]()
//
// You can also provide a custom public key with a custom validation function:
//
// basedepinject.ProvideCustomPubKeyAndValidationFunc(func(pub Ed25519PublicKey) error {
// if len(pub.Key) != 64 {
// return fmt.Errorf("invalid pub key size")
// }
// })
),
depinject.Invoke(
std.RegisterInterfaces,
Expand Down
9 changes: 6 additions & 3 deletions simapp/v2/go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,12 @@ require (
google.golang.org/protobuf v1.34.2
)

require (
cosmossdk.io/x/accounts/defaults/base v0.0.0-00010101000000-000000000000
cosmossdk.io/x/accounts/defaults/lockup v0.0.0-00010101000000-000000000000
cosmossdk.io/x/accounts/defaults/multisig v0.0.0-00010101000000-000000000000
)

require (
buf.build/gen/go/cometbft/cometbft/protocolbuffers/go v1.34.2-20240701160653-fedbb9acfd2f.2 // indirect
buf.build/gen/go/cosmos/gogo-proto/protocolbuffers/go v1.34.2-20240130113600-88ef6483f90f.2 // indirect
Expand All @@ -59,9 +65,6 @@ require (
cosmossdk.io/server/v2/appmanager v0.0.0-20240802110823-cffeedff643d // indirect
cosmossdk.io/server/v2/stf v0.0.0-20240708142107-25e99c54bac1 // indirect
cosmossdk.io/store v1.1.1 // indirect
cosmossdk.io/x/accounts/defaults/base v0.0.0-00010101000000-000000000000 // indirect
cosmossdk.io/x/accounts/defaults/lockup v0.0.0-20240417181816-5e7aae0db1f5 // indirect
cosmossdk.io/x/accounts/defaults/multisig v0.0.0-00010101000000-000000000000 // indirect
cosmossdk.io/x/tx v0.13.5 // indirect
filippo.io/edwards25519 v1.1.0 // indirect
github.com/99designs/go-keychain v0.0.0-20191008050251-8e49817e8af4 // indirect
Expand Down
3 changes: 1 addition & 2 deletions tests/e2e/accounts/multisig/test_suite.go
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,6 @@ import (
"cosmossdk.io/core/transaction"
"cosmossdk.io/math"
"cosmossdk.io/simapp"
multisigaccount "cosmossdk.io/x/accounts/defaults/multisig"
v1 "cosmossdk.io/x/accounts/defaults/multisig/v1"
"cosmossdk.io/x/bank/testutil"

Expand Down Expand Up @@ -76,7 +75,7 @@ func (s *E2ETestSuite) initAccount(ctx context.Context, sender []byte, membersPo
members = append(members, &v1.Member{Address: addrStr, Weight: power})
}

_, accountAddr, err := s.app.AccountsKeeper.Init(ctx, multisigaccount.MULTISIG_ACCOUNT, sender,
_, accountAddr, err := s.app.AccountsKeeper.Init(ctx, "multisig", sender,
&v1.MsgInit{
Members: members,
Config: &v1.Config{
Expand Down
93 changes: 91 additions & 2 deletions x/accounts/README.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,95 @@
# x/accounts
# x/accounts Module

The x/accounts module provides module and facilities for writing smart cosmos-sdk accounts.
The x/accounts module enhances the Cosmos SDK by providing tools and infrastructure for creating advanced smart accounts.

# The Authentication Interface

x/accounts introduces the `Authentication` interface, allowing for flexible transaction (TX) authentication beyond traditional public key cryptography.

Chain developers can implement tailored authentication methods for their accounts. Any account that implements the `Authentication` interface can be authenticated within a transaction.

To implement the `Authentication` interface in x/accounts, an account must expose an execution handler capable of processing a specific message type.

The key message type for authentication is `MsgAuthenticate`, which is defined in the module's protocol buffer files:

[interfaces/account_abstraction/v1/interface.proto](./proto/cosmos/accounts/interfaces/account_abstraction/v1/interface.proto)

Copy link
Member

Choose a reason for hiding this comment

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

nit (can be done during the doc week). We should use the go reference markdown code

## Authentication Mechanism

### AnteHandler in the SDK

The Cosmos SDK utilizes an `AnteHandler` to verify transaction (TX) integrity. Its primary function is to ensure that the messages within a transaction are correctly signed by the purported sender.

Copy link
Member

Choose a reason for hiding this comment

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

nit (can be done during the doc week), let's mention tx validator (antehandler) to be future proof already

### Authentication Flow for x/accounts Module

When the `AnteHandler` identifies that a message sender (and transaction signer) belongs to the x/accounts module, it delegates the authentication process to that module.

#### Authentication Interface Requirement

For successful authentication, the account must implement the `Authentication` interface. If an account fails to implement this interface, it's considered non-externally owned, resulting in transaction rejection.

##### Sequence Diagram

```mermaid
graph TD
A[Tx Is Received] --> B[Execute Signature Verification Ante Handler]
B --> D{Is signer an x/accounts account?}
D -->|No| E[Continue with signature verification ante handler]
D -->|Yes| F{Does account handle MsgAuthenticate?}
F -->|No| G[Fail TX: Non-externally owned account]
F -->|Yes| H[Invoke signer account MsgAuthenticate]
E --> I[End]
G --> I
H --> I
```


## Implementing the Authentication Interface

To implement the Authentication interface, an account must handle the execution of `MsgAuthenticate`. Here's an example of how to do this:

```go
package base

import (
"context"
"errors"
aa_interface_v1 "github.com/cosmos/cosmos-sdk/x/accounts/interfaces/account_abstraction/v1"
"github.com/cosmos/cosmos-sdk/x/accounts/std"
)

// Account represents a base account structure
type Account struct {
// Account fields...
}

// Authenticate implements the authentication flow for an abstracted base account.
func (a Account) Authenticate(ctx context.Context, msg *aa_interface_v1.MsgAuthenticate) (*aa_interface_v1.MsgAuthenticateResponse, error) {
if !accountstd.SenderIsAccountsModule(ctx) {
return nil, errors.New("unauthorized: only accounts module is allowed to call this")
}
// Implement your authentication logic here
// ...
return &aa_interface_v1.MsgAuthenticateResponse{}, nil
}

// RegisterExecuteHandlers registers the execution handlers for the account.
func (a Account) RegisterExecuteHandlers(builder *accountstd.ExecuteBuilder) {
accountstd.RegisterExecuteHandler(builder, a.SwapPubKey) // Other handlers
accountstd.RegisterExecuteHandler(builder, a.Authenticate) // Implements the Authentication interface
}
```

### Key Implementation Points

1. **Sender Verification**: Always verify that the sender is the x/accounts module. This prevents unauthorized accounts from triggering authentication.
2. **Authentication Safety**: Ensure your authentication mechanism is secure:
- Prevent replay attacks by making it impossible to reuse the same action with the same signature.


#### Implementation example

Please find an example [here](./defaults/base/account.go).

# Supporting Custom Accounts in the x/auth gRPC Server

Expand Down
10 changes: 10 additions & 0 deletions x/accounts/accountstd/exports.go
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,16 @@ type InitBuilder = implementation.InitBuilder
// AccountCreatorFunc is the exported type of AccountCreatorFunc.
type AccountCreatorFunc = implementation.AccountCreatorFunc

func DIAccount[A Interface](name string, constructor func(deps Dependencies) (A, error)) DepinjectAccount {
return DepinjectAccount{MakeAccount: AddAccount(name, constructor)}
}

type DepinjectAccount struct {
MakeAccount AccountCreatorFunc
}

func (DepinjectAccount) IsManyPerContainerType() {}

// Dependencies is the exported type of Dependencies.
type Dependencies = implementation.Dependencies

Expand Down
2 changes: 2 additions & 0 deletions x/accounts/defaults/base/account.go
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,8 @@ var (

type Option func(a *Account)

func (Option) IsManyPerContainerType() {}

func NewAccount(name string, handlerMap *signing.HandlerMap, options ...Option) accountstd.AccountCreatorFunc {
return func(deps accountstd.Dependencies) (string, accountstd.Interface, error) {
acc := Account{
Expand Down
31 changes: 31 additions & 0 deletions x/accounts/defaults/base/depinject/depinject.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
package basedepinject

import (
"cosmossdk.io/depinject"
"cosmossdk.io/x/accounts/accountstd"
"cosmossdk.io/x/accounts/defaults/base"
"cosmossdk.io/x/tx/signing"
)

type Inputs struct {
depinject.In

SignHandlersMap *signing.HandlerMap
Options []base.Option
}

func ProvideAccount(in Inputs) accountstd.DepinjectAccount {
return accountstd.DepinjectAccount{MakeAccount: base.NewAccount("base", in.SignHandlersMap, in.Options...)}
}

func ProvideSecp256K1PubKey() base.Option {
return base.WithSecp256K1PubKey()
}

func ProvideCustomPubkey[T any, PT base.PubKeyG[T]]() base.Option {
return base.WithPubKey[T, PT]()
}

func ProvideCustomPubKeyAndValidationFunc[T any, PT base.PubKeyG[T]](validateFn func(PT) error) base.Option {
return base.WithPubKeyWithValidationFunc(validateFn)
}
10 changes: 1 addition & 9 deletions x/accounts/defaults/base/go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ require (
cosmossdk.io/api v0.7.6
cosmossdk.io/collections v0.4.0
cosmossdk.io/core v1.0.0-alpha.3
cosmossdk.io/depinject v1.0.0
cosmossdk.io/x/accounts v0.0.0-20240913065641-0064ccbce64e
cosmossdk.io/x/tx v0.13.3
github.com/cosmos/cosmos-sdk v0.53.0
Expand All @@ -19,7 +20,6 @@ require (
buf.build/gen/go/cometbft/cometbft/protocolbuffers/go v1.34.2-20240701160653-fedbb9acfd2f.2 // indirect
buf.build/gen/go/cosmos/gogo-proto/protocolbuffers/go v1.34.2-20240130113600-88ef6483f90f.2 // indirect
cosmossdk.io/core/testing v0.0.0-20240923163230-04da382a9f29 // indirect
cosmossdk.io/depinject v1.0.0 // indirect
cosmossdk.io/errors v1.0.1 // indirect
cosmossdk.io/log v1.4.1 // indirect
cosmossdk.io/math v1.3.0 // indirect
Expand Down Expand Up @@ -174,15 +174,7 @@ replace (
cosmossdk.io/collections => ../../../../collections // TODO tag new collections ASAP
cosmossdk.io/store => ../../../../store
cosmossdk.io/x/accounts => ../../.
cosmossdk.io/x/accounts/defaults/multisig => ../multisig
cosmossdk.io/x/auth => ../../../auth
cosmossdk.io/x/bank => ../../../bank
cosmossdk.io/x/consensus => ../../../consensus
cosmossdk.io/x/distribution => ../../../distribution
cosmossdk.io/x/gov => ../../../gov
cosmossdk.io/x/mint => ../../../mint
cosmossdk.io/x/protocolpool => ../../../protocolpool
cosmossdk.io/x/slashing => ../../../slashing
cosmossdk.io/x/staking => ../../../staking
cosmossdk.io/x/tx => ../../../tx
)
31 changes: 31 additions & 0 deletions x/accounts/defaults/lockup/depinject/depinject.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
package lockupdepinject

import (
"cosmossdk.io/x/accounts/accountstd"
"cosmossdk.io/x/accounts/defaults/lockup"
)

func ProvideAllLockupAccounts() []accountstd.DepinjectAccount {
return []accountstd.DepinjectAccount{
ProvidePeriodicLockingAccount(),
ProvideContinuousLockingAccount(),
ProvidePermanentLockingAccount(),
ProvideDelayedLockingAccount(),
}
}

func ProvideContinuousLockingAccount() accountstd.DepinjectAccount {
return accountstd.DIAccount(lockup.CONTINUOUS_LOCKING_ACCOUNT, lockup.NewContinuousLockingAccount)
}

func ProvidePeriodicLockingAccount() accountstd.DepinjectAccount {
return accountstd.DIAccount(lockup.PERIODIC_LOCKING_ACCOUNT, lockup.NewPeriodicLockingAccount)
}

func ProvideDelayedLockingAccount() accountstd.DepinjectAccount {
return accountstd.DIAccount(lockup.DELAYED_LOCKING_ACCOUNT, lockup.NewDelayedLockingAccount)
}

func ProvidePermanentLockingAccount() accountstd.DepinjectAccount {
return accountstd.DIAccount(lockup.PERMANENT_LOCKING_ACCOUNT, lockup.NewPermanentLockingAccount)
}
7 changes: 1 addition & 6 deletions x/accounts/defaults/lockup/go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -151,13 +151,8 @@ replace (
cosmossdk.io/collections => ../../../../collections // TODO tag new collections ASAP
cosmossdk.io/store => ../../../../store
cosmossdk.io/x/accounts => ../../.
cosmossdk.io/x/accounts/defaults/multisig => ../multisig
cosmossdk.io/x/bank => ../../../bank
cosmossdk.io/x/consensus => ../../../consensus
cosmossdk.io/x/distribution => ../../../distribution
cosmossdk.io/x/gov => ../../../gov
cosmossdk.io/x/mint => ../../../mint
cosmossdk.io/x/protocolpool => ../../../protocolpool
cosmossdk.io/x/slashing => ../../../slashing
cosmossdk.io/x/staking => ../../../staking
cosmossdk.io/x/tx => ../../../tx
)
2 changes: 0 additions & 2 deletions x/accounts/defaults/lockup/go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -18,8 +18,6 @@ cosmossdk.io/math v1.3.0 h1:RC+jryuKeytIiictDslBP9i1fhkVm6ZDmZEoNP316zE=
cosmossdk.io/math v1.3.0/go.mod h1:vnRTxewy+M7BtXBNFybkuhSH4WfedVAAnERHgVFhp3k=
cosmossdk.io/schema v0.3.0 h1:01lcaM4trhzZ1HQTfTV8z6Ma1GziOZ/YmdzBN3F720c=
cosmossdk.io/schema v0.3.0/go.mod h1:RDAhxIeNB4bYqAlF4NBJwRrgtnciMcyyg0DOKnhNZQQ=
cosmossdk.io/x/tx v0.13.3 h1:Ha4mNaHmxBc6RMun9aKuqul8yHiL78EKJQ8g23Zf73g=
cosmossdk.io/x/tx v0.13.3/go.mod h1:I8xaHv0rhUdIvIdptKIqzYy27+n2+zBVaxO6fscFhys=
filippo.io/edwards25519 v1.1.0 h1:FNf4tywRC1HmFuKW5xopWpigGjJKiJSV0Cqo0cJWDaA=
filippo.io/edwards25519 v1.1.0/go.mod h1:BxyFTGdWcka3PhytdK4V28tE5sGfRvvvRV7EaN4VDT4=
github.com/99designs/go-keychain v0.0.0-20191008050251-8e49817e8af4 h1:/vQbFIOMbk2FiG/kXiLl8BRyzTWDw7gX/Hz7Dd5eDMs=
Expand Down
2 changes: 0 additions & 2 deletions x/accounts/defaults/multisig/account.go
Original file line number Diff line number Diff line change
Expand Up @@ -16,8 +16,6 @@ import (
"github.com/cosmos/cosmos-sdk/codec"
)

var MULTISIG_ACCOUNT = "multisig-account"

var (
MembersPrefix = collections.NewPrefix(0)
SequencePrefix = collections.NewPrefix(1)
Expand Down
Loading
Loading