sdk/shreds: add the feed subscription program's FeedDistribution account - #4216
Open
bgm-malbeclabs wants to merge 1 commit into
Open
sdk/shreds: add the feed subscription program's FeedDistribution account#4216bgm-malbeclabs wants to merge 1 commit into
bgm-malbeclabs wants to merge 1 commit into
Conversation
The feed subscription program is a second program alongside shred subscription, and this SDK carried nothing for it, so every consumer decoded the account at fixed byte offsets itself. Lake has one such copy today. FeedDistribution is a bytemuck Pod onchain, read here field by field, which agrees with the Pod bytes only because the field order leaves no interior padding. Two tests pin that: the 120-byte size in TestStructSizes, and every field of a real mainnet account, whose three bump seeds around a zero proportion make a one-byte shift detectable rather than merely plausible. Client is built around one program ID, so it gains no fetch method. DeserializeFeedDistribution is exported instead, for a caller that brings its own getProgramAccounts call. sdk-test never ran ./sdk/shreds/go/..., so this package's layout pins have never run in CI. Added, and the package passes.
bgm-malbeclabs
force-pushed
the
sdk/shreds-feed-distribution
branch
from
August 20, 2026 21:31
c54019a to
540df10
Compare
martinsander00
approved these changes
Aug 20, 2026
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary of Changes
sdk/shreds/gonow carries the feed subscription program'sFeedDistributionaccount: how much USDC one feed collected for one calendar month. That program is a second program alongside shred subscription and had nothing in this SDK, so each Go caller decoded the account at fixed byte offsets itself.malbeclabs/lakeholds one such copy today and can delete it once this lands.FeedDistributionis abytemuckPod onchain (#[repr(C, align(8))]), read here field by field. That agrees with the Pod bytes only because the field order leaves no interior padding, and nothing in the Rust struct states that. Two tests pin it: the 120-byte total inTestStructSizes, and every field of a real mainnet account.Clientis built around one program ID, so it gains no fetch method.DeserializeFeedDistributionis exported instead, for a caller that makes its owngetProgramAccountscall.FeedProgramIDnames the program.make sdk-testnever ran./sdk/shreds/go/..., so this package's layout pins have never run in CI. It runs them now, and the package passes.Read a month as an allocation, not as cash that arrived in it: one subscription payment is credited across the calendar months the subscription spans, in day fractions, so an account can exist for a month that has not started. Sum every month for cash collected to date.
Diff Breakdown
Additive only, and more than half of it is the layout guard.
Key files (click to expand)
sdk/shreds/go/state_test.go— the layout guard: a real mainnet account decoded field by field, and a v1 discriminator rejectedsdk/shreds/go/state.go— theFeedDistributionstruct, under a--- Feed subscription program ---bannersdk/shreds/go/discriminator_test.go—FeedDistributionin the uniqueness map, plus a hex pin on the seed hashsdk/shreds/go/client.go—DeserializeFeedDistribution, the exported door onto the shared decodersdk/shreds/go/discriminator.go—sha256First8("dz::account::feed_distribution::v2")sdk/shreds/go/config.go—FeedProgramIDTesting Verification
crW8HCYDpQVyCxYG7m3hXeC42rAnjoLroGGfgGLLXM2, read from mainnet-beta on 2026-08-19, and checks every field. The three bump seeds around a zero proportion (255, 0, 253, 255) are what make a one-byte shift fail rather than merely look wrong.v1account is orphaned, since v2 replaced the per-month vault with a per-feed vault, so reading one as v2 has to be an error rather than a wrong amount.FeedDistributiondecoded and oneProgramConfigcorrectly skipped by discriminator, totalling 51,205.50 USDC collected to date. The pinned account reads 6,145.16 today against 2,080.65 on 19 Aug, which matches the field only ever increasing.Note for reviewers
doublezero-shredsnow ships generated bindings for this program atsdk/go/feedgen, and this struct describes the same bytes by hand. That repository is private, so lake and any other public consumer cannot import it: pulling it in needsGOPRIVATE, a git URL rewrite, a Dockerfile build secret, and a token that does not exist in lake today. Hence the hand-written copy.The cost is that a program change regenerates
feedgenand leaves this struct stale. The size and field pins turn that into a test failure rather than a wrong number, which is the best this arrangement can do. Making one place canonical is tracked in malbeclabs/infra#2330.