bank

package
v0.0.0 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Aug 11, 2026 License: Apache-2.0, UNKNOWN not legal advice Imports: 0 Imported by: 0

Documentation

Index

Constants

View Source
const (
	QueryBalance = "balances"
	QuerySupply  = "supply"
)

Query paths.

View Source
const (
	// BalancePrefix namespaces split-tier balances — every denom outside the
	// account-tier allowlist, which is a strict superset of the realm-issued ones.
	BalancePrefix = "/b/"
)

Balance storage.

A balance whose denom is in the account tier lives inside the account object, in its Coins field. Every other balance lives on its own at

/b/ || addr (20 raw bytes) || denom      ->  amount, 8-byte big-endian

The account tier is an allowlist of the chain's gas denoms, injected at construction (see NewViewKeeper). It is tiny by design: a balance there is free only because the account object is rewritten on every transaction its owner sends anyway, to bump the sequence, and that argument holds for gas denoms and nothing else. Anything else kept there would be unbounded third-party-writable data on the holder's own metered critical path — see the ADR for the attack that enables, and for why the allowlist is closed and injected rather than a governance param.

Not to be confused with who may *issue* a denom, which is std.IsRealmDenom and is enforced at the banker.

Layout constraints, all load-bearing:

  • The address is not length-prefixed, which is safe only while crypto.Address is a fixed [20]byte: the denom is the remainder at a constant offset, so it may itself contain "/" and ":" freely.
  • Store keys are not gas-metered, so key size is bounded only by MaxDenomLength (274) in tm2/pkg/std. Value size is metered, which is why the amount is fixed-width rather than amino-encoded.
  • "/b/" must not prefix, or be prefixed by, any other key in the shared main store. Check bare names too — "gasPrice", "globalAccountNumber", "pkg:", "consensus_params", GnoVM object ids — not only "/..." prefixes. Pinned by TestBalancePrefixDoesNotCollide. Deliberately not nested under "/a/", where the session-account precedent shows nesting creates an iteration-filter hazard.
View Source
const (
	ModuleName = "bank"
)
View Source
const RouterKey = ModuleName

RouterKey is they name of the bank module

View Source
const SupplyPrefix = "/supply/"

SupplyPrefix is where the per-denom supply counter lives:

/supply/ || denom   ->   amount, 8-byte big-endian

Spelled out rather than abbreviated. Every module shares one store here, so the prefix is what namespaces the keyspace — cosmos can afford a single opaque byte because each of its modules gets its own mounted store, and we cannot. Store keys are not gas-metered, so the extra bytes cost nothing but state.

Deliberately not "/s/": that is auth.SessionStoreKeyInfix verbatim, and while a session key begins "/a/" so the two ranges cannot overlap, sharing the spelling would make a search for one return the other.

Variables

View Source
var Package = amino.RegisterPackage(amino.NewPackage(
	"github.com/gnolang/gno/tm2/pkg/sdk/bank",
	"bank",
	amino.GetCallersDirname(),
).WithDependencies().WithTypes(
	NoInputsError{}, "NoInputsError",
	NoOutputsError{}, "NoOutputsError",
	InputOutputMismatchError{}, "InputOutputMismatchError",
	MsgSend{}, "MsgSend",
	GenesisState{}, "GenesisState",
	Params{}, "Params",
))

Functions

func AccountTierInvariant

func AccountTierInvariant(view ViewKeeper) sdk.Invariant

AccountTierInvariant checks the balances held inside account objects.

Every denom there must be in the allowlist. A denom that is not is stranded: the keeper routes it to the split tier, so GetCoin reports zero while GetCoins reports it, and it cannot be spent. A realm-issuable denom there is worse than stranded and is reported as such — its issuer could mint into a shared metered blob, which is the griefing the split exists to close.

func AllInvariants

func AllInvariants(view ViewKeeper) sdk.Invariant

AllInvariants runs every bank invariant.

func BalanceKey

func BalanceKey(addr crypto.Address, denom string) []byte

BalanceKey returns the store key holding addr's balance of denom.

Only valid for split-tier denoms; account-tier denoms live in the account object.

func BalanceKeysInvariant

