Skip to content

Commit f56c340

Browse files
committed
refactor: introduce @expects tag and relabel unenforced @precondition annotations across SDK
1 parent c541d49 commit f56c340

18 files changed

Lines changed: 40 additions & 39 deletions

CLAUDE.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -100,6 +100,7 @@ The `/issue` skill applies these labels automatically when creating issues via C
100100
- Path aliases: `@/src/*` and `@packageJSON`
101101
- All env vars prefixed with `PUBLIC_` and validated in `src/env.ts`
102102
- JSDoc comments on exported functions/components (follow existing patterns)
103+
- Use `@precondition` in JSDoc ONLY for conditions enforced at runtime with a throw/guard. Use `@expects` for documented assumptions the caller is responsible for (TypeScript-enforced, gracefully handled, or downstream-validated). If you write `@precondition`, the function MUST validate and throw on violation.
103104

104105
## Styling
105106

src/sdk/core/chain/explorer.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,8 +8,8 @@ type ExplorerParams =
88
/**
99
* Builds an explorer URL for a transaction, address, or block.
1010
*
11-
* @precondition registry is a valid ChainRegistry
12-
* @precondition params.chainId identifies a chain, params contains exactly one of tx/address/block
11+
* @expects registry is a valid ChainRegistry
12+
* @expects params.chainId identifies a chain, params contains exactly one of tx/address/block
1313
* @postcondition returns a fully qualified URL string, or null if chain/explorer/path not found
1414
* @postcondition if explorer.queryParams is defined, they are appended as URL search params
1515
*/

