-
Notifications
You must be signed in to change notification settings - Fork 3.7k
/
exports.go
166 lines (137 loc) · 5.72 KB
/
exports.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
// Package accountstd exports the types and functions that are used by developers to implement smart accounts.
package accountstd
import (
"bytes"
"context"
"errors"
"fmt"
"cosmossdk.io/core/transaction"
"cosmossdk.io/x/accounts/internal/implementation"
sdk "github.com/cosmos/cosmos-sdk/types"
"github.com/cosmos/cosmos-sdk/types/address"
)
var (
accountsModuleAddress = address.Module("accounts")
ErrInvalidType = errors.New("invalid type")
)
// Interface is the exported interface of an Account.
type Interface = implementation.Account
// ExecuteBuilder is the exported type of ExecuteBuilder.
type ExecuteBuilder = implementation.ExecuteBuilder
// QueryBuilder is the exported type of QueryBuilder.
type QueryBuilder = implementation.QueryBuilder
// InitBuilder is the exported type of InitBuilder.
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
func RegisterExecuteHandler[
Req any, ProtoReq implementation.ProtoMsgG[Req], Resp any, ProtoResp implementation.ProtoMsgG[Resp],
](router *ExecuteBuilder, handler func(ctx context.Context, req ProtoReq) (ProtoResp, error),
) {
implementation.RegisterExecuteHandler(router, handler)
}
// RegisterQueryHandler registers a query handler for a smart account that uses protobuf.
func RegisterQueryHandler[
Req any, ProtoReq implementation.ProtoMsgG[Req], Resp any, ProtoResp implementation.ProtoMsgG[Resp],
](router *QueryBuilder, handler func(ctx context.Context, req ProtoReq) (ProtoResp, error),
) {
implementation.RegisterQueryHandler(router, handler)
}
// RegisterInitHandler registers an initialisation handler for a smart account that uses protobuf.
func RegisterInitHandler[
Req any, ProtoReq implementation.ProtoMsgG[Req], Resp any, ProtoResp implementation.ProtoMsgG[Resp],
](router *InitBuilder, handler func(ctx context.Context, req ProtoReq) (ProtoResp, error),
) {
implementation.RegisterInitHandler(router, handler)
}
// AddAccount is a helper function to add a smart account to the list of smart accounts.
func AddAccount[A Interface](name string, constructor func(deps Dependencies) (A, error)) AccountCreatorFunc {
return func(deps implementation.Dependencies) (string, implementation.Account, error) {
acc, err := constructor(deps)
return name, acc, err
}
}
// Whoami returns the address of the account being invoked.
func Whoami(ctx context.Context) []byte {
return implementation.Whoami(ctx)
}
// Sender returns the sender of the execution request.
func Sender(ctx context.Context) []byte {
return implementation.Sender(ctx)
}
// HasSender checks if the execution context was sent from the provided sender
func HasSender(ctx context.Context, wantSender []byte) bool {
return bytes.Equal(Sender(ctx), wantSender)
}
// SenderIsSelf checks if the sender of the request is the account itself.
func SenderIsSelf(ctx context.Context) bool { return HasSender(ctx, Whoami(ctx)) }
// SenderIsAccountsModule returns true if the sender of the execution request is the accounts module.
func SenderIsAccountsModule(ctx context.Context) bool {
return bytes.Equal(Sender(ctx), accountsModuleAddress)
}
// Funds returns if any funds were sent during the execute or init request. In queries this
// returns nil.
func Funds(ctx context.Context) sdk.Coins { return implementation.Funds(ctx) }
func ExecModule[MsgResp, Msg transaction.Msg](ctx context.Context, msg Msg) (resp MsgResp, err error) {
untyped, err := implementation.ExecModule(ctx, msg)
if err != nil {
return resp, err
}
return assertOrErr[MsgResp](untyped)
}
// QueryModule can be used by an account to execute a module query.
func QueryModule[Resp, Req transaction.Msg](ctx context.Context, req Req) (resp Resp, err error) {
untyped, err := implementation.QueryModule(ctx, req)
if err != nil {
return resp, err
}
return assertOrErr[Resp](untyped)
}
// UnpackAny unpacks a protobuf Any message generically.
func UnpackAny[Msg any, ProtoMsg implementation.ProtoMsgG[Msg]](any *implementation.Any) (*Msg, error) {
return implementation.UnpackAny[Msg, ProtoMsg](any)
}
// PackAny packs a protobuf Any message generically.
func PackAny(msg transaction.Msg) (*implementation.Any, error) {
return implementation.PackAny(msg)
}
// ExecModuleAnys can be used to execute a list of messages towards a module
// when those messages are packed in Any messages. The function returns a list
// of responses packed in Any messages.
func ExecModuleAnys(ctx context.Context, msgs []*implementation.Any) ([]*implementation.Any, error) {
responses := make([]*implementation.Any, len(msgs))
for i, msg := range msgs {
concreteMessage, err := implementation.UnpackAnyRaw(msg)
if err != nil {
return nil, fmt.Errorf("error unpacking message %d: %w", i, err)
}
resp, err := implementation.ExecModule(ctx, concreteMessage)
if err != nil {
return nil, fmt.Errorf("error executing message %d: %w", i, err)
}
// pack again
respAnyPB, err := implementation.PackAny(resp)
if err != nil {
return nil, fmt.Errorf("error packing response %d: %w", i, err)
}
responses[i] = respAnyPB
}
return responses, nil
}
// asserts the given any to the provided generic, returns ErrInvalidType if it can't.
func assertOrErr[T any](r any) (concrete T, err error) {
concrete, ok := r.(T)
if !ok {
return concrete, ErrInvalidType
}
return concrete, nil
}