func BalanceKeysInvariant(view ViewKeeper) sdk.Invariant

BalanceKeysInvariant sweeps the split-tier keyspace.

Checks that every key under BalancePrefix is well formed and names a valid denom; that every value decodes to a positive amount; that no denom there belongs to the account tier; that a realm-shaped denom has a shape a realm could have issued; and that every address holding a balance has an account object, without which the funds are permanently unspendable because the address cannot sign.

Reads nothing through the keeper's typed accessors. splitCoins, GetCoins and decodeBalance all panic on precisely the states reported here, and an invariant must enumerate every violation rather than die at the first.

func BalancePrefixKey

func BalancePrefixKey(addr crypto.Address) []byte

BalancePrefixKey returns the prefix covering every balance held by addr, the analogue of auth.SessionPrefixKey. Iterating it yields denoms in ascending order.

func ErrInputOutputMismatch

func ErrInputOutputMismatch() error

func ErrNoInputs

func ErrNoInputs() error

func ErrNoOutputs

func ErrNoOutputs() error

func NewHandler

func NewHandler(bank BankKeeper) bankHandler

NewHandler returns a handler for "bank" type messages.

func SupplyInvariant

func SupplyInvariant(view ViewKeeper) sdk.Invariant

SupplyInvariant checks the recorded supply against the balances actually held.

This is the only redundancy check in the set: two numbers maintained by different code that must agree. The others are structural — they check shapes, tiers and key/field agreement — and a mint that bypassed the counter looks perfectly well formed to all of them. Here it does not.

Reports in both directions. A denom held with no record is what an unaccounted credit produces; a record with nothing held is what a lost balance write produces.

func SupplyKey

func SupplyKey(denom string) []byte

SupplyKey returns the store key holding denom's total supply.

func ValidateGenesis

func ValidateGenesis(data GenesisState) error

ValidateGenesis performs basic validation of genesis data returning an error for any failed validation criteria.

func ValidateInputsOutputs

func ValidateInputsOutputs(inputs []Input, outputs []Output) error

ValidateInputsOutputs validates that each respective input and output is valid and that the sum of inputs is equal to the sum of outputs.

Types

type BankKeeper

type BankKeeper struct {
	ViewKeeper
	// contains filtered or unexported fields
}

BankKeeper only allows transfers between accounts without the possibility of creating coins. It implements the BankKeeperI interface.

func NewBankKeeper

func NewBankKeeper(acck auth.AccountKeeper, pk params.ParamsKeeperI, key store.StoreKey, accountDenoms []string) BankKeeper

NewBankKeeper returns a new BankKeeper.

accountDenoms is the allowlist of denoms held inside the account object; see balance.go. Everything else gets its own key. Pass the chain's gas denoms.

func (BankKeeper) AddCoins

func (bank BankKeeper) AddCoins(ctx sdk.Context, addr crypto.Address, amt std.Coins) error

AddCoins adds amt to the coins at the addr.

func (BankKeeper) BurnCoins

func (bank BankKeeper) BurnCoins(ctx sdk.Context, addr crypto.Address, amt std.Coins) error

BurnCoins destroys amt held by addr, lowering the supply counter.

func (BankKeeper) ExportGenesis

func (bank BankKeeper) ExportGenesis(ctx sdk.Context) GenesisState

ExportGenesis returns a GenesisState for a given context and keeper

func (BankKeeper) GetParams

func (bank BankKeeper) GetParams(ctx sdk.Context) Params

func (BankKeeper) InitGenesis

func (bank BankKeeper) InitGenesis(ctx sdk.Context, data GenesisState)

InitGenesis - Init store state from genesis data

func (BankKeeper) InputOutputCoins

func (bank BankKeeper) InputOutputCoins(ctx sdk.Context, inputs []Input, outputs []Output) error

InputOutputCoins handles a list of inputs and outputs

func (BankKeeper) MintCoins

func (bank BankKeeper) MintCoins(ctx sdk.Context, addr crypto.Address, amt std.Coins) error

MintCoins creates amt and credits it to addr, raising the supply counter.

