feat(APP-667): Pull token voting ERC20 members from aragon-subdomain - #1128
feat(APP-667): Pull token voting ERC20 members from aragon-subdomain#1128asciiman wants to merge 36 commits into
Conversation
|
🚀 Preview Deployment: View Here |
|
E2E results (preview) Smoke
|
…-aragon-subdomain
…-aragon-subdomain Brings the branch across the monorepo restructure (apps/app) and reconciles the two aragon-domain integrations: - Relocated all branch-added files from src/ into apps/app/src/ (per MIGRATION.md). - Kept @aragon/aragon-domain pinned to the 0.0.0-20260626160332 snapshot (superset of 0.3.1: adds getTokenVotingMembership + required rpcUrls load arg); main's ^0.3.1 dropped, lockfile regenerated. - .env.example: adopted main's NEXT_SECRET_ENVIO_* variable names. - Dropped branch-local graphql/graphql-request/ddd-core-ts direct deps (declared as regular dependencies of the package itself). Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…ainService pattern Aligns the branch's aragon-domain integration with the service architecture main established in APP-795, replacing the ad-hoc route + raw fetch: - aragonDomainService.backend singleton now passes the required rpcUrls to AragonDomain.load and exposes getTokenVotingMembership. - New tokenVotingMembershipService client/server/api triplet typed entirely with package DTOs; BFF route moves from /api/subdomain/members to /api/domain/token-voting/members with monitoring on failure. - Source routing consolidated into a single fetchTokenVotingMembership util (domain transport injected: BFF client on the browser, in-process controller via tokenVotingMembershipOptionsServer for RSC prefetch). - getMemberList reverted to its generic pre-branch form; routing fields move to IGetTokenVotingMembershipQueryParams; tokenProcessBodyField now uses the dedicated membership hook for its member count. - daoMembersPage prefetches the token-voting membership query for token-voting/lock-to-vote plugins via the shared buildTokenVotingMembershipParams helper, restoring SSR cache hydration for those lists. - "subdomain" vocabulary renamed to "domain" (resolveMemberSource, DOMAIN_NETWORKS) to avoid clashing with ENS subdomains. - Temporary aragonDomain.d.ts augmentation bridges the two member-profile DTO exports missing from the pinned snapshot; delete on the next published aragon-domain version. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
The new snapshot exports the member-profile DTOs that were missing from the 6/26 snapshot, so the temporary aragonDomain.d.ts module augmentation is deleted with it. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…embershipParams Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…gMembershipParams
Replaces the defensive `settings as { token?: ... }` read with a typed
contract: the helper takes IDaoPlugin<ITokenVotingMembershipPluginSettings>,
and the members page narrows its generic plugin through the new
isTokenVotingMembershipPlugin type guard (the same interfaceType→settings
contract the slot registry relies on). tokenMemberListBase already carries
the stronger type and is unchanged. A discriminated-union IDaoPlugin would
make the guard unnecessary — noted in the guard's jsdoc as the future fix.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…berListPlugin The plugin set is defined by which component renders the list (TokenMemberListBase serves both token-voting and lock-to-vote), not by the TokenVoting plugin identity — the old name read as the latter. Query and params names stay tied to the aragon-domain DTO. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
| }, | ||
| "dependencies": { | ||
| "@aragon/aragon-domain": "^0.3.1", | ||
| "@aragon/aragon-domain": "0.0.0-20260730113648", |
There was a problem hiding this comment.
Don't merge until this is updated with release build of lib.
There was a problem hiding this comment.
Not approving yet, your own note still stands: the dep's on the dev snapshot 0.0.0-20260730113648, so release build (and a rebase onto main) before this goes. Code side's solid, a couple of type nits inline.
…-aragon-subdomain
| pluginInterfaceType: PluginInterfaceType.TOKEN_VOTING, | ||
| tokenAddress: membership.token.address, | ||
| tokenUnderlying: | ||
| (membership.token as { underlying?: string | null }) |
There was a problem hiding this comment.
This cast is quietly doing the routing. ITokenSetupMembershipForm.token doesn't declare underlying, and the value only survives because tokenBodyUtils spreads the full settings token in. If someone later builds membership.token to the declared shape, a mainnet wrapped or VE body flips to the domain source and shows the wrong holder count with no warning. Can we declare underlying on the form token type (picked off ITokenPluginSettingsToken) so the compiler catches it?
| network != null && | ||
| DOMAIN_NETWORKS.has(network) && | ||
| interfaceType === PluginInterfaceType.TOKEN_VOTING && | ||
| tokenUnderlying == null; |
There was a problem hiding this comment.
The VE exclusion leans on VE tokens always carrying underlying, but the type only promises that for the wrap-needed case, and votingEscrow never reaches the routing params. If a mainnet VE deployment ever ships with underlying null, its list reads plain ERC20Votes balances from the domain instead of escrow locks. Threading a votingEscrow flag through buildTokenVotingMembershipParams and excluding on it here keeps the predicate self-contained.
| const { queryParams } = params; | ||
| const { tokenAddress, page, pageSize } = queryParams; | ||
|
|
||
| if (tokenAddress != null && resolveMemberSource(queryParams) === 'domain') { |
There was a problem hiding this comment.
When the domain fetch throws, mainnet lists now hard-error where legacy used to serve them, since this slice has no runtime fallback. If that's on purpose so indexer problems surface instead of hiding behind legacy data, all good.
| @@ -1,2 +1,3 @@ | |||
| export { DaoMembersPage, type IDaoMembersPageProps } from './daoMembersPage'; | |||
| // The DaoMembersPage RSC is NOT exported here on purpose since imports | |||
There was a problem hiding this comment.
nit: missing word in the comment.
| // The DaoMembersPage RSC is NOT exported here on purpose since imports | |
| // The DaoMembersPage RSC is NOT exported here on purpose since it imports |
Description
This repoints the mainnet ERC-20 Token Voting member list from the legacy backend to the aragon-domain package as the first slice of the platform architecture migration.
Requests are routed per plugin. Eligible token-voting queries go to the new domain BFF. Everything else falls back to the legacy backend unchanged. Both sources return the same library-owned DTO.
What's in this PR
aragonDomainServicepattern previously introduced. A client/server service pair over a lazy server singleton now wires per-network RPC URLs and exposes the full controller viagetDomain()instead of per-method delegates.Where to look
Start with
governanceService/utils/fetchTokenVotingMembership. This is the single routing implementation both the client fetch and the RSC prefetch share, with the domain transport injected.resolveMemberSourceholds the eligibility rules, andbuildTokenVotingMembershipParamscarries the server/client query-key contract. The two sides must build identical params.Notes
daoUtils.isLinkedAccountPluginnow uses a server-safe address comparison. The gov-ui-kit shim's exports aren't callable from RSC context, and the members-page prefetch is its first server-side caller.TokenMemberListBase, and the routing predicate always sends LTV to the legacy backend. Moving LTV to its own query is deferred until the aragon-domain adds a lock-to-vote membership use case with its own DTO, so that code path only needs to be built once.Type of Change
Developer Checklist:
Review Checklist: