[#35] Scaffold @plotlink/sdk with core methods#126
Conversation
Adds packages/sdk/ with TypeScript + tsup (ESM + CJS dual output):
- PlotLink client class with constructor({ privateKey, rpcUrl })
- createStoryline() — upload to IPFS via Filebase, call StoryFactory
- chainPlot() — upload content, call StoryFactory.chainPlot()
- getStoryline() / getPlots() — read from on-chain event logs
- registerAgent() — call ERC-8004 register(agentURI)
- claimRoyalties(tokenAddress) — call MCV2_Bond.claimRoyalties()
- getRoyaltyInfo(tokenAddress) — read unclaimed royalty balance
ABIs mirrored from lib/contracts/ for standalone use.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
project7-interns
left a comment
There was a problem hiding this comment.
Verdict: REQUEST CHANGES
Summary
The SDK package scaffolding is substantial, but the agent-registration API is incomplete relative to issue #35. The required flow is register + setAgentWallet, and the current SDK only exposes registerAgent() for the initial registration transaction.
Findings
- [high]
registerAgent()does not implement the required wallet-binding step- File:
packages/sdk/src/client.ts:333 - Suggestion: Issue #35 explicitly calls for agent methods wrapping ERC-8004 registration including
register + setAgentWallet. Right nowregisterAgent()stops afterregister(agentURI)and returnsagentId, with no way to sign the EIP-712 payload or callsetAgentWallet. Add the wallet-binding path to the SDK API, or expose a separate method that completessetAgentWalletwith the correct contract ABI and typed-data flow.
- File:
- [high] The SDK ERC-8004 ABI is missing
setAgentWallet, so the required flow cannot be implemented by consumers- File:
packages/sdk/src/abi.ts:82 - Suggestion: Mirror the full ERC-8004 ABI needed for the SDK contract surface, including
setAgentWalletand any event/type details required for the signing flow. As written, the package cannot support the issue's required agent-wallet binding step.
- File:
Decision
Request changes because issue #35 requires the SDK to wrap the full agent registration flow, and the current package only implements the first transaction.
project7-interns
left a comment
There was a problem hiding this comment.
T2b Review: REQUEST CHANGES
Good scaffold overall — ABIs are accurate, build config is clean, credential handling is correct. Several issues to address:
Critical
viemis bothdependencyandpeerDependency— will cause duplicate bundles in consumer projects. Move topeerDependenciesonly, add todevDependencies.genreparameter increateStoryline()is accepted but never used — not passed to contract or IPFS metadata. Either include it in the upload payload or remove from the signature.- No content length validation — the web app enforces 500-10,000 chars via
lib/content.ts. SDK should port these guards since it's the public API boundary.
High
fromBlock: BigInt(0)ingetStoryline()/getPlots()— scanning from block 0 on Base will timeout or be rejected by RPC providers. Add aDEPLOYMENT_BLOCKconstant as default.- Fragile ABI array indexing —
storyFactoryAbi[1]/storyFactoryAbi[0]for events will silently break if ABI is reordered. Use named references (.find(e => e.name === "...")) or export individual event objects. - Constructor silently defaults non-8453 chainIds to baseSepolia — passing chainId
1(mainnet) would get baseSepolia config. Throw on unsupported chainIds.
Low
- Unused
TransportConfigimport — will fail lint. - S3Client created per upload call — consider caching on the instance.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
project7-interns
left a comment
There was a problem hiding this comment.
Verdict: REQUEST CHANGES
Summary
The new setAgentWallet() method closes the gap I previously flagged, but there are still blocking SDK issues outside that flow. In particular, the read APIs scan from genesis on every call, which is not a viable default on Base for an SDK package.
Findings
- [high]
getStoryline()andgetPlots()scan logs from block 0, which will become unusably slow or time out on Base- File:
packages/sdk/src/client.ts:252 - Suggestion: Add deployment block constants for the PlotLink contracts and use those as
fromBlockdefaults instead ofBigInt(0). An SDK method that always scans from genesis is not production-usable.
- File:
- [medium]
viemis declared as both a runtime dependency and a peer dependency- File:
packages/sdk/package.json:26 - Suggestion: Pick one packaging model. Keeping
viemin both places can lead to duplicate installs and mismatched types for consumers.
- File:
- [medium] Unsupported
chainIdvalues silently fall back to Base Sepolia- File:
packages/sdk/src/client.ts:116 - Suggestion: Validate
chainIdexplicitly and throw for unsupported values. Quietly routing an arbitrary chain ID to Base Sepolia is a dangerous default for a signing SDK.
- File:
Decision
Request changes because the SDK's read methods are still not safe/usable at scale in their current form, and the constructor/packaging defaults need tightening before this is ready for consumers.
- Replace fromBlock: BigInt(0) with DEPLOYMENT_BLOCK constant to avoid full-chain scans that time out on Base - Remove viem from dependencies, keep only as peerDependency - Throw on unsupported chainId instead of silently falling back to Base Sepolia Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
project7-interns
left a comment
There was a problem hiding this comment.
Verdict: REQUEST CHANGES
Summary
The SDK code issues I previously flagged are fixed, but the current PR is still blocked by a real CI failure. Root npm run typecheck now fails because the repository typecheck includes packages/sdk/tsup.config.ts, while tsup is only installed in the SDK package.
Findings
- [high] Root typecheck fails because
packages/sdk/tsup.config.tsimportstsup, which is not available to the root TypeScript run- File:
packages/sdk/tsup.config.ts:1 - Suggestion: Exclude
packages/sdk/tsup.config.tsfrom the root typecheck path, addtsupwhere the root checker can resolve it, or restructure the package config so the repo-widenpm run typecheckpasses as required by the issue.
- File:
Decision
Request changes because the PR currently fails the required lint-and-typecheck check.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
project7-interns
left a comment
There was a problem hiding this comment.
Verdict: APPROVE
Summary
The follow-up fixes resolve the previously blocking SDK issues: the ERC-8004 wallet-binding path is implemented, event-log reads now start from a deployment block instead of genesis, unsupported chain IDs throw, and the root typecheck no longer trips over the SDK build config. The package now satisfies issue #35's required SDK surface and CI passed.
Findings
- None.
Decision
Approve because the SDK scaffolding and required methods are in place, the contract-facing correctness issues are addressed, and lint-and-typecheck passed.
project7-interns
left a comment
There was a problem hiding this comment.
T2b Re-review: REQUEST CHANGES
5 of 9 original issues fixed (viem dep, fromBlock, chainId validation, tsconfig, setAgentWallet). 4 remain:
Still open
-
genreparam increateStoryline()is accepted but never used — not passed to contract or IPFS metadata. This is a data-loss API bug — callers think genre is stored but it's silently discarded. Either include it in the IPFS upload payload or remove from the signature. -
No content length validation — empty strings and oversized content flow to IPFS + chain unchecked. Port the 500-10,000 char limits from the web app's
lib/content.ts. -
Fragile ABI array indexing —
storyFactoryAbi[1]/storyFactoryAbi[0]for events. If ABI array is reordered, these silently break. Use named references:storyFactoryAbi.find(e => e.name === "StorylineCreated")or export individual event objects. -
Unused
TransportConfigimport —client.tsimportstype TransportConfigfrom viem but never uses it. Will failnoUnusedLocals.
- Include genre in IPFS metadata payload (was accepted but discarded) - Add validateNonEmpty() for required string params at SDK boundary - Replace fragile storyFactoryAbi[0]/[1] with named find() constants - Remove unused TransportConfig import Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
project7-interns
left a comment
There was a problem hiding this comment.
T2b Re-review: APPROVE
All 4 remaining issues fixed:
genrenow included in IPFS metadata payload — no more silent data lossvalidateNonEmpty()guards on all string params across all methods- Named event constants (
StorylineCreatedEvent,PlotChainedEvent) replace fragile array indexing - Unused
TransportConfigimport removed
Combined with the earlier fixes (viem peerDep, DEPLOYMENT_BLOCK, chainId validation, tsconfig exclusion, setAgentWallet), all 9 original issues are resolved. Ship it.
Summary
Fixes #35
packages/sdk/with TypeScript + tsup (dual ESM/CJS output with type declarations)PlotLinkclient class with constructor{ privateKey, rpcUrl }and optionalfilebaseconfigcreateStoryline(),chainPlot(),getStoryline(),getPlots(),registerAgent(),claimRoyalties(),getRoyaltyInfo()lib/contracts/— StoryFactory, ERC-8004, MCV2_Bondlib/filebase.ts)simulateContract+writeContractpatternTest plan
cd packages/sdk && npm run typecheckpassescd packages/sdk && npm run buildproducesdist/with.js,.cjs,.d.ts,.d.ctsPlotLinkfrom built output — constructor creates valid viem clientscreateStoryline()with Filebase creds against testnet🤖 Generated with Claude Code