const EventSend, EventClose
Event names emitted by AllowanceSender. Use these constants when asserting on events from off-chain observers or test code.
Package allowancesender provides a bounded, granter-revocable spending capability that wraps a banker.Banker source.
Package allowancesender provides a bounded, granter-revocable spending capability that wraps a banker.Banker source.
Realm A wants to grant realm B the ability to spend up to some bounded amount from A's address (or A's tx envelope) within a single call, without giving B unbounded access. After A's call to B returns, A revokes the capability via Close(); B cannot use it across tx boundaries even if it persisted the reference.
1src := banker.NewBanker(banker.BankerTypeRealmSend, cur)
2al := allowancesender.New(src, granterAddr,
3 chain.NewCoins(chain.NewCoin("ugnot", 1_000_000)))
4defer al.Close()
5bRealm.DoSomething(cross, al) // B can call al.Send up to cap
On return (success or panic), `defer al.Close()` flips the closed flag. If B persisted al, B's stored reference is now dead — any later al.Send() panics with "closed".
Despite the underlying type wrapping a banker.Banker, *AllowanceSender does NOT satisfy the banker.Banker interface. The other Banker methods (GetCoins, TotalCoin, IssueCoin, RemoveCoin) have no meaningful behavior on an allowance abstraction:
Send is the only meaningful operation; hence the "Sender" name. If you need to plug into a banker.Banker-shaped API, write an adapter in your own package.
AllowanceSender emits chain events at two points so off-chain observers can track allowance lifecycles. Events are emitted from the calling realm's package path (whichever realm holds the AllowanceSender pointer when the method is called).
The underlying inner banker also emits its own bank-keeper events for the actual coin movement; AllowanceSender's events sit on top of those for allowance-level audit trails.
New creates a new AllowanceSender wrapping inner with the given limit. payer is the address that inner.SendCoins will draw from (must match the realm address inner was created against; the banker enforces this at SendCoins time).
inner must be the canonical Banker produced by banker.NewBanker; hand-rolled Banker implementations (no-op fakes, decorators) are rejected via banker.IsCanonical. This guarantees that a callee receiving a *AllowanceSender from a granter realm can rely on Send actually moving real coins via the bank-keeper, not via a fake banker that no-ops SendCoins.
Panics if inner is not canonical or payer is invalid. limit may be empty (zero allowance — every Send panics with "cap exceeded"); limit may also contain multiple denoms.
1type AllowanceSender struct {
2 inner banker.Banker // unexported — callees cannot extract
3 payer address // address debited; must match inner's source
4 limit chain.Coins // maximum cumulative spend, per-denom
5 spent chain.Coins // running total of spends, per-denom
6 closed bool // once true, all further Send calls panic
7}AllowanceSender is a bounded, revocable spending capability over a source banker.Banker. Always pass *AllowanceSender (pointer); value copies are not supported and would not share state.
Does NOT satisfy banker.Banker — the other Banker methods (GetCoins, TotalCoin, IssueCoin, RemoveCoin) have no meaningful behavior on an allowance and are deliberately omitted.
Cap returns a defensive copy of the maximum cumulative spend. Mutating the returned slice does not affect internal state.
Close terminates the allowance. Subsequent Send calls panic. Idempotent — calling twice is fine; the second call is a no-op and does not re-emit the AllowanceSenderClose event.
Closed reports whether Close has been called.
Payer returns the address that this allowance debits from.
Remaining returns cap - spent, per denom. Denoms with non-positive remainder are omitted.
Send debits up to (cap - spent) per denom from payer to to via the inner banker. Updates spent on success. On any panic (including inner.SendCoins panic for bank-level reasons like insufficient balance), spent is rolled back — caller's accounting stays accurate even if a caller wraps Send in a defer-recover.
Arithmetic uses math/overflow.Add64; an overflow on (spent+amount) panics with a distinct message rather than silently wrapping. This closes the int64-overflow vector where a malicious callee passes a MaxInt64-style amount to bypass the cap check.
Negative amounts are rejected explicitly. chain.NewCoin permits signed amounts at construction; we don't accept them.
Emits "AllowanceSenderSend" event on success.
Panics:
Spent returns a defensive copy of the cumulative amount spent. Mutating the returned slice does not affect internal state.