This and BurnCoins are the only paths that change supply. Transfers are supply-neutral, so AddCoins and subtract deliberately do not touch the counter: they also carry fees and storage-deposit refunds, and a counter that followed them would make an unpaired credit look legitimate instead of breaking the supply invariant — which is the whole point of keeping a second number.

Supply is capped at MaxInt64 per denom. That is a real constraint, not a formality: before this counter existed two addresses could each hold MaxInt64 of one denom, since AddCoins bounds each balance and nothing bounded the total.

func (BankKeeper) RecomputeSupply

func (bank BankKeeper) RecomputeSupply(ctx sdk.Context)

RecomputeSupply rewrites every supply record from the balances actually held.

For genesis and offline tooling only, never a metered path and never a live chain: it writes state outside any block, so a node that ran it and one that did not would diverge.

Genesis needs this rather than an incremental hook because SetCoins cannot compute its own delta. InitChainer writes the account object with the full pre-split balance *before* calling SetCoins, so SetCoins reads old == new and a delta would be zero for every vesting account — and that pre-write cannot be removed, since the vesting constructors validate OriginalVesting against it.

Do not run this to silence a SupplyInvariant finding. It makes the record agree with whatever is held, corruption included: on a double-homed denom — one with both an account-object entry and a /b/ key — the totals sum both homes, so this records the doubled figure and the supply invariant then reports healthy. Measured: 20 recorded against 25 held becomes 25 against 25. The corruption itself stays visible, because BalanceKeysInvariant owns the stray key and still reports it, so check the other invariants before concluding a supply mismatch was a bookkeeping error. Genesis cannot reach that state — a balances file lists one amount per denom per address, so SetCoins produces a single home — which is why this is a caution for offline tooling rather than a guard here.

func (BankKeeper) RestrictedDenoms

func (bank BankKeeper) RestrictedDenoms(ctx sdk.Context) []string

func (BankKeeper) SendCoins

func (bank BankKeeper) SendCoins(ctx sdk.Context, fromAddr crypto.Address, toAddr crypto.Address, amt std.Coins) error

SendCoins moves coins from one account to another, restrction could be applied

func (BankKeeper) SendCoinsUnrestricted

func (bank BankKeeper) SendCoinsUnrestricted(ctx sdk.Context, fromAddr crypto.Address, toAddr crypto.Address, amt std.Coins) error

SendCoinsUnrestricted is used for paying gas. It bypasses vesting and session-spend checks.

func (BankKeeper) SetCoins

func (bank BankKeeper) SetCoins(ctx sdk.Context, addr crypto.Address, amt std.Coins) error

SetCoins replaces every balance at addr.

Replace-all is only meaningful at genesis and in tests; ordinary transfers use AddCoins/SubtractCoins, which touch one key per split-tier denom moved. Balances present but absent from amt are deleted, so this is a replacement and not a merge.

Does not maintain the supply counter. It cannot: InitChainer writes the account object with the full pre-split amount before calling this, so the old value read here equals the new one and any delta would be zero for a vesting account. Call RecomputeSupply after a batch of these; see supply.go.

Stays exported despite that, because genesis lives in another package (gno.land/pkg/gnoland) and has to call it. The protection that matters is already structural rather than lexical: SetCoins is absent from both vm.BankKeeperI and auth.BankKeeperI, so neither a realm nor the ante handler can reach it. Only a new tm2-side handler holding BankKeeperI could, which is what the warning below is for.

Cost is O(denoms currently held), and each removal is a full store write, so this is not safe to call on an address whose denom count an attacker controls — clearing a few hundred would exceed the block gas limit. Every caller today runs at genesis, where the count is known.

func (BankKeeper) SetParams

func (bank BankKeeper) SetParams(ctx sdk.Context, params Params) error

func (BankKeeper) SetRestrictedDenoms

func (bank BankKeeper) SetRestrictedDenoms(ctx sdk.Context, restrictedDenoms []string)

This is a convenience function for manually setting the restricted denoms. Useful for testing and initchain setup.

func (BankKeeper) SubtractCoins

func (bank BankKeeper) SubtractCoins(ctx sdk.Context, addr crypto.Address, amt std.Coins) error

SubtractCoins subtracts amt from the coins at the addr.

