maxRenderedRealm
untyped bigintAttacker-controlled strings are clamped before they reach the sanitizer, so escaping costs a bounded constant rather than scaling with input. Sanitizing runs ~11,310 gas/byte (InlineCode) against ~31 for the raw concatenation it replaced, and Render is reachable unauthenticated through vm/qrender under maxGasQuery = 3\_000\_000\_000. ExecutorCreationRealm is dispatched through the public dao.Executor interface, so a hostile executor computes it per call while storing almost nothing. Measured on the real render path: a 250KB value costs 2,839,117,770 gas unclamped against 18,749,984 clamped. 250KB is just under the cap; about 265KB crosses it (3,008,818,394), and past that the page cannot be rendered at all by anyone. Choosing the larger number costs the attacker nothing, since the value is computed per call and almost nothing is stored. Removing that amplification is the point of this file. It does NOT make the page safe, and nothing here should be read as claiming so. The executor's method body runs inside the same query and is unbounded: an executor that simply burns CPU before returning a short string still renders the proposal page permanently un-queryable, for a few hundred bytes of on-chain storage. That predates this change — Render has always called ExecutorString() and ExecutorCreationRealm() through the public interface — and bounding it needs a gas budget around executor dispatch, not a clamp.
Value
(256 <untyped> bigint)
maxRenderedReason
untyped bigintAttacker-controlled strings are clamped before they reach the sanitizer, so escaping costs a bounded constant rather than scaling with input. Sanitizing runs ~11,310 gas/byte (InlineCode) against ~31 for the raw concatenation it replaced, and Render is reachable unauthenticated through vm/qrender under maxGasQuery = 3\_000\_000\_000. ExecutorCreationRealm is dispatched through the public dao.Executor interface, so a hostile executor computes it per call while storing almost nothing. Measured on the real render path: a 250KB value costs 2,839,117,770 gas unclamped against 18,749,984 clamped. 250KB is just under the cap; about 265KB crosses it (3,008,818,394), and past that the page cannot be rendered at all by anyone. Choosing the larger number costs the attacker nothing, since the value is computed per call and almost nothing is stored. Removing that amplification is the point of this file. It does NOT make the page safe, and nothing here should be read as claiming so. The executor's method body runs inside the same query and is unbounded: an executor that simply burns CPU before returning a short string still renders the proposal page permanently un-queryable, for a few hundred bytes of on-chain storage. That predates this change — Render has always called ExecutorString() and ExecutorCreationRealm() through the public interface — and bounding it needs a gas budget around executor dispatch, not a clamp.
Value
(1024 <untyped> bigint)
maxRenderedError
untyped bigintAttacker-controlled strings are clamped before they reach the sanitizer, so escaping costs a bounded constant rather than scaling with input. Sanitizing runs ~11,310 gas/byte (InlineCode) against ~31 for the raw concatenation it replaced, and Render is reachable unauthenticated through vm/qrender under maxGasQuery = 3\_000\_000\_000. ExecutorCreationRealm is dispatched through the public dao.Executor interface, so a hostile executor computes it per call while storing almost nothing. Measured on the real render path: a 250KB value costs 2,839,117,770 gas unclamped against 18,749,984 clamped. 250KB is just under the cap; about 265KB crosses it (3,008,818,394), and past that the page cannot be rendered at all by anyone. Choosing the larger number costs the attacker nothing, since the value is computed per call and almost nothing is stored. Removing that amplification is the point of this file. It does NOT make the page safe, and nothing here should be read as claiming so. The executor's method body runs inside the same query and is unbounded: an executor that simply burns CPU before returning a short string still renders the proposal page permanently un-queryable, for a few hundred bytes of on-chain storage. That predates this change — Render has always called ExecutorString() and ExecutorCreationRealm() through the public interface — and bounding it needs a gas budget around executor dispatch, not a clamp.
Value
(256 <untyped> bigint)
maxRenderedTitle
untyped bigintAttacker-controlled strings are clamped before they reach the sanitizer, so escaping costs a bounded constant rather than scaling with input. Sanitizing runs ~11,310 gas/byte (InlineCode) against ~31 for the raw concatenation it replaced, and Render is reachable unauthenticated through vm/qrender under maxGasQuery = 3\_000\_000\_000. ExecutorCreationRealm is dispatched through the public dao.Executor interface, so a hostile executor computes it per call while storing almost nothing. Measured on the real render path: a 250KB value costs 2,839,117,770 gas unclamped against 18,749,984 clamped. 250KB is just under the cap; about 265KB crosses it (3,008,818,394), and past that the page cannot be rendered at all by anyone. Choosing the larger number costs the attacker nothing, since the value is computed per call and almost nothing is stored. Removing that amplification is the point of this file. It does NOT make the page safe, and nothing here should be read as claiming so. The executor's method body runs inside the same query and is unbounded: an executor that simply burns CPU before returning a short string still renders the proposal page permanently un-queryable, for a few hundred bytes of on-chain storage. That predates this change — Render has always called ExecutorString() and ExecutorCreationRealm() through the public interface — and bounding it needs a gas budget around executor dispatch, not a clamp.
Value
(512 <untyped> bigint)
maxRenderedPayment
untyped bigintAttacker-controlled strings are clamped before they reach the sanitizer, so escaping costs a bounded constant rather than scaling with input. Sanitizing runs ~11,310 gas/byte (InlineCode) against ~31 for the raw concatenation it replaced, and Render is reachable unauthenticated through vm/qrender under maxGasQuery = 3\_000\_000\_000. ExecutorCreationRealm is dispatched through the public dao.Executor interface, so a hostile executor computes it per call while storing almost nothing. Measured on the real render path: a 250KB value costs 2,839,117,770 gas unclamped against 18,749,984 clamped. 250KB is just under the cap; about 265KB crosses it (3,008,818,394), and past that the page cannot be rendered at all by anyone. Choosing the larger number costs the attacker nothing, since the value is computed per call and almost nothing is stored. Removing that amplification is the point of this file. It does NOT make the page safe, and nothing here should be read as claiming so. The executor's method body runs inside the same query and is unbounded: an executor that simply burns CPU before returning a short string still renders the proposal page permanently un-queryable, for a few hundred bytes of on-chain storage. That predates this change — Render has always called ExecutorString() and ExecutorCreationRealm() through the public interface — and bounding it needs a gas budget around executor dispatch, not a clamp.
Value
(512 <untyped> bigint)
clampField
func(s string, max int) stringAlways clamp first — before escaping, and before any other pass over the value. Trimming used to run before the clamp, which meant it walked every byte the executor returned: 250KB of spaces cost 1,368,719,824 gas to render nothing, and 560KB cost 3,048,904,520, past the query cap. Clamping first bounds that scan and brought the same 560KB down to 16,657,792. Never clamp after escaping either. The escapers size their wrapper from the string they are handed — InlineCode picks a fence long enough to outscan the backticks it can see. Cutting a value that has already been escaped can slice the closing fence off and leave the span hanging open, which is worse than not clamping at all. Both call sites read InlineCode(clampField(...)) for that reason, and the enormous-value case in filetests/executor\_disclosure\_filetest.gno fails if the two are swapped. clampField cuts s to at most max bytes, backing off to a rune boundary so a well-formed multi-byte character is not split, and marks the result so a reader can tell it was cut. Input that is already invalid UTF-8 can still leave a dangling lead byte; the sanitizer tolerates that. The marker avoids markdown punctuation: these values are escaped downstream, and parentheses would come back as "\\(truncated\\)".
- OID
- 01bbad…438b:3
clampField details
FilterByTier
typeValue
v0.FilterByTier
NewFilterByTier
func(tier string) v0.FilterByTier- OID
- 01bbad…438b:5
NewFilterByTier details
ErrMemberNotFound
*errors.errorString- OID
- 01bbad…438b:8
ErrMemberNotFound details
GovDAO
typeValue
v0.GovDAO
NewGovDAO
func() *v0.GovDAO- OID
- 01bbad…438b:10
NewGovDAO details
_govdao
*v0.GovDAOSetting this to a global variable forces attaching the GovDAO struct to this realm. TODO replace with future \`attach()\`.
- OID
- 01bbad…438b:66
_govdao details
law
*v0.Law- OID
- 01bbad…438b:64
law details
govDAO
*v0.GovDAO- OID
- 01bbad…438b:13
govDAO details
init.14
func()- OID
- 01bbad…438b:35
init.14 details
Render
func(in string) string- OID
- 01bbad…438b:37
Render details
AddMember
func(addr .uverse.address)AddMember allows T1 and T2 members to freely add T3 members using their invitation points.
- OID
- 01bbad…438b:38
AddMember details
GetInstance
func(int, rlm .uverse.realm) *v0.GovDAOGetInstance returns the singleton \*GovDAO. Only the loader realm may call it (used during the bootstrap UpdateImpl handoff). The IsCurrent() check rejects stale or stashed realm values; PkgPath() after the check is the authentic immediate caller.
- OID
- 01bbad…438b:39
GetInstance details
NewChangeLawRequest
func(newLaw v0.Law) dao.ProposalRequest- OID
- 01bbad…438b:40
NewChangeLawRequest details
NewUpgradeDaoImplRequest
func(newDao dao.DAO, realmPkg string, reason string) dao.ProposalRequest- OID
- 01bbad…438b:42
NewUpgradeDaoImplRequest details
NewAddMemberRequest
func(addr .uverse.address, tier string, portfolio string) dao.ProposalRequest- OID
- 01bbad…438b:43
NewAddMemberRequest details
NewWithdrawMemberRequest
func(addr .uverse.address, reason string) dao.ProposalRequest- OID
- 01bbad…438b:44
NewWithdrawMemberRequest details
NewPromoteMemberRequest
func(addr .uverse.address, fromTier string, toTier string) dao.ProposalRequest- OID
- 01bbad…438b:45
NewPromoteMemberRequest details
NewTreasuryPaymentRequest
func(payment v0.Payment, reason string) dao.ProposalRequest- OID
- 01bbad…438b:46
NewTreasuryPaymentRequest details
NewTreasuryGRC20TokensUpdate
func(newTokenKeys []string) dao.ProposalRequestNewTreasuryGRC20TokensUpdate creates a proposal request to update the list of GRC20 tokens registry keys used by the treasury. The new list, if voted and accepted, will overwrite the current one.
- OID
- 01bbad…438b:47
NewTreasuryGRC20TokensUpdate details
memberByTier
func(tier string) *v0.Member- OID
- 01bbad…438b:48
memberByTier details
render
typeValue
v0.render
NewRender
func(d *v0.GovDAO) *v0.render- OID
- 01bbad…438b:49
NewRender details
isPropActive
func(ps *v0.proposalStatus) bool- OID
- 01bbad…438b:51
isPropActive details
getPropStatus
func(ps *v0.proposalStatus) string- OID
- 01bbad…438b:52
getPropStatus details
renderActionBar
func(sPid string) string- OID
- 01bbad…438b:53
renderActionBar details
tryResolveAddr
func(addr .uverse.address) stringtryResolveAddr renders the author/voter as a username link. RenderLink interpolates the username raw into "\[@name](/u/name)" (r/sys/users), so this is markdown-safe ONLY because r/sys/users validateName restricts names to ^\[a-z]\[a-z0-9]\*(\[\_-]\[a-z0-9]+)\*$ (max 64) — no markdown/HTML metachar. If that charset ever loosens, this line and writeVotes in types.gno need escaping.
- OID
- 01bbad…438b:54
tryResolveAddr details
Law
typeValue
v0.Law
NewLaw
func(supermajority float64) v0.Law- OID
- 01bbad…438b:55
NewLaw details
ProposalsStatuses
typeProposalsStatuses contains the status of all the proposals indexed by the proposal ID.
Value
v0.ProposalsStatuses
NewProposalsStatuses
func() v0.ProposalsStatuses- OID
- 01bbad…438b:57
NewProposalsStatuses details
proposalStatus
typeValue
v0.proposalStatus
getMembers
func() v0.MembersByTier- OID
- 01bbad…438b:58
getMembers details
newEmptyVoteStore
func() v0.MembersByTier- OID
- 01bbad…438b:59
newEmptyVoteStore details
newProposalStatus
func(allowedToVote []string) *v0.proposalStatus- OID
- 01bbad…438b:60
newProposalStatus details
StringifyVotes
func(int, rlm .uverse.realm, ps *v0.proposalStatus) string- OID
- 01bbad…438b:61
StringifyVotes details
writeVotes
func(int, rlm .uverse.realm, sb *strings.Builder, t v0.MembersByTier, title string)- OID
- 01bbad…438b:62
writeVotes details
StringifyProposal
func(p *dao.Proposal) string- OID
- 01bbad…438b:63