src/sdk/core/errors/format.ts

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@
1111
/**
1212
* Extracts shortMessage from viem errors, walking the cause chain if needed.
1313
*
14-
* @precondition error is any value (null-safe)
14+
* @expects error is any value (null-safe)
1515
* @postcondition returns the first shortMessage or details found, or null
1616
*/
1717
export function extractViemErrorMessage(error: unknown): string | null {
@@ -40,7 +40,7 @@ export function extractViemErrorMessage(error: unknown): string | null {
4040
* Strips technical data (hex, addresses, viem internals) from error messages.
4141
* Acts as a safety net so no raw data leaks to the user.
4242
*
43-
* @precondition message is a non-empty string
43+
* @expects message is a non-empty string
4444
* @postcondition returns a sanitized string with technical data removed
4545
*/
4646
export function sanitizeErrorMessage(message: string): string {
@@ -81,7 +81,7 @@ export function sanitizeErrorMessage(message: string): string {
8181
* 3. Extract revert reason from "execution reverted: ..." pattern
8282
* 4. Sanitize remaining verbose messages (strip hex, addresses, technical blocks)
8383
*
84-
* @precondition error is any value — string, Error, viem error, null, undefined
84+
* @expects error is any value — string, Error, viem error, null, undefined
8585
* @postcondition returns a clean, user-friendly string (never empty, never throws)
8686
*/
8787
export function formatErrorMessage(error: unknown): string {

src/sdk/core/evm/read-client.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ import type { EndpointConfig } from '../chain/descriptor'
66
/**
77
* Read-only client factory for EVM chains. Wraps viem's createPublicClient.
88
*
9-
* @precondition endpoint.url is a valid JSON-RPC URL
9+
* @expects endpoint.url is a valid JSON-RPC URL
1010
* @postcondition returns a viem PublicClient for read-only chain queries
1111
*/
1212
export const evmReadClientFactory: ReadClientFactory<PublicClient> = {

src/sdk/core/evm/server-wallet.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,7 @@ export interface EvmServerWalletConfig {
3333
* Returns no Provider — server wallets have no UI layer.
3434
*
3535
* @precondition config.privateKey is a valid hex-encoded private key
36-
* @precondition config.chain is a valid viem Chain
36+
* @expects config.chain is a valid viem Chain
3737
* @postcondition returned adapter.chainType === 'evm'
3838
* @postcondition returned bundle has no Provider (server wallets have no UI)
3939
* @invariant adapter.chainType never changes after construction

src/sdk/core/evm/transaction.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -98,7 +98,7 @@ export function createEvmTransactionAdapter(
9898
/**
9999
* Estimates gas and validates readiness for the given transaction params.
100100
*
101-
* @precondition params.chainId is in supportedChains
101+
* @expects params.chainId is in supportedChains
102102
* @postcondition if ready === true -> execute() can be called with these params
103103
* @postcondition if ready === false -> reason explains why (human-readable)
104104
* @throws {InsufficientFundsError} if balance too low for gas estimation
@@ -225,7 +225,7 @@ export function createEvmTransactionAdapter(
225225
/**
226226
* Waits for the transaction to be confirmed or times out.
227227
*
228-
* @precondition ref was returned by a previous execute() call on this adapter
228+
* @expects ref was returned by a previous execute() call on this adapter
229229
* @postcondition result.status is 'success', 'reverted', or 'timeout'
230230
* @postcondition if 'success' -> result.receipt contains a viem TransactionReceipt
231231
* @throws never (timeout returns TransactionResult with status: 'timeout')

src/sdk/core/evm/wallet.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -288,7 +288,7 @@ export function createEvmWalletAdapter(config: EvmWalletConfig): EvmWalletAdapte
288288
* Signs EIP-712 typed data with the connected wallet.
289289
*
290290
* @precondition getStatus().connected === true
291-
* @precondition metadata.capabilities.signTypedData === true
291+
* @expects metadata.capabilities.signTypedData === true
292292
* @postcondition result.address matches the signing account
293293
* @throws {WalletNotConnectedError} if not connected
294294
* @throws {SigningRejectedError} if user cancels

src/sdk/core/read-client.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ import type { ChainRegistry } from './chain/registry'
55
* Creates a typed read-only client using a specific factory.
66
* For CLI tools, agent scripts, and other non-React consumers.
77
*
8-
* @precondition chainId is registered in the registry
8+
* @expects chainId is registered in the registry
99
* @postcondition returns a typed client, or null if chain/endpoint not found
1010
*/
1111
export function createReadClient<TClient>(
@@ -28,7 +28,7 @@ export function createReadClient<TClient>(
2828
* Resolves a read-only client from a heterogeneous factory array.
2929
* For multi-VM loops where the chain type isn't known ahead of time.
3030
*
31-
* @precondition chainId is registered in the registry
31+
* @expects chainId is registered in the registry
3232
* @postcondition returns a client, or null if chain/factory/endpoint not found
3333
*/
3434
export function resolveReadClient(

src/sdk/core/utils/wrap-adapter.ts

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@ export interface WrapAdapterHooks {
1616
* Always return an args array — return the input unchanged for pass-through.
1717
* Errors propagate (not fire-and-forget).
1818
*
19-
* @precondition args is the original arguments array
19+
* @expects args is the original arguments array
2020
* @postcondition returned array replaces args for the method call
2121
* @throws any error thrown here aborts the method call
2222
*/
@@ -41,7 +41,7 @@ export interface WrapAdapterHooks {
4141
* Always return a value — return the input unchanged for pass-through.
4242
* Errors propagate (not fire-and-forget).
4343
*
44-
* @precondition result is the resolved value from the method
44+
* @expects result is the resolved value from the method
4545
* @postcondition returned value replaces the method result
4646
* @throws any error thrown here aborts the call
4747
*/
@@ -66,7 +66,7 @@ function collectMethodKeys(obj: object): string[] {
6666
*
6767
* Execution order: `beforeCall` -> `onBefore` -> method -> `onAfter` -> `afterCall`
6868
*
69-
* @precondition adapter is a non-null object
69+
* @expects adapter is a non-null object
7070
* @postcondition returned object has the same interface as adapter with hooks applied
7171
* @throws errors from `beforeCall`/`afterCall` propagate; observation hook errors are swallowed
7272
*/

src/sdk/react/components/WalletGuard.tsx

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,7 @@ export interface WalletGuardProps {
2525
/**
2626
* Level 4 escape hatch: explicit wallet adapter — bypasses provider resolution.
2727
* Only applies in single-chain mode (not with `require` prop).
28-
* @precondition if adapter provided, require must not be set (single-chain mode only)
28+
* @expects if adapter provided, require must not be set (single-chain mode only)
2929
*/
3030
adapter?: WalletAdapter
3131
children?: ReactNode
@@ -51,7 +51,7 @@ export interface WalletGuardProps {
5151
* - **Single-chain** (chainId/chainType props): uses useWallet for one adapter
5252
* - **Multi-chain** (require prop): uses useMultiWallet, checks each requirement
5353
*
54-
* @precondition Either `require` or `chainId`/`chainType` should be provided, not both
54+
* @expects Either `require` or `chainId`/`chainType` should be provided, not both
5555
* @postcondition Renders children only when all wallet requirements are satisfied
5656
* @throws Never — renders fallback UI or null instead of throwing
5757
*/
@@ -74,7 +74,7 @@ export const WalletGuard: FC<WalletGuardProps> = (props) => {
7474

7575
/**
7676
* Internal component for single-chain wallet gating (original behavior).
77-
* @precondition useWallet hook is available via provider context
77+
* @expects useWallet hook is available via provider context
7878
* @postcondition Renders children when wallet is connected to the correct chain
7979
*/
8080
const SingleChainGuard: FC<WalletGuardProps> = ({
@@ -119,7 +119,7 @@ interface MultiChainGuardProps extends WalletGuardProps {
119119
/**
120120
* Internal component for multi-chain wallet gating.
121121
* Iterates requirements and renders fallback for the first unmet one.
122-
* @precondition useMultiWallet hook is available via provider context
122+
* @expects useMultiWallet hook is available via provider context
123123
* @postcondition Renders children only when every requirement has a connected wallet
124124
*/
125125
const MultiChainGuard: FC<MultiChainGuardProps> = ({

0 commit comments

Comments
 (0)