Enforces vesting: if the account is a VestingAccount, the amount must not exceed the spendable (unlocked) balance at the current block time.

Does not enforce the session spend limit or the transfer restriction, which both live in SendCoins. BurnCoins debits through here, so a realm removing its own coin does not consume a session's allowance — which changes nothing it could not already do, since removal needs no consent from the holder.

func (BankKeeper) WillSetParam

func (bank BankKeeper) WillSetParam(ctx sdk.Context, key string, value any)

type BankKeeperI

type BankKeeperI interface {
	ViewKeeperI

	InputOutputCoins(ctx sdk.Context, inputs []Input, outputs []Output) error
	SendCoins(ctx sdk.Context, fromAddr crypto.Address, toAddr crypto.Address, amt std.Coins) error

	SubtractCoins(ctx sdk.Context, addr crypto.Address, amt std.Coins) error
	AddCoins(ctx sdk.Context, addr crypto.Address, amt std.Coins) error
	SetCoins(ctx sdk.Context, addr crypto.Address, amt std.Coins) error
	SendCoinsUnrestricted(ctx sdk.Context, fromAddr crypto.Address, toAddr crypto.Address, amt std.Coins) error

	InitGenesis(ctx sdk.Context, data GenesisState)
	GetParams(ctx sdk.Context) Params

	MintCoins(ctx sdk.Context, addr crypto.Address, amt std.Coins) error
	BurnCoins(ctx sdk.Context, addr crypto.Address, amt std.Coins) error
	RecomputeSupply(ctx sdk.Context)
}

bank.Keeper defines a module interface that facilitates the transfer of coins between accounts without the possibility of creating coins.

type BankParamsContextKey

type BankParamsContextKey struct{}

type GenesisState

type GenesisState struct {
	Params Params `json:"params" yaml:"params"`
}

GenesisState - all state that must be provided at genesis

func DefaultGenesisState

func DefaultGenesisState() GenesisState

DefaultGenesisState - Return a default genesis state

func NewGenesisState

func NewGenesisState(params Params) GenesisState

NewGenesisState - Create a new genesis state

func (GenesisState) MarshalBinary2

func (goo GenesisState) MarshalBinary2(cdc *amino.Codec, buf []byte, offset int) (int, error)

func (GenesisState) SizeBinary2

func (goo GenesisState) SizeBinary2(cdc *amino.Codec) (int, error)

func (*GenesisState) UnmarshalBinary2

func (goo *GenesisState) UnmarshalBinary2(cdc *amino.Codec, bz []byte, anyDepth int) error

type Input

type Input struct {
	Address crypto.Address `json:"address" yaml:"address"`
	Coins   std.Coins      `json:"coins" yaml:"coins"`
}

Input models transaction input

func NewInput

func NewInput(addr crypto.Address, coins std.Coins) Input

NewInput - create a transaction input, used with MsgMultiSend

func (Input) ValidateBasic

func (in Input) ValidateBasic() error

ValidateBasic - validate transaction input

type InputOutputMismatchError

type InputOutputMismatchError struct {
	// contains filtered or unexported fields
}

func (InputOutputMismatchError) AssertABCIError

func (InputOutputMismatchError) AssertABCIError()

func (InputOutputMismatchError) Error

func (e InputOutputMismatchError) Error() string

func (InputOutputMismatchError) MarshalBinary2

func (goo InputOutputMismatchError) MarshalBinary2(cdc *amino.Codec, buf []byte, offset int) (int, error)

func (InputOutputMismatchError) SizeBinary2

func (goo InputOutputMismatchError) SizeBinary2(cdc *amino.Codec) (int, error)

func (*InputOutputMismatchError) UnmarshalBinary2

func (goo *InputOutputMismatchError) UnmarshalBinary2(cdc *amino.Codec, bz []byte, anyDepth int) error

type MsgMultiSend

type MsgMultiSend struct {
	Inputs  []Input  `json:"inputs" yaml:"inputs"`
	Outputs []Output `json:"outputs" yaml:"outputs"`
}

MsgMultiSend - high level transaction of the coin module

func NewMsgMultiSend

func NewMsgMultiSend(in []Input, out []Output) MsgMultiSend

