diff --git a/x/logic/predicate/bank.go b/x/logic/predicate/bank.go index 297335dc..c59f6eb8 100644 --- a/x/logic/predicate/bank.go +++ b/x/logic/predicate/bank.go @@ -6,6 +6,7 @@ import ( "github.com/ichiban/prolog/engine" "github.com/samber/lo" + cdctypes "github.com/cosmos/cosmos-sdk/codec/types" sdk "github.com/cosmos/cosmos-sdk/types" "github.com/axone-protocol/axoned/v10/x/logic/prolog" @@ -96,18 +97,24 @@ func BankLockedBalances(vm *engine.VM, address, balances engine.Term, cont engin // # Examples: // // # Query the locked coins of the account. -// - account('axone1ffd5wx65l407yvm478cxzlgygw07h79sw4jwpa', X). +// - account('axone1ffd5wx65l407yvm478cxzlgygw07h79sw4jwpa'). // // # Query the all accounts existing in the blockchain. -// - account(Acc). +// - account(Address). func account(vm *engine.VM, address engine.Term, cont engine.Cont, env *engine.Env) *engine.Promise { return engine.Delay(func(ctx context.Context) *engine.Promise { - sdkContext, err := prolog.UnwrapSDKContext(ctx, env) + authKeeper, err := prolog.ContextValue[types.AccountKeeper](ctx, types.AuthKeeperContextKey, env) + if err != nil { + return engine.Error(err) + } + authQueryService, err := prolog.ContextValue[types.AuthQueryService](ctx, types.AuthQueryServiceContextKey, env) + if err != nil { + return engine.Error(err) + } + interfaceRegistry, err := prolog.ContextValue[cdctypes.InterfaceRegistry](ctx, types.InterfaceRegistryContextKey, env) if err != nil { return engine.Error(err) } - authKeeper := sdkContext.Value(types.AuthKeeperContextKey).(types.AccountKeeper) - authQueryService := sdkContext.Value(types.AuthQueryServiceContextKey).(types.AuthQueryService) switch acc := env.Resolve(address).(type) { case engine.Atom: @@ -125,7 +132,7 @@ func account(vm *engine.VM, address engine.Term, cont engine.Cont, env *engine.E return cont(env) }) case engine.Variable: - return engine.DelaySeq(IterMap(Accounts(ctx, authQueryService), + return engine.DelaySeq(IterMap(Accounts(ctx, authQueryService, interfaceRegistry), func(it lo.Tuple2[sdk.AccountI, error]) engine.PromiseFunc { return func(_ context.Context) *engine.Promise { addr, err := lo.Unpack2(it) @@ -147,11 +154,10 @@ func fetchBalances(vm *engine.VM, address engine.Term, balances engine.Term, coi bankKeeper types.BankKeeper, address sdk.AccAddress) sdk.Coins, cont engine.Cont, env *engine.Env, ) *engine.Promise { return engine.Delay(func(ctx context.Context) *engine.Promise { - sdkContext, err := prolog.UnwrapSDKContext(ctx, env) + bankKeeper, err := prolog.ContextValue[types.BankKeeper](ctx, types.BankKeeperContextKey, env) if err != nil { return engine.Error(err) } - bankKeeper := sdkContext.Value(types.BankKeeperContextKey).(types.BankKeeper) return account(vm, address, func(env *engine.Env) *engine.Promise { switch acc := env.Resolve(address).(type) { diff --git a/x/logic/prolog/context.go b/x/logic/prolog/context.go index c804a81d..d06a03c7 100644 --- a/x/logic/prolog/context.go +++ b/x/logic/prolog/context.go @@ -6,6 +6,8 @@ import ( "github.com/ichiban/prolog/engine" sdk "github.com/cosmos/cosmos-sdk/types" + + "github.com/axone-protocol/axoned/v10/x/logic/types" ) // UnwrapSDKContext retrieves a Context from a context.Context instance @@ -20,3 +22,14 @@ func UnwrapSDKContext(ctx context.Context, env *engine.Env) (sdk.Context, error) return sdk.Context{}, engine.ResourceError(ResourceContext(), env) } + +// ContextValue returns the value associated with this key in the context. +// If the value is not found, it returns the error: error(resource_error(resource_context())). +func ContextValue[V any](ctx context.Context, key types.ContextKey, env *engine.Env) (V, error) { + if value, ok := ctx.Value(key).(V); ok { + return value, nil + } + + var zero V + return zero, engine.ResourceError(ResourceContextValue(string(key)), env) +} diff --git a/x/logic/prolog/error.go b/x/logic/prolog/error.go index b0d2c3a1..ed8118b6 100644 --- a/x/logic/prolog/error.go +++ b/x/logic/prolog/error.go @@ -87,6 +87,11 @@ func ResourceContext() engine.Term { return AtomResourceContext } +// ResourceContextValue returns a term representing the context resource with the given key. +func ResourceContextValue(key string) engine.Term { + return AtomResourceContext.Apply(engine.NewAtom(key)) +} + // ResourceModule returns a term representing the module resource with the given name. func ResourceModule(module string) engine.Term { return AtomResourceModule.Apply(engine.NewAtom(module))