NewMsgMultiSend - construct arbitrary multi-in, multi-out send msg.

func (MsgMultiSend) GetSignBytes

func (msg MsgMultiSend) GetSignBytes() []byte

GetSignBytes Implements Msg.

func (MsgMultiSend) GetSigners

func (msg MsgMultiSend) GetSigners() []crypto.Address

GetSigners Implements Msg.

func (MsgMultiSend) Route

func (msg MsgMultiSend) Route() string

Route Implements Msg

func (MsgMultiSend) SpendForSigner

func (msg MsgMultiSend) SpendForSigner(signer crypto.Address) std.Coins

SpendForSigner implements std.SpendEstimator. Sums the coins of all inputs where Address == signer. An input-less signer returns nil.

func (MsgMultiSend) Type

func (msg MsgMultiSend) Type() string

Type Implements Msg

func (MsgMultiSend) ValidateBasic

func (msg MsgMultiSend) ValidateBasic() error

ValidateBasic Implements Msg.

type MsgSend

type MsgSend struct {
	FromAddress crypto.Address `json:"from_address" yaml:"from_address"`
	ToAddress   crypto.Address `json:"to_address" yaml:"to_address"`
	Amount      std.Coins      `json:"amount" yaml:"amount"`
}

MsgSend - high level transaction of the coin module

func NewMsgSend

func NewMsgSend(fromAddr, toAddr crypto.Address, amount std.Coins) MsgSend

NewMsgSend - construct arbitrary multi-in, multi-out send msg.

func (MsgSend) GetSignBytes

func (msg MsgSend) GetSignBytes() []byte

GetSignBytes Implements Msg.

func (MsgSend) GetSigners

func (msg MsgSend) GetSigners() []crypto.Address

GetSigners Implements Msg.

func (MsgSend) MarshalBinary2

func (goo MsgSend) MarshalBinary2(cdc *amino.Codec, buf []byte, offset int) (int, error)

func (MsgSend) Route

func (msg MsgSend) Route() string

Route Implements Msg.

func (MsgSend) SizeBinary2

func (goo MsgSend) SizeBinary2(cdc *amino.Codec) (int, error)

func (MsgSend) SpendForSigner

func (msg MsgSend) SpendForSigner(signer crypto.Address) std.Coins

SpendForSigner implements std.SpendEstimator. Returns Amount when signer is the sender, zero otherwise.

func (MsgSend) Type

func (msg MsgSend) Type() string

Type Implements Msg.

func (*MsgSend) UnmarshalBinary2

func (goo *MsgSend) UnmarshalBinary2(cdc *amino.Codec, bz []byte, anyDepth int) error

func (MsgSend) ValidateBasic

func (msg MsgSend) ValidateBasic() error

ValidateBasic Implements Msg.

type NoInputsError

type NoInputsError struct {
	// contains filtered or unexported fields
}

declare all bank errors. NOTE: these are meant to be used in conjunction with pkgs/errors.

func (NoInputsError) AssertABCIError

func (NoInputsError) AssertABCIError()

func (NoInputsError) Error

func (e NoInputsError) Error() string

func (NoInputsError) MarshalBinary2

func (goo NoInputsError) MarshalBinary2(cdc *amino.Codec, buf []byte, offset int) (int, error)

func (NoInputsError) SizeBinary2

func (goo NoInputsError) SizeBinary2(cdc *amino.Codec) (int, error)

func (*NoInputsError) UnmarshalBinary2

func (goo *NoInputsError) UnmarshalBinary2(cdc *amino.Codec, bz []byte, anyDepth int) error

type NoOutputsError

type NoOutputsError struct {
	// contains filtered or unexported fields
}

func (NoOutputsError) AssertABCIError

func (NoOutputsError) AssertABCIError()

func (NoOutputsError) Error

func (e NoOutputsError) Error() string

func (NoOutputsError) MarshalBinary2

func (goo NoOutputsError) MarshalBinary2(cdc *amino.Codec, buf []byte, offset int) (int, error)

func (NoOutputsError) SizeBinary2

func (goo NoOutputsError) SizeBinary2(cdc *amino.Codec) (int, error)

func (*NoOutputsError) UnmarshalBinary2

func (goo *NoOutputsError) UnmarshalBinary2(cdc *amino.Codec, bz []byte, anyDepth int) error

type Output

type Output struct {
	Address crypto.Address `json:"address" yaml:"address"`
	Coins   std.Coins      `json:"coins" yaml:"coins"`
}

Output models transaction outputs

func NewOutput

func NewOutput(addr crypto.Address, coins std.Coins) Output

NewOutput - create a transaction output, used with MsgMultiSend

func (Output) ValidateBasic

func (out Output) ValidateBasic() error

ValidateBasic - validate transaction output

type Params

type Params struct {
	RestrictedDenoms []string `json:"restricted_denoms" yaml:"restricted_denoms"`
}

Params defines the parameters for the bank module.

func DefaultParams

func DefaultParams() Params

DefaultParams returns a default set of parameters.

func NewParams

func NewParams(restDenoms []string) Params

NewParams creates a new Params object

func (Params) MarshalBinary2

func (goo Params) MarshalBinary2(cdc *amino.Codec, buf []byte, offset int) (int, error)

func (Params) SizeBinary2

func (goo Params) SizeBinary2(cdc *amino.Codec) (int, error)

func (Params) String

func (p Params) String() string

String implements the stringer interface.

func (*Params) UnmarshalBinary2

func (goo *Params) UnmarshalBinary2(cdc *amino.Codec, bz []byte, anyDepth int) error

func (*Params) Validate

func (p *Params) Validate() error

type ViewKeeper

type ViewKeeper struct {
	// contains filtered or unexported fields
}

ViewKeeper implements a read only keeper implementation of ViewKeeperI.

func NewViewKeeper

func NewViewKeeper(acck auth.AccountKeeper, key store.StoreKey, accountDenoms []string) ViewKeeper

NewViewKeeper returns a new ViewKeeper.

accountDenoms is the allowlist of denoms held inside the account object.

func (ViewKeeper) GetCoin

func (view ViewKeeper) GetCoin(ctx sdk.Context, addr crypto.Address, denom string) int64

GetCoin returns addr's balance of one denom without reading any other. This is the O(1) accessor.

func (ViewKeeper) GetCoins

func (view ViewKeeper) GetCoins(ctx sdk.Context, addr crypto.Address) std.Coins

GetCoins returns every coin held at addr, from both tiers.

The two are merged rather than concatenated. An earlier version could concatenate, because the split tier held only "/"-prefixed denoms which sort below everything else; with an allowlist that no longer holds — a split denom such as "atom" sorts before an account-tier "ugnot" — so neither order is universally ascending. Coins.Add is a merge over sorted sets, and the tiers are disjoint by construction, so no two amounts are ever summed.

Costs O(number of split-tier denoms held). Use GetCoin when one denom will do — that is the whole point of the split.

func (ViewKeeper) HasCoins

func (view ViewKeeper) HasCoins(ctx sdk.Context, addr crypto.Address, amt std.Coins) bool

HasCoins returns whether or not an account has at least amt coins.

Checked per denom so that holding many unrelated denoms costs nothing here. An empty amt is satisfied, as under the previous IsAllGTE. The two differ on one unreachable edge — a zero-amount entry against an empty balance set, which IsAllGTE rejected and this accepts — because valid std.Coins never carry a zero amount.

func (ViewKeeper) Logger

func (view ViewKeeper) Logger(ctx sdk.Context) *slog.Logger

Logger returns a module-specific logger.

func (ViewKeeper) TotalSupply

func (view ViewKeeper) TotalSupply(ctx sdk.Context, denom string) int64

TotalSupply returns how much of denom exists, or zero for a denom nobody holds.

type ViewKeeperI

type ViewKeeperI interface {
	GetCoins(ctx sdk.Context, addr crypto.Address) std.Coins
	GetCoin(ctx sdk.Context, addr crypto.Address, denom string) int64
	HasCoins(ctx sdk.Context, addr crypto.Address, amt std.Coins) bool
	TotalSupply(ctx sdk.Context, denom string) int64
}

ViewKeeperI defines a module interface that facilitates read only access to account balances.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL